From 0a870333a60e435b3653eaa5f8b794befed44466 Mon Sep 17 00:00:00 2001
From: Nick Larsen <nick.larsen@stackable.tech>
Date: Fri, 23 Aug 2024 10:01:49 +0200
Subject: [PATCH 1/3] fix(script): be more explicit about where to find
 Cargo.tomls

---
 .scripts/verify_crate_versions.sh | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/.scripts/verify_crate_versions.sh b/.scripts/verify_crate_versions.sh
index 7a516403e..d0ca5399d 100755
--- a/.scripts/verify_crate_versions.sh
+++ b/.scripts/verify_crate_versions.sh
@@ -11,7 +11,7 @@ set -euo pipefail
 # stackable-versioned-0.1.1
 # stackable-webhook-0.3.1
 
-for CRATE in $(find . -mindepth 2 -name Cargo.toml | sed -e 's|^./crates/\([a-z0-9_\-]\+\).*|\1|' | sort); do
+for CRATE in $(find ./crates/ -mindepth 2 -name Cargo.toml -print0 | xargs -0 -n 1 dirname | xargs -n 1 basename | sort); do
     # Get the version in Cargo.toml
     CRATE_VERSION=$(grep 'version' "./crates/$CRATE/Cargo.toml" | grep -oE '[0-9]+\.[0-9]+\.[0-9]+' | head -1)
     [ -n "$CRATE_VERSION" ] || (

From 8aac6def41d06ec855d8a8f0d8f4ab99beb67b3b Mon Sep 17 00:00:00 2001
From: Nick Larsen <nick.larsen@stackable.tech>
Date: Fri, 23 Aug 2024 10:03:05 +0200
Subject: [PATCH 2/3] test(stackable-versioned-macros): move tests without
 assertions into trybuild pass/fail examples

---
 Cargo.lock                                    | 83 ++++++++++++++++++-
 Cargo.toml                                    |  1 +
 crates/stackable-versioned-macros/Cargo.toml  |  1 +
 .../tests/bad/README.md                       |  6 ++
 .../tests/bad/deprecate.rs                    | 14 ++++
 .../tests/bad/deprecate.stderr                |  5 ++
 .../tests/bad/skip_from_all.rs                | 24 ++++++
 .../tests/bad/skip_from_all.stderr            | 35 ++++++++
 .../tests/bad/skip_from_version.rs            | 24 ++++++
 .../tests/bad/skip_from_version.stderr        | 33 ++++++++
 .../stackable-versioned-macros/tests/from.rs  | 35 --------
 .../tests/good/README.md                      |  6 ++
 .../tests/good/attributes_enum.rs             | 43 ++++++++++
 .../attributes_struct.rs}                     | 48 +----------
 .../tests/{ => good}/basic.rs                 |  3 +-
 .../tests/{ => good}/deprecate.rs             |  3 +-
 .../tests/{ => good}/rename.rs                |  3 +-
 .../tests/good/skip_from_version.rs           | 28 +++++++
 .../tests/trybuild.rs                         | 40 +++++++++
 19 files changed, 345 insertions(+), 90 deletions(-)
 create mode 100644 crates/stackable-versioned-macros/tests/bad/README.md
 create mode 100644 crates/stackable-versioned-macros/tests/bad/deprecate.rs
 create mode 100644 crates/stackable-versioned-macros/tests/bad/deprecate.stderr
 create mode 100644 crates/stackable-versioned-macros/tests/bad/skip_from_all.rs
 create mode 100644 crates/stackable-versioned-macros/tests/bad/skip_from_all.stderr
 create mode 100644 crates/stackable-versioned-macros/tests/bad/skip_from_version.rs
 create mode 100644 crates/stackable-versioned-macros/tests/bad/skip_from_version.stderr
 create mode 100644 crates/stackable-versioned-macros/tests/good/README.md
 create mode 100644 crates/stackable-versioned-macros/tests/good/attributes_enum.rs
 rename crates/stackable-versioned-macros/tests/{attributes.rs => good/attributes_struct.rs} (56%)
 rename crates/stackable-versioned-macros/tests/{ => good}/basic.rs (98%)
 rename crates/stackable-versioned-macros/tests/{ => good}/deprecate.rs (92%)
 rename crates/stackable-versioned-macros/tests/{ => good}/rename.rs (93%)
 create mode 100644 crates/stackable-versioned-macros/tests/good/skip_from_version.rs
 create mode 100644 crates/stackable-versioned-macros/tests/trybuild.rs

