From 2d3601a0a89c23fc186f306c2090588401aa0a39 Mon Sep 17 00:00:00 2001 From: mxsm Date: Wed, 12 Aug 2026 17:20:54 +0800 Subject: [PATCH] Publish the final CheetahString 3.1 architecture and performance audit --- API.md | 23 +- Cargo.toml | 1 + ...tring-architecture-performance-report.html | 645 ++++++++++++++++++ scripts/tests/test_repository_contracts.py | 6 +- 4 files changed, 668 insertions(+), 7 deletions(-) create mode 100644 cheetah-string-architecture-performance-report.html diff --git a/API.md b/API.md index 73d3f8a..b221cf3 100644 --- a/API.md +++ b/API.md @@ -1,8 +1,16 @@ # API compatibility -CheetahString 3.1 keeps the existing 3.x source surface while tightening the -private implementation. Public methods, traits, variants, aliases, and return -types are not removed or renamed in this release line. +CheetahString 3.1 keeps the stable 3.x source surface while tightening the +private implementation. Public stable methods, traits, variants, aliases, and +return types are not removed or renamed in this release line. + +There is one documented safety exception: the published +`experimental-packed` module was removed after strict-provenance Miri exposed +undefined behavior in its safe API. The Cargo feature name remains as a no-op +for dependency resolution, but code importing `cheetah_string::packed` must +migrate to `CheetahString` or `CheetahBuilder`. A registry comparison against +3.0.0 therefore reports the expected removal of the experimental module, its +constant, and `PackedCheetahString`. ## Pattern contract @@ -46,9 +54,12 @@ expressions. ## Automated compatibility gate `.github/workflows/api-compatibility.yml` runs `cargo-semver-checks` with -minor-release rules against `origin/main` and all features. The repository also -compiles a downstream-style test that calls the hidden compatibility method and -checks the exact constructor and substring result types. +minor-release rules against `origin/main` and all features. This protects each +new pull request after the packed retirement baseline; it does not conceal the +approved experimental safety removal relative to the published 3.0.0 crate. +The repository also compiles a downstream-style test that calls the hidden +compatibility method and checks the exact constructor and substring result +types. Local reproduction: diff --git a/Cargo.toml b/Cargo.toml index 1759581..c938dcc 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,6 +14,7 @@ description = """ An immutable, clone-cheap UTF-8 string with explicit construction and byte interoperability """ exclude = [ + "docs/**", "bench-results/packed-evidence/**", "bench-results/usage-inventory/**", "bench-results/base/**", diff --git a/cheetah-string-architecture-performance-report.html b/cheetah-string-architecture-performance-report.html new file mode 100644 index 0000000..dad6111 --- /dev/null +++ b/cheetah-string-architecture-performance-report.html @@ -0,0 +1,645 @@ + + + + + + + CheetahString 3.1 架构与性能复审 · 95/100 + + + + + +
+
+
+
+
Architecture × Performance × Evidence
+

CheetahString
深度审计

+

3.1 已把最初审计中的安全、布局、MSRV、分配、API 与发布证据缺口逐项闭合:保持 23B SSO 与 Arc<str> 克隆语义,同时用安全 Rust niche 将对象压到 24B。它仍不是所有写入型负载上的 String 替代品,但已具备可验证的发布级工程闭环。

+
+ 203 / 203 Rust tests + 24B object + 23B SSO + 61 Miri tests + Rust 1.95 matrix: PASS + stable API gate: PASS +
+
+
+
95/ 100 · 综合评分
+
+
+
+ +
+
+
+
00 / VERDICT
+

结论先行

评分对象是合并后的完整 3.1 仓库。置信度:高;布局、分配、MSRV 与 API 结论由门禁证明,Criterion 时序仍只作为本机诊断。

+
+
建议使用:协议字段、路由键、缓存键等“构造一次、读取和克隆很多次”的 UTF-8 值;已有长 Arc<str> 可零拷贝接管。
保留 String持续追加、频繁变换、一次性消费,或必须保留 spare capacity 的写入路径。
+
+
核心架构
成熟

Inline / Static / Shared 三态、Builder 写入边界、byte/text 所有权与私有 pattern dispatch 相互一致;兼容 shim 不参与内部实现。

+
性能画像
可预测

