test-weak 技术文档
路径:
components/crate_interface/test_crates/test-weak类型:二进制 crate(独立测试工作区成员,publish = false) 分层:组件层 /crate_interface多 crate 测试矩阵 / 最终链接验证端 Rust 要求:nightly(依赖#![feature(linkage)]) 文档依据:components/crate_interface/test_crates/test-weak/Cargo.toml、components/crate_interface/test_crates/test-weak/src/main.rs、components/crate_interface/test_crates/Cargo.toml、components/crate_interface/test_crates/run_tests.sh、components/crate_interface/README.md、components/crate_interface/tests/test_weak_default.rs、components/crate_interface/Cargo.toml、Cargo.toml
test-weak 是 crate_interface weak_default 测试矩阵中负责“强覆盖优先级与混合解析”的最终链接/验证端。它把 define-weak-traits 提供的弱符号默认实现、impl-weak-traits 提供的覆盖型实现,以及调用侧断言逻辑真正收束到同一个 nightly 可执行文件里,借此观察链接器最终到底选择了强符号还是弱符号。与 components/crate_interface/tests/test_weak_default.rs 这样的最小功能测试相比,test-weak 验证的是更接近真实使用方式的跨 crate 链接结果。
1. 架构设计分析
1.1 在测试矩阵中的真实定位
test-weak 与 test-simple 一样,都是独立测试工作区里的资产,而不是正式产品组件:
- 仓库顶层
Cargo.toml将components/crate_interface/test_crates排除在主工作区之外 components/crate_interface/Cargo.toml也把test_crates排除在crate_interface自身工作区之外components/crate_interface/test_crates/Cargo.toml把整组测试 crate 统一设为publish = false
它的存在目的不是提供某种“运行时默认实现服务”,而是作为 weak_default 测试矩阵中的终端可执行体,验证强符号优先级、弱符号回退以及二者混合共存是否符合设计。
1.2 为什么它不是“纯完整实现测试”
虽然 test-weak 链接的是 impl-weak-traits,但这个二进制并不意味着“所有方法、所有接口都走强符号”:
FullImpl会完整覆盖WeakDefaultIfAllDefaultImpl只覆写method_a(),保留method_b()与method_c()的默认实现NamespacedWeakImpl只实现必需的get_id()CallerWeakImpl只实现compute()SelfRefFullImpl只覆写base_value()与transform(),其余衍生逻辑继续使用默认实现
因此,test-weak 的真实价值不是“证明某个 crate 能完全实现 trait”,而是证明在一个最终二进制里,强符号覆盖、弱符号保留与默认实现内部代理可以同时成立。
1.3 链接锚点设计
src/main.rs 用匿名常量块通过 std::any::type_name::<...>() 显式引用了:
FullImplAllDefaultImplNamespacedWeakImplCallerWeakImplSelfRefFullImpl
这些类型引用的作用不是实例化对象,而是确保实现侧符号稳定进入最终链接单元。没有这一步,测试可能会退化成“调用代码存在,但实现侧并未真实参与最终程序”。
1.4 覆盖场景矩阵
main() 依次运行 7 个测试函数,对应 define-weak-traits 中最重要的 nightly 风险面:
| 测试函数 | 覆盖对象 | 关注点 |
|---|---|---|
test_full_impl_required_methods() | WeakDefaultIf | 必需方法是否命中强符号实现 |
test_full_impl_overridden_defaults() | WeakDefaultIf | 默认方法被覆写后,强符号是否压过弱符号 |
test_all_default_interface() | AllDefaultIf | 同一接口里强弱符号能否混合共存 |
test_namespaced_weak_interface() | NamespacedWeakIf | namespace = WeakNs 与弱默认机制能否并存 |
test_caller_weak_interface() | CallerWeakIf | gen_caller 与默认回退是否一致工作 |
test_mixed_strong_and_weak() | AllDefaultIf | 混合解析在循环调用下是否稳定 |
test_self_ref_full() | SelfRefIf | 默认实现内部 Self:: 直接调用和函数引用是否正确转向强符号 |
其中 test_self_ref_full() 的技术含量最高,因为它不只验证“有没有覆盖”,还验证 Self::base_value() 与 let f = Self::transform 这两种代理路径在最终链接后是否都命中正确实现。
1.5 与其它测试的关系
components/crate_interface/tests/test_weak_default.rs 已经提供了一个最小的 weak_default 功能检查,但它的目的更接近“确认该 feature 能工作”。test-weak 则是下一层验证:
- 定义侧在一个 crate 中生成弱符号默认实现
- 实现侧在另一个 crate 中导出覆盖型强符号
- 最终二进制在第三个 crate 中观测强弱符号的解析结果
也就是说,它是 README 所描述的“跨 crate 定义/实现/调用模型”在 weak_default 场景下的最终证明。
2. 核心功能说明
2.1 主要能力
- 验证强符号在存在覆盖时能优先于弱符号默认实现
- 验证未覆写的方法仍可在同一二进制中回退到默认实现
- 验证
namespace与gen_caller不会破坏弱符号解析语义 - 验证默认实现内部
Self::直接调用与函数引用都能正确命中强覆盖版本