diff --git a/Cargo.lock b/Cargo.lock
index 357d027e8..0a97a055a 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -2219,7 +2219,7 @@ version = "3.1.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "6d37c51ca738a55da99dc0c4a34860fd675453b8b36209178c2249bb13651284"
 dependencies = [
- "toml_edit",
+ "toml_edit 0.21.1",
 ]
 
 [[package]]
@@ -2714,6 +2714,15 @@ dependencies = [
  "serde",
 ]
 
+[[package]]
+name = "serde_spanned"
+version = "0.6.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "eb5b1b31579f3811bf615c144393417496f152e12ac8b7663bf664f4a815306d"
+dependencies = [
+ "serde",
+]
+
 [[package]]
 name = "serde_urlencoded"
 version = "0.7.1"
@@ -2991,6 +3000,7 @@ dependencies = [
  "rstest",
  "strum",
  "syn 2.0.74",
+ "trybuild",
 ]
 
 [[package]]
@@ -3098,6 +3108,15 @@ dependencies = [
  "windows-sys 0.59.0",
 ]
 
+[[package]]
+name = "termcolor"
+version = "1.4.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755"
+dependencies = [
+ "winapi-util",
+]
+
 [[package]]
 name = "thiserror"
 version = "1.0.63"
@@ -3291,11 +3310,26 @@ dependencies = [
  "tokio",
 ]
 
+[[package]]
+name = "toml"
+version = "0.8.19"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a1ed1f98e3fdc28d6d910e6737ae6ab1a93bf1985935a1193e68f93eeb68d24e"
+dependencies = [
+ "serde",
+ "serde_spanned",
+ "toml_datetime",
+ "toml_edit 0.22.20",
+]
+
 [[package]]
 name = "toml_datetime"
 version = "0.6.8"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41"
+dependencies = [
+ "serde",
+]
 
 [[package]]
 name = "toml_edit"
@@ -3305,7 +3339,20 @@ checksum = "6a8534fd7f78b5405e860340ad6575217ce99f38d4d5c8f2442cb5ecb50090e1"
 dependencies = [
  "indexmap 2.4.0",
  "toml_datetime",
- "winnow",
+ "winnow 0.5.40",
+]
+
+[[package]]
+name = "toml_edit"
+version = "0.22.20"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "583c44c02ad26b0c3f3066fe629275e50627026c51ac2e595cca4c230ce1ce1d"
+dependencies = [
+ "indexmap 2.4.0",
+ "serde",
+ "serde_spanned",
+ "toml_datetime",
+ "winnow 0.6.18",
 ]
 
 [[package]]
@@ -3498,6 +3545,20 @@ version = "0.2.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b"
 
+[[package]]
+name = "trybuild"
+version = "1.0.99"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "207aa50d36c4be8d8c6ea829478be44a372c6a77669937bb39c698e52f1491e8"
+dependencies = [
+ "glob",
+ "serde",
+ "serde_derive",
+ "serde_json",
+ "termcolor",
+ "toml",
+]
+
 [[package]]
 name = "typenum"
 version = "1.17.0"
@@ -3693,6 +3754,15 @@ version = "0.4.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
 
+[[package]]
+name = "winapi-util"
+version = "0.1.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb"
+dependencies = [
+ "windows-sys 0.59.0",
+]
+
 [[package]]
 name = "winapi-x86_64-pc-windows-gnu"
 version = "0.4.0"
@@ -3790,6 +3860,15 @@ dependencies = [
  "memchr",
 ]
 
+[[package]]
+name = "winnow"
+version = "0.6.18"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "68a9bda4691f099d435ad181000724da8e5899daa10713c2d432552b9ccd3a6f"
+dependencies = [
+ "memchr",
+]
+
 [[package]]
 name = "x509-cert"
 version = "0.2.5"