24B 槽位与 String 等大;长 clone、Arc<str> adoption、char 与短 concat 均为 0 allocation。长 freeze/transform 仍需复制。

+
发布成熟度
闭环

5 套工作流覆盖 MSRV、文档、Miri、fuzz build、audit、性能和 semver;发布在校验与 digest 检查后才创建 tag。

+
+
+
+ +
+
+
+
01 / SCORE
+

100 分评分账本

权重向架构与性能倾斜(合计 55 分);每一处扣分都能落到源码、命令结果或本机测量。

+
+
+
核心架构与 API三态模型、模块职责、3.1 兼容面
24/25
+
运行时性能克隆、搜索、构造、真实形状负载
28/30
+
内存与分配24B 对象、23B SSO、freeze、共享边界
15/15
+
正确性与安全测试、Miri、unsafe、feature 风险
14/15
+
工程证据与发布CI、MSRV、文档、可复现性、供应链
14/15
+
+

总分 95/100。仍使用最初报告的独立 rubric:退役存在 UB 的实验 packed API、兼容 shim 与既有 Error 聚合模型合计扣 1 分;长 transform/substring/freeze 的复制成本扣 2 分;CI 只编译 fuzz target、尚无持续限时 fuzz 执行扣 1 分;跨机器时序没有固定 CPU 阻断门禁再扣 1 分。评分不依赖已删除的旧自评分脚本。

+
+
+ +
+
+
+
02 / ARCH
+

架构:用不可变性买下确定的克隆成本

根模块是薄门面,核心类型再按 construct / convert / query / pattern / repr / traits 分层。真正的架构中心不是 SSO,而是“构造历史不能改变 clone 复杂度”。

+
+ +
+
+
+
&str / String / Arc<str> / Vec<u8>safe bytes 先做 UTF-8 validation
+
CheetahBuilderString 承担 mutation / reserve / clear
+
&'static str显式 static constructor
+
+
+
+
length / ownership gate普通构造:≤23B inline;长值 freeze
+
finish()mutable → immutable;长值复制进 Arc<str>
+
from_static_str()无论长度,直接选择 Static
+
+
+
+
Inline受限 len enum + [u8; 23] · 0 heap alloc
+
Static&'static str · 0 heap alloc
+
SharedArc<str> · clone = atomic refcount
+
+
+
+ +
+

设计已闭合的部分

  • 稳定表示只有 Inline / Static / Shared 三态,字段私有,文本语义统一。
  • Builder 把可变容量从 value type 剥离,避免构造历史改变 clone 复杂度。
  • From<Arc<str>> 对长值保留 payload pointer;短值仍 canonicalize 为 Inline。
  • lines() 暴露 DoubleEnded / Clone / Fused;char 与 string split 在类型层表达能力。
  • pattern 查询使用私有 sealed classifier;3.1 兼容方法仅作为桥接面保留。
  • 错误返回矩阵、静态优先级和复制边界已在 API.md 中明确。
+

仍保留的架构权衡

  • 显式 from_static_str 总是 Static,而非按长度 Inline;这是记录清楚的 ownership 优先规则。
  • from(String)finish() 必须把可变 payload 冻结为 Arc<str>,不能做到零复制。
  • substring 产生独立值,不保存 shared slice 的 offset/length,因此长片段需分配复制。
  • 3.1 为源码兼容继续保留隐藏 pattern dispatch 与 umbrella Error;内部实现已与其解耦。
  • experimental-simd 的收益依操作和长度而异,保持默认关闭。
+
+ +
“零分配克隆/接管”不等于“所有构造零成本”。Arc<str> adoption 为 0 allocation;长 borrowed / exact-capacity String freeze 为 1 次;spare-capacity String / Builder freeze 为 2 次。三条路径都由直接计数契约和 schema-v3 benchmark evidence 验证,而非同构推断。
+ +

稳定复杂度模型

+
+ + + + + + + + + + +
操作Inline / StaticShared架构含义
cloneO(1),复制有界 24B / 指针O(1),Arc 原子计数0 allocation;长值 payload pointer 不变
as_str / lenO(1)O(1)一次 enum dispatch,可内联
from(&str)O(k≤23),0 allocO(n),1 live allocation长 borrowed input 复制进 Arc
from(Arc<str>)O(k≤23),0 allocO(1),0 alloc长值 ownership-preserving;pointer 不变
from(String) / finishO(k≤23),结果 inlineO(n),1–2 allocation eventsspare capacity 先 shrink/realloc
substringO(k),复制O(k),长结果 1 alloc不是 shared slice
Add / transform≤23B concat 直接栈上,0 allocO(n+m);长结果经 String freeze长变换通常应先保留 String/Builder
+
+
+ +
+
+
+
03 / PERF
+

