agy-superpowers 5.2.2 → 5.2.3
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.
- package/README.md +47 -150
- package/package.json +1 -1
- package/template/agent/rules/scratch-scripts.md +37 -0
- package/template/agent/rules/superpowers.md +4 -51
- package/template/agent/skills/ai-integrated-product/SKILL.md +0 -57
- package/template/agent/skills/analytics-setup/SKILL.md +0 -51
- package/template/agent/skills/api-design/SKILL.md +0 -193
- package/template/agent/skills/app-store-optimizer/SKILL.md +0 -127
- package/template/agent/skills/auth-and-identity/SKILL.md +0 -167
- package/template/agent/skills/backend-developer/SKILL.md +0 -148
- package/template/agent/skills/bootstrapper-finance/SKILL.md +0 -55
- package/template/agent/skills/chrome-extension-developer/SKILL.md +0 -53
- package/template/agent/skills/community-manager/SKILL.md +0 -115
- package/template/agent/skills/content-marketer/SKILL.md +0 -111
- package/template/agent/skills/conversion-optimizer/SKILL.md +0 -142
- package/template/agent/skills/cto-architect/SKILL.md +0 -133
- package/template/agent/skills/customer-success-manager/SKILL.md +0 -126
- package/template/agent/skills/data-analyst/SKILL.md +0 -147
- package/template/agent/skills/devops-engineer/SKILL.md +0 -117
- package/template/agent/skills/email-infrastructure/SKILL.md +0 -164
- package/template/agent/skills/game-design/SKILL.md +0 -194
- package/template/agent/skills/game-developer/SKILL.md +0 -175
- package/template/agent/skills/growth-hacker/SKILL.md +0 -122
- package/template/agent/skills/idea-validator/SKILL.md +0 -55
- package/template/agent/skills/indie-legal/SKILL.md +0 -53
- package/template/agent/skills/influencer-marketer/SKILL.md +0 -141
- package/template/agent/skills/landing-page-builder/SKILL.md +0 -59
- package/template/agent/skills/launch-strategist/SKILL.md +0 -62
- package/template/agent/skills/market-researcher/SKILL.md +0 -53
- package/template/agent/skills/micro-saas-builder/SKILL.md +0 -56
- package/template/agent/skills/monetization-strategist/SKILL.md +0 -119
- package/template/agent/skills/paid-acquisition-specialist/SKILL.md +0 -119
- package/template/agent/skills/pricing-psychologist/SKILL.md +0 -58
- package/template/agent/skills/real-time-features/SKILL.md +0 -194
- package/template/agent/skills/retention-specialist/SKILL.md +0 -123
- package/template/agent/skills/rust-developer/SKILL.md +0 -281
- package/template/agent/skills/rust-developer/references/rust-rules/_sections.md +0 -231
- package/template/agent/skills/rust-developer/references/rust-rules/anti-clone-excessive.md +0 -124
- package/template/agent/skills/rust-developer/references/rust-rules/anti-collect-intermediate.md +0 -131
- package/template/agent/skills/rust-developer/references/rust-rules/anti-empty-catch.md +0 -132
- package/template/agent/skills/rust-developer/references/rust-rules/anti-expect-lazy.md +0 -95
- package/template/agent/skills/rust-developer/references/rust-rules/anti-format-hot-path.md +0 -141
- package/template/agent/skills/rust-developer/references/rust-rules/anti-index-over-iter.md +0 -125
- package/template/agent/skills/rust-developer/references/rust-rules/anti-lock-across-await.md +0 -127
- package/template/agent/skills/rust-developer/references/rust-rules/anti-over-abstraction.md +0 -120
- package/template/agent/skills/rust-developer/references/rust-rules/anti-panic-expected.md +0 -131
- package/template/agent/skills/rust-developer/references/rust-rules/anti-premature-optimize.md +0 -156
- package/template/agent/skills/rust-developer/references/rust-rules/anti-string-for-str.md +0 -122
- package/template/agent/skills/rust-developer/references/rust-rules/anti-stringly-typed.md +0 -167
- package/template/agent/skills/rust-developer/references/rust-rules/anti-type-erasure.md +0 -134
- package/template/agent/skills/rust-developer/references/rust-rules/anti-unwrap-abuse.md +0 -143
- package/template/agent/skills/rust-developer/references/rust-rules/anti-vec-for-slice.md +0 -121
- package/template/agent/skills/rust-developer/references/rust-rules/api-builder-must-use.md +0 -143
- package/template/agent/skills/rust-developer/references/rust-rules/api-builder-pattern.md +0 -187
- package/template/agent/skills/rust-developer/references/rust-rules/api-common-traits.md +0 -165
- package/template/agent/skills/rust-developer/references/rust-rules/api-default-impl.md +0 -177
- package/template/agent/skills/rust-developer/references/rust-rules/api-extension-trait.md +0 -163
- package/template/agent/skills/rust-developer/references/rust-rules/api-from-not-into.md +0 -146
- package/template/agent/skills/rust-developer/references/rust-rules/api-impl-asref.md +0 -142
- package/template/agent/skills/rust-developer/references/rust-rules/api-impl-into.md +0 -160
- package/template/agent/skills/rust-developer/references/rust-rules/api-must-use.md +0 -125
- package/template/agent/skills/rust-developer/references/rust-rules/api-newtype-safety.md +0 -162
- package/template/agent/skills/rust-developer/references/rust-rules/api-non-exhaustive.md +0 -177
- package/template/agent/skills/rust-developer/references/rust-rules/api-parse-dont-validate.md +0 -184
- package/template/agent/skills/rust-developer/references/rust-rules/api-sealed-trait.md +0 -168
- package/template/agent/skills/rust-developer/references/rust-rules/api-serde-optional.md +0 -182
- package/template/agent/skills/rust-developer/references/rust-rules/api-typestate.md +0 -199
- package/template/agent/skills/rust-developer/references/rust-rules/async-bounded-channel.md +0 -175
- package/template/agent/skills/rust-developer/references/rust-rules/async-broadcast-pubsub.md +0 -185
- package/template/agent/skills/rust-developer/references/rust-rules/async-cancellation-token.md +0 -203
- package/template/agent/skills/rust-developer/references/rust-rules/async-clone-before-await.md +0 -171
- package/template/agent/skills/rust-developer/references/rust-rules/async-join-parallel.md +0 -158
- package/template/agent/skills/rust-developer/references/rust-rules/async-joinset-structured.md +0 -195
- package/template/agent/skills/rust-developer/references/rust-rules/async-mpsc-queue.md +0 -171
- package/template/agent/skills/rust-developer/references/rust-rules/async-no-lock-await.md +0 -156
- package/template/agent/skills/rust-developer/references/rust-rules/async-oneshot-response.md +0 -191
- package/template/agent/skills/rust-developer/references/rust-rules/async-select-racing.md +0 -198
- package/template/agent/skills/rust-developer/references/rust-rules/async-spawn-blocking.md +0 -154
- package/template/agent/skills/rust-developer/references/rust-rules/async-tokio-fs.md +0 -167
- package/template/agent/skills/rust-developer/references/rust-rules/async-tokio-runtime.md +0 -169
- package/template/agent/skills/rust-developer/references/rust-rules/async-try-join.md +0 -172
- package/template/agent/skills/rust-developer/references/rust-rules/async-watch-latest.md +0 -189
- package/template/agent/skills/rust-developer/references/rust-rules/doc-all-public.md +0 -113
- package/template/agent/skills/rust-developer/references/rust-rules/doc-cargo-metadata.md +0 -147
- package/template/agent/skills/rust-developer/references/rust-rules/doc-errors-section.md +0 -122
- package/template/agent/skills/rust-developer/references/rust-rules/doc-examples-section.md +0 -161
- package/template/agent/skills/rust-developer/references/rust-rules/doc-hidden-setup.md +0 -149
- package/template/agent/skills/rust-developer/references/rust-rules/doc-intra-links.md +0 -138
- package/template/agent/skills/rust-developer/references/rust-rules/doc-link-types.md +0 -169
- package/template/agent/skills/rust-developer/references/rust-rules/doc-module-inner.md +0 -116
- package/template/agent/skills/rust-developer/references/rust-rules/doc-panics-section.md +0 -128
- package/template/agent/skills/rust-developer/references/rust-rules/doc-question-mark.md +0 -136
- package/template/agent/skills/rust-developer/references/rust-rules/doc-safety-section.md +0 -131
- package/template/agent/skills/rust-developer/references/rust-rules/err-anyhow-app.md +0 -179
- package/template/agent/skills/rust-developer/references/rust-rules/err-context-chain.md +0 -144
- package/template/agent/skills/rust-developer/references/rust-rules/err-custom-type.md +0 -152
- package/template/agent/skills/rust-developer/references/rust-rules/err-doc-errors.md +0 -145
- package/template/agent/skills/rust-developer/references/rust-rules/err-expect-bugs-only.md +0 -133
- package/template/agent/skills/rust-developer/references/rust-rules/err-from-impl.md +0 -152
- package/template/agent/skills/rust-developer/references/rust-rules/err-lowercase-msg.md +0 -124
- package/template/agent/skills/rust-developer/references/rust-rules/err-no-unwrap-prod.md +0 -115
- package/template/agent/skills/rust-developer/references/rust-rules/err-question-mark.md +0 -151
- package/template/agent/skills/rust-developer/references/rust-rules/err-result-over-panic.md +0 -130
- package/template/agent/skills/rust-developer/references/rust-rules/err-source-chain.md +0 -155
- package/template/agent/skills/rust-developer/references/rust-rules/err-thiserror-lib.md +0 -171
- package/template/agent/skills/rust-developer/references/rust-rules/lint-cargo-metadata.md +0 -138
- package/template/agent/skills/rust-developer/references/rust-rules/lint-deny-correctness.md +0 -107
- package/template/agent/skills/rust-developer/references/rust-rules/lint-missing-docs.md +0 -154
- package/template/agent/skills/rust-developer/references/rust-rules/lint-pedantic-selective.md +0 -118
- package/template/agent/skills/rust-developer/references/rust-rules/lint-rustfmt-check.md +0 -157
- package/template/agent/skills/rust-developer/references/rust-rules/lint-unsafe-doc.md +0 -133
- package/template/agent/skills/rust-developer/references/rust-rules/lint-warn-complexity.md +0 -131
- package/template/agent/skills/rust-developer/references/rust-rules/lint-warn-perf.md +0 -136
- package/template/agent/skills/rust-developer/references/rust-rules/lint-warn-style.md +0 -135
- package/template/agent/skills/rust-developer/references/rust-rules/lint-warn-suspicious.md +0 -122
- package/template/agent/skills/rust-developer/references/rust-rules/lint-workspace-lints.md +0 -172
- package/template/agent/skills/rust-developer/references/rust-rules/mem-arena-allocator.md +0 -168
- package/template/agent/skills/rust-developer/references/rust-rules/mem-arrayvec.md +0 -142
- package/template/agent/skills/rust-developer/references/rust-rules/mem-assert-type-size.md +0 -168
- package/template/agent/skills/rust-developer/references/rust-rules/mem-avoid-format.md +0 -147
- package/template/agent/skills/rust-developer/references/rust-rules/mem-box-large-variant.md +0 -158
- package/template/agent/skills/rust-developer/references/rust-rules/mem-boxed-slice.md +0 -139
- package/template/agent/skills/rust-developer/references/rust-rules/mem-clone-from.md +0 -147
- package/template/agent/skills/rust-developer/references/rust-rules/mem-compact-string.md +0 -149
- package/template/agent/skills/rust-developer/references/rust-rules/mem-reuse-collections.md +0 -174
- package/template/agent/skills/rust-developer/references/rust-rules/mem-smaller-integers.md +0 -159
- package/template/agent/skills/rust-developer/references/rust-rules/mem-smallvec.md +0 -138
- package/template/agent/skills/rust-developer/references/rust-rules/mem-thinvec.md +0 -142
- package/template/agent/skills/rust-developer/references/rust-rules/mem-with-capacity.md +0 -156
- package/template/agent/skills/rust-developer/references/rust-rules/mem-write-over-format.md +0 -172
- package/template/agent/skills/rust-developer/references/rust-rules/mem-zero-copy.md +0 -164
- package/template/agent/skills/rust-developer/references/rust-rules/name-acronym-word.md +0 -99
- package/template/agent/skills/rust-developer/references/rust-rules/name-as-free.md +0 -104
- package/template/agent/skills/rust-developer/references/rust-rules/name-consts-screaming.md +0 -94
- package/template/agent/skills/rust-developer/references/rust-rules/name-crate-no-rs.md +0 -78
- package/template/agent/skills/rust-developer/references/rust-rules/name-funcs-snake.md +0 -76
- package/template/agent/skills/rust-developer/references/rust-rules/name-into-ownership.md +0 -123
- package/template/agent/skills/rust-developer/references/rust-rules/name-is-has-bool.md +0 -127
- package/template/agent/skills/rust-developer/references/rust-rules/name-iter-convention.md +0 -129
- package/template/agent/skills/rust-developer/references/rust-rules/name-iter-method.md +0 -131
- package/template/agent/skills/rust-developer/references/rust-rules/name-iter-type-match.md +0 -142
- package/template/agent/skills/rust-developer/references/rust-rules/name-lifetime-short.md +0 -86
- package/template/agent/skills/rust-developer/references/rust-rules/name-no-get-prefix.md +0 -154
- package/template/agent/skills/rust-developer/references/rust-rules/name-to-expensive.md +0 -118
- package/template/agent/skills/rust-developer/references/rust-rules/name-type-param-single.md +0 -92
- package/template/agent/skills/rust-developer/references/rust-rules/name-types-camel.md +0 -65
- package/template/agent/skills/rust-developer/references/rust-rules/name-variants-camel.md +0 -101
- package/template/agent/skills/rust-developer/references/rust-rules/opt-bounds-check.md +0 -161
- package/template/agent/skills/rust-developer/references/rust-rules/opt-cache-friendly.md +0 -187
- package/template/agent/skills/rust-developer/references/rust-rules/opt-codegen-units.md +0 -142
- package/template/agent/skills/rust-developer/references/rust-rules/opt-cold-unlikely.md +0 -152
- package/template/agent/skills/rust-developer/references/rust-rules/opt-inline-always-rare.md +0 -141
- package/template/agent/skills/rust-developer/references/rust-rules/opt-inline-never-cold.md +0 -181
- package/template/agent/skills/rust-developer/references/rust-rules/opt-inline-small.md +0 -160
- package/template/agent/skills/rust-developer/references/rust-rules/opt-likely-hint.md +0 -171
- package/template/agent/skills/rust-developer/references/rust-rules/opt-lto-release.md +0 -130
- package/template/agent/skills/rust-developer/references/rust-rules/opt-pgo-profile.md +0 -167
- package/template/agent/skills/rust-developer/references/rust-rules/opt-simd-portable.md +0 -144
- package/template/agent/skills/rust-developer/references/rust-rules/opt-target-cpu.md +0 -154
- package/template/agent/skills/rust-developer/references/rust-rules/own-arc-shared.md +0 -141
- package/template/agent/skills/rust-developer/references/rust-rules/own-borrow-over-clone.md +0 -95
- package/template/agent/skills/rust-developer/references/rust-rules/own-clone-explicit.md +0 -135
- package/template/agent/skills/rust-developer/references/rust-rules/own-copy-small.md +0 -124
- package/template/agent/skills/rust-developer/references/rust-rules/own-cow-conditional.md +0 -135
- package/template/agent/skills/rust-developer/references/rust-rules/own-lifetime-elision.md +0 -134
- package/template/agent/skills/rust-developer/references/rust-rules/own-move-large.md +0 -134
- package/template/agent/skills/rust-developer/references/rust-rules/own-mutex-interior.md +0 -105
- package/template/agent/skills/rust-developer/references/rust-rules/own-rc-single-thread.md +0 -65
- package/template/agent/skills/rust-developer/references/rust-rules/own-refcell-interior.md +0 -97
- package/template/agent/skills/rust-developer/references/rust-rules/own-rwlock-readers.md +0 -122
- package/template/agent/skills/rust-developer/references/rust-rules/own-slice-over-vec.md +0 -119
- package/template/agent/skills/rust-developer/references/rust-rules/perf-black-box-bench.md +0 -153
- package/template/agent/skills/rust-developer/references/rust-rules/perf-chain-avoid.md +0 -136
- package/template/agent/skills/rust-developer/references/rust-rules/perf-collect-into.md +0 -133
- package/template/agent/skills/rust-developer/references/rust-rules/perf-collect-once.md +0 -120
- package/template/agent/skills/rust-developer/references/rust-rules/perf-drain-reuse.md +0 -137
- package/template/agent/skills/rust-developer/references/rust-rules/perf-entry-api.md +0 -134
- package/template/agent/skills/rust-developer/references/rust-rules/perf-extend-batch.md +0 -150
- package/template/agent/skills/rust-developer/references/rust-rules/perf-iter-lazy.md +0 -123
- package/template/agent/skills/rust-developer/references/rust-rules/perf-iter-over-index.md +0 -113
- package/template/agent/skills/rust-developer/references/rust-rules/perf-profile-first.md +0 -175
- package/template/agent/skills/rust-developer/references/rust-rules/perf-release-profile.md +0 -149
- package/template/agent/skills/rust-developer/references/rust-rules/proj-bin-dir.md +0 -142
- package/template/agent/skills/rust-developer/references/rust-rules/proj-flat-small.md +0 -133
- package/template/agent/skills/rust-developer/references/rust-rules/proj-lib-main-split.md +0 -148
- package/template/agent/skills/rust-developer/references/rust-rules/proj-mod-by-feature.md +0 -130
- package/template/agent/skills/rust-developer/references/rust-rules/proj-mod-rs-dir.md +0 -120
- package/template/agent/skills/rust-developer/references/rust-rules/proj-prelude-module.md +0 -155
- package/template/agent/skills/rust-developer/references/rust-rules/proj-pub-crate-internal.md +0 -139
- package/template/agent/skills/rust-developer/references/rust-rules/proj-pub-super-parent.md +0 -135
- package/template/agent/skills/rust-developer/references/rust-rules/proj-pub-use-reexport.md +0 -162
- package/template/agent/skills/rust-developer/references/rust-rules/proj-workspace-deps.md +0 -186
- package/template/agent/skills/rust-developer/references/rust-rules/proj-workspace-large.md +0 -162
- package/template/agent/skills/rust-developer/references/rust-rules/test-arrange-act-assert.md +0 -160
- package/template/agent/skills/rust-developer/references/rust-rules/test-cfg-test-module.md +0 -151
- package/template/agent/skills/rust-developer/references/rust-rules/test-criterion-bench.md +0 -171
- package/template/agent/skills/rust-developer/references/rust-rules/test-descriptive-names.md +0 -142
- package/template/agent/skills/rust-developer/references/rust-rules/test-doctest-examples.md +0 -168
- package/template/agent/skills/rust-developer/references/rust-rules/test-fixture-raii.md +0 -151
- package/template/agent/skills/rust-developer/references/rust-rules/test-integration-dir.md +0 -144
- package/template/agent/skills/rust-developer/references/rust-rules/test-mock-traits.md +0 -189
- package/template/agent/skills/rust-developer/references/rust-rules/test-mockall-mocking.md +0 -226
- package/template/agent/skills/rust-developer/references/rust-rules/test-proptest-properties.md +0 -161
- package/template/agent/skills/rust-developer/references/rust-rules/test-should-panic.md +0 -130
- package/template/agent/skills/rust-developer/references/rust-rules/test-tokio-async.md +0 -154
- package/template/agent/skills/rust-developer/references/rust-rules/test-use-super.md +0 -127
- package/template/agent/skills/rust-developer/references/rust-rules/type-enum-states.md +0 -154
- package/template/agent/skills/rust-developer/references/rust-rules/type-generic-bounds.md +0 -142
- package/template/agent/skills/rust-developer/references/rust-rules/type-never-diverge.md +0 -146
- package/template/agent/skills/rust-developer/references/rust-rules/type-newtype-ids.md +0 -160
- package/template/agent/skills/rust-developer/references/rust-rules/type-newtype-validated.md +0 -159
- package/template/agent/skills/rust-developer/references/rust-rules/type-no-stringly.md +0 -144
- package/template/agent/skills/rust-developer/references/rust-rules/type-option-nullable.md +0 -137
- package/template/agent/skills/rust-developer/references/rust-rules/type-phantom-marker.md +0 -188
- package/template/agent/skills/rust-developer/references/rust-rules/type-repr-transparent.md +0 -143
- package/template/agent/skills/rust-developer/references/rust-rules/type-result-fallible.md +0 -131
- package/template/agent/skills/saas-architect/SKILL.md +0 -139
- package/template/agent/skills/security-engineer/SKILL.md +0 -133
- package/template/agent/skills/seo-specialist/SKILL.md +0 -130
- package/template/agent/skills/solo-founder-ops/SKILL.md +0 -56
|
@@ -1,144 +0,0 @@
|
|
|
1
|
-
# test-integration-dir
|
|
2
|
-
|
|
3
|
-
> Put integration tests in the `tests/` directory
|
|
4
|
-
|
|
5
|
-
## Why It Matters
|
|
6
|
-
|
|
7
|
-
Integration tests live in `tests/` at the crate root, separate from `src/`. Each file in `tests/` is compiled as a separate crate, testing your library's public API as external users would. This separation ensures you're testing the real public interface, not implementation details.
|
|
8
|
-
|
|
9
|
-
## Structure
|
|
10
|
-
|
|
11
|
-
```
|
|
12
|
-
my_project/
|
|
13
|
-
├── Cargo.toml
|
|
14
|
-
├── src/
|
|
15
|
-
│ ├── lib.rs
|
|
16
|
-
│ └── internal.rs
|
|
17
|
-
└── tests/
|
|
18
|
-
├── integration_test.rs # Each file is a separate test binary
|
|
19
|
-
├── api_tests.rs
|
|
20
|
-
└── common/ # Shared test utilities
|
|
21
|
-
└── mod.rs
|
|
22
|
-
```
|
|
23
|
-
|
|
24
|
-
## Bad
|
|
25
|
-
|
|
26
|
-
```rust
|
|
27
|
-
// src/lib.rs
|
|
28
|
-
// Mixing integration test logic in library code
|
|
29
|
-
#[test]
|
|
30
|
-
fn integration_test_full_workflow() {
|
|
31
|
-
// This is a unit test location, not integration
|
|
32
|
-
}
|
|
33
|
-
```
|
|
34
|
-
|
|
35
|
-
## Good
|
|
36
|
-
|
|
37
|
-
```rust
|
|
38
|
-
// tests/integration_test.rs
|
|
39
|
-
use my_crate::{Client, Config}; // Uses public API only
|
|
40
|
-
|
|
41
|
-
#[test]
|
|
42
|
-
fn test_full_workflow() {
|
|
43
|
-
let config = Config::default();
|
|
44
|
-
let client = Client::new(config);
|
|
45
|
-
|
|
46
|
-
let result = client.process("input");
|
|
47
|
-
assert!(result.is_ok());
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
#[test]
|
|
51
|
-
fn test_error_handling() {
|
|
52
|
-
let client = Client::new(Config::strict());
|
|
53
|
-
|
|
54
|
-
let result = client.process("invalid");
|
|
55
|
-
assert!(matches!(result, Err(Error::InvalidInput { .. })));
|
|
56
|
-
}
|
|
57
|
-
```
|
|
58
|
-
|
|
59
|
-
## Shared Test Utilities
|
|
60
|
-
|
|
61
|
-
```rust
|
|
62
|
-
// tests/common/mod.rs
|
|
63
|
-
use my_crate::Config;
|
|
64
|
-
|
|
65
|
-
pub fn test_config() -> Config {
|
|
66
|
-
Config {
|
|
67
|
-
timeout: Duration::from_secs(5),
|
|
68
|
-
retries: 3,
|
|
69
|
-
debug: true,
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
pub fn setup_test_environment() {
|
|
74
|
-
// Set up test fixtures
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
// tests/api_tests.rs
|
|
78
|
-
mod common;
|
|
79
|
-
|
|
80
|
-
use my_crate::Client;
|
|
81
|
-
|
|
82
|
-
#[test]
|
|
83
|
-
fn test_with_shared_config() {
|
|
84
|
-
common::setup_test_environment();
|
|
85
|
-
let client = Client::new(common::test_config());
|
|
86
|
-
// ...
|
|
87
|
-
}
|
|
88
|
-
```
|
|
89
|
-
|
|
90
|
-
## Organizing Many Tests
|
|
91
|
-
|
|
92
|
-
```rust
|
|
93
|
-
// tests/api/mod.rs
|
|
94
|
-
mod auth;
|
|
95
|
-
mod users;
|
|
96
|
-
mod orders;
|
|
97
|
-
|
|
98
|
-
// tests/api/auth.rs
|
|
99
|
-
use my_crate::auth::{login, logout};
|
|
100
|
-
|
|
101
|
-
#[test]
|
|
102
|
-
fn test_login_success() { ... }
|
|
103
|
-
|
|
104
|
-
#[test]
|
|
105
|
-
fn test_login_invalid_credentials() { ... }
|
|
106
|
-
|
|
107
|
-
// tests/api/users.rs
|
|
108
|
-
use my_crate::users::{create_user, get_user};
|
|
109
|
-
|
|
110
|
-
#[test]
|
|
111
|
-
fn test_create_user() { ... }
|
|
112
|
-
```
|
|
113
|
-
|
|
114
|
-
## Integration vs Unit Tests
|
|
115
|
-
|
|
116
|
-
| Unit Tests | Integration Tests |
|
|
117
|
-
|------------|-------------------|
|
|
118
|
-
| In `src/` with `#[cfg(test)]` | In `tests/` directory |
|
|
119
|
-
| Access private items | Public API only |
|
|
120
|
-
| Test individual functions | Test module interactions |
|
|
121
|
-
| Fast, isolated | May be slower |
|
|
122
|
-
| `cargo test --lib` | `cargo test --test '*'` |
|
|
123
|
-
|
|
124
|
-
## Running Specific Tests
|
|
125
|
-
|
|
126
|
-
```bash
|
|
127
|
-
# Run all tests
|
|
128
|
-
cargo test
|
|
129
|
-
|
|
130
|
-
# Run only integration tests
|
|
131
|
-
cargo test --test '*'
|
|
132
|
-
|
|
133
|
-
# Run specific integration test file
|
|
134
|
-
cargo test --test integration_test
|
|
135
|
-
|
|
136
|
-
# Run tests matching pattern
|
|
137
|
-
cargo test --test api_tests test_login
|
|
138
|
-
```
|
|
139
|
-
|
|
140
|
-
## See Also
|
|
141
|
-
|
|
142
|
-
- [test-cfg-test-module](./test-cfg-test-module.md) - Unit test modules
|
|
143
|
-
- [test-descriptive-names](./test-descriptive-names.md) - Test naming
|
|
144
|
-
- [test-tokio-async](./test-tokio-async.md) - Async integration tests
|
|
@@ -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
|
package/template/agent/skills/rust-developer/references/rust-rules/test-proptest-properties.md
DELETED
|
@@ -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
|