diff --git a/Cargo.toml b/Cargo.toml
index e2f7893f2..85b99aa73 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -70,6 +70,7 @@ tracing = "0.1.40"
 tracing-appender = "0.2.3"
 tracing-opentelemetry = "0.24.0"
 tracing-subscriber = { version = "0.3.18", features = ["env-filter", "json"] }
+trybuild = "1.0.99"
 url = { version = "2.5.2", features = ["serde"] }
 x509-cert = { version = "0.2.5", features = ["builder"] }
 zeroize = "1.8.1"
diff --git a/crates/stackable-versioned-macros/Cargo.toml b/crates/stackable-versioned-macros/Cargo.toml
index eef09494e..e58943ec7 100644
--- a/crates/stackable-versioned-macros/Cargo.toml
+++ b/crates/stackable-versioned-macros/Cargo.toml
@@ -22,3 +22,4 @@ quote.workspace = true
 
 [dev-dependencies]
 rstest.workspace = true
+trybuild.workspace = true
diff --git a/crates/stackable-versioned-macros/tests/bad/README.md b/crates/stackable-versioned-macros/tests/bad/README.md
new file mode 100644
index 000000000..d19327a52
--- /dev/null
+++ b/crates/stackable-versioned-macros/tests/bad/README.md
@@ -0,0 +1,6 @@
+# trybuild bad cases
+
+Code that is expected to fail lives here along with the expected compiler output
+for each case. Please see the docs in [tests/trybuild.rs].
+
+[tests/trybuild.rs]: ../trybuild.rs
diff --git a/crates/stackable-versioned-macros/tests/bad/deprecate.rs b/crates/stackable-versioned-macros/tests/bad/deprecate.rs
new file mode 100644
index 000000000..65ba4c2c6
--- /dev/null
+++ b/crates/stackable-versioned-macros/tests/bad/deprecate.rs
@@ -0,0 +1,14 @@
+use stackable_versioned_macros::versioned;
+
+fn main() {
+    #[versioned(
+        version(name = "v1alpha1"),
+        version(name = "v1beta1"),
+        version(name = "v1")
+    )]
+    struct Foo {
+        #[deprecated]
+        bar: usize,
+        baz: bool,
+    }
+}
diff --git a/crates/stackable-versioned-macros/tests/bad/deprecate.stderr b/crates/stackable-versioned-macros/tests/bad/deprecate.stderr
new file mode 100644
index 000000000..1882ec773
--- /dev/null
+++ b/crates/stackable-versioned-macros/tests/bad/deprecate.stderr
@@ -0,0 +1,5 @@
+error: deprecation must be done using #[versioned(deprecated(since = "VERSION"))]
+  --> tests/bad/deprecate.rs:10:9
+   |
+10 |         #[deprecated]
+   |         ^
diff --git a/crates/stackable-versioned-macros/tests/bad/skip_from_all.rs b/crates/stackable-versioned-macros/tests/bad/skip_from_all.rs
new file mode 100644
index 000000000..b883a501b
--- /dev/null
+++ b/crates/stackable-versioned-macros/tests/bad/skip_from_all.rs
@@ -0,0 +1,24 @@
+use stackable_versioned_macros::versioned;
+
+fn main() {
+    #[versioned(
+        version(name = "v1alpha1"),
+        version(name = "v1beta1"),
+        version(name = "v1"),
+        options(skip(from))
+    )]
+    pub struct Foo {
+        #[versioned(
+            added(since = "v1beta1"),
+            deprecated(since = "v1", note = "not needed")
+        )]
+        deprecated_bar: usize,
+        baz: bool,
+    }
+
+    let foo_v1alpha1 = v1alpha1::Foo { baz: true };
+
+    // There are no From impls for any version. You need to convert it manually.
+    #[allow(dead_code)]
+    let foo_v1beta1 = v1beta1::Foo::from(foo_v1alpha1);
+}
diff --git a/crates/stackable-versioned-macros/tests/bad/skip_from_all.stderr b/crates/stackable-versioned-macros/tests/bad/skip_from_all.stderr
new file mode 100644
index 000000000..7115cbe49
--- /dev/null
+++ b/crates/stackable-versioned-macros/tests/bad/skip_from_all.stderr
@@ -0,0 +1,35 @@
+error[E0308]: mismatched types
+  --> tests/bad/skip_from_all.rs:23:42
+   |
+23 |     let foo_v1beta1 = v1beta1::Foo::from(foo_v1alpha1);
+   |                       ------------------ ^^^^^^^^^^^^ expected `v1beta1::Foo`, found `v1alpha1::Foo`
+   |                       |
+   |                       arguments to this function are incorrect
+   |
+   = note: `v1alpha1::Foo` and `v1beta1::Foo` have similar names, but are actually distinct types
+note: `v1alpha1::Foo` is defined in module `crate::main::v1alpha1` of the current crate
+  --> tests/bad/skip_from_all.rs:4:5
+   |
+4  | /     #[versioned(
+5  | |         version(name = "v1alpha1"),
+6  | |         version(name = "v1beta1"),
+7  | |         version(name = "v1"),
+8  | |         options(skip(from))
+9  | |     )]
+   | |______^
+note: `v1beta1::Foo` is defined in module `crate::main::v1beta1` of the current crate
+  --> tests/bad/skip_from_all.rs:4:5
+   |
+4  | /     #[versioned(
+5  | |         version(name = "v1alpha1"),
+6  | |         version(name = "v1beta1"),
+7  | |         version(name = "v1"),
+8  | |         options(skip(from))
+9  | |     )]
+   | |______^
+note: associated function defined here
+  --> $RUST/core/src/convert/mod.rs
+   |
+   |     fn from(value: T) -> Self;
+   |        ^^^^
+   = note: this error originates in the attribute macro `versioned` (in Nightly builds, run with -Z macro-backtrace for more info)
diff --git a/crates/stackable-versioned-macros/tests/bad/skip_from_version.rs b/crates/stackable-versioned-macros/tests/bad/skip_from_version.rs
new file mode 100644
index 000000000..e08fc2325
--- /dev/null
+++ b/crates/stackable-versioned-macros/tests/bad/skip_from_version.rs
@@ -0,0 +1,24 @@
+use stackable_versioned_macros::versioned;
+
+fn main() {
+    #[versioned(
+        version(name = "v1alpha1"),
+        version(name = "v1beta1", skip(from)),
+        version(name = "v1")
+    )]
+    pub struct Foo {
+        #[versioned(
+            added(since = "v1beta1"),
+            deprecated(since = "v1", note = "not needed")
+        )]
+        deprecated_bar: usize,
+        baz: bool,
+    }
+
+    let foo_v1alpha1 = v1alpha1::Foo { baz: true };
+    let foo_v1beta1 = v1beta1::Foo::from(foo_v1alpha1);
+
+    #[allow(dead_code)]
+    // v1beta1 has no From impl. You need to convert it manually.
+    let foo_v1 = v1::Foo::from(foo_v1beta1);
+}
diff --git a/crates/stackable-versioned-macros/tests/bad/skip_from_version.stderr b/crates/stackable-versioned-macros/tests/bad/skip_from_version.stderr
new file mode 100644
index 000000000..95e828bba
--- /dev/null
+++ b/crates/stackable-versioned-macros/tests/bad/skip_from_version.stderr
@@ -0,0 +1,33 @@
+error[E0308]: mismatched types
+  --> tests/bad/skip_from_version.rs:23:32
+   |
+23 |     let foo_v1 = v1::Foo::from(foo_v1beta1);
+   |                  ------------- ^^^^^^^^^^^ expected `main::v1::Foo`, found `v1beta1::Foo`
+   |                  |
+   |                  arguments to this function are incorrect
+   |
+   = note: `v1beta1::Foo` and `main::v1::Foo` have similar names, but are actually distinct types
+note: `v1beta1::Foo` is defined in module `crate::main::v1beta1` of the current crate
+  --> tests/bad/skip_from_version.rs:4:5
+   |
+4  | /     #[versioned(
+5  | |         version(name = "v1alpha1"),
+6  | |         version(name = "v1beta1", skip(from)),
+7  | |         version(name = "v1")
+8  | |     )]
+   | |______^
+note: `main::v1::Foo` is defined in module `crate::main::v1` of the current crate
+  --> tests/bad/skip_from_version.rs:4:5
+   |
+4  | /     #[versioned(
+5  | |         version(name = "v1alpha1"),
+6  | |         version(name = "v1beta1", skip(from)),
+7  | |         version(name = "v1")
+8  | |     )]
+   | |______^
+note: associated function defined here
+  --> $RUST/core/src/convert/mod.rs
+   |
+   |     fn from(value: T) -> Self;
+   |        ^^^^
+   = note: this error originates in the attribute macro `versioned` (in Nightly builds, run with -Z macro-backtrace for more info)
diff --git a/crates/stackable-versioned-macros/tests/from.rs b/crates/stackable-versioned-macros/tests/from.rs
index e644e00d6..0012743c1 100644
--- a/crates/stackable-versioned-macros/tests/from.rs
+++ b/crates/stackable-versioned-macros/tests/from.rs
@@ -51,38 +51,3 @@ fn from_custom_default_fn() {
     assert_eq!(foo_v1beta1.bar, 42);
     assert!(foo_v1beta1.baz);
 }