性能:读多写少模型成立,构造边界仍需按负载取舍

当前提交的 Criterion 本地诊断:Windows 11 / i7-11700K / rustc 1.96.1。评分只依赖可重复的布局与分配契约;未固定频率、CPU affinity 与双向 base/head 的纳秒数据只用于解释趋势。

+
+ +
+
1 KiB clone
26.49 ns

String 为 246.10 ns,本机约 9.29×;共享长值 clone 为 O(1) 且零分配。

+
25B borrowed construction
55.75 ns

String 为 40.69 ns;刚越过 23B inline 边界时,本机 median 慢约 37%

+
10k × 25B topic insert
653.37 µs

String 为 614.94 µs;本机 median 差约 6.3%,95% CI 重叠,判定为近似持平。

+
+ +

克隆曲线:23B 内联是有界复制,长值是常数时间共享

+
+
+
+
10B · Cheetah
18.28 ns
+
10B · String
31.01 ns
+
23B · Cheetah
27.25 ns
+
23B · String
46.28 ns
+
24B · Cheetah
19.14 ns
+
24B · String
40.55 ns
+
1KiB · Cheetah
26.49 ns
+
1KiB · String
246.10 ns
+
+

前六条以 60 ns 为满刻度;1KiB 两条以 246.10 ns 为满刻度。精确值见右表。

+
+
+ + + + + + + + +
payloadCheetah cloneString clone判断
10 B18.277 ns31.010 ns快约 41%
23 B27.245 ns46.283 ns快约 41%
24 B19.136 ns40.545 ns快约 53%
100 B23.262 ns69.200 ns快约 66%
1 KiB26.494 ns246.10 ns9.29× 快
+
+
可重复证据:长值 clone 在分配计数器下为 0 allocation,且 clone 前后 payload 指针一致。短值 clone 最多复制 23B;长值只增加 Arc<str> 的原子引用计数。
+ +

构造与冻结:零拷贝入口已补齐,SSO 边界仍可观察

+
+
From<Arc<str>> · long
0 alloc

转换复用原 payload 指针;这是调用方已有共享字符串时的真实零拷贝入口。

+
1KiB freeze
1 / 2 alloc

exact-capacity 输入 1 次、1040B;spare-capacity 输入 2 次、2064B。写入侧仍为 O(n) 冻结。

+
+
+ + + + + + + + +
borrowed inputCheetahString::fromString::from本机判断
23 B28.884 ns46.666 ns内联,快约 38%
24 B54.287 ns34.819 ns进入 Shared,慢约 56%
25 B55.754 ns40.688 ns慢约 37%
100 B73.848 ns70.509 ns近似持平
1 KiB295.22 ns295.64 ns近似持平
+ +

Schema v3:确定性分配证据

+
+ + + + + + + + +
操作allocation eventsallocated bytes契约
1KiB borrowed → Shared11040一次共享 backing 分配
1KiB owned exact → Shared11040冻结复制到最终 backing
1KiB owned spare → Shared22064收缩/复制成本显式可见
long Arc<str> adoption00payload pointer reused
Shared clone / char / short concat00三个热路径均有回归门禁
+ +
RocketMQ 形状已接近持平。10,000 个 25B topic 插入的 median:CompactString 580.14 µs、String 614.94 µs、CheetahString 653.37 µs、Arc<str> 666.42 µs。Cheetah 比 String 慢约 6.3%,但两者 95% CI 重叠;24B 槽位消除了旧 32B 表示的密度劣势。随机 hash seed 与本机噪声仍使该结果只适合作为诊断,不作为发布硬门。
+ +

搜索与 SIMD:代码路径保守,历史基线仅作方向性参考

+
+

memchr/memmem + Finder

空 needle 为 O(1),单字节走 memchr,多字节走 memmem;重复查询可复用预构建 Finder。该路径在 3.1 未改变,初始审计中 64KiB 末尾单字节诊断为 613 ns,而 str::find 为 36.5 µs。

