168 lines
8.6 KiB
Rust
168 lines
8.6 KiB
Rust
//! Preparation only. Compile as an ordinary binary, never with --test.
|
|
#[allow(dead_code)]
|
|
#[path = "inputs/document.rs"]
|
|
mod document;
|
|
|
|
use document::Document;
|
|
use oa_core::{Command, Id, Project, language, prepare_command, source_files};
|
|
use oa_core::source_project::{self, ProjectLimits, SourceBundle};
|
|
use oa_core::validation::Severity;
|
|
use serde_json::{Value, json};
|
|
use std::collections::{BTreeMap, BTreeSet};
|
|
use std::path::{Path, PathBuf};
|
|
use std::time::Instant;
|
|
|
|
const OLD: &str = "oa_restore_work";
|
|
const NEW: &str = "oa_restore_pressure";
|
|
|
|
fn timed<T>(phase: &str, iteration: usize, action: impl FnOnce() -> T) -> T {
|
|
let clock = Instant::now();
|
|
let result = action();
|
|
let elapsed = clock.elapsed();
|
|
// Printing, result checks and dropping returned values are outside the interval.
|
|
println!("{}", json!({"record":"timing", "phase":phase, "iteration":iteration,
|
|
"elapsed_ns":elapsed.as_nanos().to_string(), "seconds":elapsed.as_secs_f64()}));
|
|
result
|
|
}
|
|
|
|
fn disk_files(root: &Path, here: &Path, files: &mut BTreeMap<PathBuf, Vec<u8>>) {
|
|
for entry in std::fs::read_dir(here).expect("read fixture directory") {
|
|
let entry = entry.expect("directory entry");
|
|
let kind = entry.file_type().expect("file kind");
|
|
assert!(!kind.is_symlink(), "fixture links are not allowed");
|
|
if kind.is_dir() {
|
|
disk_files(root, &entry.path(), files);
|
|
} else {
|
|
assert!(kind.is_file());
|
|
files.insert(entry.path().strip_prefix(root).unwrap().to_owned(),
|
|
std::fs::read(entry.path()).expect("read fixture bytes"));
|
|
}
|
|
}
|
|
}
|
|
|
|
fn physical(root: &Path) -> BTreeMap<PathBuf, Vec<u8>> {
|
|
let mut result = BTreeMap::new();
|
|
disk_files(root, root, &mut result);
|
|
result
|
|
}
|
|
|
|
fn ids(project: &Project) -> BTreeSet<Id> {
|
|
project.identities().into_iter().map(|(id, _)| id).collect()
|
|
}
|
|
|
|
fn expected_source(baseline: &SourceBundle, cli: &Value) -> SourceBundle {
|
|
assert_eq!(cli["format_version"], 1);
|
|
assert_eq!(cli["operation"], "rename-alias");
|
|
assert_eq!(cli["status"], "preview");
|
|
assert_eq!(cli["exit_code"], 0);
|
|
assert_eq!(cli["written"], false);
|
|
let mut expected = baseline.clone();
|
|
let mut paths = BTreeSet::new();
|
|
let changes = cli["changes"].as_array().expect("preserved CLI changes");
|
|
assert!(!changes.is_empty());
|
|
for change in changes {
|
|
let path = change["path"].as_str().expect("changed path");
|
|
assert!(paths.insert(path));
|
|
assert_eq!(baseline.files.get(path).map(String::as_str), change["before"].as_str());
|
|
*expected.files.get_mut(path).expect("existing source only") =
|
|
change["after"].as_str().expect("expected source").to_owned();
|
|
}
|
|
expected
|
|
}
|
|
|
|
fn main() {
|
|
let args: Vec<_> = std::env::args().collect();
|
|
assert_eq!(args.len(), 4, "probe ENTRY CLI_PREVIEW_JSON ITERATIONS");
|
|
let entry = Path::new(&args[1]);
|
|
let iterations: usize = args[3].parse().expect("iteration count");
|
|
assert!((1..=5).contains(&iterations), "bounded to 1..5 samples");
|
|
let root = entry.parent().expect("entry parent");
|
|
let before_disk = physical(root);
|
|
assert_eq!(before_disk.len(), 37, "pinned realistic walkthrough");
|
|
let cli: Value = serde_json::from_slice(&std::fs::read(&args[2]).expect("CLI prediction")).unwrap();
|
|
let limits = ProjectLimits::default();
|
|
|
|
// Disk discovery/load is reported separately and excluded from accepted-command timing.
|
|
let loaded = timed("source_files_load_including_io", 0, ||
|
|
source_files::load_project(entry, limits).expect("load fixture"));
|
|
assert!(!loaded.diagnostics.iter().any(|d| d.diagnostic.severity == Severity::Error));
|
|
let baseline = loaded.reachable_bundle();
|
|
assert_eq!(baseline.files.len(), 30, "pinned reachable source count");
|
|
for source in baseline.files.values() {
|
|
let declarations = language::analyze(source).declarations;
|
|
assert!(declarations.iter().all(|declaration| declaration.id.is_some()),
|
|
"all baseline declarations must retain authored identities");
|
|
}
|
|
let expected_bundle = expected_source(&baseline, &cli);
|
|
println!("{}", json!({"record":"fixture", "reachable_files":baseline.files.len(),
|
|
"physical_files":before_disk.len(), "source_bytes":baseline.files.values().map(String::len).sum::<usize>(),
|
|
"old":OLD,"new":NEW,"iterations":iterations,
|
|
"scope":"accepted snapshot in-process, realistic release1; no UI/disk writes/RSS measurement"}));
|
|
|
|
for iteration in 1..=iterations {
|
|
// Cloning inputs is outside the initialization timing. Initialization remains separate.
|
|
let initial = baseline.clone();
|
|
let mut document = timed("document_initial_compile_and_history_estimate", iteration, ||
|
|
Document::from_bundle(initial, limits).expect("initialize accepted document"));
|
|
assert_eq!(document.bundle(), &baseline, "no UUID stabilization or normalization");
|
|
assert!(!document.dirty() && !document.can_undo() && !document.can_redo());
|
|
let original = document.project().clone();
|
|
let all_ids = ids(&original);
|
|
let target = original.identities().into_iter().find(|(_, alias)| *alias == OLD).unwrap().0;
|
|
assert!(!original.identities().iter().any(|(_, alias)| *alias == NEW));
|
|
let mut expected_project = original.clone();
|
|
expected_project.elements.get_mut(&target).expect("activity target").alias = NEW.into();
|
|
let snapshot = document.snapshot();
|
|
|
|
// Report the phase order: samples alternate to expose warm-up/order effects.
|
|
let execute_first = iteration % 2 == 1;
|
|
println!("{}",json!({"record":"order","iteration":iteration,"execute_first":execute_first}));
|
|
if execute_first {
|
|
let command = Command::SetAlias(target, NEW.into());
|
|
timed("document_execute", iteration, || document.execute(command)).expect("execute rename");
|
|
}
|
|
let command = Command::SetAlias(target, NEW.into());
|
|
let prepared = timed("prepare_command", iteration, ||
|
|
prepare_command(&original, &command)).expect("prepare rename");
|
|
assert_eq!(prepared.project, expected_project);
|
|
assert_eq!(ids(&prepared.project), all_ids);
|
|
let updated = timed("source_update_with_identity_map", iteration, ||
|
|
source_project::update_bundle_with_identity_map(&snapshot, &prepared.project,
|
|
&prepared.identity_map, limits)).expect("prepare source preview");
|
|
assert_eq!(updated.decoded.project, expected_project);
|
|
assert_eq!(updated.bundle, expected_bundle, "full source equality to preserved CLI prediction");
|
|
assert_eq!(snapshot.bundle, baseline, "preview leaves accepted snapshot untouched");
|
|
assert_eq!(snapshot.decoded.project, original);
|
|
if !execute_first {
|
|
assert_eq!(document.project(), &original);
|
|
assert_eq!(document.bundle(), &baseline);
|
|
assert_eq!(document.revision(), 0);
|
|
let command = Command::SetAlias(target, NEW.into());
|
|
timed("document_execute", iteration, || document.execute(command)).expect("execute rename");
|
|
}
|
|
assert_eq!(document.project(), &expected_project);
|
|
assert_eq!(document.bundle(), &expected_bundle);
|
|
assert_eq!(ids(document.project()), all_ids);
|
|
assert_eq!(document.revision(), 1);
|
|
assert!(document.dirty() && document.can_undo() && !document.can_redo());
|
|
assert!(timed("document_undo", iteration, || document.undo()));
|
|
assert_eq!(document.project(), &original);
|
|
assert_eq!(document.bundle(), &baseline);
|
|
assert_eq!(document.revision(), 2);
|
|
assert!(!document.dirty() && !document.can_undo() && document.can_redo());
|
|
assert!(timed("document_redo", iteration, || document.redo()));
|
|
assert_eq!(document.project(), &expected_project);
|
|
assert_eq!(document.bundle(), &expected_bundle);
|
|
assert_eq!(ids(document.project()), all_ids);
|
|
assert_eq!(document.revision(), 3);
|
|
assert!(document.dirty() && document.can_undo() && !document.can_redo());
|
|
// All file reads, equality assertions and output are outside command intervals.
|
|
assert_eq!(physical(root), before_disk, "probe must not write fixture files");
|
|
println!("{}", json!({"record":"verified","iteration":iteration,
|
|
"complete_project_source_equality":true,"uuid_set_unchanged":true,
|
|
"preview_snapshot_unchanged":true,"undo_redo_exact":true,"physical_files_unchanged":true}));
|
|
}
|
|
assert_eq!(physical(root), before_disk);
|
|
println!("{}",json!({"record":"complete","samples":iterations,"physical_files_unchanged":true}));
|
|
}
|