-
-#[test]
-fn skip_from_all() {
-    #[versioned(
-        version(name = "v1alpha1"),
-        version(name = "v1beta1"),
-        version(name = "v1"),
-        options(skip(from))
-    )]
-    pub struct Foo {
-        #[versioned(
-            added(since = "v1beta1"),
-            deprecated(since = "v1", note = "not needed")
-        )]
-        deprecated_bar: usize,
-        baz: bool,
-    }
-}
-
-#[test]
-fn skip_from_version() {
-    #[versioned(
-        version(name = "v1alpha1"),
-        version(name = "v1beta1", skip(from)),
-        version(name = "v1")
-    )]
-    pub struct Foo {
-        #[versioned(
-            added(since = "v1beta1"),
-            deprecated(since = "v1", note = "not needed")
-        )]
-        deprecated_bar: usize,
-        baz: bool,
-    }
-}
diff --git a/crates/stackable-versioned-macros/tests/good/README.md b/crates/stackable-versioned-macros/tests/good/README.md
new file mode 100644
index 000000000..e928d0edd
--- /dev/null
+++ b/crates/stackable-versioned-macros/tests/good/README.md
@@ -0,0 +1,6 @@
+# trybuild good cases
+
+Code that is expected to compile lives here. Please see the docs in
+[tests/trybuild.rs].
+
+[tests/trybuild.rs]: ../trybuild.rs
diff --git a/crates/stackable-versioned-macros/tests/good/attributes_enum.rs b/crates/stackable-versioned-macros/tests/good/attributes_enum.rs
new file mode 100644
index 000000000..578f1cc5e
--- /dev/null
+++ b/crates/stackable-versioned-macros/tests/good/attributes_enum.rs
@@ -0,0 +1,43 @@
+use stackable_versioned_macros::versioned;
+
+#[allow(dead_code)]
+fn main() {
+    /// General enum docs that cover all versions.
+    #[versioned(
+        version(name = "v1alpha1"),
+        version(
+            name = "v1beta1",
+            doc = r#"
+                Additional docs for this version which are purposefully long to
+                show how manual line wrapping works. \
+                Multi-line docs are also supported, as per regular doc-comments.
+            "#
+        ),
+        version(name = "v1beta2"),
+        version(name = "v1"),
+        version(name = "v2"),
+        options(skip(from))
+    )]
+    #[derive(Default)]
+    enum Foo {
+        /// This variant is available in every version (so far).
+        #[default]
+        Foo,
+
+        /// Keep the main field docs the same, even after the field is
+        /// deprecated.
+        #[versioned(deprecated(since = "v1beta1", note = "gone"))]
+        DeprecatedBar,
+
+        /// This is for baz
+        #[versioned(added(since = "v1beta1"))]
+        // Just to check stackable-versioned deprecation warning appears.
+        // #[deprecated]
+        Baz,
+
+        /// This is will keep changing over time.
+        #[versioned(renamed(since = "v1beta1", from = "Qoox"))]
+        #[versioned(renamed(since = "v1", from = "Qaax"))]
+        Quux,
+    }
+}
diff --git a/crates/stackable-versioned-macros/tests/attributes.rs b/crates/stackable-versioned-macros/tests/good/attributes_struct.rs
similarity index 56%
rename from crates/stackable-versioned-macros/tests/attributes.rs
rename to crates/stackable-versioned-macros/tests/good/attributes_struct.rs
index 929bf73d3..7747a960f 100644
--- a/crates/stackable-versioned-macros/tests/attributes.rs
+++ b/crates/stackable-versioned-macros/tests/good/attributes_struct.rs
@@ -1,8 +1,6 @@
 use stackable_versioned_macros::versioned;
 
