Skip to content

Commit 32a749d

Browse files
test(stackable-versioned): Add snapshot testing (#881)
* test: Add default snapshot testing * chore: Accept snapshots * test: Rename basic snapshot test * Update crates/stackable-versioned-macros/fixtures/README.md Co-authored-by: Nick <10092581+NickLarsenNZ@users.noreply.github.com> * chore: Update snapshot testing README * chore: Mark .snap files as generated * chore: Add k8s snapshot test, rework test utils * chore: Move compile-fail tests * test: Add k8s feature gate * test: Update stderr output files * chore: Mark .stderr files as generated * chore: Add changelog entry * chore: Partial revert of ff2fd24 --------- Co-authored-by: Nick <10092581+NickLarsenNZ@users.noreply.github.com>
1 parent 8b0172d commit 32a749d

38 files changed

+1129
-371
lines changed

.gitattributes

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
*.stderr linguist-generated
2+
*.snap linguist-generated

Cargo.lock

+90
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

+11-4
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ either = "1.13.0"
2626
futures = "0.3.30"
2727
futures-util = "0.3.30"
2828
indexmap = "2.5"
29+
insta = { version= "1.40", features = ["glob"] }
2930
hyper = { version = "1.4.1", features = ["full"] }
3031
hyper-util = "0.1.8"
3132
itertools = "0.13.0"
@@ -41,6 +42,7 @@ opentelemetry-otlp = "0.16.0"
4142
opentelemetry-semantic-conventions = "0.15.0"
4243
p256 = { version = "0.13.2", features = ["ecdsa"] }
4344
pin-project = "1.1.5"
45+
prettyplease = "0.2.22"
4446
proc-macro2 = "1.0.86"
4547
quote = "1.0.37"
4648
rand = "0.8.5"
@@ -77,7 +79,12 @@ x509-cert = { version = "0.2.5", features = ["builder"] }
7779
zeroize = "1.8.1"
7880

7981
# Use O3 in tests to improve the RSA key generation speed in the stackable-certs crate
80-
[profile.test.package.stackable-certs]
81-
opt-level = 3
82-
[profile.test.package."rsa"]
83-
opt-level = 3
82+
[profile.test.package]
83+
stackable-certs.opt-level = 3
84+
rsa.opt-level = 3
85+
86+
# Run snapshot testing faster even as a dev dependecy.
87+
# See https://insta.rs/docs/quickstart/#optional-faster-runs
88+
[profile.dev.package]
89+
insta.opt-level = 3
90+
similar.opt-level = 3

crates/stackable-versioned-macros/Cargo.toml

+4
Original file line numberDiff line numberDiff line change
@@ -38,9 +38,13 @@ syn.workspace = true
3838
quote.workspace = true
3939

4040
[dev-dependencies]
41+
insta.workspace = true
42+
prettyplease.workspace = true
43+
regex.workspace = true
4144
rstest.workspace = true
4245
schemars.workspace = true
4346
serde.workspace = true
4447
serde_json.workspace = true
4548
serde_yaml.workspace = true
49+
snafu.workspace = true
4650
trybuild.workspace = true
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
# Snapshot Testing
2+
3+
> [!NOTE]
4+
> Also see the compile-fail tests, described [here](../tests/README.md).
5+
6+
This folder contains fixtures for snapshot testing the `#[versioned()]` macro. Snapshot testing is
7+
done using the [insta] crate. It provides a [CLI tool][insta-cli] called `cargo-insta` and a
8+
[VS Code extension][insta-ext].
9+
10+
Test inputs and snapshots of the expected output are located in the `fixtures` folder. There are two
11+
inputs to the `#[versioned()]` macro because it is an attribute macro:
12+
13+
> The first TokenStream is the delimited token tree following the attribute’s name, not including
14+
> the outer delimiters. If the attribute is written as a bare attribute name, the attribute
15+
> TokenStream is empty. The second TokenStream is the rest of the item including other attributes on
16+
> the item.
17+
>
18+
> _(Taken from the [Rust reference][rust-ref])_
19+
20+
Because of that, a special delimiter is used in the input files which separates the two inputs while
21+
still enabling developers to write valid Rust code. The delimiter is `// ---\n`. Most of the inner
22+
workings are located in [this file](../src/test_utils.rs).
23+
24+
```rust
25+
#[versioned(
26+
version(name = "v1alpha1"),
27+
version(name = "v1beta1"),
28+
version(name = "v1")
29+
)]
30+
// --- <- See here!
31+
pub(crate) struct Foo {
32+
#[versioned(
33+
changed(since = "v1beta1", from_name = "jjj", from_type = "u8"),
34+
changed(since = "v1", from_type = "u16"),
35+
)]
36+
bar: usize,
37+
baz: bool,
38+
}
39+
```
40+
41+
## Recommended Workflow
42+
43+
First, add new input files (which automatically get picked up by `insta`) to the `fixtures/inputs`
44+
folder. Make sure the delimiter is placed correctly between the attribute and the container
45+
definition. Doc comments on the container have to be placed after the delimiter. Next, generate the
46+
snapshot files (initially not accepted) by running
47+
48+
```shell
49+
cargo insta test -p stackable-versioned-macros
50+
```
51+
52+
This command will place the new snapshot files (with a `.new` extension) in the `fixtures/snapshots`
53+
folder. These new snapshot files must not appear on `main`, but can be shared on branches for
54+
collaboration. To review them, run the `cargo insta review` command, then accept or fix the
55+
snapshots. Once all are accepted (ie: no `.new` files remaining), check in the files.
56+
57+
[rust-ref]: https://doc.rust-lang.org/reference/procedural-macros.html#attribute-macros
58+
[insta-ext]: https://insta.rs/docs/vscode/
59+
[insta-cli]: https://insta.rs/docs/cli/
60+
[insta]: https://insta.rs/
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
#[versioned(
2+
version(name = "v1alpha1"),
3+
version(
4+
name = "v1beta1",
5+
doc = r#"
6+
Additional docs for this version which are purposefully long to
7+
show how manual line wrapping works. \
8+
Multi-line docs are also supported, as per regular doc-comments.
9+
"#
10+
),
11+
version(name = "v1beta2"),
12+
version(name = "v1"),
13+
version(name = "v2"),
14+
options(skip(from))
15+
)]
16+
// ---
17+
#[derive(Default)]
18+
enum Foo {
19+
/// This variant is available in every version (so far).
20+
#[default]
21+
Foo,
22+
23+
/// Keep the main field docs the same, even after the field is
24+
/// deprecated.
25+
#[versioned(deprecated(since = "v1beta1", note = "gone"))]
26+
DeprecatedBar,
27+
28+
/// This is for baz
29+
#[versioned(added(since = "v1beta1"))]
30+
// Just to check stackable-versioned deprecation warning appears.
31+
// #[deprecated]
32+
Baz,
33+
34+
/// This is will keep changing over time.
35+
#[versioned(changed(since = "v1beta1", from_name = "Qoox"))]
36+
#[versioned(changed(since = "v1", from_name = "Qaax"))]
37+
Quux,
38+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
#[versioned(
2+
version(name = "v1alpha1"),
3+
version(
4+
name = "v1beta1",
5+
doc = r#"
6+
Additional docs for this version which are purposefully long to
7+
show how manual line wrapping works. \
8+
Multi-line docs are also supported, as per regular doc-comments.
9+
"#
10+
),
11+
version(name = "v1beta2"),
12+
version(name = "v1"),
13+
version(name = "v2"),
14+
options(skip(from))
15+
)]
16+
// ---
17+
/// Test
18+
#[derive(Default)]
19+
struct Foo {
20+
/// This field is available in every version (so far).
21+
foo: String,
22+
23+
/// Keep the main field docs the same, even after the field is deprecated.
24+
#[versioned(deprecated(since = "v1beta1", note = "gone"))]
25+
deprecated_bar: String,
26+
27+
/// This is for baz
28+
#[versioned(added(since = "v1beta1"))]
29+
baz: String,
30+
31+
/// This is will keep changing over time.
32+
#[versioned(changed(since = "v1beta1", from_name = "qoox"))]
33+
#[versioned(changed(since = "v1", from_name = "qaax"))]
34+
quux: String,
35+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
#[versioned(
2+
version(name = "v1alpha1", deprecated),
3+
version(name = "v1beta1"),
4+
version(name = "v1"),
5+
version(name = "v2"),
6+
version(name = "v3")
7+
)]
8+
// ---
9+
pub(crate) struct Foo {
10+
#[versioned(
11+
changed(since = "v1beta1", from_name = "jjj", from_type = "u8"),
12+
changed(since = "v1", from_type = "u16"),
13+
deprecated(since = "v2", note = "not empty")
14+
)]
15+
/// Test
16+
deprecated_bar: usize,
17+
baz: bool,
18+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
#[versioned(
2+
version(name = "v1alpha1"),
3+
version(name = "v1beta1"),
4+
version(name = "v1"),
5+
version(name = "v2"),
6+
version(name = "v3")
7+
)]
8+
// ---
9+
enum Foo {
10+
#[versioned(deprecated(since = "v1"))]
11+
DeprecatedBar,
12+
Baz,
13+
}

0 commit comments

Comments
 (0)