Strengthen mixed Project public-wrapper and storage oracles

This commit is contained in:
2026-09-23 11:27:45 -07:00
parent 8f0d96ca63
commit b9a31bb848
@@ -578,6 +578,35 @@ fn complete_static_architecture_and_unicode_warning_mapping() {
let warning = &resolved.warnings()[0].diagnostic;
assert_eq!(warning.line, 6);
assert_eq!(warning.column, 1);
// Same physical line: the two header-name scalars occupy seven UTF-8
// bytes. Independently authored coordinates distinguish column60 from
// byte-column65; the warning covers the complete Work declaration.
let inline = SourceBundle {
entry: "main.arcadia".into(),
files: BTreeMap::from([(
"main.arcadia".into(),
format!(
"arcadia 8;\r\nproject p \"港🌊\" id \"{}\" {{ oa_activity w \"Work\" id \"{}\" {{}} }}\r\n",
id(1),
id(2)
),
)]),
};
let inline_value = accepted(&inline);
assert_eq!(inline_value.warnings().len(), 1);
let inline_warning = &inline_value.warnings()[0];
assert_eq!(inline_warning.path, "main.arcadia");
assert_eq!(inline_warning.diagnostic.code, "unallocated_leaf");
assert_eq!(inline_warning.diagnostic.object_id, Some(id(2)));
assert_eq!(inline_warning.diagnostic.line, 2);
assert_eq!(inline_warning.diagnostic.column, 60);
assert_eq!(
inline_warning.diagnostic.span,
Span {
start: 76,
end: 141
}
);
let mut bad = bundle.clone();
*bad.files.get_mut("main.arcadia").unwrap() =
bad.files["main.arcadia"].replace("base 1;", "base true + 1;");
@@ -646,19 +675,32 @@ fn mapped_warning_path_copies_are_admitted_before_retention() {
assert_eq!(roomy.warnings().len(), 1);
assert_eq!(roomy.warnings()[0].diagnostic.code, "unnamed");
assert_eq!(roomy.warnings()[0].path, bundle.entry);
let profile = super::super::super::budget::Limits {
bytes: source.len(),
..super::super::super::budget::Limits::source8(language::ParseLimits::UNLIMITED)
};
let parsed = parse_with_profile(&bundle, ProjectLimits::default(), profile).unwrap();
let failure = match resolve(parsed) {
Ok(_) => panic!("truncated warnings or uncharged copied path"),
Err(e) => e,
};
assert_eq!(
failure.diagnostics[0].diagnostic.message,
"Source8 index/output byte limit exceeded."
);
// Retained syntax owns alias "p" (1 byte). The mapped warning owns path188
// + code "unnamed"7 + field "name"4 + message36 =235 additional bytes.
// A per-producer cap would accept235; their simultaneous live total is236.
assert_eq!(bundle.entry.len(), 188);
assert_eq!("Give the project a descriptive name.".len(), 36);
for (bytes, fits) in [(source.len(), false), (235, false), (236, true)] {
let profile = super::super::super::budget::Limits {
bytes,
..super::super::super::budget::Limits::source8(language::ParseLimits::UNLIMITED)
};
let parsed = parse_with_profile(&bundle, ProjectLimits::default(), profile).unwrap();
match resolve(parsed) {
Ok(value) => {
assert!(fits, "mapped diagnostics lost their live syntax overlap");
assert_eq!(value.warnings(), roomy.warnings());
assert_eq!(value.storage.live.text, 236);
}
Err(failure) => {
assert!(!fits, "exact total must fit: {failure:?}");
assert_eq!(
failure.diagnostics[0].diagnostic.message,
"Source8 index/output byte limit exceeded."
);
}
}
}
}
#[test]
@@ -796,20 +838,13 @@ fn retained_nested_record_policy_cannot_be_replaced_at_resolution() {
}
#[test]
fn shared_ordinary_construction_preserves_legacy_scratch_and_existing_errors() {
fn public_source3_and_source7_preserve_legacy_scratch_defaults_and_errors() {
let bundle = single(&format!("oa_activity w \"Work\" id \"{}\" {{}}", id(2)));
let parsed = parse(&bundle, ProjectLimits::default()).unwrap();
let file = &parsed.files[0];
let mut old = file.ordinary.header.as_ref().unwrap().project.clone();
old.schema_version = 3;
let aliases = BTreeMap::from([("p".into(), id(1)), ("w".into(), id(2))]);
let migrated = language::resolve_declarations(
old,
&file.ordinary.declarations,
&aliases,
language::ParseLimits::UNLIMITED,
)
.unwrap();
// Existing source3_bridge tests compare complete public source3/JSON3
// migration. This small shared-decoder regression uses that public wrapper
// too, retaining the independent exact Activity expectation below.
let old_source = bundle.files["main.arcadia"].replacen("arcadia 8;", "arcadia 3;", 1);
let migrated = language::parse_with_report(&old_source).unwrap();
assert_eq!(migrated.project.schema_version, SCHEMA_VERSION);
assert_eq!(
migrated.project.elements[&id(2)],
@@ -823,9 +858,11 @@ fn shared_ordinary_construction_preserves_legacy_scratch_and_existing_errors() {
}
);
let scenario = single(&format!("oa_scenario q \"Scenario\" id \"{}\" {{}}", id(2)));
let value = accepted(&scenario);
let scenario_source = scenario.files["main.arcadia"].replacen("arcadia 8;", "arcadia 7;", 1);
let value =
language::parse_limited(&scenario_source, language::ParseLimits::UNLIMITED).unwrap();
assert!(
matches!(value.project.elements[&id(2)].shared(), Some(SharedBody::Scenario { viewpoint: ScenarioViewpoint::MixedLegacy, steps, .. }) if steps.is_empty())
matches!(value.elements[&id(2)].shared(), Some(SharedBody::Scenario { viewpoint: ScenarioViewpoint::MixedLegacy, steps, .. }) if steps.is_empty())
);
let missing = single(&format!(
"node n id \"{}\" {{ diagram @d; }} diagram d \"D\" id \"{}\" {{}}",
@@ -833,7 +870,9 @@ fn shared_ordinary_construction_preserves_legacy_scratch_and_existing_errors() {
id(3)
));
assert_eq!(
rejected(&missing).diagnostics[0].diagnostic.message,
language::parse(&missing.files["main.arcadia"].replacen("arcadia 8;", "arcadia 7;", 1))
.unwrap_err()[0]
.message,
"Missing required field 'element'."
);
let conflict = single(&format!(
@@ -842,7 +881,9 @@ fn shared_ordinary_construction_preserves_legacy_scratch_and_existing_errors() {
id(3)
));
assert_eq!(
rejected(&conflict).diagnostics[0].diagnostic.code,
language::parse(&conflict.files["main.arcadia"].replacen("arcadia 8;", "arcadia 7;", 1))
.unwrap_err()[0]
.code,
"conflicting_parent"
);
}