@hasna/terminal 2.3.0 → 2.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (202) hide show
  1. package/dist/cli.js +64 -16
  2. package/package.json +1 -1
  3. package/src/ai.ts +8 -0
  4. package/src/cli.tsx +57 -18
  5. package/src/output-processor.ts +6 -1
  6. package/src/output-store.ts +58 -12
  7. package/src/tool-profiles.ts +139 -0
  8. package/temp/rtk/.claude/agents/code-reviewer.md +0 -221
  9. package/temp/rtk/.claude/agents/debugger.md +0 -519
  10. package/temp/rtk/.claude/agents/rtk-testing-specialist.md +0 -461
  11. package/temp/rtk/.claude/agents/rust-rtk.md +0 -511
  12. package/temp/rtk/.claude/agents/technical-writer.md +0 -355
  13. package/temp/rtk/.claude/commands/diagnose.md +0 -352
  14. package/temp/rtk/.claude/commands/test-routing.md +0 -362
  15. package/temp/rtk/.claude/hooks/bash/pre-commit-format.sh +0 -16
  16. package/temp/rtk/.claude/hooks/rtk-rewrite.sh +0 -70
  17. package/temp/rtk/.claude/hooks/rtk-suggest.sh +0 -152
  18. package/temp/rtk/.claude/rules/cli-testing.md +0 -526
  19. package/temp/rtk/.claude/skills/issue-triage/SKILL.md +0 -348
  20. package/temp/rtk/.claude/skills/issue-triage/templates/issue-comment.md +0 -134
  21. package/temp/rtk/.claude/skills/performance.md +0 -435
  22. package/temp/rtk/.claude/skills/pr-triage/SKILL.md +0 -315
  23. package/temp/rtk/.claude/skills/pr-triage/templates/review-comment.md +0 -71
  24. package/temp/rtk/.claude/skills/repo-recap.md +0 -206
  25. package/temp/rtk/.claude/skills/rtk-tdd/SKILL.md +0 -78
  26. package/temp/rtk/.claude/skills/rtk-tdd/references/testing-patterns.md +0 -124
  27. package/temp/rtk/.claude/skills/security-guardian.md +0 -503
  28. package/temp/rtk/.claude/skills/ship.md +0 -404
  29. package/temp/rtk/.github/workflows/benchmark.yml +0 -34
  30. package/temp/rtk/.github/workflows/dco-check.yaml +0 -12
  31. package/temp/rtk/.github/workflows/release-please.yml +0 -51
  32. package/temp/rtk/.github/workflows/release.yml +0 -343
  33. package/temp/rtk/.github/workflows/security-check.yml +0 -135
  34. package/temp/rtk/.github/workflows/validate-docs.yml +0 -78
  35. package/temp/rtk/.release-please-manifest.json +0 -3
  36. package/temp/rtk/ARCHITECTURE.md +0 -1491
  37. package/temp/rtk/CHANGELOG.md +0 -640
  38. package/temp/rtk/CLAUDE.md +0 -605
  39. package/temp/rtk/CONTRIBUTING.md +0 -199
  40. package/temp/rtk/Cargo.lock +0 -1668
  41. package/temp/rtk/Cargo.toml +0 -64
  42. package/temp/rtk/Formula/rtk.rb +0 -43
  43. package/temp/rtk/INSTALL.md +0 -390
  44. package/temp/rtk/LICENSE +0 -21
  45. package/temp/rtk/README.md +0 -386
  46. package/temp/rtk/README_es.md +0 -159
  47. package/temp/rtk/README_fr.md +0 -197
  48. package/temp/rtk/README_ja.md +0 -159
  49. package/temp/rtk/README_ko.md +0 -159
  50. package/temp/rtk/README_zh.md +0 -167
  51. package/temp/rtk/ROADMAP.md +0 -15
  52. package/temp/rtk/SECURITY.md +0 -217
  53. package/temp/rtk/TEST_EXEC_TIME.md +0 -102
  54. package/temp/rtk/build.rs +0 -57
  55. package/temp/rtk/docs/AUDIT_GUIDE.md +0 -432
  56. package/temp/rtk/docs/FEATURES.md +0 -1410
  57. package/temp/rtk/docs/TROUBLESHOOTING.md +0 -309
  58. package/temp/rtk/docs/filter-workflow.md +0 -102
  59. package/temp/rtk/docs/images/gain-dashboard.jpg +0 -0
  60. package/temp/rtk/docs/tracking.md +0 -583
  61. package/temp/rtk/hooks/opencode-rtk.ts +0 -39
  62. package/temp/rtk/hooks/rtk-awareness.md +0 -29
  63. package/temp/rtk/hooks/rtk-rewrite.sh +0 -61
  64. package/temp/rtk/hooks/test-rtk-rewrite.sh +0 -442
  65. package/temp/rtk/install.sh +0 -124
  66. package/temp/rtk/release-please-config.json +0 -10
  67. package/temp/rtk/scripts/benchmark.sh +0 -592
  68. package/temp/rtk/scripts/check-installation.sh +0 -162
  69. package/temp/rtk/scripts/install-local.sh +0 -37
  70. package/temp/rtk/scripts/rtk-economics.sh +0 -137
  71. package/temp/rtk/scripts/test-all.sh +0 -561
  72. package/temp/rtk/scripts/test-aristote.sh +0 -227
  73. package/temp/rtk/scripts/test-tracking.sh +0 -79
  74. package/temp/rtk/scripts/update-readme-metrics.sh +0 -32
  75. package/temp/rtk/scripts/validate-docs.sh +0 -73
  76. package/temp/rtk/src/aws_cmd.rs +0 -880
  77. package/temp/rtk/src/binlog.rs +0 -1645
  78. package/temp/rtk/src/cargo_cmd.rs +0 -1727
  79. package/temp/rtk/src/cc_economics.rs +0 -1157
  80. package/temp/rtk/src/ccusage.rs +0 -340
  81. package/temp/rtk/src/config.rs +0 -187
  82. package/temp/rtk/src/container.rs +0 -855
  83. package/temp/rtk/src/curl_cmd.rs +0 -134
  84. package/temp/rtk/src/deps.rs +0 -268
  85. package/temp/rtk/src/diff_cmd.rs +0 -367
  86. package/temp/rtk/src/discover/mod.rs +0 -274
  87. package/temp/rtk/src/discover/provider.rs +0 -388
  88. package/temp/rtk/src/discover/registry.rs +0 -2022
  89. package/temp/rtk/src/discover/report.rs +0 -202
  90. package/temp/rtk/src/discover/rules.rs +0 -667
  91. package/temp/rtk/src/display_helpers.rs +0 -402
  92. package/temp/rtk/src/dotnet_cmd.rs +0 -1771
  93. package/temp/rtk/src/dotnet_format_report.rs +0 -133
  94. package/temp/rtk/src/dotnet_trx.rs +0 -593
  95. package/temp/rtk/src/env_cmd.rs +0 -204
  96. package/temp/rtk/src/filter.rs +0 -462
  97. package/temp/rtk/src/filters/README.md +0 -52
  98. package/temp/rtk/src/filters/ansible-playbook.toml +0 -34
  99. package/temp/rtk/src/filters/basedpyright.toml +0 -47
  100. package/temp/rtk/src/filters/biome.toml +0 -45
  101. package/temp/rtk/src/filters/brew-install.toml +0 -37
  102. package/temp/rtk/src/filters/composer-install.toml +0 -40
  103. package/temp/rtk/src/filters/df.toml +0 -16
  104. package/temp/rtk/src/filters/dotnet-build.toml +0 -64
  105. package/temp/rtk/src/filters/du.toml +0 -16
  106. package/temp/rtk/src/filters/fail2ban-client.toml +0 -15
  107. package/temp/rtk/src/filters/gcc.toml +0 -49
  108. package/temp/rtk/src/filters/gcloud.toml +0 -22
  109. package/temp/rtk/src/filters/hadolint.toml +0 -24
  110. package/temp/rtk/src/filters/helm.toml +0 -29
  111. package/temp/rtk/src/filters/iptables.toml +0 -27
  112. package/temp/rtk/src/filters/jj.toml +0 -28
  113. package/temp/rtk/src/filters/jq.toml +0 -24
  114. package/temp/rtk/src/filters/make.toml +0 -41
  115. package/temp/rtk/src/filters/markdownlint.toml +0 -24
  116. package/temp/rtk/src/filters/mix-compile.toml +0 -27
  117. package/temp/rtk/src/filters/mix-format.toml +0 -15
  118. package/temp/rtk/src/filters/mvn-build.toml +0 -44
  119. package/temp/rtk/src/filters/oxlint.toml +0 -43
  120. package/temp/rtk/src/filters/ping.toml +0 -63
  121. package/temp/rtk/src/filters/pio-run.toml +0 -40
  122. package/temp/rtk/src/filters/poetry-install.toml +0 -50
  123. package/temp/rtk/src/filters/pre-commit.toml +0 -35
  124. package/temp/rtk/src/filters/ps.toml +0 -16
  125. package/temp/rtk/src/filters/quarto-render.toml +0 -41
  126. package/temp/rtk/src/filters/rsync.toml +0 -48
  127. package/temp/rtk/src/filters/shellcheck.toml +0 -27
  128. package/temp/rtk/src/filters/shopify-theme.toml +0 -29
  129. package/temp/rtk/src/filters/skopeo.toml +0 -45
  130. package/temp/rtk/src/filters/sops.toml +0 -16
  131. package/temp/rtk/src/filters/ssh.toml +0 -44
  132. package/temp/rtk/src/filters/stat.toml +0 -34
  133. package/temp/rtk/src/filters/swift-build.toml +0 -41
  134. package/temp/rtk/src/filters/systemctl-status.toml +0 -33
  135. package/temp/rtk/src/filters/terraform-plan.toml +0 -35
  136. package/temp/rtk/src/filters/tofu-fmt.toml +0 -16
  137. package/temp/rtk/src/filters/tofu-init.toml +0 -38
  138. package/temp/rtk/src/filters/tofu-plan.toml +0 -35
  139. package/temp/rtk/src/filters/tofu-validate.toml +0 -17
  140. package/temp/rtk/src/filters/trunk-build.toml +0 -39
  141. package/temp/rtk/src/filters/ty.toml +0 -50
  142. package/temp/rtk/src/filters/uv-sync.toml +0 -37
  143. package/temp/rtk/src/filters/xcodebuild.toml +0 -99
  144. package/temp/rtk/src/filters/yamllint.toml +0 -25
  145. package/temp/rtk/src/find_cmd.rs +0 -598
  146. package/temp/rtk/src/format_cmd.rs +0 -386
  147. package/temp/rtk/src/gain.rs +0 -723
  148. package/temp/rtk/src/gh_cmd.rs +0 -1651
  149. package/temp/rtk/src/git.rs +0 -2012
  150. package/temp/rtk/src/go_cmd.rs +0 -592
  151. package/temp/rtk/src/golangci_cmd.rs +0 -254
  152. package/temp/rtk/src/grep_cmd.rs +0 -288
  153. package/temp/rtk/src/gt_cmd.rs +0 -810
  154. package/temp/rtk/src/hook_audit_cmd.rs +0 -283
  155. package/temp/rtk/src/hook_check.rs +0 -171
  156. package/temp/rtk/src/init.rs +0 -1859
  157. package/temp/rtk/src/integrity.rs +0 -537
  158. package/temp/rtk/src/json_cmd.rs +0 -231
  159. package/temp/rtk/src/learn/detector.rs +0 -628
  160. package/temp/rtk/src/learn/mod.rs +0 -119
  161. package/temp/rtk/src/learn/report.rs +0 -184
  162. package/temp/rtk/src/lint_cmd.rs +0 -694
  163. package/temp/rtk/src/local_llm.rs +0 -316
  164. package/temp/rtk/src/log_cmd.rs +0 -248
  165. package/temp/rtk/src/ls.rs +0 -324
  166. package/temp/rtk/src/main.rs +0 -2482
  167. package/temp/rtk/src/mypy_cmd.rs +0 -389
  168. package/temp/rtk/src/next_cmd.rs +0 -241
  169. package/temp/rtk/src/npm_cmd.rs +0 -236
  170. package/temp/rtk/src/parser/README.md +0 -267
  171. package/temp/rtk/src/parser/error.rs +0 -46
  172. package/temp/rtk/src/parser/formatter.rs +0 -336
  173. package/temp/rtk/src/parser/mod.rs +0 -311
  174. package/temp/rtk/src/parser/types.rs +0 -119
  175. package/temp/rtk/src/pip_cmd.rs +0 -302
  176. package/temp/rtk/src/playwright_cmd.rs +0 -479
  177. package/temp/rtk/src/pnpm_cmd.rs +0 -573
  178. package/temp/rtk/src/prettier_cmd.rs +0 -221
  179. package/temp/rtk/src/prisma_cmd.rs +0 -482
  180. package/temp/rtk/src/psql_cmd.rs +0 -382
  181. package/temp/rtk/src/pytest_cmd.rs +0 -384
  182. package/temp/rtk/src/read.rs +0 -217
  183. package/temp/rtk/src/rewrite_cmd.rs +0 -50
  184. package/temp/rtk/src/ruff_cmd.rs +0 -402
  185. package/temp/rtk/src/runner.rs +0 -271
  186. package/temp/rtk/src/summary.rs +0 -297
  187. package/temp/rtk/src/tee.rs +0 -405
  188. package/temp/rtk/src/telemetry.rs +0 -248
  189. package/temp/rtk/src/toml_filter.rs +0 -1655
  190. package/temp/rtk/src/tracking.rs +0 -1416
  191. package/temp/rtk/src/tree.rs +0 -209
  192. package/temp/rtk/src/tsc_cmd.rs +0 -259
  193. package/temp/rtk/src/utils.rs +0 -432
  194. package/temp/rtk/src/verify_cmd.rs +0 -47
  195. package/temp/rtk/src/vitest_cmd.rs +0 -385
  196. package/temp/rtk/src/wc_cmd.rs +0 -401
  197. package/temp/rtk/src/wget_cmd.rs +0 -260
  198. package/temp/rtk/tests/fixtures/dotnet/build_failed.txt +0 -11
  199. package/temp/rtk/tests/fixtures/dotnet/format_changes.json +0 -31
  200. package/temp/rtk/tests/fixtures/dotnet/format_empty.json +0 -1
  201. package/temp/rtk/tests/fixtures/dotnet/format_success.json +0 -12
  202. package/temp/rtk/tests/fixtures/dotnet/test_failed.txt +0 -18
