From a0d0eedcfa8902880d3a619f5a750713cf3d52e8 Mon Sep 17 00:00:00 2001 From: Isabel Atkinson Date: Wed, 22 Oct 2025 16:02:22 -0600 Subject: [PATCH] RUST-2294 Fold serde-tests into regular tests --- .evergreen/check-clippy.sh | 3 - .evergreen/check-rustfmt.sh | 2 - .evergreen/run-tests.sh | 3 - Cargo.lock | 35 + Cargo.toml | 2 +- serde-tests/Cargo.lock | 908 --------- serde-tests/Cargo.toml | 30 - serde-tests/lib.rs | 1 - serde-tests/rustfmt.toml | 9 - src/tests/serde.rs | 1739 +---------------- {serde-tests => src/tests/serde}/json.rs | 10 +- .../tests/serde/serialize_deserialize.rs | 230 +-- src/tests/serde/util.rs | 152 ++ src/tests/serde_helpers.rs | 1739 ++++++++++++++++- 14 files changed, 1987 insertions(+), 2876 deletions(-) delete mode 100644 serde-tests/Cargo.lock delete mode 100644 serde-tests/Cargo.toml delete mode 100644 serde-tests/lib.rs delete mode 100644 serde-tests/rustfmt.toml rename {serde-tests => src/tests/serde}/json.rs (91%) rename serde-tests/test.rs => src/tests/serde/serialize_deserialize.rs (80%) create mode 100644 src/tests/serde/util.rs diff --git a/.evergreen/check-clippy.sh b/.evergreen/check-clippy.sh index ca811c7e..6a88f3bd 100755 --- a/.evergreen/check-clippy.sh +++ b/.evergreen/check-clippy.sh @@ -10,6 +10,3 @@ CLIPPY_VERSION=1.89.0 rustup install $CLIPPY_VERSION cargo +$CLIPPY_VERSION clippy --all-targets --all-features -p bson -- -D warnings - -cd serde-tests -cargo +$CLIPPY_VERSION clippy --all-targets --all-features -p serde-tests -- -D warnings diff --git a/.evergreen/check-rustfmt.sh b/.evergreen/check-rustfmt.sh index fe7b032c..31230f12 100755 --- a/.evergreen/check-rustfmt.sh +++ b/.evergreen/check-rustfmt.sh @@ -4,5 +4,3 @@ set -o errexit . ~/.cargo/env cargo +nightly fmt -- --check - -cd serde-tests && cargo +nightly fmt -- --check diff --git a/.evergreen/run-tests.sh b/.evergreen/run-tests.sh index 5b01e50f..3dc1b334 100755 --- a/.evergreen/run-tests.sh +++ b/.evergreen/run-tests.sh @@ -8,6 +8,3 @@ set -o errexit RUST_BACKTRACE=1 cargo test --all-targets # Test with all features and including doctests RUST_BACKTRACE=1 cargo test --all-features - -cd serde-tests -RUST_BACKTRACE=1 cargo test diff --git a/Cargo.lock b/Cargo.lock index fadaf750..613340bd 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -128,6 +128,7 @@ dependencies = [ "pretty_assertions", "proptest", "rand", + "rmp-serde", "serde", "serde_bytes", "serde_json", @@ -145,6 +146,12 @@ version = "3.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "46c5e41b57b8bba42a04676d81cb89e9ee8e859a1a66f80a5a72e1cb76b34d43" +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + [[package]] name = "cast" version = "0.3.0" @@ -606,6 +613,12 @@ dependencies = [ "winapi", ] +[[package]] +name = "paste" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" + [[package]] name = "plotters" version = "0.3.7" @@ -839,6 +852,28 @@ version = "0.8.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7a2d987857b319362043e95f5353c0535c1f58eec5336fdfcf626430af7def58" +[[package]] +name = "rmp" +version = "0.8.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "228ed7c16fa39782c3b3468e974aec2795e9089153cd08ee2e9aefb3613334c4" +dependencies = [ + "byteorder", + "num-traits", + "paste", +] + +[[package]] +name = "rmp-serde" +version = "0.15.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "723ecff9ad04f4ad92fe1c8ca6c20d2196d9286e9c60727c4cb5511629260e9d" +dependencies = [ + "byteorder", + "rmp", + "serde", +] + [[package]] name = "rustix" version = "1.1.2" diff --git a/Cargo.toml b/Cargo.toml index c4105f8c..999e3153 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -24,7 +24,6 @@ exclude = [ "etc/**", "examples/**", "fuzz/**", - "serde-tests/**", "src/tests/**", "rustfmt.toml", ".travis.yml", @@ -89,6 +88,7 @@ serde_path_to_error = "0.1.16" serde_json = { version = "1", features = ["preserve_order"] } chrono = { version = "0.4", features = ["serde", "clock", "std"], default-features = false } jiff = { version = "0.2", default-features = false, features = ["std"] } +rmp-serde = "0.15" [package.metadata.docs.rs] all-features = true diff --git a/serde-tests/Cargo.lock b/serde-tests/Cargo.lock deleted file mode 100644 index ea41fa86..00000000 --- a/serde-tests/Cargo.lock +++ /dev/null @@ -1,908 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -version = 4 - -[[package]] -name = "ahash" -version = "0.8.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c99f64d1e06488f620f932677e24bc6e2897582980441ae90a671415bd7ec2f" -dependencies = [ - "cfg-if", - "getrandom 0.2.8", - "once_cell", - "version_check", -] - -[[package]] -name = "android_system_properties" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" -dependencies = [ - "libc", -] - -[[package]] -name = "ansi_term" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b" -dependencies = [ - "winapi", -] - -[[package]] -name = "autocfg" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" - -[[package]] -name = "base64" -version = "0.13.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" - -[[package]] -name = "base64" -version = "0.22.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" - -[[package]] -name = "bitflags" -version = "2.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c8214115b7bf84099f1309324e63141d4c5d7cc26862f97a0a857dbefe165bd" - -[[package]] -name = "bitvec" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bc2832c24239b0141d5674bb9174f9d68a8b5b3f2753311927c172ca46f7e9c" -dependencies = [ - "funty", - "radium", - "tap", - "wyz", -] - -[[package]] -name = "bson" -version = "3.0.0" -dependencies = [ - "ahash", - "base64 0.22.1", - "bitvec", - "chrono", - "getrandom 0.2.8", - "getrandom 0.3.2", - "hex", - "indexmap 2.1.0", - "js-sys", - "once_cell", - "rand", - "serde", - "serde_bytes", - "serde_json", - "serde_with", - "simdutf8", - "thiserror", - "time 0.3.17", - "uuid", -] - -[[package]] -name = "bumpalo" -version = "3.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "572f695136211188308f16ad2ca5c851a712c464060ae6974944458eb83880ba" - -[[package]] -name = "byteorder" -version = "1.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" - -[[package]] -name = "cc" -version = "1.0.77" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e9f73505338f7d905b19d18738976aae232eb46b8efc15554ffc56deb5d9ebe4" - -[[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.23" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16b0a3d9ed01224b22057780a37bb8c5dbfe1be8ba48678e7bf57ec4b385411f" -dependencies = [ - "iana-time-zone", - "js-sys", - "num-integer", - "num-traits", - "serde", - "time 0.1.45", - "wasm-bindgen", - "winapi", -] - -[[package]] -name = "codespan-reporting" -version = "0.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3538270d33cc669650c4b093848450d380def10c331d38c768e34cac80576e6e" -dependencies = [ - "termcolor", - "unicode-width", -] - -[[package]] -name = "core-foundation-sys" -version = "0.8.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5827cebf4670468b8772dd191856768aedcb1b0278a04f989f7766351917b9dc" - -[[package]] -name = "ctor" -version = "0.1.26" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d2301688392eb071b0bf1a37be05c469d3cc4dbbd95df672fe28ab021e6a096" -dependencies = [ - "quote", - "syn 1.0.104", -] - -[[package]] -name = "cxx" -version = "1.0.82" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4a41a86530d0fe7f5d9ea779916b7cadd2d4f9add748b99c2c029cbbdfaf453" -dependencies = [ - "cc", - "cxxbridge-flags", - "cxxbridge-macro", - "link-cplusplus", -] - -[[package]] -name = "cxx-build" -version = "1.0.82" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06416d667ff3e3ad2df1cd8cd8afae5da26cf9cec4d0825040f88b5ca659a2f0" -dependencies = [ - "cc", - "codespan-reporting", - "once_cell", - "proc-macro2", - "quote", - "scratch", - "syn 1.0.104", -] - -[[package]] -name = "cxxbridge-flags" -version = "1.0.82" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "820a9a2af1669deeef27cb271f476ffd196a2c4b6731336011e0ba63e2c7cf71" - -[[package]] -name = "cxxbridge-macro" -version = "1.0.82" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a08a6e2fcc370a089ad3b4aaf54db3b1b4cee38ddabce5896b33eb693275f470" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.104", -] - -[[package]] -name = "darling" -version = "0.20.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc7f46116c46ff9ab3eb1597a45688b6715c6e628b5c133e288e709a29bcb4ee" -dependencies = [ - "darling_core", - "darling_macro", -] - -[[package]] -name = "darling_core" -version = "0.20.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d00b9596d185e565c2207a0b01f8bd1a135483d02d9b7b0a54b11da8d53412e" -dependencies = [ - "fnv", - "ident_case", - "proc-macro2", - "quote", - "strsim", - "syn 2.0.101", -] - -[[package]] -name = "darling_macro" -version = "0.20.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc34b93ccb385b40dc71c6fceac4b2ad23662c7eeb248cf10d529b7e055b6ead" -dependencies = [ - "darling_core", - "quote", - "syn 2.0.101", -] - -[[package]] -name = "difference" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "524cbf6897b527295dff137cec09ecf3a05f4fddffd7dfcd1585403449e74198" - -[[package]] -name = "equivalent" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" - -[[package]] -name = "fnv" -version = "1.0.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" - -[[package]] -name = "funty" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" - -[[package]] -name = "getrandom" -version = "0.2.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c05aeb6a22b8f62540c194aac980f2115af067bfe15a0734d7277a768d396b31" -dependencies = [ - "cfg-if", - "js-sys", - "libc", - "wasi 0.11.0+wasi-snapshot-preview1", - "wasm-bindgen", -] - -[[package]] -name = "getrandom" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73fea8450eea4bac3940448fb7ae50d91f034f941199fcd9d909a5a07aa455f0" -dependencies = [ - "cfg-if", - "js-sys", - "libc", - "r-efi", - "wasi 0.14.2+wasi-0.2.4", - "wasm-bindgen", -] - -[[package]] -name = "hashbrown" -version = "0.12.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" - -[[package]] -name = "hashbrown" -version = "0.14.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604" - -[[package]] -name = "hex" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" - -[[package]] -name = "iana-time-zone" -version = "0.1.53" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64c122667b287044802d6ce17ee2ddf13207ed924c712de9a66a5814d5b64765" -dependencies = [ - "android_system_properties", - "core-foundation-sys", - "iana-time-zone-haiku", - "js-sys", - "wasm-bindgen", - "winapi", -] - -[[package]] -name = "iana-time-zone-haiku" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0703ae284fc167426161c2e3f1da3ea71d94b21bedbcc9494e92b28e334e3dca" -dependencies = [ - "cxx", - "cxx-build", -] - -[[package]] -name = "ident_case" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" - -[[package]] -name = "indexmap" -version = "1.9.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1885e79c1fc4b10f0e172c475f458b7f7b93061064d98c3293e98c5ba0c8b399" -dependencies = [ - "autocfg", - "hashbrown 0.12.3", - "serde", -] - -[[package]] -name = "indexmap" -version = "2.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d530e1a18b1cb4c484e6e34556a0d948706958449fca0cab753d649f2bce3d1f" -dependencies = [ - "equivalent", - "hashbrown 0.14.3", - "serde", -] - -[[package]] -name = "itoa" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4217ad341ebadf8d8e724e264f13e593e0648f5b3e94b3896a5df283be015ecc" - -[[package]] -name = "js-sys" -version = "0.3.77" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1cfaf33c695fc6e08064efbc1f72ec937429614f25eef83af942d0e227c3a28f" -dependencies = [ - "once_cell", - "wasm-bindgen", -] - -[[package]] -name = "libc" -version = "0.2.172" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d750af042f7ef4f724306de029d18836c26c1765a54a6a3f094cbd23a7267ffa" - -[[package]] -name = "link-cplusplus" -version = "1.0.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9272ab7b96c9046fbc5bc56c06c117cb639fe2d509df0c421cad82d2915cf369" -dependencies = [ - "cc", -] - -[[package]] -name = "log" -version = "0.4.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e" -dependencies = [ - "cfg-if", -] - -[[package]] -name = "num-integer" -version = "0.1.45" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9" -dependencies = [ - "autocfg", - "num-traits", -] - -[[package]] -name = "num-traits" -version = "0.2.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd" -dependencies = [ - "autocfg", -] - -[[package]] -name = "once_cell" -version = "1.16.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86f0b0d4bf799edbc74508c1e8bf170ff5f41238e5f8225603ca7caaae2b7860" - -[[package]] -name = "output_vt100" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "628223faebab4e3e40667ee0b2336d34a5b960ff60ea743ddfdbcf7770bcfb66" -dependencies = [ - "winapi", -] - -[[package]] -name = "paste" -version = "1.0.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1de2e551fb905ac83f73f7aedf2f0cb4a0da7e35efa24a202a936269f1f18e1" - -[[package]] -name = "ppv-lite86" -version = "0.2.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" - -[[package]] -name = "pretty_assertions" -version = "0.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f81e1644e1b54f5a68959a29aa86cde704219254669da328ecfdf6a1f09d427" -dependencies = [ - "ansi_term", - "ctor", - "difference", - "output_vt100", -] - -[[package]] -name = "proc-macro2" -version = "1.0.95" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778" -dependencies = [ - "unicode-ident", -] - -[[package]] -name = "quote" -version = "1.0.40" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d" -dependencies = [ - "proc-macro2", -] - -[[package]] -name = "r-efi" -version = "5.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74765f6d916ee2faa39bc8e68e4f3ed8949b48cccdac59983d287a7cb71ce9c5" - -[[package]] -name = "radium" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09" - -[[package]] -name = "rand" -version = "0.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fbfd9d094a40bf3ae768db9361049ace4c0e04a4fd6b359518bd7b73a73dd97" -dependencies = [ - "rand_chacha", - "rand_core", -] - -[[package]] -name = "rand_chacha" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb" -dependencies = [ - "ppv-lite86", - "rand_core", -] - -[[package]] -name = "rand_core" -version = "0.9.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38" -dependencies = [ - "getrandom 0.3.2", -] - -[[package]] -name = "rmp" -version = "0.8.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44519172358fd6d58656c86ab8e7fbc9e1490c3e8f14d35ed78ca0dd07403c9f" -dependencies = [ - "byteorder", - "num-traits", - "paste", -] - -[[package]] -name = "rmp-serde" -version = "0.15.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "723ecff9ad04f4ad92fe1c8ca6c20d2196d9286e9c60727c4cb5511629260e9d" -dependencies = [ - "byteorder", - "rmp", - "serde", -] - -[[package]] -name = "rustversion" -version = "1.0.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eded382c5f5f786b989652c49544c4877d9f015cc22e145a5ea8ea66c2921cd2" - -[[package]] -name = "ryu" -version = "1.0.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4501abdff3ae82a1c1b477a17252eb69cee9e66eb915c1abaa4f44d873df9f09" - -[[package]] -name = "scratch" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c8132065adcfd6e02db789d9285a0deb2f3fcb04002865ab67d5fb103533898" - -[[package]] -name = "serde" -version = "1.0.219" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f0e2c6ed6606019b4e29e69dbaba95b11854410e5347d525002456dbbb786b6" -dependencies = [ - "serde_derive", -] - -[[package]] -name = "serde-tests" -version = "0.1.0" -dependencies = [ - "base64 0.13.1", - "bson", - "chrono", - "hex", - "pretty_assertions", - "rmp-serde", - "serde", - "serde_json", - "serde_with", - "uuid", -] - -[[package]] -name = "serde_bytes" -version = "0.11.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cfc50e8183eeeb6178dcb167ae34a8051d63535023ae38b5d8d12beae193d37b" -dependencies = [ - "serde", -] - -[[package]] -name = "serde_derive" -version = "1.0.219" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.101", -] - -[[package]] -name = "serde_json" -version = "1.0.89" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "020ff22c755c2ed3f8cf162dbb41a7268d934702f3ed3631656ea597e08fc3db" -dependencies = [ - "indexmap 1.9.2", - "itoa", - "ryu", - "serde", -] - -[[package]] -name = "serde_with" -version = "3.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ad483d2ab0149d5a5ebcd9972a3852711e0153d863bf5a5d0391d28883c4a20" -dependencies = [ - "base64 0.22.1", - "chrono", - "hex", - "indexmap 1.9.2", - "indexmap 2.1.0", - "serde", - "serde_derive", - "serde_json", - "serde_with_macros", - "time 0.3.17", -] - -[[package]] -name = "serde_with_macros" -version = "3.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "65569b702f41443e8bc8bbb1c5779bd0450bbe723b56198980e80ec45780bce2" -dependencies = [ - "darling", - "proc-macro2", - "quote", - "syn 2.0.101", -] - -[[package]] -name = "simdutf8" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3a9fe34e3e7a50316060351f37187a3f546bce95496156754b601a5fa71b76e" - -[[package]] -name = "strsim" -version = "0.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" - -[[package]] -name = "syn" -version = "1.0.104" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ae548ec36cf198c0ef7710d3c230987c2d6d7bd98ad6edc0274462724c585ce" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "syn" -version = "2.0.101" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ce2b7fc941b3a24138a0a7cf8e858bfc6a992e7978a068a5c760deb0ed43caf" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "tap" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" - -[[package]] -name = "termcolor" -version = "1.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bab24d30b911b2376f3a13cc2cd443142f0c81dda04c118693e35b3835757755" -dependencies = [ - "winapi-util", -] - -[[package]] -name = "thiserror" -version = "2.0.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "567b8a2dae586314f7be2a752ec7474332959c6460e02bde30d702a66d488708" -dependencies = [ - "thiserror-impl", -] - -[[package]] -name = "thiserror-impl" -version = "2.0.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f7cf42b4507d8ea322120659672cf1b9dbb93f8f2d4ecfd6e51350ff5b17a1d" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.101", -] - -[[package]] -name = "time" -version = "0.1.45" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b797afad3f312d1c66a56d11d0316f916356d11bd158fbc6ca6389ff6bf805a" -dependencies = [ - "libc", - "wasi 0.10.0+wasi-snapshot-preview1", - "winapi", -] - -[[package]] -name = "time" -version = "0.3.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a561bf4617eebd33bca6434b988f39ed798e527f51a1e797d0ee4f61c0a38376" -dependencies = [ - "itoa", - "serde", - "time-core", - "time-macros", -] - -[[package]] -name = "time-core" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e153e1f1acaef8acc537e68b44906d2db6436e2b35ac2c6b42640fff91f00fd" - -[[package]] -name = "time-macros" -version = "0.2.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d967f99f534ca7e495c575c62638eebc2898a8c84c119b89e250477bc4ba16b2" -dependencies = [ - "time-core", -] - -[[package]] -name = "unicode-ident" -version = "1.0.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ceab39d59e4c9499d4e5a8ee0e2735b891bb7308ac83dfb4e80cad195c9f6f3" - -[[package]] -name = "unicode-width" -version = "0.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0edd1e5b14653f783770bce4a4dabb4a5108a5370a5f5d8cfe8710c361f6c8b" - -[[package]] -name = "uuid" -version = "1.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "422ee0de9031b5b948b97a8fc04e3aa35230001a722ddd27943e0be31564ce4c" -dependencies = [ - "getrandom 0.2.8", - "serde", - "wasm-bindgen", -] - -[[package]] -name = "version_check" -version = "0.9.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" - -[[package]] -name = "wasi" -version = "0.10.0+wasi-snapshot-preview1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f" - -[[package]] -name = "wasi" -version = "0.11.0+wasi-snapshot-preview1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" - -[[package]] -name = "wasi" -version = "0.14.2+wasi-0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9683f9a5a998d873c0d21fcbe3c083009670149a8fab228644b8bd36b2c48cb3" -dependencies = [ - "wit-bindgen-rt", -] - -[[package]] -name = "wasm-bindgen" -version = "0.2.100" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1edc8929d7499fc4e8f0be2262a241556cfc54a0bea223790e71446f2aab1ef5" -dependencies = [ - "cfg-if", - "once_cell", - "rustversion", - "wasm-bindgen-macro", -] - -[[package]] -name = "wasm-bindgen-backend" -version = "0.2.100" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f0a0651a5c2bc21487bde11ee802ccaf4c51935d0d3d42a6101f98161700bc6" -dependencies = [ - "bumpalo", - "log", - "proc-macro2", - "quote", - "syn 2.0.101", - "wasm-bindgen-shared", -] - -[[package]] -name = "wasm-bindgen-macro" -version = "0.2.100" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fe63fc6d09ed3792bd0897b314f53de8e16568c2b3f7982f468c0bf9bd0b407" -dependencies = [ - "quote", - "wasm-bindgen-macro-support", -] - -[[package]] -name = "wasm-bindgen-macro-support" -version = "0.2.100" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.101", - "wasm-bindgen-backend", - "wasm-bindgen-shared", -] - -[[package]] -name = "wasm-bindgen-shared" -version = "0.2.100" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a05d73b933a847d6cccdda8f838a22ff101ad9bf93e33684f39c1f5f0eece3d" -dependencies = [ - "unicode-ident", -] - -[[package]] -name = "winapi" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" -dependencies = [ - "winapi-i686-pc-windows-gnu", - "winapi-x86_64-pc-windows-gnu", -] - -[[package]] -name = "winapi-i686-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" - -[[package]] -name = "winapi-util" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" -dependencies = [ - "winapi", -] - -[[package]] -name = "winapi-x86_64-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" - -[[package]] -name = "wit-bindgen-rt" -version = "0.39.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f42320e61fe2cfd34354ecb597f86f413484a798ba44a8ca1165c58d42da6c1" -dependencies = [ - "bitflags", -] - -[[package]] -name = "wyz" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05f360fc0b24296329c78fda852a1e9ae82de9cf7b27dae4b7f62f118f77b9ed" -dependencies = [ - "tap", -] diff --git a/serde-tests/Cargo.toml b/serde-tests/Cargo.toml deleted file mode 100644 index 8e344904..00000000 --- a/serde-tests/Cargo.toml +++ /dev/null @@ -1,30 +0,0 @@ -[package] -name = "serde-tests" -version = "0.1.0" -authors = ["Kevin Yeh "] -edition = "2018" - -[features] -default = [] - -[dependencies] -bson = { path = "..", features = ["uuid-1", "chrono-0_4", "serde", "serde_with-3", "serde_json-1"] } -serde = { version = "1.0", features = ["derive"] } -pretty_assertions = "0.6.1" -hex = "0.4.2" -serde_with = "3" -chrono = "0.4" -uuid = "1" - -[dev-dependencies] -serde_json = { version = "1", features = ["preserve_order"] } -rmp-serde = "0.15" -base64 = "0.13.0" - -[lib] -name = "serde_tests" -path = "lib.rs" - -[[test]] -name = "serde" -path = "test.rs" diff --git a/serde-tests/lib.rs b/serde-tests/lib.rs deleted file mode 100644 index 65e2cc34..00000000 --- a/serde-tests/lib.rs +++ /dev/null @@ -1 +0,0 @@ -// intentionally blank diff --git a/serde-tests/rustfmt.toml b/serde-tests/rustfmt.toml deleted file mode 100644 index ca924c9a..00000000 --- a/serde-tests/rustfmt.toml +++ /dev/null @@ -1,9 +0,0 @@ -combine_control_expr = false -comment_width = 100 -condense_wildcard_suffixes = true -format_strings = true -normalize_comments = true -use_try_shorthand = true -wrap_comments = true -imports_layout = "HorizontalVertical" -imports_granularity = "Crate" diff --git a/src/tests/serde.rs b/src/tests/serde.rs index 3996fcee..4de53932 100644 --- a/src/tests/serde.rs +++ b/src/tests/serde.rs @@ -1,15 +1,21 @@ #![allow(clippy::disallowed_names)] +mod json; +mod serialize_deserialize; +pub(crate) mod util; + +use std::{ + collections::BTreeMap, + convert::{TryFrom, TryInto}, +}; + use crate::{ bson, cstr, deserialize_from_bson, - deserialize_from_document, doc, oid::ObjectId, - serde_helpers::{self, datetime, object_id, timestamp, u32, u64}, serialize_to_bson, - serialize_to_document, spec::BinarySubtype, tests::LOCK, Binary, @@ -18,16 +24,10 @@ use crate::{ Deserializer, Document, Serializer, - Timestamp, }; use serde::{Deserialize, Serialize}; use serde_json::json; -use serde_with::serde_as; -use std::{ - collections::BTreeMap, - convert::{TryFrom, TryInto}, -}; #[test] fn test_ser_vec() { @@ -310,56 +310,6 @@ fn test_binary_non_generic_roundtrip() { assert_eq!(x, f); } -#[test] -fn test_binary_helper_generic_roundtrip() { - let _guard = LOCK.run_concurrently(); - #[derive(Serialize, Deserialize, Debug, PartialEq)] - pub struct Foo { - data: Binary, - } - - let x = Foo { - data: Binary { - subtype: BinarySubtype::Generic, - bytes: b"12345abcde".to_vec(), - }, - }; - - let b = serialize_to_bson(&x).unwrap(); - assert_eq!( - b.as_document().unwrap(), - &doc! {"data": Bson::Binary(Binary { subtype: BinarySubtype::Generic, bytes: b"12345abcde".to_vec() })} - ); - - let f = deserialize_from_bson::(b).unwrap(); - assert_eq!(x, f); -} - -#[test] -fn test_binary_helper_non_generic_roundtrip() { - let _guard = LOCK.run_concurrently(); - #[derive(Serialize, Deserialize, Debug, PartialEq)] - pub struct Foo { - data: Binary, - } - - let x = Foo { - data: Binary { - subtype: BinarySubtype::BinaryOld, - bytes: b"12345abcde".to_vec(), - }, - }; - - let b = serialize_to_bson(&x).unwrap(); - assert_eq!( - b.as_document().unwrap(), - &doc! {"data": Bson::Binary(Binary { subtype: BinarySubtype::BinaryOld, bytes: b"12345abcde".to_vec() })} - ); - - let f = deserialize_from_bson::(b).unwrap(); - assert_eq!(x, f); -} - #[test] fn test_byte_vec() { let _guard = LOCK.run_concurrently(); @@ -602,1677 +552,6 @@ fn test_serialize_deserialize_unsigned_numbers() { assert!(doc_result.is_err()); } -#[test] -#[cfg(feature = "serde_with-3")] -fn test_oid_helpers() { - let _guard = LOCK.run_concurrently(); - - #[serde_as] - #[derive(Serialize, Deserialize, Debug, PartialEq)] - struct A { - #[serde_as(as = "object_id::AsHexString")] - oid: ObjectId, - - #[serde_as(as = "Option")] - oid_optional_none: Option, - - #[serde_as(as = "Option")] - oid_optional_some: Option, - - #[serde_as(as = "Vec")] - oid_vector: Vec, - } - - let oid = ObjectId::new(); - let a = A { - oid, - oid_optional_none: None, - oid_optional_some: Some(oid), - oid_vector: vec![oid], - }; - - // Serialize the struct to BSON - let doc = serialize_to_document(&a).unwrap(); - - // Validate serialized data - assert_eq!( - doc.get_str("oid").unwrap(), - oid.to_hex(), - "Expected serialized oid to match original ObjectId as hex string." - ); - - assert_eq!( - doc.get("oid_optional_none"), - Some(&Bson::Null), - "Expected serialized oid_optional_none to be None." - ); - - assert_eq!( - doc.get("oid_optional_some"), - Some(&Bson::String(oid.to_hex())), - "Expected serialized oid_optional_some to match original." - ); - - let oid_vector = doc - .get_array("oid_vector") - .expect("Expected serialized oid_vector to be a BSON array."); - let expected_oid_vector: Vec = vec![Bson::String(oid.to_hex())]; - assert_eq!( - oid_vector, &expected_oid_vector, - "Expected each serialized element in oid_vector match the original." - ); - - // Validate deserialized data - let a_deserialized: A = deserialize_from_document(doc).unwrap(); - assert_eq!( - a_deserialized, a, - "Deserialized struct does not match original." - ); - - // Validate deserializing error case with an invalid ObjectId string - let invalid_doc = doc! { - "oid": "not_a_valid_oid", - "oid_optional_none": Bson::Null, - "oid_optional_some": "also_invalid_oid", - "oid_vector": ["bad1", "bad2"] - }; - let result: Result = deserialize_from_document(invalid_doc); - assert!( - result.is_err(), - "Deserialization should fail for invalid ObjectId strings" - ); - let err_string = format!("{:?}", result.unwrap_err()); - assert!( - err_string.contains("BSON error"), - "Expected error message to mention BSON error: {}", - err_string - ); - - #[serde_as] - #[derive(Serialize, Deserialize, Debug, PartialEq)] - struct B { - #[serde_as(as = "object_id::FromHexString")] - oid: String, - - #[serde_as(as = "Option")] - oid_optional_none: Option, - - #[serde_as(as = "Option")] - oid_optional_some: Option, - - #[serde_as(as = "Vec")] - oid_vector: Vec, - } - - let oid = ObjectId::new(); - let b = B { - oid: oid.to_string(), - oid_optional_none: None, - oid_optional_some: Some(oid.to_string()), - oid_vector: vec![oid.to_string()], - }; - - // Serialize the struct to BSON - let doc = serialize_to_document(&b).unwrap(); - - // Validate serialized data - assert_eq!( - doc.get_object_id("oid").unwrap(), - oid, - "Expected serialized oid to match original ObjectId." - ); - - assert_eq!( - doc.get("oid_optional_none"), - Some(&Bson::Null), - "Expected serialized oid_optional_none to be None." - ); - - assert_eq!( - doc.get("oid_optional_some"), - Some(&Bson::ObjectId(oid)), - "Expected serialized oid_optional_some to match original." - ); - - let oid_vector = doc - .get_array("oid_vector") - .expect("Expected serialized oid_vector to be a BSON array."); - let expected_oid_vector: Vec = vec![Bson::ObjectId(oid)]; - assert_eq!( - oid_vector, &expected_oid_vector, - "Expected each serialized element in oid_vector match the original." - ); - - // Validate deserialized data - let b_deserialized: B = deserialize_from_document(doc).unwrap(); - assert_eq!( - b_deserialized, b, - "Deserialized struct does not match original." - ); - - // Validate serializing error case with an invalid ObjectId string - let invalid_oid = "invalid_oid"; - let bad_b = B { - oid: invalid_oid.to_string(), - oid_optional_none: None, - oid_optional_some: Some(invalid_oid.to_string()), - oid_vector: vec![invalid_oid.to_string()], - }; - let result = serialize_to_document(&bad_b); - assert!( - result.is_err(), - "Serialization should fail for invalid ObjectId strings" - ); - let err_string = format!("{:?}", result.unwrap_err()); - assert!( - err_string.contains("BSON error"), - "Expected error message to mention BSON error: {}", - err_string - ); -} - -#[test] -#[cfg(feature = "serde_with-3")] -fn test_datetime_rfc3339_string_helpers() { - let _guard = LOCK.run_concurrently(); - - #[serde_as] - #[derive(Deserialize, Serialize, Debug, PartialEq)] - struct A { - #[serde_as(as = "datetime::AsRfc3339String")] - pub date: DateTime, - - #[serde_as(as = "Option")] - pub date_optional_none: Option, - - #[serde_as(as = "Option")] - pub date_optional_some: Option, - - #[serde_as(as = "Vec")] - pub date_vector: Vec, - } - - let iso = "1996-12-20T00:39:57Z"; - let date = DateTime::parse_rfc3339_str(iso).unwrap(); - let a = A { - date, - date_optional_none: None, - date_optional_some: Some(date), - date_vector: vec![date], - }; - - // Serialize the struct to BSON - let doc = serialize_to_document(&a).unwrap(); - - // Validate serialized data - assert_eq!( - doc.get_str("date").unwrap(), - iso, - "Expected serialized date to match original date from RFC 3339 string." - ); - - assert_eq!( - doc.get("date_optional_none"), - Some(&Bson::Null), - "Expected serialized date_optional_none to be None." - ); - - assert_eq!( - doc.get("date_optional_some"), - Some(&Bson::String(iso.to_string())), - "Expected serialized date_optional_some to match original." - ); - - let date_vector = doc - .get_array("date_vector") - .expect("Expected serialized date_vector to be a BSON array."); - let expected_date_vector: Vec = vec![Bson::String(date.try_to_rfc3339_string().unwrap())]; - assert_eq!( - date_vector, &expected_date_vector, - "Expected each serialized element in date_vector to match the original." - ); - - // Validate deserialized data - let a_deserialized: A = deserialize_from_document(doc).unwrap(); - assert_eq!( - a_deserialized, a, - "Deserialized struct does not match original." - ); - - // Validate deserializing error case with an invalid DateTime string - let invalid_doc = doc! { - "date": "not_a_valid_date", - "date_optional_none": Bson::Null, - "date_optional_some": "also_invalid_date", - "date_vector": ["bad1", "bad2"] - }; - let result: Result = deserialize_from_document(invalid_doc); - assert!( - result.is_err(), - "Deserialization should fail for invalid DateTime strings" - ); - let err_string = format!("{:?}", result.unwrap_err()); - assert!( - err_string.contains("BSON error"), - "Expected error message to mention BSON error: {}", - err_string - ); - - #[serde_as] - #[derive(Deserialize, Serialize, Debug, PartialEq)] - struct B { - #[serde_as(as = "datetime::FromRfc3339String")] - pub date: String, - - #[serde_as(as = "Option")] - pub date_optional_none: Option, - - #[serde_as(as = "Option")] - pub date_optional_some: Option, - - #[serde_as(as = "Vec")] - pub date_vector: Vec, - } - - let date = DateTime::now(); - let b = B { - date: date.try_to_rfc3339_string().unwrap(), - date_optional_none: None, - date_optional_some: Some(date.try_to_rfc3339_string().unwrap()), - date_vector: vec![date.try_to_rfc3339_string().unwrap()], - }; - - // Serialize the struct to BSON - let doc = serialize_to_document(&b).unwrap(); - - // Validate serialized data - assert_eq!( - *doc.get_datetime("date").unwrap(), - date, - "Expected serialized date to be a BSON DateTime." - ); - - assert_eq!( - doc.get("date_optional_none"), - Some(&Bson::Null), - "Expected serialized date_optional_none to be None." - ); - - assert_eq!( - doc.get("date_optional_some"), - Some(&Bson::DateTime(date)), - "Expected serialized date_optional_some to match original." - ); - - let date_vector = doc - .get_array("date_vector") - .expect("Expected serialized date_vector to be a BSON array."); - let expected_date_vector: Vec = vec![Bson::DateTime(date)]; - assert_eq!( - date_vector, &expected_date_vector, - "Expected each serialized element in date_vector match the original." - ); - - // Validate deserialized data - let b_deserialized: B = deserialize_from_document(doc).unwrap(); - assert_eq!( - b_deserialized, b, - "Deserialized struct does not match original." - ); - - // Validate serializing error case with an invalid DateTime string - let invalid_date = "invalid_date"; - let bad_b = B { - date: invalid_date.to_string(), - date_optional_none: None, - date_optional_some: Some(invalid_date.to_string()), - date_vector: vec![invalid_date.to_string()], - }; - let result = serialize_to_document(&bad_b); - assert!( - result.is_err(), - "Serialization should fail for invalid DateTime strings" - ); - let err_string = format!("{:?}", result.unwrap_err()); - assert!( - err_string.contains("BSON error"), - "Expected error message to mention BSON error: {}", - err_string - ); -} - -#[test] -#[cfg(feature = "serde_with-3")] -fn test_datetime_i64_helper() { - let _guard = LOCK.run_concurrently(); - - #[serde_as] - #[derive(Serialize, Deserialize, Debug, PartialEq)] - struct A { - #[serde_as(as = "datetime::FromI64")] - date: i64, - - #[serde_as(as = "Option")] - date_optional_none: Option, - - #[serde_as(as = "Option")] - date_optional_some: Option, - - #[serde_as(as = "Vec")] - date_vector: Vec, - } - - let date = DateTime::now(); - let a = A { - date: date.timestamp_millis(), - date_optional_none: None, - date_optional_some: Some(date.timestamp_millis()), - date_vector: vec![date.timestamp_millis()], - }; - - // Serialize the struct to BSON - let doc = serialize_to_document(&a).unwrap(); - - // Validate serialized data - assert_eq!( - doc.get_datetime("date").unwrap(), - &date, - "Expected serialized date to match original date." - ); - - assert_eq!( - doc.get("date_optional_none"), - Some(&Bson::Null), - "Expected serialized date_optional_none to be None." - ); - - assert_eq!( - doc.get("date_optional_some"), - Some(&Bson::DateTime(date)), - "Expected serialized date_optional_some to match original." - ); - - let date_vector = doc - .get_array("date_vector") - .expect("Expected serialized date_vector to be a BSON array."); - let expected_date_vector: Vec = vec![Bson::DateTime(date)]; - assert_eq!( - date_vector, &expected_date_vector, - "Expected each serialized element in date_vector match the original." - ); - - // Validate deserialized data - let a_deserialized: A = deserialize_from_document(doc).unwrap(); - assert_eq!( - a_deserialized, a, - "Deserialized struct does not match original." - ); -} - -#[test] -#[cfg(all(feature = "chrono-0_4", feature = "serde_with-3"))] -fn test_datetime_chrono04_datetime_helper() { - let _guard = LOCK.run_concurrently(); - - use std::str::FromStr; - - #[serde_as] - #[derive(Deserialize, Serialize, Debug, PartialEq)] - struct A { - #[serde_as(as = "datetime::FromChrono04DateTime")] - pub date: chrono::DateTime, - - #[serde_as(as = "Option")] - pub date_optional_none: Option>, - - #[serde_as(as = "Option")] - pub date_optional_some: Option>, - - #[serde_as(as = "Vec")] - pub date_vector: Vec>, - } - - let iso = "1996-12-20T00:39:57Z"; - let date: chrono::DateTime = chrono::DateTime::from_str(iso).unwrap(); - let a: A = A { - date, - date_optional_none: None, - date_optional_some: Some(date), - date_vector: vec![date], - }; - - // Serialize the struct to BSON - let doc = serialize_to_document(&a).unwrap(); - - // Validate serialized data - assert_eq!( - doc.get_datetime("date").unwrap().to_chrono(), - date, - "Expected serialized date to match original date." - ); - - assert_eq!( - doc.get("date_optional_none"), - Some(&Bson::Null), - "Expected serialized date_optional_none to be None." - ); - - assert_eq!( - doc.get("date_optional_some"), - Some(&Bson::DateTime(DateTime::from_chrono(date))), - "Expected serialized date_optional_some to match original." - ); - - let date_vector = doc - .get_array("date_vector") - .expect("Expected serialized date_vector to be a BSON array."); - let expected_date_vector: Vec = vec![Bson::DateTime(date.into())]; - assert_eq!( - date_vector, &expected_date_vector, - "Expected each serialized element in date_vector to be a BSON DateTime matching the \ - original." - ); - - // Validate deserialized data - let a_deserialized: A = deserialize_from_document(doc).unwrap(); - assert_eq!( - a_deserialized, a, - "Deserialized struct does not match original." - ); -} - -#[test] -#[cfg(all(feature = "jiff-0_2", feature = "serde_with-3"))] -fn test_datetime_jiff02_timestamp_helper() { - let _guard = LOCK.run_concurrently(); - - use std::str::FromStr; - - #[serde_as] - #[derive(Deserialize, Serialize, Debug, PartialEq)] - struct A { - #[serde_as(as = "datetime::FromJiff02Timestamp")] - pub date: jiff::Timestamp, - - #[serde_as(as = "Option")] - pub date_optional_none: Option, - - #[serde_as(as = "Option")] - pub date_optional_some: Option, - - #[serde_as(as = "Vec")] - pub date_vector: Vec, - } - - let iso = "1996-12-20T00:39:57Z"; - let date: jiff::Timestamp = jiff::Timestamp::from_str(iso).unwrap(); - let a: A = A { - date, - date_optional_none: None, - date_optional_some: Some(date), - date_vector: vec![date], - }; - - // Serialize the struct to BSON - let doc = serialize_to_document(&a).unwrap(); - - // Validate serialized data - assert_eq!( - doc.get_datetime("date").unwrap().to_jiff(), - date, - "Expected serialized date to match original date." - ); - - assert_eq!( - doc.get("date_optional_none"), - Some(&Bson::Null), - "Expected serialized date_optional_none to be None." - ); - - assert_eq!( - doc.get("date_optional_some"), - Some(&Bson::DateTime(DateTime::from_jiff(date))), - "Expected serialized date_optional_some to match original." - ); - - let date_vector = doc - .get_array("date_vector") - .expect("Expected serialized date_vector to be a BSON array."); - let expected_date_vector: Vec = vec![Bson::DateTime(date.into())]; - assert_eq!( - date_vector, &expected_date_vector, - "Expected each serialized element in date_vector to be a BSON DateTime matching the \ - original." - ); - - // Validate deserialized data - let a_deserialized: A = deserialize_from_document(doc).unwrap(); - assert_eq!( - a_deserialized, a, - "Deserialized struct does not match original." - ); -} - -#[test] -#[cfg(all(feature = "time-0_3", feature = "serde_with-3"))] -fn test_datetime_time03_offset_datetime_helper() { - use time::OffsetDateTime; - let _guard = LOCK.run_concurrently(); - - #[serde_as] - #[derive(Deserialize, Serialize, Debug, PartialEq)] - struct A { - #[serde_as(as = "datetime::FromTime03OffsetDateTime")] - pub date: OffsetDateTime, - - #[serde_as(as = "Option")] - pub date_optional_none: Option, - - #[serde_as(as = "Option")] - pub date_optional_some: Option, - - #[serde_as(as = "Vec")] - pub date_vector: Vec, - } - - let date = DateTime::now(); - let a: A = A { - date: date.to_time_0_3(), - date_optional_none: None, - date_optional_some: Some(date.to_time_0_3()), - date_vector: vec![date.to_time_0_3()], - }; - - // Serialize the struct to BSON - let doc = serialize_to_document(&a).unwrap(); - - // Validate serialized data - assert_eq!( - doc.get_datetime("date").unwrap(), - &date, - "Expected serialized date to match original date." - ); - - assert_eq!( - doc.get("date_optional_none"), - Some(&Bson::Null), - "Expected serialized date_optional_none to be None." - ); - - assert_eq!( - doc.get("date_optional_some"), - Some(&Bson::DateTime(date)), - "Expected serialized date_optional_some to match original." - ); - - let date_vector = doc - .get_array("date_vector") - .expect("Expected serialized date_vector to be a BSON array."); - let expected_date_vector: Vec = vec![Bson::DateTime(date)]; - assert_eq!( - date_vector, &expected_date_vector, - "Expected each serialized element in date_vector to be a BSON DateTime matching the \ - original." - ); - - // Validate deserialized data - let a_deserialized: A = deserialize_from_document(doc).unwrap(); - assert_eq!( - a_deserialized, a, - "Deserialized struct does not match original." - ); -} - -#[test] -#[cfg(feature = "serde_with-3")] -fn test_timestamp_u32_helpers() { - let _guard = LOCK.run_concurrently(); - - #[serde_as] - #[derive(Deserialize, Serialize, Debug, PartialEq)] - struct A { - #[serde_as(as = "timestamp::AsU32")] - pub timestamp: Timestamp, - - #[serde_as(as = "Option")] - pub timestamp_optional_none: Option, - - #[serde_as(as = "Option")] - pub timestamp_optional_some: Option, - - #[serde_as(as = "Vec")] - pub timestamp_vector: Vec, - } - - let time = 12345; - let timestamp = Timestamp { time, increment: 0 }; - let a = A { - timestamp, - timestamp_optional_none: None, - timestamp_optional_some: Some(timestamp), - timestamp_vector: vec![timestamp], - }; - - // Serialize the struct to BSON - let doc = serialize_to_document(&a).unwrap(); - - // Validate serialized data - assert_eq!( - doc.get("timestamp").unwrap(), - &Bson::Int64(time as i64), - "Expected serialized time to match the original." - ); - - assert_eq!( - doc.get("timestamp_optional_none"), - Some(&Bson::Null), - "Expected serialized timestamp_optional_none to be None." - ); - - assert_eq!( - doc.get("timestamp_optional_some"), - Some(&Bson::Int64(time as i64)), - "Expected serialized timestamp_optional_some to match original time." - ); - - let timestamp_vector = doc - .get_array("timestamp_vector") - .expect("Expected serialized timestamp_vector to be a BSON array."); - let expected_timestamp_vector: Vec = vec![Bson::Int64(time as i64)]; - assert_eq!( - timestamp_vector, &expected_timestamp_vector, - "Expected each serialized element in timestamp_vector to match the original." - ); - - // Validate deserialized data - let a_deserialized: A = deserialize_from_document(doc).unwrap(); - assert_eq!( - a_deserialized, a, - "Deserialized struct does not match original." - ); - - // Validate serializing error case with an invalid Timestamp - let invalid_timestamp_for_serializing = Timestamp { - time: 0, - increment: 2, - }; - let bad_a: A = A { - timestamp: invalid_timestamp_for_serializing, - timestamp_optional_none: None, - timestamp_optional_some: Some(invalid_timestamp_for_serializing), - timestamp_vector: vec![invalid_timestamp_for_serializing], - }; - let result = serialize_to_document(&bad_a); - assert!( - result.is_err(), - "Serialization should fail for Timestamp with increment != 0" - ); - let err_string = format!("{:?}", result.unwrap_err()); - assert!( - err_string.contains("Cannot convert Timestamp with a non-zero increment to u32"), - "Expected error message to mention non-zero increment: {}", - err_string - ); - - #[serde_as] - #[derive(Deserialize, Serialize, Debug, PartialEq)] - struct B { - #[serde_as(as = "timestamp::FromU32")] - pub time: u32, - - #[serde_as(as = "Option")] - pub time_optional_none: Option, - - #[serde_as(as = "Option")] - pub time_optional_some: Option, - - #[serde_as(as = "Vec")] - pub time_vector: Vec, - } - - let time = 12345; - let b = B { - time, - time_optional_none: None, - time_optional_some: Some(time), - time_vector: vec![time], - }; - - // Serialize the struct to BSON - let doc = serialize_to_document(&b).unwrap(); - - // Validate serialized data - assert_eq!( - doc.get_timestamp("time").unwrap(), - Timestamp { time, increment: 0 }, - "Expected serialized time to match the original." - ); - - assert_eq!( - doc.get("time_optional_none"), - Some(&Bson::Null), - "Expected serialized time_optional_none to be None." - ); - - assert_eq!( - doc.get("time_optional_some"), - Some(&Bson::Timestamp(Timestamp { time, increment: 0 })), - "Expected serialized time_optional_some to match original." - ); - - let time_vector = doc - .get_array("time_vector") - .expect("Expected serialized time_vector to be a BSON array."); - let expected_time_vector: Vec = vec![Bson::Timestamp(Timestamp { time, increment: 0 })]; - assert_eq!( - time_vector, &expected_time_vector, - "Expected each serialized element in time_vector to match the original." - ); - - // Validate deserialized data - let b_deserialized: B = deserialize_from_document(doc).unwrap(); - assert_eq!( - b_deserialized, b, - "Deserialized struct does not match original." - ); - - // Validate deserializing error case with an invalid Timestamp - let invalid_timestamp_for_deserializing = Timestamp { - time: 0, - increment: 2, - }; - let invalid_doc = doc! { - "time": invalid_timestamp_for_deserializing, - "time_optional_none": Bson::Null, - "time_optional_some": Some(invalid_timestamp_for_deserializing), - "time_vector": [invalid_timestamp_for_deserializing] - }; - let result: Result = deserialize_from_document(invalid_doc); - assert!( - result.is_err(), - "Deserialization should fail for Timestamp with increment != 0" - ); - let err_string = format!("{:?}", result.unwrap_err()); - assert!( - err_string.contains("Cannot convert Timestamp with a non-zero increment to u32"), - "Expected error message to mention non-zero increment: {}", - err_string - ); -} - -#[test] -#[cfg(feature = "serde_with-3")] -fn test_u32_f64_helper() { - let _guard = LOCK.run_concurrently(); - - #[serde_as] - #[derive(Deserialize, Serialize, Debug, PartialEq)] - struct A { - #[serde_as(as = "u32::AsF64")] - pub value: u32, - - #[serde_as(as = "Option")] - pub value_optional_none: Option, - - #[serde_as(as = "Option")] - pub value_optional_some: Option, - - #[serde_as(as = "Vec")] - pub value_vector: Vec, - } - - let value = 12345; - let a = A { - value, - value_optional_none: None, - value_optional_some: Some(value), - value_vector: vec![value], - }; - - // Serialize the struct to BSON - let doc = serialize_to_document(&a).unwrap(); - - // Validate serialized data - assert_eq!( - doc.get("value"), - Some(&Bson::Double(value as f64)), - "Expected serialized value to match the original." - ); - - assert_eq!( - doc.get("value_optional_none"), - Some(&Bson::Null), - "Expected serialized value_optional_none to be None." - ); - - assert_eq!( - doc.get("value_optional_some"), - Some(&Bson::Double(value as f64)), - "Expected serialized value_optional_some to match original." - ); - - let value_vector = doc - .get_array("value_vector") - .expect("Expected serialized value_vector to be a BSON array."); - let expected_value_vector: Vec = vec![Bson::Double(value as f64)]; - assert_eq!( - value_vector, &expected_value_vector, - "Expected each serialized element in value_vector to match the original." - ); - - // Validate deserialized data - let a_deserialized: A = deserialize_from_document(doc).unwrap(); - assert_eq!( - a_deserialized, a, - "Deserialized struct does not match original." - ); -} - -#[test] -#[cfg(feature = "serde_with-3")] -fn test_u32_i32_helper() { - let _guard = LOCK.run_concurrently(); - - #[serde_as] - #[derive(Deserialize, Serialize, Debug, PartialEq)] - struct A { - #[serde_as(as = "u32::AsI32")] - value: u32, - - #[serde_as(as = "Option")] - value_optional_none: Option, - - #[serde_as(as = "Option")] - value_optional_some: Option, - - #[serde_as(as = "Vec")] - value_vector: Vec, - } - - let value = 1; - let a = A { - value, - value_optional_none: None, - value_optional_some: Some(value), - value_vector: vec![value], - }; - - // Serialize the struct to BSON - let doc = serialize_to_document(&a).unwrap(); - - // Validate serialized data - assert_eq!( - doc.get_i32("value").unwrap(), - value as i32, - "Expected serialized value to match original." - ); - - assert_eq!( - doc.get("value_optional_none"), - Some(&Bson::Null), - "Expected serialized value_optional_none to be None." - ); - - assert_eq!( - doc.get("value_optional_some"), - Some(&Bson::Int32(value as i32)), - "Expected serialized value_optional_some to match original." - ); - - let value_vector = doc - .get_array("value_vector") - .expect("Expected serialized value_vector to be a BSON array."); - let expected_value_vector: Vec = vec![Bson::Int32(value as i32)]; - assert_eq!( - value_vector, &expected_value_vector, - "Expected each serialized element in value_vector to match the original." - ); - - // Validate deserialized data - let a_deserialized: A = deserialize_from_document(doc).unwrap(); - assert_eq!( - a_deserialized, a, - "Deserialized struct does not match original." - ); - - // Validate serialization fails because u32::MAX is too large to fit in i32 - let invalid_value_for_serializing = u32::MAX; - let bad_a: A = A { - value: invalid_value_for_serializing, - value_optional_none: None, - value_optional_some: Some(invalid_value_for_serializing), - value_vector: vec![invalid_value_for_serializing], - }; - let result = serialize_to_document(&bad_a); - assert!( - result.is_err(), - "Serialization should fail for u32::MAX since it can't be exactly represented as i32" - ); - let err_string = format!("{:?}", result.unwrap_err()); - assert!( - err_string.contains("Cannot convert u32"), - "Expected error message to mention failed u32 to i32 conversion, got: {}", - err_string - ); - - // Validate deserialization fails for i32::MIN because negative values can't be converted to - // u32 - let invalid_value_for_deserializing = i32::MIN; - let bad_a = doc! { - "value": invalid_value_for_deserializing, - "value_optional_none": Bson::Null, - "value_optional_some": Some(invalid_value_for_deserializing), - "value_vector": [invalid_value_for_deserializing], - }; - let result: Result = deserialize_from_document(bad_a); - assert!( - result.is_err(), - "Deserialization should fail for i32::MIN since it can't be exactly represented as u32" - ); - let err_string = format!("{:?}", result.unwrap_err()); - assert!( - err_string.contains("Cannot convert i32"), - "Expected error message to mention failed i32 to u32 conversion, got: {}", - err_string - ); -} - -#[test] -#[cfg(feature = "serde_with-3")] -fn test_u32_i64_helper() { - let _guard = LOCK.run_concurrently(); - - #[serde_as] - #[derive(Deserialize, Serialize, Debug, PartialEq)] - struct A { - #[serde_as(as = "u32::AsI64")] - value: u32, - - #[serde_as(as = "Option")] - value_optional_none: Option, - - #[serde_as(as = "Option")] - value_optional_some: Option, - - #[serde_as(as = "Vec")] - value_vector: Vec, - } - - let value = u32::MAX; - let a = A { - value, - value_optional_none: None, - value_optional_some: Some(value), - value_vector: vec![value], - }; - - // Serialize the struct to BSON - let doc = serialize_to_document(&a).unwrap(); - - // Validate serialized data - assert_eq!( - doc.get_i64("value").unwrap(), - value as i64, - "Expected serialized value to match original." - ); - - assert_eq!( - doc.get("value_optional_none"), - Some(&Bson::Null), - "Expected serialized value_optional_none to be None." - ); - - assert_eq!( - doc.get("value_optional_some"), - Some(&Bson::Int64(value as i64)), - "Expected serialized value_optional_some to match original." - ); - - let value_vector = doc - .get_array("value_vector") - .expect("Expected serialized value_vector to be a BSON array."); - let expected_value_vector: Vec = vec![Bson::Int64(value as i64)]; - assert_eq!( - value_vector, &expected_value_vector, - "Expected each serialized element in value_vector to match the original." - ); - - // Validate deserialized data - let a_deserialized: A = deserialize_from_document(doc).unwrap(); - assert_eq!( - a_deserialized, a, - "Round-trip failed: deserialized struct did not match original." - ); - - // Validate deserialization fails for i64::MIN because negative values can't be converted to - // u32 - let invalid_value_for_deserializing = i64::MIN; - let bad_a = doc! { - "value": invalid_value_for_deserializing, - "value_optional_none": Bson::Null, - "value_optional_some": Some(invalid_value_for_deserializing), - "value_vector": [invalid_value_for_deserializing], - }; - let result: Result = deserialize_from_document(bad_a); - assert!( - result.is_err(), - "Deserialization should fail for i64::MIN since it can't be exactly represented as u32" - ); - let err_string = format!("{:?}", result.unwrap_err()); - assert!( - err_string.contains("Cannot convert i64"), - "Expected error message to mention failed i64 to u32 conversion, got: {}", - err_string - ); -} - -#[test] -#[cfg(feature = "serde_with-3")] -fn test_u64_f64_helper() { - let _guard = LOCK.run_concurrently(); - - #[serde_as] - #[derive(Deserialize, Serialize, Debug, PartialEq)] - struct A { - #[serde_as(as = "u64::AsF64")] - pub value: u64, - - #[serde_as(as = "Option")] - pub value_optional_none: Option, - - #[serde_as(as = "Option")] - pub value_optional_some: Option, - - #[serde_as(as = "Vec")] - pub value_vector: Vec, - } - - let value = 12345; - let a = A { - value, - value_optional_none: None, - value_optional_some: Some(value), - value_vector: vec![value], - }; - - // Serialize the struct to BSON - let doc = serialize_to_document(&a).unwrap(); - - // Validate serialized data - assert_eq!( - doc.get("value"), - Some(&Bson::Double(value as f64)), - "Expected serialized value to match the original." - ); - - assert_eq!( - doc.get("value_optional_none"), - Some(&Bson::Null), - "Expected serialized value_optional_none to be None." - ); - - assert_eq!( - doc.get("value_optional_some"), - Some(&Bson::Double(value as f64)), - "Expected serialized value_optional_some to match original." - ); - - let value_vector = doc - .get_array("value_vector") - .expect("Expected serialized value_vector to be a BSON array."); - let expected_value_vector: Vec = vec![Bson::Double(value as f64)]; - assert_eq!( - value_vector, &expected_value_vector, - "Expected each serialized element in value_vector to match the original." - ); - - // Validate deserialized data - let a_deserialized: A = deserialize_from_document(doc).unwrap(); - assert_eq!( - a_deserialized, a, - "Deserialized struct does not match original." - ); - - // Validate serializing error case with u64 over size limit - let invalid_value_for_serializing = u64::MAX; - let bad_a: A = A { - value: invalid_value_for_serializing, - value_optional_none: None, - value_optional_some: Some(invalid_value_for_serializing), - value_vector: vec![invalid_value_for_serializing], - }; - let result = serialize_to_document(&bad_a); - assert!( - result.is_err(), - "Serialization should fail for u64::MAX since it can't be exactly represented as f64" - ); - let err_string = format!("{:?}", result.unwrap_err()); - assert!( - err_string.contains("Cannot convert u64"), - "Expected error message to mention failed u64 to f64 conversion, got: {}", - err_string - ); -} - -#[test] -#[cfg(feature = "serde_with-3")] -fn test_u64_i32_helper() { - let _guard = LOCK.run_concurrently(); - - #[serde_as] - #[derive(Deserialize, Serialize, Debug, PartialEq)] - struct A { - #[serde_as(as = "u64::AsI32")] - value: u64, - - #[serde_as(as = "Option")] - value_optional_none: Option, - - #[serde_as(as = "Option")] - value_optional_some: Option, - - #[serde_as(as = "Vec")] - value_vector: Vec, - } - - let value = 1; - let a = A { - value, - value_optional_none: None, - value_optional_some: Some(value), - value_vector: vec![value], - }; - - // Serialize the struct to BSON - let doc = serialize_to_document(&a).unwrap(); - - // Validate serialized data - assert_eq!( - doc.get_i32("value").unwrap(), - value as i32, - "Expected serialized value to match original." - ); - - assert_eq!( - doc.get("value_optional_none"), - Some(&Bson::Null), - "Expected serialized value_optional_none to be None." - ); - - assert_eq!( - doc.get("value_optional_some"), - Some(&Bson::Int32(value as i32)), - "Expected serialized value_optional_some to match original." - ); - - let value_vector = doc - .get_array("value_vector") - .expect("Expected serialized value_vector to be a BSON array."); - let expected_value_vector: Vec = vec![Bson::Int32(value as i32)]; - assert_eq!( - value_vector, &expected_value_vector, - "Expected each serialized element in value_vector to match the original." - ); - - // Validate deserialized data - let a_deserialized: A = deserialize_from_document(doc).unwrap(); - assert_eq!( - a_deserialized, a, - "Round-trip failed: deserialized struct did not match original." - ); - - // Validate serialization fails because i32::MAX + 1 is too large to fit in i32 - let invalid_value_for_serializing = i32::MAX as u64 + 1; - let bad_a: A = A { - value: invalid_value_for_serializing, - value_optional_none: None, - value_optional_some: Some(invalid_value_for_serializing), - value_vector: vec![invalid_value_for_serializing], - }; - let result = serialize_to_document(&bad_a); - assert!( - result.is_err(), - "Serialization should fail for u64::MAX since it can't be exactly represented as i32" - ); - let err_string = format!("{:?}", result.unwrap_err()); - assert!( - err_string.contains("Cannot convert u64"), - "Expected error message to mention failed u64 to i32 conversion, got: {}", - err_string - ); - - // Validate deserialization fails for i32::MIN because negative values can't be converted to - // u64 - let invalid_value_for_deserializing = i32::MIN; - let bad_a = doc! { - "value": invalid_value_for_deserializing, - "value_optional_none": Bson::Null, - "value_optional_some": Some(invalid_value_for_deserializing), - "value_vector": [invalid_value_for_deserializing], - }; - let result: Result = deserialize_from_document(bad_a); - assert!( - result.is_err(), - "Deserialization should fail for i32::MIN since it can't be exactly represented as u64" - ); - let err_string = format!("{:?}", result.unwrap_err()); - assert!( - err_string.contains("Cannot convert i32"), - "Expected error message to mention failed i32 to u64 conversion, got: {}", - err_string - ); -} - -#[test] -#[cfg(feature = "serde_with-3")] -fn test_u64_i64_helper() { - let _guard = LOCK.run_concurrently(); - #[serde_as] - #[derive(Deserialize, Serialize, Debug, PartialEq)] - struct A { - #[serde_as(as = "u64::AsI64")] - value: u64, - - #[serde_as(as = "Option")] - value_optional_none: Option, - - #[serde_as(as = "Option")] - value_optional_some: Option, - - #[serde_as(as = "Vec")] - value_vector: Vec, - } - - let value = i64::MAX as u64; - let a = A { - value, - value_optional_none: None, - value_optional_some: Some(value), - value_vector: vec![value], - }; - - // Serialize the struct to BSON - let doc = serialize_to_document(&a).unwrap(); - - // Validate serialized data - assert_eq!( - doc.get_i64("value").unwrap(), - value as i64, - "Expected serialized value to match original." - ); - - assert_eq!( - doc.get("value_optional_none"), - Some(&Bson::Null), - "Expected serialized value_optional_none to be None." - ); - - assert_eq!( - doc.get("value_optional_some"), - Some(&Bson::Int64(value as i64)), - "Expected serialized value_optional_some to match original." - ); - - let value_vector = doc - .get_array("value_vector") - .expect("Expected serialized value_vector to be a BSON array."); - let expected_value_vector: Vec = vec![Bson::Int64(value as i64)]; - assert_eq!( - value_vector, &expected_value_vector, - "Expected each serialized element in value_vector to match the original." - ); - - // Validate deserialized data - let a_deserialized: A = deserialize_from_document(doc).unwrap(); - assert_eq!( - a_deserialized, a, - "Round-trip failed: deserialized struct did not match original." - ); - - // Validate serialization fails because i64::MAX + 1 is too large to fit in i64 - let invalid_value_for_serializing = i64::MAX as u64 + 1; - let bad_a: A = A { - value: invalid_value_for_serializing, - value_optional_none: None, - value_optional_some: Some(invalid_value_for_serializing), - value_vector: vec![invalid_value_for_serializing], - }; - let result = serialize_to_document(&bad_a); - assert!( - result.is_err(), - "Serialization should fail for (i64::MAX as u64) + 1 since it can't be exactly \ - represented as i64" - ); - let err_string = format!("{:?}", result.unwrap_err()); - assert!( - err_string.contains("Cannot convert u64"), - "Expected error message to mention failed u64 to i64 conversion, got: {}", - err_string - ); - - // Validate deserialization fails for i64::MIN because negative values can't be converted to - // u64 - let invalid_value_for_deserializing = i64::MIN; - let bad_a = doc! { - "value": invalid_value_for_deserializing, - "value_optional_none": Bson::Null, - "value_optional_some": Some(invalid_value_for_deserializing), - "value_vector": [invalid_value_for_deserializing], - }; - let result: Result = deserialize_from_document(bad_a); - assert!( - result.is_err(), - "Deserialization should fail for i64::MIN since it can't be exactly represented as u64" - ); - let err_string = format!("{:?}", result.unwrap_err()); - assert!( - err_string.contains("Cannot convert i64"), - "Expected error message to mention failed i64 to u64 conversion, got: {}", - err_string - ); -} - -#[test] -#[cfg(all(feature = "serde_with-3", feature = "uuid-1"))] -fn test_uuid_1_helpers() { - use crate::uuid::UuidRepresentation; - use serde_helpers::uuid_1; - use uuid::Uuid; - - let _guard = LOCK.run_concurrently(); - - fn assert_binary_match( - actual: &Bson, - uuid: &Uuid, - expected_subtype: BinarySubtype, - uuid_representation: UuidRepresentation, - ) { - match actual { - Bson::Binary(Binary { subtype, bytes }) => { - assert_eq!( - subtype, &expected_subtype, - "Expected subtype {:?}, but got {:?}", - expected_subtype, subtype - ); - let expected_bytes = { - let uuid: crate::Uuid = crate::uuid::Uuid::from(*uuid); - crate::Binary::from_uuid_with_representation(uuid, uuid_representation).bytes - }; - assert_eq!( - bytes, &expected_bytes, - "Serialized binary bytes did not match for representation {:?}", - uuid_representation - ); - } - other => panic!("Expected Bson::Binary, got {:?}", other), - } - } - - #[serde_as] - #[derive(Serialize, Deserialize, Debug, PartialEq)] - struct A { - #[serde_as(as = "uuid_1::AsBinary")] - uuid: Uuid, - - #[serde_as(as = "Option")] - uuid_optional_none: Option, - - #[serde_as(as = "Option")] - uuid_optional_some: Option, - - #[serde_as(as = "Vec")] - uuid_vector: Vec, - } - - let uuid = Uuid::parse_str("936DA01F9ABD4d9d80C702AF85C822A8").unwrap(); - let a: A = A { - uuid, - uuid_optional_none: None, - uuid_optional_some: Some(uuid), - uuid_vector: vec![uuid], - }; - - // Serialize the struct to BSON - let doc = serialize_to_document(&a).unwrap(); - - // Validate serialized data - assert_binary_match( - doc.get("uuid").unwrap(), - &uuid, - BinarySubtype::Uuid, - UuidRepresentation::Standard, - ); - - assert_eq!( - doc.get("uuid_optional_none"), - Some(&Bson::Null), - "Expected serialized uuid_optional_none to be None." - ); - - assert_binary_match( - doc.get("uuid_optional_some").unwrap(), - &uuid, - BinarySubtype::Uuid, - UuidRepresentation::Standard, - ); - - let uuid_vector = doc - .get_array("uuid_vector") - .expect("Expected serialized uuid_vector to be a BSON array."); - assert_eq!(uuid_vector.len(), 1); - assert_binary_match( - &uuid_vector[0], - &uuid, - BinarySubtype::Uuid, - UuidRepresentation::Standard, - ); - - // Validate deserialized data - let a_deserialized: A = deserialize_from_document(doc).unwrap(); - assert_eq!( - a_deserialized, a, - "Deserialized struct does not match original." - ); - - #[serde_as] - #[derive(Serialize, Deserialize, Debug, PartialEq)] - struct B { - #[serde_as(as = "uuid_1::AsCSharpLegacyBinary")] - uuid: Uuid, - - #[serde_as(as = "Option")] - uuid_optional_none: Option, - - #[serde_as(as = "Option")] - uuid_optional_some: Option, - - #[serde_as(as = "Vec")] - uuid_vector: Vec, - } - - let uuid = Uuid::parse_str("936DA01F9ABD4d9d80C702AF85C822A8").unwrap(); - let b: B = B { - uuid, - uuid_optional_none: None, - uuid_optional_some: Some(uuid), - uuid_vector: vec![uuid], - }; - - // Serialize the struct to BSON - let doc = serialize_to_document(&b).unwrap(); - - // Validate serialized data - assert_binary_match( - doc.get("uuid").unwrap(), - &uuid, - BinarySubtype::UuidOld, - UuidRepresentation::CSharpLegacy, - ); - - assert_eq!( - doc.get("uuid_optional_none"), - Some(&Bson::Null), - "Expected serialized uuid_optional_none to be None." - ); - - assert_binary_match( - doc.get("uuid_optional_some").unwrap(), - &uuid, - BinarySubtype::UuidOld, - UuidRepresentation::CSharpLegacy, - ); - - let uuid_vector = doc - .get_array("uuid_vector") - .expect("Expected uuid_vector to be a BSON array"); - assert_eq!(uuid_vector.len(), 1); - assert_binary_match( - &uuid_vector[0], - &uuid, - BinarySubtype::UuidOld, - UuidRepresentation::CSharpLegacy, - ); - - // Validate deserialized data - let b_deserialized: B = deserialize_from_document(doc).unwrap(); - assert_eq!( - b_deserialized, b, - "Deserialized struct does not match original." - ); - - #[serde_as] - #[derive(Serialize, Deserialize, Debug, PartialEq)] - struct C { - #[serde_as(as = "uuid_1::AsJavaLegacyBinary")] - uuid: Uuid, - - #[serde_as(as = "Option")] - uuid_optional_none: Option, - - #[serde_as(as = "Option")] - uuid_optional_some: Option, - - #[serde_as(as = "Vec")] - uuid_vector: Vec, - } - - let uuid = Uuid::parse_str("936DA01F9ABD4d9d80C702AF85C822A8").unwrap(); - let c: C = C { - uuid, - uuid_optional_none: None, - uuid_optional_some: Some(uuid), - uuid_vector: vec![uuid], - }; - - // Serialize the struct to BSON - let doc = serialize_to_document(&c).unwrap(); - - // Validate serialized data - assert_binary_match( - doc.get("uuid").unwrap(), - &uuid, - BinarySubtype::UuidOld, - UuidRepresentation::JavaLegacy, - ); - - assert_eq!( - doc.get("uuid_optional_none"), - Some(&Bson::Null), - "Expected serialized uuid_optional_none to be None." - ); - - assert_binary_match( - doc.get("uuid_optional_some").unwrap(), - &uuid, - BinarySubtype::UuidOld, - UuidRepresentation::JavaLegacy, - ); - - let uuid_vector = doc - .get_array("uuid_vector") - .expect("Expected uuid_vector to be a BSON array"); - assert_eq!(uuid_vector.len(), 1); - assert_binary_match( - &uuid_vector[0], - &uuid, - BinarySubtype::UuidOld, - UuidRepresentation::JavaLegacy, - ); - - // Validate deserialized data - let c_deserialized: C = deserialize_from_document(doc).unwrap(); - assert_eq!( - c_deserialized, c, - "Deserialized struct does not match original." - ); - - #[serde_as] - #[derive(Serialize, Deserialize, Debug, PartialEq)] - struct D { - #[serde_as(as = "uuid_1::AsPythonLegacyBinary")] - uuid: Uuid, - - #[serde_as(as = "Option")] - uuid_optional_none: Option, - - #[serde_as(as = "Option")] - uuid_optional_some: Option, - - #[serde_as(as = "Vec")] - uuid_vector: Vec, - } - - let uuid = Uuid::parse_str("936DA01F9ABD4d9d80C702AF85C822A8").unwrap(); - let d: D = D { - uuid, - uuid_optional_none: None, - uuid_optional_some: Some(uuid), - uuid_vector: vec![uuid], - }; - - // Serialize the struct to BSON - let doc = serialize_to_document(&d).unwrap(); - - // Validate serialized data - assert_binary_match( - doc.get("uuid").unwrap(), - &uuid, - BinarySubtype::UuidOld, - UuidRepresentation::PythonLegacy, - ); - - assert_eq!( - doc.get("uuid_optional_none"), - Some(&Bson::Null), - "Expected serialized uuid_optional_none to be None." - ); - - assert_binary_match( - doc.get("uuid_optional_some").unwrap(), - &uuid, - BinarySubtype::UuidOld, - UuidRepresentation::PythonLegacy, - ); - - let uuid_vector = doc - .get_array("uuid_vector") - .expect("Expected uuid_vector to be a BSON array"); - assert_eq!(uuid_vector.len(), 1); - assert_binary_match( - &uuid_vector[0], - &uuid, - BinarySubtype::UuidOld, - UuidRepresentation::PythonLegacy, - ); - - // Validate deserialized data - let d_deserialized: D = deserialize_from_document(doc).unwrap(); - assert_eq!( - d_deserialized, d, - "Deserialized struct does not match original." - ); -} - #[test] fn large_dates() { let _guard = LOCK.run_concurrently(); diff --git a/serde-tests/json.rs b/src/tests/serde/json.rs similarity index 91% rename from serde-tests/json.rs rename to src/tests/serde/json.rs index 8b12f014..c38ed3b2 100644 --- a/serde-tests/json.rs +++ b/src/tests/serde/json.rs @@ -1,11 +1,11 @@ use pretty_assertions::assert_eq; use serde_json::json; -use super::AllTypes; +use serde::{Deserialize, Serialize}; -use bson::{cstr, doc, Bson, JavaScriptCodeWithScope, RawArrayBuf, RawBson, RawDocumentBuf}; +use crate::{cstr, doc, Bson, JavaScriptCodeWithScope, RawArrayBuf, RawBson, RawDocumentBuf}; -use serde::{Deserialize, Serialize}; +use super::util::AllTypes; #[test] fn all_types_json() { @@ -39,8 +39,8 @@ fn all_types_json() { "b": true, "d": 12.5, "binary": v.binary.bytes, - "binary_old": { "$binary": { "base64": base64::encode(&v.binary_old.bytes), "subType": "02" } }, - "binary_other": { "$binary": { "base64": base64::encode(&v.binary_old.bytes), "subType": "81" } }, + "binary_old": { "$binary": { "base64": crate::base64::encode(&v.binary_old.bytes), "subType": "02" } }, + "binary_other": { "$binary": { "base64": crate::base64::encode(&v.binary_old.bytes), "subType": "81" } }, "date": { "$date": { "$numberLong": v.date.timestamp_millis().to_string() } }, "regex": { "$regularExpression": { "pattern": v.regex.pattern, "options": v.regex.options } }, "ts": { "$timestamp": { "t": 123, "i": 456 } }, diff --git a/serde-tests/test.rs b/src/tests/serde/serialize_deserialize.rs similarity index 80% rename from serde-tests/test.rs rename to src/tests/serde/serialize_deserialize.rs index 95d17186..29891474 100644 --- a/serde-tests/test.rs +++ b/src/tests/serde/serialize_deserialize.rs @@ -1,7 +1,11 @@ #![allow(clippy::cognitive_complexity)] #![allow(clippy::vec_init_then_push)] -mod json; +use std::{ + borrow::Cow, + collections::{BTreeMap, HashSet}, + iter::FromIterator, +}; use pretty_assertions::assert_eq; use serde::{ @@ -11,13 +15,7 @@ use serde::{ Serialize, }; -use std::{ - borrow::Cow, - collections::{BTreeMap, HashSet}, - iter::FromIterator, -}; - -use bson::{ +use crate::{ cstr, doc, oid::ObjectId, @@ -41,11 +39,12 @@ use bson::{ RawJavaScriptCodeWithScopeRef, RawRegexRef, Regex, - Timestamp, Utf8Lossy, Uuid, }; +use super::util::AllTypes; + /// Verifies the following: /// - round trip `expected_value` through `Document`: /// - serializing the `expected_value` to a `Document` matches the `expected_doc` @@ -54,41 +53,41 @@ use bson::{ /// - serializing `expected_value` to BSON bytes matches the raw BSON bytes of `expected_doc` /// - deserializing a `T` from the serialized bytes produces `expected_value` /// - deserializing a `Document` from the serialized bytes produces `expected_doc` -/// - `bson::to_vec` and `Document::to_vec` produce the same result given the same input +/// - `crate::to_vec` and `Document::to_vec` produce the same result given the same input fn run_test(expected_value: &T, expected_doc: &Document, description: &str) where T: Serialize + DeserializeOwned + PartialEq + std::fmt::Debug, { let expected_bytes = expected_doc.to_vec().expect(description); - let expected_bytes_serde = bson::serialize_to_vec(&expected_value).expect(description); + let expected_bytes_serde = crate::serialize_to_vec(&expected_value).expect(description); assert_eq!(expected_bytes_serde, expected_bytes, "{}", description); - let expected_bytes_from_doc_serde = bson::serialize_to_vec(&expected_doc).expect(description); + let expected_bytes_from_doc_serde = crate::serialize_to_vec(&expected_doc).expect(description); assert_eq!( expected_bytes_from_doc_serde, expected_bytes, "{}", description ); - let serialized_doc = bson::serialize_to_document(&expected_value).expect(description); + let serialized_doc = crate::serialize_to_document(&expected_value).expect(description); assert_eq!(&serialized_doc, expected_doc, "{}", description); assert_eq!( expected_value, - &bson::deserialize_from_document::(serialized_doc).expect(description), + &crate::deserialize_from_document::(serialized_doc).expect(description), "{}", description ); assert_eq!( - &bson::deserialize_from_reader::<_, T>(expected_bytes.as_slice()).expect(description), + &crate::deserialize_from_reader::<_, T>(expected_bytes.as_slice()).expect(description), expected_value, "{}", description ); assert_eq!( - &bson::deserialize_from_reader::<_, Document>(expected_bytes.as_slice()) + &crate::deserialize_from_reader::<_, Document>(expected_bytes.as_slice()) .expect(description), expected_doc, "{}", @@ -107,19 +106,19 @@ where let expected_bytes = expected_doc.to_vec().expect(description); assert_eq!( - &bson::deserialize_from_document::(expected_doc.clone()).expect(description), + &crate::deserialize_from_document::(expected_doc.clone()).expect(description), expected_value, "{}", description ); assert_eq!( - &bson::deserialize_from_reader::<_, T>(expected_bytes.as_slice()).expect(description), + &crate::deserialize_from_reader::<_, T>(expected_bytes.as_slice()).expect(description), expected_value, "{}", description ); assert_eq!( - &bson::deserialize_from_reader::<_, Document>(expected_bytes.as_slice()) + &crate::deserialize_from_reader::<_, Document>(expected_bytes.as_slice()) .expect(description), expected_doc, "{}", @@ -134,8 +133,8 @@ fn run_raw_round_trip_test<'de, T>(bytes: &'de [u8], description: &str) where T: Deserialize<'de> + Serialize + std::fmt::Debug, { - let t: T = bson::deserialize_from_slice(bytes).expect(description); - let vec = bson::serialize_to_vec(&t).expect(description); + let t: T = crate::deserialize_from_slice(bytes).expect(description); + let vec = crate::serialize_to_vec(&t).expect(description); assert_eq!(vec.as_slice(), bytes); } @@ -442,12 +441,12 @@ fn type_conversion() { let doc = doc! { "bar": 1_i64 }; - let deserialized: Foo = bson::deserialize_from_document(doc.clone()).unwrap(); + let deserialized: Foo = crate::deserialize_from_document(doc.clone()).unwrap(); assert_eq!(deserialized, v); let bytes = doc.to_vec().unwrap(); - let bson_deserialized: Foo = bson::deserialize_from_reader(bytes.as_slice()).unwrap(); + let bson_deserialized: Foo = crate::deserialize_from_reader(bytes.as_slice()).unwrap(); assert_eq!(bson_deserialized, v); } @@ -460,11 +459,11 @@ fn missing_errors() { let doc = doc! {}; - bson::deserialize_from_document::(doc.clone()).unwrap_err(); + crate::deserialize_from_document::(doc.clone()).unwrap_err(); let bytes = doc.to_vec().unwrap(); - bson::deserialize_from_reader::<_, Foo>(bytes.as_slice()).unwrap_err(); + crate::deserialize_from_reader::<_, Foo>(bytes.as_slice()).unwrap_err(); } #[test] @@ -678,11 +677,11 @@ fn unused_fields_deny() { "a": 1, "b": 2, }; - bson::deserialize_from_document::(doc.clone()) + crate::deserialize_from_document::(doc.clone()) .expect_err("extra fields should cause failure"); let bytes = doc.to_vec().unwrap(); - bson::deserialize_from_reader::<_, Foo>(bytes.as_slice()) + crate::deserialize_from_reader::<_, Foo>(bytes.as_slice()) .expect_err("extra fields should cause failure"); } @@ -738,7 +737,7 @@ fn raw_doc_buf() { d: RawDocumentBuf, } - let bytes = bson::serialize_to_vec(&doc! { + let bytes = crate::serialize_to_vec(&doc! { "d": { "a": 12, "b": 5.5, @@ -760,7 +759,7 @@ fn raw_doc() { d: &'a RawDocument, } - let bytes = bson::serialize_to_vec(&doc! { + let bytes = crate::serialize_to_vec(&doc! { "d": { "a": 12, "b": 5.5, @@ -782,7 +781,7 @@ fn raw_array() { d: &'a RawArray, } - let bytes = bson::serialize_to_vec(&doc! { + let bytes = crate::serialize_to_vec(&doc! { "d": [1, true, { "ok": 1 }, [ "sub", "array" ], Uuid::new()] }) .expect("raw_array"); @@ -807,7 +806,7 @@ fn raw_binary() { other: RawBinaryRef<'a>, } - let bytes = bson::serialize_to_vec(&doc! { + let bytes = crate::serialize_to_vec(&doc! { "generic": Binary { bytes: vec![1, 2, 3, 4, 5], subtype: BinarySubtype::Generic, @@ -835,7 +834,7 @@ fn raw_regex() { r: RawRegexRef<'a>, } - let bytes = bson::serialize_to_vec(&doc! { + let bytes = crate::serialize_to_vec(&doc! { "r": Regex { pattern: cstr!("a[b-c]d").into(), options: cstr!("ab").into(), @@ -854,7 +853,7 @@ fn raw_code_w_scope() { r: RawJavaScriptCodeWithScopeRef<'a>, } - let bytes = bson::serialize_to_vec(&doc! { + let bytes = crate::serialize_to_vec(&doc! { "r": JavaScriptCodeWithScope { code: "console.log(x)".to_string(), scope: doc! { "x": 1 }, @@ -879,142 +878,6 @@ fn raw_db_pointer() { run_raw_round_trip_test::(bytes.as_slice(), "raw_db_pointer"); } -#[derive(Debug, Deserialize, Serialize, PartialEq)] -struct SubDoc { - a: i32, - b: i32, -} - -#[derive(Debug, Deserialize, Serialize, PartialEq)] -struct AllTypes { - x: i32, - y: i64, - s: String, - array: Vec, - bson: Bson, - oid: ObjectId, - null: Option<()>, - subdoc: Document, - b: bool, - d: f64, - binary: Binary, - binary_old: Binary, - binary_other: Binary, - date: DateTime, - regex: Regex, - ts: Timestamp, - i: SubDoc, - undefined: Bson, - code: Bson, - code_w_scope: JavaScriptCodeWithScope, - decimal: Decimal128, - symbol: Bson, - min_key: Bson, - max_key: Bson, -} - -impl AllTypes { - fn fixtures() -> (Self, Document) { - let binary = Binary { - bytes: vec![36, 36, 36], - subtype: BinarySubtype::Generic, - }; - let binary_old = Binary { - bytes: vec![36, 36, 36], - subtype: BinarySubtype::BinaryOld, - }; - let binary_other = Binary { - bytes: vec![36, 36, 36], - subtype: BinarySubtype::UserDefined(0x81), - }; - let date = DateTime::now(); - let regex = Regex { - pattern: cstr!("hello").into(), - options: cstr!("x").into(), - }; - let timestamp = Timestamp { - time: 123, - increment: 456, - }; - let code = Bson::JavaScriptCode("console.log(1)".to_string()); - let code_w_scope = JavaScriptCodeWithScope { - code: "console.log(a)".to_string(), - scope: doc! { "a": 1 }, - }; - let oid = ObjectId::new(); - let subdoc = doc! { "k": true, "b": { "hello": "world" } }; - - let decimal = { - let bytes = hex::decode("18000000136400D0070000000000000000000000003A3000").unwrap(); - let d = Document::from_reader(bytes.as_slice()).unwrap(); - match d.get("d") { - Some(Bson::Decimal128(d)) => *d, - c => panic!("expected decimal128, got {:?}", c), - } - }; - - let doc = doc! { - "x": 1, - "y": 2_i64, - "s": "oke", - "array": [ true, "oke", { "12": 24 } ], - "bson": 1234.5, - "oid": oid, - "null": Bson::Null, - "subdoc": subdoc.clone(), - "b": true, - "d": 12.5, - "binary": binary.clone(), - "binary_old": binary_old.clone(), - "binary_other": binary_other.clone(), - "date": date, - "regex": regex.clone(), - "ts": timestamp, - "i": { "a": 300, "b": 12345 }, - "undefined": Bson::Undefined, - "code": code.clone(), - "code_w_scope": code_w_scope.clone(), - "decimal": Bson::Decimal128(decimal), - "symbol": Bson::Symbol("ok".to_string()), - "min_key": Bson::MinKey, - "max_key": Bson::MaxKey, - }; - - let v = AllTypes { - x: 1, - y: 2, - s: "oke".to_string(), - array: vec![ - Bson::Boolean(true), - Bson::String("oke".to_string()), - Bson::Document(doc! { "12": 24 }), - ], - bson: Bson::Double(1234.5), - oid, - null: None, - subdoc, - b: true, - d: 12.5, - binary, - binary_old, - binary_other, - date, - regex, - ts: timestamp, - i: SubDoc { a: 300, b: 12345 }, - undefined: Bson::Undefined, - code, - code_w_scope, - decimal, - symbol: Bson::Symbol("ok".to_string()), - min_key: Bson::MinKey, - max_key: Bson::MaxKey, - }; - - (v, doc) - } -} - #[test] fn all_types() { let (v, doc) = AllTypes::fixtures(); @@ -1050,7 +913,7 @@ fn all_raw_types_rmp() { regex: RawRegexRef<'a>, } - let doc_bytes = bson::serialize_to_vec(&doc! { + let doc_bytes = crate::serialize_to_vec(&doc! { "bson": "some string", "array": [1, 2, 3], "binary": Binary { bytes: vec![1, 2, 3], subtype: BinarySubtype::Generic }, @@ -1138,7 +1001,7 @@ fn borrowed() { }; let deserialized: Foo = - bson::deserialize_from_slice(bson.as_slice()).expect("deserialization should succeed"); + crate::deserialize_from_slice(bson.as_slice()).expect("deserialization should succeed"); assert_eq!(deserialized, v); } @@ -1181,13 +1044,13 @@ fn u2i() { let v = TooBig { u_64: i64::MAX as u64 + 1, }; - bson::serialize_to_document(&v).unwrap_err(); - bson::serialize_to_vec(&v).unwrap_err(); + crate::serialize_to_document(&v).unwrap_err(); + crate::serialize_to_vec(&v).unwrap_err(); } #[test] fn serde_with_chrono() { - use bson::serde_helpers::datetime; + use crate::serde_helpers::datetime; #[serde_with::serde_as] #[derive(Deserialize, Serialize, PartialEq, Debug)] struct Foo { @@ -1199,7 +1062,7 @@ fn serde_with_chrono() { } let f = Foo { - as_bson: Some(bson::DateTime::now().into()), + as_bson: Some(crate::DateTime::now().into()), none_bson: None, }; let expected = doc! { @@ -1212,7 +1075,7 @@ fn serde_with_chrono() { #[test] fn serde_with_uuid() { - use bson::serde_helpers::uuid_1; + use crate::serde_helpers::uuid_1; #[serde_with::serde_as] #[derive(Deserialize, Serialize, PartialEq, Debug)] struct Foo { @@ -1228,7 +1091,7 @@ fn serde_with_uuid() { none_bson: None, }; let expected = doc! { - "as_bson": bson::Uuid::from(f.as_bson.unwrap()), + "as_bson": crate::Uuid::from(f.as_bson.unwrap()), "none_bson": Bson::Null }; @@ -1315,15 +1178,15 @@ fn hint_cleared() { "binary": binary_value.clone() }; - let bytes = bson::serialize_to_vec(&doc_value).unwrap(); + let bytes = crate::serialize_to_vec(&doc_value).unwrap(); let doc = RawDocument::from_bytes(&bytes).unwrap(); let binary = doc.get_binary("binary").unwrap(); let f = Foo { doc, binary }; - let serialized_bytes = bson::serialize_to_vec(&f).unwrap(); - let round_doc: Document = bson::deserialize_from_slice(&serialized_bytes).unwrap(); + let serialized_bytes = crate::serialize_to_vec(&f).unwrap(); + let round_doc: Document = crate::deserialize_from_slice(&serialized_bytes).unwrap(); assert_eq!(round_doc, doc! { "doc": doc_value, "binary": binary_value }); } @@ -1331,12 +1194,13 @@ fn hint_cleared() { #[test] fn invalid_length() { // This is a regression test for fuzzer-generated input (RUST-1240). - assert!(bson::deserialize_from_slice::(&[4, 0, 0, 128, 0, 87]).is_err()); + assert!(crate::deserialize_from_slice::(&[4, 0, 0, 128, 0, 87]).is_err()); } #[test] fn code_with_scope_too_long() { // This is a regression test for fuzzer-generated input (RUST-2241). - let bytes = base64::decode("KAAAAAsBCRwPAAAACwFAAAAEAA8AEAAAAAYAAAAA9wD5/wAABgALAA==").unwrap(); - assert!(bson::deserialize_from_slice::>(&bytes).is_err()); + let bytes = + crate::base64::decode("KAAAAAsBCRwPAAAACwFAAAAEAA8AEAAAAAYAAAAA9wD5/wAABgALAA==").unwrap(); + assert!(crate::deserialize_from_slice::>(&bytes).is_err()); } diff --git a/src/tests/serde/util.rs b/src/tests/serde/util.rs new file mode 100644 index 00000000..4c587e09 --- /dev/null +++ b/src/tests/serde/util.rs @@ -0,0 +1,152 @@ +use serde::{self, Deserialize, Serialize}; + +use crate::{ + cstr, + doc, + oid::ObjectId, + spec::BinarySubtype, + Binary, + Bson, + DateTime, + Decimal128, + Document, + JavaScriptCodeWithScope, + Regex, + Timestamp, +}; + +#[derive(Debug, Deserialize, Serialize, PartialEq)] +pub(super) struct AllTypes { + pub(super) x: i32, + pub(super) y: i64, + pub(super) s: String, + pub(super) array: Vec, + pub(super) bson: Bson, + pub(super) oid: ObjectId, + pub(super) null: Option<()>, + pub(super) subdoc: Document, + pub(super) b: bool, + pub(super) d: f64, + pub(super) binary: Binary, + pub(super) binary_old: Binary, + pub(super) binary_other: Binary, + pub(super) date: DateTime, + pub(super) regex: Regex, + pub(super) ts: Timestamp, + pub(super) i: SubDoc, + pub(super) undefined: Bson, + pub(super) code: Bson, + pub(super) code_w_scope: JavaScriptCodeWithScope, + pub(super) decimal: Decimal128, + pub(super) symbol: Bson, + pub(super) min_key: Bson, + pub(super) max_key: Bson, +} + +#[derive(Debug, Deserialize, Serialize, PartialEq)] +pub(super) struct SubDoc { + pub(super) a: i32, + pub(super) b: i32, +} + +impl AllTypes { + pub(super) fn fixtures() -> (Self, Document) { + let binary = Binary { + bytes: vec![36, 36, 36], + subtype: BinarySubtype::Generic, + }; + let binary_old = Binary { + bytes: vec![36, 36, 36], + subtype: BinarySubtype::BinaryOld, + }; + let binary_other = Binary { + bytes: vec![36, 36, 36], + subtype: BinarySubtype::UserDefined(0x81), + }; + let date = DateTime::now(); + let regex = Regex { + pattern: cstr!("hello").into(), + options: cstr!("x").into(), + }; + let timestamp = Timestamp { + time: 123, + increment: 456, + }; + let code = Bson::JavaScriptCode("console.log(1)".to_string()); + let code_w_scope = JavaScriptCodeWithScope { + code: "console.log(a)".to_string(), + scope: doc! { "a": 1 }, + }; + let oid = ObjectId::new(); + let subdoc = doc! { "k": true, "b": { "hello": "world" } }; + + let decimal = { + let bytes = hex::decode("18000000136400D0070000000000000000000000003A3000").unwrap(); + let d = Document::from_reader(bytes.as_slice()).unwrap(); + match d.get("d") { + Some(Bson::Decimal128(d)) => *d, + c => panic!("expected decimal128, got {:?}", c), + } + }; + + let doc = doc! { + "x": 1, + "y": 2_i64, + "s": "oke", + "array": [ true, "oke", { "12": 24 } ], + "bson": 1234.5, + "oid": oid, + "null": Bson::Null, + "subdoc": subdoc.clone(), + "b": true, + "d": 12.5, + "binary": binary.clone(), + "binary_old": binary_old.clone(), + "binary_other": binary_other.clone(), + "date": date, + "regex": regex.clone(), + "ts": timestamp, + "i": { "a": 300, "b": 12345 }, + "undefined": Bson::Undefined, + "code": code.clone(), + "code_w_scope": code_w_scope.clone(), + "decimal": Bson::Decimal128(decimal), + "symbol": Bson::Symbol("ok".to_string()), + "min_key": Bson::MinKey, + "max_key": Bson::MaxKey, + }; + + let v = AllTypes { + x: 1, + y: 2, + s: "oke".to_string(), + array: vec![ + Bson::Boolean(true), + Bson::String("oke".to_string()), + Bson::Document(doc! { "12": 24 }), + ], + bson: Bson::Double(1234.5), + oid, + null: None, + subdoc, + b: true, + d: 12.5, + binary, + binary_old, + binary_other, + date, + regex, + ts: timestamp, + i: SubDoc { a: 300, b: 12345 }, + undefined: Bson::Undefined, + code, + code_w_scope, + decimal, + symbol: Bson::Symbol("ok".to_string()), + min_key: Bson::MinKey, + max_key: Bson::MaxKey, + }; + + (v, doc) + } +} diff --git a/src/tests/serde_helpers.rs b/src/tests/serde_helpers.rs index 7e683bbe..3c0d6c95 100644 --- a/src/tests/serde_helpers.rs +++ b/src/tests/serde_helpers.rs @@ -2,7 +2,25 @@ use core::str; use serde::{de::Visitor, Deserialize, Serialize}; -use crate::{deserialize_from_slice, serde_helpers::HumanReadable, Utf8Lossy}; +use crate::{ + deserialize_from_bson, + deserialize_from_document, + deserialize_from_slice, + doc, + oid::ObjectId, + serde_helpers::{self, datetime, object_id, timestamp, u32, u64, HumanReadable}, + serialize_to_bson, + serialize_to_document, + spec::BinarySubtype, + tests::LOCK, + Binary, + Bson, + DateTime, + Timestamp, + Utf8Lossy, +}; + +use serde_with::serde_as; #[test] fn human_readable_wrapper() { @@ -165,3 +183,1722 @@ fn utf8_lossy_wrapper() { assert_eq!(s.s1.0, expected_replacement); assert_eq!(s.s2, expected_replacement); } +#[test] +#[cfg(feature = "serde_with-3")] +fn test_u64_i32_helper() { + let _guard = LOCK.run_concurrently(); + + #[serde_as] + #[derive(Deserialize, Serialize, Debug, PartialEq)] + struct A { + #[serde_as(as = "u64::AsI32")] + value: u64, + + #[serde_as(as = "Option")] + value_optional_none: Option, + + #[serde_as(as = "Option")] + value_optional_some: Option, + + #[serde_as(as = "Vec")] + value_vector: Vec, + } + + let value = 1; + let a = A { + value, + value_optional_none: None, + value_optional_some: Some(value), + value_vector: vec![value], + }; + + // Serialize the struct to BSON + let doc = serialize_to_document(&a).unwrap(); + + // Validate serialized data + assert_eq!( + doc.get_i32("value").unwrap(), + value as i32, + "Expected serialized value to match original." + ); + + assert_eq!( + doc.get("value_optional_none"), + Some(&Bson::Null), + "Expected serialized value_optional_none to be None." + ); + + assert_eq!( + doc.get("value_optional_some"), + Some(&Bson::Int32(value as i32)), + "Expected serialized value_optional_some to match original." + ); + + let value_vector = doc + .get_array("value_vector") + .expect("Expected serialized value_vector to be a BSON array."); + let expected_value_vector: Vec = vec![Bson::Int32(value as i32)]; + assert_eq!( + value_vector, &expected_value_vector, + "Expected each serialized element in value_vector to match the original." + ); + + // Validate deserialized data + let a_deserialized: A = deserialize_from_document(doc).unwrap(); + assert_eq!( + a_deserialized, a, + "Round-trip failed: deserialized struct did not match original." + ); + + // Validate serialization fails because i32::MAX + 1 is too large to fit in i32 + let invalid_value_for_serializing = i32::MAX as u64 + 1; + let bad_a: A = A { + value: invalid_value_for_serializing, + value_optional_none: None, + value_optional_some: Some(invalid_value_for_serializing), + value_vector: vec![invalid_value_for_serializing], + }; + let result = serialize_to_document(&bad_a); + assert!( + result.is_err(), + "Serialization should fail for u64::MAX since it can't be exactly represented as i32" + ); + let err_string = format!("{:?}", result.unwrap_err()); + assert!( + err_string.contains("Cannot convert u64"), + "Expected error message to mention failed u64 to i32 conversion, got: {}", + err_string + ); + + // Validate deserialization fails for i32::MIN because negative values can't be converted to + // u64 + let invalid_value_for_deserializing = i32::MIN; + let bad_a = doc! { + "value": invalid_value_for_deserializing, + "value_optional_none": Bson::Null, + "value_optional_some": Some(invalid_value_for_deserializing), + "value_vector": [invalid_value_for_deserializing], + }; + let result: Result = deserialize_from_document(bad_a); + assert!( + result.is_err(), + "Deserialization should fail for i32::MIN since it can't be exactly represented as u64" + ); + let err_string = format!("{:?}", result.unwrap_err()); + assert!( + err_string.contains("Cannot convert i32"), + "Expected error message to mention failed i32 to u64 conversion, got: {}", + err_string + ); +} +#[test] +fn test_binary_helper_generic_roundtrip() { + let _guard = LOCK.run_concurrently(); + #[derive(Serialize, Deserialize, Debug, PartialEq)] + pub struct Foo { + data: Binary, + } + + let x = Foo { + data: Binary { + subtype: BinarySubtype::Generic, + bytes: b"12345abcde".to_vec(), + }, + }; + + let b = serialize_to_bson(&x).unwrap(); + assert_eq!( + b.as_document().unwrap(), + &doc! {"data": Bson::Binary(Binary { subtype: BinarySubtype::Generic, bytes: b"12345abcde".to_vec() })} + ); + + let f = deserialize_from_bson::(b).unwrap(); + assert_eq!(x, f); +} + +#[test] +fn test_binary_helper_non_generic_roundtrip() { + let _guard = LOCK.run_concurrently(); + #[derive(Serialize, Deserialize, Debug, PartialEq)] + pub struct Foo { + data: Binary, + } + + let x = Foo { + data: Binary { + subtype: BinarySubtype::BinaryOld, + bytes: b"12345abcde".to_vec(), + }, + }; + + let b = serialize_to_bson(&x).unwrap(); + assert_eq!( + b.as_document().unwrap(), + &doc! {"data": Bson::Binary(Binary { subtype: BinarySubtype::BinaryOld, bytes: b"12345abcde".to_vec() })} + ); + + let f = deserialize_from_bson::(b).unwrap(); + assert_eq!(x, f); +} + +#[test] +#[cfg(feature = "serde_with-3")] +fn test_oid_helpers() { + let _guard = LOCK.run_concurrently(); + + #[serde_as] + #[derive(Serialize, Deserialize, Debug, PartialEq)] + struct A { + #[serde_as(as = "object_id::AsHexString")] + oid: ObjectId, + + #[serde_as(as = "Option")] + oid_optional_none: Option, + + #[serde_as(as = "Option")] + oid_optional_some: Option, + + #[serde_as(as = "Vec")] + oid_vector: Vec, + } + + let oid = ObjectId::new(); + let a = A { + oid, + oid_optional_none: None, + oid_optional_some: Some(oid), + oid_vector: vec![oid], + }; + + // Serialize the struct to BSON + let doc = serialize_to_document(&a).unwrap(); + + // Validate serialized data + assert_eq!( + doc.get_str("oid").unwrap(), + oid.to_hex(), + "Expected serialized oid to match original ObjectId as hex string." + ); + + assert_eq!( + doc.get("oid_optional_none"), + Some(&Bson::Null), + "Expected serialized oid_optional_none to be None." + ); + + assert_eq!( + doc.get("oid_optional_some"), + Some(&Bson::String(oid.to_hex())), + "Expected serialized oid_optional_some to match original." + ); + + let oid_vector = doc + .get_array("oid_vector") + .expect("Expected serialized oid_vector to be a BSON array."); + let expected_oid_vector: Vec = vec![Bson::String(oid.to_hex())]; + assert_eq!( + oid_vector, &expected_oid_vector, + "Expected each serialized element in oid_vector match the original." + ); + + // Validate deserialized data + let a_deserialized: A = deserialize_from_document(doc).unwrap(); + assert_eq!( + a_deserialized, a, + "Deserialized struct does not match original." + ); + + // Validate deserializing error case with an invalid ObjectId string + let invalid_doc = doc! { + "oid": "not_a_valid_oid", + "oid_optional_none": Bson::Null, + "oid_optional_some": "also_invalid_oid", + "oid_vector": ["bad1", "bad2"] + }; + let result: Result = deserialize_from_document(invalid_doc); + assert!( + result.is_err(), + "Deserialization should fail for invalid ObjectId strings" + ); + let err_string = format!("{:?}", result.unwrap_err()); + assert!( + err_string.contains("BSON error"), + "Expected error message to mention BSON error: {}", + err_string + ); + + #[serde_as] + #[derive(Serialize, Deserialize, Debug, PartialEq)] + struct B { + #[serde_as(as = "object_id::FromHexString")] + oid: String, + + #[serde_as(as = "Option")] + oid_optional_none: Option, + + #[serde_as(as = "Option")] + oid_optional_some: Option, + + #[serde_as(as = "Vec")] + oid_vector: Vec, + } + + let oid = ObjectId::new(); + let b = B { + oid: oid.to_string(), + oid_optional_none: None, + oid_optional_some: Some(oid.to_string()), + oid_vector: vec![oid.to_string()], + }; + + // Serialize the struct to BSON + let doc = serialize_to_document(&b).unwrap(); + + // Validate serialized data + assert_eq!( + doc.get_object_id("oid").unwrap(), + oid, + "Expected serialized oid to match original ObjectId." + ); + + assert_eq!( + doc.get("oid_optional_none"), + Some(&Bson::Null), + "Expected serialized oid_optional_none to be None." + ); + + assert_eq!( + doc.get("oid_optional_some"), + Some(&Bson::ObjectId(oid)), + "Expected serialized oid_optional_some to match original." + ); + + let oid_vector = doc + .get_array("oid_vector") + .expect("Expected serialized oid_vector to be a BSON array."); + let expected_oid_vector: Vec = vec![Bson::ObjectId(oid)]; + assert_eq!( + oid_vector, &expected_oid_vector, + "Expected each serialized element in oid_vector match the original." + ); + + // Validate deserialized data + let b_deserialized: B = deserialize_from_document(doc).unwrap(); + assert_eq!( + b_deserialized, b, + "Deserialized struct does not match original." + ); + + // Validate serializing error case with an invalid ObjectId string + let invalid_oid = "invalid_oid"; + let bad_b = B { + oid: invalid_oid.to_string(), + oid_optional_none: None, + oid_optional_some: Some(invalid_oid.to_string()), + oid_vector: vec![invalid_oid.to_string()], + }; + let result = serialize_to_document(&bad_b); + assert!( + result.is_err(), + "Serialization should fail for invalid ObjectId strings" + ); + let err_string = format!("{:?}", result.unwrap_err()); + assert!( + err_string.contains("BSON error"), + "Expected error message to mention BSON error: {}", + err_string + ); +} + +#[test] +#[cfg(feature = "serde_with-3")] +fn test_datetime_rfc3339_string_helpers() { + let _guard = LOCK.run_concurrently(); + + #[serde_as] + #[derive(Deserialize, Serialize, Debug, PartialEq)] + struct A { + #[serde_as(as = "datetime::AsRfc3339String")] + pub date: DateTime, + + #[serde_as(as = "Option")] + pub date_optional_none: Option, + + #[serde_as(as = "Option")] + pub date_optional_some: Option, + + #[serde_as(as = "Vec")] + pub date_vector: Vec, + } + + let iso = "1996-12-20T00:39:57Z"; + let date = DateTime::parse_rfc3339_str(iso).unwrap(); + let a = A { + date, + date_optional_none: None, + date_optional_some: Some(date), + date_vector: vec![date], + }; + + // Serialize the struct to BSON + let doc = serialize_to_document(&a).unwrap(); + + // Validate serialized data + assert_eq!( + doc.get_str("date").unwrap(), + iso, + "Expected serialized date to match original date from RFC 3339 string." + ); + + assert_eq!( + doc.get("date_optional_none"), + Some(&Bson::Null), + "Expected serialized date_optional_none to be None." + ); + + assert_eq!( + doc.get("date_optional_some"), + Some(&Bson::String(iso.to_string())), + "Expected serialized date_optional_some to match original." + ); + + let date_vector = doc + .get_array("date_vector") + .expect("Expected serialized date_vector to be a BSON array."); + let expected_date_vector: Vec = vec![Bson::String(date.try_to_rfc3339_string().unwrap())]; + assert_eq!( + date_vector, &expected_date_vector, + "Expected each serialized element in date_vector to match the original." + ); + + // Validate deserialized data + let a_deserialized: A = deserialize_from_document(doc).unwrap(); + assert_eq!( + a_deserialized, a, + "Deserialized struct does not match original." + ); + + // Validate deserializing error case with an invalid DateTime string + let invalid_doc = doc! { + "date": "not_a_valid_date", + "date_optional_none": Bson::Null, + "date_optional_some": "also_invalid_date", + "date_vector": ["bad1", "bad2"] + }; + let result: Result = deserialize_from_document(invalid_doc); + assert!( + result.is_err(), + "Deserialization should fail for invalid DateTime strings" + ); + let err_string = format!("{:?}", result.unwrap_err()); + assert!( + err_string.contains("BSON error"), + "Expected error message to mention BSON error: {}", + err_string + ); + + #[serde_as] + #[derive(Deserialize, Serialize, Debug, PartialEq)] + struct B { + #[serde_as(as = "datetime::FromRfc3339String")] + pub date: String, + + #[serde_as(as = "Option")] + pub date_optional_none: Option, + + #[serde_as(as = "Option")] + pub date_optional_some: Option, + + #[serde_as(as = "Vec")] + pub date_vector: Vec, + } + + let date = DateTime::now(); + let b = B { + date: date.try_to_rfc3339_string().unwrap(), + date_optional_none: None, + date_optional_some: Some(date.try_to_rfc3339_string().unwrap()), + date_vector: vec![date.try_to_rfc3339_string().unwrap()], + }; + + // Serialize the struct to BSON + let doc = serialize_to_document(&b).unwrap(); + + // Validate serialized data + assert_eq!( + *doc.get_datetime("date").unwrap(), + date, + "Expected serialized date to be a BSON DateTime." + ); + + assert_eq!( + doc.get("date_optional_none"), + Some(&Bson::Null), + "Expected serialized date_optional_none to be None." + ); + + assert_eq!( + doc.get("date_optional_some"), + Some(&Bson::DateTime(date)), + "Expected serialized date_optional_some to match original." + ); + + let date_vector = doc + .get_array("date_vector") + .expect("Expected serialized date_vector to be a BSON array."); + let expected_date_vector: Vec = vec![Bson::DateTime(date)]; + assert_eq!( + date_vector, &expected_date_vector, + "Expected each serialized element in date_vector match the original." + ); + + // Validate deserialized data + let b_deserialized: B = deserialize_from_document(doc).unwrap(); + assert_eq!( + b_deserialized, b, + "Deserialized struct does not match original." + ); + + // Validate serializing error case with an invalid DateTime string + let invalid_date = "invalid_date"; + let bad_b = B { + date: invalid_date.to_string(), + date_optional_none: None, + date_optional_some: Some(invalid_date.to_string()), + date_vector: vec![invalid_date.to_string()], + }; + let result = serialize_to_document(&bad_b); + assert!( + result.is_err(), + "Serialization should fail for invalid DateTime strings" + ); + let err_string = format!("{:?}", result.unwrap_err()); + assert!( + err_string.contains("BSON error"), + "Expected error message to mention BSON error: {}", + err_string + ); +} + +#[test] +#[cfg(feature = "serde_with-3")] +fn test_datetime_i64_helper() { + let _guard = LOCK.run_concurrently(); + + #[serde_as] + #[derive(Serialize, Deserialize, Debug, PartialEq)] + struct A { + #[serde_as(as = "datetime::FromI64")] + date: i64, + + #[serde_as(as = "Option")] + date_optional_none: Option, + + #[serde_as(as = "Option")] + date_optional_some: Option, + + #[serde_as(as = "Vec")] + date_vector: Vec, + } + + let date = DateTime::now(); + let a = A { + date: date.timestamp_millis(), + date_optional_none: None, + date_optional_some: Some(date.timestamp_millis()), + date_vector: vec![date.timestamp_millis()], + }; + + // Serialize the struct to BSON + let doc = serialize_to_document(&a).unwrap(); + + // Validate serialized data + assert_eq!( + doc.get_datetime("date").unwrap(), + &date, + "Expected serialized date to match original date." + ); + + assert_eq!( + doc.get("date_optional_none"), + Some(&Bson::Null), + "Expected serialized date_optional_none to be None." + ); + + assert_eq!( + doc.get("date_optional_some"), + Some(&Bson::DateTime(date)), + "Expected serialized date_optional_some to match original." + ); + + let date_vector = doc + .get_array("date_vector") + .expect("Expected serialized date_vector to be a BSON array."); + let expected_date_vector: Vec = vec![Bson::DateTime(date)]; + assert_eq!( + date_vector, &expected_date_vector, + "Expected each serialized element in date_vector match the original." + ); + + // Validate deserialized data + let a_deserialized: A = deserialize_from_document(doc).unwrap(); + assert_eq!( + a_deserialized, a, + "Deserialized struct does not match original." + ); +} + +#[test] +#[cfg(all(feature = "chrono-0_4", feature = "serde_with-3"))] +fn test_datetime_chrono04_datetime_helper() { + let _guard = LOCK.run_concurrently(); + + use std::str::FromStr; + + #[serde_as] + #[derive(Deserialize, Serialize, Debug, PartialEq)] + struct A { + #[serde_as(as = "datetime::FromChrono04DateTime")] + pub date: chrono::DateTime, + + #[serde_as(as = "Option")] + pub date_optional_none: Option>, + + #[serde_as(as = "Option")] + pub date_optional_some: Option>, + + #[serde_as(as = "Vec")] + pub date_vector: Vec>, + } + + let iso = "1996-12-20T00:39:57Z"; + let date: chrono::DateTime = chrono::DateTime::from_str(iso).unwrap(); + let a: A = A { + date, + date_optional_none: None, + date_optional_some: Some(date), + date_vector: vec![date], + }; + + // Serialize the struct to BSON + let doc = serialize_to_document(&a).unwrap(); + + // Validate serialized data + assert_eq!( + doc.get_datetime("date").unwrap().to_chrono(), + date, + "Expected serialized date to match original date." + ); + + assert_eq!( + doc.get("date_optional_none"), + Some(&Bson::Null), + "Expected serialized date_optional_none to be None." + ); + + assert_eq!( + doc.get("date_optional_some"), + Some(&Bson::DateTime(DateTime::from_chrono(date))), + "Expected serialized date_optional_some to match original." + ); + + let date_vector = doc + .get_array("date_vector") + .expect("Expected serialized date_vector to be a BSON array."); + let expected_date_vector: Vec = vec![Bson::DateTime(date.into())]; + assert_eq!( + date_vector, &expected_date_vector, + "Expected each serialized element in date_vector to be a BSON DateTime matching the \ + original." + ); + + // Validate deserialized data + let a_deserialized: A = deserialize_from_document(doc).unwrap(); + assert_eq!( + a_deserialized, a, + "Deserialized struct does not match original." + ); +} + +#[test] +#[cfg(all(feature = "jiff-0_2", feature = "serde_with-3"))] +fn test_datetime_jiff02_timestamp_helper() { + let _guard = LOCK.run_concurrently(); + + use std::str::FromStr; + + #[serde_as] + #[derive(Deserialize, Serialize, Debug, PartialEq)] + struct A { + #[serde_as(as = "datetime::FromJiff02Timestamp")] + pub date: jiff::Timestamp, + + #[serde_as(as = "Option")] + pub date_optional_none: Option, + + #[serde_as(as = "Option")] + pub date_optional_some: Option, + + #[serde_as(as = "Vec")] + pub date_vector: Vec, + } + + let iso = "1996-12-20T00:39:57Z"; + let date: jiff::Timestamp = jiff::Timestamp::from_str(iso).unwrap(); + let a: A = A { + date, + date_optional_none: None, + date_optional_some: Some(date), + date_vector: vec![date], + }; + + // Serialize the struct to BSON + let doc = serialize_to_document(&a).unwrap(); + + // Validate serialized data + assert_eq!( + doc.get_datetime("date").unwrap().to_jiff(), + date, + "Expected serialized date to match original date." + ); + + assert_eq!( + doc.get("date_optional_none"), + Some(&Bson::Null), + "Expected serialized date_optional_none to be None." + ); + + assert_eq!( + doc.get("date_optional_some"), + Some(&Bson::DateTime(DateTime::from_jiff(date))), + "Expected serialized date_optional_some to match original." + ); + + let date_vector = doc + .get_array("date_vector") + .expect("Expected serialized date_vector to be a BSON array."); + let expected_date_vector: Vec = vec![Bson::DateTime(date.into())]; + assert_eq!( + date_vector, &expected_date_vector, + "Expected each serialized element in date_vector to be a BSON DateTime matching the \ + original." + ); + + // Validate deserialized data + let a_deserialized: A = deserialize_from_document(doc).unwrap(); + assert_eq!( + a_deserialized, a, + "Deserialized struct does not match original." + ); +} + +#[test] +#[cfg(all(feature = "time-0_3", feature = "serde_with-3"))] +fn test_datetime_time03_offset_datetime_helper() { + use time::OffsetDateTime; + let _guard = LOCK.run_concurrently(); + + #[serde_as] + #[derive(Deserialize, Serialize, Debug, PartialEq)] + struct A { + #[serde_as(as = "datetime::FromTime03OffsetDateTime")] + pub date: OffsetDateTime, + + #[serde_as(as = "Option")] + pub date_optional_none: Option, + + #[serde_as(as = "Option")] + pub date_optional_some: Option, + + #[serde_as(as = "Vec")] + pub date_vector: Vec, + } + + let date = DateTime::now(); + let a: A = A { + date: date.to_time_0_3(), + date_optional_none: None, + date_optional_some: Some(date.to_time_0_3()), + date_vector: vec![date.to_time_0_3()], + }; + + // Serialize the struct to BSON + let doc = serialize_to_document(&a).unwrap(); + + // Validate serialized data + assert_eq!( + doc.get_datetime("date").unwrap(), + &date, + "Expected serialized date to match original date." + ); + + assert_eq!( + doc.get("date_optional_none"), + Some(&Bson::Null), + "Expected serialized date_optional_none to be None." + ); + + assert_eq!( + doc.get("date_optional_some"), + Some(&Bson::DateTime(date)), + "Expected serialized date_optional_some to match original." + ); + + let date_vector = doc + .get_array("date_vector") + .expect("Expected serialized date_vector to be a BSON array."); + let expected_date_vector: Vec = vec![Bson::DateTime(date)]; + assert_eq!( + date_vector, &expected_date_vector, + "Expected each serialized element in date_vector to be a BSON DateTime matching the \ + original." + ); + + // Validate deserialized data + let a_deserialized: A = deserialize_from_document(doc).unwrap(); + assert_eq!( + a_deserialized, a, + "Deserialized struct does not match original." + ); +} + +#[test] +#[cfg(feature = "serde_with-3")] +fn test_timestamp_u32_helpers() { + let _guard = LOCK.run_concurrently(); + + #[serde_as] + #[derive(Deserialize, Serialize, Debug, PartialEq)] + struct A { + #[serde_as(as = "timestamp::AsU32")] + pub timestamp: Timestamp, + + #[serde_as(as = "Option")] + pub timestamp_optional_none: Option, + + #[serde_as(as = "Option")] + pub timestamp_optional_some: Option, + + #[serde_as(as = "Vec")] + pub timestamp_vector: Vec, + } + + let time = 12345; + let timestamp = Timestamp { time, increment: 0 }; + let a = A { + timestamp, + timestamp_optional_none: None, + timestamp_optional_some: Some(timestamp), + timestamp_vector: vec![timestamp], + }; + + // Serialize the struct to BSON + let doc = serialize_to_document(&a).unwrap(); + + // Validate serialized data + assert_eq!( + doc.get("timestamp").unwrap(), + &Bson::Int64(time as i64), + "Expected serialized time to match the original." + ); + + assert_eq!( + doc.get("timestamp_optional_none"), + Some(&Bson::Null), + "Expected serialized timestamp_optional_none to be None." + ); + + assert_eq!( + doc.get("timestamp_optional_some"), + Some(&Bson::Int64(time as i64)), + "Expected serialized timestamp_optional_some to match original time." + ); + + let timestamp_vector = doc + .get_array("timestamp_vector") + .expect("Expected serialized timestamp_vector to be a BSON array."); + let expected_timestamp_vector: Vec = vec![Bson::Int64(time as i64)]; + assert_eq!( + timestamp_vector, &expected_timestamp_vector, + "Expected each serialized element in timestamp_vector to match the original." + ); + + // Validate deserialized data + let a_deserialized: A = deserialize_from_document(doc).unwrap(); + assert_eq!( + a_deserialized, a, + "Deserialized struct does not match original." + ); + + // Validate serializing error case with an invalid Timestamp + let invalid_timestamp_for_serializing = Timestamp { + time: 0, + increment: 2, + }; + let bad_a: A = A { + timestamp: invalid_timestamp_for_serializing, + timestamp_optional_none: None, + timestamp_optional_some: Some(invalid_timestamp_for_serializing), + timestamp_vector: vec![invalid_timestamp_for_serializing], + }; + let result = serialize_to_document(&bad_a); + assert!( + result.is_err(), + "Serialization should fail for Timestamp with increment != 0" + ); + let err_string = format!("{:?}", result.unwrap_err()); + assert!( + err_string.contains("Cannot convert Timestamp with a non-zero increment to u32"), + "Expected error message to mention non-zero increment: {}", + err_string + ); + + #[serde_as] + #[derive(Deserialize, Serialize, Debug, PartialEq)] + struct B { + #[serde_as(as = "timestamp::FromU32")] + pub time: u32, + + #[serde_as(as = "Option")] + pub time_optional_none: Option, + + #[serde_as(as = "Option")] + pub time_optional_some: Option, + + #[serde_as(as = "Vec")] + pub time_vector: Vec, + } + + let time = 12345; + let b = B { + time, + time_optional_none: None, + time_optional_some: Some(time), + time_vector: vec![time], + }; + + // Serialize the struct to BSON + let doc = serialize_to_document(&b).unwrap(); + + // Validate serialized data + assert_eq!( + doc.get_timestamp("time").unwrap(), + Timestamp { time, increment: 0 }, + "Expected serialized time to match the original." + ); + + assert_eq!( + doc.get("time_optional_none"), + Some(&Bson::Null), + "Expected serialized time_optional_none to be None." + ); + + assert_eq!( + doc.get("time_optional_some"), + Some(&Bson::Timestamp(Timestamp { time, increment: 0 })), + "Expected serialized time_optional_some to match original." + ); + + let time_vector = doc + .get_array("time_vector") + .expect("Expected serialized time_vector to be a BSON array."); + let expected_time_vector: Vec = vec![Bson::Timestamp(Timestamp { time, increment: 0 })]; + assert_eq!( + time_vector, &expected_time_vector, + "Expected each serialized element in time_vector to match the original." + ); + + // Validate deserialized data + let b_deserialized: B = deserialize_from_document(doc).unwrap(); + assert_eq!( + b_deserialized, b, + "Deserialized struct does not match original." + ); + + // Validate deserializing error case with an invalid Timestamp + let invalid_timestamp_for_deserializing = Timestamp { + time: 0, + increment: 2, + }; + let invalid_doc = doc! { + "time": invalid_timestamp_for_deserializing, + "time_optional_none": Bson::Null, + "time_optional_some": Some(invalid_timestamp_for_deserializing), + "time_vector": [invalid_timestamp_for_deserializing] + }; + let result: Result = deserialize_from_document(invalid_doc); + assert!( + result.is_err(), + "Deserialization should fail for Timestamp with increment != 0" + ); + let err_string = format!("{:?}", result.unwrap_err()); + assert!( + err_string.contains("Cannot convert Timestamp with a non-zero increment to u32"), + "Expected error message to mention non-zero increment: {}", + err_string + ); +} + +#[test] +#[cfg(feature = "serde_with-3")] +fn test_u32_f64_helper() { + let _guard = LOCK.run_concurrently(); + + #[serde_as] + #[derive(Deserialize, Serialize, Debug, PartialEq)] + struct A { + #[serde_as(as = "u32::AsF64")] + pub value: u32, + + #[serde_as(as = "Option")] + pub value_optional_none: Option, + + #[serde_as(as = "Option")] + pub value_optional_some: Option, + + #[serde_as(as = "Vec")] + pub value_vector: Vec, + } + + let value = 12345; + let a = A { + value, + value_optional_none: None, + value_optional_some: Some(value), + value_vector: vec![value], + }; + + // Serialize the struct to BSON + let doc = serialize_to_document(&a).unwrap(); + + // Validate serialized data + assert_eq!( + doc.get("value"), + Some(&Bson::Double(value as f64)), + "Expected serialized value to match the original." + ); + + assert_eq!( + doc.get("value_optional_none"), + Some(&Bson::Null), + "Expected serialized value_optional_none to be None." + ); + + assert_eq!( + doc.get("value_optional_some"), + Some(&Bson::Double(value as f64)), + "Expected serialized value_optional_some to match original." + ); + + let value_vector = doc + .get_array("value_vector") + .expect("Expected serialized value_vector to be a BSON array."); + let expected_value_vector: Vec = vec![Bson::Double(value as f64)]; + assert_eq!( + value_vector, &expected_value_vector, + "Expected each serialized element in value_vector to match the original." + ); + + // Validate deserialized data + let a_deserialized: A = deserialize_from_document(doc).unwrap(); + assert_eq!( + a_deserialized, a, + "Deserialized struct does not match original." + ); +} + +#[test] +#[cfg(feature = "serde_with-3")] +fn test_u32_i32_helper() { + let _guard = LOCK.run_concurrently(); + + #[serde_as] + #[derive(Deserialize, Serialize, Debug, PartialEq)] + struct A { + #[serde_as(as = "u32::AsI32")] + value: u32, + + #[serde_as(as = "Option")] + value_optional_none: Option, + + #[serde_as(as = "Option")] + value_optional_some: Option, + + #[serde_as(as = "Vec")] + value_vector: Vec, + } + + let value = 1; + let a = A { + value, + value_optional_none: None, + value_optional_some: Some(value), + value_vector: vec![value], + }; + + // Serialize the struct to BSON + let doc = serialize_to_document(&a).unwrap(); + + // Validate serialized data + assert_eq!( + doc.get_i32("value").unwrap(), + value as i32, + "Expected serialized value to match original." + ); + + assert_eq!( + doc.get("value_optional_none"), + Some(&Bson::Null), + "Expected serialized value_optional_none to be None." + ); + + assert_eq!( + doc.get("value_optional_some"), + Some(&Bson::Int32(value as i32)), + "Expected serialized value_optional_some to match original." + ); + + let value_vector = doc + .get_array("value_vector") + .expect("Expected serialized value_vector to be a BSON array."); + let expected_value_vector: Vec = vec![Bson::Int32(value as i32)]; + assert_eq!( + value_vector, &expected_value_vector, + "Expected each serialized element in value_vector to match the original." + ); + + // Validate deserialized data + let a_deserialized: A = deserialize_from_document(doc).unwrap(); + assert_eq!( + a_deserialized, a, + "Deserialized struct does not match original." + ); + + // Validate serialization fails because u32::MAX is too large to fit in i32 + let invalid_value_for_serializing = u32::MAX; + let bad_a: A = A { + value: invalid_value_for_serializing, + value_optional_none: None, + value_optional_some: Some(invalid_value_for_serializing), + value_vector: vec![invalid_value_for_serializing], + }; + let result = serialize_to_document(&bad_a); + assert!( + result.is_err(), + "Serialization should fail for u32::MAX since it can't be exactly represented as i32" + ); + let err_string = format!("{:?}", result.unwrap_err()); + assert!( + err_string.contains("Cannot convert u32"), + "Expected error message to mention failed u32 to i32 conversion, got: {}", + err_string + ); + + // Validate deserialization fails for i32::MIN because negative values can't be converted to + // u32 + let invalid_value_for_deserializing = i32::MIN; + let bad_a = doc! { + "value": invalid_value_for_deserializing, + "value_optional_none": Bson::Null, + "value_optional_some": Some(invalid_value_for_deserializing), + "value_vector": [invalid_value_for_deserializing], + }; + let result: Result = deserialize_from_document(bad_a); + assert!( + result.is_err(), + "Deserialization should fail for i32::MIN since it can't be exactly represented as u32" + ); + let err_string = format!("{:?}", result.unwrap_err()); + assert!( + err_string.contains("Cannot convert i32"), + "Expected error message to mention failed i32 to u32 conversion, got: {}", + err_string + ); +} + +#[test] +#[cfg(feature = "serde_with-3")] +fn test_u32_i64_helper() { + let _guard = LOCK.run_concurrently(); + + #[serde_as] + #[derive(Deserialize, Serialize, Debug, PartialEq)] + struct A { + #[serde_as(as = "u32::AsI64")] + value: u32, + + #[serde_as(as = "Option")] + value_optional_none: Option, + + #[serde_as(as = "Option")] + value_optional_some: Option, + + #[serde_as(as = "Vec")] + value_vector: Vec, + } + + let value = u32::MAX; + let a = A { + value, + value_optional_none: None, + value_optional_some: Some(value), + value_vector: vec![value], + }; + + // Serialize the struct to BSON + let doc = serialize_to_document(&a).unwrap(); + + // Validate serialized data + assert_eq!( + doc.get_i64("value").unwrap(), + value as i64, + "Expected serialized value to match original." + ); + + assert_eq!( + doc.get("value_optional_none"), + Some(&Bson::Null), + "Expected serialized value_optional_none to be None." + ); + + assert_eq!( + doc.get("value_optional_some"), + Some(&Bson::Int64(value as i64)), + "Expected serialized value_optional_some to match original." + ); + + let value_vector = doc + .get_array("value_vector") + .expect("Expected serialized value_vector to be a BSON array."); + let expected_value_vector: Vec = vec![Bson::Int64(value as i64)]; + assert_eq!( + value_vector, &expected_value_vector, + "Expected each serialized element in value_vector to match the original." + ); + + // Validate deserialized data + let a_deserialized: A = deserialize_from_document(doc).unwrap(); + assert_eq!( + a_deserialized, a, + "Round-trip failed: deserialized struct did not match original." + ); + + // Validate deserialization fails for i64::MIN because negative values can't be converted to + // u32 + let invalid_value_for_deserializing = i64::MIN; + let bad_a = doc! { + "value": invalid_value_for_deserializing, + "value_optional_none": Bson::Null, + "value_optional_some": Some(invalid_value_for_deserializing), + "value_vector": [invalid_value_for_deserializing], + }; + let result: Result = deserialize_from_document(bad_a); + assert!( + result.is_err(), + "Deserialization should fail for i64::MIN since it can't be exactly represented as u32" + ); + let err_string = format!("{:?}", result.unwrap_err()); + assert!( + err_string.contains("Cannot convert i64"), + "Expected error message to mention failed i64 to u32 conversion, got: {}", + err_string + ); +} + +#[test] +#[cfg(feature = "serde_with-3")] +fn test_u64_f64_helper() { + let _guard = LOCK.run_concurrently(); + + #[serde_as] + #[derive(Deserialize, Serialize, Debug, PartialEq)] + struct A { + #[serde_as(as = "u64::AsF64")] + pub value: u64, + + #[serde_as(as = "Option")] + pub value_optional_none: Option, + + #[serde_as(as = "Option")] + pub value_optional_some: Option, + + #[serde_as(as = "Vec")] + pub value_vector: Vec, + } + + let value = 12345; + let a = A { + value, + value_optional_none: None, + value_optional_some: Some(value), + value_vector: vec![value], + }; + + // Serialize the struct to BSON + let doc = serialize_to_document(&a).unwrap(); + + // Validate serialized data + assert_eq!( + doc.get("value"), + Some(&Bson::Double(value as f64)), + "Expected serialized value to match the original." + ); + + assert_eq!( + doc.get("value_optional_none"), + Some(&Bson::Null), + "Expected serialized value_optional_none to be None." + ); + + assert_eq!( + doc.get("value_optional_some"), + Some(&Bson::Double(value as f64)), + "Expected serialized value_optional_some to match original." + ); + + let value_vector = doc + .get_array("value_vector") + .expect("Expected serialized value_vector to be a BSON array."); + let expected_value_vector: Vec = vec![Bson::Double(value as f64)]; + assert_eq!( + value_vector, &expected_value_vector, + "Expected each serialized element in value_vector to match the original." + ); + + // Validate deserialized data + let a_deserialized: A = deserialize_from_document(doc).unwrap(); + assert_eq!( + a_deserialized, a, + "Deserialized struct does not match original." + ); + + // Validate serializing error case with u64 over size limit + let invalid_value_for_serializing = u64::MAX; + let bad_a: A = A { + value: invalid_value_for_serializing, + value_optional_none: None, + value_optional_some: Some(invalid_value_for_serializing), + value_vector: vec![invalid_value_for_serializing], + }; + let result = serialize_to_document(&bad_a); + assert!( + result.is_err(), + "Serialization should fail for u64::MAX since it can't be exactly represented as f64" + ); + let err_string = format!("{:?}", result.unwrap_err()); + assert!( + err_string.contains("Cannot convert u64"), + "Expected error message to mention failed u64 to f64 conversion, got: {}", + err_string + ); +} + +#[test] +#[cfg(feature = "serde_with-3")] +fn test_u64_i64_helper() { + let _guard = LOCK.run_concurrently(); + #[serde_as] + #[derive(Deserialize, Serialize, Debug, PartialEq)] + struct A { + #[serde_as(as = "u64::AsI64")] + value: u64, + + #[serde_as(as = "Option")] + value_optional_none: Option, + + #[serde_as(as = "Option")] + value_optional_some: Option, + + #[serde_as(as = "Vec")] + value_vector: Vec, + } + + let value = i64::MAX as u64; + let a = A { + value, + value_optional_none: None, + value_optional_some: Some(value), + value_vector: vec![value], + }; + + // Serialize the struct to BSON + let doc = serialize_to_document(&a).unwrap(); + + // Validate serialized data + assert_eq!( + doc.get_i64("value").unwrap(), + value as i64, + "Expected serialized value to match original." + ); + + assert_eq!( + doc.get("value_optional_none"), + Some(&Bson::Null), + "Expected serialized value_optional_none to be None." + ); + + assert_eq!( + doc.get("value_optional_some"), + Some(&Bson::Int64(value as i64)), + "Expected serialized value_optional_some to match original." + ); + + let value_vector = doc + .get_array("value_vector") + .expect("Expected serialized value_vector to be a BSON array."); + let expected_value_vector: Vec = vec![Bson::Int64(value as i64)]; + assert_eq!( + value_vector, &expected_value_vector, + "Expected each serialized element in value_vector to match the original." + ); + + // Validate deserialized data + let a_deserialized: A = deserialize_from_document(doc).unwrap(); + assert_eq!( + a_deserialized, a, + "Round-trip failed: deserialized struct did not match original." + ); + + // Validate serialization fails because i64::MAX + 1 is too large to fit in i64 + let invalid_value_for_serializing = i64::MAX as u64 + 1; + let bad_a: A = A { + value: invalid_value_for_serializing, + value_optional_none: None, + value_optional_some: Some(invalid_value_for_serializing), + value_vector: vec![invalid_value_for_serializing], + }; + let result = serialize_to_document(&bad_a); + assert!( + result.is_err(), + "Serialization should fail for (i64::MAX as u64) + 1 since it can't be exactly \ + represented as i64" + ); + let err_string = format!("{:?}", result.unwrap_err()); + assert!( + err_string.contains("Cannot convert u64"), + "Expected error message to mention failed u64 to i64 conversion, got: {}", + err_string + ); + + // Validate deserialization fails for i64::MIN because negative values can't be converted to + // u64 + let invalid_value_for_deserializing = i64::MIN; + let bad_a = doc! { + "value": invalid_value_for_deserializing, + "value_optional_none": Bson::Null, + "value_optional_some": Some(invalid_value_for_deserializing), + "value_vector": [invalid_value_for_deserializing], + }; + let result: Result = deserialize_from_document(bad_a); + assert!( + result.is_err(), + "Deserialization should fail for i64::MIN since it can't be exactly represented as u64" + ); + let err_string = format!("{:?}", result.unwrap_err()); + assert!( + err_string.contains("Cannot convert i64"), + "Expected error message to mention failed i64 to u64 conversion, got: {}", + err_string + ); +} + +#[test] +#[cfg(all(feature = "serde_with-3", feature = "uuid-1"))] +fn test_uuid_1_helpers() { + use crate::uuid::UuidRepresentation; + use serde_helpers::uuid_1; + use uuid::Uuid; + + let _guard = LOCK.run_concurrently(); + + fn assert_binary_match( + actual: &Bson, + uuid: &Uuid, + expected_subtype: BinarySubtype, + uuid_representation: UuidRepresentation, + ) { + match actual { + Bson::Binary(Binary { subtype, bytes }) => { + assert_eq!( + subtype, &expected_subtype, + "Expected subtype {:?}, but got {:?}", + expected_subtype, subtype + ); + let expected_bytes = { + let uuid: crate::Uuid = crate::uuid::Uuid::from(*uuid); + crate::Binary::from_uuid_with_representation(uuid, uuid_representation).bytes + }; + assert_eq!( + bytes, &expected_bytes, + "Serialized binary bytes did not match for representation {:?}", + uuid_representation + ); + } + other => panic!("Expected Bson::Binary, got {:?}", other), + } + } + + #[serde_as] + #[derive(Serialize, Deserialize, Debug, PartialEq)] + struct A { + #[serde_as(as = "uuid_1::AsBinary")] + uuid: Uuid, + + #[serde_as(as = "Option")] + uuid_optional_none: Option, + + #[serde_as(as = "Option")] + uuid_optional_some: Option, + + #[serde_as(as = "Vec")] + uuid_vector: Vec, + } + + let uuid = Uuid::parse_str("936DA01F9ABD4d9d80C702AF85C822A8").unwrap(); + let a: A = A { + uuid, + uuid_optional_none: None, + uuid_optional_some: Some(uuid), + uuid_vector: vec![uuid], + }; + + // Serialize the struct to BSON + let doc = serialize_to_document(&a).unwrap(); + + // Validate serialized data + assert_binary_match( + doc.get("uuid").unwrap(), + &uuid, + BinarySubtype::Uuid, + UuidRepresentation::Standard, + ); + + assert_eq!( + doc.get("uuid_optional_none"), + Some(&Bson::Null), + "Expected serialized uuid_optional_none to be None." + ); + + assert_binary_match( + doc.get("uuid_optional_some").unwrap(), + &uuid, + BinarySubtype::Uuid, + UuidRepresentation::Standard, + ); + + let uuid_vector = doc + .get_array("uuid_vector") + .expect("Expected serialized uuid_vector to be a BSON array."); + assert_eq!(uuid_vector.len(), 1); + assert_binary_match( + &uuid_vector[0], + &uuid, + BinarySubtype::Uuid, + UuidRepresentation::Standard, + ); + + // Validate deserialized data + let a_deserialized: A = deserialize_from_document(doc).unwrap(); + assert_eq!( + a_deserialized, a, + "Deserialized struct does not match original." + ); + + #[serde_as] + #[derive(Serialize, Deserialize, Debug, PartialEq)] + struct B { + #[serde_as(as = "uuid_1::AsCSharpLegacyBinary")] + uuid: Uuid, + + #[serde_as(as = "Option")] + uuid_optional_none: Option, + + #[serde_as(as = "Option")] + uuid_optional_some: Option, + + #[serde_as(as = "Vec")] + uuid_vector: Vec, + } + + let uuid = Uuid::parse_str("936DA01F9ABD4d9d80C702AF85C822A8").unwrap(); + let b: B = B { + uuid, + uuid_optional_none: None, + uuid_optional_some: Some(uuid), + uuid_vector: vec![uuid], + }; + + // Serialize the struct to BSON + let doc = serialize_to_document(&b).unwrap(); + + // Validate serialized data + assert_binary_match( + doc.get("uuid").unwrap(), + &uuid, + BinarySubtype::UuidOld, + UuidRepresentation::CSharpLegacy, + ); + + assert_eq!( + doc.get("uuid_optional_none"), + Some(&Bson::Null), + "Expected serialized uuid_optional_none to be None." + ); + + assert_binary_match( + doc.get("uuid_optional_some").unwrap(), + &uuid, + BinarySubtype::UuidOld, + UuidRepresentation::CSharpLegacy, + ); + + let uuid_vector = doc + .get_array("uuid_vector") + .expect("Expected uuid_vector to be a BSON array"); + assert_eq!(uuid_vector.len(), 1); + assert_binary_match( + &uuid_vector[0], + &uuid, + BinarySubtype::UuidOld, + UuidRepresentation::CSharpLegacy, + ); + + // Validate deserialized data + let b_deserialized: B = deserialize_from_document(doc).unwrap(); + assert_eq!( + b_deserialized, b, + "Deserialized struct does not match original." + ); + + #[serde_as] + #[derive(Serialize, Deserialize, Debug, PartialEq)] + struct C { + #[serde_as(as = "uuid_1::AsJavaLegacyBinary")] + uuid: Uuid, + + #[serde_as(as = "Option")] + uuid_optional_none: Option, + + #[serde_as(as = "Option")] + uuid_optional_some: Option, + + #[serde_as(as = "Vec")] + uuid_vector: Vec, + } + + let uuid = Uuid::parse_str("936DA01F9ABD4d9d80C702AF85C822A8").unwrap(); + let c: C = C { + uuid, + uuid_optional_none: None, + uuid_optional_some: Some(uuid), + uuid_vector: vec![uuid], + }; + + // Serialize the struct to BSON + let doc = serialize_to_document(&c).unwrap(); + + // Validate serialized data + assert_binary_match( + doc.get("uuid").unwrap(), + &uuid, + BinarySubtype::UuidOld, + UuidRepresentation::JavaLegacy, + ); + + assert_eq!( + doc.get("uuid_optional_none"), + Some(&Bson::Null), + "Expected serialized uuid_optional_none to be None." + ); + + assert_binary_match( + doc.get("uuid_optional_some").unwrap(), + &uuid, + BinarySubtype::UuidOld, + UuidRepresentation::JavaLegacy, + ); + + let uuid_vector = doc + .get_array("uuid_vector") + .expect("Expected uuid_vector to be a BSON array"); + assert_eq!(uuid_vector.len(), 1); + assert_binary_match( + &uuid_vector[0], + &uuid, + BinarySubtype::UuidOld, + UuidRepresentation::JavaLegacy, + ); + + // Validate deserialized data + let c_deserialized: C = deserialize_from_document(doc).unwrap(); + assert_eq!( + c_deserialized, c, + "Deserialized struct does not match original." + ); + + #[serde_as] + #[derive(Serialize, Deserialize, Debug, PartialEq)] + struct D { + #[serde_as(as = "uuid_1::AsPythonLegacyBinary")] + uuid: Uuid, + + #[serde_as(as = "Option")] + uuid_optional_none: Option, + + #[serde_as(as = "Option")] + uuid_optional_some: Option, + + #[serde_as(as = "Vec")] + uuid_vector: Vec, + } + + let uuid = Uuid::parse_str("936DA01F9ABD4d9d80C702AF85C822A8").unwrap(); + let d: D = D { + uuid, + uuid_optional_none: None, + uuid_optional_some: Some(uuid), + uuid_vector: vec![uuid], + }; + + // Serialize the struct to BSON + let doc = serialize_to_document(&d).unwrap(); + + // Validate serialized data + assert_binary_match( + doc.get("uuid").unwrap(), + &uuid, + BinarySubtype::UuidOld, + UuidRepresentation::PythonLegacy, + ); + + assert_eq!( + doc.get("uuid_optional_none"), + Some(&Bson::Null), + "Expected serialized uuid_optional_none to be None." + ); + + assert_binary_match( + doc.get("uuid_optional_some").unwrap(), + &uuid, + BinarySubtype::UuidOld, + UuidRepresentation::PythonLegacy, + ); + + let uuid_vector = doc + .get_array("uuid_vector") + .expect("Expected uuid_vector to be a BSON array"); + assert_eq!(uuid_vector.len(), 1); + assert_binary_match( + &uuid_vector[0], + &uuid, + BinarySubtype::UuidOld, + UuidRepresentation::PythonLegacy, + ); + + // Validate deserialized data + let d_deserialized: D = deserialize_from_document(doc).unwrap(); + assert_eq!( + d_deserialized, d, + "Deserialized struct does not match original." + ); +}