+

实验 SSE2 默认关闭

初始诊断呈混合结果:16B equality 明显受益,但 starts_with 和部分中等长度 equality 退化。3.1 修复 Rust 1.95 编译边界但未把 SIMD 设为默认;这一决策与证据一致。

+
+

搜索与 SIMD 数值来自初始审计基线,不混入当前 95 分评分。启用 SIMD 前仍应按 CPU family、操作和长度校准,并保留 portable fallback。

+
+
+ +
+
+
+
04 / MEMORY
+

内存布局:安全 24B 表示保留完整 23B SSO

私有的受约束长度枚举为三态表示提供安全 niche;64 位与 32 位布局快照都把 CheetahStringOption<CheetahString> 固定在 24B,未引入整数化指针。

+
+
+
+
+
CheetahString
24 B
+
Option<Cheetah>
24 B
+
String
24 B
+
Arc<str>
16 B
+
&str
16 B
+
+
+

容器级含义

100 万个元素只算对象槽位:Cheetah 与 String 都约 22.9 MiB。相对旧 32B 表示,Cheetah 每百万元素节省约 7.6 MiB;10,000 项的确定性证据为 240,000B,对照旧表示为 320,000B。

HashMap 中 (CheetahString, usize)(String, usize) 的 payload 均为 32B。这个结果同时保留 23B SSO、Option niche 与稳定指针 provenance。

+
+

来源:LAYOUT.mdtests/layout_snapshot.rs 与 schema-v3 allocation evidence;CI 在原生 i686 target 上运行 32 位布局测试。

+
+
+ +
+
+
+
05 / SAFETY
+

安全:问题表示已退役,稳定 24B 路径通过 provenance 验证

3.1 不再公开旧 packed 模块;兼容 feature 名仅为空操作。当前 24B 表示使用 Safe Rust 的枚举 niche,稳定 unsafe 边界集中记录并由 Miri、审计和全特性测试共同约束。

+
+ +
+
Rust tests
203/203

171 unit/integration + 32 doctests;all-features 全过。

+
Miri matrix
61 pass

lib 4、API 3、basic 47、bytes 7,覆盖三种 storage mode 与转换边界。

+
Supply chain
0 findings

74 个依赖;本地 advisory database 中无漏洞或 warning。

+
+ +
P2

将 fuzz 从“可构建”提升为持续执行

Safety workflow 会编译两个稳定 fuzz target,但当前证据没有固定时长的自动 corpus 执行。字符编码和 bytes 转换边界适合增加 Linux sanitizer runner 与定时任务。

残余风险:输入空间
safety.yml
fuzz_targets/
+
P2

为时延回归准备固定硬件基线

布局与分配已是确定性硬门,但 Criterion 时延仍受本机频率、后台负载和 hash seed 影响。若要阻断时延回归,需要固定 runner、base/head 交错轮次和原始 artifact。

残余风险:性能漂移
performance.yml
+
P3

继续隔离 3.1 兼容 surface

旧 pattern dispatch 和 umbrella Error 为不升级大版本而保留,但内部查询已不再依赖公开 dispatch,并有下游 API 合约与 semver 基线。未来删除必须留到主版本。

残余风险:演进成本
API.md
+ +
安全结论:旧 packed safe API 已从发布 surface 移除;experimental-packed 仅保留为 3.1 兼容 no-op feature。内部 unchecked helper 已改成真实 unsafe fn 边界,每个调用点必须给出局部证明;SAFETY.md 集中记录稳定不变量和 Miri 矩阵。
+
+
+ +
+
+
+
06 / EVIDENCE
+

工程质量:证据链闭合,发布路径 fail-closed

3.1 将测试、文档、MSRV、Miri、供应链、API 兼容和确定性性能证据拆成五个固定 SHA 的 workflow。README、crate metadata 与实际门禁一致,发布验证先于 tag 和 publish。

