oxedyne/ore/oracle/tests/file_identity.rs
4.0 KiB, 1 run
created by r2848102244:103, which is this file's identity for as long as the history lasts, whatever it is later renamed to
download · who wrote it · its history
| 1 | //! Assertions over stage four. Panics are the point. |
| 2 | |
| 3 | use ore_oracle::mcases; |
| 4 | use ore_oracle::mrep::MRep; |
| 5 | use ore_oracle::mstage; |
| 6 | use ore_oracle::repo::Identity; |
| 7 | |
| 8 | /// Every candidate is checked; the two serious ones are checked hardest. |
| 9 | const ALL: [Identity; 3] = [ |
| 10 | Identity::Derived, |
| 11 | Identity::Recorded, |
| 12 | Identity::RecordedLocal, |
| 13 | ]; |
| 14 | |
| 15 | /// Every file-identity case meets the prediction the options note wrote down |
| 16 | /// before the case was run. |
| 17 | #[test] |
| 18 | fn stage4_cases_meet_predictions() { |
| 19 | for ident in ALL { |
| 20 | let outs = match mcases::all(ident) { |
| 21 | Ok(o) => o, |
| 22 | Err(e) => panic!("{:?} failed to run: {}", ident, e), |
| 23 | }; |
| 24 | for o in &outs { |
| 25 | assert!(o.met(), "{:?} / {}: predicted {}, got {}", |
| 26 | ident, o.name, o.expect, o.got); |
| 27 | } |
| 28 | } |
| 29 | } |
| 30 | |
| 31 | /// A byte is rendered in exactly one file, and no live byte is rendered |
| 32 | /// nowhere. This is the repository-wide invariant design note section 4.8 |
| 33 | /// claims comes free with a global claim register, and only the candidates |
| 34 | /// that keep the register global earn it. |
| 35 | #[test] |
| 36 | fn stage4_conservation_holds_where_the_register_is_global() { |
| 37 | for ident in [Identity::Derived, Identity::Recorded] { |
| 38 | let outs = match mcases::all(ident) { |
| 39 | Ok(o) => o, |
| 40 | Err(e) => panic!("{:?} failed to run: {}", ident, e), |
| 41 | }; |
| 42 | for o in &outs { |
| 43 | assert!(o.conserved(), |
| 44 | "{:?} / {}: {} bytes rendered twice, {} lost", |
| 45 | ident, o.name, o.duplicated, o.lost); |
| 46 | } |
| 47 | } |
| 48 | } |
| 49 | |
| 50 | /// The per-file claim register `fe2o3_ore` has today renders moved bytes in |
| 51 | /// both files at once. This test records the defect; it does not excuse it. |
| 52 | #[test] |
| 53 | fn stage4_a_per_file_register_duplicates_across_a_cross_file_move() { |
| 54 | let o = match mcases::case_cross_file_move_with_edit(Identity::RecordedLocal) { |
| 55 | Ok(o) => o, |
| 56 | Err(e) => panic!("case failed to run: {}", e), |
| 57 | }; |
| 58 | assert_eq!(o.duplicated, 6, |
| 59 | "the duplication has changed shape; re-examine it: {}", o.got); |
| 60 | } |
| 61 | |
| 62 | /// File identity does not perturb single-file semantics: all ten stage-one |
| 63 | /// expectations come out unchanged through the multi-file engine. |
| 64 | #[test] |
| 65 | fn stage4_single_file_regression() { |
| 66 | for ident in ALL { |
| 67 | let outs = match mcases::regression(ident) { |
| 68 | Ok(o) => o, |
| 69 | Err(e) => panic!("{:?} failed to run: {}", ident, e), |
| 70 | }; |
| 71 | for o in &outs { |
| 72 | assert!(o.met(), "{:?} / {}: expected {:?}, got {:?}", |
| 73 | ident, o.name, o.expect, o.got); |
| 74 | assert!(o.conserved(), "{:?} / {}: conservation failed", ident, o.name); |
| 75 | } |
| 76 | } |
| 77 | } |
| 78 | |
| 79 | /// A path is bytes, so a path git permits and a Rust string does not survives |
| 80 | /// the whole engine. |
| 81 | #[test] |
| 82 | fn stage4_paths_are_bytes() { |
| 83 | for ident in ALL { |
| 84 | let mut r = MRep::new(1, ident); |
| 85 | let raw: &[u8] = b"caf\xe9/\xff.txt"; |
| 86 | assert!(String::from_utf8(raw.to_vec()).is_err(), "the fixture must not be UTF-8"); |
| 87 | let (_, f) = match r.create(raw) { |
| 88 | Ok(x) => x, |
| 89 | Err(e) => panic!("{:?}: create failed: {}", ident, e), |
| 90 | }; |
| 91 | if let Err(e) = r.insert(f, 0, b"bytes") { |
| 92 | panic!("{:?}: insert failed: {}", ident, e); |
| 93 | } |
| 94 | let v = match r.view() { |
| 95 | Ok(v) => v, |
| 96 | Err(e) => panic!("{:?}: render failed: {}", ident, e), |
| 97 | }; |
| 98 | let out = match v.file(f) { |
| 99 | Some(x) => x, |
| 100 | None => panic!("{:?}: the file went missing", ident), |
| 101 | }; |
| 102 | assert_eq!(out.path, raw); |
| 103 | assert_eq!(out.bytes, b"bytes"); |
| 104 | } |
| 105 | } |
| 106 | |
| 107 | /// Randomised multi-file trials converge, conserve, and leave no slot without |
| 108 | /// a file. |
| 109 | #[test] |
| 110 | fn stage4_randomised_trials() { |
| 111 | for ident in [Identity::Derived, Identity::Recorded] { |
| 112 | for seed in 0..30u64 { |
| 113 | if let Err(e) = mstage::trial(4000 + seed, ident, 3, 3, 8, 3) { |
| 114 | panic!("{:?} seed {}: {}", ident, seed, e); |
| 115 | } |
| 116 | } |
| 117 | } |
| 118 | } |
| 119 | |
| 120 | /// Moving a file's origin anchor puts one whole file inside another. It is |
| 121 | /// unauthorable through a frontend and coherent when it arrives anyway; the |
| 122 | /// note argues about whether the renderer should refuse it. |
| 123 | #[test] |
| 124 | fn stage4_moving_an_origin_anchor_concatenates_two_files() { |
| 125 | let o = match mcases::case_moving_an_origin_anchor() { |
| 126 | Ok(o) => o, |
| 127 | Err(e) => panic!("case failed to run: {}", e), |
| 128 | }; |
| 129 | assert!(o.met(), "predicted {}, got {}", o.expect, o.got); |
| 130 | assert!(o.conserved()); |
| 131 | } |