From c7a9c43b5bfdda7c3869ac461f03d043e5b1e3b7 Mon Sep 17 00:00:00 2001 From: Valentin Popov Date: Tue, 30 Jun 2026 02:47:24 +0400 Subject: [PATCH] test(inspection): cover archive diagnostic span context --- crates/fparkan-inspection/src/lib.rs | 22 ++++++++++++++++++---- fixtures/acceptance/coverage.tsv | 2 +- 2 files changed, 19 insertions(+), 5 deletions(-) diff --git a/crates/fparkan-inspection/src/lib.rs b/crates/fparkan-inspection/src/lib.rs index 7fce95e..519490c 100644 --- a/crates/fparkan-inspection/src/lib.rs +++ b/crates/fparkan-inspection/src/lib.rs @@ -21,7 +21,7 @@ //! Shared inspection helpers for format-backed tooling. use fparkan_diagnostics::{ - diagnostic, render_human, Diagnostic, DiagnosticCode, DiagnosticContext, Phase, + diagnostic, render_human, Diagnostic, DiagnosticCode, DiagnosticContext, Phase, SourceSpan, }; use fparkan_msh::{decode_msh, validate_msh, ModelAsset}; use fparkan_nres::{decode as decode_nres, NresDocument, ReadProfile}; @@ -215,7 +215,7 @@ fn inspect_archive_bytes( Arc::from(bytes.to_vec().into_boxed_slice()), ReadProfile::Compatible, ) - .map_err(|err| archive_parse_diagnostic("S1.NRES.DECODE", source, err.to_string()))?; + .map_err(|err| archive_parse_diagnostic("S1.NRES.DECODE", source, bytes, err.to_string()))?; let mut sample = Vec::new(); for entry in document.entries().iter().take(sample_limit) { sample.push(NresEntrySummary { @@ -234,7 +234,7 @@ fn inspect_archive_bytes( Arc::from(bytes.to_vec().into_boxed_slice()), fparkan_rsli::ReadProfile::Compatible, ) - .map_err(|err| archive_parse_diagnostic("S1.RSLI.DECODE", source, err.to_string()))?; + .map_err(|err| archive_parse_diagnostic("S1.RSLI.DECODE", source, bytes, err.to_string()))?; Ok(ArchiveInspection::Rsli { entries: document.entries().len(), }) @@ -242,6 +242,7 @@ fn inspect_archive_bytes( Err(archive_parse_diagnostic( "S1.RESOURCE.UNSUPPORTED_ARCHIVE", source, + bytes, "unsupported archive magic".to_string(), )) } @@ -386,11 +387,16 @@ fn load_model_document_from_root( fn archive_parse_diagnostic( code: &'static str, source: Option<&Path>, + bytes: &[u8], message: String, ) -> Diagnostic { diagnostic(DiagnosticCode(code), message).with_context(DiagnosticContext { phase: Some(Phase::Parse), path: source.map(|path| path.display().to_string()), + span: Some(SourceSpan { + offset: 0, + length: u64::try_from(bytes.len().min(4)).unwrap_or(4), + }), ..DiagnosticContext::default() }) } @@ -414,7 +420,7 @@ mod tests { } #[test] - fn archive_diagnostic_preserves_source_path() { + fn archive_diagnostic_preserves_source_path_phase_and_span() { let dir = temp_dir("inspect-diagnostic"); let path = dir.join("broken.nres"); fs::write(&path, b"NRes").expect("broken nres"); @@ -428,6 +434,14 @@ mod tests { diagnostic.context.path.as_deref(), Some(expected_path.as_str()) ); + assert_eq!(diagnostic.context.phase, Some(Phase::Parse)); + assert_eq!( + diagnostic.context.span, + Some(SourceSpan { + offset: 0, + length: 4 + }) + ); } #[test] diff --git a/fixtures/acceptance/coverage.tsv b/fixtures/acceptance/coverage.tsv index 3ec44f4..37a2891 100644 --- a/fixtures/acceptance/coverage.tsv +++ b/fixtures/acceptance/coverage.tsv @@ -154,7 +154,7 @@ S1-RES-004 covered cargo test -p fparkan-resource --offline entry_read_error_car S1-RES-005 covered cargo test -p fparkan-resource --offline archive_cache_evicts_by_byte_budget S1-RES-006 covered cargo test -p fparkan-resource --offline archive_cache_eviction_makes_old_handles_stale S1-RES-007 covered cargo test -p fparkan-resource --offline lossy_equivalent_archive_paths_remain_distinct -S1-DIAG-001 partial cargo test -p fparkan-inspection --offline archive_diagnostic_preserves_source_path; entry/span coverage is still missing +S1-DIAG-001 partial cargo test -p fparkan-inspection --offline archive_diagnostic_preserves_source_path_phase_and_span; archive_entry coverage is still missing S1-VFS-001 covered cargo test -p fparkan-vfs --offline memory_vfs_uses_exact_lookup S1-VFS-002 covered cargo test -p fparkan-vfs --offline overlay_vfs_uses_first_matching_layer S1-VFS-003 covered cargo test -p fparkan-vfs --offline directory_vfs_resolves_ascii_casefolded_segments