Skip to content

Commit 04349c1

Browse files
kimkulakowski
authored andcommitted
lib: Provide Arbitrary impls for Hash and DataKey
Allows to remove custom strategies for the commit log types (in core), and may become useful for future property testing efforts.
1 parent 8e484e1 commit 04349c1

File tree

7 files changed

+29
-28
lines changed

7 files changed

+29
-28
lines changed

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crates/core/Cargo.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,8 @@ odb_sled = []
9999
default = ["odb_sled"]
100100

101101
[dev-dependencies]
102+
spacetimedb-lib = { path = "../lib", features = ["proptest"] }
103+
102104
rusqlite.workspace = true
103105
criterion.workspace = true
104106
proptest.workspace = true

crates/core/src/db/messages/commit.rs

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@ use proptest_derive::Arbitrary;
2222
pub struct Commit {
2323
/// The [`Hash`] over the encoded bytes of the previous commit, or `None` if
2424
/// it is the very first commit.
25-
#[cfg_attr(test, proptest(strategy = "arbitrary::parent_commit_hash()"))]
2625
pub parent_commit_hash: Option<Hash>,
2726
/// Counter of all commits in a log.
2827
pub commit_offset: u64,
@@ -39,13 +38,6 @@ pub struct Commit {
3938
#[cfg(test)]
4039
mod arbitrary {
4140
use super::*;
42-
43-
// [`Hash`] is defined in `lib`, so we can't have an [`Arbitrary`] impl for
44-
// it just yet due to orphan rules.
45-
pub fn parent_commit_hash() -> impl Strategy<Value = Option<Hash>> {
46-
any::<Option<[u8; 32]>>().prop_map(|maybe_hash| maybe_hash.map(|data| Hash { data }))
47-
}
48-
4941
// Custom strategy to apply an upper bound on the number of [`Transaction`]s
5042
// generated.
5143
//

crates/core/src/db/messages/write.rs

Lines changed: 0 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,6 @@ use anyhow::Context as _;
44
pub use spacetimedb_lib::DataKey;
55
use spacetimedb_sats::buffer::{BufReader, BufWriter, DecodeError};
66

7-
#[cfg(test)]
8-
use proptest::prelude::*;
97
#[cfg(test)]
108
use proptest_derive::Arbitrary;
119

@@ -21,27 +19,9 @@ use proptest_derive::Arbitrary;
2119
pub struct Write {
2220
pub operation: Operation,
2321
pub set_id: u32, // aka table id
24-
#[cfg_attr(test, proptest(strategy = "arbitrary::datakey()"))]
2522
pub data_key: DataKey,
2623
}
2724

28-
#[cfg(test)]
29-
mod arbitrary {
30-
use super::*;
31-
32-
// [`DataKey`] is defined in `lib`, so we can't have an [`Arbitrary`] impl
33-
// for it just yet due to orphan rules.
34-
pub fn datakey() -> impl Strategy<Value = DataKey> {
35-
// Create [`DataKey::Inline`] and [`DataKey::Hash`] with the same
36-
// probability. [`DataKey::from_data`] will take care of choosing the
37-
// variant based in the input length.
38-
prop_oneof![
39-
prop::collection::vec(any::<u8>(), 0..31).prop_map(DataKey::from_data),
40-
prop::collection::vec(any::<u8>(), 31..255).prop_map(DataKey::from_data)
41-
]
42-
}
43-
}
44-
4525
/// The operation of a [`Write`], either insert or delete.
4626
///
4727
/// Encoded as a single byte with bits:

crates/lib/Cargo.toml

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ required-features = ["serde"]
1717
default = ["serde"]
1818
serde = ["dep:serde", "spacetimedb-sats/serde", "dep:serde_with", "chrono/serde"]
1919
cli = ["clap"]
20+
# Allows using `Arbitrary` impls defined in this crate.
21+
proptest = ["dep:proptest", "dep:proptest-derive"]
2022

2123
[dependencies]
2224
spacetimedb-bindings-macro = { path = "../bindings-macro", version = "0.7.2" }
@@ -37,9 +39,16 @@ sha3.workspace = true
3739
thiserror.workspace = true
3840
tracing.workspace = true
3941

42+
# For the 'proptest' feature.
43+
proptest = { workspace = true, optional = true }
44+
proptest-derive = { workspace = true, optional = true }
45+
4046
[dev-dependencies]
4147
rand.workspace = true
4248
bytes.workspace = true
4349
serde_json.workspace = true
4450
insta.workspace = true
51+
52+
# Also as dev-dependencies for use in _this_ crate's tests.
4553
proptest.workspace = true
54+
proptest-derive.workspace = true

crates/lib/src/data_key.rs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,13 @@ use std::ops::Deref;
44
use crate::buffer::{BufReader, BufWriter, DecodeError};
55
use crate::hash::hash_bytes;
66

7+
#[cfg(any(test, feature = "proptest"))]
8+
use proptest::prelude::*;
9+
#[cfg(any(test, feature = "proptest"))]
10+
use proptest_derive::Arbitrary;
11+
712
#[derive(Debug, Copy, Clone, PartialEq, Ord, PartialOrd, Eq, Hash)]
13+
#[cfg_attr(any(test, feature = "proptest"), derive(Arbitrary))]
814
pub enum DataKey {
915
Data(InlineData),
1016
Hash(super::Hash),
@@ -78,6 +84,16 @@ impl fmt::Debug for InlineData {
7884
}
7985
}
8086

87+
#[cfg(any(test, feature = "proptest"))]
88+
impl Arbitrary for InlineData {
89+
type Parameters = ();
90+
type Strategy = prop::strategy::Map<prop::collection::VecStrategy<prop::num::u8::Any>, fn(Vec<u8>) -> InlineData>;
91+
92+
fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy {
93+
prop::collection::vec(any::<u8>(), 0..MAX_INLINE).prop_map(|bytes| InlineData::from_bytes(&bytes).unwrap())
94+
}
95+
}
96+
8197
const IS_HASH_BIT: u8 = 0b1000_0000;
8298

8399
// <flags(1)><value(0-32)>

crates/lib/src/hash.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ use crate::hex::HexString;
77
pub const HASH_SIZE: usize = 32;
88

99
#[derive(Eq, PartialEq, PartialOrd, Ord, Clone, Copy, Hash)]
10+
#[cfg_attr(any(test, feature = "proptest"), derive(proptest_derive::Arbitrary))]
1011
pub struct Hash {
1112
pub data: [u8; HASH_SIZE],
1213
}

0 commit comments

Comments
 (0)