+
+ +
+ + + + + + + + + + + + + + + +
验证结果事实判断
cargo test --all-featuresPASS203/203171 unit/integration + 32 doctests
cargo clippy --all-targets --all-features -- -D warningsPASS0 warnings现代工具链洁净
cargo fmt --all -- --checkPASSclean格式门禁正常
no_std + serde/bytes/simd matrixPASSstable + Rust 1.95功能组合可构建/测试
cargo packagePASS79 files · 394.3 KiB发布包自包含且排除未跟踪 docs
Miri matrixPASS61 tests三种表示与 API/bytes 边界通过
rustdoc -D warningsPASS22/22 documented;2/2 examplesdefault/no-default/all-features 均受控
Rust 1.95 packaged consumersPASSdefault + feature consumersMSRV 对发布包与 SIMD 成立
API compatibilityPASS*post-retirement baseline: 196 pass对 3.0.0 有 3 个已批准的实验安全移除
Python repository testsPASS24 testsworkflow 与证据 schema 自包含
cargo auditPASS0 vulnerabilities / 0 warnings无失维护的项目依赖
fuzz targetsPASS2 targets build编译有门;持续执行仍为改进项
+ +

当前证据链的四个支点

+
+

五类 workflow 分责

CI、Safety、Performance、API Compatibility 与 Release 分离,第三方 Actions 固定到完整 commit SHA,职责与 README 声明一致。

.github/workflows/

+

发布顺序 fail-closed

版本输入经环境变量与格式校验;fmt、Clippy、test、package 和内容校验全部通过后,才创建 tag 并发布。

release.yml

+

确定性性能 schema v3

布局、分配次数、分配字节、Arc 指针复用与 10k 容器密度由机器可读证据和 Python verifier 共同验证。

PERFORMANCE.md

+

文档与元数据同源

3.1.0、Rust 1.95、feature surface、安全边界与性能承诺在 Cargo metadata、README 和根级专题文档中一致。

README.md · Cargo.toml

+
+ +
工程结论:初始审计中的 MSRV、Miri、rustdoc、依赖、文档和发布顺序缺陷均已有自动门禁。当前主要工程缺口不再是“证据是否存在”,而是把 fuzz 动态执行与固定硬件时延基线提升到同等可重复级别。
+
+
+ +
+
+
+
07 / ROADMAP
+

从 95 分继续收敛:强化连续证据,不扩大 3.1 surface

安全退役、24B 表示、MSRV、发布与 API 门禁已经落地。后续工作应围绕可重复测量和写入侧成本展开;兼容性清理不在 3.1 内破坏式推进。

+
+
+

持续执行 fuzz corpus

  • 在 Linux sanitizer runner 上定时执行两个稳定 target,而不只验证可编译。
  • 保存 crash artifact、seed corpus 与最小化输入,并把重现命令写入 Safety workflow。
  • 优先覆盖 UTF-8 边界、共享转换、substring range 与 clone/drop 交错。
+

建立固定硬件时延基线

  • 使用固定 CPU runner、锁定频率与 affinity,交错执行 base/head。
  • 上传 Criterion 原始 artifact、环境指纹与置信区间,不用单次 geomean 阻断发布。
  • 布局与 allocation schema v3 继续作为跨 runner 的确定性硬门。
+

优化写入侧长值路径

  • 对 upper/lower/replace/repeat 与 substring 分别测量中间 String 和 freeze copy。
  • 保持 From<Arc<str>> 零拷贝;为常见 exact/spare 容量分布建立真实 workload。
  • 只有在 API 语义清楚且 allocation contract 不退化时才引入专用 builder 快路径。
+

维持 3.1 兼容边界

  • 继续保留 deprecated pattern dispatch 与既有 Error 类型,不在 3.1 删除。
  • 内部实现保持依赖私有 classifier;通过 cargo-semver-checks 和 downstream contract 监控 surface。
  • 若未来允许主版本,再单独评估兼容 shim 与错误模型清理。
+
+
+
+ +
+
+
+
08 / METHOD
+

方法、范围与可复现命令

复审基线为 300b313c3217a46a470c9b590ffc9e80584e9759,最终报告通过独立 PR 合入。报告把机器可重复的测试、布局、分配、MSRV 和 API 合约与本机 Criterion 诊断严格分开;评分不依赖一次性纳秒结果。

+
+ +
+
环境

Windows NT 10.0.26200
x86_64-pc-windows-msvc
i7-11700K @ 3.60GHz
rustc/cargo 1.96.1
LLVM 22.1.2

+
仓库规模

15 src files / 2,326 lines
16 integration files / 1,764 lines
10 benchmarks / 1,934 lines
2 fuzz targets
5 workflows
3 normal deps at all-features

