diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 247d0c9..e46e943 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -8,12 +8,12 @@ jobs: strategy: matrix: rust: - - 1.70.0 + - 1.65.0 - stable - beta - nightly include: - - rust: 1.70.0 + - rust: 1.65.0 allow_failure: false - rust: stable allow_failure: false @@ -23,10 +23,12 @@ jobs: allow_failure: true fail-fast: false steps: - - uses: actions/checkout@v4 - - uses: dtolnay/rust-toolchain@master + - uses: actions/checkout@v1 + - uses: actions-rs/toolchain@v1 with: + profile: minimal toolchain: ${{ matrix.rust }} + override: true - name: Check with no feature flags run: cargo check --verbose --no-default-features continue-on-error: ${{ matrix.allow_failure }} diff --git a/CHANGELOG.md b/CHANGELOG.md index 9f6ce93..e21e380 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,27 +1,5 @@ # Changelog -## [1.0.0-alpha.17] - 2024-12-02 - -### Changed - -- For newtype variants of internally-tagged enums, prefer referencing the inner type's schema via `$ref` instead of always inlining the schema (https://github.com/GREsau/schemars/pull/355) _(this change was included in the release notes for 1.0.0-alpha.16, but was accidentally excluded from the published crate)_ - -## [1.0.0-alpha.16] - 2024-11-25 - -### Removed (_⚠️ breaking changes ⚠️_) - -- the `enumset1`/`enumset` optional dependency has been removed, as its `JsonSchema` impl did not actually match the default serialization format of `EnumSet` (https://github.com/GREsau/schemars/pull/339) - -### Changed (_⚠️ breaking changes ⚠️_) - -- MSRV is now 1.70 -- [The `example` attribute](https://graham.cool/schemars/deriving/attributes/#example) value is now an arbitrary expression, rather than a string literal identifying a function to call. To avoid silent behaviour changes, the expression must not be a string literal where the value can be parsed as a function path - e.g. `#[schemars(example = "foo")]` is now a compile error, but `#[schemars(example = foo())]` is allowed (as is `#[schemars(example = &"foo")]` if you want the the literal string value `"foo"` to be the example). - -### Fixed - -- The "deserialize" schema for `bytes::Bytes`/`BytesMut` now allows strings, matching the actual deserialize behaviour of the types. -- The schema for `either::Either` now matches the actual serialize/deserialize behaviour of that type. - ## [1.0.0-alpha.15] - 2024-09-05 ### Added diff --git a/Cargo.lock b/Cargo.lock index 0f30998..665db12 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,210 +2,60 @@ # It is not intended for manual editing. version = 3 -[[package]] -name = "ahash" -version = "0.8.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011" -dependencies = [ - "cfg-if", - "getrandom", - "once_cell", - "serde", - "version_check", - "zerocopy", -] - -[[package]] -name = "aho-corasick" -version = "1.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" -dependencies = [ - "memchr", -] - -[[package]] -name = "anstream" -version = "0.6.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64e15c1ab1f89faffbf04a634d5e1962e9074f2741eef6d97f3c4e322426d526" -dependencies = [ - "anstyle", - "anstyle-parse", - "anstyle-query", - "anstyle-wincon", - "colorchoice", - "is_terminal_polyfill", - "utf8parse", -] - -[[package]] -name = "anstyle" -version = "1.0.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bec1de6f59aedf83baf9ff929c98f2ad654b97c9510f4e70cf6f661d49fd5b1" - -[[package]] -name = "anstyle-parse" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb47de1e80c2b463c735db5b217a0ddc39d612e7ac9e2e96a5aed1f57616c1cb" -dependencies = [ - "utf8parse", -] - -[[package]] -name = "anstyle-query" -version = "1.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d36fc52c7f6c869915e99412912f22093507da8d9e942ceaf66fe4b7c14422a" -dependencies = [ - "windows-sys 0.52.0", -] - -[[package]] -name = "anstyle-wincon" -version = "3.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5bf74e1b6e971609db8ca7a9ce79fd5768ab6ae46441c572e46cf596f59e57f8" -dependencies = [ - "anstyle", - "windows-sys 0.52.0", -] - -[[package]] -name = "anyhow" -version = "1.0.87" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "10f00e1f6e58a40e807377c75c6a7f97bf9044fab57816f2414e6f5f4499d7b8" - [[package]] name = "arrayvec" -version = "0.7.6" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" -dependencies = [ - "serde", -] +checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711" [[package]] name = "autocfg" -version = "1.3.0" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" +checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" [[package]] -name = "base64" -version = "0.22.1" +name = "basic-toml" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" +checksum = "7bfc506e7a2370ec239e1d072507b2a80c833083699d3c6fa176fbb4de8448c6" +dependencies = [ + "serde", +] [[package]] name = "bigdecimal" -version = "0.4.5" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51d712318a27c7150326677b321a5fa91b55f6d9034ffd67f20319e147d40cee" +checksum = "c06619be423ea5bb86c95f087d5707942791a08a85530df0db2209a3ecfb8bc9" dependencies = [ "autocfg", "libm", "num-bigint", "num-integer", "num-traits", - "serde", ] -[[package]] -name = "bit-set" -version = "0.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0700ddab506f33b20a03b13996eccd309a48e5ff77d0d95926aa0210fb4e95f1" -dependencies = [ - "bit-vec", -] - -[[package]] -name = "bit-vec" -version = "0.6.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb" - -[[package]] -name = "bitflags" -version = "2.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" - -[[package]] -name = "bumpalo" -version = "3.16.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" - -[[package]] -name = "bytecount" -version = "0.6.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ce89b21cab1437276d2650d57e971f9d548a2d9037cc231abdc0562b97498ce" - [[package]] name = "bytes" -version = "1.7.1" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8318a53db07bb3f8dca91a600466bdb3f2eaadeedfdbcf02e1accbad9271ba50" -dependencies = [ - "serde", -] - -[[package]] -name = "castaway" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0abae9be0aaf9ea96a3b1b8b1b55c602ca751eba1b1500220cea4ecbafe7c0d5" -dependencies = [ - "rustversion", -] - -[[package]] -name = "cfg-if" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +checksum = "a2bd12c1caf447e69cd4528f47f94d203fd2582878ecb9e9465484c4148a8223" [[package]] name = "chrono" -version = "0.4.38" +version = "0.4.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a21f936df1771bf62b77f047b726c4625ff2e8aa607c01ec06e5a05bd8463401" +checksum = "7f2c685bad3eb3d45a01354cedb7d5faa66194d1d58ba6e267a8de788f79db38" dependencies = [ "num-traits", - "serde", -] - -[[package]] -name = "colorchoice" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3fd119d74b830634cea2a0f58bbd0d54540518a14397557951e79340abc28c0" - -[[package]] -name = "compact_str" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f86b9c4c00838774a6d902ef931eff7470720c51d90c2e32cfe15dc304737b3f" -dependencies = [ - "castaway", - "cfg-if", - "itoa", - "ryu", - "static_assertions", ] [[package]] name = "darling" -version = "0.20.10" +version = "0.20.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f63b86c8a8826a49b8c21f08a2d07338eec8d900540f8630dc76284be802989" +checksum = "0209d94da627ab5605dcccf08bb18afa5009cfbef48d8a8b7d7bdbc79be25c5e" dependencies = [ "darling_core", "darling_macro", @@ -213,36 +63,26 @@ dependencies = [ [[package]] name = "darling_core" -version = "0.20.10" +version = "0.20.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95133861a8032aaea082871032f5815eb9e98cef03fa916ab4500513994df9e5" +checksum = "177e3443818124b357d8e76f53be906d60937f0d3a90773a664fa63fa253e621" dependencies = [ "fnv", "ident_case", "proc-macro2", "quote", - "strsim", - "syn 2.0.77", + "syn", ] [[package]] name = "darling_macro" -version = "0.20.10" +version = "0.20.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d336a2a514f6ccccaa3e09b02d41d35330c07ddf03a62165fcec10bb561c7806" +checksum = "836a9bbc7ad63342d6d6e7b815ccab164bc77a2d95d84bc3117a8c0d5c98e2d5" dependencies = [ "darling_core", "quote", - "syn 2.0.77", -] - -[[package]] -name = "deranged" -version = "0.3.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4" -dependencies = [ - "powerfmt", + "syn", ] [[package]] @@ -253,17 +93,35 @@ checksum = "56254986775e3233ffa9c4d7d3faaf6d36a2c09d30b20687e9f88bc8bafc16c8" [[package]] name = "dyn-clone" -version = "1.0.17" +version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d6ef0072f8a535281e4876be788938b528e9a1d43900b82c2569af7da799125" +checksum = "23d2f3407d9a573d666de4b5bdf10569d73ca9478087346697dcbae6244bfbcd" [[package]] name = "either" -version = "1.13.0" +version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" +checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07" + +[[package]] +name = "enumset" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "226c0da7462c13fb57e5cc9e0dc8f0635e7d27f276a3a7fd30054647f669007d" dependencies = [ - "serde", + "enumset_derive", +] + +[[package]] +name = "enumset_derive" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e08b6c6ab82d70f08844964ba10c7babb716de2ecaeab9be5717918a5177d3af" +dependencies = [ + "darling", + "proc-macro2", + "quote", + "syn", ] [[package]] @@ -272,17 +130,6 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" -[[package]] -name = "fancy-regex" -version = "0.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "531e46835a22af56d1e3b66f04844bed63158bc094a628bec1d321d9b4c44bf2" -dependencies = [ - "bit-set", - "regex-automata", - "regex-syntax", -] - [[package]] name = "fnv" version = "1.0.7" @@ -291,60 +138,13 @@ checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" [[package]] name = "form_urlencoded" -version = "1.2.1" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" +checksum = "a62bc1cf6f830c2ec14a513a9fb124d0a213a629668a4186f329db21fe045652" dependencies = [ "percent-encoding", ] -[[package]] -name = "fraction" -version = "0.15.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f158e3ff0a1b334408dc9fb811cd99b446986f4d8b741bb08f9df1604085ae7" -dependencies = [ - "lazy_static", - "num", -] - -[[package]] -name = "garde" -version = "0.20.0" -source = "git+https://github.com/jprochazk/garde.git?rev=be00ddddf8de14530ee890ccfdbaf0b13fb32852#be00ddddf8de14530ee890ccfdbaf0b13fb32852" -dependencies = [ - "compact_str", - "garde_derive", - "once_cell", - "regex", - "smallvec", - "url", -] - -[[package]] -name = "garde_derive" -version = "0.20.0" -source = "git+https://github.com/jprochazk/garde.git?rev=be00ddddf8de14530ee890ccfdbaf0b13fb32852#be00ddddf8de14530ee890ccfdbaf0b13fb32852" -dependencies = [ - "proc-macro2", - "quote", - "regex", - "syn 2.0.77", -] - -[[package]] -name = "getrandom" -version = "0.2.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" -dependencies = [ - "cfg-if", - "js-sys", - "libc", - "wasi", - "wasm-bindgen", -] - [[package]] name = "glob" version = "0.3.1" @@ -353,9 +153,9 @@ checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" [[package]] name = "hashbrown" -version = "0.14.5" +version = "0.14.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" +checksum = "f93e7192158dbcda357bdec5fb5788eebf8bbac027f3f33e719d29135ae84156" [[package]] name = "ident_case" @@ -365,9 +165,9 @@ checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" [[package]] name = "idna" -version = "0.5.0" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6" +checksum = "7d20d6b07bfbc108882d88ed8e37d39636dcc260e15e30c45e6ba089610b917c" dependencies = [ "unicode-bidi", "unicode-normalization", @@ -375,84 +175,19 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.5.0" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68b900aa2f7301e21c36462b170ee99994de34dff39a4a6a528e80e7376d07e5" +checksum = "93ead53efc7ea8ed3cfb0c79fc8023fbb782a5432b52830b6518941cebe6505c" dependencies = [ "equivalent", "hashbrown", - "serde", -] - -[[package]] -name = "is_terminal_polyfill" -version = "1.70.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" - -[[package]] -name = "iso8601" -version = "0.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "924e5d73ea28f59011fec52a0d12185d496a9b075d360657aed2a5707f701153" -dependencies = [ - "nom", ] [[package]] name = "itoa" -version = "1.0.11" +version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" - -[[package]] -name = "js-sys" -version = "0.3.70" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1868808506b929d7b0cfa8f75951347aa71bb21144b7791bae35d9bccfcfe37a" -dependencies = [ - "wasm-bindgen", -] - -[[package]] -name = "jsonschema" -version = "0.20.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2eef4e82b548e08ac880d307c8e8838b45f497a08d3202f3b26c9debaed8058" -dependencies = [ - "ahash", - "anyhow", - "base64", - "bytecount", - "fancy-regex", - "fraction", - "getrandom", - "iso8601", - "itoa", - "memchr", - "num-cmp", - "once_cell", - "parking_lot", - "percent-encoding", - "regex", - "serde", - "serde_json", - "time", - "url", - "uuid-simd", -] - -[[package]] -name = "lazy_static" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" - -[[package]] -name = "libc" -version = "0.2.158" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8adc4bb1803a324070e64a98ae98f38934d91957a99cfb3a43dcbc01bc56439" +checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38" [[package]] name = "libm" @@ -460,109 +195,17 @@ version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058" -[[package]] -name = "lock_api" -version = "0.4.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" -dependencies = [ - "autocfg", - "scopeguard", -] - -[[package]] -name = "log" -version = "0.4.22" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" - [[package]] name = "memchr" -version = "2.7.4" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" - -[[package]] -name = "minimal-lexical" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" - -[[package]] -name = "nom" -version = "7.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" -dependencies = [ - "memchr", - "minimal-lexical", -] - -[[package]] -name = "normalize-line-endings" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61807f77802ff30975e01f4f071c8ba10c022052f98b3294119f3e615d13e5be" - -[[package]] -name = "num" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "35bd024e8b2ff75562e5f34e7f4905839deb4b22955ef5e73d2fea1b9813cb23" -dependencies = [ - "num-bigint", - "num-complex", - "num-integer", - "num-iter", - "num-rational", - "num-traits", -] +checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" [[package]] name = "num-bigint" -version = "0.4.6" +version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9" -dependencies = [ - "num-integer", - "num-traits", -] - -[[package]] -name = "num-cmp" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "63335b2e2c34fae2fb0aa2cecfd9f0832a1e24b3b32ecec612c3426d46dc8aaa" - -[[package]] -name = "num-complex" -version = "0.4.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73f88a1307638156682bada9d7604135552957b7818057dcef22705b4d509495" -dependencies = [ - "num-traits", -] - -[[package]] -name = "num-conv" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" - -[[package]] -name = "num-integer" -version = "0.1.46" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" -dependencies = [ - "num-traits", -] - -[[package]] -name = "num-iter" -version = "0.1.45" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1429034a0490724d0075ebb2bc9e875d6503c3cf69e235a8941aa757d83ef5bf" +checksum = "608e7659b5c3d7cba262d894801b9ec9d00de989e8a82bd4bef91d08da45cdc0" dependencies = [ "autocfg", "num-integer", @@ -570,71 +213,35 @@ dependencies = [ ] [[package]] -name = "num-rational" -version = "0.4.2" +name = "num-integer" +version = "0.1.45" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f83d14da390562dca69fc84082e73e548e1ad308d24accdedd2720017cb37824" +checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9" dependencies = [ - "num-bigint", - "num-integer", + "autocfg", "num-traits", ] [[package]] name = "num-traits" -version = "0.2.19" +version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +checksum = "39e3200413f237f41ab11ad6d161bc7239c84dcb631773ccd7de3dfe4b5c267c" dependencies = [ "autocfg", ] [[package]] name = "once_cell" -version = "1.19.0" +version = "1.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" - -[[package]] -name = "outref" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4030760ffd992bef45b0ae3f10ce1aba99e33464c90d14dd7c039884963ddc7a" - -[[package]] -name = "parking_lot" -version = "0.12.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27" -dependencies = [ - "lock_api", - "parking_lot_core", -] - -[[package]] -name = "parking_lot_core" -version = "0.9.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" -dependencies = [ - "cfg-if", - "libc", - "redox_syscall", - "smallvec", - "windows-targets", -] +checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" [[package]] name = "percent-encoding" -version = "2.3.1" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" - -[[package]] -name = "powerfmt" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" +checksum = "9b2a4787296e9989611394c33f193f676704af1686e70b8f8033ab5ba9a35a94" [[package]] name = "pretty_assertions" @@ -646,132 +253,63 @@ dependencies = [ "yansi", ] -[[package]] -name = "proc-macro-error" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" -dependencies = [ - "proc-macro-error-attr", - "proc-macro2", - "quote", - "syn 1.0.109", - "version_check", -] - -[[package]] -name = "proc-macro-error-attr" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" -dependencies = [ - "proc-macro2", - "quote", - "version_check", -] - [[package]] name = "proc-macro2" -version = "1.0.86" +version = "1.0.81" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77" +checksum = "3d1597b0c024618f09a9c3b8655b7e430397a36d23fdafec26d6965e9eec3eba" dependencies = [ "unicode-ident", ] [[package]] name = "quote" -version = "1.0.37" +version = "1.0.36" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" +checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" dependencies = [ "proc-macro2", ] -[[package]] -name = "redox_syscall" -version = "0.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a908a6e00f1fdd0dfd9c0eb08ce85126f6d8bbda50017e74bc4a4b7d4a926a4" -dependencies = [ - "bitflags", -] - [[package]] name = "ref-cast" -version = "1.0.23" +version = "1.0.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ccf0a6f84d5f1d581da8b41b47ec8600871962f2a528115b542b362d4b744931" +checksum = "c4846d4c50d1721b1a3bef8af76924eef20d5e723647333798c1b519b3a9473f" dependencies = [ "ref-cast-impl", ] [[package]] name = "ref-cast-impl" -version = "1.0.23" +version = "1.0.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bcc303e793d3734489387d205e9b186fac9c6cfacedd98cbb2e8a5943595f3e6" +checksum = "5fddb4f8d99b0a2ebafc65a87a69a7b9875e4b1ae1f00db265d300ef7f28bccc" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn", ] -[[package]] -name = "regex" -version = "1.10.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4219d74c6b67a3654a9fbebc4b419e22126d13d2f3c4a07ee0cb61ff79a79619" -dependencies = [ - "aho-corasick", - "memchr", - "regex-automata", - "regex-syntax", -] - -[[package]] -name = "regex-automata" -version = "0.4.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38caf58cc5ef2fed281f89292ef23f6365465ed9a41b7a7754eb4e26496c92df" -dependencies = [ - "aho-corasick", - "memchr", - "regex-syntax", -] - -[[package]] -name = "regex-syntax" -version = "0.8.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b" - [[package]] name = "rust_decimal" -version = "1.36.0" +version = "1.32.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b082d80e3e3cc52b2ed634388d436fe1f4de6af5786cc2de9ba9737527bdf555" +checksum = "a4c4216490d5a413bc6d10fa4742bd7d4955941d062c0ef873141d6b0e7b30fd" dependencies = [ "arrayvec", "num-traits", - "serde", ] -[[package]] -name = "rustversion" -version = "1.0.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "955d28af4278de8121b7ebeb796b6a45735dc01436d898801014aced2773a3d6" - [[package]] name = "ryu" -version = "1.0.18" +version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" +checksum = "1ad4cc8da4ef723ed60bced201181d83791ad433213d8c24efffda1eec85d741" [[package]] name = "schemars" -version = "1.0.0-alpha.17" +version = "1.0.0-alpha.15" dependencies = [ "arrayvec", "bigdecimal", @@ -779,89 +317,75 @@ dependencies = [ "chrono", "dyn-clone", "either", - "garde", + "enumset", "indexmap", - "jsonschema", "pretty_assertions", "ref-cast", - "regex", "rust_decimal", "schemars_derive", "semver", "serde", "serde_json", - "serde_repr", "smallvec", "smol_str", - "snapbox", "trybuild", "url", "uuid", - "validator", ] [[package]] name = "schemars_derive" -version = "1.0.0-alpha.17" +version = "1.0.0-alpha.15" dependencies = [ "pretty_assertions", "proc-macro2", "quote", "serde_derive_internals", - "syn 2.0.77", + "syn", ] -[[package]] -name = "scopeguard" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" - [[package]] name = "semver" -version = "1.0.23" +version = "1.0.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b" -dependencies = [ - "serde", -] +checksum = "836fa6a3e1e547f9a2c4040802ec865b5d85f4014efe00555d7090a3dcaa1090" [[package]] name = "serde" -version = "1.0.210" +version = "1.0.208" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8e3592472072e6e22e0a54d5904d9febf8508f65fb8552499a1abc7d1078c3a" +checksum = "cff085d2cb684faa248efb494c39b68e522822ac0de72ccf08109abde717cfb2" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.210" +version = "1.0.208" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "243902eda00fad750862fc144cea25caca5e20d615af0a81bee94ca738f1df1f" +checksum = "24008e81ff7613ed8e5ba0cfaf24e2c2f1e5b8a0495711e44fcd4882fca62bcf" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn", ] [[package]] name = "serde_derive_internals" -version = "0.29.1" +version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "18d26a20a969b9e3fdf2fc2d9f21eda6c40e2de84c9408bb5d3b05d499aae711" +checksum = "330f01ce65a3a5fe59a60c82f3c9a024b573b8a6e875bd233fe5f934e71d54e3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn", ] [[package]] name = "serde_json" -version = "1.0.128" +version = "1.0.127" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ff5456707a1de34e7e37f2a6fd3d3f808c318259cbd01ab6377795054b483d8" +checksum = "8043c06d9f82bd7271361ed64f415fe5e12a77fdb52e573e7f06a516dea329ad" dependencies = [ "indexmap", "itoa", @@ -870,101 +394,23 @@ dependencies = [ "serde", ] -[[package]] -name = "serde_repr" -version = "0.1.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c64451ba24fc7a6a2d60fc75dd9c83c90903b19028d4eff35e88fc1e86564e9" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.77", -] - -[[package]] -name = "serde_spanned" -version = "0.6.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb5b1b31579f3811bf615c144393417496f152e12ac8b7663bf664f4a815306d" -dependencies = [ - "serde", -] - -[[package]] -name = "similar" -version = "2.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1de1d4f81173b03af4c0cbed3c898f6bff5b870e4a7f5d6f4057d62a7a4b686e" - [[package]] name = "smallvec" -version = "1.13.2" +version = "1.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" -dependencies = [ - "serde", -] +checksum = "942b4a808e05215192e39f4ab80813e599068285906cc91aa64f923db842bd5a" [[package]] name = "smol_str" -version = "0.2.2" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd538fb6910ac1099850255cf94a94df6551fbdd602454387d0adb2d1ca6dead" -dependencies = [ - "serde", -] - -[[package]] -name = "snapbox" -version = "0.6.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "840b73eb3148bc3cbc10ebe00ec9bc6d96033e658d022c4adcbf3f35596fd64a" -dependencies = [ - "anstream", - "anstyle", - "normalize-line-endings", - "serde", - "serde_json", - "similar", - "snapbox-macros", -] - -[[package]] -name = "snapbox-macros" -version = "0.3.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16569f53ca23a41bb6f62e0a5084aa1661f4814a67fa33696a79073e03a664af" -dependencies = [ - "anstream", -] - -[[package]] -name = "static_assertions" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" - -[[package]] -name = "strsim" -version = "0.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" +checksum = "e6845563ada680337a52d43bb0b29f396f2d911616f6573012645b9e3d048a49" [[package]] name = "syn" -version = "1.0.109" +version = "2.0.60" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" -dependencies = [ - "proc-macro2", - "unicode-ident", -] - -[[package]] -name = "syn" -version = "2.0.77" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f35bcdf61fd8e7be6caf75f429fdca8beb3ed76584befb503b1569faee373ed" +checksum = "909518bc7b1c9b779f1bbf07f2929d35af9f0f37e47c6e9ef7f9dddc1e1821f3" dependencies = [ "proc-macro2", "quote", @@ -973,48 +419,18 @@ dependencies = [ [[package]] name = "termcolor" -version = "1.4.1" +version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755" +checksum = "6093bad37da69aab9d123a8091e4be0aa4a03e4d601ec641c327398315f62b64" dependencies = [ "winapi-util", ] -[[package]] -name = "time" -version = "0.3.36" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5dfd88e563464686c916c7e46e623e520ddc6d79fa6641390f2e3fa86e83e885" -dependencies = [ - "deranged", - "num-conv", - "powerfmt", - "serde", - "time-core", - "time-macros", -] - -[[package]] -name = "time-core" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" - -[[package]] -name = "time-macros" -version = "0.2.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f252a68540fde3a3877aeea552b832b40ab9a69e318efd078774a01ddee1ccf" -dependencies = [ - "num-conv", - "time-core", -] - [[package]] name = "tinyvec" -version = "1.8.0" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "445e881f4f6d382d5f27c034e25eb92edd7c784ceab92a0937db7f2e9471b938" +checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" dependencies = [ "tinyvec_macros", ] @@ -1025,59 +441,26 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" -[[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", -] - -[[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" -version = "0.22.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "583c44c02ad26b0c3f3066fe629275e50627026c51ac2e595cca4c230ce1ce1d" -dependencies = [ - "indexmap", - "serde", - "serde_spanned", - "toml_datetime", - "winnow", -] - [[package]] name = "trybuild" -version = "1.0.99" +version = "1.0.85" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "207aa50d36c4be8d8c6ea829478be44a372c6a77669937bb39c698e52f1491e8" +checksum = "196a58260a906cedb9bf6d8034b6379d0c11f552416960452f267402ceeddff1" dependencies = [ + "basic-toml", "glob", + "once_cell", "serde", "serde_derive", "serde_json", "termcolor", - "toml", ] [[package]] name = "unicode-bidi" -version = "0.3.15" +version = "0.3.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08f95100a766bf4f8f28f90d77e0a5461bbdb219042e7679bebe79004fed8d75" +checksum = "92888ba5573ff080736b3648696b70cafad7d250551175acbaa4e0385b3e1460" [[package]] name = "unicode-ident" @@ -1087,276 +470,63 @@ checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" [[package]] name = "unicode-normalization" -version = "0.1.23" +version = "0.1.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a56d1686db2308d901306f92a263857ef59ea39678a5458e7cb17f01415101f5" +checksum = "5c5713f0fc4b5db668a2ac63cdb7bb4469d8c9fed047b1d0292cc7b0ce2ba921" dependencies = [ "tinyvec", ] [[package]] name = "url" -version = "2.5.2" +version = "2.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22784dbdf76fdde8af1aeda5622b546b422b6fc585325248a2bf9f5e41e94d6c" +checksum = "143b538f18257fac9cad154828a57c6bf5157e1aa604d4816b5995bf6de87ae5" dependencies = [ "form_urlencoded", "idna", "percent-encoding", - "serde", ] -[[package]] -name = "utf8parse" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" - [[package]] name = "uuid" -version = "1.10.0" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81dfa00651efa65069b0b6b651f4aaa31ba9e3c3ce0137aaad053604ee7e0314" +checksum = "88ad59a7560b41a70d191093a945f0b87bc1deeda46fb237479708a1d6b6cdfc" + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" dependencies = [ - "serde", + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", ] [[package]] -name = "uuid-simd" -version = "0.8.0" +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23b082222b4f6619906941c17eb2297fff4c2fb96cb60164170522942a200bd8" -dependencies = [ - "outref", - "uuid", - "vsimd", -] - -[[package]] -name = "validator" -version = "0.18.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db79c75af171630a3148bd3e6d7c4f42b6a9a014c2945bc5ed0020cbb8d9478e" -dependencies = [ - "idna", - "once_cell", - "regex", - "serde", - "serde_derive", - "serde_json", - "url", - "validator_derive", -] - -[[package]] -name = "validator_derive" -version = "0.18.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df0bcf92720c40105ac4b2dda2a4ea3aa717d4d6a862cc217da653a4bd5c6b10" -dependencies = [ - "darling", - "once_cell", - "proc-macro-error", - "proc-macro2", - "quote", - "syn 2.0.77", -] - -[[package]] -name = "version_check" -version = "0.9.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" - -[[package]] -name = "vsimd" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c3082ca00d5a5ef149bb8b555a72ae84c9c59f7250f013ac822ac2e49b19c64" - -[[package]] -name = "wasi" -version = "0.11.0+wasi-snapshot-preview1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" - -[[package]] -name = "wasm-bindgen" -version = "0.2.93" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a82edfc16a6c469f5f44dc7b571814045d60404b55a0ee849f9bcfa2e63dd9b5" -dependencies = [ - "cfg-if", - "once_cell", - "wasm-bindgen-macro", -] - -[[package]] -name = "wasm-bindgen-backend" -version = "0.2.93" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9de396da306523044d3302746f1208fa71d7532227f15e347e2d93e4145dd77b" -dependencies = [ - "bumpalo", - "log", - "once_cell", - "proc-macro2", - "quote", - "syn 2.0.77", - "wasm-bindgen-shared", -] - -[[package]] -name = "wasm-bindgen-macro" -version = "0.2.93" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "585c4c91a46b072c92e908d99cb1dcdf95c5218eeb6f3bf1efa991ee7a68cccf" -dependencies = [ - "quote", - "wasm-bindgen-macro-support", -] - -[[package]] -name = "wasm-bindgen-macro-support" -version = "0.2.93" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "afc340c74d9005395cf9dd098506f7f44e38f2b4a21c6aaacf9a105ea5e1e836" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.77", - "wasm-bindgen-backend", - "wasm-bindgen-shared", -] - -[[package]] -name = "wasm-bindgen-shared" -version = "0.2.93" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c62a0a307cb4a311d3a07867860911ca130c3494e8c2719593806c08bc5d0484" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" [[package]] name = "winapi-util" -version = "0.1.9" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb" +checksum = "f29e6f9198ba0d26b4c9f07dbe6f9ed633e1f3d5b8b414090084349e46a52596" dependencies = [ - "windows-sys 0.59.0", + "winapi", ] [[package]] -name = "windows-sys" -version = "0.52.0" +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" -dependencies = [ - "windows-targets", -] - -[[package]] -name = "windows-sys" -version = "0.59.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" -dependencies = [ - "windows-targets", -] - -[[package]] -name = "windows-targets" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" -dependencies = [ - "windows_aarch64_gnullvm", - "windows_aarch64_msvc", - "windows_i686_gnu", - "windows_i686_gnullvm", - "windows_i686_msvc", - "windows_x86_64_gnu", - "windows_x86_64_gnullvm", - "windows_x86_64_msvc", -] - -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" - -[[package]] -name = "windows_i686_gnu" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" - -[[package]] -name = "windows_i686_gnullvm" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" - -[[package]] -name = "windows_i686_msvc" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" - -[[package]] -name = "winnow" -version = "0.6.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68a9bda4691f099d435ad181000724da8e5899daa10713c2d432552b9ccd3a6f" -dependencies = [ - "memchr", -] +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] name = "yansi" version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09041cd90cf85f7f8b2df60c646f853b7f535ce68f85244eb6731cf89fa498ec" - -[[package]] -name = "zerocopy" -version = "0.7.35" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" -dependencies = [ - "zerocopy-derive", -] - -[[package]] -name = "zerocopy-derive" -version = "0.7.35" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.77", -] diff --git a/README.md b/README.md index fc68efc..be8bfc9 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,7 @@ [![CI Build](https://img.shields.io/github/actions/workflow/status/GREsau/schemars/ci.yml?branch=master&logo=GitHub)](https://github.com/GREsau/schemars/actions) [![Crates.io](https://img.shields.io/crates/v/schemars)](https://crates.io/crates/schemars) [![Docs](https://img.shields.io/docsrs/schemars/1.0.0--latest?label=docs)](https://docs.rs/schemars/1.0.0--latest) -[![MSRV 1.70+](https://img.shields.io/badge/msrv-1.70-blue)](https://blog.rust-lang.org/2023/06/01/Rust-1.70.0.html) +[![MSRV 1.65+](https://img.shields.io/badge/msrv-1.65-blue)](https://blog.rust-lang.org/2022/11/03/Rust-1.65.0.html) Generate JSON Schema documents from Rust code @@ -268,6 +268,7 @@ Schemars can implement `JsonSchema` on types from several popular crates, enable - `bytes1` - [bytes](https://crates.io/crates/bytes) (^1.0) - `chrono04` - [chrono](https://crates.io/crates/chrono) (^0.4) - `either1` - [either](https://crates.io/crates/either) (^1.3) +- `enumset1` - [enumset](https://crates.io/crates/enumset) (^1.0) - `indexmap2` - [indexmap](https://crates.io/crates/indexmap) (^2.0) - `rust_decimal1` - [rust_decimal](https://crates.io/crates/rust_decimal) (^1.0) - `semver1` - [semver](https://crates.io/crates/semver) (^1.0.9) @@ -280,5 +281,5 @@ For example, to implement `JsonSchema` on types from `chrono`, enable it as a fe ```toml [dependencies] -schemars = { version = "1.0.0-alpha.17", features = ["chrono04"] } +schemars = { version = "1.0.0-alpha.15", features = ["chrono04"] } ``` diff --git a/docs/0-migrating.md b/docs/0-migrating.md index be79b36..80fccb3 100644 --- a/docs/0-migrating.md +++ b/docs/0-migrating.md @@ -23,9 +23,10 @@ All optional dependencies are now suffixed by their version: - `url` is now `url2` - `bytes` is now `bytes1` - `rust_decimal` is now `rust_decimal1` +- `enumset` is now `enumset1` - `smol_str` is now `smol_str02` - `semver` is now `semver1` -- `enumset`, `indexmap`, `uuid08`, `arrayvec05` and `bigdecimal03` have been removed +- `indexmap`, `uuid08`, `arrayvec05` and `bigdecimal03` have been removed - `indexmap2`, `arrayvec07` and `bigdecimal04` are unchanged ## `Schema` is now a wrapper around `serde_json::Value` diff --git a/docs/4-features.md b/docs/4-features.md index 1141154..c2b80d1 100644 --- a/docs/4-features.md +++ b/docs/4-features.md @@ -18,6 +18,7 @@ Schemars can implement `JsonSchema` on types from several popular crates, enable - `bytes1` - [bytes](https://crates.io/crates/bytes) (^1.0) - `chrono04` - [chrono](https://crates.io/crates/chrono) (^0.4) - `either1` - [either](https://crates.io/crates/either) (^1.3) +- `enumset1` - [enumset](https://crates.io/crates/enumset) (^1.0) - `indexmap2` - [indexmap](https://crates.io/crates/indexmap) (^2.0) - `rust_decimal1` - [rust_decimal](https://crates.io/crates/rust_decimal) (^1.0) - `semver1` - [semver](https://crates.io/crates/semver) (^1.0.9) @@ -30,5 +31,5 @@ For example, to implement `JsonSchema` on types from `chrono`, enable it as a fe ```toml [dependencies] -schemars = { version = "1.0.0-alpha.17", features = ["chrono04"] } +schemars = { version = "1.0.0-alpha.15", features = ["chrono04"] } ``` diff --git a/docs/_includes/attributes.md b/docs/_includes/attributes.md index 1497b0f..37f6833 100644 --- a/docs/_includes/attributes.md +++ b/docs/_includes/attributes.md @@ -298,15 +298,13 @@ Set on a container, variant or field to set the generated schema's `title` and/o

-`#[schemars(example = value)]` +`#[schemars(example = "some::function")]`

-Set on a container, variant or field to include the given value in the generated schema's `examples`. The value can be any type that implements serde's `Serialize` trait - it does not need to be the same type as the attached struct/field. This attribute can be repeated to specify multiple examples. +Set on a container, variant or field to include the result of the given function in the generated schema's `examples`. The function should take no parameters and can return any type that implements serde's `Serialize` trait - it does not need to return the same type as the attached struct/field. This attribute can be repeated to specify multiple examples. -In previous versions of schemars, the value had to be a string literal identifying a defined function that would be called to return the actual example value (similar to the [`default`](#default) attribute). To avoid the new attribute behaviour from silently breaking old consumers, string literals consisting of a single word (e.g. `#[schemars(example = "my_fn")]`) or a path (e.g. `#[schemars(example = "my_mod::my_fn")]`) are currently disallowed. This restriction may be relaxed in a future version of schemars, but for now if you want to include such a string as the literal example value, this can be done by borrowing the value, e.g. `#[schemars(example = &"my_fn")]`. If you instead want to call a function to get the example value (mirrorring the old behaviour), you must use an explicit function call expression, e.g. `#[schemars(example = my_fn())]`. - -Alternatively, to directly set multiple examples without repeating `example = ...` attribute, you can instead use the [`extend`](#extend) attribute, e.g. `#[schemars(extend("examples" = [1, 2, 3]))]`. +To use the result of arbitrary expressions as examples, you can instead use the [`extend`](#extend) attribute, e.g. `[schemars(extend("examples" = ["example string"]))]`.

diff --git a/schemars/Cargo.toml b/schemars/Cargo.toml index 96232ea..7645939 100644 --- a/schemars/Cargo.toml +++ b/schemars/Cargo.toml @@ -3,17 +3,17 @@ name = "schemars" description = "Generate JSON Schemas from Rust code" homepage = "https://graham.cool/schemars/" repository = "https://github.com/GREsau/schemars" -version = "1.0.0-alpha.17" +version = "1.0.0-alpha.15" authors = ["Graham Esau "] edition = "2021" license = "MIT" readme = "README.md" keywords = ["rust", "json-schema", "serde"] categories = ["encoding", "no-std"] -rust-version = "1.70" +rust-version = "1.65" [dependencies] -schemars_derive = { version = "=1.0.0-alpha.17", optional = true, path = "../schemars_derive" } +schemars_derive = { version = "=1.0.0-alpha.15", optional = true, path = "../schemars_derive" } serde = { version = "1.0", default-features = false, features = ["alloc"]} serde_json = { version = "1.0.127", default-features = false, features = ["alloc"] } dyn-clone = "1.0" @@ -24,9 +24,10 @@ arrayvec07 = { version = "0.7", default-features = false, optional = true, packa bigdecimal04 = { version = "0.4", default-features = false, optional = true, package = "bigdecimal" } bytes1 = { version = "1.0", default-features = false, optional = true, package = "bytes" } chrono04 = { version = "0.4", default-features = false, optional = true, package = "chrono" } -either1 = { version = "1.3", default-features = false, optional = true, package = "either" } +either1 = { version = "1.3", default-features = false, optional = true, package = "either" } +enumset1 = { version = "1.0", default-features = false, optional = true, package = "enumset" } indexmap2 = { version = "2.0", default-features = false, optional = true, package = "indexmap" } -rust_decimal1 = { version = "1", default-features = false, optional = true, package = "rust_decimal" } +rust_decimal1 = { version = "1", default-features = false, optional = true, package = "rust_decimal"} semver1 = { version = "1.0.9", default-features = false, optional = true, package = "semver" } smallvec1 = { version = "1.0", default-features = false, optional = true, package = "smallvec" } smol_str02 = { version = "0.2.1", default-features = false, optional = true, package = "smol_str" } @@ -37,26 +38,6 @@ uuid1 = { version = "1.0", default-features = false, optional = true, package = pretty_assertions = "1.2.1" trybuild = "1.0" serde = { version = "1.0", features = ["derive"] } -jsonschema = { version = "0.20", default-features = false } -snapbox = { version = "0.6.17", features = ["json"] } -serde_repr = "0.1.19" -# Use github source until published garde version supports `length(equal = ...)` attr -garde = { git = "https://github.com/jprochazk/garde.git", rev = "be00ddddf8de14530ee890ccfdbaf0b13fb32852", features = ["derive", "email", "regex", "url"] } -validator = { version = "0.18.1", features = ["derive"] } -regex = { version = "1.10.6", default-features = false } - -arrayvec07 = { version = "0.7", default-features = false, features = ["serde"], package = "arrayvec"} -bigdecimal04 = { version = "0.4", default-features = false, features = ["serde"], package = "bigdecimal" } -bytes1 = { version = "1.0", default-features = false, features = ["serde"], package = "bytes" } -chrono04 = { version = "0.4", default-features = false, features = ["serde"], package = "chrono" } -either1 = { version = "1.3", default-features = false, features = ["serde"], package = "either" } -indexmap2 = { version = "2.0", default-features = false, features = ["serde"], package = "indexmap" } -rust_decimal1 = { version = "1", default-features = false, features = ["serde"], package = "rust_decimal" } -semver1 = { version = "1.0.9", default-features = false, features = ["serde"], package = "semver" } -smallvec1 = { version = "1.0", default-features = false, features = ["serde"], package = "smallvec" } -smol_str02 = { version = "0.2.1", default-features = false, features = ["serde"], package = "smol_str" } -url2 = { version = "2.0", default-features = false, features = ["serde"], package = "url" } -uuid1 = { version = "1.0", default-features = false, features = ["serde"], package = "uuid" } [features] default = ["derive", "std"] @@ -79,10 +60,66 @@ raw_value = ["serde_json/raw_value"] # For internal/CI use only _ui_test = [] +[[test]] +name = "std_time" +required-features = ["std"] + +[[test]] +name = "ffi" +required-features = ["std"] + [[test]] name = "ui" required-features = ["_ui_test"] +[[test]] +name = "chrono" +required-features = ["chrono04"] + +[[test]] +name = "indexmap" +required-features = ["indexmap2"] + +[[test]] +name = "either" +required-features = ["either1"] + +[[test]] +name = "uuid" +required-features = ["uuid1"] + +[[test]] +name = "smallvec" +required-features = ["smallvec1"] + +[[test]] +name = "bytes" +required-features = ["bytes1"] + +[[test]] +name = "arrayvec" +required-features = ["arrayvec07"] + +[[test]] +name = "url" +required-features = ["url2"] + +[[test]] +name = "enumset" +required-features = ["enumset1"] + +[[test]] +name = "smol_str" +required-features = ["smol_str02"] + +[[test]] +name = "semver" +required-features = ["semver1"] + +[[test]] +name = "decimal" +required-features = ["rust_decimal1", "bigdecimal04"] + [package.metadata.docs.rs] all-features = true rustdoc-args = ["--extend-css", "docs-rs-custom.css"] diff --git a/schemars/src/_private/mod.rs b/schemars/src/_private/mod.rs index aa5c6fe..3989f49 100644 --- a/schemars/src/_private/mod.rs +++ b/schemars/src/_private/mod.rs @@ -1,5 +1,5 @@ use crate::_alloc_prelude::*; -use crate::transform::{transform_immediate_subschemas, Transform}; +use crate::transform::transform_immediate_subschemas; use crate::{JsonSchema, Schema, SchemaGenerator}; use serde::Serialize; use serde_json::{json, map::Entry, Map, Value}; @@ -12,39 +12,6 @@ pub extern crate serde_json; pub use rustdoc::get_title_and_description; -pub fn json_schema_for_internally_tagged_enum_newtype_variant( - generator: &mut SchemaGenerator, -) -> Schema { - let mut schema = T::json_schema(generator); - - // Inline the newtype's inner schema if any of: - // - The type specifies that its schema should always be inlined - // - The generator settings specify that all schemas should be inlined - // - The inner type is a unit struct, which would cause an unsatisfiable schema due to mismatched `type`. - // In this case, we replace its type with "object" in `apply_internal_enum_variant_tag` - // - The inner schema specified `"additionalProperties": false` or `"unevaluatedProperties": false`, - // since that would disallow the variant tag. If additional/unevaluatedProperties is in the top-level - // schema, then we can leave it there, because it will "see" the variant tag property. But if it is - // nested e.g. in an `allOf`, then it must be removed, which is why we run `AllowUnknownProperties` - // but only on immediate subschemas. - - let mut transform = AllowUnknownProperties::default(); - transform_immediate_subschemas(&mut transform, &mut schema); - - if T::always_inline_schema() - || generator.settings().inline_subschemas - || schema.get("type").and_then(Value::as_str) == Some("null") - || schema.get("additionalProperties").and_then(Value::as_bool) == Some(false) - || schema.get("unevaluatedProperties").and_then(Value::as_bool) == Some(false) - || transform.did_modify - { - return schema; - } - - // ...otherwise, we can freely refer to the schema via a `$ref` - generator.subschema_for::() -} - // Helper for generating schemas for flattened `Option` fields. pub fn json_schema_for_flatten( generator: &mut SchemaGenerator, @@ -58,29 +25,20 @@ pub fn json_schema_for_flatten( // Always allow aditional/unevaluated properties, because the outer struct determines // whether it denies unknown fields. - AllowUnknownProperties::default().transform(&mut schema); + allow_unknown_properties(&mut schema); schema } -#[derive(Default)] -struct AllowUnknownProperties { - did_modify: bool, -} - -impl Transform for AllowUnknownProperties { - fn transform(&mut self, schema: &mut Schema) { - if schema.get("additionalProperties").and_then(Value::as_bool) == Some(false) { - schema.remove("additionalProperties"); - self.did_modify = true; - } - if schema.get("unevaluatedProperties").and_then(Value::as_bool) == Some(false) { - schema.remove("unevaluatedProperties"); - self.did_modify = true; - } - - transform_immediate_subschemas(self, schema); +fn allow_unknown_properties(schema: &mut Schema) { + if schema.get("additionalProperties").and_then(Value::as_bool) == Some(false) { + schema.remove("additionalProperties"); } + if schema.get("unevaluatedProperties").and_then(Value::as_bool) == Some(false) { + schema.remove("unevaluatedProperties"); + } + + transform_immediate_subschemas(&mut allow_unknown_properties, schema); } /// Hack to simulate specialization: diff --git a/schemars/src/generate.rs b/schemars/src/generate.rs index 498d3b4..375fa08 100644 --- a/schemars/src/generate.rs +++ b/schemars/src/generate.rs @@ -671,14 +671,13 @@ where impl Debug for Box { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - #[allow(clippy::used_underscore_items)] self._debug_type_name(f) } } fn _assert_send() { - fn assert() {} + fn _assert() {} - assert::(); - assert::(); + _assert::(); + _assert::(); } diff --git a/schemars/src/json_schema_impls/bytes1.rs b/schemars/src/json_schema_impls/bytes1.rs deleted file mode 100644 index f679e0d..0000000 --- a/schemars/src/json_schema_impls/bytes1.rs +++ /dev/null @@ -1,29 +0,0 @@ -use crate::_alloc_prelude::*; -use crate::generate::Contract; -use crate::{JsonSchema, Schema}; -use alloc::borrow::Cow; -use serde_json::Value; - -impl JsonSchema for bytes1::Bytes { - fn schema_name() -> Cow<'static, str> { - "Bytes".into() - } - - fn schema_id() -> Cow<'static, str> { - "bytes::Bytes".into() - } - - fn json_schema(generator: &mut crate::SchemaGenerator) -> crate::Schema { - let ty = match generator.contract() { - Contract::Deserialize => Value::Array(vec!["array".into(), "string".into()]), - Contract::Serialize => "array".into(), - }; - - let mut result = Schema::default(); - result.insert("type".to_owned(), ty); - result.insert("items".to_owned(), generator.subschema_for::().into()); - result - } -} - -forward_impl!(bytes1::BytesMut => bytes1::Bytes); diff --git a/schemars/src/json_schema_impls/chrono04.rs b/schemars/src/json_schema_impls/chrono04.rs index 700af09..a153aca 100644 --- a/schemars/src/json_schema_impls/chrono04.rs +++ b/schemars/src/json_schema_impls/chrono04.rs @@ -58,5 +58,5 @@ macro_rules! formatted_string_impl { formatted_string_impl!(NaiveDate, "date"); formatted_string_impl!(NaiveDateTime, "partial-date-time"); -formatted_string_impl!(NaiveTime, "partial-time"); +formatted_string_impl!(NaiveTime, "partial-date-time"); formatted_string_impl!(DateTime, "date-time", JsonSchema for DateTime); diff --git a/schemars/src/json_schema_impls/either1.rs b/schemars/src/json_schema_impls/either1.rs index 2be1684..0e9a129 100644 --- a/schemars/src/json_schema_impls/either1.rs +++ b/schemars/src/json_schema_impls/either1.rs @@ -17,28 +17,7 @@ impl JsonSchema for Either { fn json_schema(generator: &mut SchemaGenerator) -> Schema { json_schema!({ - "oneOf": [ - { - "type": "object", - "properties": { - "Left": generator.subschema_for::() - }, - "additionalProperties": false, - "required": [ - "Left" - ] - }, - { - "type": "object", - "properties": { - "Right": generator.subschema_for::() - }, - "additionalProperties": false, - "required": [ - "Right" - ] - } - ] + "anyOf": [generator.subschema_for::(), generator.subschema_for::()], }) } } diff --git a/schemars/src/json_schema_impls/ffi.rs b/schemars/src/json_schema_impls/ffi.rs index 638fb6c..cf2efe5 100644 --- a/schemars/src/json_schema_impls/ffi.rs +++ b/schemars/src/json_schema_impls/ffi.rs @@ -2,7 +2,6 @@ use crate::SchemaGenerator; use crate::_alloc_prelude::*; use crate::{json_schema, JsonSchema, Schema}; use alloc::borrow::Cow; -use serde_json::json; use std::ffi::{CStr, CString, OsStr, OsString}; impl JsonSchema for OsString { @@ -38,31 +37,5 @@ impl JsonSchema for OsString { forward_impl!(OsStr => OsString); -impl JsonSchema for CString { - fn schema_name() -> Cow<'static, str> { - "CString".into() - } - - fn schema_id() -> Cow<'static, str> { - "std::ffi::CString".into() - } - - fn json_schema(generator: &mut SchemaGenerator) -> Schema { - let ty = if generator.contract().is_deserialize() { - json!(["array", "string"]) - } else { - json!("array") - }; - - json_schema!({ - "type": ty, - "items": { - "type": "integer", - "minimum": 1, - "maximum": 255 - }, - }) - } -} - -forward_impl!(CStr => CString); +forward_impl!(CString => Vec); +forward_impl!(CStr => Vec); diff --git a/schemars/src/json_schema_impls/mod.rs b/schemars/src/json_schema_impls/mod.rs index cbe1a07..1921a6a 100644 --- a/schemars/src/json_schema_impls/mod.rs +++ b/schemars/src/json_schema_impls/mod.rs @@ -42,7 +42,8 @@ macro_rules! forward_impl { mod array; mod core; mod maps; -mod nonzero; +mod nonzero_signed; +mod nonzero_unsigned; mod primitives; mod sequences; mod serdejson; @@ -60,7 +61,10 @@ mod ffi; mod arrayvec07; #[cfg(feature = "bytes1")] -mod bytes1; +mod bytes1 { + forward_impl!(bytes1::Bytes => alloc::vec::Vec); + forward_impl!(bytes1::BytesMut => alloc::vec::Vec); +} #[cfg(feature = "chrono04")] mod chrono04; @@ -71,6 +75,9 @@ mod decimal; #[cfg(feature = "either1")] mod either1; +#[cfg(feature = "enumset1")] +forward_impl!(( crate::JsonSchema for enumset1::EnumSet) => alloc::collections::BTreeSet); + #[cfg(feature = "indexmap2")] mod indexmap2; diff --git a/schemars/src/json_schema_impls/nonzero.rs b/schemars/src/json_schema_impls/nonzero.rs deleted file mode 100644 index ede0c58..0000000 --- a/schemars/src/json_schema_impls/nonzero.rs +++ /dev/null @@ -1,64 +0,0 @@ -use crate::_alloc_prelude::*; -use crate::{JsonSchema, Schema, SchemaGenerator}; -use alloc::borrow::Cow; -use core::num::*; - -macro_rules! nonzero_signed_impl { - ($type:ty => $primitive:ty) => { - impl JsonSchema for $type { - always_inline!(); - - fn schema_name() -> Cow<'static, str> { - stringify!($type).into() - } - - fn schema_id() -> Cow<'static, str> { - stringify!(std::num::$type).into() - } - - fn json_schema(generator: &mut SchemaGenerator) -> Schema { - let mut schema = <$primitive>::json_schema(generator); - schema.insert("not".to_owned(), serde_json::json!({ - "const": 0 - })); - schema - } - } - }; -} - -nonzero_signed_impl!(NonZeroI8 => i8); -nonzero_signed_impl!(NonZeroI16 => i16); -nonzero_signed_impl!(NonZeroI32 => i32); -nonzero_signed_impl!(NonZeroI64 => i64); -nonzero_signed_impl!(NonZeroI128 => i128); -nonzero_signed_impl!(NonZeroIsize => isize); - -macro_rules! nonzero_unsigned_impl { - ($type:ty => $primitive:ty) => { - impl JsonSchema for $type { - always_inline!(); - - fn schema_name() -> Cow<'static, str> { - stringify!($type).into() - } - - fn schema_id() -> Cow<'static, str> { - stringify!(std::num::$type).into() - } - - fn json_schema(generator: &mut SchemaGenerator) -> Schema { - let mut schema = <$primitive>::json_schema(generator); - schema.insert("minimum".to_owned(), 1.into()); - schema - } - } - }; -} - -nonzero_unsigned_impl!(NonZeroU8 => u8); -nonzero_unsigned_impl!(NonZeroU16 => u16); -nonzero_unsigned_impl!(NonZeroU32 => u32); -nonzero_unsigned_impl!(NonZeroU64 => u64); -nonzero_unsigned_impl!(NonZeroU128 => u128); -nonzero_unsigned_impl!(NonZeroUsize => usize); diff --git a/schemars/src/json_schema_impls/nonzero_signed.rs b/schemars/src/json_schema_impls/nonzero_signed.rs new file mode 100644 index 0000000..c5b3e84 --- /dev/null +++ b/schemars/src/json_schema_impls/nonzero_signed.rs @@ -0,0 +1,37 @@ +use crate::SchemaGenerator; +use crate::_alloc_prelude::*; +use crate::{JsonSchema, Schema}; +use alloc::borrow::Cow; +use core::num::*; + +macro_rules! nonzero_unsigned_impl { + ($type:ty => $primitive:ty) => { + impl JsonSchema for $type { + always_inline!(); + + fn schema_name() -> Cow<'static, str> { + stringify!($type).into() + } + + fn schema_id() -> Cow<'static, str> { + stringify!(std::num::$type).into() + } + + fn json_schema(generator: &mut SchemaGenerator) -> Schema { + let mut schema = <$primitive>::json_schema(generator); + let object = schema.ensure_object(); + object.insert("not".to_owned(), serde_json::json!({ + "const": 0 + })); + schema + } + } + }; +} + +nonzero_unsigned_impl!(NonZeroI8 => i8); +nonzero_unsigned_impl!(NonZeroI16 => i16); +nonzero_unsigned_impl!(NonZeroI32 => i32); +nonzero_unsigned_impl!(NonZeroI64 => i64); +nonzero_unsigned_impl!(NonZeroI128 => i128); +nonzero_unsigned_impl!(NonZeroIsize => isize); diff --git a/schemars/src/json_schema_impls/nonzero_unsigned.rs b/schemars/src/json_schema_impls/nonzero_unsigned.rs new file mode 100644 index 0000000..c6711ab --- /dev/null +++ b/schemars/src/json_schema_impls/nonzero_unsigned.rs @@ -0,0 +1,36 @@ +use crate::JsonSchema; +use crate::Schema; +use crate::SchemaGenerator; +use crate::_alloc_prelude::*; +use alloc::borrow::Cow; +use core::num::*; + +macro_rules! nonzero_unsigned_impl { + ($type:ty => $primitive:ty) => { + impl JsonSchema for $type { + always_inline!(); + + fn schema_name() -> Cow<'static, str> { + stringify!($type).into() + } + + fn schema_id() -> Cow<'static, str> { + stringify!(std::num::$type).into() + } + + fn json_schema(generator: &mut SchemaGenerator) -> Schema { + let mut schema = <$primitive>::json_schema(generator); + let object = schema.ensure_object(); + object.insert("minimum".to_owned(), 1.into()); + schema + } + } + }; +} + +nonzero_unsigned_impl!(NonZeroU8 => u8); +nonzero_unsigned_impl!(NonZeroU16 => u16); +nonzero_unsigned_impl!(NonZeroU32 => u32); +nonzero_unsigned_impl!(NonZeroU64 => u64); +nonzero_unsigned_impl!(NonZeroU128 => u128); +nonzero_unsigned_impl!(NonZeroUsize => usize); diff --git a/schemars/src/json_schema_impls/semver1.rs b/schemars/src/json_schema_impls/semver1.rs index 65ec8d3..1869fa9 100644 --- a/schemars/src/json_schema_impls/semver1.rs +++ b/schemars/src/json_schema_impls/semver1.rs @@ -4,8 +4,10 @@ use alloc::borrow::Cow; use semver1::Version; impl JsonSchema for Version { + always_inline!(); + fn schema_name() -> Cow<'static, str> { - "SemVer".into() + "Version".into() } fn schema_id() -> Cow<'static, str> { diff --git a/schemars/src/lib.rs b/schemars/src/lib.rs index b62a153..b516c6f 100644 --- a/schemars/src/lib.rs +++ b/schemars/src/lib.rs @@ -145,6 +145,7 @@ pub mod r#gen { /// /// assert_eq!(>::schema_id(), <&mut GenericType<&i32>>::schema_id()); /// ``` + pub trait JsonSchema { /// Whether JSON Schemas generated for this type should be included directly in parent schemas, /// rather than being re-used where possible using the `$ref` keyword. diff --git a/schemars/tests/actual/README.md b/schemars/tests/actual/README.md new file mode 100644 index 0000000..9fbbbab --- /dev/null +++ b/schemars/tests/actual/README.md @@ -0,0 +1,3 @@ +# Actual Generated Schemas + +If a test fails because a generated schema did not match the expected JSON, then the actual schema will be written to a JSON file in this directory. \ No newline at end of file diff --git a/schemars/tests/arrayvec.rs b/schemars/tests/arrayvec.rs new file mode 100644 index 0000000..e32d1a7 --- /dev/null +++ b/schemars/tests/arrayvec.rs @@ -0,0 +1,12 @@ +mod util; +use util::*; + +#[test] +fn arrayvec07() -> TestResult { + test_default_generated_schema::>("arrayvec") +} + +#[test] +fn arrayvec07_string() -> TestResult { + test_default_generated_schema::>("arrayvec_string") +} diff --git a/schemars/tests/integration/bound.rs b/schemars/tests/bound.rs similarity index 57% rename from schemars/tests/integration/bound.rs rename to schemars/tests/bound.rs index 71dfba3..cb545dd 100644 --- a/schemars/tests/integration/bound.rs +++ b/schemars/tests/bound.rs @@ -1,6 +1,9 @@ -use crate::prelude::*; +mod util; use std::marker::PhantomData; +use schemars::JsonSchema; +use util::*; + struct MyIterator; impl Iterator for MyIterator { @@ -13,7 +16,7 @@ impl Iterator for MyIterator { // The default trait bounds would require T to implement JsonSchema, // which MyIterator does not. -#[derive(JsonSchema, Serialize, Deserialize)] +#[derive(JsonSchema)] #[schemars(bound = "T::Item: JsonSchema", rename = "MyContainer")] pub struct MyContainer where @@ -24,12 +27,6 @@ where } #[test] -fn manual_bound_set() { - test!(MyContainer) - .assert_snapshot() - .assert_allows_ser_roundtrip([MyContainer { - associated: "test".to_owned(), - generic: PhantomData, - }]) - .assert_matches_de_roundtrip(arbitrary_values()); +fn manual_bound_set() -> TestResult { + test_default_generated_schema::>("bound") } diff --git a/schemars/tests/bytes.rs b/schemars/tests/bytes.rs new file mode 100644 index 0000000..5797411 --- /dev/null +++ b/schemars/tests/bytes.rs @@ -0,0 +1,8 @@ +mod util; +use bytes1::{Bytes, BytesMut}; +use util::*; + +#[test] +fn bytes() -> TestResult { + test_default_generated_schema::<(Bytes, BytesMut)>("bytes") +} diff --git a/schemars/tests/chrono.rs b/schemars/tests/chrono.rs new file mode 100644 index 0000000..da6f8d4 --- /dev/null +++ b/schemars/tests/chrono.rs @@ -0,0 +1,19 @@ +mod util; +use chrono04::prelude::*; +use schemars::JsonSchema; +use util::*; + +#[allow(dead_code)] +#[derive(JsonSchema)] +struct ChronoTypes { + weekday: Weekday, + date_time: DateTime, + naive_date: NaiveDate, + naive_date_time: NaiveDateTime, + naive_time: NaiveTime, +} + +#[test] +fn chrono_types() -> TestResult { + test_default_generated_schema::("chrono-types") +} diff --git a/schemars/tests/contract.rs b/schemars/tests/contract.rs new file mode 100644 index 0000000..bd5160c --- /dev/null +++ b/schemars/tests/contract.rs @@ -0,0 +1,214 @@ +mod util; +use schemars::{generate::SchemaSettings, JsonSchema}; +use util::*; + +#[allow(dead_code)] +#[derive(JsonSchema)] +#[schemars(rename_all(serialize = "SCREAMING-KEBAB-CASE"))] +struct MyStruct { + #[schemars(skip_deserializing)] + read_only: bool, + #[schemars(skip_serializing)] + write_only: bool, + #[schemars(default)] + default: bool, + #[schemars(skip_serializing_if = "anything")] + skip_serializing_if: bool, + #[schemars(rename(serialize = "ser_renamed", deserialize = "de_renamed"))] + renamed: bool, + option: Option, +} + +#[test] +fn contract_deserialize() -> TestResult { + test_generated_schema::( + "contract_deserialize", + SchemaSettings::default().for_deserialize(), + ) +} + +#[test] +fn contract_serialize() -> TestResult { + test_generated_schema::( + "contract_serialize", + SchemaSettings::default().for_serialize(), + ) +} + +#[allow(dead_code)] +#[derive(JsonSchema)] +struct TupleStruct( + String, + #[schemars(skip_serializing)] bool, + String, + #[schemars(skip_deserializing)] bool, + String, +); + +#[test] +fn contract_deserialize_tuple_struct() -> TestResult { + test_generated_schema::( + "contract_deserialize_tuple_struct", + SchemaSettings::default().for_deserialize(), + ) +} + +#[test] +fn contract_serialize_tuple_struct() -> TestResult { + test_generated_schema::( + "contract_serialize_tuple_struct", + SchemaSettings::default().for_serialize(), + ) +} + +#[allow(dead_code)] +#[derive(JsonSchema)] +#[schemars( + rename_all(serialize = "SCREAMING-KEBAB-CASE"), + rename_all_fields(serialize = "PascalCase") +)] +enum ExternalEnum { + #[schemars(skip_deserializing)] + ReadOnlyUnit, + #[schemars(skip_serializing)] + WriteOnlyUnit, + #[schemars(skip_deserializing)] + ReadOnlyStruct { s: String }, + #[schemars(skip_serializing)] + WriteOnlyStruct { i: isize }, + #[schemars(rename(serialize = "ser_renamed_unit", deserialize = "de_renamed_unit"))] + RenamedUnit, + #[schemars(rename(serialize = "ser_renamed_struct", deserialize = "de_renamed_struct"))] + RenamedStruct { b: bool }, +} + +#[test] +fn contract_deserialize_external_tag_enum() -> TestResult { + test_generated_schema::( + "contract_deserialize_external_tag_enum", + SchemaSettings::default().for_deserialize(), + ) +} + +#[test] +fn contract_serialize_external_tag_enum() -> TestResult { + test_generated_schema::( + "contract_serialize_external_tag_enum", + SchemaSettings::default().for_serialize(), + ) +} + +#[allow(dead_code)] +#[derive(JsonSchema)] +#[schemars( + tag = "tag", + rename_all(serialize = "SCREAMING-KEBAB-CASE"), + rename_all_fields(serialize = "PascalCase") +)] +enum InternalEnum { + #[schemars(skip_deserializing)] + ReadOnlyUnit, + #[schemars(skip_serializing)] + WriteOnlyUnit, + #[schemars(skip_deserializing)] + ReadOnlyStruct { s: String }, + #[schemars(skip_serializing)] + WriteOnlyStruct { i: isize }, + #[schemars(rename(serialize = "ser_renamed_unit", deserialize = "de_renamed_unit"))] + RenamedUnit, + #[schemars(rename(serialize = "ser_renamed_struct", deserialize = "de_renamed_struct"))] + RenamedStruct { b: bool }, +} + +#[test] +fn contract_deserialize_internal_tag_enum() -> TestResult { + test_generated_schema::( + "contract_deserialize_internal_tag_enum", + SchemaSettings::default().for_deserialize(), + ) +} + +#[test] +fn contract_serialize_internal_tag_enum() -> TestResult { + test_generated_schema::( + "contract_serialize_internal_tag_enum", + SchemaSettings::default().for_serialize(), + ) +} + +#[allow(dead_code)] +#[derive(JsonSchema)] +#[schemars( + tag = "tag", + content = "content", + rename_all(serialize = "SCREAMING-KEBAB-CASE"), + rename_all_fields(serialize = "PascalCase") +)] +enum AdjacentEnum { + #[schemars(skip_deserializing)] + ReadOnlyUnit, + #[schemars(skip_serializing)] + WriteOnlyUnit, + #[schemars(skip_deserializing)] + ReadOnlyStruct { s: String }, + #[schemars(skip_serializing)] + WriteOnlyStruct { i: isize }, + #[schemars(rename(serialize = "ser_renamed_unit", deserialize = "de_renamed_unit"))] + RenamedUnit, + #[schemars(rename(serialize = "ser_renamed_struct", deserialize = "de_renamed_struct"))] + RenamedStruct { b: bool }, +} + +#[test] +fn contract_deserialize_adjacent_tag_enum() -> TestResult { + test_generated_schema::( + "contract_deserialize_adjacent_tag_enum", + SchemaSettings::default().for_deserialize(), + ) +} + +#[test] +fn contract_serialize_adjacent_tag_enum() -> TestResult { + test_generated_schema::( + "contract_serialize_adjacent_tag_enum", + SchemaSettings::default().for_serialize(), + ) +} + +#[allow(dead_code)] +#[derive(JsonSchema)] +#[schemars( + untagged, + rename_all(serialize = "SCREAMING-KEBAB-CASE"), + rename_all_fields(serialize = "PascalCase") +)] +enum UntaggedEnum { + #[schemars(skip_deserializing)] + ReadOnlyUnit, + #[schemars(skip_serializing)] + WriteOnlyUnit, + #[schemars(skip_deserializing)] + ReadOnlyStruct { s: String }, + #[schemars(skip_serializing)] + WriteOnlyStruct { i: isize }, + #[schemars(rename(serialize = "ser_renamed_unit", deserialize = "de_renamed_unit"))] + RenamedUnit, + #[schemars(rename(serialize = "ser_renamed_struct", deserialize = "de_renamed_struct"))] + RenamedStruct { b: bool }, +} + +#[test] +fn contract_deserialize_untagged_enum() -> TestResult { + test_generated_schema::( + "contract_deserialize_untagged_enum", + SchemaSettings::default().for_deserialize(), + ) +} + +#[test] +fn contract_serialize_untagged_enum() -> TestResult { + test_generated_schema::( + "contract_serialize_untagged_enum", + SchemaSettings::default().for_serialize(), + ) +} diff --git a/schemars/tests/crate_alias.rs b/schemars/tests/crate_alias.rs new file mode 100644 index 0000000..e5d56f9 --- /dev/null +++ b/schemars/tests/crate_alias.rs @@ -0,0 +1,20 @@ +mod util; +use ::schemars as not_schemars; +use util::*; + +#[allow(unused_imports)] +use std as schemars; + +#[allow(dead_code)] +#[derive(not_schemars::JsonSchema)] +#[schemars(crate = "not_schemars")] +struct Struct { + /// This is a document + foo: i32, + bar: bool, +} + +#[test] +fn test_crate_alias() -> TestResult { + test_default_generated_schema::("crate_alias") +} diff --git a/schemars/tests/decimal.rs b/schemars/tests/decimal.rs new file mode 100644 index 0000000..246e813 --- /dev/null +++ b/schemars/tests/decimal.rs @@ -0,0 +1,12 @@ +mod util; +use util::*; + +#[test] +fn rust_decimal() -> TestResult { + test_default_generated_schema::("rust_decimal") +} + +#[test] +fn bigdecimal04() -> TestResult { + test_default_generated_schema::("bigdecimal04") +} diff --git a/schemars/tests/default.rs b/schemars/tests/default.rs new file mode 100644 index 0000000..ab489f5 --- /dev/null +++ b/schemars/tests/default.rs @@ -0,0 +1,59 @@ +mod util; +use schemars::JsonSchema; +use util::*; + +fn is_default(value: &T) -> bool { + value == &T::default() +} + +fn ten_and_true() -> MyStruct2 { + MyStruct2 { + my_int: 10, + my_bool: true, + } +} + +fn six() -> i32 { + 6 +} + +fn custom_serialize(value: &MyStruct2, ser: S) -> Result +where + S: serde::Serializer, +{ + ser.collect_str(&format_args!("i:{} b:{}", value.my_int, value.my_bool)) +} + +#[allow(dead_code)] +#[derive(Default, JsonSchema)] +#[serde(default)] +struct MyStruct { + my_int: i32, + my_bool: bool, + my_optional_string: Option, + #[serde(serialize_with = "custom_serialize")] + my_struct2: MyStruct2, + #[serde( + serialize_with = "custom_serialize", + skip_serializing_if = "is_default" + )] + my_struct2_default_skipped: MyStruct2, + not_serialize: NotSerialize, +} + +#[allow(dead_code)] +#[derive(Default, JsonSchema, PartialEq)] +#[serde(default = "ten_and_true")] +struct MyStruct2 { + #[serde(default = "six")] + my_int: i32, + my_bool: bool, +} + +#[derive(Default, JsonSchema)] +struct NotSerialize; + +#[test] +fn schema_default_values() -> TestResult { + test_default_generated_schema::("default") +} diff --git a/schemars/tests/deprecated.rs b/schemars/tests/deprecated.rs new file mode 100644 index 0000000..1772a8f --- /dev/null +++ b/schemars/tests/deprecated.rs @@ -0,0 +1,39 @@ +#![allow(deprecated)] + +mod util; +use schemars::JsonSchema; +use util::*; + +#[allow(dead_code)] +#[derive(JsonSchema)] +#[deprecated] +struct DeprecatedStruct { + foo: i32, + #[deprecated] + deprecated_field: bool, +} + +#[test] +fn deprecated_struct() -> TestResult { + test_default_generated_schema::("deprecated-struct") +} + +#[allow(dead_code)] +#[derive(JsonSchema)] +#[deprecated] +enum DeprecatedEnum { + Unit, + #[deprecated] + DeprecatedUnitVariant, + #[deprecated] + DeprecatedStructVariant { + foo: i32, + #[deprecated] + deprecated_field: bool, + }, +} + +#[test] +fn deprecated_enum() -> TestResult { + test_default_generated_schema::("deprecated-enum") +} diff --git a/schemars/tests/integration/docs.rs b/schemars/tests/docs.rs similarity index 81% rename from schemars/tests/integration/docs.rs rename to schemars/tests/docs.rs index 4ca11c7..7086c69 100644 --- a/schemars/tests/integration/docs.rs +++ b/schemars/tests/docs.rs @@ -1,4 +1,6 @@ -use crate::prelude::*; +mod util; +use schemars::JsonSchema; +use util::*; #[allow(dead_code)] #[derive(JsonSchema)] @@ -22,11 +24,6 @@ struct MyStruct { #[derive(JsonSchema)] struct MyUnitStruct; -#[test] -fn doc_comments_struct() { - test!(MyStruct).assert_snapshot(); -} - #[allow(dead_code)] #[doc = " # This is the enum's title "] #[doc = " This is "] @@ -58,8 +55,13 @@ enum MyEnum { } #[test] -fn doc_comments_enum() { - test!(MyEnum).assert_snapshot(); +fn doc_comments_struct() -> TestResult { + test_default_generated_schema::("doc_comments_struct") +} + +#[test] +fn doc_comments_enum() -> TestResult { + test_default_generated_schema::("doc_comments_enum") } /// # OverrideDocs struct @@ -80,6 +82,6 @@ struct OverrideDocs { } #[test] -fn doc_comments_override() { - test!(OverrideDocs).assert_snapshot(); +fn doc_comments_override() -> TestResult { + test_default_generated_schema::("doc_comments_override") } diff --git a/schemars/tests/either.rs b/schemars/tests/either.rs new file mode 100644 index 0000000..5dcd079 --- /dev/null +++ b/schemars/tests/either.rs @@ -0,0 +1,8 @@ +mod util; +use either1::Either; +use util::*; + +#[test] +fn either() -> TestResult { + test_default_generated_schema::>>("either") +} diff --git a/schemars/tests/enum.rs b/schemars/tests/enum.rs new file mode 100644 index 0000000..45698a7 --- /dev/null +++ b/schemars/tests/enum.rs @@ -0,0 +1,185 @@ +mod util; +use std::collections::BTreeMap; + +use schemars::JsonSchema; +use util::*; + +// Ensure that schemars_derive uses the full path to std::string::String +pub struct String; + +#[derive(JsonSchema)] +struct UnitStruct; + +#[allow(dead_code)] +#[derive(JsonSchema)] +struct Struct { + foo: i32, + bar: bool, +} + +#[allow(dead_code)] +#[derive(JsonSchema)] +#[schemars(rename_all = "camelCase")] +enum External { + UnitOne, + StringMap(BTreeMap<&'static str, &'static str>), + UnitStructNewType(UnitStruct), + StructNewType(Struct), + Struct { + foo: i32, + bar: bool, + }, + UnitTwo, + Tuple(i32, bool), + #[schemars(with = "i32")] + WithInt, +} + +#[test] +fn enum_external_tag() -> TestResult { + test_default_generated_schema::("enum-external") +} + +#[allow(dead_code)] +#[derive(JsonSchema)] +#[schemars(tag = "typeProperty")] +enum Internal { + UnitOne, + StringMap(BTreeMap<&'static str, &'static str>), + UnitStructNewType(UnitStruct), + StructNewType(Struct), + Struct { + foo: i32, + bar: bool, + }, + UnitTwo, + #[schemars(with = "i32")] + WithInt, +} + +#[test] +fn enum_internal_tag() -> TestResult { + test_default_generated_schema::("enum-internal") +} + +#[allow(dead_code)] +#[derive(JsonSchema)] +#[schemars(untagged)] +enum Untagged { + UnitOne, + StringMap(BTreeMap<&'static str, &'static str>), + UnitStructNewType(UnitStruct), + StructNewType(Struct), + Struct { + foo: i32, + bar: bool, + }, + Tuple(i32, bool), + #[schemars(with = "i32")] + WithInt, +} + +#[test] +fn enum_untagged() -> TestResult { + test_default_generated_schema::("enum-untagged") +} + +#[allow(dead_code)] +#[derive(JsonSchema)] +#[schemars(tag = "t", content = "c")] +enum Adjacent { + UnitOne, + StringMap(BTreeMap<&'static str, &'static str>), + UnitStructNewType(UnitStruct), + StructNewType(Struct), + Struct { + foo: i32, + bar: bool, + }, + Tuple(i32, bool), + UnitTwo, + #[schemars(with = "i32")] + WithInt, +} + +#[test] +fn enum_adjacent_tagged() -> TestResult { + test_default_generated_schema::("enum-adjacent-tagged") +} + +#[allow(dead_code)] +#[derive(JsonSchema)] +#[schemars(tag = "typeProperty")] +enum SimpleInternal { + A, + B, + C, +} + +#[test] +fn enum_simple_internal_tag() -> TestResult { + test_default_generated_schema::("enum-simple-internal") +} + +#[allow(dead_code)] +#[derive(JsonSchema)] +enum SoundOfMusic { + /// # A deer + /// + /// A female deer + Do, + /// A drop of golden sun + Re, + /// A name I call myself + Mi, +} + +#[test] +fn enum_unit_with_doc_comments() -> TestResult { + test_default_generated_schema::("enum-unit-doc") +} + +#[derive(JsonSchema)] +enum NoVariants {} + +#[test] +fn enum_no_variants() -> TestResult { + test_default_generated_schema::("no-variants") +} + +#[derive(JsonSchema)] +#[serde(rename_all_fields = "PascalCase")] +pub enum RenameAllFields { + First { + nested_attribute: std::string::String, + }, +} + +#[derive(JsonSchema)] +#[serde(rename_all = "snake_case")] +pub enum RenameAll { + First { nested_attribute: bool }, +} + +#[derive(JsonSchema)] +pub enum RenameAttribute { + First { + #[serde(rename = "RenamedAttribute")] + nested_attribute: std::string::String, + }, +} + +#[test] +fn enum_unit_rename_attribute() -> TestResult { + test_default_generated_schema::("enum-rename-attr") +} + +#[test] +fn enum_unit_rename_all_fields() -> TestResult { + test_default_generated_schema::("enum-rename-all-fields") +} + +#[test] +fn enum_unit_rename_all() -> TestResult { + test_default_generated_schema::("enum-rename-all") +} diff --git a/schemars/tests/enum_deny_unknown_fields.rs b/schemars/tests/enum_deny_unknown_fields.rs new file mode 100644 index 0000000..ef56d05 --- /dev/null +++ b/schemars/tests/enum_deny_unknown_fields.rs @@ -0,0 +1,127 @@ +mod util; +use std::collections::BTreeMap; + +use schemars::JsonSchema; +use util::*; + +// Ensure that schemars_derive uses the full path to std::string::String +pub struct String; + +#[derive(JsonSchema)] +struct UnitStruct; + +#[allow(dead_code)] +#[derive(JsonSchema)] +struct Struct { + foo: i32, + bar: bool, +} + +// Outer container should always have additionalProperties: false +// `Struct` variant should have additionalProperties: false +#[allow(dead_code)] +#[derive(JsonSchema)] +#[schemars(rename_all = "camelCase", deny_unknown_fields)] +enum External { + UnitOne, + StringMap(BTreeMap<&'static str, &'static str>), + UnitStructNewType(UnitStruct), + StructNewType(Struct), + Struct { + foo: i32, + bar: bool, + }, + UnitTwo, + Tuple(i32, bool), + #[schemars(with = "i32")] + WithInt, +} + +#[test] +fn enum_external_tag() -> TestResult { + test_default_generated_schema::("enum-external-duf") +} + +// Only `Struct` variant should have additionalProperties: false +#[allow(dead_code)] +#[derive(JsonSchema)] +#[schemars(tag = "typeProperty", deny_unknown_fields)] +enum Internal { + UnitOne, + StringMap(BTreeMap<&'static str, &'static str>), + UnitStructNewType(UnitStruct), + StructNewType(Struct), + Struct { + foo: i32, + bar: bool, + }, + UnitTwo, + #[schemars(with = "i32")] + WithInt, +} + +#[test] +fn enum_internal_tag() -> TestResult { + test_default_generated_schema::("enum-internal-duf") +} + +// Only `Struct` variant should have additionalProperties: false +#[allow(dead_code)] +#[derive(JsonSchema)] +#[schemars(untagged, deny_unknown_fields)] +enum Untagged { + UnitOne, + StringMap(BTreeMap<&'static str, &'static str>), + UnitStructNewType(UnitStruct), + StructNewType(Struct), + Struct { + foo: i32, + bar: bool, + }, + Tuple(i32, bool), + #[schemars(with = "i32")] + WithInt, +} + +#[test] +fn enum_untagged() -> TestResult { + test_default_generated_schema::("enum-untagged-duf") +} + +// Outer container and `Struct` variant should have additionalProperties: false +#[allow(dead_code)] +#[derive(JsonSchema)] +#[schemars(tag = "t", content = "c", deny_unknown_fields)] +enum Adjacent { + UnitOne, + StringMap(BTreeMap<&'static str, &'static str>), + UnitStructNewType(UnitStruct), + StructNewType(Struct), + Struct { + foo: i32, + bar: bool, + }, + Tuple(i32, bool), + UnitTwo, + #[schemars(with = "i32")] + WithInt, +} + +#[test] +fn enum_adjacent_tagged() -> TestResult { + test_default_generated_schema::("enum-adjacent-tagged-duf") +} + +#[allow(dead_code)] +#[derive(JsonSchema)] +#[schemars(tag = "typeProperty", deny_unknown_fields)] +enum SimpleInternal { + A, + B, + C, +} + +#[test] +fn enum_simple_internal_tag() -> TestResult { + test_default_generated_schema::("enum-simple-internal-duf") +} diff --git a/schemars/tests/enum_flatten.rs b/schemars/tests/enum_flatten.rs new file mode 100644 index 0000000..4c94a4c --- /dev/null +++ b/schemars/tests/enum_flatten.rs @@ -0,0 +1,89 @@ +mod util; +use schemars::{generate::SchemaSettings, JsonSchema}; +use util::*; + +#[allow(dead_code)] +#[derive(JsonSchema)] +struct Flat { + f: f32, + #[schemars(flatten)] + e1: Enum1, + #[schemars(flatten)] + e2: Enum2, + #[schemars(flatten)] + e3: Enum3, + #[schemars(flatten)] + e4: Enum4, + #[schemars(flatten)] + e5: Enum5, +} + +#[allow(dead_code)] +#[derive(JsonSchema)] +enum Enum1 { + B(bool), + S(String), +} + +#[allow(dead_code)] +#[derive(JsonSchema)] +enum Enum2 { + U(u32), + F(f64), +} + +#[allow(dead_code)] +#[derive(JsonSchema)] +enum Enum3 { + B2(bool), + S2(String), +} + +#[allow(dead_code)] +#[derive(JsonSchema)] +enum Enum4 { + U2(u32), + F2(f64), +} + +#[allow(dead_code)] +#[derive(JsonSchema)] +enum Enum5 { + B3(bool), + S3(String), +} + +#[test] +fn test_flat_schema() -> TestResult { + test_default_generated_schema::("enum_flatten") +} + +#[allow(dead_code)] +#[derive(JsonSchema)] +#[schemars(deny_unknown_fields)] +struct FlatDenyUnknownFields { + f: f32, + #[schemars(flatten)] + e1: Enum1, + #[schemars(flatten)] + e2: Enum2, + #[schemars(flatten)] + e3: Enum3, + #[schemars(flatten)] + e4: Enum4, + #[schemars(flatten)] + e5: Enum5, +} + +#[test] +fn test_flat_schema_duf() -> TestResult { + test_default_generated_schema::("enum_flatten_duf") +} + +#[test] +fn test_flat_schema_duf_draft07() -> TestResult { + test_generated_schema::( + "enum_flatten_duf_draft07", + SchemaSettings::draft07(), + ) +} diff --git a/schemars/tests/enum_repr.rs b/schemars/tests/enum_repr.rs new file mode 100644 index 0000000..d318347 --- /dev/null +++ b/schemars/tests/enum_repr.rs @@ -0,0 +1,35 @@ +mod util; +use schemars::JsonSchema_repr; +use util::*; + +#[derive(JsonSchema_repr)] +#[repr(u8)] +pub enum Enum { + Zero, + One, + Five = 5, + Six, + Three = 3, +} + +#[test] +fn enum_repr() -> TestResult { + test_default_generated_schema::("enum-repr") +} + +#[derive(JsonSchema_repr)] +#[repr(i64)] +#[serde(rename = "Renamed")] +/// Description from comment +pub enum EnumWithAttrs { + Zero, + One, + Five = 5, + Six, + Three = 3, +} + +#[test] +fn enum_repr_with_attrs() -> TestResult { + test_default_generated_schema::("enum-repr-with-attrs") +} diff --git a/schemars/tests/enumset.rs b/schemars/tests/enumset.rs new file mode 100644 index 0000000..c04ba0e --- /dev/null +++ b/schemars/tests/enumset.rs @@ -0,0 +1,18 @@ +mod util; +use enumset1::{EnumSet, EnumSetType}; +use schemars::JsonSchema; +use util::*; + +// needed to derive EnumSetType when using a crate alias +extern crate enumset1 as enumset; + +#[derive(EnumSetType, JsonSchema)] +enum Foo { + Bar, + Baz, +} + +#[test] +fn enumset() -> TestResult { + test_default_generated_schema::>("enumset") +} diff --git a/schemars/tests/examples.rs b/schemars/tests/examples.rs new file mode 100644 index 0000000..bbe9af5 --- /dev/null +++ b/schemars/tests/examples.rs @@ -0,0 +1,25 @@ +mod util; +use schemars::JsonSchema; +use serde::Serialize; +use util::*; + +#[derive(Default, JsonSchema, Serialize)] +#[schemars(example = "Struct::default", example = "null")] +struct Struct { + #[schemars(example = "eight", example = "null")] + foo: i32, + bar: bool, + #[schemars(example = "null")] + baz: Option<&'static str>, +} + +fn eight() -> i32 { + 8 +} + +fn null() {} + +#[test] +fn examples() -> TestResult { + test_default_generated_schema::("examples") +} diff --git a/schemars/tests/integration/snapshots/schemars/tests/integration/arrayvec.rs~arrayvec07.json b/schemars/tests/expected/arrayvec.json similarity index 70% rename from schemars/tests/integration/snapshots/schemars/tests/integration/arrayvec.rs~arrayvec07.json rename to schemars/tests/expected/arrayvec.json index df98947..998d087 100644 --- a/schemars/tests/integration/snapshots/schemars/tests/integration/arrayvec.rs~arrayvec07.json +++ b/schemars/tests/expected/arrayvec.json @@ -1,10 +1,10 @@ { "$schema": "https://json-schema.org/draft/2020-12/schema", - "title": "Array_up_to_size_8_of_int32", + "title": "Array_up_to_size_16_of_int32", "type": "array", "items": { "type": "integer", "format": "int32" }, - "maxItems": 8 + "maxItems": 16 } \ No newline at end of file diff --git a/schemars/tests/integration/snapshots/schemars/tests/integration/structs.rs~newtype.json b/schemars/tests/expected/arrayvec_string.json similarity index 79% rename from schemars/tests/integration/snapshots/schemars/tests/integration/structs.rs~newtype.json rename to schemars/tests/expected/arrayvec_string.json index 3c5dfcb..0604332 100644 --- a/schemars/tests/integration/snapshots/schemars/tests/integration/structs.rs~newtype.json +++ b/schemars/tests/expected/arrayvec_string.json @@ -1,5 +1,5 @@ { "$schema": "https://json-schema.org/draft/2020-12/schema", - "title": "NewType", + "title": "string", "type": "string" } \ No newline at end of file diff --git a/schemars/tests/integration/snapshots/schemars/tests/integration/decimal.rs~decimal_types.de.json b/schemars/tests/expected/bigdecimal04.json similarity index 100% rename from schemars/tests/integration/snapshots/schemars/tests/integration/decimal.rs~decimal_types.de.json rename to schemars/tests/expected/bigdecimal04.json diff --git a/schemars/tests/integration/snapshots/schemars/tests/integration/bound.rs~manual_bound_set.json b/schemars/tests/expected/bound.json similarity index 100% rename from schemars/tests/integration/snapshots/schemars/tests/integration/bound.rs~manual_bound_set.json rename to schemars/tests/expected/bound.json diff --git a/schemars/tests/expected/bytes.json b/schemars/tests/expected/bytes.json new file mode 100644 index 0000000..80486c1 --- /dev/null +++ b/schemars/tests/expected/bytes.json @@ -0,0 +1,25 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "title": "Tuple_of_Array_of_uint8_and_Array_of_uint8", + "type": "array", + "prefixItems": [ + { + "type": "array", + "items": { + "type": "integer", + "format": "uint8", + "minimum": 0 + } + }, + { + "type": "array", + "items": { + "type": "integer", + "format": "uint8", + "minimum": 0 + } + } + ], + "minItems": 2, + "maxItems": 2 +} \ No newline at end of file diff --git a/schemars/tests/integration/snapshots/schemars/tests/integration/chrono.rs~chrono.json b/schemars/tests/expected/chrono-types.json similarity index 95% rename from schemars/tests/integration/snapshots/schemars/tests/integration/chrono.rs~chrono.json rename to schemars/tests/expected/chrono-types.json index b2477c2..de26130 100644 --- a/schemars/tests/integration/snapshots/schemars/tests/integration/chrono.rs~chrono.json +++ b/schemars/tests/expected/chrono-types.json @@ -29,7 +29,7 @@ }, "naive_time": { "type": "string", - "format": "partial-time" + "format": "partial-date-time" } }, "required": [ diff --git a/schemars/tests/integration/snapshots/schemars/tests/integration/contract.rs~struct_allow_unknown_fields.de.json b/schemars/tests/expected/contract_deserialize.json similarity index 93% rename from schemars/tests/integration/snapshots/schemars/tests/integration/contract.rs~struct_allow_unknown_fields.de.json rename to schemars/tests/expected/contract_deserialize.json index 6281568..6b24d01 100644 --- a/schemars/tests/integration/snapshots/schemars/tests/integration/contract.rs~struct_allow_unknown_fields.de.json +++ b/schemars/tests/expected/contract_deserialize.json @@ -1,6 +1,6 @@ { "$schema": "https://json-schema.org/draft/2020-12/schema", - "title": "StructAllowUnknownFields", + "title": "MyStruct", "type": "object", "properties": { "write_only": { diff --git a/schemars/tests/integration/snapshots/schemars/tests/integration/contract.rs~adjacently_tagged_enum.de.json b/schemars/tests/expected/contract_deserialize_adjacent_tag_enum.json similarity index 100% rename from schemars/tests/integration/snapshots/schemars/tests/integration/contract.rs~adjacently_tagged_enum.de.json rename to schemars/tests/expected/contract_deserialize_adjacent_tag_enum.json diff --git a/schemars/tests/integration/snapshots/schemars/tests/integration/contract.rs~externally_tagged_enum.de.json b/schemars/tests/expected/contract_deserialize_external_tag_enum.json similarity index 100% rename from schemars/tests/integration/snapshots/schemars/tests/integration/contract.rs~externally_tagged_enum.de.json rename to schemars/tests/expected/contract_deserialize_external_tag_enum.json diff --git a/schemars/tests/integration/snapshots/schemars/tests/integration/contract.rs~internally_tagged_enum.de.json b/schemars/tests/expected/contract_deserialize_internal_tag_enum.json similarity index 100% rename from schemars/tests/integration/snapshots/schemars/tests/integration/contract.rs~internally_tagged_enum.de.json rename to schemars/tests/expected/contract_deserialize_internal_tag_enum.json diff --git a/schemars/tests/integration/snapshots/schemars/tests/integration/contract.rs~tuple_struct.de.json b/schemars/tests/expected/contract_deserialize_tuple_struct.json similarity index 100% rename from schemars/tests/integration/snapshots/schemars/tests/integration/contract.rs~tuple_struct.de.json rename to schemars/tests/expected/contract_deserialize_tuple_struct.json diff --git a/schemars/tests/integration/snapshots/schemars/tests/integration/contract.rs~untagged_enum.de.json b/schemars/tests/expected/contract_deserialize_untagged_enum.json similarity index 100% rename from schemars/tests/integration/snapshots/schemars/tests/integration/contract.rs~untagged_enum.de.json rename to schemars/tests/expected/contract_deserialize_untagged_enum.json diff --git a/schemars/tests/integration/snapshots/schemars/tests/integration/contract.rs~struct_allow_unknown_fields.ser.json b/schemars/tests/expected/contract_serialize.json similarity index 93% rename from schemars/tests/integration/snapshots/schemars/tests/integration/contract.rs~struct_allow_unknown_fields.ser.json rename to schemars/tests/expected/contract_serialize.json index c405275..b82231f 100644 --- a/schemars/tests/integration/snapshots/schemars/tests/integration/contract.rs~struct_allow_unknown_fields.ser.json +++ b/schemars/tests/expected/contract_serialize.json @@ -1,6 +1,6 @@ { "$schema": "https://json-schema.org/draft/2020-12/schema", - "title": "StructAllowUnknownFields", + "title": "MyStruct", "type": "object", "properties": { "READ-ONLY": { diff --git a/schemars/tests/integration/snapshots/schemars/tests/integration/contract.rs~adjacently_tagged_enum.ser.json b/schemars/tests/expected/contract_serialize_adjacent_tag_enum.json similarity index 100% rename from schemars/tests/integration/snapshots/schemars/tests/integration/contract.rs~adjacently_tagged_enum.ser.json rename to schemars/tests/expected/contract_serialize_adjacent_tag_enum.json diff --git a/schemars/tests/integration/snapshots/schemars/tests/integration/contract.rs~externally_tagged_enum.ser.json b/schemars/tests/expected/contract_serialize_external_tag_enum.json similarity index 100% rename from schemars/tests/integration/snapshots/schemars/tests/integration/contract.rs~externally_tagged_enum.ser.json rename to schemars/tests/expected/contract_serialize_external_tag_enum.json diff --git a/schemars/tests/integration/snapshots/schemars/tests/integration/contract.rs~internally_tagged_enum.ser.json b/schemars/tests/expected/contract_serialize_internal_tag_enum.json similarity index 100% rename from schemars/tests/integration/snapshots/schemars/tests/integration/contract.rs~internally_tagged_enum.ser.json rename to schemars/tests/expected/contract_serialize_internal_tag_enum.json diff --git a/schemars/tests/integration/snapshots/schemars/tests/integration/contract.rs~tuple_struct.ser.json b/schemars/tests/expected/contract_serialize_tuple_struct.json similarity index 100% rename from schemars/tests/integration/snapshots/schemars/tests/integration/contract.rs~tuple_struct.ser.json rename to schemars/tests/expected/contract_serialize_tuple_struct.json diff --git a/schemars/tests/integration/snapshots/schemars/tests/integration/contract.rs~untagged_enum.ser.json b/schemars/tests/expected/contract_serialize_untagged_enum.json similarity index 100% rename from schemars/tests/integration/snapshots/schemars/tests/integration/contract.rs~untagged_enum.ser.json rename to schemars/tests/expected/contract_serialize_untagged_enum.json diff --git a/schemars/tests/integration/snapshots/schemars/tests/integration/structs.rs~normal.json b/schemars/tests/expected/crate_alias.json similarity index 65% rename from schemars/tests/integration/snapshots/schemars/tests/integration/structs.rs~normal.json rename to schemars/tests/expected/crate_alias.json index 961fc9a..c2f1430 100644 --- a/schemars/tests/integration/snapshots/schemars/tests/integration/structs.rs~normal.json +++ b/schemars/tests/expected/crate_alias.json @@ -1,10 +1,12 @@ { "$schema": "https://json-schema.org/draft/2020-12/schema", - "title": "NormalStruct", + "title": "Struct", "type": "object", "properties": { "foo": { - "type": "string" + "description": "This is a document", + "type": "integer", + "format": "int32" }, "bar": { "type": "boolean" diff --git a/schemars/tests/expected/default.json b/schemars/tests/expected/default.json new file mode 100644 index 0000000..72e580d --- /dev/null +++ b/schemars/tests/expected/default.json @@ -0,0 +1,52 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "title": "MyStruct", + "type": "object", + "properties": { + "my_int": { + "type": "integer", + "format": "int32", + "default": 0 + }, + "my_bool": { + "type": "boolean", + "default": false + }, + "my_optional_string": { + "type": [ + "string", + "null" + ], + "default": null + }, + "my_struct2": { + "$ref": "#/$defs/MyStruct2", + "default": "i:0 b:false" + }, + "my_struct2_default_skipped": { + "$ref": "#/$defs/MyStruct2" + }, + "not_serialize": { + "$ref": "#/$defs/NotSerialize" + } + }, + "$defs": { + "MyStruct2": { + "type": "object", + "properties": { + "my_int": { + "type": "integer", + "format": "int32", + "default": 6 + }, + "my_bool": { + "type": "boolean", + "default": true + } + } + }, + "NotSerialize": { + "type": "null" + } + } +} \ No newline at end of file diff --git a/schemars/tests/integration/snapshots/schemars/tests/integration/deprecated.rs~deprecated_enum.json b/schemars/tests/expected/deprecated-enum.json similarity index 100% rename from schemars/tests/integration/snapshots/schemars/tests/integration/deprecated.rs~deprecated_enum.json rename to schemars/tests/expected/deprecated-enum.json diff --git a/schemars/tests/integration/snapshots/schemars/tests/integration/deprecated.rs~deprecated_struct.json b/schemars/tests/expected/deprecated-struct.json similarity index 86% rename from schemars/tests/integration/snapshots/schemars/tests/integration/deprecated.rs~deprecated_struct.json rename to schemars/tests/expected/deprecated-struct.json index 55967e5..b7396ab 100644 --- a/schemars/tests/integration/snapshots/schemars/tests/integration/deprecated.rs~deprecated_struct.json +++ b/schemars/tests/expected/deprecated-struct.json @@ -7,14 +7,14 @@ "type": "integer", "format": "int32" }, - "bar": { + "deprecated_field": { "type": "boolean", "deprecated": true } }, "required": [ "foo", - "bar" + "deprecated_field" ], "deprecated": true } \ No newline at end of file diff --git a/schemars/tests/integration/snapshots/schemars/tests/integration/docs.rs~doc_comments_enum.de.json b/schemars/tests/expected/doc_comments_enum.json similarity index 100% rename from schemars/tests/integration/snapshots/schemars/tests/integration/docs.rs~doc_comments_enum.de.json rename to schemars/tests/expected/doc_comments_enum.json diff --git a/schemars/tests/integration/snapshots/schemars/tests/integration/docs.rs~doc_comments_override.json b/schemars/tests/expected/doc_comments_override.json similarity index 100% rename from schemars/tests/integration/snapshots/schemars/tests/integration/docs.rs~doc_comments_override.json rename to schemars/tests/expected/doc_comments_override.json diff --git a/schemars/tests/integration/snapshots/schemars/tests/integration/docs.rs~doc_comments_struct.json b/schemars/tests/expected/doc_comments_struct.json similarity index 100% rename from schemars/tests/integration/snapshots/schemars/tests/integration/docs.rs~doc_comments_struct.json rename to schemars/tests/expected/doc_comments_struct.json diff --git a/schemars/tests/expected/duration_and_systemtime.json b/schemars/tests/expected/duration_and_systemtime.json new file mode 100644 index 0000000..7e301e5 --- /dev/null +++ b/schemars/tests/expected/duration_and_systemtime.json @@ -0,0 +1,57 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "title": "MyStruct", + "type": "object", + "properties": { + "duration": { + "$ref": "#/$defs/Duration" + }, + "time": { + "$ref": "#/$defs/SystemTime" + } + }, + "required": [ + "duration", + "time" + ], + "$defs": { + "Duration": { + "type": "object", + "properties": { + "secs": { + "type": "integer", + "format": "uint64", + "minimum": 0 + }, + "nanos": { + "type": "integer", + "format": "uint32", + "minimum": 0 + } + }, + "required": [ + "secs", + "nanos" + ] + }, + "SystemTime": { + "type": "object", + "properties": { + "secs_since_epoch": { + "type": "integer", + "format": "uint64", + "minimum": 0 + }, + "nanos_since_epoch": { + "type": "integer", + "format": "uint32", + "minimum": 0 + } + }, + "required": [ + "secs_since_epoch", + "nanos_since_epoch" + ] + } + } +} \ No newline at end of file diff --git a/schemars/tests/expected/either.json b/schemars/tests/expected/either.json new file mode 100644 index 0000000..18d8f51 --- /dev/null +++ b/schemars/tests/expected/either.json @@ -0,0 +1,20 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "title": "Either_int32_or_Either_boolean_or_null", + "anyOf": [ + { + "type": "integer", + "format": "int32" + }, + { + "anyOf": [ + { + "type": "boolean" + }, + { + "type": "null" + } + ] + } + ] +} \ No newline at end of file diff --git a/schemars/tests/integration/snapshots/schemars/tests/integration/enums_deny_unknown_fields.rs~adjacently_tagged_enum.json b/schemars/tests/expected/enum-adjacent-tagged-duf.json similarity index 60% rename from schemars/tests/integration/snapshots/schemars/tests/integration/enums_deny_unknown_fields.rs~adjacently_tagged_enum.json rename to schemars/tests/expected/enum-adjacent-tagged-duf.json index 9c4b6d9..b181f55 100644 --- a/schemars/tests/integration/snapshots/schemars/tests/integration/enums_deny_unknown_fields.rs~adjacently_tagged_enum.json +++ b/schemars/tests/expected/enum-adjacent-tagged-duf.json @@ -5,24 +5,24 @@ { "type": "object", "properties": { - "tag": { + "t": { "type": "string", - "const": "Unit" + "const": "UnitOne" } }, "required": [ - "tag" + "t" ], "additionalProperties": false }, { "type": "object", "properties": { - "tag": { + "t": { "type": "string", "const": "StringMap" }, - "content": { + "c": { "type": "object", "additionalProperties": { "type": "string" @@ -30,53 +30,53 @@ } }, "required": [ - "tag", - "content" + "t", + "c" ], "additionalProperties": false }, { "type": "object", "properties": { - "tag": { + "t": { + "type": "string", + "const": "UnitStructNewType" + }, + "c": { + "$ref": "#/$defs/UnitStruct" + } + }, + "required": [ + "t", + "c" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "t": { "type": "string", "const": "StructNewType" }, - "content": { + "c": { "$ref": "#/$defs/Struct" } }, "required": [ - "tag", - "content" + "t", + "c" ], "additionalProperties": false }, { "type": "object", "properties": { - "tag": { - "type": "string", - "const": "StructDenyUnknownFieldsNewType" - }, - "content": { - "$ref": "#/$defs/StructDenyUnknownFields" - } - }, - "required": [ - "tag", - "content" - ], - "additionalProperties": false - }, - { - "type": "object", - "properties": { - "tag": { + "t": { "type": "string", "const": "Struct" }, - "content": { + "c": { "type": "object", "properties": { "foo": { @@ -95,13 +95,75 @@ } }, "required": [ - "tag", - "content" + "t", + "c" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "t": { + "type": "string", + "const": "Tuple" + }, + "c": { + "type": "array", + "prefixItems": [ + { + "type": "integer", + "format": "int32" + }, + { + "type": "boolean" + } + ], + "minItems": 2, + "maxItems": 2 + } + }, + "required": [ + "t", + "c" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "t": { + "type": "string", + "const": "UnitTwo" + } + }, + "required": [ + "t" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "t": { + "type": "string", + "const": "WithInt" + }, + "c": { + "type": "integer", + "format": "int32" + } + }, + "required": [ + "t", + "c" ], "additionalProperties": false } ], "$defs": { + "UnitStruct": { + "type": "null" + }, "Struct": { "type": "object", "properties": { @@ -117,23 +179,6 @@ "foo", "bar" ] - }, - "StructDenyUnknownFields": { - "type": "object", - "properties": { - "baz": { - "type": "integer", - "format": "int32" - }, - "foobar": { - "type": "boolean" - } - }, - "additionalProperties": false, - "required": [ - "baz", - "foobar" - ] } } } \ No newline at end of file diff --git a/schemars/tests/integration/snapshots/schemars/tests/integration/enums.rs~adjacently_tagged_enum.json b/schemars/tests/expected/enum-adjacent-tagged.json similarity index 74% rename from schemars/tests/integration/snapshots/schemars/tests/integration/enums.rs~adjacently_tagged_enum.json rename to schemars/tests/expected/enum-adjacent-tagged.json index e75faf2..7599fd1 100644 --- a/schemars/tests/integration/snapshots/schemars/tests/integration/enums.rs~adjacently_tagged_enum.json +++ b/schemars/tests/expected/enum-adjacent-tagged.json @@ -5,23 +5,23 @@ { "type": "object", "properties": { - "tag": { + "t": { "type": "string", "const": "UnitOne" } }, "required": [ - "tag" + "t" ] }, { "type": "object", "properties": { - "tag": { + "t": { "type": "string", "const": "StringMap" }, - "content": { + "c": { "type": "object", "additionalProperties": { "type": "string" @@ -29,50 +29,50 @@ } }, "required": [ - "tag", - "content" + "t", + "c" ] }, { "type": "object", "properties": { - "tag": { + "t": { "type": "string", "const": "UnitStructNewType" }, - "content": { + "c": { "$ref": "#/$defs/UnitStruct" } }, "required": [ - "tag", - "content" + "t", + "c" ] }, { "type": "object", "properties": { - "tag": { + "t": { "type": "string", "const": "StructNewType" }, - "content": { + "c": { "$ref": "#/$defs/Struct" } }, "required": [ - "tag", - "content" + "t", + "c" ] }, { "type": "object", "properties": { - "tag": { + "t": { "type": "string", "const": "Struct" }, - "content": { + "c": { "type": "object", "properties": { "foo": { @@ -90,18 +90,18 @@ } }, "required": [ - "tag", - "content" + "t", + "c" ] }, { "type": "object", "properties": { - "tag": { + "t": { "type": "string", "const": "Tuple" }, - "content": { + "c": { "type": "array", "prefixItems": [ { @@ -117,55 +117,37 @@ } }, "required": [ - "tag", - "content" + "t", + "c" ] }, { "type": "object", "properties": { - "tag": { + "t": { "type": "string", "const": "UnitTwo" } }, "required": [ - "tag" + "t" ] }, { "type": "object", "properties": { - "tag": { + "t": { "type": "string", - "const": "UnitAsInt" + "const": "WithInt" }, - "content": { + "c": { "type": "integer", - "format": "uint64", - "minimum": 0 + "format": "int32" } }, "required": [ - "tag", - "content" - ] - }, - { - "type": "object", - "properties": { - "tag": { - "type": "string", - "const": "TupleAsStr" - }, - "content": { - "type": "string", - "pattern": "^\\d+ (true|false)$" - } - }, - "required": [ - "tag", - "content" + "t", + "c" ] } ], diff --git a/schemars/tests/integration/snapshots/schemars/tests/integration/enums.rs~externally_tagged_enum.json b/schemars/tests/expected/enum-external-duf.json similarity index 87% rename from schemars/tests/integration/snapshots/schemars/tests/integration/enums.rs~externally_tagged_enum.json rename to schemars/tests/expected/enum-external-duf.json index c5e19aa..76be5b3 100644 --- a/schemars/tests/integration/snapshots/schemars/tests/integration/enums.rs~externally_tagged_enum.json +++ b/schemars/tests/expected/enum-external-duf.json @@ -62,6 +62,7 @@ "type": "boolean" } }, + "additionalProperties": false, "required": [ "foo", "bar" @@ -99,27 +100,13 @@ { "type": "object", "properties": { - "unitAsInt": { + "withInt": { "type": "integer", - "format": "uint64", - "minimum": 0 + "format": "int32" } }, "required": [ - "unitAsInt" - ], - "additionalProperties": false - }, - { - "type": "object", - "properties": { - "tupleAsStr": { - "type": "string", - "pattern": "^\\d+ (true|false)$" - } - }, - "required": [ - "tupleAsStr" + "withInt" ], "additionalProperties": false } diff --git a/schemars/tests/integration/snapshots/schemars/tests/integration/enums_deny_unknown_fields.rs~externally_tagged_enum.json b/schemars/tests/expected/enum-external.json similarity index 65% rename from schemars/tests/integration/snapshots/schemars/tests/integration/enums_deny_unknown_fields.rs~externally_tagged_enum.json rename to schemars/tests/expected/enum-external.json index 911428b..3c660fb 100644 --- a/schemars/tests/integration/snapshots/schemars/tests/integration/enums_deny_unknown_fields.rs~externally_tagged_enum.json +++ b/schemars/tests/expected/enum-external.json @@ -5,13 +5,14 @@ { "type": "string", "enum": [ - "Unit" + "unitOne", + "unitTwo" ] }, { "type": "object", "properties": { - "StringMap": { + "stringMap": { "type": "object", "additionalProperties": { "type": "string" @@ -19,38 +20,38 @@ } }, "required": [ - "StringMap" + "stringMap" ], "additionalProperties": false }, { "type": "object", "properties": { - "StructNewType": { + "unitStructNewType": { + "$ref": "#/$defs/UnitStruct" + } + }, + "required": [ + "unitStructNewType" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "structNewType": { "$ref": "#/$defs/Struct" } }, "required": [ - "StructNewType" + "structNewType" ], "additionalProperties": false }, { "type": "object", "properties": { - "StructDenyUnknownFieldsNewType": { - "$ref": "#/$defs/StructDenyUnknownFields" - } - }, - "required": [ - "StructDenyUnknownFieldsNewType" - ], - "additionalProperties": false - }, - { - "type": "object", - "properties": { - "Struct": { + "struct": { "type": "object", "properties": { "foo": { @@ -61,7 +62,6 @@ "type": "boolean" } }, - "additionalProperties": false, "required": [ "foo", "bar" @@ -69,12 +69,51 @@ } }, "required": [ - "Struct" + "struct" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "tuple": { + "type": "array", + "prefixItems": [ + { + "type": "integer", + "format": "int32" + }, + { + "type": "boolean" + } + ], + "minItems": 2, + "maxItems": 2 + } + }, + "required": [ + "tuple" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "withInt": { + "type": "integer", + "format": "int32" + } + }, + "required": [ + "withInt" ], "additionalProperties": false } ], "$defs": { + "UnitStruct": { + "type": "null" + }, "Struct": { "type": "object", "properties": { @@ -90,23 +129,6 @@ "foo", "bar" ] - }, - "StructDenyUnknownFields": { - "type": "object", - "properties": { - "baz": { - "type": "integer", - "format": "int32" - }, - "foobar": { - "type": "boolean" - } - }, - "additionalProperties": false, - "required": [ - "baz", - "foobar" - ] } } } \ No newline at end of file diff --git a/schemars/tests/integration/snapshots/schemars/tests/integration/enums_deny_unknown_fields.rs~internally_tagged_enum.json b/schemars/tests/expected/enum-internal-duf.json similarity index 65% rename from schemars/tests/integration/snapshots/schemars/tests/integration/enums_deny_unknown_fields.rs~internally_tagged_enum.json rename to schemars/tests/expected/enum-internal-duf.json index ab5e53a..73e4743 100644 --- a/schemars/tests/integration/snapshots/schemars/tests/integration/enums_deny_unknown_fields.rs~internally_tagged_enum.json +++ b/schemars/tests/expected/enum-internal-duf.json @@ -5,20 +5,20 @@ { "type": "object", "properties": { - "tag": { + "typeProperty": { "type": "string", - "const": "Unit" + "const": "UnitOne" } }, "required": [ - "tag" + "typeProperty" ], "additionalProperties": false }, { "type": "object", "properties": { - "tag": { + "typeProperty": { "type": "string", "const": "StringMap" } @@ -27,42 +27,41 @@ "type": "string" }, "required": [ - "tag" + "typeProperty" ] }, { "type": "object", "properties": { - "tag": { + "typeProperty": { + "type": "string", + "const": "UnitStructNewType" + } + }, + "required": [ + "typeProperty" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "foo": { + "type": "integer", + "format": "int32" + }, + "bar": { + "type": "boolean" + }, + "typeProperty": { "type": "string", "const": "StructNewType" } }, - "$ref": "#/$defs/Struct", "required": [ - "tag" - ] - }, - { - "type": "object", - "properties": { - "baz": { - "type": "integer", - "format": "int32" - }, - "foobar": { - "type": "boolean" - }, - "tag": { - "type": "string", - "const": "StructDenyUnknownFieldsNewType" - } - }, - "additionalProperties": false, - "required": [ - "tag", - "baz", - "foobar" + "typeProperty", + "foo", + "bar" ] }, { @@ -75,35 +74,43 @@ "bar": { "type": "boolean" }, - "tag": { + "typeProperty": { "type": "string", "const": "Struct" } }, "additionalProperties": false, "required": [ - "tag", + "typeProperty", "foo", "bar" ] - } - ], - "$defs": { - "Struct": { + }, + { "type": "object", "properties": { - "foo": { - "type": "integer", - "format": "int32" - }, - "bar": { - "type": "boolean" + "typeProperty": { + "type": "string", + "const": "UnitTwo" } }, "required": [ - "foo", - "bar" + "typeProperty" + ], + "additionalProperties": false + }, + { + "type": "object", + "format": "int32", + "properties": { + "typeProperty": { + "type": "string", + "const": "WithInt" + } + }, + "required": [ + "typeProperty" ] } - } + ] } \ No newline at end of file diff --git a/schemars/tests/integration/snapshots/schemars/tests/integration/enums.rs~internally_tagged_enum.json b/schemars/tests/expected/enum-internal.json similarity index 77% rename from schemars/tests/integration/snapshots/schemars/tests/integration/enums.rs~internally_tagged_enum.json rename to schemars/tests/expected/enum-internal.json index 219be7a..2fd9770 100644 --- a/schemars/tests/integration/snapshots/schemars/tests/integration/enums.rs~internally_tagged_enum.json +++ b/schemars/tests/expected/enum-internal.json @@ -5,19 +5,19 @@ { "type": "object", "properties": { - "tag": { + "typeProperty": { "type": "string", "const": "UnitOne" } }, "required": [ - "tag" + "typeProperty" ] }, { "type": "object", "properties": { - "tag": { + "typeProperty": { "type": "string", "const": "StringMap" } @@ -26,32 +26,19 @@ "type": "string" }, "required": [ - "tag" + "typeProperty" ] }, { "type": "object", "properties": { - "tag": { + "typeProperty": { "type": "string", "const": "UnitStructNewType" } }, "required": [ - "tag" - ] - }, - { - "type": "object", - "properties": { - "tag": { - "type": "string", - "const": "StructNewType" - } - }, - "$ref": "#/$defs/Struct", - "required": [ - "tag" + "typeProperty" ] }, { @@ -64,13 +51,34 @@ "bar": { "type": "boolean" }, - "tag": { + "typeProperty": { + "type": "string", + "const": "StructNewType" + } + }, + "required": [ + "typeProperty", + "foo", + "bar" + ] + }, + { + "type": "object", + "properties": { + "foo": { + "type": "integer", + "format": "int32" + }, + "bar": { + "type": "boolean" + }, + "typeProperty": { "type": "string", "const": "Struct" } }, "required": [ - "tag", + "typeProperty", "foo", "bar" ] @@ -78,32 +86,27 @@ { "type": "object", "properties": { - "tag": { + "typeProperty": { "type": "string", "const": "UnitTwo" } }, "required": [ - "tag" + "typeProperty" ] - } - ], - "$defs": { - "Struct": { + }, + { "type": "object", + "format": "int32", "properties": { - "foo": { - "type": "integer", - "format": "int32" - }, - "bar": { - "type": "boolean" + "typeProperty": { + "type": "string", + "const": "WithInt" } }, "required": [ - "foo", - "bar" + "typeProperty" ] } - } + ] } \ No newline at end of file diff --git a/schemars/tests/expected/enum-rename-all-fields.json b/schemars/tests/expected/enum-rename-all-fields.json new file mode 100644 index 0000000..422a694 --- /dev/null +++ b/schemars/tests/expected/enum-rename-all-fields.json @@ -0,0 +1,26 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "title": "RenameAllFields", + "oneOf": [ + { + "type": "object", + "properties": { + "First": { + "type": "object", + "properties": { + "NestedAttribute": { + "type": "string" + } + }, + "required": [ + "NestedAttribute" + ] + } + }, + "required": [ + "First" + ], + "additionalProperties": false + } + ] +} \ No newline at end of file diff --git a/schemars/tests/expected/enum-rename-all.json b/schemars/tests/expected/enum-rename-all.json new file mode 100644 index 0000000..eb237be --- /dev/null +++ b/schemars/tests/expected/enum-rename-all.json @@ -0,0 +1,26 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "title": "RenameAll", + "oneOf": [ + { + "type": "object", + "properties": { + "first": { + "type": "object", + "properties": { + "nested_attribute": { + "type": "boolean" + } + }, + "required": [ + "nested_attribute" + ] + } + }, + "required": [ + "first" + ], + "additionalProperties": false + } + ] +} \ No newline at end of file diff --git a/schemars/tests/expected/enum-rename-attr.json b/schemars/tests/expected/enum-rename-attr.json new file mode 100644 index 0000000..a9f3706 --- /dev/null +++ b/schemars/tests/expected/enum-rename-attr.json @@ -0,0 +1,26 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "title": "RenameAttribute", + "oneOf": [ + { + "type": "object", + "properties": { + "First": { + "type": "object", + "properties": { + "RenamedAttribute": { + "type": "string" + } + }, + "required": [ + "RenamedAttribute" + ] + } + }, + "required": [ + "First" + ], + "additionalProperties": false + } + ] +} \ No newline at end of file diff --git a/schemars/tests/integration/snapshots/schemars/tests/integration/enum_repr.rs~enum_repr.json b/schemars/tests/expected/enum-repr-with-attrs.json similarity index 85% rename from schemars/tests/integration/snapshots/schemars/tests/integration/enum_repr.rs~enum_repr.json rename to schemars/tests/expected/enum-repr-with-attrs.json index 964952a..89d941b 100644 --- a/schemars/tests/integration/snapshots/schemars/tests/integration/enum_repr.rs~enum_repr.json +++ b/schemars/tests/expected/enum-repr-with-attrs.json @@ -1,6 +1,6 @@ { "$schema": "https://json-schema.org/draft/2020-12/schema", - "title": "EnumWithReprAttr", + "title": "Renamed", "description": "Description from comment", "type": "integer", "enum": [ diff --git a/schemars/tests/integration/snapshots/schemars/tests/integration/skip.rs~skip_enum_variants.json b/schemars/tests/expected/enum-repr.json similarity index 64% rename from schemars/tests/integration/snapshots/schemars/tests/integration/skip.rs~skip_enum_variants.json rename to schemars/tests/expected/enum-repr.json index a24653a..b3e6bb9 100644 --- a/schemars/tests/integration/snapshots/schemars/tests/integration/skip.rs~skip_enum_variants.json +++ b/schemars/tests/expected/enum-repr.json @@ -1,9 +1,12 @@ { "$schema": "https://json-schema.org/draft/2020-12/schema", "title": "Enum", - "type": "string", + "type": "integer", "enum": [ - "Included1", - "Included2" + 0, + 1, + 5, + 6, + 3 ] } \ No newline at end of file diff --git a/schemars/tests/expected/enum-simple-internal-duf.json b/schemars/tests/expected/enum-simple-internal-duf.json new file mode 100644 index 0000000..aaf1eef --- /dev/null +++ b/schemars/tests/expected/enum-simple-internal-duf.json @@ -0,0 +1,45 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "title": "SimpleInternal", + "oneOf": [ + { + "type": "object", + "properties": { + "typeProperty": { + "type": "string", + "const": "A" + } + }, + "required": [ + "typeProperty" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "typeProperty": { + "type": "string", + "const": "B" + } + }, + "required": [ + "typeProperty" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "typeProperty": { + "type": "string", + "const": "C" + } + }, + "required": [ + "typeProperty" + ], + "additionalProperties": false + } + ] +} \ No newline at end of file diff --git a/schemars/tests/expected/enum-simple-internal.json b/schemars/tests/expected/enum-simple-internal.json new file mode 100644 index 0000000..e955d2a --- /dev/null +++ b/schemars/tests/expected/enum-simple-internal.json @@ -0,0 +1,42 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "title": "SimpleInternal", + "oneOf": [ + { + "type": "object", + "properties": { + "typeProperty": { + "type": "string", + "const": "A" + } + }, + "required": [ + "typeProperty" + ] + }, + { + "type": "object", + "properties": { + "typeProperty": { + "type": "string", + "const": "B" + } + }, + "required": [ + "typeProperty" + ] + }, + { + "type": "object", + "properties": { + "typeProperty": { + "type": "string", + "const": "C" + } + }, + "required": [ + "typeProperty" + ] + } + ] +} \ No newline at end of file diff --git a/schemars/tests/integration/snapshots/schemars/tests/integration/enums.rs~unit_variants_with_doc_comments.json b/schemars/tests/expected/enum-unit-doc.json similarity index 100% rename from schemars/tests/integration/snapshots/schemars/tests/integration/enums.rs~unit_variants_with_doc_comments.json rename to schemars/tests/expected/enum-unit-doc.json diff --git a/schemars/tests/integration/snapshots/schemars/tests/integration/enums.rs~untagged_enum.json b/schemars/tests/expected/enum-untagged-duf.json similarity index 88% rename from schemars/tests/integration/snapshots/schemars/tests/integration/enums.rs~untagged_enum.json rename to schemars/tests/expected/enum-untagged-duf.json index e744d55..58bdbe1 100644 --- a/schemars/tests/integration/snapshots/schemars/tests/integration/enums.rs~untagged_enum.json +++ b/schemars/tests/expected/enum-untagged-duf.json @@ -28,6 +28,7 @@ "type": "boolean" } }, + "additionalProperties": false, "required": [ "foo", "bar" @@ -47,17 +48,9 @@ "minItems": 2, "maxItems": 2 }, - { - "type": "null" - }, { "type": "integer", - "format": "uint64", - "minimum": 0 - }, - { - "type": "string", - "pattern": "^\\d+ (true|false)$" + "format": "int32" } ], "$defs": { diff --git a/schemars/tests/integration/snapshots/schemars/tests/integration/enums_deny_unknown_fields.rs~untagged_enum.json b/schemars/tests/expected/enum-untagged.json similarity index 75% rename from schemars/tests/integration/snapshots/schemars/tests/integration/enums_deny_unknown_fields.rs~untagged_enum.json rename to schemars/tests/expected/enum-untagged.json index 1e6a367..643cd20 100644 --- a/schemars/tests/integration/snapshots/schemars/tests/integration/enums_deny_unknown_fields.rs~untagged_enum.json +++ b/schemars/tests/expected/enum-untagged.json @@ -12,10 +12,10 @@ } }, { - "$ref": "#/$defs/Struct" + "$ref": "#/$defs/UnitStruct" }, { - "$ref": "#/$defs/StructDenyUnknownFields" + "$ref": "#/$defs/Struct" }, { "type": "object", @@ -28,14 +28,34 @@ "type": "boolean" } }, - "additionalProperties": false, "required": [ "foo", "bar" ] + }, + { + "type": "array", + "prefixItems": [ + { + "type": "integer", + "format": "int32" + }, + { + "type": "boolean" + } + ], + "minItems": 2, + "maxItems": 2 + }, + { + "type": "integer", + "format": "int32" } ], "$defs": { + "UnitStruct": { + "type": "null" + }, "Struct": { "type": "object", "properties": { @@ -51,23 +71,6 @@ "foo", "bar" ] - }, - "StructDenyUnknownFields": { - "type": "object", - "properties": { - "baz": { - "type": "integer", - "format": "int32" - }, - "foobar": { - "type": "boolean" - } - }, - "additionalProperties": false, - "required": [ - "baz", - "foobar" - ] } } } \ No newline at end of file diff --git a/schemars/tests/integration/snapshots/schemars/tests/integration/enums_flattened.rs~enums_flattened.json b/schemars/tests/expected/enum_flatten.json similarity index 99% rename from schemars/tests/integration/snapshots/schemars/tests/integration/enums_flattened.rs~enums_flattened.json rename to schemars/tests/expected/enum_flatten.json index 7df8b88..dffd89e 100644 --- a/schemars/tests/integration/snapshots/schemars/tests/integration/enums_flattened.rs~enums_flattened.json +++ b/schemars/tests/expected/enum_flatten.json @@ -1,6 +1,6 @@ { "$schema": "https://json-schema.org/draft/2020-12/schema", - "title": "Container", + "title": "Flat", "type": "object", "properties": { "f": { diff --git a/schemars/tests/integration/snapshots/schemars/tests/integration/enums_flattened.rs~enums_flattened_deny_unknown_fields.json b/schemars/tests/expected/enum_flatten_duf.json similarity index 98% rename from schemars/tests/integration/snapshots/schemars/tests/integration/enums_flattened.rs~enums_flattened_deny_unknown_fields.json rename to schemars/tests/expected/enum_flatten_duf.json index 2032360..37493cc 100644 --- a/schemars/tests/integration/snapshots/schemars/tests/integration/enums_flattened.rs~enums_flattened_deny_unknown_fields.json +++ b/schemars/tests/expected/enum_flatten_duf.json @@ -1,6 +1,6 @@ { "$schema": "https://json-schema.org/draft/2020-12/schema", - "title": "ContainerDenyUnknownFields", + "title": "FlatDenyUnknownFields", "type": "object", "properties": { "f": { diff --git a/schemars/tests/integration/snapshots/schemars/tests/integration/enums_flattened.rs~enums_flattened_deny_unknown_fields_draft07.json b/schemars/tests/expected/enum_flatten_duf_draft07.json similarity index 98% rename from schemars/tests/integration/snapshots/schemars/tests/integration/enums_flattened.rs~enums_flattened_deny_unknown_fields_draft07.json rename to schemars/tests/expected/enum_flatten_duf_draft07.json index 695f282..62323dd 100644 --- a/schemars/tests/integration/snapshots/schemars/tests/integration/enums_flattened.rs~enums_flattened_deny_unknown_fields_draft07.json +++ b/schemars/tests/expected/enum_flatten_duf_draft07.json @@ -1,6 +1,6 @@ { "$schema": "http://json-schema.org/draft-07/schema#", - "title": "ContainerDenyUnknownFields", + "title": "FlatDenyUnknownFields", "type": "object", "properties": { "f": { diff --git a/schemars/tests/expected/enumset.json b/schemars/tests/expected/enumset.json new file mode 100644 index 0000000..72a39a1 --- /dev/null +++ b/schemars/tests/expected/enumset.json @@ -0,0 +1,18 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "title": "Set_of_Foo", + "type": "array", + "uniqueItems": true, + "items": { + "$ref": "#/$defs/Foo" + }, + "$defs": { + "Foo": { + "type": "string", + "enum": [ + "Bar", + "Baz" + ] + } + } +} \ No newline at end of file diff --git a/schemars/tests/integration/snapshots/schemars/tests/integration/examples.rs~examples.de.json b/schemars/tests/expected/examples.json similarity index 95% rename from schemars/tests/integration/snapshots/schemars/tests/integration/examples.rs~examples.de.json rename to schemars/tests/expected/examples.json index da04166..b891aa0 100644 --- a/schemars/tests/integration/snapshots/schemars/tests/integration/examples.rs~examples.de.json +++ b/schemars/tests/expected/examples.json @@ -20,8 +20,7 @@ "null" ], "examples": [ - null, - "foo" + null ] } }, diff --git a/schemars/tests/integration/snapshots/schemars/tests/integration/extend.rs~extend_adjacently_tagged_enum.json b/schemars/tests/expected/extend_enum_adjacent.json similarity index 98% rename from schemars/tests/integration/snapshots/schemars/tests/integration/extend.rs~extend_adjacently_tagged_enum.json rename to schemars/tests/expected/extend_enum_adjacent.json index 543ff4f..4167faf 100644 --- a/schemars/tests/integration/snapshots/schemars/tests/integration/extend.rs~extend_adjacently_tagged_enum.json +++ b/schemars/tests/expected/extend_enum_adjacent.json @@ -1,6 +1,6 @@ { "$schema": "https://json-schema.org/draft/2020-12/schema", - "title": "AdjacentEnum", + "title": "Adjacent", "oneOf": [ { "type": "object", diff --git a/schemars/tests/integration/snapshots/schemars/tests/integration/extend.rs~extend_externally_tagged_enum.json b/schemars/tests/expected/extend_enum_external.json similarity index 98% rename from schemars/tests/integration/snapshots/schemars/tests/integration/extend.rs~extend_externally_tagged_enum.json rename to schemars/tests/expected/extend_enum_external.json index 9c6f37a..c15d47f 100644 --- a/schemars/tests/integration/snapshots/schemars/tests/integration/extend.rs~extend_externally_tagged_enum.json +++ b/schemars/tests/expected/extend_enum_external.json @@ -1,6 +1,6 @@ { "$schema": "https://json-schema.org/draft/2020-12/schema", - "title": "ExternalEnum", + "title": "External", "oneOf": [ { "type": "string", diff --git a/schemars/tests/integration/snapshots/schemars/tests/integration/extend.rs~extend_internally_tagged_enum.json b/schemars/tests/expected/extend_enum_internal.json similarity index 82% rename from schemars/tests/integration/snapshots/schemars/tests/integration/extend.rs~extend_internally_tagged_enum.json rename to schemars/tests/expected/extend_enum_internal.json index c0f6354..0dee817 100644 --- a/schemars/tests/integration/snapshots/schemars/tests/integration/extend.rs~extend_internally_tagged_enum.json +++ b/schemars/tests/expected/extend_enum_internal.json @@ -1,30 +1,30 @@ { "$schema": "https://json-schema.org/draft/2020-12/schema", - "title": "InternalEnum", + "title": "Internal", "oneOf": [ { "type": "object", "properties": { - "t": { + "typeProperty": { "type": "string", "const": "Unit" } }, "required": [ - "t" + "typeProperty" ], "foo": "bar" }, { "type": "object", "properties": { - "t": { + "typeProperty": { "type": "string", "const": "NewType" } }, "required": [ - "t" + "typeProperty" ], "foo": "bar" }, @@ -38,13 +38,13 @@ "b": { "type": "boolean" }, - "t": { + "typeProperty": { "type": "string", "const": "Struct" } }, "required": [ - "t", + "typeProperty", "i", "b" ], diff --git a/schemars/tests/integration/snapshots/schemars/tests/integration/extend.rs~extend_untagged_enum.json b/schemars/tests/expected/extend_enum_untagged.json similarity index 96% rename from schemars/tests/integration/snapshots/schemars/tests/integration/extend.rs~extend_untagged_enum.json rename to schemars/tests/expected/extend_enum_untagged.json index 8a0df44..4f733fe 100644 --- a/schemars/tests/integration/snapshots/schemars/tests/integration/extend.rs~extend_untagged_enum.json +++ b/schemars/tests/expected/extend_enum_untagged.json @@ -1,6 +1,6 @@ { "$schema": "https://json-schema.org/draft/2020-12/schema", - "title": "UntaggedEnum", + "title": "Untagged", "anyOf": [ { "type": "null", diff --git a/schemars/tests/integration/snapshots/schemars/tests/integration/extend.rs~extend_struct.json b/schemars/tests/expected/extend_struct.json similarity index 85% rename from schemars/tests/integration/snapshots/schemars/tests/integration/extend.rs~extend_struct.json rename to schemars/tests/expected/extend_struct.json index 8586867..fc7dd50 100644 --- a/schemars/tests/integration/snapshots/schemars/tests/integration/extend.rs~extend_struct.json +++ b/schemars/tests/expected/extend_struct.json @@ -7,10 +7,7 @@ "foo": "bar" }, "int": { - "type": [ - "number", - "string" - ], + "type": "overridden", "format": "int32" } }, @@ -18,6 +15,7 @@ "value", "int" ], + "msg": "hello world", "obj": { "array": [ null, diff --git a/schemars/tests/integration/snapshots/schemars/tests/integration/flatten.rs~flattened_struct.json b/schemars/tests/expected/flatten.json similarity index 85% rename from schemars/tests/integration/snapshots/schemars/tests/integration/flatten.rs~flattened_struct.json rename to schemars/tests/expected/flatten.json index 689d245..7dfd54e 100644 --- a/schemars/tests/integration/snapshots/schemars/tests/integration/flatten.rs~flattened_struct.json +++ b/schemars/tests/expected/flatten.json @@ -13,6 +13,10 @@ "s": { "type": "string" }, + "os": { + "type": "string", + "default": "" + }, "v": { "type": "array", "items": { @@ -24,6 +28,7 @@ "required": [ "f", "b", + "s", "v" ] } \ No newline at end of file diff --git a/schemars/tests/integration/snapshots/schemars/tests/integration/flatten.rs~flattened_value.json b/schemars/tests/expected/flattened_value.json similarity index 100% rename from schemars/tests/integration/snapshots/schemars/tests/integration/flatten.rs~flattened_value.json rename to schemars/tests/expected/flattened_value.json diff --git a/schemars/tests/integration/snapshots/schemars/tests/integration/from_value.rs~json_value.json b/schemars/tests/expected/from_json_value.json similarity index 77% rename from schemars/tests/integration/snapshots/schemars/tests/integration/from_value.rs~json_value.json rename to schemars/tests/expected/from_json_value.json index 0818d4d..b217fad 100644 --- a/schemars/tests/integration/snapshots/schemars/tests/integration/from_value.rs~json_value.json +++ b/schemars/tests/expected/from_json_value.json @@ -5,6 +5,12 @@ "zero": { "type": "integer" }, + "one": { + "type": "integer" + }, + "minusOne": { + "type": "integer" + }, "zeroPointZero": { "type": "number" }, @@ -15,15 +21,11 @@ "object": { "type": "object", "properties": { - "strings": { + "array": { "type": "array", "items": { "type": "string" } - }, - "mixed": { - "type": "array", - "items": true } } } @@ -31,17 +33,15 @@ "examples": [ { "zero": 0, + "one": 1, + "minusOne": -1, "zeroPointZero": 0.0, "bool": true, "null": null, "object": { - "strings": [ + "array": [ "foo", "bar" - ], - "mixed": [ - 1, - true ] } } diff --git a/schemars/tests/integration/snapshots/schemars/tests/integration/from_value.rs~custom_struct.json b/schemars/tests/expected/from_value_2019_09.json similarity index 85% rename from schemars/tests/integration/snapshots/schemars/tests/integration/from_value.rs~custom_struct.json rename to schemars/tests/expected/from_value_2019_09.json index 96d2358..939410d 100644 --- a/schemars/tests/integration/snapshots/schemars/tests/integration/from_value.rs~custom_struct.json +++ b/schemars/tests/expected/from_value_2019_09.json @@ -1,5 +1,5 @@ { - "$schema": "https://json-schema.org/draft/2020-12/schema", + "$schema": "https://json-schema.org/draft/2019-09/schema", "title": "MyStruct", "type": "object", "properties": { @@ -22,7 +22,7 @@ "my_vec": { "type": "array", "items": { - "type": "number" + "type": "string" } }, "my_empty_map": { @@ -35,7 +35,9 @@ }, "my_tuple": { "type": "array", - "prefixItems": [ + "minItems": 2, + "maxItems": 2, + "items": [ { "type": "string", "minLength": 1, @@ -44,9 +46,7 @@ { "type": "integer" } - ], - "maxItems": 2, - "minItems": 2 + ] } } } @@ -58,12 +58,11 @@ "myNullableEnum": null, "myInnerStruct": { "my_map": { - "k": 1.23 + "": 0.0 }, "my_vec": [ - 1.0, - 2.0, - 3.0 + "hello", + "world" ], "my_empty_map": {}, "my_empty_vec": [], diff --git a/schemars/tests/expected/from_value_draft07.json b/schemars/tests/expected/from_value_draft07.json new file mode 100644 index 0000000..721e871 --- /dev/null +++ b/schemars/tests/expected/from_value_draft07.json @@ -0,0 +1,76 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "MyStruct", + "type": "object", + "properties": { + "myInt": { + "type": "integer" + }, + "myBool": { + "type": "boolean" + }, + "myNullableEnum": true, + "myInnerStruct": { + "type": "object", + "properties": { + "my_map": { + "type": "object", + "additionalProperties": { + "type": "number" + } + }, + "my_vec": { + "type": "array", + "items": { + "type": "string" + } + }, + "my_empty_map": { + "type": "object", + "additionalProperties": true + }, + "my_empty_vec": { + "type": "array", + "items": true + }, + "my_tuple": { + "type": "array", + "minItems": 2, + "maxItems": 2, + "items": [ + { + "type": "string", + "minLength": 1, + "maxLength": 1 + }, + { + "type": "integer" + } + ] + } + } + } + }, + "examples": [ + { + "myInt": 123, + "myBool": true, + "myNullableEnum": null, + "myInnerStruct": { + "my_map": { + "": 0.0 + }, + "my_vec": [ + "hello", + "world" + ], + "my_empty_map": {}, + "my_empty_vec": [], + "my_tuple": [ + "💩", + 42 + ] + } + } + ] +} \ No newline at end of file diff --git a/schemars/tests/integration/snapshots/schemars/tests/integration/from_value.rs~custom_struct_openapi3.json b/schemars/tests/expected/from_value_openapi3.json similarity index 94% rename from schemars/tests/integration/snapshots/schemars/tests/integration/from_value.rs~custom_struct_openapi3.json rename to schemars/tests/expected/from_value_openapi3.json index 7e52acd..88f08a7 100644 --- a/schemars/tests/integration/snapshots/schemars/tests/integration/from_value.rs~custom_struct_openapi3.json +++ b/schemars/tests/expected/from_value_openapi3.json @@ -24,7 +24,7 @@ "my_vec": { "type": "array", "items": { - "type": "number" + "type": "string" } }, "my_empty_map": { @@ -59,12 +59,11 @@ "myNullableEnum": null, "myInnerStruct": { "my_map": { - "k": 1.23 + "": 0.0 }, "my_vec": [ - 1.0, - 2.0, - 3.0 + "hello", + "world" ], "my_empty_map": {}, "my_empty_vec": [], diff --git a/schemars/tests/integration/snapshots/schemars/tests/integration/validator.rs~validate_attrs.json b/schemars/tests/expected/garde.json similarity index 71% rename from schemars/tests/integration/snapshots/schemars/tests/integration/validator.rs~validate_attrs.json rename to schemars/tests/expected/garde.json index f4e1fc4..1f5d8a6 100644 --- a/schemars/tests/integration/snapshots/schemars/tests/integration/validator.rs~validate_attrs.json +++ b/schemars/tests/expected/garde.json @@ -1,25 +1,25 @@ { "$schema": "https://json-schema.org/draft/2020-12/schema", - "title": "ValidateAttrStruct", + "title": "Struct", "type": "object", "properties": { "min_max": { "type": "number", "format": "float", - "minimum": 1.0, - "maximum": 100.0 + "minimum": 0.01, + "maximum": 100 }, "min_max2": { "type": "number", "format": "float", - "minimum": 1.0, - "maximum": 10.0 + "minimum": 1, + "maximum": 1000 }, - "regex_str": { + "regex_str1": { "type": "string", - "pattern": "^[Hh]ello" + "pattern": "^[Hh]ello\\b" }, - "contains_str": { + "contains_str1": { "type": "string", "pattern": "substring\\.\\.\\." }, @@ -36,10 +36,16 @@ "minLength": 1, "maxLength": 100 }, + "non_empty_str2": { + "type": "string", + "minLength": 1, + "maxLength": 1000 + }, "pair": { "type": "array", "items": { - "type": "string" + "type": "integer", + "format": "int32" }, "minItems": 2, "maxItems": 2 @@ -49,19 +55,18 @@ }, "x": { "type": "integer", - "format": "int32", - "minimum": -100, - "maximum": 100 + "format": "int32" } }, "required": [ "min_max", "min_max2", - "regex_str", - "contains_str", + "regex_str1", + "contains_str1", "email_address", "homepage", "non_empty_str", + "non_empty_str2", "pair", "required_option", "x" diff --git a/schemars/tests/integration/snapshots/schemars/tests/integration/garde.rs~garde_attrs_newtype.json b/schemars/tests/expected/garde_newtype.json similarity index 81% rename from schemars/tests/integration/snapshots/schemars/tests/integration/garde.rs~garde_attrs_newtype.json rename to schemars/tests/expected/garde_newtype.json index fbefa51..cd835f5 100644 --- a/schemars/tests/integration/snapshots/schemars/tests/integration/garde.rs~garde_attrs_newtype.json +++ b/schemars/tests/expected/garde_newtype.json @@ -1,6 +1,6 @@ { "$schema": "https://json-schema.org/draft/2020-12/schema", - "title": "GardeAttrNewType", + "title": "NewType", "type": "integer", "format": "uint8", "minimum": 0, diff --git a/schemars/tests/integration/snapshots/schemars/tests/integration/garde.rs~garde_attrs.json b/schemars/tests/expected/garde_schemars_attrs.json similarity index 69% rename from schemars/tests/integration/snapshots/schemars/tests/integration/garde.rs~garde_attrs.json rename to schemars/tests/expected/garde_schemars_attrs.json index a95287b..f548706 100644 --- a/schemars/tests/integration/snapshots/schemars/tests/integration/garde.rs~garde_attrs.json +++ b/schemars/tests/expected/garde_schemars_attrs.json @@ -1,25 +1,25 @@ { "$schema": "https://json-schema.org/draft/2020-12/schema", - "title": "GardeAttrStruct", + "title": "Struct2", "type": "object", "properties": { "min_max": { "type": "number", "format": "float", - "minimum": 1.0, - "maximum": 100.0 + "minimum": 0.01, + "maximum": 100 }, "min_max2": { "type": "number", "format": "float", - "minimum": 1.0, - "maximum": 10.0 + "minimum": 1, + "maximum": 1000 }, - "regex_str": { + "regex_str1": { "type": "string", - "pattern": "^[Hh]ello" + "pattern": "^[Hh]ello\\b" }, - "contains_str": { + "contains_str1": { "type": "string", "pattern": "substring\\.\\.\\." }, @@ -34,13 +34,18 @@ "non_empty_str": { "type": "string", "minLength": 1, - "maxLength": 10 + "maxLength": 100 + }, + "non_empty_str2": { + "type": "string", + "minLength": 1, + "maxLength": 1000 }, "pair": { "type": "array", "items": { - "type": "string", - "minLength": 1 + "type": "integer", + "format": "int32" }, "minItems": 2, "maxItems": 2 @@ -50,19 +55,18 @@ }, "x": { "type": "integer", - "format": "int32", - "minimum": -100, - "maximum": 100 + "format": "int32" } }, "required": [ "min_max", "min_max2", - "regex_str", - "contains_str", + "regex_str1", + "contains_str1", "email_address", "homepage", "non_empty_str", + "non_empty_str2", "pair", "required_option", "x" diff --git a/schemars/tests/integration/snapshots/schemars/tests/integration/garde.rs~garde_attrs_tuple.json b/schemars/tests/expected/garde_tuple.json similarity index 90% rename from schemars/tests/integration/snapshots/schemars/tests/integration/garde.rs~garde_attrs_tuple.json rename to schemars/tests/expected/garde_tuple.json index 2341eeb..fa81224 100644 --- a/schemars/tests/integration/snapshots/schemars/tests/integration/garde.rs~garde_attrs_tuple.json +++ b/schemars/tests/expected/garde_tuple.json @@ -1,6 +1,6 @@ { "$schema": "https://json-schema.org/draft/2020-12/schema", - "title": "GardeAttrTuple", + "title": "Tuple", "type": "array", "prefixItems": [ { diff --git a/schemars/tests/expected/indexmap.json b/schemars/tests/expected/indexmap.json new file mode 100644 index 0000000..8ba90a8 --- /dev/null +++ b/schemars/tests/expected/indexmap.json @@ -0,0 +1,25 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "title": "IndexMapTypes", + "type": "object", + "properties": { + "map": { + "type": "object", + "additionalProperties": { + "type": "boolean" + } + }, + "set": { + "type": "array", + "uniqueItems": true, + "items": { + "type": "integer", + "format": "int" + } + } + }, + "required": [ + "map", + "set" + ] +} \ No newline at end of file diff --git a/schemars/tests/integration/snapshots/schemars/tests/integration/inline_subschemas.rs~struct_recursive.de.json b/schemars/tests/expected/inline-subschemas-recursive.json similarity index 100% rename from schemars/tests/integration/snapshots/schemars/tests/integration/inline_subschemas.rs~struct_recursive.de.json rename to schemars/tests/expected/inline-subschemas-recursive.json diff --git a/schemars/tests/integration/snapshots/schemars/tests/integration/inline_subschemas.rs~struct_normal.json b/schemars/tests/expected/inline-subschemas.json similarity index 100% rename from schemars/tests/integration/snapshots/schemars/tests/integration/inline_subschemas.rs~struct_normal.json rename to schemars/tests/expected/inline-subschemas.json diff --git a/schemars/tests/expected/macro_built_enum.json b/schemars/tests/expected/macro_built_enum.json new file mode 100644 index 0000000..b27df44 --- /dev/null +++ b/schemars/tests/expected/macro_built_enum.json @@ -0,0 +1,32 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "title": "OuterEnum", + "oneOf": [ + { + "type": "object", + "properties": { + "InnerStruct": { + "$ref": "#/$defs/InnerStruct" + } + }, + "required": [ + "InnerStruct" + ], + "additionalProperties": false + } + ], + "$defs": { + "InnerStruct": { + "type": "object", + "properties": { + "x": { + "type": "integer", + "format": "int32" + } + }, + "required": [ + "x" + ] + } + } +} \ No newline at end of file diff --git a/schemars/tests/expected/macro_built_struct.json b/schemars/tests/expected/macro_built_struct.json new file mode 100644 index 0000000..1d0fd08 --- /dev/null +++ b/schemars/tests/expected/macro_built_struct.json @@ -0,0 +1,20 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "title": "A", + "type": "object", + "properties": { + "x": { + "type": "integer", + "format": "uint8", + "minimum": 0 + }, + "v": { + "type": "integer", + "format": "int32" + } + }, + "required": [ + "x", + "v" + ] +} \ No newline at end of file diff --git a/schemars/tests/integration/snapshots/schemars/tests/integration/enums.rs~no_variants.json b/schemars/tests/expected/no-variants.json similarity index 100% rename from schemars/tests/integration/snapshots/schemars/tests/integration/enums.rs~no_variants.json rename to schemars/tests/expected/no-variants.json diff --git a/schemars/tests/expected/no_std.json b/schemars/tests/expected/no_std.json new file mode 100644 index 0000000..68da890 --- /dev/null +++ b/schemars/tests/expected/no_std.json @@ -0,0 +1,70 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "title": "MyStruct", + "type": "object", + "properties": { + "my_int": { + "type": "integer", + "format": "int32" + }, + "my_bool": { + "type": "boolean" + }, + "my_nullable_enum": { + "anyOf": [ + { + "$ref": "#/$defs/MyEnum" + }, + { + "type": "null" + } + ] + } + }, + "required": [ + "my_int", + "my_bool" + ], + "$defs": { + "MyEnum": { + "oneOf": [ + { + "type": "object", + "properties": { + "StringNewType": { + "type": "string" + } + }, + "required": [ + "StringNewType" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "StructVariant": { + "type": "object", + "properties": { + "floats": { + "type": "array", + "items": { + "type": "number", + "format": "float" + } + } + }, + "required": [ + "floats" + ] + } + }, + "required": [ + "StructVariant" + ], + "additionalProperties": false + } + ] + } + } +} \ No newline at end of file diff --git a/schemars/tests/expected/nonzero_ints.json b/schemars/tests/expected/nonzero_ints.json new file mode 100644 index 0000000..432e3b0 --- /dev/null +++ b/schemars/tests/expected/nonzero_ints.json @@ -0,0 +1,34 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "title": "MyStruct", + "type": "object", + "properties": { + "unsigned": { + "type": "integer", + "format": "uint32", + "minimum": 0 + }, + "nonzero_unsigned": { + "type": "integer", + "format": "uint32", + "minimum": 1 + }, + "signed": { + "type": "integer", + "format": "int32" + }, + "nonzero_signed": { + "type": "integer", + "format": "int32", + "not": { + "const": 0 + } + } + }, + "required": [ + "unsigned", + "nonzero_unsigned", + "signed", + "nonzero_signed" + ] +} \ No newline at end of file diff --git a/schemars/tests/expected/os_strings.json b/schemars/tests/expected/os_strings.json new file mode 100644 index 0000000..72e0be1 --- /dev/null +++ b/schemars/tests/expected/os_strings.json @@ -0,0 +1,55 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "title": "OsStrings", + "type": "object", + "properties": { + "owned": { + "$ref": "#/$defs/OsString" + }, + "borrowed": { + "$ref": "#/$defs/OsString" + } + }, + "required": [ + "owned", + "borrowed" + ], + "$defs": { + "OsString": { + "oneOf": [ + { + "type": "object", + "properties": { + "Unix": { + "type": "array", + "items": { + "type": "integer", + "format": "uint8", + "minimum": 0 + } + } + }, + "required": [ + "Unix" + ] + }, + { + "type": "object", + "properties": { + "Windows": { + "type": "array", + "items": { + "type": "integer", + "format": "uint16", + "minimum": 0 + } + } + }, + "required": [ + "Windows" + ] + } + ] + } + } +} \ No newline at end of file diff --git a/schemars/tests/integration/snapshots/schemars/tests/integration/structs.rs~renamed_fields.json b/schemars/tests/expected/property-name-struct.json similarity index 64% rename from schemars/tests/integration/snapshots/schemars/tests/integration/structs.rs~renamed_fields.json rename to schemars/tests/expected/property-name-struct.json index 1c305d6..82ea9ed 100644 --- a/schemars/tests/integration/snapshots/schemars/tests/integration/structs.rs~renamed_fields.json +++ b/schemars/tests/expected/property-name-struct.json @@ -1,19 +1,24 @@ { "$schema": "https://json-schema.org/draft/2020-12/schema", - "title": "RenamedFields", + "title": "MyStruct", "type": "object", "properties": { "camelCase": { "type": "integer", "format": "int32" }, - "new_name": { + "new_name_1": { + "type": "integer", + "format": "int32" + }, + "new_name_2": { "type": "integer", "format": "int32" } }, "required": [ "camelCase", - "new_name" + "new_name_1", + "new_name_2" ] } \ No newline at end of file diff --git a/schemars/tests/expected/range.json b/schemars/tests/expected/range.json new file mode 100644 index 0000000..64db4bd --- /dev/null +++ b/schemars/tests/expected/range.json @@ -0,0 +1,89 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "title": "MyStruct", + "type": "object", + "properties": { + "range": { + "$ref": "#/$defs/Range_of_uint" + }, + "inclusive": { + "$ref": "#/$defs/Range_of_double" + }, + "bound": { + "$ref": "#/$defs/Bound_of_string" + } + }, + "required": [ + "range", + "inclusive", + "bound" + ], + "$defs": { + "Range_of_uint": { + "type": "object", + "properties": { + "start": { + "type": "integer", + "format": "uint", + "minimum": 0 + }, + "end": { + "type": "integer", + "format": "uint", + "minimum": 0 + } + }, + "required": [ + "start", + "end" + ] + }, + "Range_of_double": { + "type": "object", + "properties": { + "start": { + "type": "number", + "format": "double" + }, + "end": { + "type": "number", + "format": "double" + } + }, + "required": [ + "start", + "end" + ] + }, + "Bound_of_string": { + "oneOf": [ + { + "type": "object", + "properties": { + "Included": { + "type": "string" + } + }, + "required": [ + "Included" + ] + }, + { + "type": "object", + "properties": { + "Excluded": { + "type": "string" + } + }, + "required": [ + "Excluded" + ] + }, + { + "type": "string", + "const": "Unbounded" + } + ] + } + } +} \ No newline at end of file diff --git a/schemars/tests/integration/snapshots/schemars/tests/integration/remote_derive.rs~simple.json b/schemars/tests/expected/remote_derive.json similarity index 64% rename from schemars/tests/integration/snapshots/schemars/tests/integration/remote_derive.rs~simple.json rename to schemars/tests/expected/remote_derive.json index 78db086..760630d 100644 --- a/schemars/tests/integration/snapshots/schemars/tests/integration/remote_derive.rs~simple.json +++ b/schemars/tests/expected/remote_derive.json @@ -3,11 +3,26 @@ "title": "Process", "type": "object", "properties": { + "command_line": { + "type": "string" + }, "wall_time": { "$ref": "#/$defs/Duration" + }, + "user_cpu_time": { + "$ref": "#/$defs/Duration", + "default": { + "secs": 0, + "nanos": 0 + } + }, + "system_cpu_time": { + "$ref": "#/$defs/Duration", + "default": "0.000000000s" } }, "required": [ + "command_line", "wall_time" ], "$defs": { diff --git a/schemars/tests/integration/snapshots/schemars/tests/integration/remote_derive.rs~type_param.json b/schemars/tests/expected/remote_derive_generic.json similarity index 50% rename from schemars/tests/integration/snapshots/schemars/tests/integration/remote_derive.rs~type_param.json rename to schemars/tests/expected/remote_derive_generic.json index 48568fd..bef4d6a 100644 --- a/schemars/tests/integration/snapshots/schemars/tests/integration/remote_derive.rs~type_param.json +++ b/schemars/tests/expected/remote_derive_generic.json @@ -1,18 +1,33 @@ { "$schema": "https://json-schema.org/draft/2020-12/schema", - "title": "TypeParam_for_string", + "title": "MyStruct_for_int32", "type": "object", "properties": { - "byte_or_bool": { + "byte_or_bool2": { "$ref": "#/$defs/Or_for_uint8_and_boolean" }, - "unit_or_t": { - "$ref": "#/$defs/Or_for_null_and_string" + "unit_or_t2": { + "$ref": "#/$defs/Or_for_null_and_int32" + }, + "s": { + "$ref": "#/$defs/Str" + }, + "fake_map": { + "type": "object", + "additionalProperties": { + "type": "array", + "uniqueItems": true, + "items": { + "type": "string" + } + } } }, "required": [ - "byte_or_bool", - "unit_or_t" + "byte_or_bool2", + "unit_or_t2", + "s", + "fake_map" ], "$defs": { "Or_for_uint8_and_boolean": { @@ -27,15 +42,19 @@ } ] }, - "Or_for_null_and_string": { + "Or_for_null_and_int32": { "anyOf": [ { "type": "null" }, { - "type": "string" + "type": "integer", + "format": "int32" } ] + }, + "Str": { + "type": "string" } } } \ No newline at end of file diff --git a/schemars/tests/expected/result.json b/schemars/tests/expected/result.json new file mode 100644 index 0000000..b468835 --- /dev/null +++ b/schemars/tests/expected/result.json @@ -0,0 +1,86 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "title": "Container", + "type": "object", + "properties": { + "result1": { + "$ref": "#/$defs/Result_of_MyStruct_or_Array_of_string" + }, + "result2": { + "$ref": "#/$defs/Result_of_boolean_or_null" + } + }, + "required": [ + "result1", + "result2" + ], + "$defs": { + "Result_of_MyStruct_or_Array_of_string": { + "oneOf": [ + { + "type": "object", + "properties": { + "Ok": { + "$ref": "#/$defs/MyStruct" + } + }, + "required": [ + "Ok" + ] + }, + { + "type": "object", + "properties": { + "Err": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "required": [ + "Err" + ] + } + ] + }, + "MyStruct": { + "type": "object", + "properties": { + "foo": { + "type": "integer", + "format": "int32" + } + }, + "required": [ + "foo" + ] + }, + "Result_of_boolean_or_null": { + "oneOf": [ + { + "type": "object", + "properties": { + "Ok": { + "type": "boolean" + } + }, + "required": [ + "Ok" + ] + }, + { + "type": "object", + "properties": { + "Err": { + "type": "null" + } + }, + "required": [ + "Err" + ] + } + ] + } + } +} \ No newline at end of file diff --git a/schemars/tests/expected/rust_decimal.json b/schemars/tests/expected/rust_decimal.json new file mode 100644 index 0000000..5e1f4c8 --- /dev/null +++ b/schemars/tests/expected/rust_decimal.json @@ -0,0 +1,9 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "title": "Decimal", + "type": [ + "string", + "number" + ], + "pattern": "^-?[0-9]+(\\.[0-9]+)?([eE][0-9]+)?$" +} \ No newline at end of file diff --git a/schemars/tests/integration/snapshots/schemars/tests/integration/same_name.rs~same_name.json b/schemars/tests/expected/same_name.json similarity index 71% rename from schemars/tests/integration/snapshots/schemars/tests/integration/same_name.rs~same_name.json rename to schemars/tests/expected/same_name.json index 00573f6..fb65854 100644 --- a/schemars/tests/integration/snapshots/schemars/tests/integration/same_name.rs~same_name.json +++ b/schemars/tests/expected/same_name.json @@ -8,15 +8,11 @@ }, "b_cfg": { "$ref": "#/$defs/Config2" - }, - "c_cfg": { - "$ref": "#/$defs/Config3" } }, "required": [ "a_cfg", - "b_cfg", - "c_cfg" + "b_cfg" ], "$defs": { "Config": { @@ -40,17 +36,6 @@ "required": [ "test2" ] - }, - "Config3": { - "type": "object", - "properties": { - "test3": { - "type": "string" - } - }, - "required": [ - "test3" - ] } } } \ No newline at end of file diff --git a/schemars/tests/integration/snapshots/schemars/tests/integration/skip.rs~skip_struct_field.json b/schemars/tests/expected/schema-name-const-generics.json similarity index 54% rename from schemars/tests/integration/snapshots/schemars/tests/integration/skip.rs~skip_struct_field.json rename to schemars/tests/expected/schema-name-const-generics.json index 821c86c..3c2edcc 100644 --- a/schemars/tests/integration/snapshots/schemars/tests/integration/skip.rs~skip_struct_field.json +++ b/schemars/tests/expected/schema-name-const-generics.json @@ -1,14 +1,14 @@ { "$schema": "https://json-schema.org/draft/2020-12/schema", - "title": "Struct", + "title": "const-generics-z-42", "type": "object", "properties": { - "included": { - "type": "boolean" + "foo": { + "type": "integer", + "format": "int32" } }, - "additionalProperties": false, "required": [ - "included" + "foo" ] } \ No newline at end of file diff --git a/schemars/tests/expected/schema-name-custom.json b/schemars/tests/expected/schema-name-custom.json new file mode 100644 index 0000000..70b4d98 --- /dev/null +++ b/schemars/tests/expected/schema-name-custom.json @@ -0,0 +1,47 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "title": "a-new-name-Array_of_string-int32-int32", + "type": "object", + "properties": { + "t": { + "type": "integer", + "format": "int32" + }, + "u": { + "type": "null" + }, + "v": { + "type": "boolean" + }, + "w": { + "type": "array", + "items": { + "type": "string" + } + }, + "inner": { + "$ref": "#/$defs/another-new-name" + } + }, + "required": [ + "t", + "u", + "v", + "w", + "inner" + ], + "$defs": { + "another-new-name": { + "type": "object", + "properties": { + "foo": { + "type": "integer", + "format": "int32" + } + }, + "required": [ + "foo" + ] + } + } +} \ No newline at end of file diff --git a/schemars/tests/expected/schema-name-default.json b/schemars/tests/expected/schema-name-default.json new file mode 100644 index 0000000..2243ddd --- /dev/null +++ b/schemars/tests/expected/schema-name-default.json @@ -0,0 +1,47 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "title": "MyStruct_for_int32_and_null_and_boolean_and_Array_of_string", + "type": "object", + "properties": { + "t": { + "type": "integer", + "format": "int32" + }, + "u": { + "type": "null" + }, + "v": { + "type": "boolean" + }, + "w": { + "type": "array", + "items": { + "type": "string" + } + }, + "inner": { + "$ref": "#/$defs/MySimpleStruct" + } + }, + "required": [ + "t", + "u", + "v", + "w", + "inner" + ], + "$defs": { + "MySimpleStruct": { + "type": "object", + "properties": { + "foo": { + "type": "integer", + "format": "int32" + } + }, + "required": [ + "foo" + ] + } + } +} \ No newline at end of file diff --git a/schemars/tests/expected/schema-name-mixed-generics.json b/schemars/tests/expected/schema-name-mixed-generics.json new file mode 100644 index 0000000..85c6792 --- /dev/null +++ b/schemars/tests/expected/schema-name-mixed-generics.json @@ -0,0 +1,63 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "title": "MixedGenericStruct_for_MyStruct_for_int32_and_null_and_boolean_and_Array_of_string_and_42_and_z", + "type": "object", + "properties": { + "generic": { + "$ref": "#/$defs/MyStruct_for_int32_and_null_and_boolean_and_Array_of_string" + }, + "foo": { + "type": "integer", + "format": "int32" + } + }, + "required": [ + "generic", + "foo" + ], + "$defs": { + "MyStruct_for_int32_and_null_and_boolean_and_Array_of_string": { + "type": "object", + "properties": { + "t": { + "type": "integer", + "format": "int32" + }, + "u": { + "type": "null" + }, + "v": { + "type": "boolean" + }, + "w": { + "type": "array", + "items": { + "type": "string" + } + }, + "inner": { + "$ref": "#/$defs/MySimpleStruct" + } + }, + "required": [ + "t", + "u", + "v", + "w", + "inner" + ] + }, + "MySimpleStruct": { + "type": "object", + "properties": { + "foo": { + "type": "integer", + "format": "int32" + } + }, + "required": [ + "foo" + ] + } + } +} \ No newline at end of file diff --git a/schemars/tests/integration/snapshots/schemars/tests/integration/settings.rs~draft2019_09.de.json b/schemars/tests/expected/schema_settings-2019_09.json similarity index 85% rename from schemars/tests/integration/snapshots/schemars/tests/integration/settings.rs~draft2019_09.de.json rename to schemars/tests/expected/schema_settings-2019_09.json index f704755..bc99f15 100644 --- a/schemars/tests/integration/snapshots/schemars/tests/integration/settings.rs~draft2019_09.de.json +++ b/schemars/tests/expected/schema_settings-2019_09.json @@ -1,13 +1,10 @@ { "$schema": "https://json-schema.org/draft/2019-09/schema", - "title": "OuterStruct", + "title": "Outer", "type": "object", "properties": { - "maybe_int": { - "type": [ - "integer", - "null" - ], + "int": { + "type": "integer", "format": "int32", "examples": [ 8, @@ -20,12 +17,9 @@ }, "value": true, "inner": { - "$ref": "#/$defs/InnerEnum" - }, - "maybe_inner": { "anyOf": [ { - "$ref": "#/$defs/InnerEnum" + "$ref": "#/$defs/Inner" }, { "type": "null" @@ -53,13 +47,13 @@ } }, "required": [ + "int", "values", "value", - "inner", "tuples" ], "$defs": { - "InnerEnum": { + "Inner": { "oneOf": [ { "type": "string", diff --git a/schemars/tests/integration/snapshots/schemars/tests/integration/settings.rs~draft2020_12.de.json b/schemars/tests/expected/schema_settings-2020_12.json similarity index 85% rename from schemars/tests/integration/snapshots/schemars/tests/integration/settings.rs~draft2020_12.de.json rename to schemars/tests/expected/schema_settings-2020_12.json index 1f51161..7964058 100644 --- a/schemars/tests/integration/snapshots/schemars/tests/integration/settings.rs~draft2020_12.de.json +++ b/schemars/tests/expected/schema_settings-2020_12.json @@ -1,13 +1,10 @@ { "$schema": "https://json-schema.org/draft/2020-12/schema", - "title": "OuterStruct", + "title": "Outer", "type": "object", "properties": { - "maybe_int": { - "type": [ - "integer", - "null" - ], + "int": { + "type": "integer", "format": "int32", "examples": [ 8, @@ -20,12 +17,9 @@ }, "value": true, "inner": { - "$ref": "#/$defs/InnerEnum" - }, - "maybe_inner": { "anyOf": [ { - "$ref": "#/$defs/InnerEnum" + "$ref": "#/$defs/Inner" }, { "type": "null" @@ -53,13 +47,13 @@ } }, "required": [ + "int", "values", "value", - "inner", "tuples" ], "$defs": { - "InnerEnum": { + "Inner": { "oneOf": [ { "type": "string", diff --git a/schemars/tests/integration/snapshots/schemars/tests/integration/settings.rs~openapi3.de.json b/schemars/tests/expected/schema_settings-openapi3.json similarity index 86% rename from schemars/tests/integration/snapshots/schemars/tests/integration/settings.rs~openapi3.de.json rename to schemars/tests/expected/schema_settings-openapi3.json index a31b385..8365822 100644 --- a/schemars/tests/integration/snapshots/schemars/tests/integration/settings.rs~openapi3.de.json +++ b/schemars/tests/expected/schema_settings-openapi3.json @@ -1,12 +1,11 @@ { "$schema": "https://spec.openapis.org/oas/3.0/schema/2021-09-28#/definitions/Schema", - "title": "OuterStruct", + "title": "Outer", "type": "object", "properties": { - "maybe_int": { + "int": { "type": "integer", "format": "int32", - "nullable": true, "example": 8 }, "values": { @@ -15,13 +14,10 @@ }, "value": {}, "inner": { - "$ref": "#/components/schemas/InnerEnum" - }, - "maybe_inner": { "nullable": true, "allOf": [ { - "$ref": "#/components/schemas/InnerEnum" + "$ref": "#/components/schemas/Inner" } ] }, @@ -46,14 +42,14 @@ } }, "required": [ + "int", "values", "value", - "inner", "tuples" ], "components": { "schemas": { - "InnerEnum": { + "Inner": { "oneOf": [ { "type": "string", diff --git a/schemars/tests/integration/snapshots/schemars/tests/integration/settings.rs~draft07.de.json b/schemars/tests/expected/schema_settings.json similarity index 84% rename from schemars/tests/integration/snapshots/schemars/tests/integration/settings.rs~draft07.de.json rename to schemars/tests/expected/schema_settings.json index a6b613e..4c435ad 100644 --- a/schemars/tests/integration/snapshots/schemars/tests/integration/settings.rs~draft07.de.json +++ b/schemars/tests/expected/schema_settings.json @@ -1,13 +1,10 @@ { "$schema": "http://json-schema.org/draft-07/schema#", - "title": "OuterStruct", + "title": "Outer", "type": "object", "properties": { - "maybe_int": { - "type": [ - "integer", - "null" - ], + "int": { + "type": "integer", "format": "int32", "examples": [ 8, @@ -20,12 +17,9 @@ }, "value": true, "inner": { - "$ref": "#/definitions/InnerEnum" - }, - "maybe_inner": { "anyOf": [ { - "$ref": "#/definitions/InnerEnum" + "$ref": "#/definitions/Inner" }, { "type": "null" @@ -53,13 +47,13 @@ } }, "required": [ + "int", "values", "value", - "inner", "tuples" ], "definitions": { - "InnerEnum": { + "Inner": { "oneOf": [ { "type": "string", diff --git a/schemars/tests/expected/schema_with-enum-adjacent-tagged.json b/schemars/tests/expected/schema_with-enum-adjacent-tagged.json new file mode 100644 index 0000000..e5877ba --- /dev/null +++ b/schemars/tests/expected/schema_with-enum-adjacent-tagged.json @@ -0,0 +1,89 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "title": "Adjacent", + "oneOf": [ + { + "type": "object", + "properties": { + "t": { + "type": "string", + "const": "Struct" + }, + "c": { + "type": "object", + "properties": { + "foo": { + "type": "boolean" + } + }, + "required": [ + "foo" + ] + } + }, + "required": [ + "t", + "c" + ] + }, + { + "type": "object", + "properties": { + "t": { + "type": "string", + "const": "NewType" + }, + "c": { + "type": "boolean" + } + }, + "required": [ + "t", + "c" + ] + }, + { + "type": "object", + "properties": { + "t": { + "type": "string", + "const": "Tuple" + }, + "c": { + "type": "array", + "prefixItems": [ + { + "type": "boolean" + }, + { + "type": "integer", + "format": "int32" + } + ], + "minItems": 2, + "maxItems": 2 + } + }, + "required": [ + "t", + "c" + ] + }, + { + "type": "object", + "properties": { + "t": { + "type": "string", + "const": "Unit" + }, + "c": { + "type": "boolean" + } + }, + "required": [ + "t", + "c" + ] + } + ] +} \ No newline at end of file diff --git a/schemars/tests/expected/schema_with-enum-external.json b/schemars/tests/expected/schema_with-enum-external.json new file mode 100644 index 0000000..5f5fe83 --- /dev/null +++ b/schemars/tests/expected/schema_with-enum-external.json @@ -0,0 +1,73 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "title": "External", + "oneOf": [ + { + "type": "object", + "properties": { + "struct": { + "type": "object", + "properties": { + "foo": { + "type": "boolean" + } + }, + "required": [ + "foo" + ] + } + }, + "required": [ + "struct" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "newType": { + "type": "boolean" + } + }, + "required": [ + "newType" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "tuple": { + "type": "array", + "prefixItems": [ + { + "type": "boolean" + }, + { + "type": "integer", + "format": "int32" + } + ], + "minItems": 2, + "maxItems": 2 + } + }, + "required": [ + "tuple" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "unit": { + "type": "boolean" + } + }, + "required": [ + "unit" + ], + "additionalProperties": false + } + ] +} \ No newline at end of file diff --git a/schemars/tests/expected/schema_with-enum-internal.json b/schemars/tests/expected/schema_with-enum-internal.json new file mode 100644 index 0000000..e6d707b --- /dev/null +++ b/schemars/tests/expected/schema_with-enum-internal.json @@ -0,0 +1,46 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "title": "Internal", + "oneOf": [ + { + "type": "object", + "properties": { + "foo": { + "type": "boolean" + }, + "typeProperty": { + "type": "string", + "const": "Struct" + } + }, + "required": [ + "typeProperty", + "foo" + ] + }, + { + "type": "object", + "properties": { + "typeProperty": { + "type": "string", + "const": "NewType" + } + }, + "required": [ + "typeProperty" + ] + }, + { + "type": "object", + "properties": { + "typeProperty": { + "type": "string", + "const": "Unit" + } + }, + "required": [ + "typeProperty" + ] + } + ] +} \ No newline at end of file diff --git a/schemars/tests/expected/schema_with-enum-untagged.json b/schemars/tests/expected/schema_with-enum-untagged.json new file mode 100644 index 0000000..9057c87 --- /dev/null +++ b/schemars/tests/expected/schema_with-enum-untagged.json @@ -0,0 +1,37 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "title": "Untagged", + "anyOf": [ + { + "type": "object", + "properties": { + "foo": { + "type": "boolean" + } + }, + "required": [ + "foo" + ] + }, + { + "type": "boolean" + }, + { + "type": "array", + "prefixItems": [ + { + "type": "boolean" + }, + { + "type": "integer", + "format": "int32" + } + ], + "minItems": 2, + "maxItems": 2 + }, + { + "type": "boolean" + } + ] +} \ No newline at end of file diff --git a/schemars/tests/expected/schema_with-newtype.json b/schemars/tests/expected/schema_with-newtype.json new file mode 100644 index 0000000..eb4a2f6 --- /dev/null +++ b/schemars/tests/expected/schema_with-newtype.json @@ -0,0 +1,5 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "title": "Newtype", + "type": "boolean" +} \ No newline at end of file diff --git a/schemars/tests/expected/schema_with-struct.json b/schemars/tests/expected/schema_with-struct.json new file mode 100644 index 0000000..0674f1e --- /dev/null +++ b/schemars/tests/expected/schema_with-struct.json @@ -0,0 +1,22 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "title": "Struct", + "type": "object", + "properties": { + "foo": { + "type": "boolean" + }, + "bar": { + "type": "integer", + "format": "int32" + }, + "baz": { + "type": "boolean" + } + }, + "required": [ + "foo", + "bar", + "baz" + ] +} \ No newline at end of file diff --git a/schemars/tests/expected/schema_with-transparent-newtype.json b/schemars/tests/expected/schema_with-transparent-newtype.json new file mode 100644 index 0000000..2aeff68 --- /dev/null +++ b/schemars/tests/expected/schema_with-transparent-newtype.json @@ -0,0 +1,5 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "title": "schema_fn", + "type": "boolean" +} \ No newline at end of file diff --git a/schemars/tests/expected/schema_with-tuple.json b/schemars/tests/expected/schema_with-tuple.json new file mode 100644 index 0000000..1296e33 --- /dev/null +++ b/schemars/tests/expected/schema_with-tuple.json @@ -0,0 +1,19 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "title": "Tuple", + "type": "array", + "prefixItems": [ + { + "type": "boolean" + }, + { + "type": "integer", + "format": "int32" + }, + { + "type": "boolean" + } + ], + "minItems": 3, + "maxItems": 3 +} \ No newline at end of file diff --git a/schemars/tests/expected/semver.json b/schemars/tests/expected/semver.json new file mode 100644 index 0000000..9f5b155 --- /dev/null +++ b/schemars/tests/expected/semver.json @@ -0,0 +1,14 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "title": "SemverTypes", + "type": "object", + "properties": { + "version": { + "type": "string", + "pattern": "^(0|[1-9]\\d*)\\.(0|[1-9]\\d*)\\.(0|[1-9]\\d*)(?:-((?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\\.(?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\\+([0-9a-zA-Z-]+(?:\\.[0-9a-zA-Z-]+)*))?$" + } + }, + "required": [ + "version" + ] +} \ No newline at end of file diff --git a/schemars/tests/expected/skip_enum_variants.json b/schemars/tests/expected/skip_enum_variants.json new file mode 100644 index 0000000..bd3a893 --- /dev/null +++ b/schemars/tests/expected/skip_enum_variants.json @@ -0,0 +1,25 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "title": "MyEnum", + "oneOf": [ + { + "type": "string", + "enum": [ + "Included2" + ] + }, + { + "type": "object", + "properties": { + "Included1": { + "type": "number", + "format": "float" + } + }, + "required": [ + "Included1" + ], + "additionalProperties": false + } + ] +} \ No newline at end of file diff --git a/schemars/tests/expected/skip_struct_fields.json b/schemars/tests/expected/skip_struct_fields.json new file mode 100644 index 0000000..16e2fea --- /dev/null +++ b/schemars/tests/expected/skip_struct_fields.json @@ -0,0 +1,19 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "title": "MyStruct", + "type": "object", + "properties": { + "writable": { + "type": "number", + "format": "float", + "writeOnly": true + }, + "included": { + "type": "null" + } + }, + "required": [ + "writable", + "included" + ] +} \ No newline at end of file diff --git a/schemars/tests/integration/snapshots/schemars/tests/integration/structs.rs~tuple.json b/schemars/tests/expected/skip_tuple_fields.json similarity index 67% rename from schemars/tests/integration/snapshots/schemars/tests/integration/structs.rs~tuple.json rename to schemars/tests/expected/skip_tuple_fields.json index f484d06..e3038bc 100644 --- a/schemars/tests/integration/snapshots/schemars/tests/integration/structs.rs~tuple.json +++ b/schemars/tests/expected/skip_tuple_fields.json @@ -4,10 +4,12 @@ "type": "array", "prefixItems": [ { - "type": "string" + "type": "number", + "format": "float", + "writeOnly": true }, { - "type": "boolean" + "type": "null" } ], "minItems": 2, diff --git a/schemars/tests/integration/snapshots/schemars/tests/integration/bytes.rs~bytes.ser.json b/schemars/tests/expected/smallvec.json similarity index 54% rename from schemars/tests/integration/snapshots/schemars/tests/integration/bytes.rs~bytes.ser.json rename to schemars/tests/expected/smallvec.json index f54610b..be50ed7 100644 --- a/schemars/tests/integration/snapshots/schemars/tests/integration/bytes.rs~bytes.ser.json +++ b/schemars/tests/expected/smallvec.json @@ -1,10 +1,8 @@ { "$schema": "https://json-schema.org/draft/2020-12/schema", - "title": "Bytes", + "title": "Array_of_string", "type": "array", "items": { - "type": "integer", - "format": "uint8", - "minimum": 0 + "type": "string" } } \ No newline at end of file diff --git a/schemars/tests/expected/smol_str.json b/schemars/tests/expected/smol_str.json new file mode 100644 index 0000000..0604332 --- /dev/null +++ b/schemars/tests/expected/smol_str.json @@ -0,0 +1,5 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "title": "string", + "type": "string" +} \ No newline at end of file diff --git a/schemars/tests/expected/struct-newtype.json b/schemars/tests/expected/struct-newtype.json new file mode 100644 index 0000000..e7b1cba --- /dev/null +++ b/schemars/tests/expected/struct-newtype.json @@ -0,0 +1,6 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "title": "Newtype", + "type": "integer", + "format": "int32" +} \ No newline at end of file diff --git a/schemars/tests/integration/snapshots/schemars/tests/integration/structs.rs~deny_unknown_fields.json b/schemars/tests/expected/struct-normal-additional-properties.json similarity index 62% rename from schemars/tests/integration/snapshots/schemars/tests/integration/structs.rs~deny_unknown_fields.json rename to schemars/tests/expected/struct-normal-additional-properties.json index 8400c1e..2c55fb7 100644 --- a/schemars/tests/integration/snapshots/schemars/tests/integration/structs.rs~deny_unknown_fields.json +++ b/schemars/tests/expected/struct-normal-additional-properties.json @@ -1,13 +1,20 @@ { "$schema": "https://json-schema.org/draft/2020-12/schema", - "title": "DenyUnknownFields", + "title": "Struct", "type": "object", "properties": { "foo": { - "type": "string" + "type": "integer", + "format": "int32" }, "bar": { "type": "boolean" + }, + "baz": { + "type": [ + "string", + "null" + ] } }, "additionalProperties": false, diff --git a/schemars/tests/expected/struct-normal.json b/schemars/tests/expected/struct-normal.json new file mode 100644 index 0000000..c49757c --- /dev/null +++ b/schemars/tests/expected/struct-normal.json @@ -0,0 +1,24 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "title": "Struct", + "type": "object", + "properties": { + "foo": { + "type": "integer", + "format": "int32" + }, + "bar": { + "type": "boolean" + }, + "baz": { + "type": [ + "string", + "null" + ] + } + }, + "required": [ + "foo", + "bar" + ] +} \ No newline at end of file diff --git a/schemars/tests/expected/struct-tuple.json b/schemars/tests/expected/struct-tuple.json new file mode 100644 index 0000000..8960068 --- /dev/null +++ b/schemars/tests/expected/struct-tuple.json @@ -0,0 +1,22 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "title": "Tuple", + "type": "array", + "prefixItems": [ + { + "type": "integer", + "format": "int32" + }, + { + "type": "boolean" + }, + { + "type": [ + "string", + "null" + ] + } + ], + "minItems": 3, + "maxItems": 3 +} \ No newline at end of file diff --git a/schemars/tests/integration/snapshots/schemars/tests/integration/structs.rs~unit.json b/schemars/tests/expected/struct-unit.json similarity index 76% rename from schemars/tests/integration/snapshots/schemars/tests/integration/structs.rs~unit.json rename to schemars/tests/expected/struct-unit.json index 9fef7a4..46f6fcf 100644 --- a/schemars/tests/integration/snapshots/schemars/tests/integration/structs.rs~unit.json +++ b/schemars/tests/expected/struct-unit.json @@ -1,5 +1,5 @@ { "$schema": "https://json-schema.org/draft/2020-12/schema", - "title": "UnitStruct", + "title": "Unit", "type": "null" } \ No newline at end of file diff --git a/schemars/tests/expected/test_flattened_struct_deny_unknown_fields.json b/schemars/tests/expected/test_flattened_struct_deny_unknown_fields.json new file mode 100644 index 0000000..1ac94b5 --- /dev/null +++ b/schemars/tests/expected/test_flattened_struct_deny_unknown_fields.json @@ -0,0 +1,52 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "title": "Tuple_of_OuterAllowUnknownFields_and_MiddleDenyUnknownFields", + "type": "array", + "prefixItems": [ + { + "$ref": "#/$defs/OuterAllowUnknownFields" + }, + { + "$ref": "#/$defs/MiddleDenyUnknownFields" + } + ], + "minItems": 2, + "maxItems": 2, + "$defs": { + "OuterAllowUnknownFields": { + "type": "object", + "properties": { + "outer_field": { + "type": "boolean" + }, + "middle_field": { + "type": "boolean" + }, + "inner_field": { + "type": "boolean" + } + }, + "required": [ + "outer_field", + "middle_field", + "inner_field" + ] + }, + "MiddleDenyUnknownFields": { + "type": "object", + "properties": { + "middle_field": { + "type": "boolean" + }, + "inner_field": { + "type": "boolean" + } + }, + "additionalProperties": false, + "required": [ + "middle_field", + "inner_field" + ] + } + } +} \ No newline at end of file diff --git a/schemars/tests/integration/snapshots/schemars/tests/integration/transform.rs~transform_enum.json b/schemars/tests/expected/transform_enum_external.json similarity index 70% rename from schemars/tests/integration/snapshots/schemars/tests/integration/transform.rs~transform_enum.json rename to schemars/tests/expected/transform_enum_external.json index 29480cf..af746e3 100644 --- a/schemars/tests/integration/snapshots/schemars/tests/integration/transform.rs~transform_enum.json +++ b/schemars/tests/expected/transform_enum_external.json @@ -5,8 +5,8 @@ { "type": "string", "const": "Unit", - "x-propertyCount": 0, - "x-upperType": "STRING" + "propertyCount": 0, + "upperType": "STRING" }, { "type": "object", @@ -17,9 +17,9 @@ "NewType" ], "additionalProperties": false, - "x-propertyCount": 1, - "x-upperType": "OBJECT" + "propertyCount": 1, + "upperType": "OBJECT" } ], - "x-propertyCount": 0 + "propertyCount": 0 } \ No newline at end of file diff --git a/schemars/tests/integration/snapshots/schemars/tests/integration/transform.rs~transform_struct.json b/schemars/tests/expected/transform_struct.json similarity index 70% rename from schemars/tests/integration/snapshots/schemars/tests/integration/transform.rs~transform_struct.json rename to schemars/tests/expected/transform_struct.json index 5a624df..6723414 100644 --- a/schemars/tests/integration/snapshots/schemars/tests/integration/transform.rs~transform_struct.json +++ b/schemars/tests/expected/transform_struct.json @@ -7,14 +7,14 @@ "int": { "type": "integer", "format": "int32", - "x-propertyCount": 0, - "x-upperType": "INTEGER" + "propertyCount": 0, + "upperType": "INTEGER" } }, "required": [ "value", "int" ], - "x-upperType": "OBJECT", - "x-propertyCount": 2 + "upperType": "OBJECT", + "propertyCount": 2 } \ No newline at end of file diff --git a/schemars/tests/expected/transparent-struct.json b/schemars/tests/expected/transparent-struct.json new file mode 100644 index 0000000..2692069 --- /dev/null +++ b/schemars/tests/expected/transparent-struct.json @@ -0,0 +1,33 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "title": "OuterStruct", + "type": "object", + "properties": { + "inner": { + "anyOf": [ + { + "$ref": "#/$defs/InnerStruct" + }, + { + "type": "null" + } + ] + } + }, + "$defs": { + "InnerStruct": { + "type": "array", + "prefixItems": [ + { + "type": "string" + }, + { + "type": "integer", + "format": "int32" + } + ], + "minItems": 2, + "maxItems": 2 + } + } +} \ No newline at end of file diff --git a/schemars/tests/integration/snapshots/schemars/tests/integration/schema_with.rs~schema_with.json b/schemars/tests/expected/url.json similarity index 69% rename from schemars/tests/integration/snapshots/schemars/tests/integration/schema_with.rs~schema_with.json rename to schemars/tests/expected/url.json index e3ea1f4..425bf85 100644 --- a/schemars/tests/integration/snapshots/schemars/tests/integration/schema_with.rs~schema_with.json +++ b/schemars/tests/expected/url.json @@ -1,14 +1,14 @@ { "$schema": "https://json-schema.org/draft/2020-12/schema", - "title": "Struct", + "title": "UrlTypes", "type": "object", "properties": { - "x": { + "url": { "type": "string", - "pattern": "^-?\\d+$" + "format": "uri" } }, "required": [ - "x" + "url" ] } \ No newline at end of file diff --git a/schemars/tests/integration/snapshots/schemars/tests/integration/url.rs~url.json b/schemars/tests/expected/uuid.json similarity index 68% rename from schemars/tests/integration/snapshots/schemars/tests/integration/url.rs~url.json rename to schemars/tests/expected/uuid.json index 5c4bf3f..98ae408 100644 --- a/schemars/tests/integration/snapshots/schemars/tests/integration/url.rs~url.json +++ b/schemars/tests/expected/uuid.json @@ -1,6 +1,6 @@ { "$schema": "https://json-schema.org/draft/2020-12/schema", - "title": "Url", + "title": "Uuid", "type": "string", - "format": "uri" + "format": "uuid" } \ No newline at end of file diff --git a/schemars/tests/expected/validate.json b/schemars/tests/expected/validate.json new file mode 100644 index 0000000..64b571f --- /dev/null +++ b/schemars/tests/expected/validate.json @@ -0,0 +1,84 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "title": "Struct", + "type": "object", + "properties": { + "min_max": { + "type": "number", + "format": "float", + "minimum": 0.01, + "maximum": 100 + }, + "min_max2": { + "type": "number", + "format": "float", + "minimum": 1, + "maximum": 1000 + }, + "regex_str1": { + "type": "string", + "pattern": "^[Hh]ello\\b" + }, + "regex_str2": { + "type": "string", + "pattern": "^[Hh]ello\\b" + }, + "contains_str1": { + "type": "string", + "pattern": "substring\\.\\.\\." + }, + "contains_str2": { + "type": "string", + "pattern": "substring\\.\\.\\." + }, + "email_address": { + "type": "string", + "format": "email" + }, + "homepage": { + "type": "string", + "format": "uri" + }, + "non_empty_str": { + "type": "string", + "minLength": 1, + "maxLength": 100 + }, + "non_empty_str2": { + "type": "string", + "minLength": 1, + "maxLength": 1000 + }, + "pair": { + "type": "array", + "items": { + "type": "integer", + "format": "int32" + }, + "minItems": 2, + "maxItems": 2 + }, + "required_option": { + "type": "boolean" + }, + "x": { + "type": "integer", + "format": "int32" + } + }, + "required": [ + "min_max", + "min_max2", + "regex_str1", + "regex_str2", + "contains_str1", + "contains_str2", + "email_address", + "homepage", + "non_empty_str", + "non_empty_str2", + "pair", + "required_option", + "x" + ] +} \ No newline at end of file diff --git a/schemars/tests/expected/validate_inner.json b/schemars/tests/expected/validate_inner.json new file mode 100644 index 0000000..a77e0d7 --- /dev/null +++ b/schemars/tests/expected/validate_inner.json @@ -0,0 +1,74 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "title": "Struct", + "type": "object", + "properties": { + "array_str_length": { + "type": "array", + "items": { + "type": "string", + "minLength": 5, + "maxLength": 100 + }, + "minItems": 2, + "maxItems": 2 + }, + "slice_str_contains": { + "type": "array", + "items": { + "type": "string", + "pattern": "substring\\.\\.\\." + } + }, + "vec_str_regex": { + "type": "array", + "items": { + "type": "string", + "pattern": "^[Hh]ello\\b" + } + }, + "vec_str_length": { + "type": "array", + "items": { + "type": "string", + "minLength": 1, + "maxLength": 100 + } + }, + "vec_str_length2": { + "type": "array", + "items": { + "type": "string", + "minLength": 1, + "maxLength": 100 + }, + "minItems": 1, + "maxItems": 3 + }, + "vec_str_url": { + "type": "array", + "items": { + "type": "string", + "format": "uri" + } + }, + "vec_i32_range": { + "type": "array", + "items": { + "type": "integer", + "format": "int32", + "minimum": -10, + "maximum": 10 + } + } + }, + "required": [ + "array_str_length", + "slice_str_contains", + "vec_str_regex", + "vec_str_length", + "vec_str_length2", + "vec_str_url", + "vec_i32_range" + ] +} \ No newline at end of file diff --git a/schemars/tests/expected/validate_newtype.json b/schemars/tests/expected/validate_newtype.json new file mode 100644 index 0000000..cd835f5 --- /dev/null +++ b/schemars/tests/expected/validate_newtype.json @@ -0,0 +1,8 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "title": "NewType", + "type": "integer", + "format": "uint8", + "minimum": 0, + "maximum": 10 +} \ No newline at end of file diff --git a/schemars/tests/expected/validate_schemars_attrs.json b/schemars/tests/expected/validate_schemars_attrs.json new file mode 100644 index 0000000..1f2e3eb --- /dev/null +++ b/schemars/tests/expected/validate_schemars_attrs.json @@ -0,0 +1,84 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "title": "Struct2", + "type": "object", + "properties": { + "min_max": { + "type": "number", + "format": "float", + "minimum": 0.01, + "maximum": 100 + }, + "min_max2": { + "type": "number", + "format": "float", + "minimum": 1, + "maximum": 1000 + }, + "regex_str1": { + "type": "string", + "pattern": "^[Hh]ello\\b" + }, + "regex_str2": { + "type": "string", + "pattern": "^\\d+$" + }, + "contains_str1": { + "type": "string", + "pattern": "substring\\.\\.\\." + }, + "contains_str2": { + "type": "string", + "pattern": "substring\\.\\.\\." + }, + "email_address": { + "type": "string", + "format": "email" + }, + "homepage": { + "type": "string", + "format": "uri" + }, + "non_empty_str": { + "type": "string", + "minLength": 1, + "maxLength": 100 + }, + "non_empty_str2": { + "type": "string", + "minLength": 1, + "maxLength": 1000 + }, + "pair": { + "type": "array", + "items": { + "type": "integer", + "format": "int32" + }, + "minItems": 2, + "maxItems": 2 + }, + "required_option": { + "type": "boolean" + }, + "x": { + "type": "integer", + "format": "int32" + } + }, + "required": [ + "min_max", + "min_max2", + "regex_str1", + "regex_str2", + "contains_str1", + "contains_str2", + "email_address", + "homepage", + "non_empty_str", + "non_empty_str2", + "pair", + "required_option", + "x" + ] +} \ No newline at end of file diff --git a/schemars/tests/expected/validate_tuple.json b/schemars/tests/expected/validate_tuple.json new file mode 100644 index 0000000..fa81224 --- /dev/null +++ b/schemars/tests/expected/validate_tuple.json @@ -0,0 +1,18 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "title": "Tuple", + "type": "array", + "prefixItems": [ + { + "type": "integer", + "format": "uint8", + "minimum": 0, + "maximum": 10 + }, + { + "type": "boolean" + } + ], + "minItems": 2, + "maxItems": 2 +} \ No newline at end of file diff --git a/schemars/tests/extend.rs b/schemars/tests/extend.rs new file mode 100644 index 0000000..2b44f5e --- /dev/null +++ b/schemars/tests/extend.rs @@ -0,0 +1,96 @@ +mod util; +use schemars::JsonSchema; +use serde_json::Value; +use util::*; + +const THREE: f64 = 3.0; + +#[allow(dead_code)] +#[derive(JsonSchema)] +#[schemars(extend("msg" = concat!("hello ", "world"), "obj" = {"array": [null, ()]}))] +#[schemars(extend("3" = THREE), extend("pi" = THREE + 0.14))] +struct Struct { + #[schemars(extend("foo" = "bar"))] + value: Value, + #[schemars(extend("type" = "overridden"))] + int: i32, +} + +#[test] +fn extend_struct() -> TestResult { + test_default_generated_schema::("extend_struct") +} + +#[allow(dead_code)] +#[derive(JsonSchema)] +#[schemars(extend("foo" = "bar"))] +enum External { + #[schemars(extend("foo" = "bar"))] + Unit, + #[schemars(extend("foo" = "bar"))] + NewType(Value), + #[schemars(extend("foo" = "bar"))] + Tuple(i32, bool), + #[schemars(extend("foo" = "bar"))] + Struct { i: i32, b: bool }, +} + +#[test] +fn extend_enum_external() -> TestResult { + test_default_generated_schema::("extend_enum_external") +} + +#[allow(dead_code)] +#[derive(JsonSchema)] +#[schemars(tag = "typeProperty", extend("foo" = "bar"))] +enum Internal { + #[schemars(extend("foo" = "bar"))] + Unit, + #[schemars(extend("foo" = "bar"))] + NewType(Value), + #[schemars(extend("foo" = "bar"))] + Struct { i: i32, b: bool }, +} + +#[test] +fn extend_enum_internal() -> TestResult { + test_default_generated_schema::("extend_enum_internal") +} + +#[allow(dead_code)] +#[derive(JsonSchema)] +#[schemars(untagged, extend("foo" = "bar"))] +enum Untagged { + #[schemars(extend("foo" = "bar"))] + Unit, + #[schemars(extend("foo" = "bar"))] + NewType(Value), + #[schemars(extend("foo" = "bar"))] + Tuple(i32, bool), + #[schemars(extend("foo" = "bar"))] + Struct { i: i32, b: bool }, +} + +#[test] +fn extend_enum_untagged() -> TestResult { + test_default_generated_schema::("extend_enum_untagged") +} + +#[allow(dead_code)] +#[derive(JsonSchema)] +#[schemars(tag = "t", content = "c", extend("foo" = "bar"))] +enum Adjacent { + #[schemars(extend("foo" = "bar"))] + Unit, + #[schemars(extend("foo" = "bar"))] + NewType(Value), + #[schemars(extend("foo" = "bar"))] + Tuple(i32, bool), + #[schemars(extend("foo" = "bar"))] + Struct { i: i32, b: bool }, +} + +#[test] +fn extend_enum_adjacent() -> TestResult { + test_default_generated_schema::("extend_enum_adjacent") +} diff --git a/schemars/tests/ffi.rs b/schemars/tests/ffi.rs new file mode 100644 index 0000000..41bb8ce --- /dev/null +++ b/schemars/tests/ffi.rs @@ -0,0 +1,16 @@ +mod util; +use schemars::JsonSchema; +use std::ffi::{OsStr, OsString}; +use util::*; + +#[allow(dead_code)] +#[derive(JsonSchema)] +struct OsStrings { + owned: OsString, + borrowed: &'static OsStr, +} + +#[test] +fn os_strings() -> TestResult { + test_default_generated_schema::("os_strings") +} diff --git a/schemars/tests/flatten.rs b/schemars/tests/flatten.rs new file mode 100644 index 0000000..a05a5c0 --- /dev/null +++ b/schemars/tests/flatten.rs @@ -0,0 +1,115 @@ +mod util; +use schemars::JsonSchema; +use serde_json::Value; +use std::collections::BTreeMap; +use util::*; + +#[allow(dead_code)] +#[derive(JsonSchema)] +struct Flat { + f: f32, + b: bool, + s: String, + #[serde(default)] + os: String, + v: Vec, +} + +#[allow(dead_code)] +#[derive(JsonSchema)] +#[schemars(rename = "Flat")] +struct Deep1 { + f: f32, + #[schemars(flatten)] + deep2: Deep2, + v: Vec, +} + +#[allow(clippy::option_option, dead_code)] +#[derive(JsonSchema)] +struct Deep2 { + b: bool, + #[serde(flatten)] + deep3: Deep3, + #[serde(flatten)] + deep4: Box>>>, +} + +#[allow(dead_code)] +#[derive(JsonSchema)] +struct Deep3 { + s: &'static str, +} + +#[allow(dead_code)] +#[derive(JsonSchema)] +struct Deep4 { + #[serde(default)] + os: &'static str, +} + +#[test] +fn test_flat_schema() -> TestResult { + test_default_generated_schema::("flatten") +} + +#[test] +fn test_flattened_schema() -> TestResult { + // intentionally using the same file as test_flat_schema, as the schema should be identical + test_default_generated_schema::("flatten") +} + +#[allow(dead_code)] +#[derive(JsonSchema)] +struct FlattenValue { + flag: bool, + #[serde(flatten)] + value: Value, +} + +#[allow(dead_code)] +#[derive(JsonSchema)] +#[schemars(rename = "FlattenValue")] +struct FlattenMap { + flag: bool, + #[serde(flatten)] + value: BTreeMap, +} + +#[test] +fn test_flattened_value() -> TestResult { + test_default_generated_schema::("flattened_value") +} + +#[test] +fn test_flattened_map() -> TestResult { + // intentionally using the same file as test_flattened_value, as the schema should be identical + test_default_generated_schema::("flattened_value") +} + +#[derive(JsonSchema)] +pub struct OuterAllowUnknownFields { + pub outer_field: bool, + #[serde(flatten)] + pub middle: MiddleDenyUnknownFields, +} + +#[derive(JsonSchema)] +#[serde(deny_unknown_fields)] +pub struct MiddleDenyUnknownFields { + pub middle_field: bool, + #[serde(flatten)] + pub inner: InnerAllowUnknownFields, +} + +#[derive(JsonSchema)] +pub struct InnerAllowUnknownFields { + pub inner_field: bool, +} + +#[test] +fn test_flattened_struct_deny_unknown_fields() -> TestResult { + test_default_generated_schema::<(OuterAllowUnknownFields, MiddleDenyUnknownFields)>( + "test_flattened_struct_deny_unknown_fields", + ) +} diff --git a/schemars/tests/from_value.rs b/schemars/tests/from_value.rs new file mode 100644 index 0000000..0934cfd --- /dev/null +++ b/schemars/tests/from_value.rs @@ -0,0 +1,94 @@ +mod util; +use schemars::generate::{SchemaGenerator, SchemaSettings}; +use serde::Serialize; +use std::collections::HashMap; +use util::*; + +#[derive(Serialize)] +#[serde(rename_all = "camelCase")] +pub struct MyStruct { + pub my_int: i32, + pub my_bool: bool, + pub my_nullable_enum: Option, + pub my_inner_struct: MyInnerStruct, + #[serde(skip)] + pub skip: i32, + #[serde(skip_serializing_if = "Option::is_none")] + pub skip_if_none: Option, +} + +#[derive(Serialize)] +pub struct MyInnerStruct { + pub my_map: HashMap, + pub my_vec: Vec<&'static str>, + pub my_empty_map: HashMap, + pub my_empty_vec: Vec<&'static str>, + pub my_tuple: (char, u8), +} + +#[derive(Serialize)] +pub enum MyEnum { + StringNewType(String), + StructVariant { floats: Vec }, +} + +fn make_value() -> MyStruct { + let mut value = MyStruct { + my_int: 123, + my_bool: true, + my_nullable_enum: None, + my_inner_struct: MyInnerStruct { + my_map: HashMap::new(), + my_vec: vec!["hello", "world"], + my_empty_map: HashMap::new(), + my_empty_vec: vec![], + my_tuple: ('💩', 42), + }, + skip: 123, + skip_if_none: None, + }; + value.my_inner_struct.my_map.insert(String::new(), 0.0); + value +} + +#[test] +fn schema_from_value_matches_draft07() -> TestResult { + let generator = SchemaSettings::draft07().into_generator(); + let actual = generator.into_root_schema_for_value(&make_value())?; + + test_schema(&actual, "from_value_draft07") +} + +#[test] +fn schema_from_value_matches_2019_09() -> TestResult { + let generator = SchemaSettings::draft2019_09().into_generator(); + let actual = generator.into_root_schema_for_value(&make_value())?; + + test_schema(&actual, "from_value_2019_09") +} + +#[test] +fn schema_from_value_matches_openapi3() -> TestResult { + let generator = SchemaSettings::openapi3().into_generator(); + let actual = generator.into_root_schema_for_value(&make_value())?; + + test_schema(&actual, "from_value_openapi3") +} + +#[test] +fn schema_from_json_value() -> TestResult { + let generator = SchemaGenerator::default(); + let actual = generator.into_root_schema_for_value(&serde_json::json!({ + "zero": 0, + "one": 1, + "minusOne": -1, + "zeroPointZero": 0.0, + "bool": true, + "null": null, + "object": { + "array": ["foo", "bar"] + }, + }))?; + + test_schema(&actual, "from_json_value") +} diff --git a/schemars/tests/garde.rs b/schemars/tests/garde.rs new file mode 100644 index 0000000..8b7ce85 --- /dev/null +++ b/schemars/tests/garde.rs @@ -0,0 +1,99 @@ +mod util; +use schemars::JsonSchema; +use util::*; + +const MIN: u32 = 1; +const MAX: u32 = 1000; + +#[allow(dead_code)] +#[derive(JsonSchema)] +pub struct Struct { + #[garde(range(min = 0.01, max = 100))] + min_max: f32, + #[garde(range(min = MIN, max = MAX))] + min_max2: f32, + #[garde(pattern(r"^[Hh]ello\b"))] + regex_str1: String, + #[garde(contains(concat!("sub","string...")))] + contains_str1: String, + #[garde(email)] + email_address: String, + #[garde(url)] + homepage: String, + #[garde(length(min = 1, max = 100))] + non_empty_str: String, + #[garde(length(min = MIN, max = MAX))] + non_empty_str2: String, + #[garde(length(equal = 2))] + pair: Vec, + #[garde(required)] + required_option: Option, + #[garde(required)] + #[serde(flatten)] + required_flattened: Option, +} + +#[allow(dead_code)] +#[derive(JsonSchema)] +pub struct Inner { + x: i32, +} + +#[test] +fn garde() -> TestResult { + test_default_generated_schema::("garde") +} + +#[allow(dead_code)] +#[derive(JsonSchema)] +pub struct Struct2 { + #[schemars(range(min = 0.01, max = 100))] + min_max: f32, + #[schemars(range(min = MIN, max = MAX))] + min_max2: f32, + #[schemars(pattern(r"^[Hh]ello\b"))] + regex_str1: String, + #[schemars(contains(concat!("sub","string...")))] + contains_str1: String, + #[schemars(email)] + email_address: String, + #[schemars(url)] + homepage: String, + #[schemars(length(min = 1, max = 100))] + non_empty_str: String, + #[schemars(length(min = MIN, max = MAX))] + non_empty_str2: String, + #[schemars(length(equal = 2))] + pair: Vec, + #[schemars(required)] + required_option: Option, + #[schemars(required)] + #[serde(flatten)] + required_flattened: Option, +} + +#[test] +fn garde_schemars_attrs() -> TestResult { + test_default_generated_schema::("garde_schemars_attrs") +} + +#[allow(dead_code)] +#[derive(JsonSchema)] +pub struct Tuple( + #[garde(range(max = 10))] u8, + #[garde(required)] Option, +); + +#[test] +fn garde_tuple() -> TestResult { + test_default_generated_schema::("garde_tuple") +} + +#[allow(dead_code)] +#[derive(JsonSchema)] +pub struct NewType(#[garde(range(max = 10))] u8); + +#[test] +fn garde_newtype() -> TestResult { + test_default_generated_schema::("garde_newtype") +} diff --git a/schemars/tests/indexmap.rs b/schemars/tests/indexmap.rs new file mode 100644 index 0000000..76fcd56 --- /dev/null +++ b/schemars/tests/indexmap.rs @@ -0,0 +1,18 @@ +mod util; +use std::collections::hash_map::RandomState; + +use indexmap2::{IndexMap, IndexSet}; +use schemars::JsonSchema; +use util::*; + +#[allow(dead_code)] +#[derive(JsonSchema)] +struct IndexMapTypes { + map: IndexMap, + set: IndexSet, +} + +#[test] +fn indexmap_types() -> TestResult { + test_default_generated_schema::("indexmap") +} diff --git a/schemars/tests/inline_subschemas.rs b/schemars/tests/inline_subschemas.rs new file mode 100644 index 0000000..a377847 --- /dev/null +++ b/schemars/tests/inline_subschemas.rs @@ -0,0 +1,43 @@ +mod util; +use schemars::generate::SchemaSettings; +use schemars::JsonSchema; +use util::*; + +#[allow(dead_code)] +#[derive(JsonSchema)] +struct MyJob { + spec: MyJobSpec, +} + +#[allow(dead_code)] +#[derive(JsonSchema)] +struct MyJobSpec { + replicas: u32, +} + +#[test] +fn struct_normal() -> TestResult { + let mut settings = SchemaSettings::default(); + settings.inline_subschemas = true; + test_generated_schema::("inline-subschemas", settings) +} + +#[allow(dead_code)] +#[derive(JsonSchema)] +struct RecursiveOuter { + direct: Option>, + indirect: Option>, +} + +#[allow(dead_code)] +#[derive(JsonSchema)] +struct RecursiveInner { + recursive: RecursiveOuter, +} + +#[test] +fn struct_recursive() -> TestResult { + let mut settings = SchemaSettings::default(); + settings.inline_subschemas = true; + test_generated_schema::("inline-subschemas-recursive", settings) +} diff --git a/schemars/tests/integration/arrayvec.rs b/schemars/tests/integration/arrayvec.rs deleted file mode 100644 index 177737a..0000000 --- a/schemars/tests/integration/arrayvec.rs +++ /dev/null @@ -1,36 +0,0 @@ -use crate::prelude::*; -use arrayvec07::{ArrayString, ArrayVec}; - -#[test] -fn arrayvec07() { - test!(ArrayVec) - .assert_snapshot() - .assert_allows_ser_roundtrip([ - ArrayVec::from_iter([]), - ArrayVec::from_iter([1, 2, 3, 4, 5, 6, 7, 8]), - ]) - .assert_matches_de_roundtrip( - (0..16).map(|len| Value::Array((0..len).map(Value::from).collect())), - ) - .assert_matches_de_roundtrip(arbitrary_values_except( - is_array_of_u64, - "FIXME schema allows out-of-range positive integers", - )); -} - -#[test] -fn arrayvec07_arraystring() { - test!(ArrayString<8>) - .assert_identical::() - .assert_allows_ser_roundtrip(["".try_into().unwrap(), "12345678".try_into().unwrap()]) - .assert_matches_de_roundtrip(arbitrary_values_except( - Value::is_string, - "There's not a good way to express UTF-8 byte length in JSON schema, so schema ignores the ArrayString's capacity.", - )); -} - -fn is_array_of_u64(value: &Value) -> bool { - value - .as_array() - .is_some_and(|a| a.iter().all(Value::is_u64)) -} diff --git a/schemars/tests/integration/bytes.rs b/schemars/tests/integration/bytes.rs deleted file mode 100644 index a0653b0..0000000 --- a/schemars/tests/integration/bytes.rs +++ /dev/null @@ -1,24 +0,0 @@ -use crate::prelude::*; -use bytes1::{Bytes, BytesMut}; - -#[test] -fn bytes() { - test!(Bytes) - .assert_snapshot() - .assert_allows_ser_roundtrip([Bytes::new(), Bytes::from_iter([12; 34])]) - .assert_matches_de_roundtrip(arbitrary_values_except( - is_array_of_u64, - "FIXME schema allows out-of-range positive integers", - )); -} - -#[test] -fn bytes_mut() { - test!(BytesMut).assert_identical::(); -} - -fn is_array_of_u64(value: &Value) -> bool { - value - .as_array() - .is_some_and(|a| a.iter().all(Value::is_u64)) -} diff --git a/schemars/tests/integration/chrono.rs b/schemars/tests/integration/chrono.rs deleted file mode 100644 index e7d5289..0000000 --- a/schemars/tests/integration/chrono.rs +++ /dev/null @@ -1,42 +0,0 @@ -use crate::prelude::*; -use chrono04::prelude::*; - -#[derive(JsonSchema, Serialize, Deserialize)] -struct ChronoTypes { - weekday: Weekday, - date_time: DateTime, - naive_date: NaiveDate, - naive_date_time: NaiveDateTime, - naive_time: NaiveTime, -} - -#[test] -fn chrono() { - test!(ChronoTypes).assert_snapshot(); - - test!(Weekday) - .assert_allows_ser_roundtrip([Weekday::Mon]) - .assert_matches_de_roundtrip(arbitrary_values()); - - test!(DateTime) - .assert_allows_ser_roundtrip_default() - .assert_matches_de_roundtrip(arbitrary_values()); - - test!(NaiveDate) - .assert_allows_ser_roundtrip_default() - .assert_matches_de_roundtrip(arbitrary_values()); - - test!(NaiveDateTime) - .assert_allows_ser_roundtrip_default() - .assert_matches_de_roundtrip(arbitrary_values_except( - Value::is_string, - "Custom format 'partial-date-time', so arbitrary strings technically allowed by schema", - )); - - test!(NaiveTime) - .assert_allows_ser_roundtrip_default() - .assert_matches_de_roundtrip(arbitrary_values_except( - Value::is_string, - "Custom format 'date-time', so arbitrary strings technically allowed by schema", - )); -} diff --git a/schemars/tests/integration/contract.rs b/schemars/tests/integration/contract.rs deleted file mode 100644 index 300a19c..0000000 --- a/schemars/tests/integration/contract.rs +++ /dev/null @@ -1,254 +0,0 @@ -use crate::prelude::*; - -#[derive(JsonSchema, Deserialize, Serialize)] -#[serde(rename_all(serialize = "SCREAMING-KEBAB-CASE"), deny_unknown_fields)] -struct StructDenyUnknownFields { - #[serde(skip_deserializing)] - read_only: bool, - #[allow(dead_code)] - #[serde(skip_serializing)] - write_only: bool, - #[serde(default)] - default: bool, - #[serde(skip_serializing_if = "core::ops::Not::not")] - skip_serializing_if: bool, - #[serde(rename(serialize = "ser_renamed", deserialize = "de_renamed"))] - renamed: bool, - option: Option, -} - -#[derive(JsonSchema, Deserialize, Serialize)] -struct StructAllowUnknownFields { - #[serde(flatten)] - inner: StructDenyUnknownFields, -} - -#[test] -fn struct_deny_unknown_fields() { - test!(StructDenyUnknownFields) - .assert_snapshot() - .assert_allows_de_roundtrip([ - json!({ "write_only": false, "skip_serializing_if": false, "de_renamed": false }), - json!({ "write_only": true, "skip_serializing_if": true, "de_renamed": true, "default": true }), - json!({ "write_only": true, "skip_serializing_if": true, "de_renamed": true, "option": true }), - ]) - .assert_rejects_de([ - json!({ "skip_serializing_if": false, "de_renamed": false }), - json!({ "write_only": false, "de_renamed": false }), - json!({ "write_only": false, "skip_serializing_if": false }), - json!({ "write_only": true, "skip_serializing_if": true, "de_renamed": true, "unknown": true }), - ]) - .assert_matches_de_roundtrip(arbitrary_values()); -} - -#[test] -fn struct_allow_unknown_fields() { - test!(StructAllowUnknownFields) - .assert_snapshot() - .assert_allows_de_roundtrip([ - json!({ "write_only": false, "skip_serializing_if": false, "de_renamed": false }), - json!({ "write_only": true, "skip_serializing_if": true, "de_renamed": true, "default": true }), - json!({ "write_only": true, "skip_serializing_if": true, "de_renamed": true, "option": true }), - json!({ "write_only": true, "skip_serializing_if": true, "de_renamed": true, "unknown": true }), - ]) - .assert_rejects_de([ - json!({ "skip_serializing_if": false, "de_renamed": false }), - json!({ "write_only": false, "de_renamed": false }), - json!({ "write_only": false, "skip_serializing_if": false }), - ]) - .assert_matches_de_roundtrip(arbitrary_values()); -} - -#[derive(JsonSchema, Deserialize, Serialize)] -struct TupleStruct( - String, - #[allow(dead_code)] - #[serde(skip_serializing)] - bool, - String, - #[serde(skip_deserializing)] bool, - String, -); - -#[test] -fn tuple_struct() { - test!(TupleStruct) - .assert_snapshot() - .assert_allows_de_roundtrip([json!(["", true, "", ""])]) - .assert_matches_de_roundtrip(arbitrary_values()); -} - -#[allow(dead_code)] -#[derive(JsonSchema, Deserialize, Serialize)] -#[serde( - rename_all(serialize = "SCREAMING-KEBAB-CASE"), - rename_all_fields(serialize = "PascalCase") -)] -enum ExternalEnum { - #[serde(skip_deserializing)] - ReadOnlyUnit, - #[serde(skip_serializing)] - WriteOnlyUnit, - #[serde(skip_deserializing)] - ReadOnlyStruct { s: String }, - #[serde(skip_serializing)] - WriteOnlyStruct { i: isize }, - #[serde(rename(serialize = "ser_renamed_unit", deserialize = "de_renamed_unit"))] - RenamedUnit, - #[serde(rename(serialize = "ser_renamed_struct", deserialize = "de_renamed_struct"))] - RenamedStruct { b: bool }, -} - -#[test] -fn externally_tagged_enum() { - test!(ExternalEnum) - .assert_snapshot() - .assert_allows_ser_roundtrip([ - ExternalEnum::ReadOnlyUnit, - ExternalEnum::ReadOnlyStruct { s: "test".into() }, - ExternalEnum::RenamedUnit, - ExternalEnum::RenamedStruct { b: true }, - ]) - .assert_allows_de_roundtrip([ - json!("WriteOnlyUnit"), - json!({ "WriteOnlyStruct": { "i": 123 } }), - json!("de_renamed_unit"), - json!({ "de_renamed_struct": { "b": true } }), - ]) - .assert_rejects_de([ - json!("READ-ONLY-UNIT"), - json!("ReadOnlyUnit"), - json!("ser_renamed_unit"), - ]) - .assert_matches_de_roundtrip(arbitrary_values()); -} - -#[allow(dead_code)] -#[derive(JsonSchema, Deserialize, Serialize)] -#[serde( - tag = "tag", - rename_all(serialize = "SCREAMING-KEBAB-CASE"), - rename_all_fields(serialize = "PascalCase") -)] -enum InternalEnum { - #[serde(skip_deserializing)] - ReadOnlyUnit, - #[serde(skip_serializing)] - WriteOnlyUnit, - #[serde(skip_deserializing)] - ReadOnlyStruct { s: String }, - #[serde(skip_serializing)] - WriteOnlyStruct { i: isize }, - #[serde(rename(serialize = "ser_renamed_unit", deserialize = "de_renamed_unit"))] - RenamedUnit, - #[serde(rename(serialize = "ser_renamed_struct", deserialize = "de_renamed_struct"))] - RenamedStruct { b: bool }, -} - -#[test] -fn internally_tagged_enum() { - test!(InternalEnum) - .assert_snapshot() - .assert_allows_ser_roundtrip([ - InternalEnum::ReadOnlyUnit, - InternalEnum::ReadOnlyStruct { s: "test".into() }, - InternalEnum::RenamedUnit, - InternalEnum::RenamedStruct { b: true }, - ]) - .assert_allows_de_roundtrip([ - json!({ "tag": "WriteOnlyUnit" }), - json!({ "tag": "WriteOnlyStruct", "i": 123 }), - json!({ "tag": "de_renamed_unit" }), - json!({ "tag": "de_renamed_struct", "b": true }), - ]) - .assert_rejects_de([ - json!({ "tag": "READ-ONLY-UNIT" }), - json!({ "tag": "ReadOnlyUnit" }), - json!({ "tag": "ser_renamed_unit" }), - ]) - .assert_matches_de_roundtrip(arbitrary_values()); -} - -#[allow(dead_code)] -#[derive(JsonSchema, Deserialize, Serialize)] -#[serde( - tag = "tag", - content = "content", - rename_all(serialize = "SCREAMING-KEBAB-CASE"), - rename_all_fields(serialize = "PascalCase") -)] -enum AdjacentEnum { - #[serde(skip_deserializing)] - ReadOnlyUnit, - #[serde(skip_serializing)] - WriteOnlyUnit, - #[serde(skip_deserializing)] - ReadOnlyStruct { s: String }, - #[serde(skip_serializing)] - WriteOnlyStruct { i: isize }, - #[serde(rename(serialize = "ser_renamed_unit", deserialize = "de_renamed_unit"))] - RenamedUnit, - #[serde(rename(serialize = "ser_renamed_struct", deserialize = "de_renamed_struct"))] - RenamedStruct { b: bool }, -} - -#[test] -fn adjacently_tagged_enum() { - test!(AdjacentEnum) - .assert_snapshot() - .assert_allows_ser_roundtrip([ - AdjacentEnum::ReadOnlyUnit, - AdjacentEnum::ReadOnlyStruct { s: "test".into() }, - AdjacentEnum::RenamedUnit, - AdjacentEnum::RenamedStruct { b: true }, - ]) - .assert_allows_de_roundtrip([ - json!({ "tag": "WriteOnlyUnit" }), - json!({ "tag": "WriteOnlyStruct", "content": { "i": 123 } }), - json!({ "tag": "de_renamed_unit" }), - json!({ "tag": "de_renamed_struct", "content": { "b": true } }), - ]) - .assert_rejects_de([ - json!({ "tag": "READ-ONLY-UNIT" }), - json!({ "tag": "ReadOnlyUnit" }), - json!({ "tag": "ser_renamed_unit" }), - ]) - .assert_matches_de_roundtrip(arbitrary_values()); -} - -#[allow(dead_code)] -#[derive(JsonSchema, Deserialize, Serialize)] -#[serde( - untagged, - rename_all(serialize = "SCREAMING-KEBAB-CASE"), - rename_all_fields(serialize = "PascalCase") -)] -enum UntaggedEnum { - #[serde(skip_deserializing)] - ReadOnlyUnit, - #[serde(skip_serializing)] - WriteOnlyUnit, - #[serde(skip_deserializing)] - ReadOnlyStruct { s: String }, - #[serde(skip_serializing)] - WriteOnlyStruct { i: isize }, - #[serde(rename(serialize = "ser_renamed_unit", deserialize = "de_renamed_unit"))] - RenamedUnit, - #[serde(rename(serialize = "ser_renamed_struct", deserialize = "de_renamed_struct"))] - RenamedStruct { b: bool }, -} - -#[test] -fn untagged_enum() { - test!(UntaggedEnum) - .assert_snapshot() - .assert_allows_ser_roundtrip([ - UntaggedEnum::ReadOnlyUnit, - UntaggedEnum::ReadOnlyStruct { s: "test".into() }, - UntaggedEnum::RenamedUnit, - UntaggedEnum::RenamedStruct { b: true }, - ]) - .assert_allows_de_roundtrip([json!(null), json!({ "i": 123 }), json!({ "b": true })]) - .assert_rejects_de([json!({ "s": "test" })]) - .assert_matches_de_roundtrip(arbitrary_values()); -} diff --git a/schemars/tests/integration/crate_alias.rs b/schemars/tests/integration/crate_alias.rs deleted file mode 100644 index f84fe22..0000000 --- a/schemars/tests/integration/crate_alias.rs +++ /dev/null @@ -1,19 +0,0 @@ -use crate::prelude::*; -use ::schemars as aliased_schemars; - -#[allow(dead_code)] -#[derive(aliased_schemars::JsonSchema, Deserialize, Serialize, Default)] -#[schemars(crate = "aliased_schemars")] -struct MyStruct { - /// Is it ok with doc comments? - foo: i32, - #[schemars(extend("x-test" = "...and extensions?"))] - bar: bool, -} - -#[test] -fn crate_alias() { - test!(MyStruct) - .assert_allows_ser_roundtrip_default() - .assert_matches_de_roundtrip(arbitrary_values()); -} diff --git a/schemars/tests/integration/decimal.rs b/schemars/tests/integration/decimal.rs deleted file mode 100644 index 77055df..0000000 --- a/schemars/tests/integration/decimal.rs +++ /dev/null @@ -1,19 +0,0 @@ -use crate::prelude::*; - -#[test] -fn decimal_types() { - #[cfg(feature = "rust_decimal1")] - test!(rust_decimal1::Decimal) - .assert_snapshot() - .assert_allows_ser_roundtrip_default() - .assert_matches_de_roundtrip(arbitrary_values()); - - #[cfg(feature = "bigdecimal04")] - test!(bigdecimal04::BigDecimal) - .assert_snapshot() - .assert_allows_ser_roundtrip_default() - .assert_matches_de_roundtrip(arbitrary_values()); - - #[cfg(all(feature = "rust_decimal1", feature = "bigdecimal04"))] - test!(bigdecimal04::BigDecimal).assert_identical::(); -} diff --git a/schemars/tests/integration/default.rs b/schemars/tests/integration/default.rs deleted file mode 100644 index 6df51cc..0000000 --- a/schemars/tests/integration/default.rs +++ /dev/null @@ -1,95 +0,0 @@ -use crate::prelude::*; - -#[derive(JsonSchema, Deserialize, Serialize, Default)] -#[serde(default)] -struct MyStruct { - integer: u32, - boolean: bool, - option_string: Option, - #[serde(skip_serializing_if = "str::is_empty")] - string_skip_empty: String, - #[serde(with = "struct_2_as_str")] - #[schemars(with = "str", pattern(r"^\d+ (true|false)$"))] - struct2: MyStruct2, - #[serde(skip_serializing)] - not_serialize: NotSerialize, -} - -#[derive(JsonSchema, Deserialize, Serialize, Default)] -#[serde(default = "ten_and_true")] -struct MyStruct2 { - #[serde(default = "six")] - integer: u32, - boolean: bool, -} - -#[allow(dead_code)] -#[derive(JsonSchema, Deserialize, Default)] -struct NotSerialize(i8); - -mod struct_2_as_str { - use super::MyStruct2; - - pub(super) fn serialize(value: &MyStruct2, ser: S) -> Result - where - S: serde::Serializer, - { - ser.collect_str(&format_args!("{} {}", value.integer, value.boolean)) - } - - pub(super) fn deserialize<'de, D>(deser: D) -> Result - where - D: serde::Deserializer<'de>, - { - use serde::de::{Deserialize, Error}; - let error = || Error::custom("invalid string"); - - let (i, b) = <&str>::deserialize(deser)? - .split_once(' ') - .ok_or_else(error)?; - - Ok(MyStruct2 { - integer: i.parse().map_err(|_| error())?, - boolean: b.parse().map_err(|_| error())?, - }) - } -} - -fn ten_and_true() -> MyStruct2 { - MyStruct2 { - integer: 10, - boolean: true, - } -} - -fn six() -> u32 { - 6 -} - -#[test] -fn default_fields() { - test!(MyStruct) - .assert_snapshot() - .assert_allows_ser_roundtrip([ - MyStruct::default(), - MyStruct { - integer: 123, - boolean: true, - option_string: Some("test".into()), - string_skip_empty: "test".into(), - struct2: ten_and_true(), - not_serialize: NotSerialize(42), - }, - ]) - .assert_allows_de_roundtrip([ - json!({}), - json!({ "not_serialize": 127 }) - ]) - .assert_rejects_de([ - json!({ "not_serialize": "a string" }) - ]) - .assert_matches_de_roundtrip(arbitrary_values_except( - Value::is_array, - "structs with `#derive(Deserialize)` can technically be deserialized from sequences, but that's not intended to be used via JSON, so schemars ignores it", - )); -} diff --git a/schemars/tests/integration/deprecated.rs b/schemars/tests/integration/deprecated.rs deleted file mode 100644 index 9bdfbef..0000000 --- a/schemars/tests/integration/deprecated.rs +++ /dev/null @@ -1,69 +0,0 @@ -#![allow(deprecated)] - -use crate::prelude::*; - -#[derive(JsonSchema, Default, Serialize, Deserialize)] -#[deprecated] -struct DeprecatedStruct { - foo: i32, - #[deprecated] - bar: bool, -} - -#[allow(deprecated)] -#[test] -fn deprecated_struct() { - test!(DeprecatedStruct) - .assert_snapshot() - .assert_allows_ser_roundtrip_default() - .custom(|schema, _| { - assert_eq!( - schema.as_value().pointer("/deprecated"), - Some(&Value::Bool(true)), - ); - assert_eq!( - schema.as_value().pointer("/properties/bar/deprecated"), - Some(&Value::Bool(true)), - ); - }); -} - -#[derive(JsonSchema, Default, Serialize, Deserialize)] -#[deprecated] -enum DeprecatedEnum { - #[default] - Unit, - #[deprecated] - DeprecatedUnitVariant, - #[deprecated] - DeprecatedStructVariant { - foo: i32, - #[deprecated] - deprecated_field: bool, - }, -} - -#[test] -fn deprecated_enum() { - test!(DeprecatedEnum) - .assert_snapshot() - .assert_allows_ser_roundtrip_default() - .custom(|schema, _| { - assert_eq!( - schema.as_value().pointer("/deprecated"), - Some(&Value::Bool(true)), - ); - assert_eq!( - schema.as_value().pointer("/oneOf/1/deprecated"), - Some(&Value::Bool(true)), - ); - assert_eq!( - schema.as_value().pointer("/oneOf/2/deprecated"), - Some(&Value::Bool(true)), - ); - assert_eq!( - schema.as_value().pointer("/oneOf/2/properties/DeprecatedStructVariant/properties/deprecated_field/deprecated"), - Some(&Value::Bool(true)), - ); - }); -} diff --git a/schemars/tests/integration/either.rs b/schemars/tests/integration/either.rs deleted file mode 100644 index 2e5a574..0000000 --- a/schemars/tests/integration/either.rs +++ /dev/null @@ -1,14 +0,0 @@ -use crate::prelude::*; -use either1::Either; - -#[test] -fn either() { - test!(Either>) - .assert_snapshot() - .assert_allows_ser_roundtrip([ - Either::Left(123), - Either::Right(Either::Left(true)), - Either::Right(Either::Right(())), - ]) - .assert_matches_de_roundtrip(arbitrary_values()); -} diff --git a/schemars/tests/integration/enum_repr.rs b/schemars/tests/integration/enum_repr.rs deleted file mode 100644 index f9a8841..0000000 --- a/schemars/tests/integration/enum_repr.rs +++ /dev/null @@ -1,37 +0,0 @@ -use crate::prelude::*; -use schemars::JsonSchema_repr; -use serde_repr::{Deserialize_repr, Serialize_repr}; - -#[derive(JsonSchema_repr, Deserialize_repr, Serialize_repr)] -#[repr(u8)] -#[serde(rename = "EnumWithReprAttr")] -/// Description from comment -pub enum Enum { - Zero, - One, - Five = 5, - Six, - Three = 3, -} - -#[test] -fn enum_repr() { - test!(Enum) - .assert_snapshot() - .assert_allows_ser_roundtrip([Enum::Zero, Enum::One, Enum::Five, Enum::Six, Enum::Three]) - .assert_allows_de_roundtrip([ - Value::from(0), - Value::from(1), - Value::from(5), - Value::from(6), - Value::from(3), - ]) - .assert_rejects_de([ - Value::from("Zero"), - Value::from("One"), - Value::from("Five"), - Value::from("Six"), - Value::from("Three"), - ]) - .assert_matches_de_roundtrip(arbitrary_values()); -} diff --git a/schemars/tests/integration/enums.rs b/schemars/tests/integration/enums.rs deleted file mode 100644 index f6cd6bc..0000000 --- a/schemars/tests/integration/enums.rs +++ /dev/null @@ -1,360 +0,0 @@ -use std::collections::BTreeMap; - -use crate::prelude::*; - -#[derive(JsonSchema, Deserialize, Serialize)] -struct UnitStruct; - -#[derive(JsonSchema, Deserialize, Serialize, Default)] -struct Struct { - foo: i32, - bar: bool, -} - -#[derive(JsonSchema, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -enum External { - UnitOne, - StringMap(BTreeMap), - UnitStructNewType(UnitStruct), - StructNewType(Struct), - Struct { - foo: i32, - bar: bool, - }, - Tuple(i32, bool), - UnitTwo, - #[serde(with = "unit_variant_as_u64")] - #[schemars(with = "u64")] - UnitAsInt, - #[serde(with = "tuple_variant_as_str")] - #[schemars(schema_with = "tuple_variant_as_str::json_schema")] - TupleAsStr(i32, bool), -} - -impl External { - fn values() -> impl IntoIterator { - [ - Self::UnitOne, - Self::StringMap( - [("hello".to_owned(), "world".to_owned())] - .into_iter() - .collect(), - ), - Self::UnitStructNewType(UnitStruct), - Self::StructNewType(Struct { - foo: 123, - bar: true, - }), - Self::Struct { - foo: 123, - bar: true, - }, - Self::Tuple(456, false), - Self::UnitTwo, - Self::UnitAsInt, - Self::TupleAsStr(789, true), - ] - } -} - -#[derive(JsonSchema, Deserialize, Serialize)] -#[serde(tag = "tag")] -enum Internal { - UnitOne, - StringMap(BTreeMap), - UnitStructNewType(UnitStruct), - StructNewType(Struct), - Struct { foo: i32, bar: bool }, - // Internally-tagged enums don't support tuple variants - // Tuple(i32, bool), - UnitTwo, - // Internally-tagged enum variants don't support non-object "payloads" - // #[serde(with = "unit_variant_as_u64")] - // #[schemars(with = "u64")] - // UnitAsInt, - // Internally-tagged enums don't support tuple variants - // #[serde(with = "tuple_variant_as_str")] - // #[schemars(schema_with = "tuple_variant_as_str::json_schema")] - // TupleAsStr(i32, bool), -} - -impl Internal { - fn values() -> impl IntoIterator { - [ - Self::UnitOne, - Self::StringMap( - [("hello".to_owned(), "world".to_owned())] - .into_iter() - .collect(), - ), - Self::UnitStructNewType(UnitStruct), - Self::StructNewType(Struct { - foo: 123, - bar: true, - }), - Self::Struct { - foo: 123, - bar: true, - }, - // Self::Tuple(456, false), - Self::UnitTwo, - // Self::UnitAsInt, - // Self::TupleAsStr(789, true), - ] - } -} - -#[derive(JsonSchema, Deserialize, Serialize)] -#[serde(tag = "tag", content = "content")] -enum Adjacent { - UnitOne, - StringMap(BTreeMap), - UnitStructNewType(UnitStruct), - StructNewType(Struct), - Struct { - foo: i32, - bar: bool, - }, - Tuple(i32, bool), - UnitTwo, - #[serde(with = "unit_variant_as_u64")] - #[schemars(with = "u64")] - UnitAsInt, - #[serde(with = "tuple_variant_as_str")] - #[schemars(schema_with = "tuple_variant_as_str::json_schema")] - TupleAsStr(i32, bool), -} - -impl Adjacent { - fn values() -> impl IntoIterator { - [ - Self::UnitOne, - Self::StringMap( - [("hello".to_owned(), "world".to_owned())] - .into_iter() - .collect(), - ), - Self::UnitStructNewType(UnitStruct), - Self::StructNewType(Struct { - foo: 123, - bar: true, - }), - Self::Struct { - foo: 123, - bar: true, - }, - Self::Tuple(456, false), - Self::UnitTwo, - Self::UnitAsInt, - Self::TupleAsStr(789, true), - ] - } -} - -#[derive(JsonSchema, Deserialize, Serialize)] -#[serde(untagged)] -enum Untagged { - UnitOne, - StringMap(BTreeMap), - UnitStructNewType(UnitStruct), - StructNewType(Struct), - Struct { - foo: i32, - bar: bool, - }, - Tuple(i32, bool), - UnitTwo, - #[serde(with = "unit_variant_as_u64")] - #[schemars(with = "u64")] - UnitAsInt, - #[serde(with = "tuple_variant_as_str")] - #[schemars(schema_with = "tuple_variant_as_str::json_schema")] - TupleAsStr(i32, bool), -} - -impl Untagged { - fn values() -> impl IntoIterator { - [ - Self::UnitOne, - Self::StringMap( - [("hello".to_owned(), "world".to_owned())] - .into_iter() - .collect(), - ), - Self::UnitStructNewType(UnitStruct), - Self::StructNewType(Struct { - foo: 123, - bar: true, - }), - Self::Struct { - foo: 123, - bar: true, - }, - Self::Tuple(456, false), - Self::UnitTwo, - Self::UnitAsInt, - Self::TupleAsStr(789, true), - ] - } -} - -mod unit_variant_as_u64 { - pub(super) fn serialize(ser: S) -> Result - where - S: serde::Serializer, - { - ser.serialize_u64(42) - } - - pub(super) fn deserialize<'de, D>(deser: D) -> Result<(), D::Error> - where - D: serde::Deserializer<'de>, - { - use serde::de::Deserialize; - - u64::deserialize(deser).map(|_| ()) - } -} - -mod tuple_variant_as_str { - pub(super) fn serialize(i: &i32, b: &bool, ser: S) -> Result - where - S: serde::Serializer, - { - ser.collect_str(&format_args!("{i} {b}")) - } - - pub(super) fn deserialize<'de, D>(deser: D) -> Result<(i32, bool), D::Error> - where - D: serde::Deserializer<'de>, - { - use serde::de::{Deserialize, Error}; - let error = || Error::custom("invalid string"); - - let (i, b) = <&str>::deserialize(deser)? - .split_once(' ') - .ok_or_else(error)?; - - Ok(( - i.parse().map_err(|_| error())?, - b.parse().map_err(|_| error())?, - )) - } - - pub(super) fn json_schema(_: &mut schemars::SchemaGenerator) -> schemars::Schema { - schemars::json_schema!({ - "type": "string", - "pattern": r"^\d+ (true|false)$" - }) - } -} - -#[test] -fn externally_tagged_enum() { - test!(External) - .assert_snapshot() - .assert_allows_ser_roundtrip(External::values()) - .assert_matches_de_roundtrip(arbitrary_values()); -} - -#[test] -fn internally_tagged_enum() { - test!(Internal) - .assert_snapshot() - .assert_allows_ser_roundtrip(Internal::values()) - .assert_matches_de_roundtrip(arbitrary_values()); -} - -#[test] -fn adjacently_tagged_enum() { - test!(Adjacent) - .assert_snapshot() - .assert_allows_ser_roundtrip(Adjacent::values()) - .assert_matches_de_roundtrip(arbitrary_values()); -} - -#[test] -fn untagged_enum() { - test!(Untagged) - .assert_snapshot() - .assert_allows_ser_roundtrip(Untagged::values()) - .assert_matches_de_roundtrip(arbitrary_values()); -} - -#[derive(JsonSchema, Serialize, Deserialize)] -enum NoVariants {} - -#[test] -fn no_variants() { - test!(NoVariants) - .assert_snapshot() - .assert_rejects_de(arbitrary_values()); -} - -#[derive(JsonSchema, Serialize, Deserialize)] -#[serde(rename_all_fields = "UPPERCASE", rename_all = "snake_case")] -enum Renamed { - StructVariant { - field: String, - }, - #[serde(rename = "custom name variant")] - RenamedStructVariant { - #[serde(rename = "custom name field")] - field: String, - }, -} - -#[test] -fn renamed() { - test!(Renamed) - .assert_snapshot() - .assert_allows_ser_roundtrip([ - Renamed::StructVariant { - field: "foo".to_owned(), - }, - Renamed::RenamedStructVariant { - field: "bar".to_owned(), - }, - ]) - .assert_rejects_de(arbitrary_values()); -} - -#[allow(dead_code)] -#[derive(JsonSchema, Deserialize, Serialize)] -enum SoundOfMusic { - /// # A deer - /// - /// A female deer - Do, - /// A drop of golden sun - Re, - /// A name I call myself - Mi, -} - -#[test] -fn unit_variants_with_doc_comments() { - test!(SoundOfMusic) - .assert_snapshot() - .assert_allows_ser_roundtrip([SoundOfMusic::Do, SoundOfMusic::Re, SoundOfMusic::Mi]) - .assert_rejects_de(arbitrary_values()) - .custom(|schema, _| { - assert_eq!( - schema.as_value().pointer("/oneOf/0/title"), - Some(&("A deer".into())), - ); - assert_eq!( - schema.as_value().pointer("/oneOf/0/description"), - Some(&("A female deer".into())), - ); - assert_eq!( - schema.as_value().pointer("/oneOf/1/description"), - Some(&("A drop of golden sun".into())), - ); - assert_eq!( - schema.as_value().pointer("/oneOf/2/description"), - Some(&("A name I call myself".into())), - ); - }); -} diff --git a/schemars/tests/integration/enums_deny_unknown_fields.rs b/schemars/tests/integration/enums_deny_unknown_fields.rs deleted file mode 100644 index e44b4f2..0000000 --- a/schemars/tests/integration/enums_deny_unknown_fields.rs +++ /dev/null @@ -1,209 +0,0 @@ -use crate::prelude::*; -use std::collections::BTreeMap; - -macro_rules! fn_values { - () => { - fn values() -> impl IntoIterator { - [ - Self::Unit, - Self::StringMap( - [("hello".to_owned(), "world".to_owned())] - .into_iter() - .collect(), - ), - Self::StructNewType(Struct { - foo: 123, - bar: true, - }), - Self::StructDenyUnknownFieldsNewType(StructDenyUnknownFields { - baz: 123, - foobar: true, - }), - Self::Struct { - foo: 123, - bar: true, - }, - ] - } - }; -} - -#[derive(JsonSchema, Deserialize, Serialize, Default)] -struct Struct { - foo: i32, - bar: bool, -} - -#[derive(JsonSchema, Deserialize, Serialize, Default)] -#[serde(deny_unknown_fields)] -struct StructDenyUnknownFields { - baz: i32, - foobar: bool, -} - -#[derive(JsonSchema, Deserialize, Serialize)] -#[serde(deny_unknown_fields)] -enum External { - Unit, - StringMap(BTreeMap), - StructNewType(Struct), - StructDenyUnknownFieldsNewType(StructDenyUnknownFields), - Struct { foo: i32, bar: bool }, -} - -impl External { - fn_values!(); -} - -#[derive(JsonSchema, Deserialize, Serialize)] -#[serde(tag = "tag", deny_unknown_fields)] -enum Internal { - Unit, - StringMap(BTreeMap), - StructNewType(Struct), - StructDenyUnknownFieldsNewType(StructDenyUnknownFields), - Struct { foo: i32, bar: bool }, -} - -impl Internal { - fn_values!(); -} - -#[derive(JsonSchema, Deserialize, Serialize)] -#[serde(tag = "tag", content = "content", deny_unknown_fields)] -enum Adjacent { - Unit, - StringMap(BTreeMap), - StructNewType(Struct), - StructDenyUnknownFieldsNewType(StructDenyUnknownFields), - Struct { foo: i32, bar: bool }, -} - -impl Adjacent { - fn_values!(); -} - -#[derive(JsonSchema, Deserialize, Serialize)] -#[serde(untagged, deny_unknown_fields)] -enum Untagged { - Unit, - StringMap(BTreeMap), - StructNewType(Struct), - StructDenyUnknownFieldsNewType(StructDenyUnknownFields), - Struct { foo: i32, bar: bool }, -} - -impl Untagged { - fn_values!(); -} - -#[test] -fn externally_tagged_enum() { - test!(External) - .assert_snapshot() - .assert_allows_ser_roundtrip(External::values()) - .assert_matches_de_roundtrip(arbitrary_values()) - .assert_rejects_de([ - json!({ - "Struct": { - "foo": 123, - "bar": true, - "extra": null - } - }), - json!({ - "StructDenyUnknownFieldsNewType": { - "baz": 123, - "foobar": true, - "extra": null - } - }), - ]) - .assert_allows_de_roundtrip([json!({ - "StructNewType": { - "foo": 123, - "bar": true, - "extra": null - } - })]); -} - -#[test] -fn internally_tagged_enum() { - test!(Internal) - .assert_snapshot() - .assert_allows_ser_roundtrip(Internal::values()) - .assert_matches_de_roundtrip(arbitrary_values()) - .assert_rejects_de([ - json!({ - "tag": "Struct", - "foo": 123, - "bar": true, - "extra": null - }), - json!({ - "tag": "StructDenyUnknownFieldsNewType", - "baz": 123, - "foobar": true, - "extra": null - }), - ]) - .assert_allows_de_roundtrip([json!({ - "tag": "StructNewType", - "foo": 123, - "bar": true, - "extra": null - })]); -} - -#[test] -fn adjacently_tagged_enum() { - test!(Adjacent) - .assert_snapshot() - .assert_allows_ser_roundtrip(Adjacent::values()) - .assert_matches_de_roundtrip(arbitrary_values()) - .assert_rejects_de([ - json!({ - "tag": "Struct", - "content": { - "foo": 123, - "bar": true, - "extra": null - } - }), - json!({ - "tag": "StructDenyUnknownFieldsNewType", - "content": { - "baz": 123, - "foobar": true, - "extra": null - } - }), - ]) - .assert_allows_de_roundtrip([json!({ - "tag": "StructNewType", - "content": { - "foo": 123, - "bar": true, - "extra": null - } - })]); -} - -#[test] -fn untagged_enum() { - test!(Untagged) - .assert_snapshot() - .assert_allows_ser_roundtrip(Untagged::values()) - .assert_matches_de_roundtrip(arbitrary_values()) - .assert_rejects_de([json!({ - "baz": 123, - "foobar": true, - "extra": null - })]) - .assert_allows_de_roundtrip([json!({ - "foo": 123, - "bar": true, - "extra": null - })]); -} diff --git a/schemars/tests/integration/enums_flattened.rs b/schemars/tests/integration/enums_flattened.rs deleted file mode 100644 index dd0f2f7..0000000 --- a/schemars/tests/integration/enums_flattened.rs +++ /dev/null @@ -1,135 +0,0 @@ -use crate::prelude::*; -use schemars::generate::SchemaSettings; - -macro_rules! fn_values { - () => { - fn values() -> impl IntoIterator { - [ - Self { - f: 1.23, - e1: Enum1::B(true), - e2: Enum2::F(4.56), - e3: Enum3::S2("abc".into()), - e4: Enum4::U2(789), - e5: Enum5::B3(false), - }, - Self { - f: 9.87, - e1: Enum1::S("def".into()), - e2: Enum2::U(654), - e3: Enum3::B2(true), - e4: Enum4::F2(3.21), - e5: Enum5::S3("ghi".into()), - }, - ] - } - }; -} - -#[derive(JsonSchema, Deserialize, Serialize)] -enum Enum1 { - B(bool), - S(String), -} - -#[derive(JsonSchema, Deserialize, Serialize)] -enum Enum2 { - U(u32), - F(f64), -} - -#[derive(JsonSchema, Deserialize, Serialize)] -enum Enum3 { - B2(bool), - S2(String), -} - -#[derive(JsonSchema, Deserialize, Serialize)] -enum Enum4 { - U2(u32), - F2(f64), -} - -#[derive(JsonSchema, Deserialize, Serialize)] -enum Enum5 { - B3(bool), - S3(String), -} - -#[derive(JsonSchema, Deserialize, Serialize)] -struct Container { - f: f32, - #[serde(flatten)] - e1: Enum1, - #[serde(flatten)] - e2: Enum2, - #[serde(flatten)] - e3: Enum3, - #[serde(flatten)] - e4: Enum4, - #[serde(flatten)] - e5: Enum5, -} - -impl Container { - fn_values!(); -} - -#[derive(JsonSchema, Deserialize, Serialize)] -#[serde(deny_unknown_fields)] -struct ContainerDenyUnknownFields { - f: f32, - #[serde(flatten)] - e1: Enum1, - #[serde(flatten)] - e2: Enum2, - #[serde(flatten)] - e3: Enum3, - #[serde(flatten)] - e4: Enum4, - #[serde(flatten)] - e5: Enum5, -} - -impl ContainerDenyUnknownFields { - fn_values!(); -} - -fn json_with_extra_field() -> Value { - json!({ - "f": 1.23, - "B": true, - "F": 4.56, - "S2": "abc", - "U2": 789, - "B3": false, - "extra": null - }) -} - -#[test] -fn enums_flattened() { - test!(Container) - .assert_snapshot() - .assert_allows_ser_roundtrip(Container::values()) - .assert_matches_de_roundtrip(arbitrary_values()) - .assert_allows_de_roundtrip([json_with_extra_field()]); -} - -#[test] -fn enums_flattened_deny_unknown_fields() { - test!(ContainerDenyUnknownFields) - .assert_snapshot() - .assert_allows_ser_roundtrip(ContainerDenyUnknownFields::values()) - .assert_matches_de_roundtrip(arbitrary_values()) - .assert_rejects_de([json_with_extra_field()]); -} - -#[test] -fn enums_flattened_deny_unknown_fields_draft07() { - test!(ContainerDenyUnknownFields, SchemaSettings::draft07()) - .assert_snapshot() - .assert_allows_ser_roundtrip(ContainerDenyUnknownFields::values()) - .assert_matches_de_roundtrip(arbitrary_values()) - .assert_rejects_de([json_with_extra_field()]); -} diff --git a/schemars/tests/integration/examples.rs b/schemars/tests/integration/examples.rs deleted file mode 100644 index 427a666..0000000 --- a/schemars/tests/integration/examples.rs +++ /dev/null @@ -1,16 +0,0 @@ -use crate::prelude::*; - -#[derive(Default, JsonSchema, Serialize)] -#[schemars(example = Struct::default(), example = ())] -struct Struct { - #[schemars(example = 4 + 4, example = ())] - foo: i32, - bar: bool, - #[schemars(example = (), example = &"foo")] - baz: Option<&'static str>, -} - -#[test] -fn examples() { - test!(Struct).assert_snapshot(); -} diff --git a/schemars/tests/integration/extend.rs b/schemars/tests/integration/extend.rs deleted file mode 100644 index e6f9506..0000000 --- a/schemars/tests/integration/extend.rs +++ /dev/null @@ -1,169 +0,0 @@ -#![allow(clippy::approx_constant)] - -use crate::prelude::*; - -static THREE: f64 = 3.0; - -#[allow(dead_code)] -#[derive(JsonSchema)] -#[schemars(extend("obj" = {"array": [null, ()]}))] -#[schemars(extend("3" = THREE), extend("pi" = THREE + 0.14))] -struct Struct { - #[schemars(extend("foo" = "bar"))] - value: Value, - #[schemars(extend("type" = ["number", "string"]))] - int: i32, -} - -#[test] -fn extend_struct() { - test!(Struct).assert_snapshot().custom(|schema, _| { - assert_eq!(schema.get("obj"), Some(&json!({ "array": [null, null] }))); - assert_eq!(schema.get("3"), Some(&json!(3.0))); - assert_eq!(schema.get("pi"), Some(&json!(3.14))); - assert_eq!( - schema.as_value().pointer("/properties/value"), - Some(&json!({ "foo": "bar" })) - ); - assert_eq!( - schema.as_value().pointer("/properties/int/type"), - Some(&json!(["number", "string"])) - ); - }); -} - -#[allow(dead_code)] -#[derive(JsonSchema)] -#[schemars(extend("obj" = {"array": [null, ()]}))] -#[schemars(extend("3" = THREE), extend("pi" = THREE + 0.14))] -struct TupleStruct( - #[schemars(extend("foo" = "bar"))] Value, - #[schemars(extend("type" = ["number", "string"]))] usize, -); - -#[test] -fn extend_tuple_struct() { - test!(TupleStruct).assert_snapshot().custom(|schema, _| { - assert_eq!(schema.get("obj"), Some(&json!({ "array": [null, null] }))); - assert_eq!(schema.get("3"), Some(&json!(3.0))); - assert_eq!(schema.get("pi"), Some(&json!(3.14))); - assert_eq!( - schema.as_value().pointer("/prefixItems/0"), - Some(&json!({ "foo": "bar" })) - ); - assert_eq!( - schema.as_value().pointer("/prefixItems/1/type"), - Some(&json!(["number", "string"])) - ); - }); -} - -#[allow(dead_code)] -#[derive(JsonSchema)] -#[schemars(extend("foo" = "bar"))] -enum ExternalEnum { - #[schemars(extend("foo" = "bar"))] - Unit, - #[schemars(extend("foo" = "bar"))] - NewType(Value), - #[schemars(extend("foo" = "bar"))] - Tuple(i32, bool), - #[schemars(extend("foo" = "bar"))] - Struct { i: i32, b: bool }, -} - -#[test] -fn extend_externally_tagged_enum() { - test!(ExternalEnum).assert_snapshot().custom(|schema, _| { - assert_eq!(schema.get("foo"), Some(&json!("bar"))); - - for i in 0..4 { - assert_eq!( - schema.as_value().pointer(&format!("/oneOf/{i}/foo")), - Some(&json!("bar")) - ); - } - }); -} - -#[allow(dead_code)] -#[derive(JsonSchema)] -#[schemars(tag = "t", extend("foo" = "bar"))] -enum InternalEnum { - #[schemars(extend("foo" = "bar"))] - Unit, - #[schemars(extend("foo" = "bar"))] - NewType(Value), - #[schemars(extend("foo" = "bar"))] - Struct { i: i32, b: bool }, -} - -#[test] -fn extend_internally_tagged_enum() { - test!(InternalEnum).assert_snapshot().custom(|schema, _| { - assert_eq!(schema.get("foo"), Some(&json!("bar"))); - - for i in 0..3 { - assert_eq!( - schema.as_value().pointer(&format!("/oneOf/{i}/foo")), - Some(&json!("bar")) - ); - } - }); -} - -#[allow(dead_code)] -#[derive(JsonSchema)] -#[schemars(tag = "t", content = "c", extend("foo" = "bar"))] -enum AdjacentEnum { - #[schemars(extend("foo" = "bar"))] - Unit, - #[schemars(extend("foo" = "bar"))] - NewType(Value), - #[schemars(extend("foo" = "bar"))] - Tuple(i32, bool), - #[schemars(extend("foo" = "bar"))] - Struct { i: i32, b: bool }, -} - -#[test] -fn extend_adjacently_tagged_enum() { - test!(AdjacentEnum).assert_snapshot().custom(|schema, _| { - assert_eq!(schema.get("foo"), Some(&json!("bar"))); - - for i in 0..4 { - assert_eq!( - schema.as_value().pointer(&format!("/oneOf/{i}/foo")), - Some(&json!("bar")) - ); - } - }); -} - -#[allow(dead_code)] -#[derive(JsonSchema)] -#[schemars(untagged, extend("foo" = "bar"))] -enum UntaggedEnum { - #[schemars(extend("foo" = "bar"))] - Unit, - #[schemars(extend("foo" = "bar"))] - NewType(Value), - #[schemars(extend("foo" = "bar"))] - Tuple(i32, bool), - #[schemars(extend("foo" = "bar"))] - Struct { i: i32, b: bool }, -} - -#[test] -fn extend_untagged_enum() { - test!(UntaggedEnum).assert_snapshot().custom(|schema, _| { - assert_eq!(schema.get("foo"), Some(&json!("bar"))); - - for i in 0..4 { - assert_eq!( - schema.as_value().pointer(&format!("/anyOf/{i}/foo")), - Some(&json!("bar")) - ); - } - }); -} diff --git a/schemars/tests/integration/flatten.rs b/schemars/tests/integration/flatten.rs deleted file mode 100644 index fe3bf83..0000000 --- a/schemars/tests/integration/flatten.rs +++ /dev/null @@ -1,93 +0,0 @@ -use crate::prelude::*; -use std::collections::BTreeMap; - -#[derive(JsonSchema, Deserialize, Serialize, Default)] -struct Flat { - f: f32, - b: bool, - #[serde(default, skip_serializing_if = "str::is_empty")] - s: String, - v: Vec, -} - -#[derive(JsonSchema, Deserialize, Serialize, Default)] -#[schemars(rename = "Flat")] -struct Deep1 { - f: f32, - #[serde(flatten)] - deep2: Deep2, - v: Vec, -} - -#[derive(JsonSchema, Deserialize, Serialize, Default)] -struct Deep2 { - b: bool, - #[serde(flatten, skip_serializing_if = "Option::is_none")] - deep3: Option, -} - -#[derive(JsonSchema, Deserialize, Serialize)] -struct Deep3 { - s: String, -} - -#[test] -fn flattened_struct() { - test!(Deep1) - .assert_snapshot() - .assert_identical::() - .assert_allows_ser_roundtrip([ - Deep1::default(), - Deep1 { - f: 1.0, - deep2: Deep2 { - b: true, - deep3: Some(Deep3 { - s: "test".to_owned(), - }), - }, - v: vec![123], - }, - ]) - .assert_matches_de_roundtrip(arbitrary_values()); -} - -#[derive(JsonSchema, Deserialize, Serialize, Default)] -struct FlattenValue { - flag: bool, - #[serde(flatten)] - value: Value, -} - -#[derive(JsonSchema, Deserialize, Serialize, Default)] -#[schemars(rename = "FlattenValue")] -struct FlattenMap { - flag: bool, - #[serde(flatten)] - value: BTreeMap, -} - -#[test] -fn flattened_value() { - test!(FlattenValue) - .assert_snapshot() - .assert_allows_ser_roundtrip([ - FlattenValue { - flag: false, - value: Value::Null, - }, - FlattenValue { - flag: true, - value: Value::Object(Default::default()), - }, - ]) - .assert_matches_de_roundtrip(arbitrary_values()); -} - -#[test] -fn flattened_map() { - test!(FlattenMap) - .assert_identical::() - .assert_allows_ser_roundtrip_default() - .assert_matches_de_roundtrip(arbitrary_values()); -} diff --git a/schemars/tests/integration/from_value.rs b/schemars/tests/integration/from_value.rs deleted file mode 100644 index 32afa1d..0000000 --- a/schemars/tests/integration/from_value.rs +++ /dev/null @@ -1,84 +0,0 @@ -use crate::prelude::*; -use schemars::generate::SchemaSettings; -use std::collections::BTreeMap; - -#[derive(JsonSchema, Deserialize, Serialize, Default, Clone)] -#[serde(rename_all = "camelCase")] -pub struct MyStruct { - pub my_int: i32, - pub my_bool: bool, - pub my_nullable_enum: Option, - pub my_inner_struct: MyInnerStruct, - #[serde(skip)] - pub _skip: i32, - #[serde(skip_serializing_if = "Option::is_none")] - pub skip_if_none: Option, -} - -#[derive(JsonSchema, Deserialize, Serialize, Default, Clone)] -pub struct MyInnerStruct { - pub my_map: BTreeMap, - pub my_vec: Vec, - pub my_empty_map: BTreeMap, - pub my_empty_vec: Vec, - pub my_tuple: (char, u8), -} - -#[derive(JsonSchema, Deserialize, Serialize, Clone)] -pub enum MyEnum { - NewType(String), - Struct { floats: Vec }, -} - -fn struct_value() -> MyStruct { - MyStruct { - my_int: 123, - my_bool: true, - my_nullable_enum: None, - my_inner_struct: MyInnerStruct { - my_map: [("k".to_owned(), 1.23)].into_iter().collect(), - my_vec: vec![1.0, 2.0, 3.0], - my_empty_map: BTreeMap::new(), - my_empty_vec: Vec::new(), - my_tuple: ('💩', 42), - }, - _skip: 123, - skip_if_none: None, - } -} - -#[test] -fn custom_struct() { - let value = struct_value(); - - test!(value: value.clone()) - .assert_snapshot() - .assert_allows_ser_roundtrip([value, MyStruct::default()]); -} - -#[test] -fn custom_struct_openapi3() { - let value = struct_value(); - - test!(value: value.clone(), SchemaSettings::openapi3()) - .assert_snapshot() - .assert_allows_ser_roundtrip([value, MyStruct::default()]); -} - -#[test] -fn json_value() { - let value = json!({ - "zero": 0, - "zeroPointZero": 0.0, - "bool": true, - "null": null, - "object": { - "strings": ["foo", "bar"], - "mixed": [1, true] - }, - }); - - test!(value: value.clone()) - .assert_snapshot() - .assert_allows_ser_roundtrip([value]); -} diff --git a/schemars/tests/integration/garde.rs b/schemars/tests/integration/garde.rs deleted file mode 100644 index e7ca2a5..0000000 --- a/schemars/tests/integration/garde.rs +++ /dev/null @@ -1,159 +0,0 @@ -use crate::prelude::*; -use garde::Validate; - -const ONE: usize = 1; -const HUNDRED: usize = 10; - -#[derive(JsonSchema, Deserialize, Serialize, Validate)] -pub struct GardeAttrStruct { - #[garde(range(min = 1.0, max = 100.0))] - min_max: f32, - #[garde(range(min = ONE as f32, max = HUNDRED as f32))] - min_max2: f32, - #[garde(pattern(r"^[Hh]ello"))] - regex_str: String, - #[garde(contains(concat!("sub","string...")))] - contains_str: String, - #[garde(email)] - email_address: String, - #[garde(url)] - homepage: String, - #[garde(length(min = ONE, max = HUNDRED))] - non_empty_str: String, - #[garde(length(equal = 2), inner(length(min = 1)))] - pair: Vec, - #[garde(required)] - required_option: Option, - #[garde(required, dive)] - #[serde(flatten)] - required_flattened: Option, -} - -#[derive(JsonSchema, Deserialize, Serialize, Validate)] -pub struct GardeAttrInner { - #[garde(range(min = -100, max = 100))] - x: i32, -} - -impl Default for GardeAttrStruct { - fn default() -> Self { - Self { - min_max: 1.0, - min_max2: 1.0, - regex_str: "Hello world".to_owned(), - contains_str: "Contains substring...".to_owned(), - email_address: "test@test.test".to_owned(), - homepage: "http://test.test".to_owned(), - non_empty_str: "test".to_owned(), - pair: vec!["a".to_owned(), "b".to_owned()], - required_option: Some(true), - required_flattened: Some(GardeAttrInner { x: 0 }), - } - } -} - -impl GardeAttrStruct { - pub fn invalid_values() -> impl IntoIterator { - static MUTATORS: &[fn(&mut GardeAttrStruct)] = &[ - |v| v.min_max = 0.9, - |v| v.min_max = 100.1, - |v| v.min_max2 = 0.9, - |v| v.min_max2 = 100.1, - |v| v.regex_str = "fail".to_owned(), - |v| v.contains_str = "fail".to_owned(), - |v| v.email_address = "fail".to_owned(), - |v| v.homepage = "fail".to_owned(), - |v| v.non_empty_str = String::new(), - |v| v.pair = Vec::new(), - |v| v.pair = vec!["a".to_owned(), "b".to_owned(), "c".to_owned()], - |v| v.pair = vec!["".to_owned(), "b".to_owned()], - |v| v.required_option = None, - |v| v.required_flattened = None, - |v| v.required_flattened = Some(GardeAttrInner { x: -101 }), - |v| v.required_flattened = Some(GardeAttrInner { x: 101 }), - ]; - MUTATORS.iter().map(|f| { - let mut result = GardeAttrStruct::default(); - f(&mut result); - result - }) - } -} - -#[test] -fn garde_attrs() { - test!(GardeAttrStruct) - .with_validator(|v| v.validate().is_ok()) - .assert_snapshot() - .assert_allows_ser_roundtrip_default() - .assert_rejects_invalid(GardeAttrStruct::invalid_values()) - .assert_matches_de_roundtrip(arbitrary_values()); -} - -#[allow(dead_code)] -#[derive(JsonSchema)] -#[schemars(rename = "GardeAttrStruct")] -pub struct SchemarsAttrStruct { - #[schemars(range(min = 1.0, max = 100.0))] - min_max: f32, - #[schemars(range(min = ONE as f32, max = HUNDRED as f32))] - min_max2: f32, - #[schemars(pattern(r"^[Hh]ello"))] - regex_str: String, - #[schemars(contains(concat!("sub","string...")))] - contains_str: String, - #[schemars(email)] - email_address: String, - #[schemars(url)] - homepage: String, - #[schemars(length(min = ONE, max = HUNDRED))] - non_empty_str: String, - #[schemars(length(equal = 2), inner(length(min = 1)))] - pair: Vec, - #[schemars(required)] - required_option: Option, - #[schemars(required)] - #[serde(flatten)] - required_flattened: Option, -} - -#[allow(dead_code)] -#[derive(JsonSchema)] -pub struct SchemarsAttrInner { - #[schemars(range(min = -100, max = 100))] - x: i32, -} - -#[test] -fn schemars_attrs() { - test!(SchemarsAttrStruct).assert_identical::(); -} - -#[derive(JsonSchema, Deserialize, Serialize, Validate)] -pub struct GardeAttrTuple( - #[garde(range(max = 10))] u8, - #[garde(required)] Option, -); - -#[test] -fn garde_attrs_tuple() { - test!(GardeAttrTuple) - .with_validator(|v| v.validate().is_ok()) - .assert_snapshot() - .assert_allows_ser_roundtrip([GardeAttrTuple(10, Some(false))]) - .assert_rejects_invalid([GardeAttrTuple(11, Some(false)), GardeAttrTuple(10, None)]) - .assert_matches_de_roundtrip(arbitrary_values()); -} - -#[derive(JsonSchema, Deserialize, Serialize, Validate)] -pub struct GardeAttrNewType(#[garde(range(max = 10))] u8); - -#[test] -fn garde_attrs_newtype() { - test!(GardeAttrNewType) - .with_validator(|v| v.validate().is_ok()) - .assert_snapshot() - .assert_allows_ser_roundtrip([GardeAttrNewType(10)]) - .assert_rejects_invalid([GardeAttrNewType(11)]) - .assert_matches_de_roundtrip(arbitrary_values()); -} diff --git a/schemars/tests/integration/indexmap.rs b/schemars/tests/integration/indexmap.rs deleted file mode 100644 index c6ef7d5..0000000 --- a/schemars/tests/integration/indexmap.rs +++ /dev/null @@ -1,19 +0,0 @@ -use crate::prelude::*; -use indexmap2::{indexmap, indexset, IndexMap, IndexSet}; -use std::collections::{BTreeMap, BTreeSet}; - -#[test] -fn indexmap() { - test!(IndexMap) - .assert_identical::>() - .assert_allows_ser_roundtrip([indexmap!(), indexmap!("key".to_owned() => true)]) - .assert_matches_de_roundtrip(arbitrary_values()); -} - -#[test] -fn indexset() { - test!(IndexSet) - .assert_identical::>() - .assert_allows_ser_roundtrip([indexset!(), indexset!("test".to_owned())]) - .assert_matches_de_roundtrip(arbitrary_values()); -} diff --git a/schemars/tests/integration/inline_subschemas.rs b/schemars/tests/integration/inline_subschemas.rs deleted file mode 100644 index 214a758..0000000 --- a/schemars/tests/integration/inline_subschemas.rs +++ /dev/null @@ -1,61 +0,0 @@ -use crate::prelude::*; -use schemars::generate::SchemaSettings; - -#[derive(JsonSchema, Deserialize, Serialize, Default)] -struct MyJob { - spec: MyJobSpec, -} - -#[derive(JsonSchema, Deserialize, Serialize, Default)] -struct MyJobSpec { - replicas: u32, -} - -#[test] -fn struct_normal() { - let settings = SchemaSettings::default().with(|s| s.inline_subschemas = true); - test!(MyJob, settings) - .assert_snapshot() - .assert_allows_ser_roundtrip_default() - .assert_matches_de_roundtrip(arbitrary_values()); -} - -#[derive(JsonSchema, Deserialize, Serialize)] -struct RecursiveOuter { - direct: Option>, - indirect: Option>, -} - -#[derive(JsonSchema, Deserialize, Serialize)] -struct RecursiveInner { - recursive: RecursiveOuter, -} - -#[test] -fn struct_recursive() { - let settings = SchemaSettings::default().with(|s| s.inline_subschemas = true); - test!(RecursiveOuter, settings) - .assert_snapshot() - .assert_allows_ser_roundtrip([ - RecursiveOuter { - direct: None, - indirect: None, - }, - RecursiveOuter { - direct: Some(Box::new(RecursiveOuter { - direct: None, - indirect: None, - })), - indirect: Some(Box::new(RecursiveInner { - recursive: RecursiveOuter { - direct: Some(Box::new(RecursiveOuter { - direct: None, - indirect: None, - })), - indirect: None, - }, - })), - }, - ]) - .assert_matches_de_roundtrip(arbitrary_values()); -} diff --git a/schemars/tests/integration/main.rs b/schemars/tests/integration/main.rs deleted file mode 100644 index eb44526..0000000 --- a/schemars/tests/integration/main.rs +++ /dev/null @@ -1,94 +0,0 @@ -#![allow(clippy::disallowed_names)] - -#[cfg(feature = "arrayvec07")] -mod arrayvec; -mod bound; -#[cfg(feature = "bytes1")] -mod bytes; -#[cfg(feature = "chrono04")] -mod chrono; -mod contract; -mod crate_alias; -#[cfg(any(feature = "rust_decimal1", feature = "bigdecimal04"))] -mod decimal; -mod default; -mod deprecated; -mod docs; -#[cfg(feature = "either1")] -mod either; -mod enum_repr; -mod enums; -mod enums_deny_unknown_fields; -mod enums_flattened; -mod examples; -mod extend; -mod flatten; -mod from_value; -mod garde; -#[cfg(feature = "indexmap2")] -mod indexmap; -mod inline_subschemas; -mod macros; -mod remote_derive; -mod same_name; -mod schema_name; -mod schema_with; -#[cfg(feature = "semver1")] -mod semver; -mod settings; -mod skip; -#[cfg(feature = "smallvec1")] -mod smallvec; -#[cfg(feature = "smol_str02")] -mod smol_str; -mod std_types; -mod structs; -mod transform; -mod transparent; -#[cfg(feature = "url2")] -mod url; -#[cfg(feature = "uuid1")] -mod uuid; -mod validator; - -mod prelude { - pub(crate) use crate::test; - pub(crate) use crate::test_helper::{arbitrary_values, arbitrary_values_except}; - pub(crate) use schemars::JsonSchema; - pub(crate) use serde::{Deserialize, Serialize}; - pub(crate) use serde_json::{json, Value}; -} - -mod test_helper; - -#[macro_export] -macro_rules! test_name { - () => {{ - fn f() {} - fn type_name_of_val(_: T) -> &'static str { - core::any::type_name::() - } - let test_fn_name = type_name_of_val(f) - .trim_end_matches("::f") - .split("::") - .last() - .unwrap(); - format!("{}~{}", core::file!(), test_fn_name) - }}; -} - -#[macro_export] -macro_rules! test { - ($type:ty, $settings:expr) => { - $crate::test_helper::TestHelper::<$type>::new($crate::test_name!(), $settings) - }; - ($type:ty) => { - test!($type, schemars::generate::SchemaSettings::default()) - }; - (value: $value:expr, $settings:expr) => { - $crate::test_helper::TestHelper::new_for_value($crate::test_name!(), $settings, $value) - }; - (value: $value:expr) => { - test!(value: $value, schemars::generate::SchemaSettings::default()) - }; -} diff --git a/schemars/tests/integration/remote_derive.rs b/schemars/tests/integration/remote_derive.rs deleted file mode 100644 index 89ecaaf..0000000 --- a/schemars/tests/integration/remote_derive.rs +++ /dev/null @@ -1,91 +0,0 @@ -use crate::prelude::*; - -mod external { - #[derive(Default)] - pub struct Duration { - pub secs: i64, - pub nanos: i32, - } - - #[allow(dead_code)] - pub enum Or { - A(A), - B(B), - } - - pub struct Str<'a>(pub &'a str); -} - -#[derive(JsonSchema, Deserialize, Serialize)] -#[serde(remote = "external::Duration")] -struct DurationDef { - secs: i64, - nanos: i32, -} - -#[derive(JsonSchema, Deserialize, Serialize, Default)] -struct Process { - #[serde(with = "DurationDef")] - wall_time: external::Duration, -} - -#[test] -fn simple() { - test!(Process) - .assert_snapshot() - .assert_allows_ser_roundtrip_default() - .assert_matches_de_roundtrip(arbitrary_values()); -} - -#[derive(JsonSchema, Deserialize, Serialize)] -#[serde(untagged, remote = "external::Or")] -enum OrDef { - A(A), - B(B), -} - -#[derive(JsonSchema, Deserialize, Serialize)] -#[serde(bound = "T: serde::de::DeserializeOwned + Serialize")] -struct TypeParam { - #[serde(with = "OrDef::")] - byte_or_bool: external::Or, - #[serde(with = "OrDef::<(), T>")] - unit_or_t: external::Or<(), T>, -} - -#[test] -fn type_param() { - test!(TypeParam) - .assert_snapshot() - .assert_allows_ser_roundtrip([ - TypeParam { - byte_or_bool: external::Or::A(123), - unit_or_t: external::Or::A(()), - }, - TypeParam { - byte_or_bool: external::Or::B(true), - unit_or_t: external::Or::B("test".to_owned()), - }, - ]) - .assert_matches_de_roundtrip(arbitrary_values()); -} - -#[allow(dead_code)] -#[derive(JsonSchema, Deserialize, Serialize)] -#[serde(remote = "external::Str")] -struct StrDef<'a>(&'a str); - -#[derive(JsonSchema, Deserialize, Serialize)] -struct LifetimeParam<'a> { - #[serde(borrow, with = "StrDef")] - s: external::Str<'a>, -} - -#[test] -fn lifetime_param() { - let s = external::Str("test"); - - test!(LifetimeParam) - .assert_snapshot() - .assert_allows_ser_only([LifetimeParam { s }]); -} diff --git a/schemars/tests/integration/same_name.rs b/schemars/tests/integration/same_name.rs deleted file mode 100644 index 02f3795..0000000 --- a/schemars/tests/integration/same_name.rs +++ /dev/null @@ -1,44 +0,0 @@ -use crate::prelude::*; - -mod a { - use super::*; - - #[derive(JsonSchema, Deserialize, Serialize, Default)] - pub struct Config { - test: String, - } -} - -mod b { - use super::*; - - #[derive(JsonSchema, Deserialize, Serialize, Default)] - pub struct Config { - test2: String, - } -} - -mod c { - use super::*; - - #[derive(JsonSchema, Deserialize, Serialize, Default)] - #[schemars(rename = "Config")] - pub struct Configuration { - test3: String, - } -} - -#[derive(JsonSchema, Deserialize, Serialize, Default)] -pub struct Config2 { - a_cfg: a::Config, - b_cfg: b::Config, - c_cfg: c::Configuration, -} - -#[test] -fn same_name() { - test!(Config2) - .assert_snapshot() - .assert_allows_ser_roundtrip_default() - .assert_matches_de_roundtrip(arbitrary_values()); -} diff --git a/schemars/tests/integration/schema_name.rs b/schemars/tests/integration/schema_name.rs deleted file mode 100644 index e04a747..0000000 --- a/schemars/tests/integration/schema_name.rs +++ /dev/null @@ -1,81 +0,0 @@ -use crate::prelude::*; - -#[derive(JsonSchema, Deserialize, Serialize, Default)] -struct SimpleStruct { - foo: i32, -} - -#[derive(JsonSchema, Deserialize, Serialize, Default)] -#[schemars(rename = "new-name")] -struct RenamedSimpleStruct { - foo: i32, -} - -#[test] -fn simple() { - test!(SimpleStruct) - .custom(|schema, _| assert_eq!(schema.get("title"), Some(&"SimpleStruct".into()))); - - test!(RenamedSimpleStruct) - .custom(|schema, _| assert_eq!(schema.get("title"), Some(&"new-name".into()))); -} - -#[derive(JsonSchema, Deserialize, Serialize, Default)] -struct TypeParams { - t: T, - u: U, - v: V, - w: W, -} - -#[derive(JsonSchema, Deserialize, Serialize, Default)] -#[schemars(rename = "new-name-{W}-{T}-{T}")] -struct RenamedTypeParams { - t: T, - u: U, - v: V, - w: W, -} - -#[test] -fn type_params() { - test!(TypeParams).custom(|schema, _| { - assert_eq!( - schema.get("title"), - Some(&"TypeParams_for_uint8_and_string_and_boolean_and_null".into()) - ) - }); - - test!(RenamedTypeParams).custom(|schema, _| { - assert_eq!( - schema.get("title"), - Some(&"new-name-null-uint8-uint8".into()) - ) - }); -} - -#[derive(JsonSchema, Deserialize, Serialize, Default)] -struct ConstGeneric { - #[schemars(range(max = INT))] - foo: i32, -} - -#[derive(JsonSchema, Deserialize, Serialize, Default)] -#[schemars(rename = "new-name-{INT}")] -struct RenamedConstGeneric { - #[schemars(range(max = INT))] - foo: i32, -} - -#[test] -fn const_generics() { - test!(ConstGeneric<123, 'X'>).custom(|schema, _| { - assert_eq!( - schema.get("title"), - Some(&"ConstGeneric_for_123_and_X".into()) - ) - }); - - test!(RenamedConstGeneric<123, 'X'>) - .custom(|schema, _| assert_eq!(schema.get("title"), Some(&"new-name-123".into()))); -} diff --git a/schemars/tests/integration/schema_with.rs b/schemars/tests/integration/schema_with.rs deleted file mode 100644 index e8c0a11..0000000 --- a/schemars/tests/integration/schema_with.rs +++ /dev/null @@ -1,46 +0,0 @@ -use crate::prelude::*; - -#[derive(JsonSchema, Deserialize, Serialize, Default)] -struct Struct { - #[serde(with = "int_as_str")] - #[schemars(schema_with = "int_as_str::json_schema")] - x: i64, -} - -mod int_as_str { - pub(super) fn serialize(value: &T, ser: S) -> Result - where - S: serde::Serializer, - T: std::fmt::Display, - { - ser.collect_str(value) - } - - pub(super) fn deserialize<'de, D, T>(deser: D) -> Result - where - D: serde::Deserializer<'de>, - T: std::str::FromStr, - { - <&str as serde::Deserialize>::deserialize(deser)? - .parse() - .map_err(serde::de::Error::custom) - } - - pub(super) fn json_schema(_: &mut schemars::SchemaGenerator) -> schemars::Schema { - schemars::json_schema!({ - "type": "string", - "pattern": r"^-?\d+$" - }) - } -} - -#[test] -fn schema_with() { - test!(Struct) - .assert_snapshot() - .assert_allows_ser_roundtrip_default() - .assert_matches_de_roundtrip(arbitrary_values_except( - Value::is_array, - "structs with `#derive(Deserialize)` can technically be deserialized from sequences, but that's not intended to be used via JSON, so schemars ignores it", - )); -} diff --git a/schemars/tests/integration/semver.rs b/schemars/tests/integration/semver.rs deleted file mode 100644 index 637b719..0000000 --- a/schemars/tests/integration/semver.rs +++ /dev/null @@ -1,32 +0,0 @@ -use crate::prelude::*; -use semver1::Version; - -#[test] -fn semver() { - test!(Version) - .assert_snapshot() - .assert_allows_de_roundtrip( - [ - "1.2.3", - "1.2.3-alpha4", - "1.2.3+build4", - "1.2.3+04", - "1.2.3-1.alpha.2+5.build.4.3-21", - ] - .into_iter() - .map(Value::from), - ) - .assert_rejects_de( - [ - "1.2", - "1.2.3.4", - "1.2.03", - "1.2.3-alpha..", - "1.2.3-alpha.04", - "1.2.3++", - ] - .into_iter() - .map(Value::from), - ) - .assert_matches_de_roundtrip(arbitrary_values()); -} diff --git a/schemars/tests/integration/settings.rs b/schemars/tests/integration/settings.rs deleted file mode 100644 index f6debe6..0000000 --- a/schemars/tests/integration/settings.rs +++ /dev/null @@ -1,68 +0,0 @@ -use crate::prelude::*; -use schemars::{generate::SchemaSettings, Schema}; - -#[derive(JsonSchema, Deserialize, Serialize, Default)] -pub struct OuterStruct { - #[schemars(extend("examples" = [8, null]))] - maybe_int: Option, - values: serde_json::Map, - value: Value, - inner: InnerEnum, - maybe_inner: Option, - tuples: Vec<(u8, i64)>, -} - -#[derive(JsonSchema, Deserialize, Serialize, Default)] -pub enum InnerEnum { - #[default] - UndocumentedUnit1, - UndocumentedUnit2, - /// This is a documented unit variant - DocumentedUnit, - ValueNewType(Value), -} - -#[test] -fn draft07() { - test!(OuterStruct, SchemaSettings::draft07()) - .assert_snapshot() - .assert_allows_ser_roundtrip_default() - .assert_matches_de_roundtrip(arbitrary_values()); -} - -#[test] -fn draft2019_09() { - test!(OuterStruct, SchemaSettings::draft2019_09()) - .assert_snapshot() - .assert_allows_ser_roundtrip_default() - .assert_matches_de_roundtrip(arbitrary_values()); -} - -#[test] -fn draft2020_12() { - test!(OuterStruct, SchemaSettings::draft2020_12()) - .assert_snapshot() - .assert_allows_ser_roundtrip_default() - .assert_matches_de_roundtrip(arbitrary_values()); -} - -#[test] -fn openapi3() { - let mut settings = SchemaSettings::openapi3(); - // Hack to apply recursive transforms to schemas at components.schemas: - // First, move them to $defs, then run the transforms, then move them back again. - settings.transforms.insert( - 0, - Box::new(|s: &mut Schema| { - let obj = s.ensure_object(); - let defs = obj["components"]["schemas"].take(); - obj.insert("$defs".to_owned(), defs); - }), - ); - settings.transforms.push(Box::new(|s: &mut Schema| { - let obj = s.ensure_object(); - obj["components"]["schemas"] = obj.remove("$defs").unwrap(); - })); - - test!(OuterStruct, settings).assert_snapshot(); -} diff --git a/schemars/tests/integration/skip.rs b/schemars/tests/integration/skip.rs deleted file mode 100644 index ea2c233..0000000 --- a/schemars/tests/integration/skip.rs +++ /dev/null @@ -1,41 +0,0 @@ -use crate::prelude::*; - -#[derive(JsonSchema, Deserialize, Serialize)] -#[serde(deny_unknown_fields)] -struct Struct { - #[serde(skip)] - _skipped: bool, - included: bool, -} - -#[test] -fn skip_struct_field() { - test!(Struct) - .assert_snapshot() - .assert_allows_de_roundtrip([json!({ "included": true })]) - .assert_rejects_de([json!({ - "_skipped": true, - "included": true - })]) - .assert_matches_de_roundtrip(arbitrary_values_except( - Value::is_array, - "structs with `#derive(Deserialize)` can technically be deserialized from sequences, but that's not intended to be used via JSON, so schemars ignores it", - )); -} - -#[derive(JsonSchema, Deserialize, Serialize)] -pub enum Enum { - Included1, - #[serde(skip)] - _Skipped, - Included2, -} - -#[test] -fn skip_enum_variants() { - test!(Enum) - .assert_snapshot() - .assert_allows_de_roundtrip([json!("Included1"), json!("Included2")]) - .assert_rejects_de([json!("_Skipped")]) - .assert_matches_de_roundtrip(arbitrary_values()); -} diff --git a/schemars/tests/integration/smallvec.rs b/schemars/tests/integration/smallvec.rs deleted file mode 100644 index 03b341b..0000000 --- a/schemars/tests/integration/smallvec.rs +++ /dev/null @@ -1,10 +0,0 @@ -use crate::prelude::*; -use smallvec1::{smallvec, SmallVec}; - -#[test] -fn smallvec() { - test!(SmallVec<[usize; 2]>) - .assert_identical::>() - .assert_allows_ser_roundtrip([smallvec![], smallvec![1, 2, 3, 4, 5]]) - .assert_matches_de_roundtrip(arbitrary_values()); -} diff --git a/schemars/tests/integration/smol_str.rs b/schemars/tests/integration/smol_str.rs deleted file mode 100644 index 9522c87..0000000 --- a/schemars/tests/integration/smol_str.rs +++ /dev/null @@ -1,11 +0,0 @@ -use smol_str02::SmolStr; - -use crate::prelude::*; - -#[test] -fn smol_str() { - test!(SmolStr) - .assert_identical::() - .assert_allows_ser_roundtrip(["".into(), "test".into()]) - .assert_matches_de_roundtrip(arbitrary_values()); -} diff --git a/schemars/tests/integration/snapshots/schemars/tests/integration/bytes.rs~bytes.de.json b/schemars/tests/integration/snapshots/schemars/tests/integration/bytes.rs~bytes.de.json deleted file mode 100644 index 65cbb8a..0000000 --- a/schemars/tests/integration/snapshots/schemars/tests/integration/bytes.rs~bytes.de.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "$schema": "https://json-schema.org/draft/2020-12/schema", - "title": "Bytes", - "type": [ - "array", - "string" - ], - "items": { - "type": "integer", - "format": "uint8", - "minimum": 0 - } -} \ No newline at end of file diff --git a/schemars/tests/integration/snapshots/schemars/tests/integration/contract.rs~struct_deny_unknown_fields.de.json b/schemars/tests/integration/snapshots/schemars/tests/integration/contract.rs~struct_deny_unknown_fields.de.json deleted file mode 100644 index b605204..0000000 --- a/schemars/tests/integration/snapshots/schemars/tests/integration/contract.rs~struct_deny_unknown_fields.de.json +++ /dev/null @@ -1,33 +0,0 @@ -{ - "$schema": "https://json-schema.org/draft/2020-12/schema", - "title": "StructDenyUnknownFields", - "type": "object", - "properties": { - "write_only": { - "type": "boolean", - "writeOnly": true - }, - "default": { - "type": "boolean", - "default": false - }, - "skip_serializing_if": { - "type": "boolean" - }, - "de_renamed": { - "type": "boolean" - }, - "option": { - "type": [ - "boolean", - "null" - ] - } - }, - "additionalProperties": false, - "required": [ - "write_only", - "skip_serializing_if", - "de_renamed" - ] -} \ No newline at end of file diff --git a/schemars/tests/integration/snapshots/schemars/tests/integration/contract.rs~struct_deny_unknown_fields.ser.json b/schemars/tests/integration/snapshots/schemars/tests/integration/contract.rs~struct_deny_unknown_fields.ser.json deleted file mode 100644 index fd118c6..0000000 --- a/schemars/tests/integration/snapshots/schemars/tests/integration/contract.rs~struct_deny_unknown_fields.ser.json +++ /dev/null @@ -1,35 +0,0 @@ -{ - "$schema": "https://json-schema.org/draft/2020-12/schema", - "title": "StructDenyUnknownFields", - "type": "object", - "properties": { - "READ-ONLY": { - "type": "boolean", - "readOnly": true, - "default": false - }, - "DEFAULT": { - "type": "boolean", - "default": false - }, - "SKIP-SERIALIZING-IF": { - "type": "boolean" - }, - "ser_renamed": { - "type": "boolean" - }, - "OPTION": { - "type": [ - "boolean", - "null" - ] - } - }, - "additionalProperties": false, - "required": [ - "READ-ONLY", - "DEFAULT", - "ser_renamed", - "OPTION" - ] -} \ No newline at end of file diff --git a/schemars/tests/integration/snapshots/schemars/tests/integration/decimal.rs~decimal_types.ser.json b/schemars/tests/integration/snapshots/schemars/tests/integration/decimal.rs~decimal_types.ser.json deleted file mode 100644 index e94ca27..0000000 --- a/schemars/tests/integration/snapshots/schemars/tests/integration/decimal.rs~decimal_types.ser.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "$schema": "https://json-schema.org/draft/2020-12/schema", - "title": "Decimal", - "type": "string", - "pattern": "^-?[0-9]+(\\.[0-9]+)?$" -} \ No newline at end of file diff --git a/schemars/tests/integration/snapshots/schemars/tests/integration/default.rs~default_fields.de.json b/schemars/tests/integration/snapshots/schemars/tests/integration/default.rs~default_fields.de.json deleted file mode 100644 index e3168e2..0000000 --- a/schemars/tests/integration/snapshots/schemars/tests/integration/default.rs~default_fields.de.json +++ /dev/null @@ -1,42 +0,0 @@ -{ - "$schema": "https://json-schema.org/draft/2020-12/schema", - "title": "MyStruct", - "type": "object", - "properties": { - "integer": { - "type": "integer", - "format": "uint32", - "minimum": 0, - "default": 0 - }, - "boolean": { - "type": "boolean", - "default": false - }, - "option_string": { - "type": [ - "string", - "null" - ], - "default": null - }, - "string_skip_empty": { - "type": "string" - }, - "struct2": { - "type": "string", - "pattern": "^\\d+ (true|false)$", - "default": "0 false" - }, - "not_serialize": { - "$ref": "#/$defs/NotSerialize", - "writeOnly": true - } - }, - "$defs": { - "NotSerialize": { - "type": "integer", - "format": "int8" - } - } -} \ No newline at end of file diff --git a/schemars/tests/integration/snapshots/schemars/tests/integration/default.rs~default_fields.ser.json b/schemars/tests/integration/snapshots/schemars/tests/integration/default.rs~default_fields.ser.json deleted file mode 100644 index f80c324..0000000 --- a/schemars/tests/integration/snapshots/schemars/tests/integration/default.rs~default_fields.ser.json +++ /dev/null @@ -1,38 +0,0 @@ -{ - "$schema": "https://json-schema.org/draft/2020-12/schema", - "title": "MyStruct", - "type": "object", - "properties": { - "integer": { - "type": "integer", - "format": "uint32", - "minimum": 0, - "default": 0 - }, - "boolean": { - "type": "boolean", - "default": false - }, - "option_string": { - "type": [ - "string", - "null" - ], - "default": null - }, - "string_skip_empty": { - "type": "string" - }, - "struct2": { - "type": "string", - "pattern": "^\\d+ (true|false)$", - "default": "0 false" - } - }, - "required": [ - "integer", - "boolean", - "option_string", - "struct2" - ] -} \ No newline at end of file diff --git a/schemars/tests/integration/snapshots/schemars/tests/integration/docs.rs~doc_comments_enum.ser.json b/schemars/tests/integration/snapshots/schemars/tests/integration/docs.rs~doc_comments_enum.ser.json deleted file mode 100644 index 3c6e680..0000000 --- a/schemars/tests/integration/snapshots/schemars/tests/integration/docs.rs~doc_comments_enum.ser.json +++ /dev/null @@ -1,46 +0,0 @@ -{ - "$schema": "https://json-schema.org/draft/2020-12/schema", - "title": "This is the enum's title", - "description": "This is \n the enum's description.", - "oneOf": [ - { - "type": "string", - "enum": [ - "UndocumentedUnit", - "UndocumentedUnit2" - ] - }, - { - "description": "This comment is included in the generated schema :)", - "type": "string", - "const": "DocumentedUnit" - }, - { - "title": "Complex variant", - "description": "This is a struct-like variant.", - "type": "object", - "properties": { - "Complex": { - "type": "object", - "properties": { - "my_nullable_string": { - "title": "A nullable string", - "description": "This field is a nullable string.\n\n This\nis\n the second\n line!\n\n\n\n\n And this is the third!", - "type": [ - "string", - "null" - ] - } - }, - "required": [ - "my_nullable_string" - ] - } - }, - "required": [ - "Complex" - ], - "additionalProperties": false - } - ] -} \ No newline at end of file diff --git a/schemars/tests/integration/snapshots/schemars/tests/integration/either.rs~either.json b/schemars/tests/integration/snapshots/schemars/tests/integration/either.rs~either.json deleted file mode 100644 index b97cf1f..0000000 --- a/schemars/tests/integration/snapshots/schemars/tests/integration/either.rs~either.json +++ /dev/null @@ -1,56 +0,0 @@ -{ - "$schema": "https://json-schema.org/draft/2020-12/schema", - "title": "Either_int32_or_Either_boolean_or_null", - "oneOf": [ - { - "type": "object", - "properties": { - "Left": { - "type": "integer", - "format": "int32" - } - }, - "additionalProperties": false, - "required": [ - "Left" - ] - }, - { - "type": "object", - "properties": { - "Right": { - "oneOf": [ - { - "type": "object", - "properties": { - "Left": { - "type": "boolean" - } - }, - "additionalProperties": false, - "required": [ - "Left" - ] - }, - { - "type": "object", - "properties": { - "Right": { - "type": "null" - } - }, - "additionalProperties": false, - "required": [ - "Right" - ] - } - ] - } - }, - "additionalProperties": false, - "required": [ - "Right" - ] - } - ] -} \ No newline at end of file diff --git a/schemars/tests/integration/snapshots/schemars/tests/integration/enums.rs~renamed.json b/schemars/tests/integration/snapshots/schemars/tests/integration/enums.rs~renamed.json deleted file mode 100644 index f2f5277..0000000 --- a/schemars/tests/integration/snapshots/schemars/tests/integration/enums.rs~renamed.json +++ /dev/null @@ -1,46 +0,0 @@ -{ - "$schema": "https://json-schema.org/draft/2020-12/schema", - "title": "Renamed", - "oneOf": [ - { - "type": "object", - "properties": { - "struct_variant": { - "type": "object", - "properties": { - "FIELD": { - "type": "string" - } - }, - "required": [ - "FIELD" - ] - } - }, - "required": [ - "struct_variant" - ], - "additionalProperties": false - }, - { - "type": "object", - "properties": { - "custom name variant": { - "type": "object", - "properties": { - "custom name field": { - "type": "string" - } - }, - "required": [ - "custom name field" - ] - } - }, - "required": [ - "custom name variant" - ], - "additionalProperties": false - } - ] -} \ No newline at end of file diff --git a/schemars/tests/integration/snapshots/schemars/tests/integration/examples.rs~examples.ser.json b/schemars/tests/integration/snapshots/schemars/tests/integration/examples.rs~examples.ser.json deleted file mode 100644 index 7de3378..0000000 --- a/schemars/tests/integration/snapshots/schemars/tests/integration/examples.rs~examples.ser.json +++ /dev/null @@ -1,41 +0,0 @@ -{ - "$schema": "https://json-schema.org/draft/2020-12/schema", - "title": "Struct", - "type": "object", - "properties": { - "foo": { - "type": "integer", - "format": "int32", - "examples": [ - 8, - null - ] - }, - "bar": { - "type": "boolean" - }, - "baz": { - "type": [ - "string", - "null" - ], - "examples": [ - null, - "foo" - ] - } - }, - "required": [ - "foo", - "bar", - "baz" - ], - "examples": [ - { - "foo": 0, - "bar": false, - "baz": null - }, - null - ] -} \ No newline at end of file diff --git a/schemars/tests/integration/snapshots/schemars/tests/integration/extend.rs~extend_tuple_struct.json b/schemars/tests/integration/snapshots/schemars/tests/integration/extend.rs~extend_tuple_struct.json deleted file mode 100644 index b62e241..0000000 --- a/schemars/tests/integration/snapshots/schemars/tests/integration/extend.rs~extend_tuple_struct.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "$schema": "https://json-schema.org/draft/2020-12/schema", - "title": "TupleStruct", - "type": "array", - "prefixItems": [ - { - "foo": "bar" - }, - { - "type": [ - "number", - "string" - ], - "format": "uint", - "minimum": 0 - } - ], - "minItems": 2, - "maxItems": 2, - "obj": { - "array": [ - null, - null - ] - }, - "3": 3.0, - "pi": 3.14 -} \ No newline at end of file diff --git a/schemars/tests/integration/snapshots/schemars/tests/integration/inline_subschemas.rs~struct_recursive.ser.json b/schemars/tests/integration/snapshots/schemars/tests/integration/inline_subschemas.rs~struct_recursive.ser.json deleted file mode 100644 index 584ee36..0000000 --- a/schemars/tests/integration/snapshots/schemars/tests/integration/inline_subschemas.rs~struct_recursive.ser.json +++ /dev/null @@ -1,70 +0,0 @@ -{ - "$schema": "https://json-schema.org/draft/2020-12/schema", - "title": "RecursiveOuter", - "type": "object", - "properties": { - "direct": { - "anyOf": [ - { - "$ref": "#/$defs/RecursiveOuter" - }, - { - "type": "null" - } - ] - }, - "indirect": { - "type": [ - "object", - "null" - ], - "properties": { - "recursive": { - "$ref": "#/$defs/RecursiveOuter" - } - }, - "required": [ - "recursive" - ] - } - }, - "required": [ - "direct", - "indirect" - ], - "$defs": { - "RecursiveOuter": { - "type": "object", - "properties": { - "direct": { - "anyOf": [ - { - "$ref": "#/$defs/RecursiveOuter" - }, - { - "type": "null" - } - ] - }, - "indirect": { - "type": [ - "object", - "null" - ], - "properties": { - "recursive": { - "$ref": "#/$defs/RecursiveOuter" - } - }, - "required": [ - "recursive" - ] - } - }, - "required": [ - "direct", - "indirect" - ] - } - } -} \ No newline at end of file diff --git a/schemars/tests/integration/snapshots/schemars/tests/integration/remote_derive.rs~lifetime_param.json b/schemars/tests/integration/snapshots/schemars/tests/integration/remote_derive.rs~lifetime_param.json deleted file mode 100644 index ff0112a..0000000 --- a/schemars/tests/integration/snapshots/schemars/tests/integration/remote_derive.rs~lifetime_param.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "$schema": "https://json-schema.org/draft/2020-12/schema", - "title": "LifetimeParam", - "type": "object", - "properties": { - "s": { - "$ref": "#/$defs/Str" - } - }, - "required": [ - "s" - ], - "$defs": { - "Str": { - "type": "string" - } - } -} \ No newline at end of file diff --git a/schemars/tests/integration/snapshots/schemars/tests/integration/semver.rs~semver.json b/schemars/tests/integration/snapshots/schemars/tests/integration/semver.rs~semver.json deleted file mode 100644 index 59bad08..0000000 --- a/schemars/tests/integration/snapshots/schemars/tests/integration/semver.rs~semver.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "$schema": "https://json-schema.org/draft/2020-12/schema", - "title": "SemVer", - "type": "string", - "pattern": "^(0|[1-9]\\d*)\\.(0|[1-9]\\d*)\\.(0|[1-9]\\d*)(?:-((?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\\.(?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\\+([0-9a-zA-Z-]+(?:\\.[0-9a-zA-Z-]+)*))?$" -} \ No newline at end of file diff --git a/schemars/tests/integration/snapshots/schemars/tests/integration/settings.rs~draft07.ser.json b/schemars/tests/integration/snapshots/schemars/tests/integration/settings.rs~draft07.ser.json deleted file mode 100644 index d76d990..0000000 --- a/schemars/tests/integration/snapshots/schemars/tests/integration/settings.rs~draft07.ser.json +++ /dev/null @@ -1,91 +0,0 @@ -{ - "$schema": "http://json-schema.org/draft-07/schema#", - "title": "OuterStruct", - "type": "object", - "properties": { - "maybe_int": { - "type": [ - "integer", - "null" - ], - "format": "int32", - "examples": [ - 8, - null - ] - }, - "values": { - "type": "object", - "additionalProperties": true - }, - "value": true, - "inner": { - "$ref": "#/definitions/InnerEnum" - }, - "maybe_inner": { - "anyOf": [ - { - "$ref": "#/definitions/InnerEnum" - }, - { - "type": "null" - } - ] - }, - "tuples": { - "type": "array", - "items": { - "type": "array", - "maxItems": 2, - "minItems": 2, - "items": [ - { - "type": "integer", - "format": "uint8", - "minimum": 0 - }, - { - "type": "integer", - "format": "int64" - } - ] - } - } - }, - "required": [ - "maybe_int", - "values", - "value", - "inner", - "maybe_inner", - "tuples" - ], - "definitions": { - "InnerEnum": { - "oneOf": [ - { - "type": "string", - "enum": [ - "UndocumentedUnit1", - "UndocumentedUnit2" - ] - }, - { - "description": "This is a documented unit variant", - "type": "string", - "const": "DocumentedUnit" - }, - { - "type": "object", - "properties": { - "ValueNewType": true - }, - "required": [ - "ValueNewType" - ], - "additionalProperties": false - } - ] - } - } -} \ No newline at end of file diff --git a/schemars/tests/integration/snapshots/schemars/tests/integration/settings.rs~draft2019_09.ser.json b/schemars/tests/integration/snapshots/schemars/tests/integration/settings.rs~draft2019_09.ser.json deleted file mode 100644 index 41c3237..0000000 --- a/schemars/tests/integration/snapshots/schemars/tests/integration/settings.rs~draft2019_09.ser.json +++ /dev/null @@ -1,91 +0,0 @@ -{ - "$schema": "https://json-schema.org/draft/2019-09/schema", - "title": "OuterStruct", - "type": "object", - "properties": { - "maybe_int": { - "type": [ - "integer", - "null" - ], - "format": "int32", - "examples": [ - 8, - null - ] - }, - "values": { - "type": "object", - "additionalProperties": true - }, - "value": true, - "inner": { - "$ref": "#/$defs/InnerEnum" - }, - "maybe_inner": { - "anyOf": [ - { - "$ref": "#/$defs/InnerEnum" - }, - { - "type": "null" - } - ] - }, - "tuples": { - "type": "array", - "items": { - "type": "array", - "maxItems": 2, - "minItems": 2, - "items": [ - { - "type": "integer", - "format": "uint8", - "minimum": 0 - }, - { - "type": "integer", - "format": "int64" - } - ] - } - } - }, - "required": [ - "maybe_int", - "values", - "value", - "inner", - "maybe_inner", - "tuples" - ], - "$defs": { - "InnerEnum": { - "oneOf": [ - { - "type": "string", - "enum": [ - "UndocumentedUnit1", - "UndocumentedUnit2" - ] - }, - { - "description": "This is a documented unit variant", - "type": "string", - "const": "DocumentedUnit" - }, - { - "type": "object", - "properties": { - "ValueNewType": true - }, - "required": [ - "ValueNewType" - ], - "additionalProperties": false - } - ] - } - } -} \ No newline at end of file diff --git a/schemars/tests/integration/snapshots/schemars/tests/integration/settings.rs~draft2020_12.ser.json b/schemars/tests/integration/snapshots/schemars/tests/integration/settings.rs~draft2020_12.ser.json deleted file mode 100644 index a200584..0000000 --- a/schemars/tests/integration/snapshots/schemars/tests/integration/settings.rs~draft2020_12.ser.json +++ /dev/null @@ -1,91 +0,0 @@ -{ - "$schema": "https://json-schema.org/draft/2020-12/schema", - "title": "OuterStruct", - "type": "object", - "properties": { - "maybe_int": { - "type": [ - "integer", - "null" - ], - "format": "int32", - "examples": [ - 8, - null - ] - }, - "values": { - "type": "object", - "additionalProperties": true - }, - "value": true, - "inner": { - "$ref": "#/$defs/InnerEnum" - }, - "maybe_inner": { - "anyOf": [ - { - "$ref": "#/$defs/InnerEnum" - }, - { - "type": "null" - } - ] - }, - "tuples": { - "type": "array", - "items": { - "type": "array", - "prefixItems": [ - { - "type": "integer", - "format": "uint8", - "minimum": 0 - }, - { - "type": "integer", - "format": "int64" - } - ], - "minItems": 2, - "maxItems": 2 - } - } - }, - "required": [ - "maybe_int", - "values", - "value", - "inner", - "maybe_inner", - "tuples" - ], - "$defs": { - "InnerEnum": { - "oneOf": [ - { - "type": "string", - "enum": [ - "UndocumentedUnit1", - "UndocumentedUnit2" - ] - }, - { - "description": "This is a documented unit variant", - "type": "string", - "const": "DocumentedUnit" - }, - { - "type": "object", - "properties": { - "ValueNewType": true - }, - "required": [ - "ValueNewType" - ], - "additionalProperties": false - } - ] - } - } -} \ No newline at end of file diff --git a/schemars/tests/integration/snapshots/schemars/tests/integration/settings.rs~openapi3.ser.json b/schemars/tests/integration/snapshots/schemars/tests/integration/settings.rs~openapi3.ser.json deleted file mode 100644 index 217541a..0000000 --- a/schemars/tests/integration/snapshots/schemars/tests/integration/settings.rs~openapi3.ser.json +++ /dev/null @@ -1,88 +0,0 @@ -{ - "$schema": "https://spec.openapis.org/oas/3.0/schema/2021-09-28#/definitions/Schema", - "title": "OuterStruct", - "type": "object", - "properties": { - "maybe_int": { - "type": "integer", - "format": "int32", - "nullable": true, - "example": 8 - }, - "values": { - "type": "object", - "additionalProperties": true - }, - "value": {}, - "inner": { - "$ref": "#/components/schemas/InnerEnum" - }, - "maybe_inner": { - "nullable": true, - "allOf": [ - { - "$ref": "#/components/schemas/InnerEnum" - } - ] - }, - "tuples": { - "type": "array", - "items": { - "type": "array", - "maxItems": 2, - "minItems": 2, - "items": [ - { - "type": "integer", - "format": "uint8", - "minimum": 0 - }, - { - "type": "integer", - "format": "int64" - } - ] - } - } - }, - "required": [ - "maybe_int", - "values", - "value", - "inner", - "maybe_inner", - "tuples" - ], - "components": { - "schemas": { - "InnerEnum": { - "oneOf": [ - { - "type": "string", - "enum": [ - "UndocumentedUnit1", - "UndocumentedUnit2" - ] - }, - { - "description": "This is a documented unit variant", - "type": "string", - "enum": [ - "DocumentedUnit" - ] - }, - { - "type": "object", - "properties": { - "ValueNewType": {} - }, - "required": [ - "ValueNewType" - ], - "additionalProperties": false - } - ] - } - } - } -} \ No newline at end of file diff --git a/schemars/tests/integration/snapshots/schemars/tests/integration/uuid.rs~uuid.json b/schemars/tests/integration/snapshots/schemars/tests/integration/uuid.rs~uuid.json deleted file mode 100644 index b6623b0..0000000 --- a/schemars/tests/integration/snapshots/schemars/tests/integration/uuid.rs~uuid.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "$schema": "https://json-schema.org/draft/2019-09/schema", - "title": "Uuid", - "type": "string", - "format": "uuid" -} \ No newline at end of file diff --git a/schemars/tests/integration/std_types.rs b/schemars/tests/integration/std_types.rs deleted file mode 100644 index 0ef2d7a..0000000 --- a/schemars/tests/integration/std_types.rs +++ /dev/null @@ -1,192 +0,0 @@ -use crate::prelude::*; -use std::ffi::{CStr, CString, OsStr, OsString}; -use std::marker::PhantomData; -use std::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6}; -use std::num::{NonZeroI64, NonZeroU64}; -use std::ops::{Bound, Range, RangeInclusive}; -use std::path::{Path, PathBuf}; -use std::time::{Duration, SystemTime}; - -#[test] -fn option() { - test!(Option) - .assert_allows_ser_roundtrip([Some(true), None]) - .assert_matches_de_roundtrip(arbitrary_values()); -} - -#[test] -fn result() { - test!(Result) - .assert_allows_ser_roundtrip([Ok(true), Err("oh no!".to_owned())]) - .assert_matches_de_roundtrip(arbitrary_values()); -} - -#[test] -fn nonzero() { - test!(NonZeroI64) - .assert_allows_ser_roundtrip([NonZeroI64::MIN, NonZeroI64::MAX]) - .assert_rejects_de([Value::from(0)]) - .assert_matches_de_roundtrip(arbitrary_values_except( - |v| v.as_u64().is_some_and(|u| u > i64::MAX as u64), - "FIXME schema allows out-of-range positive integers", - )); - - test!(NonZeroU64) - .assert_allows_ser_roundtrip([NonZeroU64::MIN, NonZeroU64::MAX]) - .assert_rejects_de([Value::from(0)]) - .assert_matches_de_roundtrip(arbitrary_values()); -} - -const IPV4_SAMPLES: [Ipv4Addr; 3] = [ - // Commented-out until https://github.com/Stranger6667/jsonschema-rs/issues/512 is fixed - // Ipv4Addr::UNSPECIFIED, - Ipv4Addr::LOCALHOST, - Ipv4Addr::BROADCAST, - Ipv4Addr::new(1, 2, 3, 4), -]; -const IPV6_SAMPLES: [Ipv6Addr; 4] = [ - Ipv6Addr::UNSPECIFIED, - Ipv6Addr::LOCALHOST, - Ipv4Addr::LOCALHOST.to_ipv6_mapped(), - Ipv6Addr::new(1, 2, 3, 4, 5, 6, 7, 8), -]; - -#[test] -fn ip_addr() { - test!(Ipv4Addr) - .assert_allows_ser_roundtrip(IPV4_SAMPLES) - .assert_matches_de_roundtrip(arbitrary_values()); - - test!(Ipv6Addr) - .assert_allows_ser_roundtrip(IPV6_SAMPLES) - .assert_matches_de_roundtrip(arbitrary_values()); - - test!(IpAddr) - .assert_allows_ser_roundtrip(IPV4_SAMPLES.map(Into::into)) - .assert_allows_ser_roundtrip(IPV6_SAMPLES.map(Into::into)) - .assert_matches_de_roundtrip(arbitrary_values_except( - Value::is_string, - "Custom format 'ip', so arbitrary strings technically allowed by schema", - )); -} - -#[test] -fn socket_addr() { - let port = 12345; - - test!(SocketAddrV4) - .assert_allows_ser_roundtrip(IPV4_SAMPLES.map(|ip| SocketAddrV4::new(ip, port))) - .assert_matches_de_roundtrip(arbitrary_values_except( - Value::is_string, - "Arbitrary strings allowed by schema", - )); - - test!(SocketAddrV6) - .assert_allows_ser_roundtrip(IPV6_SAMPLES.map(|ip| SocketAddrV6::new(ip, port, 0, 0))) - .assert_matches_de_roundtrip(arbitrary_values_except( - Value::is_string, - "Arbitrary strings allowed by schema", - )); - - test!(SocketAddr) - .assert_allows_ser_roundtrip(IPV4_SAMPLES.map(|ip| (ip, port).into())) - .assert_allows_ser_roundtrip(IPV6_SAMPLES.map(|ip| (ip, port).into())) - .assert_matches_de_roundtrip(arbitrary_values_except( - Value::is_string, - "Arbitrary strings allowed by schema", - )); -} - -#[test] -fn time() { - test!(SystemTime) - .assert_allows_ser_roundtrip([SystemTime::UNIX_EPOCH, SystemTime::now()]) - .assert_matches_de_roundtrip(arbitrary_values()); - - test!(Duration) - .assert_allows_ser_roundtrip([Duration::from_secs(0), Duration::from_secs_f64(123.456)]) - .assert_matches_de_roundtrip(arbitrary_values()); -} - -#[test] -fn c_strings() { - let strings = [ - CString::default(), - CString::new("test").unwrap(), - CString::new([255]).unwrap(), - ]; - - test!(CString) - .assert_allows_ser_roundtrip(strings.clone()) - .assert_matches_de_roundtrip(arbitrary_values_except( - |v| v.as_str().is_some_and(|s| s.contains('\0')), - "CString cannot contain null bytes, but schema does not enforce this", - )); - - test!(Box) - .assert_identical::() - .assert_allows_ser_roundtrip(strings.into_iter().map(Into::into)) - .assert_matches_de_roundtrip(arbitrary_values_except( - |v| v.as_str().is_some_and(|s| s.contains('\0')), - "CString cannot contain null bytes, but schema does not enforce this", - )); -} - -#[test] -fn os_strings() { - let strings = [OsString::new(), OsString::from("test")]; - - test!(OsString) - .assert_allows_ser_roundtrip(strings.clone()) - .assert_matches_de_roundtrip(arbitrary_values()); - - test!(Box) - .assert_identical::() - .assert_allows_ser_roundtrip(strings.into_iter().map(Into::into)) - .assert_matches_de_roundtrip(arbitrary_values()); -} - -#[test] -fn paths() { - let strings = [PathBuf::new(), PathBuf::from("test")]; - - test!(PathBuf) - .assert_identical::() - .assert_allows_ser_roundtrip(strings.clone()) - .assert_matches_de_roundtrip(arbitrary_values()); - - test!(Box) - .assert_identical::() - .assert_identical::() - .assert_allows_ser_roundtrip(strings.into_iter().map(Into::into)) - .assert_matches_de_roundtrip(arbitrary_values()); -} - -#[test] -fn bound() { - test!(Bound).assert_allows_ser_roundtrip([ - Bound::Included(123), - Bound::Excluded(456), - Bound::Unbounded, - ]); -} - -#[test] -fn ranges() { - test!(Range) - .assert_allows_ser_roundtrip([0..0, 123..456]) - .assert_matches_de_roundtrip(arbitrary_values()); - - test!(RangeInclusive) - .assert_allows_ser_roundtrip([0..=0, 123..=456]) - .assert_matches_de_roundtrip(arbitrary_values()); -} - -#[test] -fn phantom_data() { - struct DoesNotImplementJsonSchema; - - test!(PhantomData) - .assert_allows_ser_roundtrip_default() - .assert_matches_de_roundtrip(arbitrary_values()); -} diff --git a/schemars/tests/integration/structs.rs b/schemars/tests/integration/structs.rs deleted file mode 100644 index 1ed5017..0000000 --- a/schemars/tests/integration/structs.rs +++ /dev/null @@ -1,89 +0,0 @@ -use crate::prelude::*; - -#[derive(JsonSchema, Deserialize, Serialize, Default)] -struct UnitStruct; - -#[test] -fn unit() { - test!(UnitStruct) - .assert_snapshot() - .assert_allows_ser_roundtrip_default() - .assert_matches_de_roundtrip(arbitrary_values()); -} - -#[derive(JsonSchema, Deserialize, Serialize, Default)] -struct NormalStruct { - foo: String, - bar: bool, -} - -#[test] -fn normal() { - test!(NormalStruct) - .assert_snapshot() - .assert_allows_ser_roundtrip_default() - .assert_allows_de_roundtrip([json!({ - "foo": "", - "bar": true, - "unknown": 123 - })]) - .assert_matches_de_roundtrip(arbitrary_values()); -} - -#[derive(JsonSchema, Deserialize, Serialize, Default)] -struct NewType(String); - -#[test] -fn newtype() { - test!(NewType) - .assert_snapshot() - .assert_allows_ser_roundtrip_default() - .assert_matches_de_roundtrip(arbitrary_values()); -} - -#[derive(JsonSchema, Deserialize, Serialize, Default)] -struct TupleStruct(String, bool); - -#[test] -fn tuple() { - test!(TupleStruct) - .assert_snapshot() - .assert_allows_ser_roundtrip_default() - .assert_matches_de_roundtrip(arbitrary_values()); -} - -#[derive(JsonSchema, Deserialize, Serialize, Default)] -#[serde(rename_all = "camelCase")] -struct RenamedFields { - camel_case: i32, - #[serde(rename = "new_name")] - old_name: i32, -} - -#[test] -fn renamed_fields() { - test!(RenamedFields) - .assert_snapshot() - .assert_allows_ser_roundtrip_default() - .assert_matches_de_roundtrip(arbitrary_values()); -} - -#[derive(JsonSchema, Deserialize, Serialize, Default)] -#[serde(deny_unknown_fields)] -struct DenyUnknownFields { - foo: String, - bar: bool, -} - -#[test] -fn deny_unknown_fields() { - test!(DenyUnknownFields) - .assert_snapshot() - .assert_allows_ser_roundtrip_default() - .assert_rejects_de([json!({ - "foo": "", - "bar": true, - "unknown": 123 - })]) - .assert_matches_de_roundtrip(arbitrary_values()); -} diff --git a/schemars/tests/integration/test_helper.rs b/schemars/tests/integration/test_helper.rs deleted file mode 100644 index 64a3394..0000000 --- a/schemars/tests/integration/test_helper.rs +++ /dev/null @@ -1,430 +0,0 @@ -use jsonschema::Validator; -use schemars::{ - generate::{Contract, SchemaSettings}, - JsonSchema, Schema, -}; -use serde::{de::DeserializeOwned, Serialize}; -use serde_json::{json, Value}; -use snapbox::IntoJson; -use std::{ - any::type_name, borrow::Borrow, cell::OnceCell, f64, marker::PhantomData, path::Path, - sync::OnceLock, -}; - -pub struct TestHelper { - settings: SchemaSettings, - name: String, - phantom: PhantomData, - de_schema: Schema, - ser_schema: Schema, - de_schema_validator: OnceCell, - ser_schema_validator: OnceCell, - validator: fn(&T) -> bool, -} - -impl TestHelper { - /// Should be used via the `test!(SomeType)` macro - pub fn new(name: String, settings: SchemaSettings) -> Self { - let de_schema = schema_for::(&settings, Contract::Deserialize); - let ser_schema = schema_for::(&settings, Contract::Serialize); - Self { - settings, - name, - phantom: PhantomData, - de_schema, - ser_schema, - de_schema_validator: OnceCell::new(), - ser_schema_validator: OnceCell::new(), - validator: |_| true, - } - } - - /// Should be used via the `test!(value: SomeType)` macro - pub fn new_for_value(name: String, settings: SchemaSettings, value: T) -> Self - where - T: Serialize, - { - let de_schema = schema_for_value(&settings, Contract::Deserialize, &value); - let ser_schema = schema_for_value(&settings, Contract::Serialize, &value); - Self { - settings, - name, - phantom: PhantomData, - de_schema, - ser_schema, - de_schema_validator: OnceCell::new(), - ser_schema_validator: OnceCell::new(), - validator: |_| true, - } - } - - pub fn with_validator(&mut self, validator: fn(&T) -> bool) -> &mut Self { - self.validator = validator; - self - } - - /// Checks the generated schema against the saved schema in the snapshots directory, for manual verification of changes. - /// - /// Run tests with the SNAPSHOTS env var set to "overwrite" to overwrite any changed snapshots. - pub fn assert_snapshot(&self) -> &Self { - let common_path = format!("tests/integration/snapshots/{}.json", self.name); - let de_path = format!("tests/integration/snapshots/{}.de.json", self.name); - let ser_path = format!("tests/integration/snapshots/{}.ser.json", self.name); - - if self.de_schema == self.ser_schema { - snapbox::assert_data_eq!( - (&self.de_schema).into_json(), - snapbox::Data::read_from(Path::new(&common_path), None).raw() - ); - _ = std::fs::remove_file(de_path); - _ = std::fs::remove_file(ser_path); - } else { - snapbox::assert_data_eq!( - (&self.de_schema).into_json(), - snapbox::Data::read_from(Path::new(&de_path), None).raw() - ); - snapbox::assert_data_eq!( - (&self.ser_schema).into_json(), - snapbox::Data::read_from(Path::new(&ser_path), None).raw() - ); - _ = std::fs::remove_file(common_path); - } - - self - } - - /// Checks that the schema generated for this type is identical to that of another type. - pub fn assert_identical(&self) -> &Self { - snapbox::assert_data_eq!( - (&self.de_schema).into_json(), - schema_for::(&self.settings, Contract::Deserialize) - .into_json() - .raw() - ); - snapbox::assert_data_eq!( - (&self.ser_schema).into_json(), - schema_for::(&self.settings, Contract::Serialize) - .into_json() - .raw() - ); - - let t = type_name::(); - let t2 = type_name::(); - assert_eq!( - T::schema_name(), - T2::schema_name(), - "`{t}` and `{t2}` have identical schemas, so should have the same schema_name" - ); - - assert_eq!( - T::schema_id(), - T2::schema_id(), - "`{t}` and `{t2}` have identical schemas, so should have the same schema_id" - ); - - assert_eq!( - T::always_inline_schema(), - T2::always_inline_schema(), - "`{t}` and `{t2}` have identical schemas, so should have the same always_inline_schema" - ); - - self - } - - pub fn custom(&self, assertion: impl Fn(&Schema, Contract)) { - assertion(&self.de_schema, Contract::Deserialize); - assertion(&self.ser_schema, Contract::Serialize); - } - - fn de_schema_validate(&self, instance: &Value) -> bool { - self.de_schema_validator - .get_or_init(|| build_validator(&self.de_schema)) - .is_valid(instance) - } - - fn ser_schema_validate(&self, instance: &Value) -> bool { - self.ser_schema_validator - .get_or_init(|| build_validator(&self.ser_schema)) - .is_valid(instance) - } -} - -fn build_validator(schema: &Schema) -> Validator { - jsonschema::options() - .should_validate_formats(true) - .build(schema.as_value()) - .expect("valid schema") -} - -impl TestHelper { - /// Checks that the "serialize" schema allows the given sample values when serialized to JSON. - /// If `T implements `DeserializeOwned`, prefer using `assert_allows_ser_roundtrip()` - pub fn assert_allows_ser_only(&self, samples: impl IntoIterator) -> &Self { - for sample in samples { - let json = serde_json::to_value(&sample).unwrap(); - - assert!( - (self.validator)(&sample), - "invalid test case - attempt to serialize value failing validation: {json}" - ); - - assert!( - self.ser_schema_validate(&json), - "serialize schema should allow serialized value: {json}" - ); - } - - self - } -} - -impl TestHelper { - /// Checks that the "serialize" schema allows the given sample values when serialized to JSON - /// and, if the value can then be deserialized, that the "deserialize" schema also allows it. - pub fn assert_allows_ser_roundtrip(&self, samples: impl IntoIterator) -> &Self { - for sample in samples { - let json = serde_json::to_value(&sample).unwrap(); - - assert!( - (self.validator)(&sample), - "invalid test case - attempt to serialize value failing validation: {json}" - ); - - assert!( - self.ser_schema_validate(&json), - "serialize schema should allow serialized value: {json}" - ); - - if T::deserialize(&json).is_ok() { - assert!( - (self.validator)(&sample), - "invalid test case - roundtripped value fails validation: {json}" - ); - assert!( - self.de_schema_validate(&json), - "deserialize schema should allow value accepted by deserialization: {json}" - ); - } else { - assert!( - !self.de_schema_validate(&json), - "deserialize schema should reject undeserializable value: {json}" - ); - } - } - - self - } - - /// Checks that the "deserialize" schema allow the given sample values, and the "serialize" - /// schema allows the value obtained from deserializing then re-serializing the sample values - /// (only for values that can successfully be serialized). - /// - /// This is intended for types that have different serialize/deserialize schemas, or when you - /// want to test specific values that are valid for deserialization but not for serialization. - pub fn assert_allows_de_roundtrip( - &self, - samples: impl IntoIterator>, - ) -> &Self { - for sample in samples { - let sample = sample.borrow(); - let Ok(deserialized) = T::deserialize(sample) else { - panic!( - "expected deserialize to succeed for {}: {sample}", - type_name::() - ) - }; - - assert!( - (self.validator)(&deserialized), - "invalid test case - deserialized value fails validation: {sample}" - ); - - assert!( - self.de_schema_validate(sample), - "deserialize schema should allow value accepted by deserialization: {sample}" - ); - - if let Ok(serialized) = serde_json::to_value(&deserialized) { - assert!( - self.ser_schema_validate(&serialized), - "serialize schema should allow serialized value: {serialized}" - ); - } - } - - self - } - - /// Checks that the "deserialize" schema allows only the given sample values that successfully - /// deserialize and pass validation. - /// - /// This is intended to be given a range of values (see `arbitrary_values`), allowing limited - /// fuzzing. - pub fn assert_matches_de_roundtrip( - &self, - samples: impl IntoIterator>, - ) -> &Self { - for value in samples { - let value = value.borrow(); - - match T::deserialize(value) { - Ok(deserialized) if (self.validator)(&deserialized) => { - assert!( - self.de_schema_validate(value), - "deserialize schema should allow value accepted by deserialization: {value}" - ); - - if let Ok(serialized) = serde_json::to_value(&deserialized) { - assert!( - self.ser_schema_validate(&serialized), - "serialize schema should allow serialized value: {serialized}" - ); - } - } - _ => { - assert!( - !self.de_schema_validate(value), - "deserialize schema should reject invalid value: {value}" - ); - - // This assertion isn't necessarily valid in the general case but it would be - // odd (though not necessarily wrong) for it to fail. If this does ever fail - // a case that should be legitimate, then this assert can be removed/weakened. - assert!( - !self.ser_schema_validate(value), - "serialize schema should reject invalid value: {value}" - ); - } - } - } - - self - } - - /// Checks that the "deserialize" schema does not allow any of the given sample values. - /// - /// While `assert_matches_de_roundtrip()` would also work in this case, `assert_rejects_de()` - /// has the advantage that it also verifies that the test case itself is actually covering the - /// failure case as intended. - pub fn assert_rejects_de(&self, values: impl IntoIterator>) -> &Self { - for value in values { - let value = value.borrow(); - - assert!( - T::deserialize(value).is_err(), - "invalid test case - expected deserialize to fail for {}: {value}", - type_name::() - ); - - assert!( - !self.de_schema_validate(value), - "deserialize schema should reject invalid value: {value}" - ); - } - - self - } - - /// Checks that neither "serialize" nor "deserialize" schemas allow any of the given sample - /// values when serialized to JSON due to the values failing validation. - pub fn assert_rejects_invalid(&self, samples: impl IntoIterator) -> &Self { - for sample in samples { - let json = serde_json::to_value(&sample).unwrap(); - - assert!( - !(self.validator)(&sample), - "invalid test case - serialized value passes validation: {json}" - ); - - assert!( - !self.de_schema_validate(&json), - "deserialize schema should reject invalid value: {json}" - ); - assert!( - !self.ser_schema_validate(&json), - "serialize schema should reject invalid value: {json}" - ); - } - - self - } - - /// Checks that both the "serialize" and "deserialize" schema allow the type's default value - /// when serialized to JSON. - pub fn assert_allows_ser_roundtrip_default(&self) -> &Self - where - T: Default, - { - self.assert_allows_ser_roundtrip([T::default()]) - } -} - -fn schema_for(base_settings: &SchemaSettings, contract: Contract) -> Schema { - base_settings - .clone() - .with(|s| s.contract = contract) - .into_generator() - .into_root_schema_for::() -} - -fn schema_for_value( - base_settings: &SchemaSettings, - contract: Contract, - value: impl Serialize, -) -> Schema { - base_settings - .clone() - .with(|s| s.contract = contract) - .into_generator() - .into_root_schema_for_value(&value) - .unwrap() -} - -/// Returns an iterator over an selection of arbitrary JSON values. -/// -/// This is intended to be used as `test!(...).assert_matches_de_roundtrip(arbitrary_values())` -pub fn arbitrary_values() -> impl Iterator { - fn primitives() -> impl Iterator { - [ - Value::Null, - false.into(), - true.into(), - 0.into(), - 255.into(), - (-1).into(), - u64::MAX.into(), - f64::consts::PI.into(), - "".into(), - "0".into(), - "3E8".into(), - "\tPâté costs “£1”\0".into(), - Value::Array(Default::default()), - Value::Object(Default::default()), - ] - .into_iter() - } - - // TODO once MSRV has reached 1.80, replace this with LazyLock - static VALUES: OnceLock> = OnceLock::new(); - - VALUES - .get_or_init(|| { - Vec::from_iter( - primitives() - .chain(primitives().map(|p| json!([p]))) - .chain(primitives().map(|p| json!({"key": p}))), - ) - }) - .iter() -} - -/// Returns an iterator over an selection of arbitrary JSON values, except for value that match -/// the given filter predicate. -/// -/// This is to handle known cases of schemas not matching the actual deserialize behaviour. -pub fn arbitrary_values_except( - filter: impl Fn(&Value) -> bool, - _reason: &str, -) -> impl Iterator { - arbitrary_values().filter(move |v| !filter(v)) -} diff --git a/schemars/tests/integration/transform.rs b/schemars/tests/integration/transform.rs deleted file mode 100644 index 94e728a..0000000 --- a/schemars/tests/integration/transform.rs +++ /dev/null @@ -1,68 +0,0 @@ -use crate::prelude::*; -use schemars::{ - transform::{RecursiveTransform, Transform}, - Schema, -}; -use serde_json::Map; - -fn insert_upper_type(schema: &mut Schema) { - if let Some(Value::String(ty)) = schema.get("type") { - schema.insert("x-upperType".to_owned(), ty.to_uppercase().into()); - } -} - -fn insert_property_count(schema: &mut Schema) { - let count = schema - .get("properties") - .and_then(Value::as_object) - .map_or(0, Map::len); - schema.insert("x-propertyCount".to_owned(), count.into()); -} - -#[derive(JsonSchema, Deserialize, Serialize, Default)] -#[schemars(transform = RecursiveTransform(insert_upper_type), transform = insert_property_count)] -struct Struct { - value: Value, - #[schemars(transform = insert_property_count)] - int: i32, -} - -#[test] -fn transform_struct() { - test!(Struct) - .assert_snapshot() - .assert_allows_ser_roundtrip_default() - .custom(assert_upper_type_valid); -} - -#[derive(JsonSchema, Deserialize, Serialize, Default)] -#[schemars(transform = RecursiveTransform(insert_upper_type), transform = insert_property_count)] -enum External { - #[default] - #[schemars(transform = insert_property_count)] - Unit, - #[schemars(transform = insert_property_count)] - NewType(Value), -} - -#[test] -fn transform_enum() { - test!(External) - .assert_snapshot() - .assert_allows_ser_roundtrip_default() - .custom(assert_upper_type_valid); -} - -fn assert_upper_type_valid(schema: &Schema, _: schemars::generate::Contract) { - let mut schema = schema.clone(); - - RecursiveTransform(|s: &mut Schema| { - assert_eq!( - s.remove("x-upperType").map(|v| v.to_string()), - s.get("type").map(|v| v.to_string().to_uppercase()), - ); - }) - .transform(&mut schema); - - assert!(!schema.to_value().to_string().contains("x-upperType")); -} diff --git a/schemars/tests/integration/transparent.rs b/schemars/tests/integration/transparent.rs deleted file mode 100644 index 2268cc5..0000000 --- a/schemars/tests/integration/transparent.rs +++ /dev/null @@ -1,27 +0,0 @@ -use crate::prelude::*; - -#[derive(JsonSchema, Deserialize, Serialize, Default)] -#[serde(transparent)] -pub struct TransparentStruct { - inner: String, -} - -#[test] -fn transparent_struct() { - test!(TransparentStruct) - .assert_identical::() - .assert_allows_ser_roundtrip_default() - .assert_matches_de_roundtrip(arbitrary_values()); -} - -#[derive(JsonSchema, Deserialize, Serialize, Default)] -#[serde(transparent)] -pub struct TransparentNewType(String); - -#[test] -fn transparent_newtype() { - test!(TransparentNewType) - .assert_identical::() - .assert_allows_ser_roundtrip_default() - .assert_matches_de_roundtrip(arbitrary_values()); -} diff --git a/schemars/tests/integration/url.rs b/schemars/tests/integration/url.rs deleted file mode 100644 index 7f1c08a..0000000 --- a/schemars/tests/integration/url.rs +++ /dev/null @@ -1,14 +0,0 @@ -use crate::prelude::*; -use url2::Url; - -#[test] -fn url() { - test!(Url) - .assert_snapshot() - .assert_allows_ser_roundtrip( - ["http://example.com", "data:text/plain,test"] - .iter() - .map(|s| s.parse().unwrap()), - ) - .assert_matches_de_roundtrip(arbitrary_values()); -} diff --git a/schemars/tests/integration/uuid.rs b/schemars/tests/integration/uuid.rs deleted file mode 100644 index 0053226..0000000 --- a/schemars/tests/integration/uuid.rs +++ /dev/null @@ -1,12 +0,0 @@ -use crate::prelude::*; -use schemars::generate::SchemaSettings; -use uuid1::Uuid; - -#[test] -fn uuid() { - // Must run with draft 2019-09 due to https://github.com/Stranger6667/jsonschema-rs/issues/456 - test!(Uuid, SchemaSettings::draft2019_09()) - .assert_snapshot() - .assert_allows_ser_roundtrip([Uuid::nil(), Uuid::max(), Uuid::from_u128(1234567890)]) - .assert_matches_de_roundtrip(arbitrary_values()); -} diff --git a/schemars/tests/integration/validator.rs b/schemars/tests/integration/validator.rs deleted file mode 100644 index 44a2708..0000000 --- a/schemars/tests/integration/validator.rs +++ /dev/null @@ -1,135 +0,0 @@ -use crate::prelude::*; -use regex::Regex; -use validator::Validate; - -const ONE: f32 = 1.0; -const HUNDRED: f32 = 10.0; - -// In real code, this would use something like a LazyLock -fn hello_regex() -> Regex { - Regex::new(r"^[Hh]ello").unwrap() -} - -#[derive(JsonSchema, Deserialize, Serialize, Validate)] -pub struct ValidateAttrStruct { - #[validate(range(min = 1.0, max = 100.0))] - min_max: f32, - #[validate(range(min = ONE, max = HUNDRED))] - min_max2: f32, - #[validate(regex(path = hello_regex()))] - regex_str: String, - #[validate(contains(pattern = "substring..."))] - contains_str: String, - #[validate(email)] - email_address: String, - #[validate(url)] - homepage: String, - #[validate(length(min = 1, max = 100))] - non_empty_str: String, - #[validate(length(equal = 2))] - pair: Vec, - #[validate(required)] - required_option: Option, - #[validate(required, nested)] - #[serde(flatten)] - required_flattened: Option, -} - -#[derive(JsonSchema, Deserialize, Serialize, Validate)] -pub struct ValidateAttrInner { - #[validate(range(min = -100, max = 100))] - x: i32, -} - -impl Default for ValidateAttrStruct { - fn default() -> Self { - Self { - min_max: 1.0, - min_max2: 1.0, - regex_str: "Hello world".to_owned(), - contains_str: "Contains substring...".to_owned(), - email_address: "test@test.test".to_owned(), - homepage: "http://test.test".to_owned(), - non_empty_str: "test".to_owned(), - pair: vec!["a".to_owned(), "b".to_owned()], - required_option: Some(true), - required_flattened: Some(ValidateAttrInner { x: 0 }), - } - } -} - -impl ValidateAttrStruct { - pub fn invalid_values() -> impl IntoIterator { - static MUTATORS: &[fn(&mut ValidateAttrStruct)] = &[ - |v| v.min_max = 0.9, - |v| v.min_max = 100.1, - |v| v.min_max2 = 0.9, - |v| v.min_max2 = 100.1, - |v| v.regex_str = "fail".to_owned(), - |v| v.contains_str = "fail".to_owned(), - |v| v.email_address = "fail".to_owned(), - |v| v.homepage = "fail".to_owned(), - |v| v.non_empty_str = String::new(), - |v| v.pair = Vec::new(), - |v| v.pair = vec!["a".to_owned(), "b".to_owned(), "c".to_owned()], - |v| v.required_option = None, - |v| v.required_flattened = None, - |v| v.required_flattened = Some(ValidateAttrInner { x: -101 }), - |v| v.required_flattened = Some(ValidateAttrInner { x: 101 }), - ]; - MUTATORS.iter().map(|f| { - let mut result = ValidateAttrStruct::default(); - f(&mut result); - result - }) - } -} - -#[test] -fn validate_attrs() { - test!(ValidateAttrStruct) - .with_validator(|v| v.validate().is_ok()) - .assert_snapshot() - .assert_allows_ser_roundtrip_default() - .assert_rejects_invalid(ValidateAttrStruct::invalid_values()) - .assert_matches_de_roundtrip(arbitrary_values()); -} - -#[allow(dead_code)] -#[derive(JsonSchema)] -#[schemars(rename = "ValidateAttrStruct")] -pub struct SchemarsAttrStruct { - #[schemars(range(min = 1.0, max = 100.0))] - min_max: f32, - #[schemars(range(min = ONE, max = HUNDRED))] - min_max2: f32, - #[schemars(regex(pattern = hello_regex()))] - regex_str: String, - #[schemars(contains(pattern = "substring..."))] - contains_str: String, - #[schemars(email)] - email_address: String, - #[schemars(url)] - homepage: String, - #[schemars(length(min = 1, max = 100))] - non_empty_str: String, - #[schemars(length(equal = 2))] - pair: Vec, - #[schemars(required)] - required_option: Option, - #[schemars(required)] - #[serde(flatten)] - required_flattened: Option, -} - -#[allow(dead_code)] -#[derive(JsonSchema)] -pub struct SchemarsAttrInner { - #[schemars(range(min = -100, max = 100))] - x: i32, -} - -#[test] -fn schemars_attrs() { - test!(SchemarsAttrStruct).assert_identical::(); -} diff --git a/schemars/tests/integration/macros.rs b/schemars/tests/macro.rs similarity index 70% rename from schemars/tests/integration/macros.rs rename to schemars/tests/macro.rs index 92c3370..25323ca 100644 --- a/schemars/tests/integration/macros.rs +++ b/schemars/tests/macro.rs @@ -1,10 +1,13 @@ -use crate::prelude::*; +mod util; +use schemars::JsonSchema; +use util::*; macro_rules! build_struct { ( $id:ident { $($t:tt)* } ) => { - #[derive(JsonSchema, Deserialize, Serialize, Default)] + #[allow(dead_code)] + #[derive(JsonSchema)] pub struct $id { x: u8, $($t)* @@ -15,8 +18,8 @@ macro_rules! build_struct { build_struct!(A { v: i32 }); #[test] -fn macro_built_struct() { - test!(A).assert_allows_ser_roundtrip_default(); +fn macro_built_struct() -> TestResult { + test_default_generated_schema::("macro_built_struct") } macro_rules! build_enum { @@ -51,9 +54,9 @@ macro_rules! build_enum { } build_enum!( - #[derive(JsonSchema, Deserialize, Serialize)] + #[derive(JsonSchema)] OuterEnum { - #[derive(JsonSchema, Deserialize, Serialize, Default)] + #[derive(JsonSchema)] InnerStruct { x: i32 } @@ -62,6 +65,6 @@ build_enum!( ); #[test] -fn macro_built_enum() { - test!(OuterEnum).assert_allows_ser_roundtrip([OuterEnum::InnerStruct(InnerStruct::default())]); +fn macro_built_enum() -> TestResult { + test_default_generated_schema::("macro_built_enum") } diff --git a/schemars/tests/no_std.rs b/schemars/tests/no_std.rs new file mode 100644 index 0000000..c011aa2 --- /dev/null +++ b/schemars/tests/no_std.rs @@ -0,0 +1,25 @@ +#![no_std] + +mod util; +use schemars::JsonSchema; +use util::*; + +extern crate alloc as test_alloc; + +#[derive(JsonSchema)] +pub struct MyStruct { + pub my_int: i32, + pub my_bool: bool, + pub my_nullable_enum: Option, +} + +#[derive(JsonSchema)] +pub enum MyEnum { + StringNewType(test_alloc::string::String), + StructVariant { floats: test_alloc::vec::Vec }, +} + +#[test] +fn no_std() -> TestResult { + test_default_generated_schema::("no_std") +} diff --git a/schemars/tests/nonzero_ints.rs b/schemars/tests/nonzero_ints.rs new file mode 100644 index 0000000..22623fa --- /dev/null +++ b/schemars/tests/nonzero_ints.rs @@ -0,0 +1,17 @@ +mod util; +use schemars::JsonSchema; +use util::*; + +#[allow(dead_code)] +#[derive(JsonSchema)] +struct MyStruct { + unsigned: u32, + nonzero_unsigned: std::num::NonZeroU32, + signed: i32, + nonzero_signed: std::num::NonZeroI32, +} + +#[test] +fn nonzero_ints() -> TestResult { + test_default_generated_schema::("nonzero_ints") +} diff --git a/schemars/tests/property_name.rs b/schemars/tests/property_name.rs new file mode 100644 index 0000000..aab52a7 --- /dev/null +++ b/schemars/tests/property_name.rs @@ -0,0 +1,20 @@ +mod util; +use schemars::JsonSchema; +use util::*; + +#[allow(dead_code)] +#[derive(JsonSchema)] +#[serde(rename_all = "camelCase")] +struct MyStruct { + camel_case: i32, + #[serde(rename = "new_name_1")] + old_name_1: i32, + #[serde(rename = "ignored")] + #[schemars(rename = "new_name_2")] + old_name_2: i32, +} + +#[test] +fn set_struct_property_names() -> TestResult { + test_default_generated_schema::("property-name-struct") +} diff --git a/schemars/tests/range.rs b/schemars/tests/range.rs new file mode 100644 index 0000000..0dad219 --- /dev/null +++ b/schemars/tests/range.rs @@ -0,0 +1,17 @@ +mod util; +use schemars::JsonSchema; +use std::ops::{Bound, Range, RangeInclusive}; +use util::*; + +#[allow(dead_code)] +#[derive(JsonSchema)] +struct MyStruct { + range: Range, + inclusive: RangeInclusive, + bound: Bound, +} + +#[test] +fn result() -> TestResult { + test_default_generated_schema::("range") +} diff --git a/schemars/tests/remote_derive.rs b/schemars/tests/remote_derive.rs new file mode 100644 index 0000000..dc349c6 --- /dev/null +++ b/schemars/tests/remote_derive.rs @@ -0,0 +1,45 @@ +mod util; + +use other_crate::Duration; +use schemars::JsonSchema; +use serde::Serialize; +use util::*; + +mod other_crate { + #[derive(Default)] + pub struct Duration { + pub secs: i64, + pub nanos: i32, + } +} + +#[derive(JsonSchema, Serialize)] +#[serde(remote = "Duration")] +struct DurationDef { + secs: i64, + nanos: i32, +} + +fn custom_serialize(value: &Duration, ser: S) -> Result +where + S: serde::Serializer, +{ + ser.collect_str(&format_args!("{}.{:09}s", value.secs, value.nanos)) +} + +#[derive(JsonSchema, Serialize)] +struct Process { + command_line: String, + #[serde(with = "DurationDef")] + wall_time: Duration, + #[serde(default, with = "DurationDef")] + user_cpu_time: Duration, + #[serde(default, serialize_with = "custom_serialize")] + #[schemars(with = "DurationDef")] + system_cpu_time: Duration, +} + +#[test] +fn remote_derive_json_schema() -> TestResult { + test_default_generated_schema::("remote_derive") +} diff --git a/schemars/tests/remote_derive_generic.rs b/schemars/tests/remote_derive_generic.rs new file mode 100644 index 0000000..53fb7d2 --- /dev/null +++ b/schemars/tests/remote_derive_generic.rs @@ -0,0 +1,49 @@ +mod util; + +use schemars::JsonSchema; +use serde::Serialize; +use std::collections::{BTreeMap, BTreeSet}; +use util::*; + +#[allow(dead_code)] +enum Or { + A(A), + B(B), +} + +#[derive(JsonSchema, Serialize)] +#[serde(untagged, remote = "Or")] +enum OrDef { + A(A), + B(B), +} + +struct Str<'a>(&'a str); + +#[allow(dead_code)] +#[derive(JsonSchema, Serialize)] +#[serde(remote = "Str")] +struct StrDef<'a>(&'a str); + +#[derive(JsonSchema, Serialize)] +struct MyStruct<'a, T: Serialize> { + // #[serde(with = "OrDef::<_, _>")] + // byte_or_bool1: Or, + #[serde(with = "OrDef::")] + byte_or_bool2: Or, + // #[serde(with = "OrDef::<_, _>")] + // unit_or_t1: Or<(), T>, + #[serde(with = "OrDef::<(), T>")] + unit_or_t2: Or<(), T>, + #[serde(borrow, with = "StrDef")] + s: Str<'a>, + // #[schemars(with = "HashMap::<_, HashSet<_>>")] + // map: BTreeMap>, + #[schemars(with = "BTreeMap::>")] + fake_map: (), +} + +#[test] +fn remote_derive_json_schema() -> TestResult { + test_default_generated_schema::>("remote_derive_generic") +} diff --git a/schemars/tests/result.rs b/schemars/tests/result.rs new file mode 100644 index 0000000..b0657e0 --- /dev/null +++ b/schemars/tests/result.rs @@ -0,0 +1,21 @@ +mod util; +use schemars::JsonSchema; +use util::*; + +#[allow(dead_code)] +#[derive(JsonSchema)] +struct MyStruct { + foo: i32, +} + +#[allow(dead_code)] +#[derive(JsonSchema)] +struct Container { + result1: Result>, + result2: Result, +} + +#[test] +fn result() -> TestResult { + test_default_generated_schema::("result") +} diff --git a/schemars/tests/same_name.rs b/schemars/tests/same_name.rs new file mode 100644 index 0000000..5e19611 --- /dev/null +++ b/schemars/tests/same_name.rs @@ -0,0 +1,35 @@ +mod util; +use schemars::JsonSchema; +use util::*; + +mod a { + use super::*; + + #[allow(dead_code)] + #[derive(JsonSchema)] + pub struct Config { + test: String, + } +} + +mod b { + use super::*; + + #[allow(dead_code)] + #[derive(JsonSchema)] + pub struct Config { + test2: String, + } +} + +#[allow(dead_code)] +#[derive(JsonSchema)] +pub struct Config2 { + a_cfg: a::Config, + b_cfg: b::Config, +} + +#[test] +fn same_name() -> TestResult { + test_default_generated_schema::("same_name") +} diff --git a/schemars/tests/schema_name.rs b/schemars/tests/schema_name.rs new file mode 100644 index 0000000..ebd8a52 --- /dev/null +++ b/schemars/tests/schema_name.rs @@ -0,0 +1,77 @@ +mod util; +use schemars::JsonSchema; +use util::*; + +#[allow(dead_code)] +#[derive(JsonSchema)] +struct MyStruct { + t: T, + u: U, + v: V, + w: W, + inner: MySimpleStruct, +} + +#[allow(dead_code)] +#[derive(JsonSchema)] +struct MySimpleStruct { + foo: i32, +} + +#[test] +fn default_name_multiple_type_params() -> TestResult { + test_default_generated_schema::>>("schema-name-default") +} + +#[allow(dead_code)] +#[derive(JsonSchema)] +#[serde(rename = "a-new-name-{W}-{T}-{T}")] +#[schemars(rename_all = "camelCase")] +struct MyRenamedStruct { + t: T, + u: U, + v: V, + w: W, + inner: MySimpleRenamedStruct, +} + +#[allow(dead_code)] +#[derive(JsonSchema)] +#[serde(rename = "this-attribute-is-ignored")] +#[schemars(rename = "another-new-name")] +struct MySimpleRenamedStruct { + foo: i32, +} + +#[test] +fn overriden_with_rename_multiple_type_params() -> TestResult { + test_default_generated_schema::>>( + "schema-name-custom", + ) +} + +#[allow(dead_code)] +#[derive(JsonSchema)] +#[schemars(rename = "const-generics-{BAR}-")] +struct ConstGenericStruct { + foo: i32, +} + +#[test] +fn overriden_with_rename_const_generics() -> TestResult { + test_default_generated_schema::>("schema-name-const-generics") +} + +#[allow(dead_code)] +#[derive(JsonSchema)] +struct MixedGenericStruct { + generic: T, + foo: i32, +} + +#[test] +fn default_name_mixed_generics() -> TestResult { + test_default_generated_schema::>, 42, 'z'>>( + "schema-name-mixed-generics", + ) +} diff --git a/schemars/tests/schema_settings.rs b/schemars/tests/schema_settings.rs new file mode 100644 index 0000000..877a77c --- /dev/null +++ b/schemars/tests/schema_settings.rs @@ -0,0 +1,68 @@ +mod util; +use schemars::generate::SchemaSettings; +use schemars::{JsonSchema, Schema}; +use serde_json::Value; +use std::collections::BTreeMap; +use util::*; + +#[derive(JsonSchema)] +pub struct Outer { + #[schemars(example = "eight", example = "null")] + pub int: i32, + pub values: BTreeMap<&'static str, Value>, + pub value: Value, + pub inner: Option, + pub tuples: Vec<(u8, i64)>, +} + +#[derive(JsonSchema)] +pub enum Inner { + UndocumentedUnit1, + UndocumentedUnit2, + /// This is a documented unit variant + DocumentedUnit, + ValueNewType(Value), +} + +fn eight() -> i32 { + 8 +} + +fn null() {} + +#[test] +fn schema_matches_draft07() -> TestResult { + test_generated_schema::("schema_settings", SchemaSettings::draft07()) +} + +#[test] +fn schema_matches_2019_09() -> TestResult { + test_generated_schema::("schema_settings-2019_09", SchemaSettings::draft2019_09()) +} + +#[test] +fn schema_matches_2020_12() -> TestResult { + test_generated_schema::("schema_settings-2020_12", SchemaSettings::draft2020_12()) +} + +#[test] +fn schema_matches_openapi3() -> TestResult { + let mut settings = SchemaSettings::openapi3(); + + // Hack to apply recursive transforms to schemas at components.schemas: + // First, move them to $defs, then run the transforms, then move them back again. + settings.transforms.insert( + 0, + Box::new(|s: &mut Schema| { + let obj = s.ensure_object(); + let defs = obj["components"]["schemas"].take(); + obj.insert("$defs".to_owned(), defs); + }), + ); + settings.transforms.push(Box::new(|s: &mut Schema| { + let obj = s.ensure_object(); + obj["components"]["schemas"] = obj.remove("$defs").unwrap(); + })); + + test_generated_schema::("schema_settings-openapi3", settings) +} diff --git a/schemars/tests/schema_with_enum.rs b/schemars/tests/schema_with_enum.rs new file mode 100644 index 0000000..df9ab09 --- /dev/null +++ b/schemars/tests/schema_with_enum.rs @@ -0,0 +1,90 @@ +mod util; +use schemars::JsonSchema; +use util::*; + +fn schema_fn(generator: &mut schemars::SchemaGenerator) -> schemars::Schema { + ::json_schema(generator) +} + +#[derive(Debug)] +pub struct DoesntImplementJsonSchema; + +#[derive(JsonSchema)] +#[schemars(rename_all = "camelCase")] +pub enum External { + Struct { + #[schemars(schema_with = "schema_fn")] + foo: DoesntImplementJsonSchema, + }, + NewType(#[schemars(schema_with = "schema_fn")] DoesntImplementJsonSchema), + Tuple( + #[schemars(schema_with = "schema_fn")] DoesntImplementJsonSchema, + i32, + ), + #[schemars(schema_with = "schema_fn")] + Unit, +} + +#[test] +fn enum_external_tag() -> TestResult { + test_default_generated_schema::("schema_with-enum-external") +} + +#[derive(JsonSchema)] +#[schemars(tag = "typeProperty")] +pub enum Internal { + Struct { + #[schemars(schema_with = "schema_fn")] + foo: DoesntImplementJsonSchema, + }, + NewType(#[schemars(schema_with = "schema_fn")] DoesntImplementJsonSchema), + #[schemars(schema_with = "schema_fn")] + Unit, +} + +#[test] +fn enum_internal_tag() -> TestResult { + test_default_generated_schema::("schema_with-enum-internal") +} + +#[derive(JsonSchema)] +#[schemars(untagged)] +pub enum Untagged { + Struct { + #[schemars(schema_with = "schema_fn")] + foo: DoesntImplementJsonSchema, + }, + NewType(#[schemars(schema_with = "schema_fn")] DoesntImplementJsonSchema), + Tuple( + #[schemars(schema_with = "schema_fn")] DoesntImplementJsonSchema, + i32, + ), + #[schemars(schema_with = "schema_fn")] + Unit, +} + +#[test] +fn enum_untagged() -> TestResult { + test_default_generated_schema::("schema_with-enum-untagged") +} + +#[derive(JsonSchema)] +#[schemars(tag = "t", content = "c")] +pub enum Adjacent { + Struct { + #[schemars(schema_with = "schema_fn")] + foo: DoesntImplementJsonSchema, + }, + NewType(#[schemars(schema_with = "schema_fn")] DoesntImplementJsonSchema), + Tuple( + #[schemars(schema_with = "schema_fn")] DoesntImplementJsonSchema, + i32, + ), + #[schemars(schema_with = "schema_fn")] + Unit, +} + +#[test] +fn enum_adjacent_tagged() -> TestResult { + test_default_generated_schema::("schema_with-enum-adjacent-tagged") +} diff --git a/schemars/tests/schema_with_struct.rs b/schemars/tests/schema_with_struct.rs new file mode 100644 index 0000000..8677627 --- /dev/null +++ b/schemars/tests/schema_with_struct.rs @@ -0,0 +1,54 @@ +mod util; +use schemars::JsonSchema; +use util::*; + +fn schema_fn(generator: &mut schemars::SchemaGenerator) -> schemars::Schema { + ::json_schema(generator) +} + +struct DoesntImplementJsonSchema; + +#[allow(dead_code)] +#[derive(JsonSchema)] +struct Struct { + #[schemars(schema_with = "schema_fn")] + foo: DoesntImplementJsonSchema, + bar: i32, + #[schemars(schema_with = "schema_fn")] + baz: DoesntImplementJsonSchema, +} + +#[test] +fn struct_normal() -> TestResult { + test_default_generated_schema::("schema_with-struct") +} + +#[allow(dead_code)] +#[derive(JsonSchema)] +pub struct Tuple( + #[schemars(schema_with = "schema_fn")] DoesntImplementJsonSchema, + i32, + #[schemars(schema_with = "schema_fn")] DoesntImplementJsonSchema, +); + +#[test] +fn struct_tuple() -> TestResult { + test_default_generated_schema::("schema_with-tuple") +} + +#[derive(JsonSchema)] +pub struct Newtype(#[schemars(schema_with = "schema_fn")] DoesntImplementJsonSchema); + +#[test] +fn struct_newtype() -> TestResult { + test_default_generated_schema::("schema_with-newtype") +} + +#[derive(JsonSchema)] +#[schemars(transparent)] +pub struct TransparentNewtype(#[schemars(schema_with = "schema_fn")] DoesntImplementJsonSchema); + +#[test] +fn struct_transparent_newtype() -> TestResult { + test_default_generated_schema::("schema_with-transparent-newtype") +} diff --git a/schemars/tests/semver.rs b/schemars/tests/semver.rs new file mode 100644 index 0000000..3c351c6 --- /dev/null +++ b/schemars/tests/semver.rs @@ -0,0 +1,15 @@ +mod util; +use schemars::JsonSchema; +use semver1::Version; +use util::*; + +#[allow(dead_code)] +#[derive(JsonSchema)] +struct SemverTypes { + version: Version, +} + +#[test] +fn semver_types() -> TestResult { + test_default_generated_schema::("semver") +} diff --git a/schemars/tests/skip.rs b/schemars/tests/skip.rs new file mode 100644 index 0000000..a95a8db --- /dev/null +++ b/schemars/tests/skip.rs @@ -0,0 +1,55 @@ +mod util; +use schemars::JsonSchema; +use util::*; + +#[allow(dead_code)] +#[derive(JsonSchema)] +struct MyStruct { + #[schemars(skip)] + skipped1: i32, + #[serde(skip)] + skipped2: bool, + #[serde(skip_deserializing)] + readable: String, + #[serde(skip_serializing)] + writable: f32, + included: (), +} + +#[test] +fn skip_struct_fields() -> TestResult { + test_default_generated_schema::("skip_struct_fields") +} + +#[allow(dead_code)] +#[derive(JsonSchema)] +struct TupleStruct( + #[schemars(skip)] i32, + #[serde(skip)] bool, + #[serde(skip_deserializing)] String, + #[serde(skip_serializing)] f32, + (), +); + +#[test] +fn skip_tuple_fields() -> TestResult { + test_default_generated_schema::("skip_tuple_fields") +} + +#[derive(JsonSchema)] +pub enum MyEnum { + #[schemars(skip)] + Skipped1(i32), + #[serde(skip)] + Skipped2, + #[serde(skip_deserializing)] + Skipped3, + #[serde(skip_serializing)] + Included1(f32), + Included2, +} + +#[test] +fn skip_enum_variants() -> TestResult { + test_default_generated_schema::("skip_enum_variants") +} diff --git a/schemars/tests/smallvec.rs b/schemars/tests/smallvec.rs new file mode 100644 index 0000000..8412a6a --- /dev/null +++ b/schemars/tests/smallvec.rs @@ -0,0 +1,8 @@ +mod util; +use smallvec1::SmallVec; +use util::*; + +#[test] +fn smallvec() -> TestResult { + test_default_generated_schema::>("smallvec") +} diff --git a/schemars/tests/smol_str.rs b/schemars/tests/smol_str.rs new file mode 100644 index 0000000..43fad30 --- /dev/null +++ b/schemars/tests/smol_str.rs @@ -0,0 +1,8 @@ +mod util; +use smol_str02::SmolStr; +use util::*; + +#[test] +fn smol_str() -> TestResult { + test_default_generated_schema::("smol_str") +} diff --git a/schemars/tests/std_time.rs b/schemars/tests/std_time.rs new file mode 100644 index 0000000..7f70a59 --- /dev/null +++ b/schemars/tests/std_time.rs @@ -0,0 +1,16 @@ +mod util; +use schemars::JsonSchema; +use std::time::{Duration, SystemTime}; +use util::*; + +#[allow(dead_code)] +#[derive(JsonSchema)] +struct MyStruct { + duration: Duration, + time: SystemTime, +} + +#[test] +fn duration_and_systemtime() -> TestResult { + test_default_generated_schema::("duration_and_systemtime") +} diff --git a/schemars/tests/struct.rs b/schemars/tests/struct.rs new file mode 100644 index 0000000..80f9ec8 --- /dev/null +++ b/schemars/tests/struct.rs @@ -0,0 +1,45 @@ +mod util; +use schemars::JsonSchema; +use util::*; + +// Ensure that schemars_derive uses the full path to std::string::String +pub struct String; + +#[allow(dead_code)] +#[derive(JsonSchema)] +struct Struct { + foo: i32, + bar: bool, + baz: Option<&'static str>, +} + +#[test] +fn struct_normal() -> TestResult { + test_default_generated_schema::("struct-normal") +} + +#[allow(dead_code)] +#[derive(JsonSchema)] +pub struct Tuple(i32, bool, Option<&'static str>); + +#[test] +fn struct_tuple() -> TestResult { + test_default_generated_schema::("struct-tuple") +} + +#[allow(dead_code)] +#[derive(JsonSchema)] +pub struct Newtype(i32); + +#[test] +fn struct_newtype() -> TestResult { + test_default_generated_schema::("struct-newtype") +} + +#[derive(JsonSchema)] +pub struct Unit; + +#[test] +fn struct_unit() -> TestResult { + test_default_generated_schema::("struct-unit") +} diff --git a/schemars/tests/struct_additional_properties.rs b/schemars/tests/struct_additional_properties.rs new file mode 100644 index 0000000..7fd64f3 --- /dev/null +++ b/schemars/tests/struct_additional_properties.rs @@ -0,0 +1,17 @@ +mod util; +use schemars::JsonSchema; +use util::*; + +#[allow(dead_code)] +#[derive(JsonSchema)] +#[serde(deny_unknown_fields)] +pub struct Struct { + foo: i32, + bar: bool, + baz: Option, +} + +#[test] +fn struct_normal_additional_properties() -> TestResult { + test_default_generated_schema::("struct-normal-additional-properties") +} diff --git a/schemars/tests/transform.rs b/schemars/tests/transform.rs new file mode 100644 index 0000000..23d5b89 --- /dev/null +++ b/schemars/tests/transform.rs @@ -0,0 +1,47 @@ +mod util; +use schemars::{transform::RecursiveTransform, JsonSchema, Schema}; +use serde_json::{Map, Value}; +use util::*; + +fn capitalize_type(schema: &mut Schema) { + if let Some(Value::String(ty)) = schema.get("type") { + schema.insert("upperType".to_owned(), ty.to_uppercase().into()); + } +} + +fn insert_property_count(schema: &mut Schema) { + let count = schema + .get("properties") + .and_then(Value::as_object) + .map_or(0, Map::len); + schema.insert("propertyCount".to_owned(), count.into()); +} + +#[allow(dead_code)] +#[derive(JsonSchema)] +#[schemars(transform = RecursiveTransform(capitalize_type), transform = insert_property_count)] +struct Struct { + value: Value, + #[schemars(transform = insert_property_count)] + int: i32, +} + +#[test] +fn transform_struct() -> TestResult { + test_default_generated_schema::("transform_struct") +} + +#[allow(dead_code)] +#[derive(JsonSchema)] +#[schemars(transform = RecursiveTransform(capitalize_type), transform = insert_property_count)] +enum External { + #[schemars(transform = insert_property_count)] + Unit, + #[schemars(transform = insert_property_count)] + NewType(Value), +} + +#[test] +fn transform_enum_external() -> TestResult { + test_default_generated_schema::("transform_enum_external") +} diff --git a/schemars/tests/transparent.rs b/schemars/tests/transparent.rs new file mode 100644 index 0000000..f8b2218 --- /dev/null +++ b/schemars/tests/transparent.rs @@ -0,0 +1,31 @@ +mod util; +use schemars::JsonSchema; +use util::*; + +#[allow(dead_code)] +#[derive(JsonSchema)] +pub struct OuterStruct { + inner: TransparentStruct, +} + +#[allow(dead_code)] +#[derive(JsonSchema)] +#[serde(transparent)] +pub struct TransparentStruct { + #[serde(with = "TransparentNewType")] + inner: (), +} + +#[allow(dead_code)] +#[derive(JsonSchema)] +#[schemars(transparent)] +pub struct TransparentNewType(Option); + +#[allow(dead_code)] +#[derive(JsonSchema)] +pub struct InnerStruct(String, i32); + +#[test] +fn transparent_struct() -> TestResult { + test_default_generated_schema::("transparent-struct") +} diff --git a/schemars/tests/ui/example_fn.rs b/schemars/tests/ui/example_fn.rs deleted file mode 100644 index c4921c5..0000000 --- a/schemars/tests/ui/example_fn.rs +++ /dev/null @@ -1,9 +0,0 @@ -use schemars::JsonSchema; - -#[derive(JsonSchema)] -#[schemars(example = "my_fn")] -pub struct Struct; - -fn my_fn() {} - -fn main() {} diff --git a/schemars/tests/ui/example_fn.stderr b/schemars/tests/ui/example_fn.stderr deleted file mode 100644 index 92a34f3..0000000 --- a/schemars/tests/ui/example_fn.stderr +++ /dev/null @@ -1,7 +0,0 @@ -error: `example` value must be an expression, and string literals that may be interpreted as function paths are currently disallowed to avoid migration errors (this restriction may be relaxed in a future version of schemars). - If you want to use the result of a function, use `#[schemars(example = my_fn())]`. - Or to use the string literal value, use `#[schemars(example = &"my_fn")]`. - --> tests/ui/example_fn.rs:4:22 - | -4 | #[schemars(example = "my_fn")] - | ^^^^^^^ diff --git a/schemars/tests/ui/transform_str.stderr b/schemars/tests/ui/transform_str.stderr index 50cf7b9..6ee3698 100644 --- a/schemars/tests/ui/transform_str.stderr +++ b/schemars/tests/ui/transform_str.stderr @@ -1,5 +1,5 @@ error: Expected a `fn(&mut Schema)` or other value implementing `schemars::transform::Transform`, found `&str`. - Did you mean `#[schemars(transform = x)]`? + Did you mean `[schemars(transform = x)]`? --> tests/ui/transform_str.rs:4:24 | 4 | #[schemars(transform = "x")] diff --git a/schemars/tests/url.rs b/schemars/tests/url.rs new file mode 100644 index 0000000..018a66b --- /dev/null +++ b/schemars/tests/url.rs @@ -0,0 +1,15 @@ +mod util; +use schemars::JsonSchema; +use url2::Url; +use util::*; + +#[allow(dead_code)] +#[derive(JsonSchema)] +struct UrlTypes { + url: Url, +} + +#[test] +fn url_types() -> TestResult { + test_default_generated_schema::("url") +} diff --git a/schemars/tests/util/mod.rs b/schemars/tests/util/mod.rs new file mode 100644 index 0000000..ff67df6 --- /dev/null +++ b/schemars/tests/util/mod.rs @@ -0,0 +1,46 @@ +use pretty_assertions::assert_eq; +use schemars::{generate::SchemaSettings, schema_for, JsonSchema, Schema}; +use std::error::Error; +use std::format; +use std::fs; +use std::prelude::rust_2021::*; + +extern crate std; + +pub type TestResult = Result<(), Box>; + +#[allow(dead_code)] // https://github.com/rust-lang/rust/issues/46379 +pub fn test_generated_schema(file: &str, settings: SchemaSettings) -> TestResult { + let actual = settings.into_generator().into_root_schema_for::(); + test_schema(&actual, file) +} + +#[allow(dead_code)] // https://github.com/rust-lang/rust/issues/46379 +pub fn test_default_generated_schema(file: &str) -> TestResult { + let actual = schema_for!(T); + test_schema(&actual, file) +} + +pub fn test_schema(actual: &Schema, file: &str) -> TestResult { + let expected_json = match fs::read_to_string(format!("tests/expected/{}.json", file)) { + Ok(j) => j, + Err(e) => { + write_actual_to_file(actual, file)?; + return Err(Box::from(e)); + } + }; + let expected = &serde_json::from_str(&expected_json)?; + + if actual != expected { + write_actual_to_file(actual, file)?; + } + + assert_eq!(expected, actual); + Ok(()) +} + +fn write_actual_to_file(schema: &Schema, file: &str) -> TestResult { + let actual_json = serde_json::to_string_pretty(&schema)?; + fs::write(format!("tests/actual/{}.json", file), actual_json)?; + Ok(()) +} diff --git a/schemars/tests/uuid.rs b/schemars/tests/uuid.rs new file mode 100644 index 0000000..77e92c2 --- /dev/null +++ b/schemars/tests/uuid.rs @@ -0,0 +1,7 @@ +mod util; +use util::*; + +#[test] +fn uuid1() -> TestResult { + test_default_generated_schema::("uuid") +} diff --git a/schemars/tests/validate.rs b/schemars/tests/validate.rs new file mode 100644 index 0000000..410593d --- /dev/null +++ b/schemars/tests/validate.rs @@ -0,0 +1,121 @@ +mod util; +use schemars::JsonSchema; +use util::*; + +struct FakeRegex(&'static str); + +impl std::fmt::Display for FakeRegex { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + self.0.fmt(f) + } +} + +// In real code, this would typically be a Regex, potentially created in a `lazy_static!`. +static STARTS_WITH_HELLO: &FakeRegex = &FakeRegex(r"^[Hh]ello\b"); + +const MIN: u32 = 1; +const MAX: u32 = 1000; + +#[allow(dead_code)] +#[derive(JsonSchema)] +pub struct Struct { + #[validate(range(min = 0.01, max = 100))] + min_max: f32, + #[validate(range(min = "MIN", max = "MAX"))] + min_max2: f32, + #[validate(regex(path = *STARTS_WITH_HELLO))] + regex_str1: String, + #[validate(regex(path = "STARTS_WITH_HELLO", code = "foo"))] + regex_str2: String, + #[validate(contains(pattern = "substring..."))] + contains_str1: String, + #[validate(contains(pattern = "substring...", message = "bar"))] + contains_str2: String, + #[validate(email)] + email_address: String, + #[validate(url(code = "code_str", message = "message"))] + homepage: String, + #[validate(length(min = 1, max = 100))] + non_empty_str: String, + #[validate(length(min = "MIN", max = "MAX"))] + non_empty_str2: String, + #[validate(length(equal = 2))] + pair: Vec, + #[validate(required)] + required_option: Option, + #[validate(required)] + #[validate] + #[serde(flatten)] + required_flattened: Option, +} + +#[allow(dead_code)] +#[derive(JsonSchema)] +pub struct Inner { + x: i32, +} + +#[test] +fn validate() -> TestResult { + test_default_generated_schema::("validate") +} + +#[allow(dead_code)] +#[derive(JsonSchema)] +pub struct Struct2 { + #[schemars(range(min = 0.01, max = 100))] + min_max: f32, + #[schemars(range(min = "MIN", max = "MAX"))] + min_max2: f32, + #[validate(regex(path = overridden))] + #[schemars(regex(pattern = *STARTS_WITH_HELLO))] + regex_str1: String, + #[schemars(regex(pattern = r"^\d+$"))] + regex_str2: String, + #[validate(contains(pattern = "overridden"))] + #[schemars(contains(pattern = "substring..."))] + contains_str1: String, + #[schemars(contains(pattern = "substring..."))] + contains_str2: String, + #[schemars(email)] + email_address: String, + #[schemars(url)] + homepage: String, + #[schemars(length(min = 1, max = 100))] + non_empty_str: String, + #[schemars(length(min = "MIN", max = "MAX"))] + non_empty_str2: String, + #[schemars(length(equal = 2))] + pair: Vec, + #[schemars(required)] + required_option: Option, + #[schemars(required)] + #[serde(flatten)] + required_flattened: Option, +} + +#[test] +fn validate_schemars_attrs() -> TestResult { + test_default_generated_schema::("validate_schemars_attrs") +} + +#[allow(dead_code)] +#[derive(JsonSchema)] +pub struct Tuple( + #[validate(range(max = 10))] u8, + #[validate(required)] Option, +); + +#[test] +fn validate_tuple() -> TestResult { + test_default_generated_schema::("validate_tuple") +} + +#[allow(dead_code)] +#[derive(JsonSchema)] +pub struct NewType(#[validate(range(max = 10))] u8); + +#[test] +fn validate_newtype() -> TestResult { + test_default_generated_schema::("validate_newtype") +} diff --git a/schemars/tests/validate_inner.rs b/schemars/tests/validate_inner.rs new file mode 100644 index 0000000..d3d8d65 --- /dev/null +++ b/schemars/tests/validate_inner.rs @@ -0,0 +1,31 @@ +mod util; + +use schemars::JsonSchema; +use util::*; + +// In real code, this would typically be a Regex, potentially created in a `lazy_static!`. +static STARTS_WITH_HELLO: &str = r"^[Hh]ello\b"; + +#[allow(dead_code)] +#[derive(JsonSchema)] +pub struct Struct<'a> { + #[schemars(inner(length(min = 5, max = 100)))] + array_str_length: [&'a str; 2], + #[schemars(inner(contains(pattern = "substring...")))] + slice_str_contains: &'a [&'a str], + #[schemars(inner(regex(pattern = STARTS_WITH_HELLO)))] + vec_str_regex: Vec, + #[schemars(inner(length(min = 1, max = 100)))] + vec_str_length: Vec<&'a str>, + #[schemars(length(min = 1, max = 3), inner(length(min = 1, max = 100)))] + vec_str_length2: Vec, + #[schemars(inner(url))] + vec_str_url: Vec, + #[schemars(inner(range(min = -10, max = 10)))] + vec_i32_range: Vec, +} + +#[test] +fn validate_inner() -> TestResult { + test_default_generated_schema::("validate_inner") +} diff --git a/schemars_derive/Cargo.toml b/schemars_derive/Cargo.toml index 1264f59..44ef667 100644 --- a/schemars_derive/Cargo.toml +++ b/schemars_derive/Cargo.toml @@ -3,14 +3,14 @@ name = "schemars_derive" description = "Macros for #[derive(JsonSchema)], for use with schemars" homepage = "https://graham.cool/schemars/" repository = "https://github.com/GREsau/schemars" -version = "1.0.0-alpha.17" +version = "1.0.0-alpha.15" authors = ["Graham Esau "] edition = "2021" license = "MIT" readme = "README.md" keywords = ["rust", "json-schema", "serde"] categories = ["encoding", "no-std"] -rust-version = "1.70" +rust-version = "1.65" [lib] proc-macro = true diff --git a/schemars_derive/src/ast/mod.rs b/schemars_derive/src/ast/mod.rs index c098959..9e632c5 100644 --- a/schemars_derive/src/ast/mod.rs +++ b/schemars_derive/src/ast/mod.rs @@ -48,7 +48,7 @@ impl<'a> Container<'a> { .map(|_| result.expect("from_ast set no errors on Ctxt, so should have returned Ok")) } - pub fn transparent_field(&'a self) -> Option<&'a Field<'a>> { + pub fn transparent_field(&'a self) -> Option<&'a Field> { if self.serde_attrs.transparent() { if let Data::Struct(_, fields) = &self.data { return Some(&fields[0]); @@ -63,7 +63,7 @@ impl<'a> Container<'a> { } } -impl Variant<'_> { +impl<'a> Variant<'a> { pub fn name(&self) -> Name { Name(self.serde_attrs.name()) } @@ -85,7 +85,7 @@ impl Variant<'_> { } } -impl Field<'_> { +impl<'a> Field<'a> { pub fn name(&self) -> Name { Name(self.serde_attrs.name()) } diff --git a/schemars_derive/src/attr/mod.rs b/schemars_derive/src/attr/mod.rs index 37350d3..14fd6eb 100644 --- a/schemars_derive/src/attr/mod.rs +++ b/schemars_derive/src/attr/mod.rs @@ -21,7 +21,7 @@ pub struct CommonAttrs { pub deprecated: bool, pub title: Option, pub description: Option, - pub examples: Vec, + pub examples: Vec, pub extensions: Vec<(String, TokenStream)>, pub transforms: Vec, } @@ -84,24 +84,7 @@ impl CommonAttrs { }, "example" => { - if let Ok(expr) = parse_name_value_expr(meta, cx) { - if let Expr::Lit(ExprLit { - lit: Lit::Str(lit_str), - .. - }) = &expr - { - if lit_str.parse::().is_ok() { - let lit_str_value = lit_str.value(); - cx.error_spanned_by(&expr, format_args!( - "`example` value must be an expression, and string literals that may be interpreted as function paths are currently disallowed to avoid migration errors \ - (this restriction may be relaxed in a future version of schemars).\n\ - If you want to use the result of a function, use `#[schemars(example = {lit_str_value}())]`.\n\ - Or to use the string literal value, use `#[schemars(example = &\"{lit_str_value}\")]`.")); - } - } - - self.examples.push(expr); - } + self.examples.extend(parse_name_value_lit_str(meta, cx)); } "extend" => { @@ -131,7 +114,7 @@ impl CommonAttrs { cx.error_spanned_by( &expr, format_args!( - "Expected a `fn(&mut Schema)` or other value implementing `schemars::transform::Transform`, found `&str`.\nDid you mean `#[schemars(transform = {})]`?", + "Expected a `fn(&mut Schema)` or other value implementing `schemars::transform::Transform`, found `&str`.\nDid you mean `[schemars(transform = {})]`?", lit_str.value() ), ) @@ -195,7 +178,7 @@ impl CommonAttrs { if !self.examples.is_empty() { let examples = self.examples.iter().map(|eg| { quote! { - schemars::_private::serde_json::value::to_value(#eg) + schemars::_private::serde_json::value::to_value(#eg()) } }); mutators.push(quote! { diff --git a/schemars_derive/src/lib.rs b/schemars_derive/src/lib.rs index 8d8ccd0..557a276 100644 --- a/schemars_derive/src/lib.rs +++ b/schemars_derive/src/lib.rs @@ -126,10 +126,7 @@ fn derive_json_schema(mut input: syn::DeriveInput, repr: bool) -> syn::Result Result { Ok(schema_expr) } -fn expr_for_field(field: &Field, is_internal_tagged_enum_newtype: bool) -> SchemaExpr { +fn expr_for_field(field: &Field, allow_ref: bool) -> SchemaExpr { let (ty, type_def) = type_for_field_schema(field); let span = field.original.span(); - let schema_expr = if field.attrs.validation.required { + let mut schema_expr = SchemaExpr::from(if field.attrs.validation.required { quote_spanned! {span=> <#ty as schemars::JsonSchema>::_schemars_private_non_optional_json_schema(#GENERATOR) } - } else if is_internal_tagged_enum_newtype { - quote_spanned! {span=> - schemars::_private::json_schema_for_internally_tagged_enum_newtype_variant::<#ty>(#GENERATOR) - } - } else { + } else if allow_ref { quote_spanned! {span=> #GENERATOR.subschema_for::<#ty>() } - }; - let mut schema_expr = SchemaExpr::from(schema_expr); + } else { + quote_spanned! {span=> + <#ty as schemars::JsonSchema>::json_schema(#GENERATOR) + } + }); schema_expr.definitions.extend(type_def); field.add_mutators(&mut schema_expr.mutators); @@ -408,7 +407,7 @@ fn expr_for_untagged_enum_variant(variant: &Variant, deny_unknown_fields: bool) match variant.style { Style::Unit => expr_for_unit_struct(), - Style::Newtype => expr_for_field(&variant.fields[0], false), + Style::Newtype => expr_for_field(&variant.fields[0], true), Style::Tuple => expr_for_tuple_struct(&variant.fields), Style::Struct => expr_for_struct(&variant.fields, &SerdeDefault::None, deny_unknown_fields), } @@ -431,7 +430,7 @@ fn expr_for_internal_tagged_enum_variant( match variant.style { Style::Unit => expr_for_unit_struct(), - Style::Newtype => expr_for_field(&variant.fields[0], true), + Style::Newtype => expr_for_field(&variant.fields[0], false), Style::Tuple => expr_for_tuple_struct(&variant.fields), Style::Struct => expr_for_struct(&variant.fields, &SerdeDefault::None, deny_unknown_fields), } @@ -445,14 +444,14 @@ fn expr_for_unit_struct() -> SchemaExpr { } fn expr_for_newtype_struct(field: &Field) -> SchemaExpr { - expr_for_field(field, false) + expr_for_field(field, true) } fn expr_for_tuple_struct(fields: &[Field]) -> SchemaExpr { let fields: Vec<_> = fields .iter() .map(|f| { - let field_expr = expr_for_field(f, false); + let field_expr = expr_for_field(f, true); f.with_contract_check(quote! { prefix_items.push((#field_expr).to_value()); }) diff --git a/update-tests.sh b/update-tests.sh index 30852e0..0ba525c 100644 --- a/update-tests.sh +++ b/update-tests.sh @@ -5,7 +5,7 @@ cd schemars rm -f tests/actual/*.json -TRYBUILD=overwrite SNAPSHOTS=overwrite cargo test --all-features --no-fail-fast --tests || : +TRYBUILD=overwrite cargo test --all-features --no-fail-fast --tests || : if ls tests/actual/*.json 1> /dev/null 2>&1; then mv -f tests/actual/*.json tests/expected/