diff --git a/crates/oa-core/src/language/analysis_source/mixed/project/tests.rs b/crates/oa-core/src/language/analysis_source/mixed/project/tests.rs index fb2f8189..0c0ac1c1 100644 --- a/crates/oa-core/src/language/analysis_source/mixed/project/tests.rs +++ b/crates/oa-core/src/language/analysis_source/mixed/project/tests.rs @@ -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" ); }