agy-superpowers 5.2.2 → 5.2.4

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 (231) hide show
  1. package/README.md +47 -150
  2. package/package.json +1 -1
  3. package/template/agent/rules/CLAUDE.md +80 -0
  4. package/template/agent/rules/code-styles.md +31 -32
  5. package/template/agent/rules/debug-confirmation-policy.md +2 -0
  6. package/template/agent/rules/file-length-policy.md +2 -0
  7. package/template/agent/rules/git-policy.md +7 -0
  8. package/template/agent/rules/language-matching.md +2 -0
  9. package/template/agent/rules/scratch-scripts.md +39 -0
  10. package/template/agent/rules/superpowers.md +8 -51
  11. package/template/agent/skills/executing-plans/SKILL.md +17 -0
  12. package/template/agent/skills/systematic-debugging/SKILL.md +16 -0
  13. package/template/agent/skills/test-driven-development/SKILL.md +16 -0
  14. package/template/agent/skills/verification-before-completion/SKILL.md +22 -0
  15. package/template/agent/skills/writing-plans/SKILL.md +16 -0
  16. package/template/agent/skills/ai-integrated-product/SKILL.md +0 -57
  17. package/template/agent/skills/analytics-setup/SKILL.md +0 -51
  18. package/template/agent/skills/api-design/SKILL.md +0 -193
  19. package/template/agent/skills/app-store-optimizer/SKILL.md +0 -127
  20. package/template/agent/skills/auth-and-identity/SKILL.md +0 -167
  21. package/template/agent/skills/backend-developer/SKILL.md +0 -148
  22. package/template/agent/skills/bootstrapper-finance/SKILL.md +0 -55
  23. package/template/agent/skills/chrome-extension-developer/SKILL.md +0 -53
  24. package/template/agent/skills/community-manager/SKILL.md +0 -115
  25. package/template/agent/skills/content-marketer/SKILL.md +0 -111
  26. package/template/agent/skills/conversion-optimizer/SKILL.md +0 -142
  27. package/template/agent/skills/cto-architect/SKILL.md +0 -133
  28. package/template/agent/skills/customer-success-manager/SKILL.md +0 -126
  29. package/template/agent/skills/data-analyst/SKILL.md +0 -147
  30. package/template/agent/skills/devops-engineer/SKILL.md +0 -117
  31. package/template/agent/skills/email-infrastructure/SKILL.md +0 -164
  32. package/template/agent/skills/game-design/SKILL.md +0 -194
  33. package/template/agent/skills/game-developer/SKILL.md +0 -175
  34. package/template/agent/skills/growth-hacker/SKILL.md +0 -122
  35. package/template/agent/skills/idea-validator/SKILL.md +0 -55
  36. package/template/agent/skills/indie-legal/SKILL.md +0 -53
  37. package/template/agent/skills/influencer-marketer/SKILL.md +0 -141
  38. package/template/agent/skills/landing-page-builder/SKILL.md +0 -59
  39. package/template/agent/skills/launch-strategist/SKILL.md +0 -62
  40. package/template/agent/skills/market-researcher/SKILL.md +0 -53
  41. package/template/agent/skills/micro-saas-builder/SKILL.md +0 -56
  42. package/template/agent/skills/monetization-strategist/SKILL.md +0 -119
  43. package/template/agent/skills/paid-acquisition-specialist/SKILL.md +0 -119
  44. package/template/agent/skills/pricing-psychologist/SKILL.md +0 -58
  45. package/template/agent/skills/real-time-features/SKILL.md +0 -194
  46. package/template/agent/skills/retention-specialist/SKILL.md +0 -123
  47. package/template/agent/skills/rust-developer/SKILL.md +0 -281
  48. package/template/agent/skills/rust-developer/references/rust-rules/_sections.md +0 -231
  49. package/template/agent/skills/rust-developer/references/rust-rules/anti-clone-excessive.md +0 -124
  50. package/template/agent/skills/rust-developer/references/rust-rules/anti-collect-intermediate.md +0 -131
  51. package/template/agent/skills/rust-developer/references/rust-rules/anti-empty-catch.md +0 -132
  52. package/template/agent/skills/rust-developer/references/rust-rules/anti-expect-lazy.md +0 -95
  53. package/template/agent/skills/rust-developer/references/rust-rules/anti-format-hot-path.md +0 -141
  54. package/template/agent/skills/rust-developer/references/rust-rules/anti-index-over-iter.md +0 -125
  55. package/template/agent/skills/rust-developer/references/rust-rules/anti-lock-across-await.md +0 -127
  56. package/template/agent/skills/rust-developer/references/rust-rules/anti-over-abstraction.md +0 -120
  57. package/template/agent/skills/rust-developer/references/rust-rules/anti-panic-expected.md +0 -131
  58. package/template/agent/skills/rust-developer/references/rust-rules/anti-premature-optimize.md +0 -156
  59. package/template/agent/skills/rust-developer/references/rust-rules/anti-string-for-str.md +0 -122
  60. package/template/agent/skills/rust-developer/references/rust-rules/anti-stringly-typed.md +0 -167
  61. package/template/agent/skills/rust-developer/references/rust-rules/anti-type-erasure.md +0 -134
  62. package/template/agent/skills/rust-developer/references/rust-rules/anti-unwrap-abuse.md +0 -143
  63. package/template/agent/skills/rust-developer/references/rust-rules/anti-vec-for-slice.md +0 -121
  64. package/template/agent/skills/rust-developer/references/rust-rules/api-builder-must-use.md +0 -143
  65. package/template/agent/skills/rust-developer/references/rust-rules/api-builder-pattern.md +0 -187
  66. package/template/agent/skills/rust-developer/references/rust-rules/api-common-traits.md +0 -165
  67. package/template/agent/skills/rust-developer/references/rust-rules/api-default-impl.md +0 -177
  68. package/template/agent/skills/rust-developer/references/rust-rules/api-extension-trait.md +0 -163
  69. package/template/agent/skills/rust-developer/references/rust-rules/api-from-not-into.md +0 -146
  70. package/template/agent/skills/rust-developer/references/rust-rules/api-impl-asref.md +0 -142
  71. package/template/agent/skills/rust-developer/references/rust-rules/api-impl-into.md +0 -160
  72. package/template/agent/skills/rust-developer/references/rust-rules/api-must-use.md +0 -125
  73. package/template/agent/skills/rust-developer/references/rust-rules/api-newtype-safety.md +0 -162
  74. package/template/agent/skills/rust-developer/references/rust-rules/api-non-exhaustive.md +0 -177
  75. package/template/agent/skills/rust-developer/references/rust-rules/api-parse-dont-validate.md +0 -184
  76. package/template/agent/skills/rust-developer/references/rust-rules/api-sealed-trait.md +0 -168
  77. package/template/agent/skills/rust-developer/references/rust-rules/api-serde-optional.md +0 -182
  78. package/template/agent/skills/rust-developer/references/rust-rules/api-typestate.md +0 -199
  79. package/template/agent/skills/rust-developer/references/rust-rules/async-bounded-channel.md +0 -175
  80. package/template/agent/skills/rust-developer/references/rust-rules/async-broadcast-pubsub.md +0 -185
  81. package/template/agent/skills/rust-developer/references/rust-rules/async-cancellation-token.md +0 -203
  82. package/template/agent/skills/rust-developer/references/rust-rules/async-clone-before-await.md +0 -171
  83. package/template/agent/skills/rust-developer/references/rust-rules/async-join-parallel.md +0 -158
  84. package/template/agent/skills/rust-developer/references/rust-rules/async-joinset-structured.md +0 -195
  85. package/template/agent/skills/rust-developer/references/rust-rules/async-mpsc-queue.md +0 -171
  86. package/template/agent/skills/rust-developer/references/rust-rules/async-no-lock-await.md +0 -156
  87. package/template/agent/skills/rust-developer/references/rust-rules/async-oneshot-response.md +0 -191
  88. package/template/agent/skills/rust-developer/references/rust-rules/async-select-racing.md +0 -198
  89. package/template/agent/skills/rust-developer/references/rust-rules/async-spawn-blocking.md +0 -154
  90. package/template/agent/skills/rust-developer/references/rust-rules/async-tokio-fs.md +0 -167
  91. package/template/agent/skills/rust-developer/references/rust-rules/async-tokio-runtime.md +0 -169
  92. package/template/agent/skills/rust-developer/references/rust-rules/async-try-join.md +0 -172
  93. package/template/agent/skills/rust-developer/references/rust-rules/async-watch-latest.md +0 -189
  94. package/template/agent/skills/rust-developer/references/rust-rules/doc-all-public.md +0 -113
  95. package/template/agent/skills/rust-developer/references/rust-rules/doc-cargo-metadata.md +0 -147
  96. package/template/agent/skills/rust-developer/references/rust-rules/doc-errors-section.md +0 -122
  97. package/template/agent/skills/rust-developer/references/rust-rules/doc-examples-section.md +0 -161
  98. package/template/agent/skills/rust-developer/references/rust-rules/doc-hidden-setup.md +0 -149
  99. package/template/agent/skills/rust-developer/references/rust-rules/doc-intra-links.md +0 -138
  100. package/template/agent/skills/rust-developer/references/rust-rules/doc-link-types.md +0 -169
  101. package/template/agent/skills/rust-developer/references/rust-rules/doc-module-inner.md +0 -116
  102. package/template/agent/skills/rust-developer/references/rust-rules/doc-panics-section.md +0 -128
  103. package/template/agent/skills/rust-developer/references/rust-rules/doc-question-mark.md +0 -136
  104. package/template/agent/skills/rust-developer/references/rust-rules/doc-safety-section.md +0 -131
  105. package/template/agent/skills/rust-developer/references/rust-rules/err-anyhow-app.md +0 -179
  106. package/template/agent/skills/rust-developer/references/rust-rules/err-context-chain.md +0 -144
  107. package/template/agent/skills/rust-developer/references/rust-rules/err-custom-type.md +0 -152
  108. package/template/agent/skills/rust-developer/references/rust-rules/err-doc-errors.md +0 -145
  109. package/template/agent/skills/rust-developer/references/rust-rules/err-expect-bugs-only.md +0 -133
  110. package/template/agent/skills/rust-developer/references/rust-rules/err-from-impl.md +0 -152
  111. package/template/agent/skills/rust-developer/references/rust-rules/err-lowercase-msg.md +0 -124
  112. package/template/agent/skills/rust-developer/references/rust-rules/err-no-unwrap-prod.md +0 -115
  113. package/template/agent/skills/rust-developer/references/rust-rules/err-question-mark.md +0 -151
  114. package/template/agent/skills/rust-developer/references/rust-rules/err-result-over-panic.md +0 -130
  115. package/template/agent/skills/rust-developer/references/rust-rules/err-source-chain.md +0 -155
  116. package/template/agent/skills/rust-developer/references/rust-rules/err-thiserror-lib.md +0 -171
  117. package/template/agent/skills/rust-developer/references/rust-rules/lint-cargo-metadata.md +0 -138
  118. package/template/agent/skills/rust-developer/references/rust-rules/lint-deny-correctness.md +0 -107
  119. package/template/agent/skills/rust-developer/references/rust-rules/lint-missing-docs.md +0 -154
  120. package/template/agent/skills/rust-developer/references/rust-rules/lint-pedantic-selective.md +0 -118
  121. package/template/agent/skills/rust-developer/references/rust-rules/lint-rustfmt-check.md +0 -157
  122. package/template/agent/skills/rust-developer/references/rust-rules/lint-unsafe-doc.md +0 -133
  123. package/template/agent/skills/rust-developer/references/rust-rules/lint-warn-complexity.md +0 -131
  124. package/template/agent/skills/rust-developer/references/rust-rules/lint-warn-perf.md +0 -136
  125. package/template/agent/skills/rust-developer/references/rust-rules/lint-warn-style.md +0 -135
  126. package/template/agent/skills/rust-developer/references/rust-rules/lint-warn-suspicious.md +0 -122
  127. package/template/agent/skills/rust-developer/references/rust-rules/lint-workspace-lints.md +0 -172
  128. package/template/agent/skills/rust-developer/references/rust-rules/mem-arena-allocator.md +0 -168
  129. package/template/agent/skills/rust-developer/references/rust-rules/mem-arrayvec.md +0 -142
  130. package/template/agent/skills/rust-developer/references/rust-rules/mem-assert-type-size.md +0 -168
  131. package/template/agent/skills/rust-developer/references/rust-rules/mem-avoid-format.md +0 -147
  132. package/template/agent/skills/rust-developer/references/rust-rules/mem-box-large-variant.md +0 -158
  133. package/template/agent/skills/rust-developer/references/rust-rules/mem-boxed-slice.md +0 -139
  134. package/template/agent/skills/rust-developer/references/rust-rules/mem-clone-from.md +0 -147
  135. package/template/agent/skills/rust-developer/references/rust-rules/mem-compact-string.md +0 -149
  136. package/template/agent/skills/rust-developer/references/rust-rules/mem-reuse-collections.md +0 -174
  137. package/template/agent/skills/rust-developer/references/rust-rules/mem-smaller-integers.md +0 -159
  138. package/template/agent/skills/rust-developer/references/rust-rules/mem-smallvec.md +0 -138
  139. package/template/agent/skills/rust-developer/references/rust-rules/mem-thinvec.md +0 -142
  140. package/template/agent/skills/rust-developer/references/rust-rules/mem-with-capacity.md +0 -156
  141. package/template/agent/skills/rust-developer/references/rust-rules/mem-write-over-format.md +0 -172
  142. package/template/agent/skills/rust-developer/references/rust-rules/mem-zero-copy.md +0 -164
  143. package/template/agent/skills/rust-developer/references/rust-rules/name-acronym-word.md +0 -99
  144. package/template/agent/skills/rust-developer/references/rust-rules/name-as-free.md +0 -104
  145. package/template/agent/skills/rust-developer/references/rust-rules/name-consts-screaming.md +0 -94
  146. package/template/agent/skills/rust-developer/references/rust-rules/name-crate-no-rs.md +0 -78
  147. package/template/agent/skills/rust-developer/references/rust-rules/name-funcs-snake.md +0 -76
  148. package/template/agent/skills/rust-developer/references/rust-rules/name-into-ownership.md +0 -123
  149. package/template/agent/skills/rust-developer/references/rust-rules/name-is-has-bool.md +0 -127
  150. package/template/agent/skills/rust-developer/references/rust-rules/name-iter-convention.md +0 -129
  151. package/template/agent/skills/rust-developer/references/rust-rules/name-iter-method.md +0 -131
  152. package/template/agent/skills/rust-developer/references/rust-rules/name-iter-type-match.md +0 -142
  153. package/template/agent/skills/rust-developer/references/rust-rules/name-lifetime-short.md +0 -86
  154. package/template/agent/skills/rust-developer/references/rust-rules/name-no-get-prefix.md +0 -154
  155. package/template/agent/skills/rust-developer/references/rust-rules/name-to-expensive.md +0 -118
  156. package/template/agent/skills/rust-developer/references/rust-rules/name-type-param-single.md +0 -92
  157. package/template/agent/skills/rust-developer/references/rust-rules/name-types-camel.md +0 -65
  158. package/template/agent/skills/rust-developer/references/rust-rules/name-variants-camel.md +0 -101
  159. package/template/agent/skills/rust-developer/references/rust-rules/opt-bounds-check.md +0 -161
  160. package/template/agent/skills/rust-developer/references/rust-rules/opt-cache-friendly.md +0 -187
  161. package/template/agent/skills/rust-developer/references/rust-rules/opt-codegen-units.md +0 -142
  162. package/template/agent/skills/rust-developer/references/rust-rules/opt-cold-unlikely.md +0 -152
  163. package/template/agent/skills/rust-developer/references/rust-rules/opt-inline-always-rare.md +0 -141
  164. package/template/agent/skills/rust-developer/references/rust-rules/opt-inline-never-cold.md +0 -181
  165. package/template/agent/skills/rust-developer/references/rust-rules/opt-inline-small.md +0 -160
  166. package/template/agent/skills/rust-developer/references/rust-rules/opt-likely-hint.md +0 -171
  167. package/template/agent/skills/rust-developer/references/rust-rules/opt-lto-release.md +0 -130
  168. package/template/agent/skills/rust-developer/references/rust-rules/opt-pgo-profile.md +0 -167
  169. package/template/agent/skills/rust-developer/references/rust-rules/opt-simd-portable.md +0 -144
  170. package/template/agent/skills/rust-developer/references/rust-rules/opt-target-cpu.md +0 -154
  171. package/template/agent/skills/rust-developer/references/rust-rules/own-arc-shared.md +0 -141
  172. package/template/agent/skills/rust-developer/references/rust-rules/own-borrow-over-clone.md +0 -95
  173. package/template/agent/skills/rust-developer/references/rust-rules/own-clone-explicit.md +0 -135
  174. package/template/agent/skills/rust-developer/references/rust-rules/own-copy-small.md +0 -124
  175. package/template/agent/skills/rust-developer/references/rust-rules/own-cow-conditional.md +0 -135
  176. package/template/agent/skills/rust-developer/references/rust-rules/own-lifetime-elision.md +0 -134
  177. package/template/agent/skills/rust-developer/references/rust-rules/own-move-large.md +0 -134
  178. package/template/agent/skills/rust-developer/references/rust-rules/own-mutex-interior.md +0 -105
  179. package/template/agent/skills/rust-developer/references/rust-rules/own-rc-single-thread.md +0 -65
  180. package/template/agent/skills/rust-developer/references/rust-rules/own-refcell-interior.md +0 -97
  181. package/template/agent/skills/rust-developer/references/rust-rules/own-rwlock-readers.md +0 -122
  182. package/template/agent/skills/rust-developer/references/rust-rules/own-slice-over-vec.md +0 -119
  183. package/template/agent/skills/rust-developer/references/rust-rules/perf-black-box-bench.md +0 -153
  184. package/template/agent/skills/rust-developer/references/rust-rules/perf-chain-avoid.md +0 -136
  185. package/template/agent/skills/rust-developer/references/rust-rules/perf-collect-into.md +0 -133
  186. package/template/agent/skills/rust-developer/references/rust-rules/perf-collect-once.md +0 -120
  187. package/template/agent/skills/rust-developer/references/rust-rules/perf-drain-reuse.md +0 -137
  188. package/template/agent/skills/rust-developer/references/rust-rules/perf-entry-api.md +0 -134
  189. package/template/agent/skills/rust-developer/references/rust-rules/perf-extend-batch.md +0 -150
  190. package/template/agent/skills/rust-developer/references/rust-rules/perf-iter-lazy.md +0 -123
  191. package/template/agent/skills/rust-developer/references/rust-rules/perf-iter-over-index.md +0 -113
  192. package/template/agent/skills/rust-developer/references/rust-rules/perf-profile-first.md +0 -175
  193. package/template/agent/skills/rust-developer/references/rust-rules/perf-release-profile.md +0 -149
  194. package/template/agent/skills/rust-developer/references/rust-rules/proj-bin-dir.md +0 -142
  195. package/template/agent/skills/rust-developer/references/rust-rules/proj-flat-small.md +0 -133
  196. package/template/agent/skills/rust-developer/references/rust-rules/proj-lib-main-split.md +0 -148
  197. package/template/agent/skills/rust-developer/references/rust-rules/proj-mod-by-feature.md +0 -130
  198. package/template/agent/skills/rust-developer/references/rust-rules/proj-mod-rs-dir.md +0 -120
  199. package/template/agent/skills/rust-developer/references/rust-rules/proj-prelude-module.md +0 -155
  200. package/template/agent/skills/rust-developer/references/rust-rules/proj-pub-crate-internal.md +0 -139
  201. package/template/agent/skills/rust-developer/references/rust-rules/proj-pub-super-parent.md +0 -135
  202. package/template/agent/skills/rust-developer/references/rust-rules/proj-pub-use-reexport.md +0 -162
  203. package/template/agent/skills/rust-developer/references/rust-rules/proj-workspace-deps.md +0 -186
  204. package/template/agent/skills/rust-developer/references/rust-rules/proj-workspace-large.md +0 -162
  205. package/template/agent/skills/rust-developer/references/rust-rules/test-arrange-act-assert.md +0 -160
  206. package/template/agent/skills/rust-developer/references/rust-rules/test-cfg-test-module.md +0 -151
  207. package/template/agent/skills/rust-developer/references/rust-rules/test-criterion-bench.md +0 -171
  208. package/template/agent/skills/rust-developer/references/rust-rules/test-descriptive-names.md +0 -142
  209. package/template/agent/skills/rust-developer/references/rust-rules/test-doctest-examples.md +0 -168
  210. package/template/agent/skills/rust-developer/references/rust-rules/test-fixture-raii.md +0 -151
  211. package/template/agent/skills/rust-developer/references/rust-rules/test-integration-dir.md +0 -144
  212. package/template/agent/skills/rust-developer/references/rust-rules/test-mock-traits.md +0 -189
  213. package/template/agent/skills/rust-developer/references/rust-rules/test-mockall-mocking.md +0 -226
  214. package/template/agent/skills/rust-developer/references/rust-rules/test-proptest-properties.md +0 -161
  215. package/template/agent/skills/rust-developer/references/rust-rules/test-should-panic.md +0 -130
  216. package/template/agent/skills/rust-developer/references/rust-rules/test-tokio-async.md +0 -154
  217. package/template/agent/skills/rust-developer/references/rust-rules/test-use-super.md +0 -127
  218. package/template/agent/skills/rust-developer/references/rust-rules/type-enum-states.md +0 -154
  219. package/template/agent/skills/rust-developer/references/rust-rules/type-generic-bounds.md +0 -142
  220. package/template/agent/skills/rust-developer/references/rust-rules/type-never-diverge.md +0 -146
  221. package/template/agent/skills/rust-developer/references/rust-rules/type-newtype-ids.md +0 -160
  222. package/template/agent/skills/rust-developer/references/rust-rules/type-newtype-validated.md +0 -159
  223. package/template/agent/skills/rust-developer/references/rust-rules/type-no-stringly.md +0 -144
  224. package/template/agent/skills/rust-developer/references/rust-rules/type-option-nullable.md +0 -137
  225. package/template/agent/skills/rust-developer/references/rust-rules/type-phantom-marker.md +0 -188
  226. package/template/agent/skills/rust-developer/references/rust-rules/type-repr-transparent.md +0 -143
  227. package/template/agent/skills/rust-developer/references/rust-rules/type-result-fallible.md +0 -131
  228. package/template/agent/skills/saas-architect/SKILL.md +0 -139
  229. package/template/agent/skills/security-engineer/SKILL.md +0 -133
  230. package/template/agent/skills/seo-specialist/SKILL.md +0 -130
  231. package/template/agent/skills/solo-founder-ops/SKILL.md +0 -56
