diff --git a/crates/frontend/tests/reader.rs b/crates/frontend/tests/reader.rs index 851a525..0e0e16c 100644 --- a/crates/frontend/tests/reader.rs +++ b/crates/frontend/tests/reader.rs @@ -60,7 +60,7 @@ fn strings_and_split_utf8_streams_produce_the_same_ast_and_exact_text() { // Reader 不剥除 BOM,词法器看到原始开头字符后才决定是否接受。 let bom = EndorReader::from_stream("", Cursor::new("\u{feff}1".as_bytes())).unwrap(); assert_eq!(bom.text(), "\u{feff}1"); - // 当前用例要求此阶段失败,随后检查具体类别、来源或底层原因,避免仅接受任意错误。 + // BOM 保留了三字节 UTF-8 编码,词法错误范围应恰好覆盖它,而不是 Reader 静默剥除。 let error = lex_source(&bom).unwrap_err(); assert_eq!(error.diagnostic.kind, DiagnosticKind::Lexical); assert_eq!(error.diagnostic.span.end, 3); @@ -71,7 +71,7 @@ fn strings_and_split_utf8_streams_produce_the_same_ast_and_exact_text() { fn source_diagnostics_keep_session_names_unicode_locations_and_original_offsets() { // 建立带来源名的原文快照,后续错误必须定位这份文本而非临时转换后的内容。 let source = EndorReader::from_text("", "\"日\" + )"); - // 当前用例要求此阶段失败,随后检查具体类别、来源或底层原因,避免仅接受任意错误。 + // 右括号没有对应表达式,语法失败仍需按含日文字符的完整原文计算列号和跨度。 let error = parse_source_expression(&source).unwrap_err(); assert_eq!(error.location.line, 1); assert_eq!(error.location.column, 7); @@ -87,7 +87,7 @@ fn source_diagnostics_keep_session_names_unicode_locations_and_original_offsets( // 建立带来源名的原文快照,后续错误必须定位这份文本而非临时转换后的内容。 let source = EndorReader::from_text("", "\r\n\"日\\q\""); - // 当前用例要求此阶段失败,随后检查具体类别、来源或底层原因,避免仅接受任意错误。 + // 第二行字符串含不支持的反斜杠转义,词法错误应保留 CRLF 后的行号和 Unicode 列。 let error = lex_source(&source).unwrap_err(); assert_eq!(error.diagnostic.kind, DiagnosticKind::Lexical); assert_eq!(error.location.line, 2); @@ -100,7 +100,7 @@ fn source_diagnostics_keep_session_names_unicode_locations_and_original_offsets( fn incomplete_or_invalid_utf8_is_rejected_without_replacement_characters() { // 覆盖无效起始字节、不完整 UTF-8 序列,以及一个合法 ASCII 前缀后的错误。 for bytes in [vec![0xff], vec![0xe6, 0x97], vec![b'a', 0xff]] { - // 当前用例要求此阶段失败,随后检查具体类别、来源或底层原因,避免仅接受任意错误。 + // 即使每次只读一个字节,聚合后非法 UTF-8 仍须作为读取编码错误拒绝,不能交给 lexer。 let error = EndorReader::from_stream("", OneByte(Cursor::new(bytes))).unwrap_err(); assert!(matches!(error.kind, SourceReadErrorKind::InvalidUtf8(_))); assert!(error.to_string().contains(": invalid UTF-8 at byte")); @@ -131,7 +131,7 @@ impl Read for FailingStream { #[test] /// 由 Rust 测试框架调用:读到一个有效字节后发生 IO 失败时仍整体失败,不向解析器提供半份快照。 fn a_failed_stream_never_returns_partially_read_source() { - // 当前用例要求此阶段失败,随后检查具体类别、来源或底层原因,避免仅接受任意错误。 + // 流先返回 x 后报错,Reader 必须整体传播 IO 失败,不能把已读前缀作为成功源码。 let error = EndorReader::from_stream("", FailingStream(false)).unwrap_err(); assert!(matches!(error.kind, SourceReadErrorKind::Io(_))); assert!(error.to_string().contains("stream failure")); @@ -182,13 +182,13 @@ fn file_sources_preserve_the_path_and_read_errors_are_not_lexical_errors() { assert!(parse_source(&source).is_ok()); // 单字节 0xff 不是 UTF-8,打开文件成功后应在解码阶段拒绝。 let invalid = SourceFile::new(&[0xff]); - // 当前用例要求此阶段失败,随后检查具体类别、来源或底层原因,避免仅接受任意错误。 + // 文件能打开但 0xff 无法解码,错误应带该文件路径并归为 InvalidUtf8。 let error = EndorReader::from_file(&invalid.0).unwrap_err(); assert!(matches!(error.kind, SourceReadErrorKind::InvalidUtf8(_))); assert!(error.to_string().contains(&invalid.0.display().to_string())); // 从基线路径换一个未创建的扩展名,验证文件不存在作为 IO 错误暴露。 let missing = file.0.with_extension("missing"); - // 当前用例要求此阶段失败,随后检查具体类别、来源或底层原因,避免仅接受任意错误。 + // 未创建的路径应返回 NotFound IO 原因,不能误分类为词法或编码失败。 let error = EndorReader::from_file(&missing).unwrap_err(); // 必须能解构出原始 IO 错误,之后检查 NotFound 或 PermissionDenied 的具体种类。 let SourceReadErrorKind::Io(error) = error.kind else { @@ -282,7 +282,7 @@ fn uri_snapshots_require_a_revision_and_preserve_it_in_source_diagnostics() { }; // 建立带来源名的原文快照,后续错误必须定位这份文本而非临时转换后的内容。 let source = EndorReader::from_endor(uri, &provider).unwrap(); - // 当前用例要求此阶段失败,随后检查具体类别、来源或底层原因,避免仅接受任意错误。 + // 已解析 URI 的字节是 UTF-8 但函数语法无效,解析诊断仍须显示 rev-one 来源。 let error = parse_source(&source).unwrap_err(); assert_eq!(error.origin, source.origin().clone()); assert!(error.to_string().contains("[revision rev-one]")); @@ -302,7 +302,7 @@ fn uri_snapshots_require_a_revision_and_preserve_it_in_source_diagnostics() { // 借用测试静态字节,load 时复制给 Reader 解码。 bytes: &[0xff], }; - // 当前用例要求此阶段失败,随后检查具体类别、来源或底层原因,避免仅接受任意错误。 + // 宿主已选择 rev-two 后才遇到非法 UTF-8,解码失败也必须保留该实际版本身份。 let error = EndorReader::from_endor(uri, &invalid).unwrap_err(); assert!(matches!(error.kind, SourceReadErrorKind::InvalidUtf8(_))); assert!(error.to_string().contains("[revision rev-two]")); @@ -344,7 +344,7 @@ fn invalid_uris_do_not_call_the_provider_and_denials_do_not_fall_back_to_files() )); } assert_eq!(provider.calls.get(), 0); - // 当前用例要求此阶段失败,随后检查具体类别、来源或底层原因,避免仅接受任意错误。 + // 基础 URI 合法但宿主拒绝访问,Reader 应保留 PermissionDenied,不尝试文件回退。 let error = EndorReader::from_endor("endor:anywhere", &DeniedProvider).unwrap_err(); // 必须能解构出原始 IO 错误,之后检查 NotFound 或 PermissionDenied 的具体种类。 let SourceReadErrorKind::Io(error) = error.kind else { diff --git a/crates/objects/tests/attribute_storage.rs b/crates/objects/tests/attribute_storage.rs index 0267331..6c7e83c 100644 --- a/crates/objects/tests/attribute_storage.rs +++ b/crates/objects/tests/attribute_storage.rs @@ -16,7 +16,7 @@ impl ObjectPayload for Proxy { fn kind_name(&self) -> &'static str { "proxy" } - /// Heap 分配/替换时记录一条拥有边,确保被代理存储或自引用 Cell 存活。 + /// Heap 分配/替换 Proxy 时记录后端存储边,释放门面或改指后端时归还该边。 fn trace(&self, visit: &mut dyn FnMut(ObjectRef)) { visit(self.0); } @@ -107,7 +107,7 @@ fn cyclic_and_foreign_attribute_storage_fail_without_mutating_fields() { // 异堆即使槽号相同也必须报 ForeignHandle,不当成普通缺字段。 let other = ObjectStore::new().unwrap(); assert_eq!(other.attribute_path(proxy), Err(VmError::ForeignHandle)); - // 归还后端外部根后仍由 Proxy 的载荷边维持存活。 + // Proxy 已改为自引用,不再持有 storage;归还其唯一外部根即可回收后端。 store.release(storage).unwrap(); store.release(proxy).unwrap(); // 外部根释放后只有 Proxy 自环残留,显式回收恰好一个对象。 @@ -130,7 +130,7 @@ impl ObjectPayload for ReflectiveType { fn allows_attributes(&self) -> bool { true } - /// Heap 分配/替换时记录一条拥有边,确保被代理存储或自引用 Cell 存活。 + /// Heap 分配反射载荷时记录 self_cell 强边,与稍后 Cell 反向持边构成测试环。 fn trace(&self, visit: &mut dyn FnMut(ObjectRef)) { visit(self.0); } diff --git a/crates/objects/tests/store.rs b/crates/objects/tests/store.rs index 0a14d1b..8d2daac 100644 --- a/crates/objects/tests/store.rs +++ b/crates/objects/tests/store.rs @@ -169,7 +169,7 @@ fn read_only_scopes_block_existing_container_and_type_writes_but_allow_fresh_res store.set_attr(fresh, "value", objects::Value::Nil).unwrap(); // Record 不原地赋值,只读引用重绑定可以返回 false 而不修改旧对象。 assert!(!store.assign_from(record, fresh).unwrap()); - // 嵌套层快照/区间只影响自身,结束必须按 LIFO。 + // 内层重新快照所有存活对象,fresh 此时也受保护;结束必须按 LIFO。 let nested = store.begin_read_only(); assert!( store @@ -206,12 +206,12 @@ fn read_tracking_regions_repeat_shared_reads_and_preserve_enclosing_dependencies // 第二对象仅在内层首次读取,外层集合也必须包含它。 let second = store.new_object().unwrap(); assert!(store.begin_read_tracking().is_err()); - // 进入时快照已有对象,之后分配的 fresh 不在本层保护集合。 + // 进入时把 first、second 列为已有对象,后面的读取才会成为本层依赖。 let scope = store.begin_read_only(); // 外层区间开始后,其内所有读取都要包含在最终结果中。 let outer = store.begin_read_tracking().unwrap(); store.object(first).unwrap(); - // 嵌套层快照/区间只影响自身,结束必须按 LIFO。 + // 子区间嵌套不另建对象保护快照;其读取同时传播给 outer,结束仍须按 LIFO。 let nested = store.begin_read_tracking().unwrap(); store.object(first).unwrap(); store.object(second).unwrap(); @@ -232,8 +232,8 @@ fn read_tracking_regions_repeat_shared_reads_and_preserve_enclosing_dependencies // 整个调用结束后未完成区间已丢弃,不能再拿旧令牌结束。 assert!(store.end_read_tracking(1).is_err()); assert!(!store.is_read_only()); - // 移除一函数仅减一条代码边,另一函数仍保留代码和常量。 + // first 没有内部拥有边,归还唯一外部根后可立即回收;借用读取记录不会保活它。 store.release(first).unwrap(); - // 最后一个函数释放后,代码/全局/常量无根链一起回收。 + // second 同样独立归还唯一根;本场景没有函数、代码对象或对象互引环。 store.release(second).unwrap(); }