-#[ignore]
-#[test]
-fn pass_struct_attributes() {
+fn main() {
     /// General struct docs that cover all versions.
     #[versioned(
         version(name = "v1alpha1"),
@@ -60,47 +58,3 @@ fn pass_struct_attributes() {
         quux: String::from("World"),
     };
 }
-
-#[ignore]
-#[allow(dead_code)]
-#[test]
-fn pass_enum_attributes() {
-    /// General enum docs that cover all versions.
-    #[versioned(
-        version(name = "v1alpha1"),
-        version(
-            name = "v1beta1",
-            doc = r#"
-                Additional docs for this version which are purposefully long to
-                show how manual line wrapping works. \
-                Multi-line docs are also supported, as per regular doc-comments.
-            "#
-        ),
-        version(name = "v1beta2"),
-        version(name = "v1"),
-        version(name = "v2"),
-        options(skip(from))
-    )]
-    #[derive(Default)]
-    enum Foo {
-        /// This variant is available in every version (so far).
-        #[default]
-        Foo,
-
-        /// Keep the main field docs the same, even after the field is
-        /// deprecated.
-        #[versioned(deprecated(since = "v1beta1", note = "gone"))]
-        DeprecatedBar,
-
-        /// This is for baz
-        #[versioned(added(since = "v1beta1"))]
-        // Just to check stackable-versioned deprecation warning appears.
-        // #[deprecated]
-        Baz,
-
-        /// This is will keep changing over time.
-        #[versioned(renamed(since = "v1beta1", from = "Qoox"))]
-        #[versioned(renamed(since = "v1", from = "Qaax"))]
-        Quux,
-    }
-}
diff --git a/crates/stackable-versioned-macros/tests/basic.rs b/crates/stackable-versioned-macros/tests/good/basic.rs
similarity index 98%
rename from crates/stackable-versioned-macros/tests/basic.rs
rename to crates/stackable-versioned-macros/tests/good/basic.rs
index ce46833c6..7ba40df21 100644
--- a/crates/stackable-versioned-macros/tests/basic.rs
+++ b/crates/stackable-versioned-macros/tests/good/basic.rs
@@ -22,8 +22,7 @@ struct Foo {
     baz: bool,
 }
 