+
统计口径

Criterion 使用 median;95% CI 重叠时不作速度排名。代码行数不代表覆盖率,测试数量也不代替 property/fuzz coverage。评分扣分只对应仍可复现的残余风险。

+
+ +
核心验证命令
+ cargo fmt --all -- --check +cargo clippy --all-targets --all-features -- -D warnings +cargo test --all-features +cargo test --no-default-features --features serde,bytes +cargo check --no-default-features +RUSTDOCFLAGS="-D warnings" cargo doc --lib --all-features --no-deps +RUSTDOCFLAGS="-D warnings" cargo doc --lib --no-deps +cargo +1.95 check --lib --all-features +& scripts\check-msrv-package.ps1 -Msrv 1.95 -AllowDirty +cargo test --test allocation_contract --all-features -- --test-threads=1 +cargo test --test layout_snapshot --all-features -- --nocapture +cargo package --allow-dirty +python -m unittest discover -s scripts/tests -p "test_*.py" -v +
+
性能命令
+ cargo bench --bench shared_backing -- __allocation_evidence_only__ --noplot 2>&1 | Tee-Object target/allocation-evidence.log +python scripts/verify-allocation-evidence.py target/allocation-evidence.log +cargo bench --bench comprehensive -- size_scaling --warm-up-time 0.5 --measurement-time 1 --sample-size 30 --noplot +cargo bench --bench mq_topic -- mq_topic_insert --warm-up-time 0.5 --measurement-time 1 --sample-size 30 --noplot +

allocation evidence 是 schema-v3 硬门;Criterion 运行期间存在桌面后台负载,未固定 governor/affinity,也未做 base/head 双向轮次。CI 重叠的差异按“近似持平”处理。

+
+
Miri / 供应链 / 受限验证
+ cargo +nightly miri test --lib --no-default-features +cargo +nightly miri test --test api_contract --no-default-features +cargo +nightly miri test --test basic --no-default-features +cargo +nightly miri test --test bytes --features bytes +cargo audit --json +cargo +nightly fuzz build +

Miri 本地矩阵共 61 项通过。两个稳定 fuzz target 纳入编译门禁,但本轮不把“build pass”表述为动态 fuzz pass;cargo audit 基于本地更新后的 advisory database。

+
+ +

关键证据索引

+
+ + + + + + + + + + + + + +
主张一手证据
三态表示与 23B inlinerepr.rsinline.rs
24B provenance-safe layoutLAYOUT.mdlayout_snapshot.rs
Arc adoption / 构造 / 冻结construct.rsbuilder.rs
allocation schema v3allocation_contract.rsPERFORMANCE.md
memchr/memmem/Findersearch.rspattern.rs
MQ topic workloadmq_topic.rs
稳定 unsafe / retired featureSAFETY.mdfeature_contract.rs
3.1 API 与 error contractsAPI.mdapi_contract.rs
MSRV / feature 声明Cargo.tomlcheck-msrv-package.ps1
CI、安全、性能、API 与发布.github/workflows/
+
+
+ +
+
+
Independent repository re-audit · generated 2026-08-12
CheetahString v3.1.0 · baseline 300b313
+ +
+
+
+ + + + diff --git a/scripts/tests/test_repository_contracts.py b/scripts/tests/test_repository_contracts.py index caee0de..dec7ca2 100644 --- a/scripts/tests/test_repository_contracts.py +++ b/scripts/tests/test_repository_contracts.py @@ -121,7 +121,7 @@ def test_retired_score_governance_is_not_shipped(self) -> None: for path in retired: self.assertFalse((ROOT / path).exists(), path) - def test_docs_directory_is_not_tracked(self) -> None: + def test_docs_directory_is_not_tracked_or_packaged(self) -> None: tracked = subprocess.run( ["git", "ls-files", "docs"], cwd=ROOT, @@ -131,6 +131,10 @@ def test_docs_directory_is_not_tracked(self) -> None: ) self.assertEqual(tracked.stdout.strip(), "") + with (ROOT / "Cargo.toml").open("rb") as manifest_file: + manifest = tomllib.load(manifest_file) + self.assertIn("docs/**", manifest["package"]["exclude"]) + if __name__ == "__main__": unittest.main()