Skip to content

Commit

Permalink
Improve Serde test coverage
Browse files Browse the repository at this point in the history
  • Loading branch information
daxpedda committed Aug 18, 2024
1 parent aa4a735 commit 4adc073
Show file tree
Hide file tree
Showing 5 changed files with 214 additions and 41 deletions.
4 changes: 3 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@ wasm-bindgen = { version = "0.2.70", default-features = false }
opt-level = 1

[dev-dependencies]
serde = { version = "1", features = ["derive"] }
serde_json = "1"
serde_test = "1"
static_assertions = "1"

[target.'cfg(not(target_family = "wasm"))'.dev-dependencies]
Expand All @@ -31,7 +34,6 @@ pollster = { version = "0.3", features = ["macro"] }
[target.'cfg(target_family = "wasm")'.dev-dependencies]
getrandom = { version = "0.2", features = ["js"] }
rand = "0.8"
serde_json = "1"
wasm-bindgen-futures = "0.4"
wasm-bindgen-test = "0.3"
web-sys = { version = "0.3", features = [
Expand Down
247 changes: 207 additions & 40 deletions tests/serde.rs
Original file line number Diff line number Diff line change
@@ -1,50 +1,217 @@
#![cfg(test)]
#![cfg(target_family = "wasm")]

mod util;

use std::time::{Duration, SystemTime as StdSystemTime};

use wasm_bindgen_test::wasm_bindgen_test;
use serde_test::Token;
use web_time::SystemTime;

wasm_bindgen_test::wasm_bindgen_test_configure!(run_in_browser);
test! {
/// De/Serialization of [`SystemTime`].
async fn system_time_json() {
let time = SystemTime::now();
let serialized = serde_json::to_string(&time).unwrap();
let deserialized: SystemTime = serde_json::from_str(&serialized).unwrap();
assert_eq!(time, deserialized);
}

/// De/Serialization of [`SystemTime`].
#[wasm_bindgen_test]
fn system_time() {
let time = SystemTime::now();
let serialized = serde_json::to_string(&time).unwrap();
let deserialized: SystemTime = serde_json::from_str(&serialized).unwrap();
assert_eq!(time, deserialized);
}
/// De/Serialization of [`SystemTime`] with
/// [`UNIX_EPOCH`](SystemTime::UNIX_EPOCH).
async fn unix_epoch_json() {
let time = SystemTime::UNIX_EPOCH;
let serialized = serde_json::to_string(&time).unwrap();
let deserialized: SystemTime = serde_json::from_str(&serialized).unwrap();
assert_eq!(time, deserialized);
}

/// De/Serialization of [`SystemTime`] with
/// [`UNIX_EPOCH`](SystemTime::UNIX_EPOCH).
#[wasm_bindgen_test]
fn unix_epoch() {
let time = SystemTime::UNIX_EPOCH;
let serialized = serde_json::to_string(&time).unwrap();
let deserialized: SystemTime = serde_json::from_str(&serialized).unwrap();
assert_eq!(time, deserialized);
}
/// De/Serialization compatibility with [`std::time::SystemTime`].
async fn std_compatibility_json() {
let time = SystemTime::now();
let serialized = serde_json::to_string(&time).unwrap();
let deserialized: StdSystemTime = serde_json::from_str(&serialized).unwrap();
assert_eq!(
time.duration_since(SystemTime::UNIX_EPOCH).unwrap(),
deserialized
.duration_since(StdSystemTime::UNIX_EPOCH)
.unwrap()
);

let time = StdSystemTime::UNIX_EPOCH + Duration::from_secs(1_000_000);
let serialized = serde_json::to_string(&time).unwrap();
let deserialized: SystemTime = serde_json::from_str(&serialized).unwrap();
assert_eq!(
time.duration_since(StdSystemTime::UNIX_EPOCH).unwrap(),
deserialized.duration_since(SystemTime::UNIX_EPOCH).unwrap()
);
}

/// Deserialization from a sequence.
async fn sequence() {
serde_test::assert_de_tokens::<SystemTime>(
&SystemTime::UNIX_EPOCH,
&[
Token::Seq { len: Some(2) },
Token::U64(0),
Token::U32(0),
Token::SeqEnd
],
);
}

/// Deserialization from a map.
async fn map() {
serde_test::assert_de_tokens::<SystemTime>(
&SystemTime::UNIX_EPOCH,
&[
Token::Map { len: Some(2) },
Token::Str("secs_since_epoch"),
Token::U64(0),
Token::Str("nanos_since_epoch"),
Token::U32(0),
Token::MapEnd
],
);

serde_test::assert_de_tokens::<SystemTime>(
&SystemTime::UNIX_EPOCH,
&[
Token::Map { len: Some(2) },
Token::Bytes(b"secs_since_epoch"),
Token::U64(0),
Token::Bytes(b"nanos_since_epoch"),
Token::U32(0),
Token::MapEnd
],
);
}

/// Deserialization failures from a sequence.
async fn failure_sequence() {
serde_test::assert_de_tokens_error::<SystemTime>(
&[
Token::Seq { len: Some(0) },
Token::SeqEnd
],
"invalid length 0, expected struct SystemTime",
);

serde_test::assert_de_tokens_error::<SystemTime>(
&[
Token::Seq { len: Some(1) },
Token::U64(0),
Token::SeqEnd
],
"invalid length 1, expected struct SystemTime",
);

serde_test::assert_de_tokens_error::<SystemTime>(
&[
Token::Seq { len: Some(2) },
Token::U64(u64::MAX),
Token::U32(u32::MAX),
Token::SeqEnd
],
"overflow deserializing SystemTime epoch offset",
);
}

/// Deserialization failures from a map.
async fn failure_map() {
serde_test::assert_de_tokens_error::<SystemTime>(
&[
Token::Map { len: Some(1) },
Token::Unit,
],
"invalid type: unit value, expected `secs_since_epoch` or `nanos_since_epoch`",
);

serde_test::assert_de_tokens_error::<SystemTime>(
&[
Token::Map { len: Some(1) },
Token::Str("test"),
],
"unknown field `test`, expected `secs_since_epoch` or `nanos_since_epoch`",
);

serde_test::assert_de_tokens_error::<SystemTime>(
&[
Token::Map { len: Some(1) },
Token::Bytes(b"test"),
],
"unknown field `test`, expected `secs_since_epoch` or `nanos_since_epoch`",
);

serde_test::assert_de_tokens_error::<SystemTime>(
&[
Token::Map { len: Some(2) },
Token::Str("secs_since_epoch"),
Token::U64(0),
Token::Str("secs_since_epoch"),
],
"duplicate field `secs_since_epoch`",
);

serde_test::assert_de_tokens_error::<SystemTime>(
&[
Token::Map { len: Some(2) },
Token::Str("nanos_since_epoch"),
Token::U64(0),
Token::Str("nanos_since_epoch"),
],
"duplicate field `nanos_since_epoch`",
);

serde_test::assert_de_tokens_error::<SystemTime>(
&[
Token::Map { len: Some(1) },
Token::Str("nanos_since_epoch"),
Token::U64(0),
Token::MapEnd,
],
"missing field `secs_since_epoch`",
);

serde_test::assert_de_tokens_error::<SystemTime>(
&[
Token::Map { len: Some(1) },
Token::Str("secs_since_epoch"),
Token::U64(0),
Token::MapEnd,
],
"missing field `nanos_since_epoch`",
);

serde_test::assert_de_tokens_error::<SystemTime>(
&[
Token::Map { len: Some(1) },
Token::Str("secs_since_epoch"),
Token::Unit,
Token::MapEnd,
],
"invalid type: unit value, expected u64",
);

serde_test::assert_de_tokens_error::<SystemTime>(
&[
Token::Map { len: Some(1) },
Token::Str("nanos_since_epoch"),
Token::Unit,
Token::MapEnd,
],
"invalid type: unit value, expected u32",
);

#[wasm_bindgen_test]
/// De/Serialization compatibility with [`std::time::SystemTime`].
fn std_compatibility() {
let time = SystemTime::now();
let serialized = serde_json::to_string(&time).unwrap();
let deserialized: StdSystemTime = serde_json::from_str(&serialized).unwrap();
assert_eq!(
time.duration_since(SystemTime::UNIX_EPOCH).unwrap(),
deserialized
.duration_since(StdSystemTime::UNIX_EPOCH)
.unwrap()
);

let time = StdSystemTime::UNIX_EPOCH + Duration::from_secs(1_000_000);
let serialized = serde_json::to_string(&time).unwrap();
let deserialized: SystemTime = serde_json::from_str(&serialized).unwrap();
assert_eq!(
time.duration_since(StdSystemTime::UNIX_EPOCH).unwrap(),
deserialized.duration_since(SystemTime::UNIX_EPOCH).unwrap()
);
serde_test::assert_de_tokens_error::<SystemTime>(
&[
Token::Map { len: Some(2) },
Token::Str("secs_since_epoch"),
Token::U64(u64::MAX),
Token::Str("nanos_since_epoch"),
Token::U32(u32::MAX),
Token::MapEnd
],
"overflow deserializing SystemTime epoch offset",
);
}
}
2 changes: 2 additions & 0 deletions tests/util/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,10 @@ mod web;
use web_time::Duration;

#[cfg(not(target_family = "wasm"))]
#[allow(unused)]
pub(crate) use self::std::*;
#[cfg(target_family = "wasm")]
#[allow(unused)]
pub(crate) use self::web::*;

pub(crate) const DIFF: Duration = Duration::from_millis(50);
Expand Down
1 change: 1 addition & 0 deletions tests/util/std.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ use std::thread;
use web_time::Duration;

/// Sleeps for the given [`Duration`].
#[allow(unused)]
pub(crate) fn sleep(duration: Duration) -> Ready<()> {
thread::sleep(duration);
future::ready(())
Expand Down
1 change: 1 addition & 0 deletions tests/util/web.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ impl Future for Sleep {
}

/// Sleeps for the given [`Duration`].
#[allow(unused)]
pub(crate) fn sleep(duration: Duration) -> Sleep {
#[cfg(target_feature = "atomics")]
enum Global {
Expand Down

0 comments on commit 4adc073

Please sign in to comment.