@@ -1,526 +0,0 @@
1
- # CLI Testing Strategy
2
-
3
- Comprehensive testing rules for RTK CLI tool development.
4
-
5
- ## Snapshot Testing (🔴 Critical)
6
-
7
- **Priority**: 🔴 **Triggers**: All filter changes, output format modifications
8
-
9
- Use `insta` crate for output validation. This is the **primary testing strategy** for RTK filters.
10
-
11
- ### Basic Snapshot Test
12
-
13
- ```rust
14
- use insta::assert_snapshot;
15
-
16
- #[test]
17
- fn test_git_log_output() {
18
- let input = include_str!("../tests/fixtures/git_log_raw.txt");
19
- let output = filter_git_log(input);
20
-
21
- // Snapshot test - will fail if output changes
22
- assert_snapshot!(output);
23
- }
24
- ```
25
-
26
- ### Workflow
27
-
28
- 1. **Write test**: Add `assert_snapshot!(output);` in test
29
- 2. **Run tests**: `cargo test` (creates new snapshots on first run)
30
- 3. **Review snapshots**: `cargo insta review` (interactive review)
31
- 4. **Accept changes**: `cargo insta accept` (if output is correct)
32
-
33
- ### When to Use
34
-
35
- - **Every new filter**: All filters must have snapshot test
36
- - **Output format changes**: When modifying filter logic
37
- - **Regression detection**: Catch unintended changes
38
-
39
- ### Example Workflow
40
-
41
- ```bash
42
- # 1. Create fixture from real command
43
- git log -20 > tests/fixtures/git_log_raw.txt
44
-
45
- # 2. Write test with assert_snapshot!
46
- cat > src/git.rs <<'EOF'
47
- #[cfg(test)]
48
- mod tests {
49
- use insta::assert_snapshot;
50
-
51
- #[test]
52
- fn test_git_log_format() {
53
- let input = include_str!("../tests/fixtures/git_log_raw.txt");
54
- let output = filter_git_log(input);
55
- assert_snapshot!(output);
56
- }
57
- }
58
- EOF
59
-
60
- # 3. Run test (creates snapshot)
61
- cargo test test_git_log_format
62
-
63
- # 4. Review snapshot
64
- cargo insta review
65
- # Press 'a' to accept, 'r' to reject
66
-
67
- # 5. Snapshot saved in src/snapshots/git.rs.snap
68
- ```
69
-
70
- ## Token Accuracy Testing (🔴 Critical)
71
-
72
- **Priority**: 🔴 **Triggers**: All filter implementations, token savings claims
73
-
74
- All filters **MUST** verify 60-90% token savings claims with real fixtures.
75
-
76
- ### Token Count Test
77
-
78
- ```rust
79
- #[cfg(test)]
80
- mod tests {
81
- fn count_tokens(text: &str) -> usize {
82
- text.split_whitespace().count()
83
- }
84
-
85
- #[test]
86
- fn test_git_log_savings() {
87
- let input = include_str!("../tests/fixtures/git_log_raw.txt");
88
- let output = filter_git_log(input);
89
-
90
- let input_tokens = count_tokens(input);
91
- let output_tokens = count_tokens(&output);
92
-
93
- let savings = 100.0 - (output_tokens as f64 / input_tokens as f64 * 100.0);
94
-
95
- assert!(
96
- savings >= 60.0,
97
- "Git log filter: expected ≥60% savings, got {:.1}%",
98
- savings
99
- );
100
- }
101
- }
102
- ```
103
-
104
- ### Creating Fixtures
105
-
106
- **Use real command output**, not synthetic data:
107
-
108
- ```bash
109
- # Capture real output
110
- git log -20 > tests/fixtures/git_log_raw.txt
111
- cargo test 2>&1 > tests/fixtures/cargo_test_raw.txt
112
- gh pr view 123 > tests/fixtures/gh_pr_view_raw.txt
113
- pnpm list > tests/fixtures/pnpm_list_raw.txt
114
-
115
- # Then use in tests:
116
- # let input = include_str!("../tests/fixtures/git_log_raw.txt");
117
- ```
118
-
119
- ### Savings Targets by Filter
120
-
121
- | Filter | Expected Savings | Rationale |
122
- |--------|------------------|-----------|
123
- | `git log` | 80%+ | Condense commits to hash + message |
124
- | `cargo test` | 90%+ | Show failures only |
125
- | `gh pr view` | 87%+ | Remove ASCII art, verbose metadata |
126
- | `pnpm list` | 70%+ | Compact dependency tree |
127
- | `docker ps` | 60%+ | Essential fields only |
128
-
129
- **Release blocker**: If savings drop below 60% for any filter, investigate and fix before merge.
130
-
131
- ## Cross-Platform Testing (🔴 Critical)
132
-
133
- **Priority**: 🔴 **Triggers**: Shell escaping changes, command execution logic
134
-
135
- RTK must work on macOS (zsh), Linux (bash), Windows (PowerShell). Shell escaping differs.
136
-
137
- ### Platform-Specific Tests
138
-
139
- ```rust
140
- #[cfg(target_os = "windows")]
141
- const EXPECTED_SHELL: &str = "cmd.exe";
142
-
143
- #[cfg(target_os = "macos")]
144
- const EXPECTED_SHELL: &str = "zsh";
145
-
146
- #[cfg(target_os = "linux")]
147
- const EXPECTED_SHELL: &str = "bash";
148
-
149
- #[test]
150
- fn test_shell_escaping() {
151
- let cmd = r#"git log --format="%H %s""#;
152
- let escaped = escape_for_shell(cmd);
153
-
154
- #[cfg(target_os = "windows")]
155
- assert_eq!(escaped, r#"git log --format=\"%H %s\""#);
156
-
157
- #[cfg(not(target_os = "windows"))]
158
- assert_eq!(escaped, r#"git log --format="%H %s""#);
159
- }
160
- ```
161
-
162
- ### Testing Platforms
163
-
164
- **macOS (primary)**:
165
- ```bash
166
- cargo test # Local testing
167
- ```
168
-
169
- **Linux (via Docker)**:
170
- ```bash
171
- docker run --rm -v $(pwd):/rtk -w /rtk rust:latest cargo test
172
- ```
173
-
174
- **Windows (via CI)**:
175
- Trust GitHub Actions CI/CD pipeline or test manually if Windows machine available.
176
-
177
- ### Shell Differences
178
-
179
- | Platform | Shell | Quote Escape | Path Sep |
180
- |----------|-------|--------------|----------|
181
- | macOS | zsh | `'single'` or `"double"` | `/` |
182
- | Linux | bash | `'single'` or `"double"` | `/` |
183
- | Windows | PowerShell | `` `backtick `` or `"double"` | `\` |
184
-
185
- ## Integration Tests (🟡 Important)
186
-
187
- **Priority**: 🟡 **Triggers**: New filter, command routing changes, release preparation
188
-
189
- Integration tests execute real commands via RTK to verify end-to-end behavior.
190
-
191
- ### Real Command Execution
192
-
193
- ```rust
194
- #[test]
195
- #[ignore] // Run with: cargo test --ignored
196
- fn test_real_git_log() {
197
- // Requires:
198
- // 1. RTK binary installed (cargo install --path .)
199
- // 2. Git repository available
200
-
201
- let output = std::process::Command::new("rtk")
202
- .args(&["git", "log", "-10"])
203
- .output()
204
- .expect("Failed to run rtk");
205
-
206
- assert!(output.status.success());
207
- assert!(!output.stdout.is_empty());
208
-
209
- // Verify condensed (not raw git output)
210
- let stdout = String::from_utf8_lossy(&output.stdout);
211
- assert!(stdout.len() < 5000, "Output too large, filter not working");
212
- }
213
- ```
214
-
215
- ### Running Integration Tests
216
-
217
- ```bash
218
- # 1. Install RTK locally
219
- cargo install --path .
220
-
221
- # 2. Run integration tests
222
- cargo test --ignored
223
-
224
- # 3. Run specific test
225
- cargo test --ignored test_real_git_log
226
- ```
227
-
228
- ### When to Run
229
-
230
- - **Before release**: Always run integration tests
231
- - **After filter changes**: Verify filter works with real command
232
- - **After hook changes**: Verify Claude Code integration works
233
-
234
- ## Performance Testing (🟡 Important)
235
-
236
- **Priority**: 🟡 **Triggers**: Performance-related changes, release preparation
237
-
238
- RTK targets <10ms startup time and <5MB memory usage.
239
-
240
- ### Benchmark Startup Time
241
-
242
- ```bash
243
- # Install hyperfine
244
- brew install hyperfine # macOS
245
- cargo install hyperfine # or via cargo
246
-
247
- # Benchmark RTK vs raw command
248
- hyperfine 'rtk git status' 'git status' --warmup 3
249
-
250
- # Should show RTK startup <10ms
251
- # Example output:
252
- # rtk git status 6.2 ms ± 0.3 ms
253
- # git status 8.1 ms ± 0.4 ms
254
- ```
255
-
256
- ### Memory Usage
257
-
258
- ```bash
259
- # macOS
260
- /usr/bin/time -l rtk git status
261
- # Look for "maximum resident set size" - should be <5MB
262
-
263
- # Linux
264
- /usr/bin/time -v rtk git status
265
- # Look for "Maximum resident set size" - should be <5000 kbytes
266
- ```
267
-
268
- ### Regression Detection
269
-
270
- **Before changes**:
271
- ```bash
272
- hyperfine 'rtk git log -10' --warmup 3 > /tmp/before.txt
273
- ```
274
-
275
- **After changes**:
276
- ```bash
277
- cargo build --release
278
- hyperfine 'target/release/rtk git log -10' --warmup 3 > /tmp/after.txt
279
- ```
280
-
281
- **Compare**:
282
- ```bash
283
- diff /tmp/before.txt /tmp/after.txt
284
- # If startup time increased >2ms, investigate
285
- ```
286
-
287
- ### Performance Targets
288
-
289
- | Metric | Target | Verification |
290
- |--------|--------|--------------|
291
- | Startup time | <10ms | `hyperfine 'rtk <cmd>'` |
292
- | Memory usage | <5MB | `time -l rtk <cmd>` |
293
- | Binary size | <5MB | `ls -lh target/release/rtk` |
294
-
295
- ## Test Organization
296
-
297
- **Directory structure**:
298
-
299
- ```
300
- rtk/
301
- ├── src/
302
- │ ├── git.rs # Filter implementation
303
- │ │ └── #[cfg(test)] mod tests { ... } # Unit tests
304
- │ ├── snapshots/ # Insta snapshots
305
- │ │ └── git.rs.snap # Snapshot for git tests
306
- ├── tests/
307
- │ ├── common/
308
- │ │ └── mod.rs # Shared test utilities (count_tokens)
309
- │ ├── fixtures/ # Real command output
310
- │ │ ├── git_log_raw.txt
311
- │ │ ├── cargo_test_raw.txt
312
- │ │ └── gh_pr_view_raw.txt
313
- │ └── integration_test.rs # Integration tests (#[ignore])
314
- ```
315
-
316
- **Best practices**:
317
- - **Unit tests**: Embedded in module (`#[cfg(test)] mod tests`)
318
- - **Fixtures**: Real command output in `tests/fixtures/`
319
- - **Snapshots**: Auto-generated in `src/snapshots/` (by insta)
320
- - **Shared utils**: `tests/common/mod.rs` (count_tokens, helpers)
321
- - **Integration**: `tests/` with `#[ignore]` attribute
322
-
323
- ## Testing Checklist
324
-
325
- When adding/modifying a filter:
326
-
327
- ### Implementation Phase
328
- - [ ] Create fixture from real command output
329
- - [ ] Add snapshot test with `assert_snapshot!()`
330
- - [ ] Add token accuracy test (verify ≥60% savings)
331
- - [ ] Test cross-platform shell escaping (if applicable)
332
-
333
- ### Quality Checks
334
- - [ ] Run `cargo test --all` (all tests pass)
335
- - [ ] Run `cargo insta review` (review snapshots)
336
- - [ ] Run `cargo test --ignored` (integration tests pass)
337
- - [ ] Benchmark startup time with `hyperfine` (<10ms)
338
-
339
- ### Before Merge
340
- - [ ] All tests passing (`cargo test --all`)
341
- - [ ] Snapshots reviewed and accepted (`cargo insta accept`)
342
- - [ ] Token savings ≥60% verified
343
- - [ ] Cross-platform tests passed (macOS + Linux)
344
- - [ ] Performance benchmarks passed (<10ms startup)
345
-
346
- ### Before Release
347
- - [ ] Integration tests passed (`cargo test --ignored`)
348
- - [ ] Performance regression check (hyperfine comparison)
349
- - [ ] Memory usage verified (<5MB with `time -l`)
350
- - [ ] Cross-platform CI passed (macOS + Linux + Windows)
351
-
352
- ## Common Testing Patterns
353
-
354
- ### Pattern: Snapshot + Token Accuracy
355
-
356
- **Use case**: Testing filter output format and savings
357
-
358
- ```rust
359
- #[cfg(test)]
360
- mod tests {
361
- use super::*;
362
- use insta::assert_snapshot;
363
-
364
- fn count_tokens(text: &str) -> usize {
365
- text.split_whitespace().count()
366
- }
367
-
368
- #[test]
369
- fn test_output_format() {
370
- let input = include_str!("../tests/fixtures/cmd_raw.txt");
371
- let output = filter_cmd(input);
372
- assert_snapshot!(output);
373
- }
374
-
375
- #[test]
376
- fn test_token_savings() {
377
- let input = include_str!("../tests/fixtures/cmd_raw.txt");
378
- let output = filter_cmd(input);
379
-
380
- let savings = 100.0 - (count_tokens(&output) as f64 / count_tokens(input) as f64 * 100.0);
381
- assert!(savings >= 60.0, "Expected ≥60% savings, got {:.1}%", savings);
382
- }
383
- }
384
- ```
385
-
386
- ### Pattern: Edge Case Testing
387
-
388
- **Use case**: Testing filter robustness
389
-
390
- ```rust
391
- #[test]
392
- fn test_empty_input() {
393
- let output = filter_cmd("");
394
- assert_eq!(output, "");
395
- }
396
-
397
- #[test]
398
- fn test_malformed_input() {
399
- let malformed = "not valid command output";
400
- let output = filter_cmd(malformed);
401
- // Should either:
402
- // 1. Return best-effort filtered output, OR
403
- // 2. Return original input unchanged (fallback)
404
- // Both acceptable - just don't panic!
405
- assert!(!output.is_empty());
406
- }
407
-
408
- #[test]
409
- fn test_unicode_input() {
410
- let unicode = "commit 日本語メッセージ";
411
- let output = filter_cmd(unicode);
412
- assert!(output.contains("commit"));
413
- }
414
-
415
- #[test]
416
- fn test_ansi_codes() {
417
- let ansi = "\x1b[32mSuccess\x1b[0m";
418
- let output = filter_cmd(ansi);
419
- // Should strip ANSI or preserve, but not break
420
- assert!(output.contains("Success") || output.contains("\x1b[32m"));
421
- }
422
- ```
423
-
424
- ### Pattern: Integration Test
425
-
426
- **Use case**: Verify end-to-end behavior
427
-
428
- ```rust
429
- #[test]
430
- #[ignore]
431
- fn test_real_command_execution() {
432
- let output = std::process::Command::new("rtk")
433
- .args(&["cmd", "args"])
434
- .output()
435
- .expect("Failed to run rtk");
436
-
437
- assert!(output.status.success());
438
- assert!(!output.stdout.is_empty());
439
-
440
- let stdout = String::from_utf8_lossy(&output.stdout);
441
- assert!(stdout.len() < 5000, "Output too large");
442
- }
443
- ```
444
-
445
- ## Anti-Patterns
446
-
447
- ❌ **DON'T** test with hardcoded synthetic data
448
- ```rust
449
- // ❌ WRONG
450
- let input = "commit abc123\nAuthor: John";
451
- let output = filter_git_log(input);
452
- // Synthetic data doesn't reflect real command output
453
- ```
454
-
455
- ✅ **DO** use real command fixtures
456
- ```rust
457
- // ✅ RIGHT
458
- let input = include_str!("../tests/fixtures/git_log_raw.txt");
459
- let output = filter_git_log(input);
460
- // Real output from `git log -20`
461
- ```
462
-
463
- ❌ **DON'T** skip cross-platform tests
464
- ```rust
465
- // ❌ WRONG - only tests current platform
466
- #[test]
467
- fn test_shell_escaping() {
468
- let escaped = escape("test");
469
- assert_eq!(escaped, "test");
470
- }
471
- ```
472
-
473
- ✅ **DO** test all platforms with cfg
474
- ```rust
475
- // ✅ RIGHT - tests all platforms
476
- #[test]
477
- fn test_shell_escaping() {
478
- let escaped = escape("test");
479
-
480
- #[cfg(target_os = "windows")]
481
- assert_eq!(escaped, "\"test\"");
482
-
483
- #[cfg(not(target_os = "windows"))]
484
- assert_eq!(escaped, "test");
485
- }
486
- ```
487
-
488
- ❌ **DON'T** ignore performance regressions
489
- ```rust
490
- // ❌ WRONG - no performance tracking
491
- #[test]
492
- fn test_filter() {
493
- let output = filter_cmd(input);
494
- assert!(!output.is_empty());
495
- }
496
- ```
497
-
498
- ✅ **DO** benchmark and track performance
499
- ```bash
500
- # ✅ RIGHT - benchmark before/after
501
- hyperfine 'rtk cmd' --warmup 3 > /tmp/before.txt
502
- # Make changes
503
- cargo build --release
504
- hyperfine 'target/release/rtk cmd' --warmup 3 > /tmp/after.txt
505
- diff /tmp/before.txt /tmp/after.txt
506
- ```
507
-
508
- ❌ **DON'T** accept <60% token savings
509
- ```rust
510
- // ❌ WRONG - no savings verification
511
- #[test]
512
- fn test_filter() {
513
- let output = filter_cmd(input);
514
- assert!(!output.is_empty());
515
- }
516
- ```
517
-
518
- ✅ **DO** verify savings claims
519
- ```rust
520
- // ✅ RIGHT - verify ≥60% savings
521
- #[test]
522
- fn test_token_savings() {
523
- let savings = calculate_savings(input, output);
524
- assert!(savings >= 60.0, "Expected ≥60%, got {:.1}%", savings);
525
- }
526
- ```