-#[test]
-fn basic() {
+fn main() {
     #[allow(deprecated)]
     let _ = v1alpha1::Foo { jjj: 0, baz: false };
     let _ = v1beta1::Foo { bar: 0, baz: false };
diff --git a/crates/stackable-versioned-macros/tests/deprecate.rs b/crates/stackable-versioned-macros/tests/good/deprecate.rs
similarity index 92%
rename from crates/stackable-versioned-macros/tests/deprecate.rs
rename to crates/stackable-versioned-macros/tests/good/deprecate.rs
index 87ebc669b..d525ee6b1 100644
--- a/crates/stackable-versioned-macros/tests/deprecate.rs
+++ b/crates/stackable-versioned-macros/tests/good/deprecate.rs
@@ -1,7 +1,6 @@
 use stackable_versioned_macros::versioned;
 
-#[test]
-fn deprecate() {
+fn main() {
     #[versioned(
         version(name = "v1alpha1"),
         version(name = "v1beta1"),
diff --git a/crates/stackable-versioned-macros/tests/rename.rs b/crates/stackable-versioned-macros/tests/good/rename.rs
similarity index 93%
rename from crates/stackable-versioned-macros/tests/rename.rs
rename to crates/stackable-versioned-macros/tests/good/rename.rs
index 052fe1144..0728f4804 100644
--- a/crates/stackable-versioned-macros/tests/rename.rs
+++ b/crates/stackable-versioned-macros/tests/good/rename.rs
@@ -1,7 +1,6 @@
 use stackable_versioned_macros::versioned;
 
-#[test]
-fn rename() {
+fn main() {
     #[versioned(
         version(name = "v1alpha1"),
         version(name = "v1beta1"),
diff --git a/crates/stackable-versioned-macros/tests/good/skip_from_version.rs b/crates/stackable-versioned-macros/tests/good/skip_from_version.rs
new file mode 100644
index 000000000..3308dc23b
--- /dev/null
+++ b/crates/stackable-versioned-macros/tests/good/skip_from_version.rs
@@ -0,0 +1,28 @@
+use stackable_versioned_macros::versioned;
+
+#[allow(unused_variables)]
+fn main() {
+    #[versioned(
+        version(name = "v1alpha1"),
+        version(name = "v1beta1", skip(from)),
+        version(name = "v1")
+    )]
+    pub struct Foo {
+        #[versioned(
+            added(since = "v1beta1"),
+            deprecated(since = "v1", note = "not needed")
+        )]
+        deprecated_bar: usize,
+        baz: bool,
+    }
+
+    let foo_v1alpha1 = v1alpha1::Foo { baz: true };
+    let foo_v1beta1 = v1beta1::Foo::from(foo_v1alpha1);
+
+    #[allow(deprecated)]
+    // v1beta1 has no From impl, so we convert it manually
+    let foo_v1 = v1::Foo {
+        deprecated_bar: 0,
+        baz: true,
+    };
+}
diff --git a/crates/stackable-versioned-macros/tests/trybuild.rs b/crates/stackable-versioned-macros/tests/trybuild.rs
new file mode 100644
index 000000000..94ba753bc
--- /dev/null
+++ b/crates/stackable-versioned-macros/tests/trybuild.rs
@@ -0,0 +1,40 @@
+//! Add code examples that you expect to compile to tests/good.
+//! Add code examples that you expect to fail compilation to tests/bad.
+//! Optionally enable/disable the modules below to make local editing easier.
+//!
+//! Please read the [trybuild workflow][1] docs to understand how to deal with
+//! failing test output.
+//!
+//! [1]: https://github.com/dtolnay/trybuild?tab=readme-ov-file#workflow
+
+// Enable the module below to get syntax highlighting and code completion.
+// Adjust the list of modules to enable syntax highlighting and code completion.
+// Unfortunately tests in subfolders aren't automatically included.
+//
+// #[allow(dead_code)]
+// mod good {
+//     mod attributes_enum;
+//     mod attributes_struct;
+//     mod basic;
+//     mod deprecate;
+//     mod rename;
+//     mod skip_from_version;
+// }
+
+// Similar to the above module, enable the module below to get syntax
+// highlighting and code completion. You will need to comment them out again but
+// before running tests, orherwise compilation will fail (as expected).
+//
+// #[allow(dead_code)]
+// mod bad {
+//     mod deprecate;
+//     mod skip_from_all;
+//     mod skip_from_version;
+// }
+
+#[test]
+fn macros() {
+    let t = trybuild::TestCases::new();
+    t.pass("tests/good/*.rs");
+    t.compile_fail("tests/bad/*.rs");
+}

From f9c6081fb9d07ed58b14351ef79f7c32ba4309a8 Mon Sep 17 00:00:00 2001
From: Nick Larsen <nick.larsen@stackable.tech>
Date: Fri, 23 Aug 2024 11:40:45 +0200
Subject: [PATCH 3/3] ci(build): add rust-src component for testing

---
 .github/workflows/build.yml | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index 5685ccb26..12e3562be 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -135,6 +135,10 @@ jobs:
       - uses: dtolnay/rust-toolchain@master
         with:
           toolchain: ${{ env.RUST_TOOLCHAIN_VERSION }}
+          # rust-src is required for trybuild stderr output comparison to work
+          # for our cases.
+          # See: https://github.com/dtolnay/trybuild/issues/236#issuecomment-1620950759
+          components: rust-src
       - uses: Swatinem/rust-cache@23bce251a8cd2ffc3c1075eaa2367cf899916d84 # v2.7.3
         with:
           key: test