diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 0fa6019..247d0c9 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -8,12 +8,12 @@ jobs: strategy: matrix: rust: - - 1.65.0 + - 1.70.0 - stable - beta - nightly include: - - rust: 1.65.0 + - rust: 1.70.0 allow_failure: false - rust: stable allow_failure: false diff --git a/CHANGELOG.md b/CHANGELOG.md index cfb6097..a84c477 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,15 @@ - 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 + +- ⚠️ MSRV is now 1.70 ⚠️ + +### 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 40a1e2c..0f07620 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,53 +2,247 @@ # 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.4" +version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711" - -[[package]] -name = "autocfg" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" - -[[package]] -name = "basic-toml" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7bfc506e7a2370ec239e1d072507b2a80c833083699d3c6fa176fbb4de8448c6" +checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" dependencies = [ "serde", ] [[package]] -name = "bigdecimal" -version = "0.4.2" +name = "autocfg" +version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c06619be423ea5bb86c95f087d5707942791a08a85530df0db2209a3ecfb8bc9" +checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" + +[[package]] +name = "base64" +version = "0.22.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" + +[[package]] +name = "bigdecimal" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51d712318a27c7150326677b321a5fa91b55f6d9034ffd67f20319e147d40cee" dependencies = [ "autocfg", "libm", "num-bigint", "num-integer", "num-traits", + "serde", ] [[package]] -name = "bytes" -version = "1.5.0" +name = "bit-set" +version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2bd12c1caf447e69cd4528f47f94d203fd2582878ecb9e9465484c4148a8223" +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" +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" [[package]] name = "chrono" -version = "0.4.31" +version = "0.4.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f2c685bad3eb3d45a01354cedb7d5faa66194d1d58ba6e267a8de788f79db38" +checksum = "a21f936df1771bf62b77f047b726c4625ff2e8aa607c01ec06e5a05bd8463401" 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" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f63b86c8a8826a49b8c21f08a2d07338eec8d900540f8630dc76284be802989" +dependencies = [ + "darling_core", + "darling_macro", +] + +[[package]] +name = "darling_core" +version = "0.20.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95133861a8032aaea082871032f5815eb9e98cef03fa916ab4500513994df9e5" +dependencies = [ + "fnv", + "ident_case", + "proc-macro2", + "quote", + "strsim", + "syn 2.0.77", +] + +[[package]] +name = "darling_macro" +version = "0.20.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d336a2a514f6ccccaa3e09b02d41d35330c07ddf03a62165fcec10bb561c7806" +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", ] [[package]] @@ -59,15 +253,18 @@ checksum = "56254986775e3233ffa9c4d7d3faaf6d36a2c09d30b20687e9f88bc8bafc16c8" [[package]] name = "dyn-clone" -version = "1.0.14" +version = "1.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23d2f3407d9a573d666de4b5bdf10569d73ca9478087346697dcbae6244bfbcd" +checksum = "0d6ef0072f8a535281e4876be788938b528e9a1d43900b82c2569af7da799125" [[package]] name = "either" -version = "1.9.0" +version = "1.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07" +checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" +dependencies = [ + "serde", +] [[package]] name = "equivalent" @@ -76,14 +273,78 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" [[package]] -name = "form_urlencoded" -version = "1.2.0" +name = "fancy-regex" +version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a62bc1cf6f830c2ec14a513a9fb124d0a213a629668a4186f329db21fe045652" +checksum = "531e46835a22af56d1e3b66f04844bed63158bc094a628bec1d321d9b4c44bf2" +dependencies = [ + "bit-set", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "form_urlencoded" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" 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" @@ -92,15 +353,21 @@ checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" [[package]] name = "hashbrown" -version = "0.14.2" +version = "0.14.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f93e7192158dbcda357bdec5fb5788eebf8bbac027f3f33e719d29135ae84156" +checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" + +[[package]] +name = "ident_case" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" [[package]] name = "idna" -version = "0.4.0" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d20d6b07bfbc108882d88ed8e37d39636dcc260e15e30c45e6ba089610b917c" +checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6" dependencies = [ "unicode-bidi", "unicode-normalization", @@ -108,19 +375,84 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.4.0" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93ead53efc7ea8ed3cfb0c79fc8023fbb782a5432b52830b6518941cebe6505c" +checksum = "68b900aa2f7301e21c36462b170ee99994de34dff39a4a6a528e80e7376d07e5" 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.9" +version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38" +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.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2be7aa9f08a262039c0b5eb11b792e4353dad5263f78e33312b7ba9e43b32ae9" +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" [[package]] name = "libm" @@ -129,16 +461,108 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058" [[package]] -name = "memchr" -version = "2.5.0" +name = "lock_api" +version = "0.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" +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" +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", +] [[package]] name = "num-bigint" -version = "0.4.4" +version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "608e7659b5c3d7cba262d894801b9ec9d00de989e8a82bd4bef91d08da45cdc0" +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" dependencies = [ "autocfg", "num-integer", @@ -146,35 +570,71 @@ dependencies = [ ] [[package]] -name = "num-integer" -version = "0.1.45" +name = "num-rational" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9" +checksum = "f83d14da390562dca69fc84082e73e548e1ad308d24accdedd2720017cb37824" dependencies = [ - "autocfg", + "num-bigint", + "num-integer", "num-traits", ] [[package]] name = "num-traits" -version = "0.2.17" +version = "0.2.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39e3200413f237f41ab11ad6d161bc7239c84dcb631773ccd7de3dfe4b5c267c" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" dependencies = [ "autocfg", ] [[package]] name = "once_cell" -version = "1.18.0" +version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" +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", +] [[package]] name = "percent-encoding" -version = "2.3.0" +version = "2.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b2a4787296e9989611394c33f193f676704af1686e70b8f8033ab5ba9a35a94" +checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" + +[[package]] +name = "powerfmt" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" [[package]] name = "pretty_assertions" @@ -187,58 +647,127 @@ dependencies = [ ] [[package]] -name = "proc-macro2" -version = "1.0.81" +name = "proc-macro-error" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d1597b0c024618f09a9c3b8655b7e430397a36d23fdafec26d6965e9eec3eba" +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" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77" dependencies = [ "unicode-ident", ] [[package]] name = "quote" -version = "1.0.36" +version = "1.0.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" +checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" dependencies = [ "proc-macro2", ] [[package]] -name = "ref-cast" -version = "1.0.22" +name = "redox_syscall" +version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4846d4c50d1721b1a3bef8af76924eef20d5e723647333798c1b519b3a9473f" +checksum = "2a908a6e00f1fdd0dfd9c0eb08ce85126f6d8bbda50017e74bc4a4b7d4a926a4" +dependencies = [ + "bitflags", +] + +[[package]] +name = "ref-cast" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ccf0a6f84d5f1d581da8b41b47ec8600871962f2a528115b542b362d4b744931" dependencies = [ "ref-cast-impl", ] [[package]] name = "ref-cast-impl" -version = "1.0.22" +version = "1.0.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5fddb4f8d99b0a2ebafc65a87a69a7b9875e4b1ae1f00db265d300ef7f28bccc" +checksum = "bcc303e793d3734489387d205e9b186fac9c6cfacedd98cbb2e8a5943595f3e6" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.77", ] +[[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.32.0" +version = "1.36.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4c4216490d5a413bc6d10fa4742bd7d4955941d062c0ef873141d6b0e7b30fd" +checksum = "b082d80e3e3cc52b2ed634388d436fe1f4de6af5786cc2de9ba9737527bdf555" dependencies = [ "arrayvec", "num-traits", + "serde", ] [[package]] -name = "ryu" -version = "1.0.15" +name = "rustversion" +version = "1.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ad4cc8da4ef723ed60bced201181d83791ad433213d8c24efffda1eec85d741" +checksum = "955d28af4278de8121b7ebeb796b6a45735dc01436d898801014aced2773a3d6" + +[[package]] +name = "ryu" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" [[package]] name = "schemars" @@ -250,19 +779,25 @@ dependencies = [ "chrono", "dyn-clone", "either", + "garde", "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]] @@ -273,51 +808,60 @@ dependencies = [ "proc-macro2", "quote", "serde_derive_internals", - "syn", + "syn 2.0.77", ] [[package]] -name = "semver" -version = "1.0.20" +name = "scopeguard" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "836fa6a3e1e547f9a2c4040802ec865b5d85f4014efe00555d7090a3dcaa1090" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" + +[[package]] +name = "semver" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b" +dependencies = [ + "serde", +] [[package]] name = "serde" -version = "1.0.208" +version = "1.0.210" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cff085d2cb684faa248efb494c39b68e522822ac0de72ccf08109abde717cfb2" +checksum = "c8e3592472072e6e22e0a54d5904d9febf8508f65fb8552499a1abc7d1078c3a" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.208" +version = "1.0.210" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24008e81ff7613ed8e5ba0cfaf24e2c2f1e5b8a0495711e44fcd4882fca62bcf" +checksum = "243902eda00fad750862fc144cea25caca5e20d615af0a81bee94ca738f1df1f" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.77", ] [[package]] name = "serde_derive_internals" -version = "0.29.0" +version = "0.29.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "330f01ce65a3a5fe59a60c82f3c9a024b573b8a6e875bd233fe5f934e71d54e3" +checksum = "18d26a20a969b9e3fdf2fc2d9f21eda6c40e2de84c9408bb5d3b05d499aae711" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.77", ] [[package]] name = "serde_json" -version = "1.0.127" +version = "1.0.128" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8043c06d9f82bd7271361ed64f415fe5e12a77fdb52e573e7f06a516dea329ad" +checksum = "6ff5456707a1de34e7e37f2a6fd3d3f808c318259cbd01ab6377795054b483d8" dependencies = [ "indexmap", "itoa", @@ -327,22 +871,100 @@ dependencies = [ ] [[package]] -name = "smallvec" -version = "1.11.1" +name = "serde_repr" +version = "0.1.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "942b4a808e05215192e39f4ab80813e599068285906cc91aa64f923db842bd5a" +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" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" +dependencies = [ + "serde", +] [[package]] name = "smol_str" -version = "0.2.1" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6845563ada680337a52d43bb0b29f396f2d911616f6573012645b9e3d048a49" +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" [[package]] name = "syn" -version = "2.0.60" +version = "1.0.109" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "909518bc7b1c9b779f1bbf07f2929d35af9f0f37e47c6e9ef7f9dddc1e1821f3" +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" dependencies = [ "proc-macro2", "quote", @@ -351,18 +973,48 @@ dependencies = [ [[package]] name = "termcolor" -version = "1.3.0" +version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6093bad37da69aab9d123a8091e4be0aa4a03e4d601ec641c327398315f62b64" +checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755" dependencies = [ "winapi-util", ] [[package]] -name = "tinyvec" -version = "1.6.0" +name = "time" +version = "0.3.36" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" +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" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "445e881f4f6d382d5f27c034e25eb92edd7c784ceab92a0937db7f2e9471b938" dependencies = [ "tinyvec_macros", ] @@ -374,25 +1026,58 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] -name = "trybuild" -version = "1.0.85" +name = "toml" +version = "0.8.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "196a58260a906cedb9bf6d8034b6379d0c11f552416960452f267402ceeddff1" +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" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "207aa50d36c4be8d8c6ea829478be44a372c6a77669937bb39c698e52f1491e8" dependencies = [ - "basic-toml", "glob", - "once_cell", "serde", "serde_derive", "serde_json", "termcolor", + "toml", ] [[package]] name = "unicode-bidi" -version = "0.3.13" +version = "0.3.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92888ba5573ff080736b3648696b70cafad7d250551175acbaa4e0385b3e1460" +checksum = "08f95100a766bf4f8f28f90d77e0a5461bbdb219042e7679bebe79004fed8d75" [[package]] name = "unicode-ident" @@ -402,63 +1087,276 @@ checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" [[package]] name = "unicode-normalization" -version = "0.1.22" +version = "0.1.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c5713f0fc4b5db668a2ac63cdb7bb4469d8c9fed047b1d0292cc7b0ce2ba921" +checksum = "a56d1686db2308d901306f92a263857ef59ea39678a5458e7cb17f01415101f5" dependencies = [ "tinyvec", ] [[package]] name = "url" -version = "2.4.1" +version = "2.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "143b538f18257fac9cad154828a57c6bf5157e1aa604d4816b5995bf6de87ae5" +checksum = "22784dbdf76fdde8af1aeda5622b546b422b6fc585325248a2bf9f5e41e94d6c" 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.5.0" +version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88ad59a7560b41a70d191093a945f0b87bc1deeda46fb237479708a1d6b6cdfc" - -[[package]] -name = "winapi" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +checksum = "81dfa00651efa65069b0b6b651f4aaa31ba9e3c3ce0137aaad053604ee7e0314" dependencies = [ - "winapi-i686-pc-windows-gnu", - "winapi-x86_64-pc-windows-gnu", + "serde", ] [[package]] -name = "winapi-i686-pc-windows-gnu" -version = "0.4.0" +name = "uuid-simd" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" +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" [[package]] name = "winapi-util" -version = "0.1.6" +version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f29e6f9198ba0d26b4c9f07dbe6f9ed633e1f3d5b8b414090084349e46a52596" +checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb" dependencies = [ - "winapi", + "windows-sys 0.59.0", ] [[package]] -name = "winapi-x86_64-pc-windows-gnu" -version = "0.4.0" +name = "windows-sys" +version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" +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", +] [[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 d26db12..b8afef2 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.65+](https://img.shields.io/badge/msrv-1.65-blue)](https://blog.rust-lang.org/2022/11/03/Rust-1.65.0.html) +[![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) Generate JSON Schema documents from Rust code diff --git a/schemars/Cargo.toml b/schemars/Cargo.toml index 8139ae0..384f3ea 100644 --- a/schemars/Cargo.toml +++ b/schemars/Cargo.toml @@ -10,7 +10,7 @@ license = "MIT" readme = "README.md" keywords = ["rust", "json-schema", "serde"] categories = ["encoding", "no-std"] -rust-version = "1.65" +rust-version = "1.70" [dependencies] schemars_derive = { version = "=1.0.0-alpha.15", optional = true, path = "../schemars_derive" } @@ -24,9 +24,9 @@ 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" } 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,6 +37,26 @@ 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.19.0", 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"] @@ -59,62 +79,10 @@ 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 = "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/json_schema_impls/bytes1.rs b/schemars/src/json_schema_impls/bytes1.rs new file mode 100644 index 0000000..f679e0d --- /dev/null +++ b/schemars/src/json_schema_impls/bytes1.rs @@ -0,0 +1,29 @@ +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 a153aca..700af09 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-date-time"); +formatted_string_impl!(NaiveTime, "partial-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 0e9a129..2be1684 100644 --- a/schemars/src/json_schema_impls/either1.rs +++ b/schemars/src/json_schema_impls/either1.rs @@ -17,7 +17,28 @@ impl JsonSchema for Either { fn json_schema(generator: &mut SchemaGenerator) -> Schema { json_schema!({ - "anyOf": [generator.subschema_for::(), generator.subschema_for::()], + "oneOf": [ + { + "type": "object", + "properties": { + "Left": generator.subschema_for::() + }, + "additionalProperties": false, + "required": [ + "Left" + ] + }, + { + "type": "object", + "properties": { + "Right": generator.subschema_for::() + }, + "additionalProperties": false, + "required": [ + "Right" + ] + } + ] }) } } diff --git a/schemars/src/json_schema_impls/ffi.rs b/schemars/src/json_schema_impls/ffi.rs index cf2efe5..638fb6c 100644 --- a/schemars/src/json_schema_impls/ffi.rs +++ b/schemars/src/json_schema_impls/ffi.rs @@ -2,6 +2,7 @@ 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 { @@ -37,5 +38,31 @@ impl JsonSchema for OsString { forward_impl!(OsStr => OsString); -forward_impl!(CString => Vec); -forward_impl!(CStr => Vec); +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); diff --git a/schemars/src/json_schema_impls/mod.rs b/schemars/src/json_schema_impls/mod.rs index 0a8bcb3..cbe1a07 100644 --- a/schemars/src/json_schema_impls/mod.rs +++ b/schemars/src/json_schema_impls/mod.rs @@ -42,8 +42,7 @@ macro_rules! forward_impl { mod array; mod core; mod maps; -mod nonzero_signed; -mod nonzero_unsigned; +mod nonzero; mod primitives; mod sequences; mod serdejson; @@ -61,10 +60,7 @@ mod ffi; mod arrayvec07; #[cfg(feature = "bytes1")] -mod bytes1 { - forward_impl!(bytes1::Bytes => alloc::vec::Vec); - forward_impl!(bytes1::BytesMut => alloc::vec::Vec); -} +mod bytes1; #[cfg(feature = "chrono04")] mod chrono04; diff --git a/schemars/src/json_schema_impls/nonzero.rs b/schemars/src/json_schema_impls/nonzero.rs new file mode 100644 index 0000000..ede0c58 --- /dev/null +++ b/schemars/src/json_schema_impls/nonzero.rs @@ -0,0 +1,64 @@ +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 deleted file mode 100644 index c5b3e84..0000000 --- a/schemars/src/json_schema_impls/nonzero_signed.rs +++ /dev/null @@ -1,37 +0,0 @@ -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 deleted file mode 100644 index c6711ab..0000000 --- a/schemars/src/json_schema_impls/nonzero_unsigned.rs +++ /dev/null @@ -1,36 +0,0 @@ -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 1869fa9..65ec8d3 100644 --- a/schemars/src/json_schema_impls/semver1.rs +++ b/schemars/src/json_schema_impls/semver1.rs @@ -4,10 +4,8 @@ use alloc::borrow::Cow; use semver1::Version; impl JsonSchema for Version { - always_inline!(); - fn schema_name() -> Cow<'static, str> { - "Version".into() + "SemVer".into() } fn schema_id() -> Cow<'static, str> { diff --git a/schemars/tests/actual/README.md b/schemars/tests/actual/README.md deleted file mode 100644 index 9fbbbab..0000000 --- a/schemars/tests/actual/README.md +++ /dev/null @@ -1,3 +0,0 @@ -# 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 deleted file mode 100644 index e32d1a7..0000000 --- a/schemars/tests/arrayvec.rs +++ /dev/null @@ -1,12 +0,0 @@ -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/bytes.rs b/schemars/tests/bytes.rs deleted file mode 100644 index 5797411..0000000 --- a/schemars/tests/bytes.rs +++ /dev/null @@ -1,8 +0,0 @@ -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 deleted file mode 100644 index da6f8d4..0000000 --- a/schemars/tests/chrono.rs +++ /dev/null @@ -1,19 +0,0 @@ -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 deleted file mode 100644 index bd5160c..0000000 --- a/schemars/tests/contract.rs +++ /dev/null @@ -1,214 +0,0 @@ -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 deleted file mode 100644 index e5d56f9..0000000 --- a/schemars/tests/crate_alias.rs +++ /dev/null @@ -1,20 +0,0 @@ -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 deleted file mode 100644 index 246e813..0000000 --- a/schemars/tests/decimal.rs +++ /dev/null @@ -1,12 +0,0 @@ -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 deleted file mode 100644 index ab489f5..0000000 --- a/schemars/tests/default.rs +++ /dev/null @@ -1,59 +0,0 @@ -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 deleted file mode 100644 index 1772a8f..0000000 --- a/schemars/tests/deprecated.rs +++ /dev/null @@ -1,39 +0,0 @@ -#![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/either.rs b/schemars/tests/either.rs deleted file mode 100644 index 5dcd079..0000000 --- a/schemars/tests/either.rs +++ /dev/null @@ -1,8 +0,0 @@ -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 deleted file mode 100644 index 45698a7..0000000 --- a/schemars/tests/enum.rs +++ /dev/null @@ -1,185 +0,0 @@ -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 deleted file mode 100644 index ef56d05..0000000 --- a/schemars/tests/enum_deny_unknown_fields.rs +++ /dev/null @@ -1,127 +0,0 @@ -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 deleted file mode 100644 index 4c94a4c..0000000 --- a/schemars/tests/enum_flatten.rs +++ /dev/null @@ -1,89 +0,0 @@ -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 deleted file mode 100644 index d318347..0000000 --- a/schemars/tests/enum_repr.rs +++ /dev/null @@ -1,35 +0,0 @@ -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/expected/arrayvec_string.json b/schemars/tests/expected/arrayvec_string.json deleted file mode 100644 index 0604332..0000000 --- a/schemars/tests/expected/arrayvec_string.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "$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/bytes.json b/schemars/tests/expected/bytes.json deleted file mode 100644 index 80486c1..0000000 --- a/schemars/tests/expected/bytes.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "$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/expected/default.json b/schemars/tests/expected/default.json deleted file mode 100644 index 72e580d..0000000 --- a/schemars/tests/expected/default.json +++ /dev/null @@ -1,52 +0,0 @@ -{ - "$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/expected/duration_and_systemtime.json b/schemars/tests/expected/duration_and_systemtime.json deleted file mode 100644 index 7e301e5..0000000 --- a/schemars/tests/expected/duration_and_systemtime.json +++ /dev/null @@ -1,57 +0,0 @@ -{ - "$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 deleted file mode 100644 index 18d8f51..0000000 --- a/schemars/tests/expected/either.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "$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/expected/enum-adjacent-tagged-duf.json b/schemars/tests/expected/enum-adjacent-tagged-duf.json deleted file mode 100644 index b181f55..0000000 --- a/schemars/tests/expected/enum-adjacent-tagged-duf.json +++ /dev/null @@ -1,184 +0,0 @@ -{ - "$schema": "https://json-schema.org/draft/2020-12/schema", - "title": "Adjacent", - "oneOf": [ - { - "type": "object", - "properties": { - "t": { - "type": "string", - "const": "UnitOne" - } - }, - "required": [ - "t" - ], - "additionalProperties": false - }, - { - "type": "object", - "properties": { - "t": { - "type": "string", - "const": "StringMap" - }, - "c": { - "type": "object", - "additionalProperties": { - "type": "string" - } - } - }, - "required": [ - "t", - "c" - ], - "additionalProperties": false - }, - { - "type": "object", - "properties": { - "t": { - "type": "string", - "const": "UnitStructNewType" - }, - "c": { - "$ref": "#/$defs/UnitStruct" - } - }, - "required": [ - "t", - "c" - ], - "additionalProperties": false - }, - { - "type": "object", - "properties": { - "t": { - "type": "string", - "const": "StructNewType" - }, - "c": { - "$ref": "#/$defs/Struct" - } - }, - "required": [ - "t", - "c" - ], - "additionalProperties": false - }, - { - "type": "object", - "properties": { - "t": { - "type": "string", - "const": "Struct" - }, - "c": { - "type": "object", - "properties": { - "foo": { - "type": "integer", - "format": "int32" - }, - "bar": { - "type": "boolean" - } - }, - "additionalProperties": false, - "required": [ - "foo", - "bar" - ] - } - }, - "required": [ - "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": { - "foo": { - "type": "integer", - "format": "int32" - }, - "bar": { - "type": "boolean" - } - }, - "required": [ - "foo", - "bar" - ] - } - } -} \ 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 deleted file mode 100644 index 422a694..0000000 --- a/schemars/tests/expected/enum-rename-all-fields.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "$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 deleted file mode 100644 index eb237be..0000000 --- a/schemars/tests/expected/enum-rename-all.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "$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 deleted file mode 100644 index a9f3706..0000000 --- a/schemars/tests/expected/enum-rename-attr.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "$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/expected/enum-simple-internal-duf.json b/schemars/tests/expected/enum-simple-internal-duf.json deleted file mode 100644 index aaf1eef..0000000 --- a/schemars/tests/expected/enum-simple-internal-duf.json +++ /dev/null @@ -1,45 +0,0 @@ -{ - "$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 deleted file mode 100644 index e955d2a..0000000 --- a/schemars/tests/expected/enum-simple-internal.json +++ /dev/null @@ -1,42 +0,0 @@ -{ - "$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/expected/from_value_2019_09.json b/schemars/tests/expected/from_value_2019_09.json deleted file mode 100644 index 939410d..0000000 --- a/schemars/tests/expected/from_value_2019_09.json +++ /dev/null @@ -1,76 +0,0 @@ -{ - "$schema": "https://json-schema.org/draft/2019-09/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/expected/indexmap.json b/schemars/tests/expected/indexmap.json deleted file mode 100644 index 8ba90a8..0000000 --- a/schemars/tests/expected/indexmap.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "$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/expected/macro_built_enum.json b/schemars/tests/expected/macro_built_enum.json deleted file mode 100644 index b27df44..0000000 --- a/schemars/tests/expected/macro_built_enum.json +++ /dev/null @@ -1,32 +0,0 @@ -{ - "$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 deleted file mode 100644 index 1d0fd08..0000000 --- a/schemars/tests/expected/macro_built_struct.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "$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/expected/no_std.json b/schemars/tests/expected/no_std.json deleted file mode 100644 index 68da890..0000000 --- a/schemars/tests/expected/no_std.json +++ /dev/null @@ -1,70 +0,0 @@ -{ - "$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 deleted file mode 100644 index 432e3b0..0000000 --- a/schemars/tests/expected/nonzero_ints.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "$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 deleted file mode 100644 index 72e0be1..0000000 --- a/schemars/tests/expected/os_strings.json +++ /dev/null @@ -1,55 +0,0 @@ -{ - "$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/expected/range.json b/schemars/tests/expected/range.json deleted file mode 100644 index 64db4bd..0000000 --- a/schemars/tests/expected/range.json +++ /dev/null @@ -1,89 +0,0 @@ -{ - "$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/expected/result.json b/schemars/tests/expected/result.json deleted file mode 100644 index b468835..0000000 --- a/schemars/tests/expected/result.json +++ /dev/null @@ -1,86 +0,0 @@ -{ - "$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 deleted file mode 100644 index 5e1f4c8..0000000 --- a/schemars/tests/expected/rust_decimal.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "$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/expected/schema-name-custom.json b/schemars/tests/expected/schema-name-custom.json deleted file mode 100644 index 70b4d98..0000000 --- a/schemars/tests/expected/schema-name-custom.json +++ /dev/null @@ -1,47 +0,0 @@ -{ - "$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 deleted file mode 100644 index 2243ddd..0000000 --- a/schemars/tests/expected/schema-name-default.json +++ /dev/null @@ -1,47 +0,0 @@ -{ - "$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 deleted file mode 100644 index 85c6792..0000000 --- a/schemars/tests/expected/schema-name-mixed-generics.json +++ /dev/null @@ -1,63 +0,0 @@ -{ - "$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/expected/schema_with-enum-adjacent-tagged.json b/schemars/tests/expected/schema_with-enum-adjacent-tagged.json deleted file mode 100644 index e5877ba..0000000 --- a/schemars/tests/expected/schema_with-enum-adjacent-tagged.json +++ /dev/null @@ -1,89 +0,0 @@ -{ - "$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-internal.json b/schemars/tests/expected/schema_with-enum-internal.json deleted file mode 100644 index e6d707b..0000000 --- a/schemars/tests/expected/schema_with-enum-internal.json +++ /dev/null @@ -1,46 +0,0 @@ -{ - "$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 deleted file mode 100644 index 9057c87..0000000 --- a/schemars/tests/expected/schema_with-enum-untagged.json +++ /dev/null @@ -1,37 +0,0 @@ -{ - "$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 deleted file mode 100644 index eb4a2f6..0000000 --- a/schemars/tests/expected/schema_with-newtype.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "$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-transparent-newtype.json b/schemars/tests/expected/schema_with-transparent-newtype.json deleted file mode 100644 index 2aeff68..0000000 --- a/schemars/tests/expected/schema_with-transparent-newtype.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "$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 deleted file mode 100644 index 1296e33..0000000 --- a/schemars/tests/expected/schema_with-tuple.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "$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 deleted file mode 100644 index 9f5b155..0000000 --- a/schemars/tests/expected/semver.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "$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 deleted file mode 100644 index bd3a893..0000000 --- a/schemars/tests/expected/skip_enum_variants.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "$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 deleted file mode 100644 index 16e2fea..0000000 --- a/schemars/tests/expected/skip_struct_fields.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "$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/expected/struct-newtype.json b/schemars/tests/expected/struct-newtype.json deleted file mode 100644 index e7b1cba..0000000 --- a/schemars/tests/expected/struct-newtype.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "$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/expected/struct-normal-additional-properties.json b/schemars/tests/expected/struct-normal-additional-properties.json deleted file mode 100644 index 2c55fb7..0000000 --- a/schemars/tests/expected/struct-normal-additional-properties.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "$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" - ] - } - }, - "additionalProperties": false, - "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 deleted file mode 100644 index 8960068..0000000 --- a/schemars/tests/expected/struct-tuple.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "$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/expected/test_flattened_struct_deny_unknown_fields.json b/schemars/tests/expected/test_flattened_struct_deny_unknown_fields.json deleted file mode 100644 index 1ac94b5..0000000 --- a/schemars/tests/expected/test_flattened_struct_deny_unknown_fields.json +++ /dev/null @@ -1,52 +0,0 @@ -{ - "$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/expected/transparent-struct.json b/schemars/tests/expected/transparent-struct.json deleted file mode 100644 index 2692069..0000000 --- a/schemars/tests/expected/transparent-struct.json +++ /dev/null @@ -1,33 +0,0 @@ -{ - "$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/expected/validate.json b/schemars/tests/expected/validate.json deleted file mode 100644 index 64b571f..0000000 --- a/schemars/tests/expected/validate.json +++ /dev/null @@ -1,84 +0,0 @@ -{ - "$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 deleted file mode 100644 index a77e0d7..0000000 --- a/schemars/tests/expected/validate_inner.json +++ /dev/null @@ -1,74 +0,0 @@ -{ - "$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 deleted file mode 100644 index cd835f5..0000000 --- a/schemars/tests/expected/validate_newtype.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "$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 deleted file mode 100644 index 1f2e3eb..0000000 --- a/schemars/tests/expected/validate_schemars_attrs.json +++ /dev/null @@ -1,84 +0,0 @@ -{ - "$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 deleted file mode 100644 index fa81224..0000000 --- a/schemars/tests/expected/validate_tuple.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "$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 deleted file mode 100644 index 2b44f5e..0000000 --- a/schemars/tests/extend.rs +++ /dev/null @@ -1,96 +0,0 @@ -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 deleted file mode 100644 index 41bb8ce..0000000 --- a/schemars/tests/ffi.rs +++ /dev/null @@ -1,16 +0,0 @@ -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 deleted file mode 100644 index a05a5c0..0000000 --- a/schemars/tests/flatten.rs +++ /dev/null @@ -1,115 +0,0 @@ -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 deleted file mode 100644 index 0934cfd..0000000 --- a/schemars/tests/from_value.rs +++ /dev/null @@ -1,94 +0,0 @@ -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 deleted file mode 100644 index 8b7ce85..0000000 --- a/schemars/tests/garde.rs +++ /dev/null @@ -1,99 +0,0 @@ -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 deleted file mode 100644 index 76fcd56..0000000 --- a/schemars/tests/indexmap.rs +++ /dev/null @@ -1,18 +0,0 @@ -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 deleted file mode 100644 index a377847..0000000 --- a/schemars/tests/inline_subschemas.rs +++ /dev/null @@ -1,43 +0,0 @@ -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 new file mode 100644 index 0000000..177737a --- /dev/null +++ b/schemars/tests/integration/arrayvec.rs @@ -0,0 +1,36 @@ +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/bound.rs b/schemars/tests/integration/bound.rs similarity index 57% rename from schemars/tests/bound.rs rename to schemars/tests/integration/bound.rs index cb545dd..71dfba3 100644 --- a/schemars/tests/bound.rs +++ b/schemars/tests/integration/bound.rs @@ -1,9 +1,6 @@ -mod util; +use crate::prelude::*; use std::marker::PhantomData; -use schemars::JsonSchema; -use util::*; - struct MyIterator; impl Iterator for MyIterator { @@ -16,7 +13,7 @@ impl Iterator for MyIterator { // The default trait bounds would require T to implement JsonSchema, // which MyIterator does not. -#[derive(JsonSchema)] +#[derive(JsonSchema, Serialize, Deserialize)] #[schemars(bound = "T::Item: JsonSchema", rename = "MyContainer")] pub struct MyContainer where @@ -27,6 +24,12 @@ where } #[test] -fn manual_bound_set() -> TestResult { - test_default_generated_schema::>("bound") +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()); } diff --git a/schemars/tests/integration/bytes.rs b/schemars/tests/integration/bytes.rs new file mode 100644 index 0000000..a0653b0 --- /dev/null +++ b/schemars/tests/integration/bytes.rs @@ -0,0 +1,24 @@ +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 new file mode 100644 index 0000000..e7d5289 --- /dev/null +++ b/schemars/tests/integration/chrono.rs @@ -0,0 +1,42 @@ +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 new file mode 100644 index 0000000..300a19c --- /dev/null +++ b/schemars/tests/integration/contract.rs @@ -0,0 +1,254 @@ +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 new file mode 100644 index 0000000..f84fe22 --- /dev/null +++ b/schemars/tests/integration/crate_alias.rs @@ -0,0 +1,19 @@ +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 new file mode 100644 index 0000000..77055df --- /dev/null +++ b/schemars/tests/integration/decimal.rs @@ -0,0 +1,19 @@ +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 new file mode 100644 index 0000000..6df51cc --- /dev/null +++ b/schemars/tests/integration/default.rs @@ -0,0 +1,95 @@ +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 new file mode 100644 index 0000000..9bdfbef --- /dev/null +++ b/schemars/tests/integration/deprecated.rs @@ -0,0 +1,69 @@ +#![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/docs.rs b/schemars/tests/integration/docs.rs similarity index 81% rename from schemars/tests/docs.rs rename to schemars/tests/integration/docs.rs index 7086c69..4ca11c7 100644 --- a/schemars/tests/docs.rs +++ b/schemars/tests/integration/docs.rs @@ -1,6 +1,4 @@ -mod util; -use schemars::JsonSchema; -use util::*; +use crate::prelude::*; #[allow(dead_code)] #[derive(JsonSchema)] @@ -24,6 +22,11 @@ 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 "] @@ -55,13 +58,8 @@ enum MyEnum { } #[test] -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") +fn doc_comments_enum() { + test!(MyEnum).assert_snapshot(); } /// # OverrideDocs struct @@ -82,6 +80,6 @@ struct OverrideDocs { } #[test] -fn doc_comments_override() -> TestResult { - test_default_generated_schema::("doc_comments_override") +fn doc_comments_override() { + test!(OverrideDocs).assert_snapshot(); } diff --git a/schemars/tests/integration/either.rs b/schemars/tests/integration/either.rs new file mode 100644 index 0000000..2e5a574 --- /dev/null +++ b/schemars/tests/integration/either.rs @@ -0,0 +1,14 @@ +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 new file mode 100644 index 0000000..f9a8841 --- /dev/null +++ b/schemars/tests/integration/enum_repr.rs @@ -0,0 +1,37 @@ +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 new file mode 100644 index 0000000..f6cd6bc --- /dev/null +++ b/schemars/tests/integration/enums.rs @@ -0,0 +1,360 @@ +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 new file mode 100644 index 0000000..9eb79bf --- /dev/null +++ b/schemars/tests/integration/enums_deny_unknown_fields.rs @@ -0,0 +1,162 @@ +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::Struct { + foo: 123, + bar: true, + }, + ] + } + }; +} + +#[derive(JsonSchema, Deserialize, Serialize, Default)] +struct Struct { + foo: i32, + bar: bool, +} + +#[derive(JsonSchema, Deserialize, Serialize)] +#[serde(deny_unknown_fields)] +enum External { + Unit, + StringMap(BTreeMap), + StructNewType(Struct), + 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), + 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), + 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), + 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 + } + })]) + .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 + })]) + .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 + } + })]) + .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_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 new file mode 100644 index 0000000..dd0f2f7 --- /dev/null +++ b/schemars/tests/integration/enums_flattened.rs @@ -0,0 +1,135 @@ +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/examples.rs b/schemars/tests/integration/examples.rs similarity index 67% rename from schemars/tests/examples.rs rename to schemars/tests/integration/examples.rs index bbe9af5..43b7419 100644 --- a/schemars/tests/examples.rs +++ b/schemars/tests/integration/examples.rs @@ -1,7 +1,4 @@ -mod util; -use schemars::JsonSchema; -use serde::Serialize; -use util::*; +use crate::prelude::*; #[derive(Default, JsonSchema, Serialize)] #[schemars(example = "Struct::default", example = "null")] @@ -20,6 +17,6 @@ fn eight() -> i32 { fn null() {} #[test] -fn examples() -> TestResult { - test_default_generated_schema::("examples") +fn examples() { + test!(Struct).assert_snapshot(); } diff --git a/schemars/tests/integration/extend.rs b/schemars/tests/integration/extend.rs new file mode 100644 index 0000000..e6f9506 --- /dev/null +++ b/schemars/tests/integration/extend.rs @@ -0,0 +1,169 @@ +#![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 new file mode 100644 index 0000000..fe3bf83 --- /dev/null +++ b/schemars/tests/integration/flatten.rs @@ -0,0 +1,93 @@ +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 new file mode 100644 index 0000000..32afa1d --- /dev/null +++ b/schemars/tests/integration/from_value.rs @@ -0,0 +1,84 @@ +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 new file mode 100644 index 0000000..e7ca2a5 --- /dev/null +++ b/schemars/tests/integration/garde.rs @@ -0,0 +1,159 @@ +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 new file mode 100644 index 0000000..c6ef7d5 --- /dev/null +++ b/schemars/tests/integration/indexmap.rs @@ -0,0 +1,19 @@ +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 new file mode 100644 index 0000000..214a758 --- /dev/null +++ b/schemars/tests/integration/inline_subschemas.rs @@ -0,0 +1,61 @@ +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/macro.rs b/schemars/tests/integration/macros.rs similarity index 70% rename from schemars/tests/macro.rs rename to schemars/tests/integration/macros.rs index 25323ca..92c3370 100644 --- a/schemars/tests/macro.rs +++ b/schemars/tests/integration/macros.rs @@ -1,13 +1,10 @@ -mod util; -use schemars::JsonSchema; -use util::*; +use crate::prelude::*; macro_rules! build_struct { ( $id:ident { $($t:tt)* } ) => { - #[allow(dead_code)] - #[derive(JsonSchema)] + #[derive(JsonSchema, Deserialize, Serialize, Default)] pub struct $id { x: u8, $($t)* @@ -18,8 +15,8 @@ macro_rules! build_struct { build_struct!(A { v: i32 }); #[test] -fn macro_built_struct() -> TestResult { - test_default_generated_schema::("macro_built_struct") +fn macro_built_struct() { + test!(A).assert_allows_ser_roundtrip_default(); } macro_rules! build_enum { @@ -54,9 +51,9 @@ macro_rules! build_enum { } build_enum!( - #[derive(JsonSchema)] + #[derive(JsonSchema, Deserialize, Serialize)] OuterEnum { - #[derive(JsonSchema)] + #[derive(JsonSchema, Deserialize, Serialize, Default)] InnerStruct { x: i32 } @@ -65,6 +62,6 @@ build_enum!( ); #[test] -fn macro_built_enum() -> TestResult { - test_default_generated_schema::("macro_built_enum") +fn macro_built_enum() { + test!(OuterEnum).assert_allows_ser_roundtrip([OuterEnum::InnerStruct(InnerStruct::default())]); } diff --git a/schemars/tests/integration/main.rs b/schemars/tests/integration/main.rs new file mode 100644 index 0000000..eb44526 --- /dev/null +++ b/schemars/tests/integration/main.rs @@ -0,0 +1,94 @@ +#![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 new file mode 100644 index 0000000..89ecaaf --- /dev/null +++ b/schemars/tests/integration/remote_derive.rs @@ -0,0 +1,91 @@ +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 new file mode 100644 index 0000000..02f3795 --- /dev/null +++ b/schemars/tests/integration/same_name.rs @@ -0,0 +1,44 @@ +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 new file mode 100644 index 0000000..e04a747 --- /dev/null +++ b/schemars/tests/integration/schema_name.rs @@ -0,0 +1,81 @@ +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 new file mode 100644 index 0000000..e8c0a11 --- /dev/null +++ b/schemars/tests/integration/schema_with.rs @@ -0,0 +1,46 @@ +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 new file mode 100644 index 0000000..637b719 --- /dev/null +++ b/schemars/tests/integration/semver.rs @@ -0,0 +1,32 @@ +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 new file mode 100644 index 0000000..f6debe6 --- /dev/null +++ b/schemars/tests/integration/settings.rs @@ -0,0 +1,68 @@ +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 new file mode 100644 index 0000000..ea2c233 --- /dev/null +++ b/schemars/tests/integration/skip.rs @@ -0,0 +1,41 @@ +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 new file mode 100644 index 0000000..03b341b --- /dev/null +++ b/schemars/tests/integration/smallvec.rs @@ -0,0 +1,10 @@ +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 new file mode 100644 index 0000000..9522c87 --- /dev/null +++ b/schemars/tests/integration/smol_str.rs @@ -0,0 +1,11 @@ +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/expected/arrayvec.json b/schemars/tests/integration/snapshots/schemars/tests/integration/arrayvec.rs~arrayvec07.json similarity index 70% rename from schemars/tests/expected/arrayvec.json rename to schemars/tests/integration/snapshots/schemars/tests/integration/arrayvec.rs~arrayvec07.json index 998d087..df98947 100644 --- a/schemars/tests/expected/arrayvec.json +++ b/schemars/tests/integration/snapshots/schemars/tests/integration/arrayvec.rs~arrayvec07.json @@ -1,10 +1,10 @@ { "$schema": "https://json-schema.org/draft/2020-12/schema", - "title": "Array_up_to_size_16_of_int32", + "title": "Array_up_to_size_8_of_int32", "type": "array", "items": { "type": "integer", "format": "int32" }, - "maxItems": 16 + "maxItems": 8 } \ No newline at end of file diff --git a/schemars/tests/expected/bound.json b/schemars/tests/integration/snapshots/schemars/tests/integration/bound.rs~manual_bound_set.json similarity index 100% rename from schemars/tests/expected/bound.json rename to schemars/tests/integration/snapshots/schemars/tests/integration/bound.rs~manual_bound_set.json 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 new file mode 100644 index 0000000..65cbb8a --- /dev/null +++ b/schemars/tests/integration/snapshots/schemars/tests/integration/bytes.rs~bytes.de.json @@ -0,0 +1,13 @@ +{ + "$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/expected/smallvec.json b/schemars/tests/integration/snapshots/schemars/tests/integration/bytes.rs~bytes.ser.json similarity index 54% rename from schemars/tests/expected/smallvec.json rename to schemars/tests/integration/snapshots/schemars/tests/integration/bytes.rs~bytes.ser.json index be50ed7..f54610b 100644 --- a/schemars/tests/expected/smallvec.json +++ b/schemars/tests/integration/snapshots/schemars/tests/integration/bytes.rs~bytes.ser.json @@ -1,8 +1,10 @@ { "$schema": "https://json-schema.org/draft/2020-12/schema", - "title": "Array_of_string", + "title": "Bytes", "type": "array", "items": { - "type": "string" + "type": "integer", + "format": "uint8", + "minimum": 0 } } \ No newline at end of file diff --git a/schemars/tests/expected/chrono-types.json b/schemars/tests/integration/snapshots/schemars/tests/integration/chrono.rs~chrono.json similarity index 95% rename from schemars/tests/expected/chrono-types.json rename to schemars/tests/integration/snapshots/schemars/tests/integration/chrono.rs~chrono.json index de26130..b2477c2 100644 --- a/schemars/tests/expected/chrono-types.json +++ b/schemars/tests/integration/snapshots/schemars/tests/integration/chrono.rs~chrono.json @@ -29,7 +29,7 @@ }, "naive_time": { "type": "string", - "format": "partial-date-time" + "format": "partial-time" } }, "required": [ diff --git a/schemars/tests/expected/contract_deserialize_adjacent_tag_enum.json b/schemars/tests/integration/snapshots/schemars/tests/integration/contract.rs~adjacently_tagged_enum.de.json similarity index 100% rename from schemars/tests/expected/contract_deserialize_adjacent_tag_enum.json rename to schemars/tests/integration/snapshots/schemars/tests/integration/contract.rs~adjacently_tagged_enum.de.json diff --git a/schemars/tests/expected/contract_serialize_adjacent_tag_enum.json b/schemars/tests/integration/snapshots/schemars/tests/integration/contract.rs~adjacently_tagged_enum.ser.json similarity index 100% rename from schemars/tests/expected/contract_serialize_adjacent_tag_enum.json rename to schemars/tests/integration/snapshots/schemars/tests/integration/contract.rs~adjacently_tagged_enum.ser.json diff --git a/schemars/tests/expected/contract_deserialize_external_tag_enum.json b/schemars/tests/integration/snapshots/schemars/tests/integration/contract.rs~externally_tagged_enum.de.json similarity index 100% rename from schemars/tests/expected/contract_deserialize_external_tag_enum.json rename to schemars/tests/integration/snapshots/schemars/tests/integration/contract.rs~externally_tagged_enum.de.json diff --git a/schemars/tests/expected/contract_serialize_external_tag_enum.json b/schemars/tests/integration/snapshots/schemars/tests/integration/contract.rs~externally_tagged_enum.ser.json similarity index 100% rename from schemars/tests/expected/contract_serialize_external_tag_enum.json rename to schemars/tests/integration/snapshots/schemars/tests/integration/contract.rs~externally_tagged_enum.ser.json diff --git a/schemars/tests/expected/contract_deserialize_internal_tag_enum.json b/schemars/tests/integration/snapshots/schemars/tests/integration/contract.rs~internally_tagged_enum.de.json similarity index 100% rename from schemars/tests/expected/contract_deserialize_internal_tag_enum.json rename to schemars/tests/integration/snapshots/schemars/tests/integration/contract.rs~internally_tagged_enum.de.json diff --git a/schemars/tests/expected/contract_serialize_internal_tag_enum.json b/schemars/tests/integration/snapshots/schemars/tests/integration/contract.rs~internally_tagged_enum.ser.json similarity index 100% rename from schemars/tests/expected/contract_serialize_internal_tag_enum.json rename to schemars/tests/integration/snapshots/schemars/tests/integration/contract.rs~internally_tagged_enum.ser.json diff --git a/schemars/tests/expected/contract_deserialize.json b/schemars/tests/integration/snapshots/schemars/tests/integration/contract.rs~struct_allow_unknown_fields.de.json similarity index 93% rename from schemars/tests/expected/contract_deserialize.json rename to schemars/tests/integration/snapshots/schemars/tests/integration/contract.rs~struct_allow_unknown_fields.de.json index 6b24d01..6281568 100644 --- a/schemars/tests/expected/contract_deserialize.json +++ b/schemars/tests/integration/snapshots/schemars/tests/integration/contract.rs~struct_allow_unknown_fields.de.json @@ -1,6 +1,6 @@ { "$schema": "https://json-schema.org/draft/2020-12/schema", - "title": "MyStruct", + "title": "StructAllowUnknownFields", "type": "object", "properties": { "write_only": { diff --git a/schemars/tests/expected/contract_serialize.json b/schemars/tests/integration/snapshots/schemars/tests/integration/contract.rs~struct_allow_unknown_fields.ser.json similarity index 93% rename from schemars/tests/expected/contract_serialize.json rename to schemars/tests/integration/snapshots/schemars/tests/integration/contract.rs~struct_allow_unknown_fields.ser.json index b82231f..c405275 100644 --- a/schemars/tests/expected/contract_serialize.json +++ b/schemars/tests/integration/snapshots/schemars/tests/integration/contract.rs~struct_allow_unknown_fields.ser.json @@ -1,6 +1,6 @@ { "$schema": "https://json-schema.org/draft/2020-12/schema", - "title": "MyStruct", + "title": "StructAllowUnknownFields", "type": "object", "properties": { "READ-ONLY": { 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 new file mode 100644 index 0000000..b605204 --- /dev/null +++ b/schemars/tests/integration/snapshots/schemars/tests/integration/contract.rs~struct_deny_unknown_fields.de.json @@ -0,0 +1,33 @@ +{ + "$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 new file mode 100644 index 0000000..fd118c6 --- /dev/null +++ b/schemars/tests/integration/snapshots/schemars/tests/integration/contract.rs~struct_deny_unknown_fields.ser.json @@ -0,0 +1,35 @@ +{ + "$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/expected/contract_deserialize_tuple_struct.json b/schemars/tests/integration/snapshots/schemars/tests/integration/contract.rs~tuple_struct.de.json similarity index 100% rename from schemars/tests/expected/contract_deserialize_tuple_struct.json rename to schemars/tests/integration/snapshots/schemars/tests/integration/contract.rs~tuple_struct.de.json diff --git a/schemars/tests/expected/contract_serialize_tuple_struct.json b/schemars/tests/integration/snapshots/schemars/tests/integration/contract.rs~tuple_struct.ser.json similarity index 100% rename from schemars/tests/expected/contract_serialize_tuple_struct.json rename to schemars/tests/integration/snapshots/schemars/tests/integration/contract.rs~tuple_struct.ser.json diff --git a/schemars/tests/expected/contract_deserialize_untagged_enum.json b/schemars/tests/integration/snapshots/schemars/tests/integration/contract.rs~untagged_enum.de.json similarity index 100% rename from schemars/tests/expected/contract_deserialize_untagged_enum.json rename to schemars/tests/integration/snapshots/schemars/tests/integration/contract.rs~untagged_enum.de.json diff --git a/schemars/tests/expected/contract_serialize_untagged_enum.json b/schemars/tests/integration/snapshots/schemars/tests/integration/contract.rs~untagged_enum.ser.json similarity index 100% rename from schemars/tests/expected/contract_serialize_untagged_enum.json rename to schemars/tests/integration/snapshots/schemars/tests/integration/contract.rs~untagged_enum.ser.json diff --git a/schemars/tests/expected/bigdecimal04.json b/schemars/tests/integration/snapshots/schemars/tests/integration/decimal.rs~decimal_types.de.json similarity index 100% rename from schemars/tests/expected/bigdecimal04.json rename to schemars/tests/integration/snapshots/schemars/tests/integration/decimal.rs~decimal_types.de.json 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 new file mode 100644 index 0000000..e94ca27 --- /dev/null +++ b/schemars/tests/integration/snapshots/schemars/tests/integration/decimal.rs~decimal_types.ser.json @@ -0,0 +1,6 @@ +{ + "$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 new file mode 100644 index 0000000..e3168e2 --- /dev/null +++ b/schemars/tests/integration/snapshots/schemars/tests/integration/default.rs~default_fields.de.json @@ -0,0 +1,42 @@ +{ + "$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 new file mode 100644 index 0000000..f80c324 --- /dev/null +++ b/schemars/tests/integration/snapshots/schemars/tests/integration/default.rs~default_fields.ser.json @@ -0,0 +1,38 @@ +{ + "$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/expected/deprecated-enum.json b/schemars/tests/integration/snapshots/schemars/tests/integration/deprecated.rs~deprecated_enum.json similarity index 100% rename from schemars/tests/expected/deprecated-enum.json rename to schemars/tests/integration/snapshots/schemars/tests/integration/deprecated.rs~deprecated_enum.json diff --git a/schemars/tests/expected/deprecated-struct.json b/schemars/tests/integration/snapshots/schemars/tests/integration/deprecated.rs~deprecated_struct.json similarity index 86% rename from schemars/tests/expected/deprecated-struct.json rename to schemars/tests/integration/snapshots/schemars/tests/integration/deprecated.rs~deprecated_struct.json index b7396ab..55967e5 100644 --- a/schemars/tests/expected/deprecated-struct.json +++ b/schemars/tests/integration/snapshots/schemars/tests/integration/deprecated.rs~deprecated_struct.json @@ -7,14 +7,14 @@ "type": "integer", "format": "int32" }, - "deprecated_field": { + "bar": { "type": "boolean", "deprecated": true } }, "required": [ "foo", - "deprecated_field" + "bar" ], "deprecated": true } \ No newline at end of file diff --git a/schemars/tests/expected/doc_comments_enum.json b/schemars/tests/integration/snapshots/schemars/tests/integration/docs.rs~doc_comments_enum.de.json similarity index 100% rename from schemars/tests/expected/doc_comments_enum.json rename to schemars/tests/integration/snapshots/schemars/tests/integration/docs.rs~doc_comments_enum.de.json 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 new file mode 100644 index 0000000..3c6e680 --- /dev/null +++ b/schemars/tests/integration/snapshots/schemars/tests/integration/docs.rs~doc_comments_enum.ser.json @@ -0,0 +1,46 @@ +{ + "$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/expected/doc_comments_override.json b/schemars/tests/integration/snapshots/schemars/tests/integration/docs.rs~doc_comments_override.json similarity index 100% rename from schemars/tests/expected/doc_comments_override.json rename to schemars/tests/integration/snapshots/schemars/tests/integration/docs.rs~doc_comments_override.json diff --git a/schemars/tests/expected/doc_comments_struct.json b/schemars/tests/integration/snapshots/schemars/tests/integration/docs.rs~doc_comments_struct.json similarity index 100% rename from schemars/tests/expected/doc_comments_struct.json rename to schemars/tests/integration/snapshots/schemars/tests/integration/docs.rs~doc_comments_struct.json 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 new file mode 100644 index 0000000..b97cf1f --- /dev/null +++ b/schemars/tests/integration/snapshots/schemars/tests/integration/either.rs~either.json @@ -0,0 +1,56 @@ +{ + "$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/expected/enum-repr-with-attrs.json b/schemars/tests/integration/snapshots/schemars/tests/integration/enum_repr.rs~enum_repr.json similarity index 85% rename from schemars/tests/expected/enum-repr-with-attrs.json rename to schemars/tests/integration/snapshots/schemars/tests/integration/enum_repr.rs~enum_repr.json index 89d941b..964952a 100644 --- a/schemars/tests/expected/enum-repr-with-attrs.json +++ b/schemars/tests/integration/snapshots/schemars/tests/integration/enum_repr.rs~enum_repr.json @@ -1,6 +1,6 @@ { "$schema": "https://json-schema.org/draft/2020-12/schema", - "title": "Renamed", + "title": "EnumWithReprAttr", "description": "Description from comment", "type": "integer", "enum": [ diff --git a/schemars/tests/expected/enum-adjacent-tagged.json b/schemars/tests/integration/snapshots/schemars/tests/integration/enums.rs~adjacently_tagged_enum.json similarity index 74% rename from schemars/tests/expected/enum-adjacent-tagged.json rename to schemars/tests/integration/snapshots/schemars/tests/integration/enums.rs~adjacently_tagged_enum.json index 7599fd1..e75faf2 100644 --- a/schemars/tests/expected/enum-adjacent-tagged.json +++ b/schemars/tests/integration/snapshots/schemars/tests/integration/enums.rs~adjacently_tagged_enum.json @@ -5,23 +5,23 @@ { "type": "object", "properties": { - "t": { + "tag": { "type": "string", "const": "UnitOne" } }, "required": [ - "t" + "tag" ] }, { "type": "object", "properties": { - "t": { + "tag": { "type": "string", "const": "StringMap" }, - "c": { + "content": { "type": "object", "additionalProperties": { "type": "string" @@ -29,50 +29,50 @@ } }, "required": [ - "t", - "c" + "tag", + "content" ] }, { "type": "object", "properties": { - "t": { + "tag": { "type": "string", "const": "UnitStructNewType" }, - "c": { + "content": { "$ref": "#/$defs/UnitStruct" } }, "required": [ - "t", - "c" + "tag", + "content" ] }, { "type": "object", "properties": { - "t": { + "tag": { "type": "string", "const": "StructNewType" }, - "c": { + "content": { "$ref": "#/$defs/Struct" } }, "required": [ - "t", - "c" + "tag", + "content" ] }, { "type": "object", "properties": { - "t": { + "tag": { "type": "string", "const": "Struct" }, - "c": { + "content": { "type": "object", "properties": { "foo": { @@ -90,18 +90,18 @@ } }, "required": [ - "t", - "c" + "tag", + "content" ] }, { "type": "object", "properties": { - "t": { + "tag": { "type": "string", "const": "Tuple" }, - "c": { + "content": { "type": "array", "prefixItems": [ { @@ -117,37 +117,55 @@ } }, "required": [ - "t", - "c" + "tag", + "content" ] }, { "type": "object", "properties": { - "t": { + "tag": { "type": "string", "const": "UnitTwo" } }, "required": [ - "t" + "tag" ] }, { "type": "object", "properties": { - "t": { + "tag": { "type": "string", - "const": "WithInt" + "const": "UnitAsInt" }, - "c": { + "content": { "type": "integer", - "format": "int32" + "format": "uint64", + "minimum": 0 } }, "required": [ - "t", - "c" + "tag", + "content" + ] + }, + { + "type": "object", + "properties": { + "tag": { + "type": "string", + "const": "TupleAsStr" + }, + "content": { + "type": "string", + "pattern": "^\\d+ (true|false)$" + } + }, + "required": [ + "tag", + "content" ] } ], diff --git a/schemars/tests/expected/enum-external.json b/schemars/tests/integration/snapshots/schemars/tests/integration/enums.rs~externally_tagged_enum.json similarity index 87% rename from schemars/tests/expected/enum-external.json rename to schemars/tests/integration/snapshots/schemars/tests/integration/enums.rs~externally_tagged_enum.json index 3c660fb..c5e19aa 100644 --- a/schemars/tests/expected/enum-external.json +++ b/schemars/tests/integration/snapshots/schemars/tests/integration/enums.rs~externally_tagged_enum.json @@ -99,13 +99,27 @@ { "type": "object", "properties": { - "withInt": { + "unitAsInt": { "type": "integer", - "format": "int32" + "format": "uint64", + "minimum": 0 } }, "required": [ - "withInt" + "unitAsInt" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "tupleAsStr": { + "type": "string", + "pattern": "^\\d+ (true|false)$" + } + }, + "required": [ + "tupleAsStr" ], "additionalProperties": false } diff --git a/schemars/tests/expected/enum-internal.json b/schemars/tests/integration/snapshots/schemars/tests/integration/enums.rs~internally_tagged_enum.json similarity index 73% rename from schemars/tests/expected/enum-internal.json rename to schemars/tests/integration/snapshots/schemars/tests/integration/enums.rs~internally_tagged_enum.json index 2fd9770..e91dcb6 100644 --- a/schemars/tests/expected/enum-internal.json +++ b/schemars/tests/integration/snapshots/schemars/tests/integration/enums.rs~internally_tagged_enum.json @@ -5,19 +5,19 @@ { "type": "object", "properties": { - "typeProperty": { + "tag": { "type": "string", "const": "UnitOne" } }, "required": [ - "typeProperty" + "tag" ] }, { "type": "object", "properties": { - "typeProperty": { + "tag": { "type": "string", "const": "StringMap" } @@ -26,19 +26,19 @@ "type": "string" }, "required": [ - "typeProperty" + "tag" ] }, { "type": "object", "properties": { - "typeProperty": { + "tag": { "type": "string", "const": "UnitStructNewType" } }, "required": [ - "typeProperty" + "tag" ] }, { @@ -51,13 +51,13 @@ "bar": { "type": "boolean" }, - "typeProperty": { + "tag": { "type": "string", "const": "StructNewType" } }, "required": [ - "typeProperty", + "tag", "foo", "bar" ] @@ -72,13 +72,13 @@ "bar": { "type": "boolean" }, - "typeProperty": { + "tag": { "type": "string", "const": "Struct" } }, "required": [ - "typeProperty", + "tag", "foo", "bar" ] @@ -86,26 +86,13 @@ { "type": "object", "properties": { - "typeProperty": { + "tag": { "type": "string", "const": "UnitTwo" } }, "required": [ - "typeProperty" - ] - }, - { - "type": "object", - "format": "int32", - "properties": { - "typeProperty": { - "type": "string", - "const": "WithInt" - } - }, - "required": [ - "typeProperty" + "tag" ] } ] diff --git a/schemars/tests/expected/no-variants.json b/schemars/tests/integration/snapshots/schemars/tests/integration/enums.rs~no_variants.json similarity index 100% rename from schemars/tests/expected/no-variants.json rename to schemars/tests/integration/snapshots/schemars/tests/integration/enums.rs~no_variants.json 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 new file mode 100644 index 0000000..f2f5277 --- /dev/null +++ b/schemars/tests/integration/snapshots/schemars/tests/integration/enums.rs~renamed.json @@ -0,0 +1,46 @@ +{ + "$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/expected/enum-unit-doc.json b/schemars/tests/integration/snapshots/schemars/tests/integration/enums.rs~unit_variants_with_doc_comments.json similarity index 100% rename from schemars/tests/expected/enum-unit-doc.json rename to schemars/tests/integration/snapshots/schemars/tests/integration/enums.rs~unit_variants_with_doc_comments.json diff --git a/schemars/tests/expected/enum-untagged.json b/schemars/tests/integration/snapshots/schemars/tests/integration/enums.rs~untagged_enum.json similarity index 88% rename from schemars/tests/expected/enum-untagged.json rename to schemars/tests/integration/snapshots/schemars/tests/integration/enums.rs~untagged_enum.json index 643cd20..e744d55 100644 --- a/schemars/tests/expected/enum-untagged.json +++ b/schemars/tests/integration/snapshots/schemars/tests/integration/enums.rs~untagged_enum.json @@ -47,9 +47,17 @@ "minItems": 2, "maxItems": 2 }, + { + "type": "null" + }, { "type": "integer", - "format": "int32" + "format": "uint64", + "minimum": 0 + }, + { + "type": "string", + "pattern": "^\\d+ (true|false)$" } ], "$defs": { diff --git a/schemars/tests/expected/enum-external-duf.json b/schemars/tests/integration/snapshots/schemars/tests/integration/enums_deny_unknown_fields.rs~adjacently_tagged_enum.json similarity index 56% rename from schemars/tests/expected/enum-external-duf.json rename to schemars/tests/integration/snapshots/schemars/tests/integration/enums_deny_unknown_fields.rs~adjacently_tagged_enum.json index 76be5b3..20f2aed 100644 --- a/schemars/tests/expected/enum-external-duf.json +++ b/schemars/tests/integration/snapshots/schemars/tests/integration/enums_deny_unknown_fields.rs~adjacently_tagged_enum.json @@ -1,18 +1,28 @@ { "$schema": "https://json-schema.org/draft/2020-12/schema", - "title": "External", + "title": "Adjacent", "oneOf": [ { - "type": "string", - "enum": [ - "unitOne", - "unitTwo" - ] + "type": "object", + "properties": { + "tag": { + "type": "string", + "const": "Unit" + } + }, + "required": [ + "tag" + ], + "additionalProperties": false }, { "type": "object", "properties": { - "stringMap": { + "tag": { + "type": "string", + "const": "StringMap" + }, + "content": { "type": "object", "additionalProperties": { "type": "string" @@ -20,38 +30,36 @@ } }, "required": [ - "stringMap" + "tag", + "content" ], "additionalProperties": false }, { "type": "object", "properties": { - "unitStructNewType": { - "$ref": "#/$defs/UnitStruct" - } - }, - "required": [ - "unitStructNewType" - ], - "additionalProperties": false - }, - { - "type": "object", - "properties": { - "structNewType": { + "tag": { + "type": "string", + "const": "StructNewType" + }, + "content": { "$ref": "#/$defs/Struct" } }, "required": [ - "structNewType" + "tag", + "content" ], "additionalProperties": false }, { "type": "object", "properties": { - "struct": { + "tag": { + "type": "string", + "const": "Struct" + }, + "content": { "type": "object", "properties": { "foo": { @@ -70,51 +78,13 @@ } }, "required": [ - "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" + "tag", + "content" ], "additionalProperties": false } ], "$defs": { - "UnitStruct": { - "type": "null" - }, "Struct": { "type": "object", "properties": { diff --git a/schemars/tests/expected/schema_with-enum-external.json b/schemars/tests/integration/snapshots/schemars/tests/integration/enums_deny_unknown_fields.rs~externally_tagged_enum.json similarity index 59% rename from schemars/tests/expected/schema_with-enum-external.json rename to schemars/tests/integration/snapshots/schemars/tests/integration/enums_deny_unknown_fields.rs~externally_tagged_enum.json index 5f5fe83..819e0e4 100644 --- a/schemars/tests/expected/schema_with-enum-external.json +++ b/schemars/tests/integration/snapshots/schemars/tests/integration/enums_deny_unknown_fields.rs~externally_tagged_enum.json @@ -2,72 +2,82 @@ "$schema": "https://json-schema.org/draft/2020-12/schema", "title": "External", "oneOf": [ + { + "type": "string", + "enum": [ + "Unit" + ] + }, { "type": "object", "properties": { - "struct": { + "StringMap": { + "type": "object", + "additionalProperties": { + "type": "string" + } + } + }, + "required": [ + "StringMap" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "StructNewType": { + "$ref": "#/$defs/Struct" + } + }, + "required": [ + "StructNewType" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "Struct": { "type": "object", "properties": { "foo": { + "type": "integer", + "format": "int32" + }, + "bar": { "type": "boolean" } }, + "additionalProperties": false, "required": [ - "foo" + "foo", + "bar" ] } }, "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" + "Struct" ], "additionalProperties": false } - ] + ], + "$defs": { + "Struct": { + "type": "object", + "properties": { + "foo": { + "type": "integer", + "format": "int32" + }, + "bar": { + "type": "boolean" + } + }, + "required": [ + "foo", + "bar" + ] + } + } } \ No newline at end of file diff --git a/schemars/tests/expected/enum-internal-duf.json b/schemars/tests/integration/snapshots/schemars/tests/integration/enums_deny_unknown_fields.rs~internally_tagged_enum.json similarity index 55% rename from schemars/tests/expected/enum-internal-duf.json rename to schemars/tests/integration/snapshots/schemars/tests/integration/enums_deny_unknown_fields.rs~internally_tagged_enum.json index 73e4743..2e5b8c8 100644 --- a/schemars/tests/expected/enum-internal-duf.json +++ b/schemars/tests/integration/snapshots/schemars/tests/integration/enums_deny_unknown_fields.rs~internally_tagged_enum.json @@ -5,20 +5,20 @@ { "type": "object", "properties": { - "typeProperty": { + "tag": { "type": "string", - "const": "UnitOne" + "const": "Unit" } }, "required": [ - "typeProperty" + "tag" ], "additionalProperties": false }, { "type": "object", "properties": { - "typeProperty": { + "tag": { "type": "string", "const": "StringMap" } @@ -27,22 +27,9 @@ "type": "string" }, "required": [ - "typeProperty" + "tag" ] }, - { - "type": "object", - "properties": { - "typeProperty": { - "type": "string", - "const": "UnitStructNewType" - } - }, - "required": [ - "typeProperty" - ], - "additionalProperties": false - }, { "type": "object", "properties": { @@ -53,13 +40,13 @@ "bar": { "type": "boolean" }, - "typeProperty": { + "tag": { "type": "string", "const": "StructNewType" } }, "required": [ - "typeProperty", + "tag", "foo", "bar" ] @@ -74,43 +61,17 @@ "bar": { "type": "boolean" }, - "typeProperty": { + "tag": { "type": "string", "const": "Struct" } }, "additionalProperties": false, "required": [ - "typeProperty", + "tag", "foo", "bar" ] - }, - { - "type": "object", - "properties": { - "typeProperty": { - "type": "string", - "const": "UnitTwo" - } - }, - "required": [ - "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/expected/enum-untagged-duf.json b/schemars/tests/integration/snapshots/schemars/tests/integration/enums_deny_unknown_fields.rs~untagged_enum.json similarity index 69% rename from schemars/tests/expected/enum-untagged-duf.json rename to schemars/tests/integration/snapshots/schemars/tests/integration/enums_deny_unknown_fields.rs~untagged_enum.json index 58bdbe1..9b58136 100644 --- a/schemars/tests/expected/enum-untagged-duf.json +++ b/schemars/tests/integration/snapshots/schemars/tests/integration/enums_deny_unknown_fields.rs~untagged_enum.json @@ -11,9 +11,6 @@ "type": "string" } }, - { - "$ref": "#/$defs/UnitStruct" - }, { "$ref": "#/$defs/Struct" }, @@ -33,30 +30,9 @@ "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": { diff --git a/schemars/tests/expected/enum_flatten.json b/schemars/tests/integration/snapshots/schemars/tests/integration/enums_flattened.rs~enums_flattened.json similarity index 99% rename from schemars/tests/expected/enum_flatten.json rename to schemars/tests/integration/snapshots/schemars/tests/integration/enums_flattened.rs~enums_flattened.json index dffd89e..7df8b88 100644 --- a/schemars/tests/expected/enum_flatten.json +++ b/schemars/tests/integration/snapshots/schemars/tests/integration/enums_flattened.rs~enums_flattened.json @@ -1,6 +1,6 @@ { "$schema": "https://json-schema.org/draft/2020-12/schema", - "title": "Flat", + "title": "Container", "type": "object", "properties": { "f": { diff --git a/schemars/tests/expected/enum_flatten_duf.json b/schemars/tests/integration/snapshots/schemars/tests/integration/enums_flattened.rs~enums_flattened_deny_unknown_fields.json similarity index 98% rename from schemars/tests/expected/enum_flatten_duf.json rename to schemars/tests/integration/snapshots/schemars/tests/integration/enums_flattened.rs~enums_flattened_deny_unknown_fields.json index 37493cc..2032360 100644 --- a/schemars/tests/expected/enum_flatten_duf.json +++ b/schemars/tests/integration/snapshots/schemars/tests/integration/enums_flattened.rs~enums_flattened_deny_unknown_fields.json @@ -1,6 +1,6 @@ { "$schema": "https://json-schema.org/draft/2020-12/schema", - "title": "FlatDenyUnknownFields", + "title": "ContainerDenyUnknownFields", "type": "object", "properties": { "f": { diff --git a/schemars/tests/expected/enum_flatten_duf_draft07.json b/schemars/tests/integration/snapshots/schemars/tests/integration/enums_flattened.rs~enums_flattened_deny_unknown_fields_draft07.json similarity index 98% rename from schemars/tests/expected/enum_flatten_duf_draft07.json rename to schemars/tests/integration/snapshots/schemars/tests/integration/enums_flattened.rs~enums_flattened_deny_unknown_fields_draft07.json index 62323dd..695f282 100644 --- a/schemars/tests/expected/enum_flatten_duf_draft07.json +++ b/schemars/tests/integration/snapshots/schemars/tests/integration/enums_flattened.rs~enums_flattened_deny_unknown_fields_draft07.json @@ -1,6 +1,6 @@ { "$schema": "http://json-schema.org/draft-07/schema#", - "title": "FlatDenyUnknownFields", + "title": "ContainerDenyUnknownFields", "type": "object", "properties": { "f": { diff --git a/schemars/tests/expected/examples.json b/schemars/tests/integration/snapshots/schemars/tests/integration/examples.rs~examples.de.json similarity index 100% rename from schemars/tests/expected/examples.json rename to schemars/tests/integration/snapshots/schemars/tests/integration/examples.rs~examples.de.json diff --git a/schemars/tests/expected/struct-normal.json b/schemars/tests/integration/snapshots/schemars/tests/integration/examples.rs~examples.ser.json similarity index 57% rename from schemars/tests/expected/struct-normal.json rename to schemars/tests/integration/snapshots/schemars/tests/integration/examples.rs~examples.ser.json index c49757c..97465db 100644 --- a/schemars/tests/expected/struct-normal.json +++ b/schemars/tests/integration/snapshots/schemars/tests/integration/examples.rs~examples.ser.json @@ -5,7 +5,11 @@ "properties": { "foo": { "type": "integer", - "format": "int32" + "format": "int32", + "examples": [ + 8, + null + ] }, "bar": { "type": "boolean" @@ -14,11 +18,23 @@ "type": [ "string", "null" + ], + "examples": [ + null ] } }, "required": [ "foo", - "bar" + "bar", + "baz" + ], + "examples": [ + { + "foo": 0, + "bar": false, + "baz": null + }, + null ] } \ No newline at end of file diff --git a/schemars/tests/expected/extend_enum_adjacent.json b/schemars/tests/integration/snapshots/schemars/tests/integration/extend.rs~extend_adjacently_tagged_enum.json similarity index 98% rename from schemars/tests/expected/extend_enum_adjacent.json rename to schemars/tests/integration/snapshots/schemars/tests/integration/extend.rs~extend_adjacently_tagged_enum.json index 4167faf..543ff4f 100644 --- a/schemars/tests/expected/extend_enum_adjacent.json +++ b/schemars/tests/integration/snapshots/schemars/tests/integration/extend.rs~extend_adjacently_tagged_enum.json @@ -1,6 +1,6 @@ { "$schema": "https://json-schema.org/draft/2020-12/schema", - "title": "Adjacent", + "title": "AdjacentEnum", "oneOf": [ { "type": "object", diff --git a/schemars/tests/expected/extend_enum_external.json b/schemars/tests/integration/snapshots/schemars/tests/integration/extend.rs~extend_externally_tagged_enum.json similarity index 98% rename from schemars/tests/expected/extend_enum_external.json rename to schemars/tests/integration/snapshots/schemars/tests/integration/extend.rs~extend_externally_tagged_enum.json index c15d47f..9c6f37a 100644 --- a/schemars/tests/expected/extend_enum_external.json +++ b/schemars/tests/integration/snapshots/schemars/tests/integration/extend.rs~extend_externally_tagged_enum.json @@ -1,6 +1,6 @@ { "$schema": "https://json-schema.org/draft/2020-12/schema", - "title": "External", + "title": "ExternalEnum", "oneOf": [ { "type": "string", diff --git a/schemars/tests/expected/extend_enum_internal.json b/schemars/tests/integration/snapshots/schemars/tests/integration/extend.rs~extend_internally_tagged_enum.json similarity index 82% rename from schemars/tests/expected/extend_enum_internal.json rename to schemars/tests/integration/snapshots/schemars/tests/integration/extend.rs~extend_internally_tagged_enum.json index 0dee817..c0f6354 100644 --- a/schemars/tests/expected/extend_enum_internal.json +++ b/schemars/tests/integration/snapshots/schemars/tests/integration/extend.rs~extend_internally_tagged_enum.json @@ -1,30 +1,30 @@ { "$schema": "https://json-schema.org/draft/2020-12/schema", - "title": "Internal", + "title": "InternalEnum", "oneOf": [ { "type": "object", "properties": { - "typeProperty": { + "t": { "type": "string", "const": "Unit" } }, "required": [ - "typeProperty" + "t" ], "foo": "bar" }, { "type": "object", "properties": { - "typeProperty": { + "t": { "type": "string", "const": "NewType" } }, "required": [ - "typeProperty" + "t" ], "foo": "bar" }, @@ -38,13 +38,13 @@ "b": { "type": "boolean" }, - "typeProperty": { + "t": { "type": "string", "const": "Struct" } }, "required": [ - "typeProperty", + "t", "i", "b" ], diff --git a/schemars/tests/expected/extend_struct.json b/schemars/tests/integration/snapshots/schemars/tests/integration/extend.rs~extend_struct.json similarity index 85% rename from schemars/tests/expected/extend_struct.json rename to schemars/tests/integration/snapshots/schemars/tests/integration/extend.rs~extend_struct.json index fc7dd50..8586867 100644 --- a/schemars/tests/expected/extend_struct.json +++ b/schemars/tests/integration/snapshots/schemars/tests/integration/extend.rs~extend_struct.json @@ -7,7 +7,10 @@ "foo": "bar" }, "int": { - "type": "overridden", + "type": [ + "number", + "string" + ], "format": "int32" } }, @@ -15,7 +18,6 @@ "value", "int" ], - "msg": "hello world", "obj": { "array": [ null, 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 new file mode 100644 index 0000000..b62e241 --- /dev/null +++ b/schemars/tests/integration/snapshots/schemars/tests/integration/extend.rs~extend_tuple_struct.json @@ -0,0 +1,28 @@ +{ + "$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/expected/extend_enum_untagged.json b/schemars/tests/integration/snapshots/schemars/tests/integration/extend.rs~extend_untagged_enum.json similarity index 96% rename from schemars/tests/expected/extend_enum_untagged.json rename to schemars/tests/integration/snapshots/schemars/tests/integration/extend.rs~extend_untagged_enum.json index 4f733fe..8a0df44 100644 --- a/schemars/tests/expected/extend_enum_untagged.json +++ b/schemars/tests/integration/snapshots/schemars/tests/integration/extend.rs~extend_untagged_enum.json @@ -1,6 +1,6 @@ { "$schema": "https://json-schema.org/draft/2020-12/schema", - "title": "Untagged", + "title": "UntaggedEnum", "anyOf": [ { "type": "null", diff --git a/schemars/tests/expected/flatten.json b/schemars/tests/integration/snapshots/schemars/tests/integration/flatten.rs~flattened_struct.json similarity index 85% rename from schemars/tests/expected/flatten.json rename to schemars/tests/integration/snapshots/schemars/tests/integration/flatten.rs~flattened_struct.json index 7dfd54e..689d245 100644 --- a/schemars/tests/expected/flatten.json +++ b/schemars/tests/integration/snapshots/schemars/tests/integration/flatten.rs~flattened_struct.json @@ -13,10 +13,6 @@ "s": { "type": "string" }, - "os": { - "type": "string", - "default": "" - }, "v": { "type": "array", "items": { @@ -28,7 +24,6 @@ "required": [ "f", "b", - "s", "v" ] } \ No newline at end of file diff --git a/schemars/tests/expected/flattened_value.json b/schemars/tests/integration/snapshots/schemars/tests/integration/flatten.rs~flattened_value.json similarity index 100% rename from schemars/tests/expected/flattened_value.json rename to schemars/tests/integration/snapshots/schemars/tests/integration/flatten.rs~flattened_value.json diff --git a/schemars/tests/expected/from_value_draft07.json b/schemars/tests/integration/snapshots/schemars/tests/integration/from_value.rs~custom_struct.json similarity index 85% rename from schemars/tests/expected/from_value_draft07.json rename to schemars/tests/integration/snapshots/schemars/tests/integration/from_value.rs~custom_struct.json index 721e871..96d2358 100644 --- a/schemars/tests/expected/from_value_draft07.json +++ b/schemars/tests/integration/snapshots/schemars/tests/integration/from_value.rs~custom_struct.json @@ -1,5 +1,5 @@ { - "$schema": "http://json-schema.org/draft-07/schema#", + "$schema": "https://json-schema.org/draft/2020-12/schema", "title": "MyStruct", "type": "object", "properties": { @@ -22,7 +22,7 @@ "my_vec": { "type": "array", "items": { - "type": "string" + "type": "number" } }, "my_empty_map": { @@ -35,9 +35,7 @@ }, "my_tuple": { "type": "array", - "minItems": 2, - "maxItems": 2, - "items": [ + "prefixItems": [ { "type": "string", "minLength": 1, @@ -46,7 +44,9 @@ { "type": "integer" } - ] + ], + "maxItems": 2, + "minItems": 2 } } } @@ -58,11 +58,12 @@ "myNullableEnum": null, "myInnerStruct": { "my_map": { - "": 0.0 + "k": 1.23 }, "my_vec": [ - "hello", - "world" + 1.0, + 2.0, + 3.0 ], "my_empty_map": {}, "my_empty_vec": [], diff --git a/schemars/tests/expected/from_value_openapi3.json b/schemars/tests/integration/snapshots/schemars/tests/integration/from_value.rs~custom_struct_openapi3.json similarity index 94% rename from schemars/tests/expected/from_value_openapi3.json rename to schemars/tests/integration/snapshots/schemars/tests/integration/from_value.rs~custom_struct_openapi3.json index 88f08a7..7e52acd 100644 --- a/schemars/tests/expected/from_value_openapi3.json +++ b/schemars/tests/integration/snapshots/schemars/tests/integration/from_value.rs~custom_struct_openapi3.json @@ -24,7 +24,7 @@ "my_vec": { "type": "array", "items": { - "type": "string" + "type": "number" } }, "my_empty_map": { @@ -59,11 +59,12 @@ "myNullableEnum": null, "myInnerStruct": { "my_map": { - "": 0.0 + "k": 1.23 }, "my_vec": [ - "hello", - "world" + 1.0, + 2.0, + 3.0 ], "my_empty_map": {}, "my_empty_vec": [], diff --git a/schemars/tests/expected/from_json_value.json b/schemars/tests/integration/snapshots/schemars/tests/integration/from_value.rs~json_value.json similarity index 77% rename from schemars/tests/expected/from_json_value.json rename to schemars/tests/integration/snapshots/schemars/tests/integration/from_value.rs~json_value.json index b217fad..0818d4d 100644 --- a/schemars/tests/expected/from_json_value.json +++ b/schemars/tests/integration/snapshots/schemars/tests/integration/from_value.rs~json_value.json @@ -5,12 +5,6 @@ "zero": { "type": "integer" }, - "one": { - "type": "integer" - }, - "minusOne": { - "type": "integer" - }, "zeroPointZero": { "type": "number" }, @@ -21,11 +15,15 @@ "object": { "type": "object", "properties": { - "array": { + "strings": { "type": "array", "items": { "type": "string" } + }, + "mixed": { + "type": "array", + "items": true } } } @@ -33,15 +31,17 @@ "examples": [ { "zero": 0, - "one": 1, - "minusOne": -1, "zeroPointZero": 0.0, "bool": true, "null": null, "object": { - "array": [ + "strings": [ "foo", "bar" + ], + "mixed": [ + 1, + true ] } } diff --git a/schemars/tests/expected/garde_schemars_attrs.json b/schemars/tests/integration/snapshots/schemars/tests/integration/garde.rs~garde_attrs.json similarity index 69% rename from schemars/tests/expected/garde_schemars_attrs.json rename to schemars/tests/integration/snapshots/schemars/tests/integration/garde.rs~garde_attrs.json index f548706..a95287b 100644 --- a/schemars/tests/expected/garde_schemars_attrs.json +++ b/schemars/tests/integration/snapshots/schemars/tests/integration/garde.rs~garde_attrs.json @@ -1,25 +1,25 @@ { "$schema": "https://json-schema.org/draft/2020-12/schema", - "title": "Struct2", + "title": "GardeAttrStruct", "type": "object", "properties": { "min_max": { "type": "number", "format": "float", - "minimum": 0.01, - "maximum": 100 + "minimum": 1.0, + "maximum": 100.0 }, "min_max2": { "type": "number", "format": "float", - "minimum": 1, - "maximum": 1000 + "minimum": 1.0, + "maximum": 10.0 }, - "regex_str1": { + "regex_str": { "type": "string", - "pattern": "^[Hh]ello\\b" + "pattern": "^[Hh]ello" }, - "contains_str1": { + "contains_str": { "type": "string", "pattern": "substring\\.\\.\\." }, @@ -34,18 +34,13 @@ "non_empty_str": { "type": "string", "minLength": 1, - "maxLength": 100 - }, - "non_empty_str2": { - "type": "string", - "minLength": 1, - "maxLength": 1000 + "maxLength": 10 }, "pair": { "type": "array", "items": { - "type": "integer", - "format": "int32" + "type": "string", + "minLength": 1 }, "minItems": 2, "maxItems": 2 @@ -55,18 +50,19 @@ }, "x": { "type": "integer", - "format": "int32" + "format": "int32", + "minimum": -100, + "maximum": 100 } }, "required": [ "min_max", "min_max2", - "regex_str1", - "contains_str1", + "regex_str", + "contains_str", "email_address", "homepage", "non_empty_str", - "non_empty_str2", "pair", "required_option", "x" diff --git a/schemars/tests/expected/garde_newtype.json b/schemars/tests/integration/snapshots/schemars/tests/integration/garde.rs~garde_attrs_newtype.json similarity index 81% rename from schemars/tests/expected/garde_newtype.json rename to schemars/tests/integration/snapshots/schemars/tests/integration/garde.rs~garde_attrs_newtype.json index cd835f5..fbefa51 100644 --- a/schemars/tests/expected/garde_newtype.json +++ b/schemars/tests/integration/snapshots/schemars/tests/integration/garde.rs~garde_attrs_newtype.json @@ -1,6 +1,6 @@ { "$schema": "https://json-schema.org/draft/2020-12/schema", - "title": "NewType", + "title": "GardeAttrNewType", "type": "integer", "format": "uint8", "minimum": 0, diff --git a/schemars/tests/expected/garde_tuple.json b/schemars/tests/integration/snapshots/schemars/tests/integration/garde.rs~garde_attrs_tuple.json similarity index 90% rename from schemars/tests/expected/garde_tuple.json rename to schemars/tests/integration/snapshots/schemars/tests/integration/garde.rs~garde_attrs_tuple.json index fa81224..2341eeb 100644 --- a/schemars/tests/expected/garde_tuple.json +++ b/schemars/tests/integration/snapshots/schemars/tests/integration/garde.rs~garde_attrs_tuple.json @@ -1,6 +1,6 @@ { "$schema": "https://json-schema.org/draft/2020-12/schema", - "title": "Tuple", + "title": "GardeAttrTuple", "type": "array", "prefixItems": [ { diff --git a/schemars/tests/expected/inline-subschemas.json b/schemars/tests/integration/snapshots/schemars/tests/integration/inline_subschemas.rs~struct_normal.json similarity index 100% rename from schemars/tests/expected/inline-subschemas.json rename to schemars/tests/integration/snapshots/schemars/tests/integration/inline_subschemas.rs~struct_normal.json diff --git a/schemars/tests/expected/inline-subschemas-recursive.json b/schemars/tests/integration/snapshots/schemars/tests/integration/inline_subschemas.rs~struct_recursive.de.json similarity index 100% rename from schemars/tests/expected/inline-subschemas-recursive.json rename to schemars/tests/integration/snapshots/schemars/tests/integration/inline_subschemas.rs~struct_recursive.de.json 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 new file mode 100644 index 0000000..584ee36 --- /dev/null +++ b/schemars/tests/integration/snapshots/schemars/tests/integration/inline_subschemas.rs~struct_recursive.ser.json @@ -0,0 +1,70 @@ +{ + "$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 new file mode 100644 index 0000000..ff0112a --- /dev/null +++ b/schemars/tests/integration/snapshots/schemars/tests/integration/remote_derive.rs~lifetime_param.json @@ -0,0 +1,18 @@ +{ + "$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/expected/remote_derive.json b/schemars/tests/integration/snapshots/schemars/tests/integration/remote_derive.rs~simple.json similarity index 64% rename from schemars/tests/expected/remote_derive.json rename to schemars/tests/integration/snapshots/schemars/tests/integration/remote_derive.rs~simple.json index 760630d..78db086 100644 --- a/schemars/tests/expected/remote_derive.json +++ b/schemars/tests/integration/snapshots/schemars/tests/integration/remote_derive.rs~simple.json @@ -3,26 +3,11 @@ "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/expected/remote_derive_generic.json b/schemars/tests/integration/snapshots/schemars/tests/integration/remote_derive.rs~type_param.json similarity index 50% rename from schemars/tests/expected/remote_derive_generic.json rename to schemars/tests/integration/snapshots/schemars/tests/integration/remote_derive.rs~type_param.json index bef4d6a..48568fd 100644 --- a/schemars/tests/expected/remote_derive_generic.json +++ b/schemars/tests/integration/snapshots/schemars/tests/integration/remote_derive.rs~type_param.json @@ -1,33 +1,18 @@ { "$schema": "https://json-schema.org/draft/2020-12/schema", - "title": "MyStruct_for_int32", + "title": "TypeParam_for_string", "type": "object", "properties": { - "byte_or_bool2": { + "byte_or_bool": { "$ref": "#/$defs/Or_for_uint8_and_boolean" }, - "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" - } - } + "unit_or_t": { + "$ref": "#/$defs/Or_for_null_and_string" } }, "required": [ - "byte_or_bool2", - "unit_or_t2", - "s", - "fake_map" + "byte_or_bool", + "unit_or_t" ], "$defs": { "Or_for_uint8_and_boolean": { @@ -42,19 +27,15 @@ } ] }, - "Or_for_null_and_int32": { + "Or_for_null_and_string": { "anyOf": [ { "type": "null" }, { - "type": "integer", - "format": "int32" + "type": "string" } ] - }, - "Str": { - "type": "string" } } } \ No newline at end of file diff --git a/schemars/tests/expected/same_name.json b/schemars/tests/integration/snapshots/schemars/tests/integration/same_name.rs~same_name.json similarity index 71% rename from schemars/tests/expected/same_name.json rename to schemars/tests/integration/snapshots/schemars/tests/integration/same_name.rs~same_name.json index fb65854..00573f6 100644 --- a/schemars/tests/expected/same_name.json +++ b/schemars/tests/integration/snapshots/schemars/tests/integration/same_name.rs~same_name.json @@ -8,11 +8,15 @@ }, "b_cfg": { "$ref": "#/$defs/Config2" + }, + "c_cfg": { + "$ref": "#/$defs/Config3" } }, "required": [ "a_cfg", - "b_cfg" + "b_cfg", + "c_cfg" ], "$defs": { "Config": { @@ -36,6 +40,17 @@ "required": [ "test2" ] + }, + "Config3": { + "type": "object", + "properties": { + "test3": { + "type": "string" + } + }, + "required": [ + "test3" + ] } } } \ No newline at end of file diff --git a/schemars/tests/expected/url.json b/schemars/tests/integration/snapshots/schemars/tests/integration/schema_with.rs~schema_with.json similarity index 69% rename from schemars/tests/expected/url.json rename to schemars/tests/integration/snapshots/schemars/tests/integration/schema_with.rs~schema_with.json index 425bf85..e3ea1f4 100644 --- a/schemars/tests/expected/url.json +++ b/schemars/tests/integration/snapshots/schemars/tests/integration/schema_with.rs~schema_with.json @@ -1,14 +1,14 @@ { "$schema": "https://json-schema.org/draft/2020-12/schema", - "title": "UrlTypes", + "title": "Struct", "type": "object", "properties": { - "url": { + "x": { "type": "string", - "format": "uri" + "pattern": "^-?\\d+$" } }, "required": [ - "url" + "x" ] } \ 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 new file mode 100644 index 0000000..59bad08 --- /dev/null +++ b/schemars/tests/integration/snapshots/schemars/tests/integration/semver.rs~semver.json @@ -0,0 +1,6 @@ +{ + "$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/expected/schema_settings.json b/schemars/tests/integration/snapshots/schemars/tests/integration/settings.rs~draft07.de.json similarity index 84% rename from schemars/tests/expected/schema_settings.json rename to schemars/tests/integration/snapshots/schemars/tests/integration/settings.rs~draft07.de.json index 4c435ad..a6b613e 100644 --- a/schemars/tests/expected/schema_settings.json +++ b/schemars/tests/integration/snapshots/schemars/tests/integration/settings.rs~draft07.de.json @@ -1,10 +1,13 @@ { "$schema": "http://json-schema.org/draft-07/schema#", - "title": "Outer", + "title": "OuterStruct", "type": "object", "properties": { - "int": { - "type": "integer", + "maybe_int": { + "type": [ + "integer", + "null" + ], "format": "int32", "examples": [ 8, @@ -17,9 +20,12 @@ }, "value": true, "inner": { + "$ref": "#/definitions/InnerEnum" + }, + "maybe_inner": { "anyOf": [ { - "$ref": "#/definitions/Inner" + "$ref": "#/definitions/InnerEnum" }, { "type": "null" @@ -47,13 +53,13 @@ } }, "required": [ - "int", "values", "value", + "inner", "tuples" ], "definitions": { - "Inner": { + "InnerEnum": { "oneOf": [ { "type": "string", 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 new file mode 100644 index 0000000..d76d990 --- /dev/null +++ b/schemars/tests/integration/snapshots/schemars/tests/integration/settings.rs~draft07.ser.json @@ -0,0 +1,91 @@ +{ + "$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/expected/schema_settings-2019_09.json b/schemars/tests/integration/snapshots/schemars/tests/integration/settings.rs~draft2019_09.de.json similarity index 85% rename from schemars/tests/expected/schema_settings-2019_09.json rename to schemars/tests/integration/snapshots/schemars/tests/integration/settings.rs~draft2019_09.de.json index bc99f15..f704755 100644 --- a/schemars/tests/expected/schema_settings-2019_09.json +++ b/schemars/tests/integration/snapshots/schemars/tests/integration/settings.rs~draft2019_09.de.json @@ -1,10 +1,13 @@ { "$schema": "https://json-schema.org/draft/2019-09/schema", - "title": "Outer", + "title": "OuterStruct", "type": "object", "properties": { - "int": { - "type": "integer", + "maybe_int": { + "type": [ + "integer", + "null" + ], "format": "int32", "examples": [ 8, @@ -17,9 +20,12 @@ }, "value": true, "inner": { + "$ref": "#/$defs/InnerEnum" + }, + "maybe_inner": { "anyOf": [ { - "$ref": "#/$defs/Inner" + "$ref": "#/$defs/InnerEnum" }, { "type": "null" @@ -47,13 +53,13 @@ } }, "required": [ - "int", "values", "value", + "inner", "tuples" ], "$defs": { - "Inner": { + "InnerEnum": { "oneOf": [ { "type": "string", 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 new file mode 100644 index 0000000..41c3237 --- /dev/null +++ b/schemars/tests/integration/snapshots/schemars/tests/integration/settings.rs~draft2019_09.ser.json @@ -0,0 +1,91 @@ +{ + "$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/expected/schema_settings-2020_12.json b/schemars/tests/integration/snapshots/schemars/tests/integration/settings.rs~draft2020_12.de.json similarity index 85% rename from schemars/tests/expected/schema_settings-2020_12.json rename to schemars/tests/integration/snapshots/schemars/tests/integration/settings.rs~draft2020_12.de.json index 7964058..1f51161 100644 --- a/schemars/tests/expected/schema_settings-2020_12.json +++ b/schemars/tests/integration/snapshots/schemars/tests/integration/settings.rs~draft2020_12.de.json @@ -1,10 +1,13 @@ { "$schema": "https://json-schema.org/draft/2020-12/schema", - "title": "Outer", + "title": "OuterStruct", "type": "object", "properties": { - "int": { - "type": "integer", + "maybe_int": { + "type": [ + "integer", + "null" + ], "format": "int32", "examples": [ 8, @@ -17,9 +20,12 @@ }, "value": true, "inner": { + "$ref": "#/$defs/InnerEnum" + }, + "maybe_inner": { "anyOf": [ { - "$ref": "#/$defs/Inner" + "$ref": "#/$defs/InnerEnum" }, { "type": "null" @@ -47,13 +53,13 @@ } }, "required": [ - "int", "values", "value", + "inner", "tuples" ], "$defs": { - "Inner": { + "InnerEnum": { "oneOf": [ { "type": "string", 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 new file mode 100644 index 0000000..a200584 --- /dev/null +++ b/schemars/tests/integration/snapshots/schemars/tests/integration/settings.rs~draft2020_12.ser.json @@ -0,0 +1,91 @@ +{ + "$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/expected/schema_settings-openapi3.json b/schemars/tests/integration/snapshots/schemars/tests/integration/settings.rs~openapi3.de.json similarity index 86% rename from schemars/tests/expected/schema_settings-openapi3.json rename to schemars/tests/integration/snapshots/schemars/tests/integration/settings.rs~openapi3.de.json index 8365822..a31b385 100644 --- a/schemars/tests/expected/schema_settings-openapi3.json +++ b/schemars/tests/integration/snapshots/schemars/tests/integration/settings.rs~openapi3.de.json @@ -1,11 +1,12 @@ { "$schema": "https://spec.openapis.org/oas/3.0/schema/2021-09-28#/definitions/Schema", - "title": "Outer", + "title": "OuterStruct", "type": "object", "properties": { - "int": { + "maybe_int": { "type": "integer", "format": "int32", + "nullable": true, "example": 8 }, "values": { @@ -14,10 +15,13 @@ }, "value": {}, "inner": { + "$ref": "#/components/schemas/InnerEnum" + }, + "maybe_inner": { "nullable": true, "allOf": [ { - "$ref": "#/components/schemas/Inner" + "$ref": "#/components/schemas/InnerEnum" } ] }, @@ -42,14 +46,14 @@ } }, "required": [ - "int", "values", "value", + "inner", "tuples" ], "components": { "schemas": { - "Inner": { + "InnerEnum": { "oneOf": [ { "type": "string", 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 new file mode 100644 index 0000000..217541a --- /dev/null +++ b/schemars/tests/integration/snapshots/schemars/tests/integration/settings.rs~openapi3.ser.json @@ -0,0 +1,88 @@ +{ + "$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/expected/enum-repr.json b/schemars/tests/integration/snapshots/schemars/tests/integration/skip.rs~skip_enum_variants.json similarity index 64% rename from schemars/tests/expected/enum-repr.json rename to schemars/tests/integration/snapshots/schemars/tests/integration/skip.rs~skip_enum_variants.json index b3e6bb9..a24653a 100644 --- a/schemars/tests/expected/enum-repr.json +++ b/schemars/tests/integration/snapshots/schemars/tests/integration/skip.rs~skip_enum_variants.json @@ -1,12 +1,9 @@ { "$schema": "https://json-schema.org/draft/2020-12/schema", "title": "Enum", - "type": "integer", + "type": "string", "enum": [ - 0, - 1, - 5, - 6, - 3 + "Included1", + "Included2" ] } \ No newline at end of file diff --git a/schemars/tests/expected/schema-name-const-generics.json b/schemars/tests/integration/snapshots/schemars/tests/integration/skip.rs~skip_struct_field.json similarity index 54% rename from schemars/tests/expected/schema-name-const-generics.json rename to schemars/tests/integration/snapshots/schemars/tests/integration/skip.rs~skip_struct_field.json index 3c2edcc..821c86c 100644 --- a/schemars/tests/expected/schema-name-const-generics.json +++ b/schemars/tests/integration/snapshots/schemars/tests/integration/skip.rs~skip_struct_field.json @@ -1,14 +1,14 @@ { "$schema": "https://json-schema.org/draft/2020-12/schema", - "title": "const-generics-z-42", + "title": "Struct", "type": "object", "properties": { - "foo": { - "type": "integer", - "format": "int32" + "included": { + "type": "boolean" } }, + "additionalProperties": false, "required": [ - "foo" + "included" ] } \ No newline at end of file diff --git a/schemars/tests/expected/crate_alias.json b/schemars/tests/integration/snapshots/schemars/tests/integration/structs.rs~deny_unknown_fields.json similarity index 65% rename from schemars/tests/expected/crate_alias.json rename to schemars/tests/integration/snapshots/schemars/tests/integration/structs.rs~deny_unknown_fields.json index c2f1430..8400c1e 100644 --- a/schemars/tests/expected/crate_alias.json +++ b/schemars/tests/integration/snapshots/schemars/tests/integration/structs.rs~deny_unknown_fields.json @@ -1,17 +1,16 @@ { "$schema": "https://json-schema.org/draft/2020-12/schema", - "title": "Struct", + "title": "DenyUnknownFields", "type": "object", "properties": { "foo": { - "description": "This is a document", - "type": "integer", - "format": "int32" + "type": "string" }, "bar": { "type": "boolean" } }, + "additionalProperties": false, "required": [ "foo", "bar" diff --git a/schemars/tests/expected/smol_str.json b/schemars/tests/integration/snapshots/schemars/tests/integration/structs.rs~newtype.json similarity index 79% rename from schemars/tests/expected/smol_str.json rename to schemars/tests/integration/snapshots/schemars/tests/integration/structs.rs~newtype.json index 0604332..3c5dfcb 100644 --- a/schemars/tests/expected/smol_str.json +++ b/schemars/tests/integration/snapshots/schemars/tests/integration/structs.rs~newtype.json @@ -1,5 +1,5 @@ { "$schema": "https://json-schema.org/draft/2020-12/schema", - "title": "string", + "title": "NewType", "type": "string" } \ No newline at end of file diff --git a/schemars/tests/expected/schema_with-struct.json b/schemars/tests/integration/snapshots/schemars/tests/integration/structs.rs~normal.json similarity index 59% rename from schemars/tests/expected/schema_with-struct.json rename to schemars/tests/integration/snapshots/schemars/tests/integration/structs.rs~normal.json index 0674f1e..961fc9a 100644 --- a/schemars/tests/expected/schema_with-struct.json +++ b/schemars/tests/integration/snapshots/schemars/tests/integration/structs.rs~normal.json @@ -1,22 +1,17 @@ { "$schema": "https://json-schema.org/draft/2020-12/schema", - "title": "Struct", + "title": "NormalStruct", "type": "object", "properties": { "foo": { - "type": "boolean" + "type": "string" }, "bar": { - "type": "integer", - "format": "int32" - }, - "baz": { "type": "boolean" } }, "required": [ "foo", - "bar", - "baz" + "bar" ] } \ No newline at end of file diff --git a/schemars/tests/expected/property-name-struct.json b/schemars/tests/integration/snapshots/schemars/tests/integration/structs.rs~renamed_fields.json similarity index 64% rename from schemars/tests/expected/property-name-struct.json rename to schemars/tests/integration/snapshots/schemars/tests/integration/structs.rs~renamed_fields.json index 82ea9ed..1c305d6 100644 --- a/schemars/tests/expected/property-name-struct.json +++ b/schemars/tests/integration/snapshots/schemars/tests/integration/structs.rs~renamed_fields.json @@ -1,24 +1,19 @@ { "$schema": "https://json-schema.org/draft/2020-12/schema", - "title": "MyStruct", + "title": "RenamedFields", "type": "object", "properties": { "camelCase": { "type": "integer", "format": "int32" }, - "new_name_1": { - "type": "integer", - "format": "int32" - }, - "new_name_2": { + "new_name": { "type": "integer", "format": "int32" } }, "required": [ "camelCase", - "new_name_1", - "new_name_2" + "new_name" ] } \ No newline at end of file diff --git a/schemars/tests/expected/skip_tuple_fields.json b/schemars/tests/integration/snapshots/schemars/tests/integration/structs.rs~tuple.json similarity index 67% rename from schemars/tests/expected/skip_tuple_fields.json rename to schemars/tests/integration/snapshots/schemars/tests/integration/structs.rs~tuple.json index e3038bc..f484d06 100644 --- a/schemars/tests/expected/skip_tuple_fields.json +++ b/schemars/tests/integration/snapshots/schemars/tests/integration/structs.rs~tuple.json @@ -4,12 +4,10 @@ "type": "array", "prefixItems": [ { - "type": "number", - "format": "float", - "writeOnly": true + "type": "string" }, { - "type": "null" + "type": "boolean" } ], "minItems": 2, diff --git a/schemars/tests/expected/struct-unit.json b/schemars/tests/integration/snapshots/schemars/tests/integration/structs.rs~unit.json similarity index 76% rename from schemars/tests/expected/struct-unit.json rename to schemars/tests/integration/snapshots/schemars/tests/integration/structs.rs~unit.json index 46f6fcf..9fef7a4 100644 --- a/schemars/tests/expected/struct-unit.json +++ b/schemars/tests/integration/snapshots/schemars/tests/integration/structs.rs~unit.json @@ -1,5 +1,5 @@ { "$schema": "https://json-schema.org/draft/2020-12/schema", - "title": "Unit", + "title": "UnitStruct", "type": "null" } \ No newline at end of file diff --git a/schemars/tests/expected/transform_enum_external.json b/schemars/tests/integration/snapshots/schemars/tests/integration/transform.rs~transform_enum.json similarity index 70% rename from schemars/tests/expected/transform_enum_external.json rename to schemars/tests/integration/snapshots/schemars/tests/integration/transform.rs~transform_enum.json index af746e3..29480cf 100644 --- a/schemars/tests/expected/transform_enum_external.json +++ b/schemars/tests/integration/snapshots/schemars/tests/integration/transform.rs~transform_enum.json @@ -5,8 +5,8 @@ { "type": "string", "const": "Unit", - "propertyCount": 0, - "upperType": "STRING" + "x-propertyCount": 0, + "x-upperType": "STRING" }, { "type": "object", @@ -17,9 +17,9 @@ "NewType" ], "additionalProperties": false, - "propertyCount": 1, - "upperType": "OBJECT" + "x-propertyCount": 1, + "x-upperType": "OBJECT" } ], - "propertyCount": 0 + "x-propertyCount": 0 } \ No newline at end of file diff --git a/schemars/tests/expected/transform_struct.json b/schemars/tests/integration/snapshots/schemars/tests/integration/transform.rs~transform_struct.json similarity index 70% rename from schemars/tests/expected/transform_struct.json rename to schemars/tests/integration/snapshots/schemars/tests/integration/transform.rs~transform_struct.json index 6723414..5a624df 100644 --- a/schemars/tests/expected/transform_struct.json +++ b/schemars/tests/integration/snapshots/schemars/tests/integration/transform.rs~transform_struct.json @@ -7,14 +7,14 @@ "int": { "type": "integer", "format": "int32", - "propertyCount": 0, - "upperType": "INTEGER" + "x-propertyCount": 0, + "x-upperType": "INTEGER" } }, "required": [ "value", "int" ], - "upperType": "OBJECT", - "propertyCount": 2 + "x-upperType": "OBJECT", + "x-propertyCount": 2 } \ No newline at end of file diff --git a/schemars/tests/expected/uuid.json b/schemars/tests/integration/snapshots/schemars/tests/integration/url.rs~url.json similarity index 68% rename from schemars/tests/expected/uuid.json rename to schemars/tests/integration/snapshots/schemars/tests/integration/url.rs~url.json index 98ae408..5c4bf3f 100644 --- a/schemars/tests/expected/uuid.json +++ b/schemars/tests/integration/snapshots/schemars/tests/integration/url.rs~url.json @@ -1,6 +1,6 @@ { "$schema": "https://json-schema.org/draft/2020-12/schema", - "title": "Uuid", + "title": "Url", "type": "string", - "format": "uuid" + "format": "uri" } \ 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 new file mode 100644 index 0000000..b6623b0 --- /dev/null +++ b/schemars/tests/integration/snapshots/schemars/tests/integration/uuid.rs~uuid.json @@ -0,0 +1,6 @@ +{ + "$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/expected/garde.json b/schemars/tests/integration/snapshots/schemars/tests/integration/validator.rs~validate_attrs.json similarity index 71% rename from schemars/tests/expected/garde.json rename to schemars/tests/integration/snapshots/schemars/tests/integration/validator.rs~validate_attrs.json index 1f5d8a6..f4e1fc4 100644 --- a/schemars/tests/expected/garde.json +++ b/schemars/tests/integration/snapshots/schemars/tests/integration/validator.rs~validate_attrs.json @@ -1,25 +1,25 @@ { "$schema": "https://json-schema.org/draft/2020-12/schema", - "title": "Struct", + "title": "ValidateAttrStruct", "type": "object", "properties": { "min_max": { "type": "number", "format": "float", - "minimum": 0.01, - "maximum": 100 + "minimum": 1.0, + "maximum": 100.0 }, "min_max2": { "type": "number", "format": "float", - "minimum": 1, - "maximum": 1000 + "minimum": 1.0, + "maximum": 10.0 }, - "regex_str1": { + "regex_str": { "type": "string", - "pattern": "^[Hh]ello\\b" + "pattern": "^[Hh]ello" }, - "contains_str1": { + "contains_str": { "type": "string", "pattern": "substring\\.\\.\\." }, @@ -36,16 +36,10 @@ "minLength": 1, "maxLength": 100 }, - "non_empty_str2": { - "type": "string", - "minLength": 1, - "maxLength": 1000 - }, "pair": { "type": "array", "items": { - "type": "integer", - "format": "int32" + "type": "string" }, "minItems": 2, "maxItems": 2 @@ -55,18 +49,19 @@ }, "x": { "type": "integer", - "format": "int32" + "format": "int32", + "minimum": -100, + "maximum": 100 } }, "required": [ "min_max", "min_max2", - "regex_str1", - "contains_str1", + "regex_str", + "contains_str", "email_address", "homepage", "non_empty_str", - "non_empty_str2", "pair", "required_option", "x" diff --git a/schemars/tests/integration/std_types.rs b/schemars/tests/integration/std_types.rs new file mode 100644 index 0000000..0ef2d7a --- /dev/null +++ b/schemars/tests/integration/std_types.rs @@ -0,0 +1,192 @@ +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 new file mode 100644 index 0000000..1ed5017 --- /dev/null +++ b/schemars/tests/integration/structs.rs @@ -0,0 +1,89 @@ +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 new file mode 100644 index 0000000..1d99b23 --- /dev/null +++ b/schemars/tests/integration/test_helper.rs @@ -0,0 +1,430 @@ +use jsonschema::JSONSchema as CompiledSchema; +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_compiled: OnceCell, + ser_schema_compiled: 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_compiled: OnceCell::new(), + ser_schema_compiled: 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_compiled: OnceCell::new(), + ser_schema_compiled: 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_compiled + .get_or_init(|| compile_schema(&self.de_schema)) + .is_valid(instance) + } + + fn ser_schema_validate(&self, instance: &Value) -> bool { + self.ser_schema_compiled + .get_or_init(|| compile_schema(&self.ser_schema)) + .is_valid(instance) + } +} + +fn compile_schema(schema: &Schema) -> CompiledSchema { + CompiledSchema::options() + .should_validate_formats(true) + .compile(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 new file mode 100644 index 0000000..94e728a --- /dev/null +++ b/schemars/tests/integration/transform.rs @@ -0,0 +1,68 @@ +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 new file mode 100644 index 0000000..2268cc5 --- /dev/null +++ b/schemars/tests/integration/transparent.rs @@ -0,0 +1,27 @@ +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 new file mode 100644 index 0000000..7f1c08a --- /dev/null +++ b/schemars/tests/integration/url.rs @@ -0,0 +1,14 @@ +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 new file mode 100644 index 0000000..0053226 --- /dev/null +++ b/schemars/tests/integration/uuid.rs @@ -0,0 +1,12 @@ +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 new file mode 100644 index 0000000..44a2708 --- /dev/null +++ b/schemars/tests/integration/validator.rs @@ -0,0 +1,135 @@ +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/no_std.rs b/schemars/tests/no_std.rs deleted file mode 100644 index c011aa2..0000000 --- a/schemars/tests/no_std.rs +++ /dev/null @@ -1,25 +0,0 @@ -#![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 deleted file mode 100644 index 22623fa..0000000 --- a/schemars/tests/nonzero_ints.rs +++ /dev/null @@ -1,17 +0,0 @@ -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 deleted file mode 100644 index aab52a7..0000000 --- a/schemars/tests/property_name.rs +++ /dev/null @@ -1,20 +0,0 @@ -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 deleted file mode 100644 index 0dad219..0000000 --- a/schemars/tests/range.rs +++ /dev/null @@ -1,17 +0,0 @@ -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 deleted file mode 100644 index dc349c6..0000000 --- a/schemars/tests/remote_derive.rs +++ /dev/null @@ -1,45 +0,0 @@ -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 deleted file mode 100644 index 53fb7d2..0000000 --- a/schemars/tests/remote_derive_generic.rs +++ /dev/null @@ -1,49 +0,0 @@ -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 deleted file mode 100644 index b0657e0..0000000 --- a/schemars/tests/result.rs +++ /dev/null @@ -1,21 +0,0 @@ -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 deleted file mode 100644 index 5e19611..0000000 --- a/schemars/tests/same_name.rs +++ /dev/null @@ -1,35 +0,0 @@ -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 deleted file mode 100644 index ebd8a52..0000000 --- a/schemars/tests/schema_name.rs +++ /dev/null @@ -1,77 +0,0 @@ -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 deleted file mode 100644 index 877a77c..0000000 --- a/schemars/tests/schema_settings.rs +++ /dev/null @@ -1,68 +0,0 @@ -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 deleted file mode 100644 index df9ab09..0000000 --- a/schemars/tests/schema_with_enum.rs +++ /dev/null @@ -1,90 +0,0 @@ -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 deleted file mode 100644 index 8677627..0000000 --- a/schemars/tests/schema_with_struct.rs +++ /dev/null @@ -1,54 +0,0 @@ -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 deleted file mode 100644 index 3c351c6..0000000 --- a/schemars/tests/semver.rs +++ /dev/null @@ -1,15 +0,0 @@ -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 deleted file mode 100644 index a95a8db..0000000 --- a/schemars/tests/skip.rs +++ /dev/null @@ -1,55 +0,0 @@ -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 deleted file mode 100644 index 8412a6a..0000000 --- a/schemars/tests/smallvec.rs +++ /dev/null @@ -1,8 +0,0 @@ -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 deleted file mode 100644 index 43fad30..0000000 --- a/schemars/tests/smol_str.rs +++ /dev/null @@ -1,8 +0,0 @@ -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 deleted file mode 100644 index 7f70a59..0000000 --- a/schemars/tests/std_time.rs +++ /dev/null @@ -1,16 +0,0 @@ -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 deleted file mode 100644 index 80f9ec8..0000000 --- a/schemars/tests/struct.rs +++ /dev/null @@ -1,45 +0,0 @@ -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 deleted file mode 100644 index 7fd64f3..0000000 --- a/schemars/tests/struct_additional_properties.rs +++ /dev/null @@ -1,17 +0,0 @@ -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 deleted file mode 100644 index 23d5b89..0000000 --- a/schemars/tests/transform.rs +++ /dev/null @@ -1,47 +0,0 @@ -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 deleted file mode 100644 index f8b2218..0000000 --- a/schemars/tests/transparent.rs +++ /dev/null @@ -1,31 +0,0 @@ -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/url.rs b/schemars/tests/url.rs deleted file mode 100644 index 018a66b..0000000 --- a/schemars/tests/url.rs +++ /dev/null @@ -1,15 +0,0 @@ -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 deleted file mode 100644 index ff67df6..0000000 --- a/schemars/tests/util/mod.rs +++ /dev/null @@ -1,46 +0,0 @@ -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 deleted file mode 100644 index 77e92c2..0000000 --- a/schemars/tests/uuid.rs +++ /dev/null @@ -1,7 +0,0 @@ -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 deleted file mode 100644 index 410593d..0000000 --- a/schemars/tests/validate.rs +++ /dev/null @@ -1,121 +0,0 @@ -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 deleted file mode 100644 index d3d8d65..0000000 --- a/schemars/tests/validate_inner.rs +++ /dev/null @@ -1,31 +0,0 @@ -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 44ef667..f6c2ae7 100644 --- a/schemars_derive/Cargo.toml +++ b/schemars_derive/Cargo.toml @@ -10,7 +10,7 @@ license = "MIT" readme = "README.md" keywords = ["rust", "json-schema", "serde"] categories = ["encoding", "no-std"] -rust-version = "1.65" +rust-version = "1.70" [lib] proc-macro = true diff --git a/schemars_derive/src/lib.rs b/schemars_derive/src/lib.rs index 557a276..8d8ccd0 100644 --- a/schemars_derive/src/lib.rs +++ b/schemars_derive/src/lib.rs @@ -126,7 +126,10 @@ fn derive_json_schema(mut input: syn::DeriveInput, repr: bool) -> syn::Result /dev/null 2>&1; then mv -f tests/actual/*.json tests/expected/