@@ -1,189 +0,0 @@
1
- # test-mock-traits
2
-
3
- > Use traits for dependencies to enable mocking in tests
4
-
5
- ## Why It Matters
6
-
7
- Concrete dependencies make testing hard—you can't easily test error paths, timeouts, or edge cases without real external systems. Extracting dependencies behind traits lets you inject test doubles (mocks, fakes, stubs), enabling isolated unit tests that run fast and cover edge cases.
8
-
9
- ## Bad
10
-
11
- ```rust
12
- struct UserService {
13
- db: PostgresConnection, // Concrete type - hard to test
14
- }
15
-
16
- impl UserService {
17
- async fn get_user(&self, id: u64) -> Result<User, Error> {
18
- // Directly calls Postgres - needs real database to test
19
- self.db.query("SELECT * FROM users WHERE id = $1", &[&id]).await
20
- }
21
- }
22
-
23
- // Test requires real Postgres instance
24
- #[tokio::test]
25
- async fn test_get_user() {
26
- let db = PostgresConnection::connect("postgres://...").await?;
27
- let service = UserService { db };
28
- // Slow, flaky, can't test error paths
29
- }
30
- ```
31
-
32
- ## Good
33
-
34
- ```rust
35
- // Define trait for dependency
36
- #[async_trait]
37
- trait UserRepository: Send + Sync {
38
- async fn find_by_id(&self, id: u64) -> Result<Option<User>, DbError>;
39
- async fn save(&self, user: &User) -> Result<(), DbError>;
40
- }
41
-
42
- // Production implementation
43
- struct PostgresUserRepo {
44
- pool: PgPool,
45
- }
46
-
47
- #[async_trait]
48
- impl UserRepository for PostgresUserRepo {
49
- async fn find_by_id(&self, id: u64) -> Result<Option<User>, DbError> {
50
- sqlx::query_as("SELECT * FROM users WHERE id = $1")
51
- .bind(id)
52
- .fetch_optional(&self.pool)
53
- .await
54
- }
55
- // ...
56
- }
57
-
58
- // Service depends on trait, not concrete type
59
- struct UserService<R: UserRepository> {
60
- repo: R,
61
- }
62
-
63
- impl<R: UserRepository> UserService<R> {
64
- async fn get_user(&self, id: u64) -> Result<User, Error> {
65
- self.repo.find_by_id(id).await?
66
- .ok_or(Error::NotFound)
67
- }
68
- }
69
-
70
- // Test with mock
71
- #[cfg(test)]
72
- mod tests {
73
- struct MockUserRepo {
74
- users: HashMap<u64, User>,
75
- }
76
-
77
- #[async_trait]
78
- impl UserRepository for MockUserRepo {
79
- async fn find_by_id(&self, id: u64) -> Result<Option<User>, DbError> {
80
- Ok(self.users.get(&id).cloned())
81
- }
82
- // ...
83
- }
84
-
85
- #[tokio::test]
86
- async fn test_get_user_found() {
87
- let mut mock = MockUserRepo { users: HashMap::new() };
88
- mock.users.insert(1, User { id: 1, name: "Alice".into() });
89
-
90
- let service = UserService { repo: mock };
91
- let user = service.get_user(1).await.unwrap();
92
-
93
- assert_eq!(user.name, "Alice");
94
- }
95
-
96
- #[tokio::test]
97
- async fn test_get_user_not_found() {
98
- let mock = MockUserRepo { users: HashMap::new() };
99
- let service = UserService { repo: mock };
100
-
101
- let result = service.get_user(999).await;
102
- assert!(matches!(result, Err(Error::NotFound)));
103
- }
104
- }
105
- ```
106
-
107
- ## mockall Crate
108
-
109
- ```rust
110
- use mockall::*;
111
- use mockall::predicate::*;
112
-
113
- #[automock]
114
- #[async_trait]
115
- trait Database: Send + Sync {
116
- async fn query(&self, sql: &str) -> Result<Vec<Row>, Error>;
117
- }
118
-
119
- #[tokio::test]
120
- async fn test_with_mockall() {
121
- let mut mock = MockDatabase::new();
122
-
123
- mock.expect_query()
124
- .with(eq("SELECT 1"))
125
- .times(1)
126
- .returning(|_| Ok(vec![Row::new()]));
127
-
128
- let result = mock.query("SELECT 1").await;
129
- assert!(result.is_ok());
130
- }
131
- ```
132
-
133
- ## Testing Error Paths
134
-
135
- ```rust
136
- #[async_trait]
137
- trait HttpClient: Send + Sync {
138
- async fn get(&self, url: &str) -> Result<Response, HttpError>;
139
- }
140
-
141
- struct FailingClient;
142
-
143
- #[async_trait]
144
- impl HttpClient for FailingClient {
145
- async fn get(&self, _url: &str) -> Result<Response, HttpError> {
146
- Err(HttpError::Timeout) // Always fails
147
- }
148
- }
149
-
150
- #[tokio::test]
151
- async fn test_handles_timeout() {
152
- let client = FailingClient;
153
- let service = ApiService { client };
154
-
155
- let result = service.fetch_data().await;
156
- assert!(matches!(result, Err(Error::NetworkError(_))));
157
- }
158
- ```
159
-
160
- ## Dynamic Dispatch Alternative
161
-
162
- ```rust
163
- // When you don't want generics everywhere
164
- struct UserService {
165
- repo: Box<dyn UserRepository>,
166
- }
167
-
168
- impl UserService {
169
- fn new(repo: impl UserRepository + 'static) -> Self {
170
- Self { repo: Box::new(repo) }
171
- }
172
- }
173
-
174
- // Slight runtime cost but cleaner API
175
- ```
176
-
177
- ## Cargo.toml
178
-
179
- ```toml
180
- [dev-dependencies]
181
- mockall = "0.11"
182
- async-trait = "0.1" # For async trait mocking
183
- ```
184
-
185
- ## See Also
186
-
187
- - [api-sealed-trait](./api-sealed-trait.md) - Trait design
188
- - [test-proptest-properties](./test-proptest-properties.md) - Property-based testing
189
- - [proj-lib-main-split](./proj-lib-main-split.md) - Testable architecture
@@ -1,226 +0,0 @@
1
- # test-mockall-mocking
2
-
3
- > Use mockall for trait mocking
4
-
5
- ## Why It Matters
6
-
7
- Unit tests should isolate the code under test from external dependencies (databases, APIs, file systems). Mockall generates mock implementations of traits, allowing you to control and verify behavior without real dependencies.
8
-
9
- ## Setup
10
-
11
- ```toml
12
- # Cargo.toml
13
- [dev-dependencies]
14
- mockall = "0.12"
15
- ```
16
-
17
- ## Basic Usage
18
-
19
- ```rust
20
- use mockall::automock;
21
-
22
- #[automock]
23
- trait Database {
24
- fn get_user(&self, id: u64) -> Option<User>;
25
- fn save_user(&self, user: &User) -> Result<(), Error>;
26
- }
27
-
28
- #[cfg(test)]
29
- mod tests {
30
- use super::*;
31
- use mockall::predicate::*;
32
-
33
- #[test]
34
- fn test_get_user() {
35
- let mut mock = MockDatabase::new();
36
-
37
- mock.expect_get_user()
38
- .with(eq(42))
39
- .returning(|_| Some(User { id: 42, name: "Alice".into() }));
40
-
41
- let service = UserService::new(mock);
42
- let user = service.find_user(42);
43
-
44
- assert_eq!(user.unwrap().name, "Alice");
45
- }
46
- }
47
- ```
48
-
49
- ## Expectations
50
-
51
- ```rust
52
- #[cfg(test)]
53
- mod tests {
54
- use super::*;
55
-
56
- #[test]
57
- fn test_save_calls() {
58
- let mut mock = MockDatabase::new();
59
-
60
- // Expect exactly one call
61
- mock.expect_save_user()
62
- .times(1)
63
- .returning(|_| Ok(()));
64
-
65
- // Expect call with specific argument
66
- mock.expect_get_user()
67
- .with(eq(42))
68
- .returning(|_| Some(User::default()));
69
-
70
- // Expect multiple calls
71
- mock.expect_get_user()
72
- .times(3..) // At least 3 times
73
- .returning(|_| None);
74
-
75
- // Expectations are verified on drop
76
- }
77
- }
78
- ```
79
-
80
- ## Predicates
81
-
82
- ```rust
83
- use mockall::predicate::*;
84
-
85
- mock.expect_process()
86
- .with(eq(42)) // Exact match
87
- .returning(|_| Ok(()));
88
-
89
- mock.expect_validate()
90
- .with(function(|s: &str| s.len() > 5)) // Custom predicate
91
- .returning(|_| true);
92
-
93
- mock.expect_search()
94
- .withf(|query, limit| { // Multiple args
95
- query.len() < 100 && *limit <= 1000
96
- })
97
- .returning(|_, _| vec![]);
98
- ```
99
-
100
- ## Sequences
101
-
102
- ```rust
103
- use mockall::Sequence;
104
-
105
- #[test]
106
- fn test_ordered_calls() {
107
- let mut seq = Sequence::new();
108
- let mut mock = MockDatabase::new();
109
-
110
- mock.expect_connect()
111
- .times(1)
112
- .in_sequence(&mut seq)
113
- .returning(|| Ok(()));
114
-
115
- mock.expect_query()
116
- .times(1)
117
- .in_sequence(&mut seq)
118
- .returning(|_| Ok(vec![]));
119
-
120
- mock.expect_disconnect()
121
- .times(1)
122
- .in_sequence(&mut seq)
123
- .returning(|| Ok(()));
124
- }
125
- ```
126
-
127
- ## Return Values
128
-
129
- ```rust
130
- // Fixed value
131
- mock.expect_count().returning(|| 42);
132
-
133
- // Based on input
134
- mock.expect_double().returning(|x| x * 2);
135
-
136
- // Different values per call
137
- mock.expect_next()
138
- .times(3)
139
- .returning(|| 1)
140
- .returning(|| 2)
141
- .returning(|| 3);
142
-
143
- // Return owned values
144
- mock.expect_get_name()
145
- .returning(|| "Alice".to_string());
146
- ```
147
-
148
- ## Mocking External Traits
149
-
150
- ```rust
151
- // For traits you don't own
152
- #[cfg_attr(test, mockall::automock)]
153
- trait HttpClient {
154
- fn get(&self, url: &str) -> Result<Response, Error>;
155
- }
156
-
157
- // In production
158
- struct RealHttpClient;
159
- impl HttpClient for RealHttpClient {
160
- fn get(&self, url: &str) -> Result<Response, Error> { /* ... */ }
161
- }
162
-
163
- // In tests
164
- #[cfg(test)]
165
- fn mock_client() -> MockHttpClient {
166
- let mut mock = MockHttpClient::new();
167
- mock.expect_get()
168
- .returning(|_| Ok(Response::new(200, "OK")));
169
- mock
170
- }
171
- ```
172
-
173
- ## Async Mocking
174
-
175
- ```rust
176
- #[automock]
177
- #[async_trait]
178
- trait AsyncDatabase {
179
- async fn fetch(&self, id: u64) -> Option<Data>;
180
- }
181
-
182
- #[tokio::test]
183
- async fn test_async() {
184
- let mut mock = MockAsyncDatabase::new();
185
-
186
- mock.expect_fetch()
187
- .returning(|_| Some(Data::default()));
188
-
189
- let result = mock.fetch(1).await;
190
- assert!(result.is_some());
191
- }
192
- ```
193
-
194
- ## Design for Testability
195
-
196
- ```rust
197
- // Accept trait, not concrete type
198
- struct Service<D: Database> {
199
- db: D,
200
- }
201
-
202
- impl<D: Database> Service<D> {
203
- fn new(db: D) -> Self {
204
- Self { db }
205
- }
206
- }
207
-
208
- // Tests use mock
209
- #[test]
210
- fn test_service() {
211
- let mock = MockDatabase::new();
212
- let service = Service::new(mock);
213
- }
214
-
215
- // Production uses real implementation
216
- fn main() {
217
- let db = PostgresDatabase::connect();
218
- let service = Service::new(db);
219
- }
220
- ```
221
-
222
- ## See Also
223
-
224
- - [test-mock-traits](./test-mock-traits.md) - Mock trait design
225
- - [test-proptest-properties](./test-proptest-properties.md) - Property testing
226
- - [test-arrange-act-assert](./test-arrange-act-assert.md) - Test structure
@@ -1,161 +0,0 @@
1
- # test-proptest-properties
2
-
3
- > Use proptest for property-based testing
4
-
5
- ## Why It Matters
6
-
7
- Property-based testing generates random inputs to verify that properties hold across all possible values, not just hand-picked examples. Proptest finds edge cases you wouldn't think to test manually—empty strings, integer overflows, unicode edge cases.
8
-
9
- ## Setup
10
-
11
- ```toml
12
- # Cargo.toml
13
- [dev-dependencies]
14
- proptest = "1.0"
15
- ```
16
-
17
- ## Basic Usage
18
-
19
- ```rust
20
- use proptest::prelude::*;
21
-
22
- proptest! {
23
- #[test]
24
- fn test_reverse_reverse_is_identity(s in ".*") {
25
- let reversed: String = s.chars().rev().collect();
26
- let double_reversed: String = reversed.chars().rev().collect();
27
- assert_eq!(s, double_reversed);
28
- }
29
-
30
- #[test]
31
- fn test_sort_is_idempotent(mut v in prop::collection::vec(any::<i32>(), 0..100)) {
32
- v.sort();
33
- let sorted = v.clone();
34
- v.sort();
35
- assert_eq!(v, sorted);
36
- }
37
- }
38
- ```
39
-
40
- ## Common Strategies
41
-
42
- ```rust
43
- use proptest::prelude::*;
44
-
45
- proptest! {
46
- // Any type implementing Arbitrary
47
- #[test]
48
- fn test_i32(x in any::<i32>()) { }
49
-
50
- // Regex-based string generation
51
- #[test]
52
- fn test_email(email in "[a-z]+@[a-z]+\\.[a-z]{2,3}") { }
53
-
54
- // Ranges
55
- #[test]
56
- fn test_range(x in 0..100i32) { }
57
-
58
- // Collections
59
- #[test]
60
- fn test_vec(v in prop::collection::vec(any::<i32>(), 0..10)) { }
61
-
62
- // Optionals
63
- #[test]
64
- fn test_option(opt in prop::option::of(any::<i32>())) { }
65
- }
66
- ```
67
-
68
- ## Custom Strategies
69
-
70
- ```rust
71
- use proptest::prelude::*;
72
-
73
- #[derive(Debug, Clone)]
74
- struct User {
75
- name: String,
76
- age: u8,
77
- }
78
-
79
- fn user_strategy() -> impl Strategy<Value = User> {
80
- ("[a-zA-Z]{1,20}", 0..120u8)
81
- .prop_map(|(name, age)| User { name, age })
82
- }
83
-
84
- proptest! {
85
- #[test]
86
- fn test_user(user in user_strategy()) {
87
- assert!(user.age < 150);
88
- assert!(!user.name.is_empty());
89
- }
90
- }
91
-
92
- // Or derive Arbitrary
93
- use proptest_derive::Arbitrary;
94
-
95
- #[derive(Debug, Arbitrary)]
96
- struct Point {
97
- x: i32,
98
- y: i32,
99
- }
100
- ```
101
-
102
- ## Properties to Test
103
-
104
- | Property | Example |
105
- |----------|---------|
106
- | Roundtrip | `decode(encode(x)) == x` |
107
- | Idempotence | `f(f(x)) == f(x)` |
108
- | Commutativity | `f(a, b) == f(b, a)` |
109
- | Associativity | `f(f(a, b), c) == f(a, f(b, c))` |
110
- | Identity | `f(x, identity) == x` |
111
- | Invariants | `len(push(v, x)) == len(v) + 1` |
112
-
113
- ## Example: Parser Roundtrip
114
-
115
- ```rust
116
- proptest! {
117
- #[test]
118
- fn parse_roundtrip(config in valid_config_strategy()) {
119
- let serialized = config.to_string();
120
- let parsed = Config::parse(&serialized).unwrap();
121
- assert_eq!(config, parsed);
122
- }
123
- }
124
- ```
125
-
126
- ## Shrinking
127
-
128
- Proptest automatically shrinks failing inputs to minimal cases:
129
-
130
- ```rust
131
- // If this fails with vec![100, 50, 75, 25, 0]
132
- // Proptest will shrink to vec![1, 0] (minimal failing case)
133
- proptest! {
134
- #[test]
135
- fn test_sorted(v in prop::collection::vec(0..1000i32, 1..100)) {
136
- let sorted = is_sorted(&v);
137
- // This will fail and shrink
138
- }
139
- }
140
- ```
141
-
142
- ## Configuration
143
-
144
- ```rust
145
- proptest! {
146
- #![proptest_config(ProptestConfig {
147
- cases: 1000, // More test cases
148
- max_shrink_iters: 10000, // More shrinking
149
- ..ProptestConfig::default()
150
- })]
151
-
152
- #[test]
153
- fn extensive_test(x in any::<i32>()) { }
154
- }
155
- ```
156
-
157
- ## See Also
158
-
159
- - [test-criterion-bench](./test-criterion-bench.md) - Benchmarking
160
- - [test-mockall-mocking](./test-mockall-mocking.md) - Mocking
161
- - [test-arrange-act-assert](./test-arrange-act-assert.md) - Test structure
@@ -1,130 +0,0 @@
1
- # test-should-panic
2
-
3
- > Use `#[should_panic]` to test that code panics as expected
4
-
5
- ## Why It Matters
6
-
7
- Some code should panic on invalid inputs or invariant violations. `#[should_panic]` verifies the panic occurs, optionally checking the panic message. This ensures defensive panics work correctly and documents expected panic conditions.
8
-
9
- ## Bad
10
-
11
- ```rust
12
- #[test]
13
- fn test_panic() {
14
- // Just calling panicking code makes test fail
15
- divide(1, 0); // Test fails with panic
16
- }
17
-
18
- // Using catch_unwind is verbose
19
- #[test]
20
- fn test_panic_manual() {
21
- let result = std::panic::catch_unwind(|| divide(1, 0));
22
- assert!(result.is_err());
23
- }
24
- ```
25
-
26
- ## Good
27
-
28
- ```rust
29
- #[test]
30
- #[should_panic]
31
- fn divide_by_zero_panics() {
32
- divide(1, 0); // Test passes when this panics
33
- }
34
-
35
- // With expected message
36
- #[test]
37
- #[should_panic(expected = "division by zero")]
38
- fn divide_by_zero_panics_with_message() {
39
- divide(1, 0); // Panics with "division by zero"
40
- }
41
-
42
- // Partial message match
43
- #[test]
44
- #[should_panic(expected = "index out of bounds")]
45
- fn index_panic_contains_message() {
46
- let v = vec![1, 2, 3];
47
- let _ = v[100]; // Message contains "index out of bounds"
48
- }
49
- ```
50
-
51
- ## Testing Invariants
52
-
53
- ```rust
54
- struct NonEmpty<T>(Vec<T>);
55
-
56
- impl<T> NonEmpty<T> {
57
- fn new(items: Vec<T>) -> Self {
58
- assert!(!items.is_empty(), "NonEmpty cannot be empty");
59
- NonEmpty(items)
60
- }
61
- }
62
-
63
- #[test]
64
- #[should_panic(expected = "NonEmpty cannot be empty")]
65
- fn non_empty_rejects_empty_vec() {
66
- NonEmpty::new(Vec::<i32>::new());
67
- }
68
-
69
- #[test]
70
- fn non_empty_accepts_non_empty_vec() {
71
- let ne = NonEmpty::new(vec![1, 2, 3]);
72
- assert_eq!(ne.0.len(), 3);
73
- }
74
- ```
75
-
76
- ## With expect() Messages
77
-
78
- ```rust
79
- fn get_config_value(key: &str) -> String {
80
- CONFIG.get(key)
81
- .expect(&format!("missing required config: {}", key))
82
- .to_string()
83
- }
84
-
85
- #[test]
86
- #[should_panic(expected = "missing required config: DATABASE_URL")]
87
- fn missing_config_panics_with_key() {
88
- get_config_value("DATABASE_URL");
89
- }
90
- ```
91
-
92
- ## When NOT to Use should_panic
93
-
94
- ```rust
95
- // ❌ For recoverable errors - use Result
96
- #[test]
97
- #[should_panic] // Wrong: this should return Err, not panic
98
- fn invalid_input_panics() {
99
- parse_config("invalid"); // Should return Err, not panic
100
- }
101
-
102
- // ✅ Return Result and test the error
103
- #[test]
104
- fn invalid_input_returns_error() {
105
- let result = parse_config("invalid");
106
- assert!(result.is_err());
107
- }
108
- ```
109
-
110
- ## Combining with Result
111
-
112
- ```rust
113
- #[test]
114
- #[should_panic]
115
- fn test_panics() -> Result<(), Error> {
116
- // Can combine with Result for setup
117
- let data = setup_test_data()?;
118
-
119
- // This should panic
120
- process_invalid(&data);
121
-
122
- Ok(()) // Never reached
123
- }
124
- ```
125
-
126
- ## See Also
127
-
128
- - [err-result-over-panic](./err-result-over-panic.md) - Panic vs Result
129
- - [err-expect-bugs-only](./err-expect-bugs-only.md) - When to use expect
130
- - [test-descriptive-names](./test-descriptive-names.md) - Test naming