test(proto): add codec property tests #117

Merged
Lochnair merged 1 commits from test/proto-properties into main 2026-08-19 17:48:25 +00:00
4 changed files with 536 additions and 4 deletions
Showing only changes of commit 2634649852 - Show all commits

No files matched your search

Generated
+158 -4
View File
@@ -109,7 +109,16 @@ version = "0.5.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0700ddab506f33b20a03b13996eccd309a48e5ff77d0d95926aa0210fb4e95f1" checksum = "0700ddab506f33b20a03b13996eccd309a48e5ff77d0d95926aa0210fb4e95f1"
dependencies = [ dependencies = [
"bit-vec", "bit-vec 0.6.3",
]
[[package]]
name = "bit-set"
version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "08807e080ed7f9d5433fa9b275196cfc35414f66a0c79d864dc51a0d825231a3"
dependencies = [
"bit-vec 0.8.0",
] ]
[[package]] [[package]]
@@ -118,6 +127,12 @@ version = "0.6.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb" checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb"
[[package]]
name = "bit-vec"
version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5e764a1d40d510daf35e07be9eb06e75770908c27d411ee6c92109c9840eaaf7"
[[package]] [[package]]
name = "bitflags" name = "bitflags"
version = "1.3.2" version = "1.3.2"
@@ -516,10 +531,16 @@ version = "0.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b95f7c0680e4142284cf8b22c14a476e87d61b004a3a0861872b32ef7ead40a2" checksum = "b95f7c0680e4142284cf8b22c14a476e87d61b004a3a0861872b32ef7ead40a2"
dependencies = [ dependencies = [
"bit-set", "bit-set 0.5.3",
"regex", "regex",
] ]
[[package]]
name = "fastrand"
version = "2.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "da7c62ceae207dd37ea5b845da6a0696c799f85e97da1ab5b7910be3c1c80223"
[[package]] [[package]]
name = "filedescriptor" name = "filedescriptor"
version = "0.8.3" version = "0.8.3"
@@ -735,6 +756,7 @@ version = "0.5.0"
dependencies = [ dependencies = [
"hmac", "hmac",
"md-5", "md-5",
"proptest",
"subtle", "subtle",
"thiserror 2.0.20", "thiserror 2.0.20",
] ]
@@ -1161,7 +1183,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3c80231409c20246a13fddb31776fb942c38553c51e871f8cbd687a4cfb5843d" checksum = "3c80231409c20246a13fddb31776fb942c38553c51e871f8cbd687a4cfb5843d"
dependencies = [ dependencies = [
"phf_shared", "phf_shared",
"rand", "rand 0.8.7",
] ]
[[package]] [[package]]
@@ -1204,6 +1226,15 @@ version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391"
[[package]]
name = "ppv-lite86"
version = "0.2.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9"
dependencies = [
"zerocopy",
]
[[package]] [[package]]
name = "proc-macro2" name = "proc-macro2"
version = "1.0.107" version = "1.0.107"
@@ -1213,6 +1244,31 @@ dependencies = [
"unicode-ident", "unicode-ident",
] ]
[[package]]
name = "proptest"
version = "1.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4b45fcc2344c680f5025fe57779faef368840d0bd1f42f216291f0dc4ace4744"
dependencies = [
"bit-set 0.8.0",
"bit-vec 0.8.0",
"bitflags 2.13.1",
"num-traits",
"rand 0.9.5",
"rand_chacha",
"rand_xorshift",
"regex-syntax",
"rusty-fork",
"tempfile",
"unarray",
]
[[package]]
name = "quick-error"
version = "1.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0"
[[package]] [[package]]
name = "quote" name = "quote"
version = "1.0.47" version = "1.0.47"
@@ -1240,7 +1296,27 @@ version = "0.8.7"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "22f6172bdec972074665ed81ed53b71da00bfc44b65a753cfde883ec4c702a1a" checksum = "22f6172bdec972074665ed81ed53b71da00bfc44b65a753cfde883ec4c702a1a"
dependencies = [ dependencies = [
"rand_core", "rand_core 0.6.4",
]
[[package]]
name = "rand"
version = "0.9.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b9ef1d0d795eb7d84685bca4f72f3649f064e6641543d3a8c415898726a57b41"
dependencies = [
"rand_chacha",
"rand_core 0.9.5",
]
[[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 0.9.5",
] ]
[[package]] [[package]]
@@ -1249,6 +1325,24 @@ version = "0.6.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
[[package]]
name = "rand_core"
version = "0.9.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "76afc826de14238e6e8c374ddcc1fa19e374fd8dd986b0d2af0d02377261d83c"
dependencies = [
"getrandom 0.3.4",
]
[[package]]
name = "rand_xorshift"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "513962919efc330f829edb2535844d1b912b0fbe2ca165d613e4e8788bb05a5a"
dependencies = [
"rand_core 0.9.5",
]
[[package]] [[package]]
name = "ratatui" name = "ratatui"
version = "0.30.2" version = "0.30.2"
@@ -1416,6 +1510,18 @@ version = "1.0.23"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cf54715a573b99ac80df0bc206da022bcd442c974952c7b9720069370852e21f" checksum = "cf54715a573b99ac80df0bc206da022bcd442c974952c7b9720069370852e21f"
[[package]]
name = "rusty-fork"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cc6bf79ff24e648f6da1f8d1f011e9cac26491b619e6b9280f2b47f1774e6ee2"
dependencies = [
"fnv",
"quick-error",
"tempfile",
"wait-timeout",
]
[[package]] [[package]]
name = "ryu" name = "ryu"
version = "1.0.23" version = "1.0.23"
@@ -1606,6 +1712,19 @@ dependencies = [
"unicode-ident", "unicode-ident",
] ]
[[package]]
name = "tempfile"
version = "3.27.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "32497e9a4c7b38532efcdebeef879707aa9f794296a4f0244f6f69e9bc8574bd"
dependencies = [
"fastrand",
"getrandom 0.4.3",
"once_cell",
"rustix",
"windows-sys",
]
[[package]] [[package]]
name = "termina" name = "termina"
version = "0.3.3" version = "0.3.3"
@@ -1780,6 +1899,12 @@ version = "0.1.7"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2896d95c02a80c6d6a5d6e953d479f5ddf2dfdb6a244441010e373ac0fb88971" checksum = "2896d95c02a80c6d6a5d6e953d479f5ddf2dfdb6a244441010e373ac0fb88971"
[[package]]
name = "unarray"
version = "0.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "eaea85b334db583fe3274d12b4cd1880032beab409c0d774be044d4480ab9a94"
[[package]] [[package]]
name = "unicode-ident" name = "unicode-ident"
version = "1.0.24" version = "1.0.24"
@@ -1842,6 +1967,15 @@ dependencies = [
"utf8parse", "utf8parse",
] ]
[[package]]
name = "wait-timeout"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "09ac3b126d3914f9849036f826e054cbabdc8519970b8998ddaf3b5bd3c65f11"
dependencies = [
"libc",
]
[[package]] [[package]]
name = "wasi" name = "wasi"
version = "0.11.1+wasi-snapshot-preview1" version = "0.11.1+wasi-snapshot-preview1"
@@ -2016,3 +2150,23 @@ name = "wit-bindgen"
version = "0.57.1" version = "0.57.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1ebf944e87a7c253233ad6766e082e3cd714b5d03812acc24c318f549614536e" checksum = "1ebf944e87a7c253233ad6766e082e3cd714b5d03812acc24c318f549614536e"
[[package]]
name = "zerocopy"
version = "0.8.56"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "556764e583adb45a9f8d413c2a147fa7e8d821e48e12b14fd560b607998b75eb"
dependencies = [
"zerocopy-derive",
]
[[package]]
name = "zerocopy-derive"
version = "0.8.56"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f2ab42fc20575779bd240faa45f94a74256f755c0fa9e89f0ede20d91d0cdfc1"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.119",
]
+3
View File
@@ -16,3 +16,6 @@ hmac = "0.13"
md-5 = "0.11" md-5 = "0.11"
subtle = "2.6.1" subtle = "2.6.1"
thiserror = "2.0.20" thiserror = "2.0.20"
[dev-dependencies]
proptest = "1.11.0"
+336
View File
@@ -764,4 +764,340 @@ mod tests {
let encoded = [99]; let encoded = [99];
assert_eq!(Params::decode(&encoded), Err(ProtoError::TruncatedVarint)); assert_eq!(Params::decode(&encoded), Err(ProtoError::TruncatedVarint));
} }
mod properties {
use super::*;
use proptest::prelude::*;
fn received_stats_strategy() -> impl Strategy<Value = ReceivedStats> {
prop_oneof![
Just(ReceivedStats::None),
Just(ReceivedStats::Count),
Just(ReceivedStats::Window),
Just(ReceivedStats::Both),
]
}
fn stamp_at_strategy() -> impl Strategy<Value = StampAt> {
prop_oneof![
Just(StampAt::None),
Just(StampAt::Send),
Just(StampAt::Receive),
Just(StampAt::Both),
Just(StampAt::Midpoint),
]
}
/// A `Clock` valid for direct construction, including `Unspecified`
/// (wire omission). Never produces an explicit zero on the wire; see
/// `explicit_clock_strategy` for that.
fn clock_strategy() -> impl Strategy<Value = Clock> {
prop_oneof![
Just(Clock::Unspecified),
Just(Clock::Wall),
Just(Clock::Monotonic),
Just(Clock::Both),
]
}
/// A `Clock` value valid to encode *explicitly* on the wire (tag 7).
/// Excludes `Unspecified`/zero, which is only ever reached by omission.
fn explicit_clock_value_strategy() -> impl Strategy<Value = i64> {
1_i64..=3
}
fn server_fill_strategy() -> impl Strategy<Value = Option<ServerFill>> {
prop_oneof![
Just(None),
proptest::collection::vec(proptest::char::any(), 0..=8).prop_map(|chars| Some(
ServerFill {
value: chars.into_iter().collect(),
}
)),
]
}
fn params_strategy() -> impl Strategy<Value = Params> {
(
any::<i64>(),
any::<i64>(),
any::<i64>(),
any::<i64>(),
any::<i64>(),
received_stats_strategy(),
stamp_at_strategy(),
clock_strategy(),
server_fill_strategy(),
)
.prop_map(
|(
protocol_version,
duration_ns,
interval_ns,
length,
dscp,
received_stats,
stamp_at,
clock,
server_fill,
)| Params {
protocol_version,
duration_ns,
interval_ns,
length,
received_stats,
stamp_at,
clock,
dscp,
server_fill,
},
)
}
fn encode_tagged_int(tag: u64, value: i64, out: &mut Vec<u8>) {
varint::encode_uvarint(tag, out);
varint::encode_varint(value, out);
}
fn encode_tagged_server_fill(value: &str, out: &mut Vec<u8>) {
varint::encode_uvarint(9, out);
varint::encode_uvarint(value.len() as u64, out);
out.extend_from_slice(value.as_bytes());
}
proptest! {
#[test]
fn valid_params_round_trip(params in params_strategy()) {
let encoded = params.encode();
let decoded = Params::decode(&encoded).unwrap();
prop_assert_eq!(decoded, params);
}
#[test]
fn encoded_param_presence_matches_omission_rules(params in params_strategy()) {
let encoded = params.encode();
let decoded = Params::decode_with_presence(&encoded).unwrap();
prop_assert_eq!(&decoded.params, &params);
prop_assert_eq!(decoded.presence.protocol_version, params.protocol_version != 0);
prop_assert_eq!(decoded.presence.duration_ns, params.duration_ns != 0);
prop_assert_eq!(decoded.presence.interval_ns, params.interval_ns != 0);
prop_assert_eq!(decoded.presence.length, params.length != 0);
prop_assert_eq!(decoded.presence.dscp, params.dscp != 0);
prop_assert_eq!(
decoded.presence.received_stats,
params.received_stats != ReceivedStats::None
);
prop_assert_eq!(decoded.presence.stamp_at, params.stamp_at != StampAt::None);
prop_assert_eq!(decoded.presence.clock, params.clock != Clock::Unspecified);
prop_assert_eq!(decoded.presence.server_fill, params.server_fill.is_some());
}
#[test]
fn repeated_protocol_version_is_last_wins(first: i64, second: i64) {
let mut encoded = Vec::new();
encode_tagged_int(1, first, &mut encoded);
encode_tagged_int(1, second, &mut encoded);
let decoded = Params::decode_with_presence(&encoded).unwrap();
prop_assert_eq!(decoded.params.protocol_version, second);
prop_assert!(decoded.presence.protocol_version);
}
#[test]
fn repeated_duration_ns_is_last_wins(first: i64, second: i64) {
let mut encoded = Vec::new();
encode_tagged_int(2, first, &mut encoded);
encode_tagged_int(2, second, &mut encoded);
let decoded = Params::decode_with_presence(&encoded).unwrap();
prop_assert_eq!(decoded.params.duration_ns, second);
prop_assert!(decoded.presence.duration_ns);
}
#[test]
fn repeated_interval_ns_is_last_wins(first: i64, second: i64) {
let mut encoded = Vec::new();
encode_tagged_int(3, first, &mut encoded);
encode_tagged_int(3, second, &mut encoded);
let decoded = Params::decode_with_presence(&encoded).unwrap();
prop_assert_eq!(decoded.params.interval_ns, second);
prop_assert!(decoded.presence.interval_ns);
}
#[test]
fn repeated_length_is_last_wins(first: i64, second: i64) {
let mut encoded = Vec::new();
encode_tagged_int(4, first, &mut encoded);
encode_tagged_int(4, second, &mut encoded);
let decoded = Params::decode_with_presence(&encoded).unwrap();
prop_assert_eq!(decoded.params.length, second);
prop_assert!(decoded.presence.length);
}
#[test]
fn repeated_received_stats_is_last_wins(first in 0_i64..=3, second in 0_i64..=3) {
let mut encoded = Vec::new();
encode_tagged_int(5, first, &mut encoded);
encode_tagged_int(5, second, &mut encoded);
let decoded = Params::decode_with_presence(&encoded).unwrap();
prop_assert_eq!(decoded.params.received_stats, ReceivedStats::try_from(second).unwrap());
prop_assert!(decoded.presence.received_stats);
}
#[test]
fn repeated_stamp_at_is_last_wins(first in 0_i64..=4, second in 0_i64..=4) {
let mut encoded = Vec::new();
encode_tagged_int(6, first, &mut encoded);
encode_tagged_int(6, second, &mut encoded);
let decoded = Params::decode_with_presence(&encoded).unwrap();
prop_assert_eq!(decoded.params.stamp_at, StampAt::try_from(second).unwrap());
prop_assert!(decoded.presence.stamp_at);
}
#[test]
fn repeated_clock_is_last_wins(
first in explicit_clock_value_strategy(),
second in explicit_clock_value_strategy(),
) {
let mut encoded = Vec::new();
encode_tagged_int(7, first, &mut encoded);
encode_tagged_int(7, second, &mut encoded);
let decoded = Params::decode_with_presence(&encoded).unwrap();
prop_assert_eq!(decoded.params.clock, Clock::try_from(second).unwrap());
prop_assert!(decoded.presence.clock);
}
#[test]
fn repeated_dscp_is_last_wins(first: i64, second: i64) {
let mut encoded = Vec::new();
encode_tagged_int(8, first, &mut encoded);
encode_tagged_int(8, second, &mut encoded);
let decoded = Params::decode_with_presence(&encoded).unwrap();
prop_assert_eq!(decoded.params.dscp, second);
prop_assert!(decoded.presence.dscp);
}
#[test]
fn repeated_server_fill_is_last_wins(
first in proptest::collection::vec(proptest::char::any(), 0..=8)
.prop_map(|chars| chars.into_iter().collect::<String>()),
second in proptest::collection::vec(proptest::char::any(), 0..=8)
.prop_map(|chars| chars.into_iter().collect::<String>()),
) {
let mut encoded = Vec::new();
encode_tagged_server_fill(&first, &mut encoded);
encode_tagged_server_fill(&second, &mut encoded);
let decoded = Params::decode_with_presence(&encoded).unwrap();
prop_assert_eq!(
decoded.params.server_fill,
Some(ServerFill { value: second })
);
prop_assert!(decoded.presence.server_fill);
}
#[test]
fn unknown_scalar_tag_prefix_does_not_disturb_known_params(
params in params_strategy(),
unknown_tag in 10_u64..=u16::MAX as u64,
unknown_value: u64,
) {
let mut prefixed = Vec::new();
varint::encode_uvarint(unknown_tag, &mut prefixed);
varint::encode_uvarint(unknown_value, &mut prefixed);
prefixed.extend_from_slice(&params.encode());
let decoded = Params::decode(&prefixed).unwrap();
prop_assert_eq!(decoded, params.clone());
let decoded_with_presence = Params::decode_with_presence(&prefixed).unwrap();
let expected_presence = Params::decode_with_presence(&params.encode()).unwrap().presence;
prop_assert_eq!(decoded_with_presence.presence, expected_presence);
}
#[test]
fn unknown_scalar_tag_suffix_does_not_disturb_known_params(
params in params_strategy(),
unknown_tag in 10_u64..=u16::MAX as u64,
unknown_value: u64,
) {
let mut suffixed = params.encode();
varint::encode_uvarint(unknown_tag, &mut suffixed);
varint::encode_uvarint(unknown_value, &mut suffixed);
let decoded = Params::decode(&suffixed).unwrap();
prop_assert_eq!(decoded, params.clone());
let decoded_with_presence = Params::decode_with_presence(&suffixed).unwrap();
let expected_presence = Params::decode_with_presence(&params.encode()).unwrap().presence;
prop_assert_eq!(decoded_with_presence.presence, expected_presence);
}
}
/// Omitted-vs-explicit-zero presence, for the fields where explicit
/// zero is valid on the wire. `Clock` is deliberately excluded: an
/// explicit zero there is rejected outright, not merely "present with
/// the default value" (see `explicit_clock_zero_is_rejected`).
#[test]
fn omitted_vs_explicit_zero_presence_for_zero_valid_fields() {
let scalar_tags = [1_u64, 2, 3, 4, 8];
for tag in scalar_tags {
let omitted = Params::decode_with_presence(&[]).unwrap();
let mut explicit_zero = Vec::new();
encode_tagged_int(tag, 0, &mut explicit_zero);
let explicit = Params::decode_with_presence(&explicit_zero).unwrap();
assert_eq!(omitted.params, explicit.params);
assert_eq!(explicit.params, Params::default());
let (omitted_presence, explicit_presence) = match tag {
1 => (
omitted.presence.protocol_version,
explicit.presence.protocol_version,
),
2 => (omitted.presence.duration_ns, explicit.presence.duration_ns),
3 => (omitted.presence.interval_ns, explicit.presence.interval_ns),
4 => (omitted.presence.length, explicit.presence.length),
8 => (omitted.presence.dscp, explicit.presence.dscp),
_ => unreachable!(),
};
assert!(!omitted_presence);
assert!(explicit_presence);
}
let enum_tags = [5_u64, 6];
for tag in enum_tags {
let omitted = Params::decode_with_presence(&[]).unwrap();
let mut explicit_zero = Vec::new();
encode_tagged_int(tag, 0, &mut explicit_zero);
let explicit = Params::decode_with_presence(&explicit_zero).unwrap();
assert_eq!(omitted.params, explicit.params);
let (omitted_presence, explicit_presence) = match tag {
5 => (
omitted.presence.received_stats,
explicit.presence.received_stats,
),
6 => (omitted.presence.stamp_at, explicit.presence.stamp_at),
_ => unreachable!(),
};
assert!(!omitted_presence);
assert!(explicit_presence);
}
// `Clock` deliberately breaks the pattern above: explicit zero is
// rejected rather than accepted-but-present.
let omitted = Params::decode_with_presence(&[]).unwrap();
assert_eq!(omitted.params.clock, Clock::Unspecified);
assert!(!omitted.presence.clock);
let mut explicit_clock_zero = Vec::new();
encode_tagged_int(7, 0, &mut explicit_clock_zero);
assert_eq!(
Params::decode_with_presence(&explicit_clock_zero),
Err(ProtoError::InvalidEnum {
name: "Clock",
value: 0,
})
);
}
}
} }
+39
View File
@@ -112,4 +112,43 @@ mod tests {
encode_uvarint(24, &mut tag); encode_uvarint(24, &mut tag);
assert_eq!(tag, [0x18]); assert_eq!(tag, [0x18]);
} }
mod properties {
use super::*;
use proptest::prelude::*;
proptest! {
#[test]
fn uvarint_round_trips(value: u64) {
let mut encoded = Vec::new();
encode_uvarint(value, &mut encoded);
prop_assert!(!encoded.is_empty());
prop_assert!(encoded.len() <= 10);
let (decoded, used) = decode_uvarint(&encoded).unwrap();
prop_assert_eq!(decoded, value);
prop_assert_eq!(used, encoded.len());
}
#[test]
fn signed_varint_round_trips(value: i64) {
let mut encoded = Vec::new();
encode_varint(value, &mut encoded);
prop_assert!(!encoded.is_empty());
prop_assert!(encoded.len() <= 10);
let (decoded, used) = decode_varint(&encoded).unwrap();
prop_assert_eq!(decoded, value);
prop_assert_eq!(used, encoded.len());
}
#[test]
fn zigzag_round_trips_from_signed(value: i64) {
prop_assert_eq!(zigzag_decode(zigzag_encode(value)), value);
}
#[test]
fn zigzag_round_trips_from_unsigned(value: u64) {
prop_assert_eq!(zigzag_encode(zigzag_decode(value)), value);
}
}
}
} }