Skip to content

Commit 431f89e

Browse files
committed
add test for enum derive and trait implementation
1 parent 18a26aa commit 431f89e

File tree

5 files changed

+235
-104
lines changed

5 files changed

+235
-104
lines changed

Cargo.toml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,4 +21,5 @@ structdiff-derive = { path = "derive", version = "=0.5.5" }
2121

2222
[dev-dependencies]
2323
bincode = "1.3.3"
24-
assert_unordered = "0.3.5"
24+
assert_unordered = "0.3.5"
25+
nanorand = { version = "0.7.0" }

tests/derives.rs

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
use std::{
2+
collections::{BTreeMap, BTreeSet, HashMap, HashSet},
3+
fmt::Debug,
4+
num::Wrapping,
5+
};
6+
7+
use structdiff::{Difference, StructDiff};
8+
9+
// Trying to come up with all the edge cases that might be relevant
10+
#[allow(dead_code)]
11+
#[cfg(not(any(feature = "serde", feature = "nanoserde")))]
12+
#[derive(Difference)]
13+
pub struct TestDeriveAll<
14+
'a,
15+
'b: 'a,
16+
A: PartialEq + 'static,
17+
const C: usize,
18+
B,
19+
D,
20+
LM: Ord = Option<isize>,
21+
const N: usize = 4,
22+
> where
23+
A: core::hash::Hash + std::cmp::Eq + Default,
24+
LM: Ord + IntoIterator<Item = isize>,
25+
[A; N]: Default,
26+
[B; C]: Default,
27+
[i32; N]: Default,
28+
[B; N]: Default,
29+
dyn Fn(&B): PartialEq + Clone + core::fmt::Debug,
30+
(dyn core::fmt::Debug + Send + 'static): Debug,
31+
{
32+
f1: (),
33+
f2: [A; N],
34+
f3: [i32; N],
35+
f4: BTreeMap<LM, BTreeSet<<LM as IntoIterator>::Item>>,
36+
f5: Option<(A, Option<&'a <LM as IntoIterator>::Item>)>,
37+
f6: HashMap<A, BTreeSet<LM>>,
38+
f7: Box<(Vec<LM>, HashSet<A>, [i128; u8::MIN as usize])>,
39+
f8: BTreeSet<Wrapping<D>>,
40+
#[difference(skip)]
41+
f9: [B; C],
42+
f10: [B; N],
43+
r#f11: Option<&'b Option<usize>>,
44+
#[difference(skip)]
45+
f12: Option<Box<dyn Fn()>>,
46+
#[difference(skip)]
47+
f13: Vec<fn(A, &(dyn core::fmt::Debug + Sync + 'static)) -> !>,
48+
#[difference(skip)]
49+
f14: Vec<Box<dyn FnMut(A, LM) -> Box<dyn Fn(i32) -> i32>>>,
50+
#[difference(skip)]
51+
f15: Vec<fn()>,
52+
}

tests/enums.rs

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
use std::{
2+
collections::{BTreeMap, BTreeSet, HashMap},
3+
fmt::Debug,
4+
num::Wrapping,
5+
};
6+
use structdiff::{Difference, StructDiff};
7+
8+
#[cfg(not(feature = "nanoserde"))]
9+
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
10+
#[derive(Debug, PartialEq, Clone, Difference, Default)]
11+
pub struct Test {
12+
pub test1: i32,
13+
pub test2: String,
14+
pub test3: Vec<i32>,
15+
pub test4: f32,
16+
pub test5: Option<usize>,
17+
}
18+
19+
#[cfg(not(feature = "nanoserde"))]
20+
#[derive(Debug, PartialEq, Clone, Difference)]
21+
pub struct TestSkip<A>
22+
where
23+
A: PartialEq,
24+
{
25+
pub test1: A,
26+
pub test2: String,
27+
#[difference(skip)]
28+
pub test3skip: Vec<i32>,
29+
pub test4: f32,
30+
}
31+
32+
#[allow(unused)]
33+
#[cfg(not(any(feature = "serde", feature = "nanoserde")))]
34+
#[derive(PartialEq, Difference, Clone)]
35+
pub enum TestDeriveAllEnum<
36+
'a,
37+
'b: 'a,
38+
A: PartialEq + 'static,
39+
const C: usize,
40+
B: PartialEq,
41+
D,
42+
LM: Ord = Option<isize>,
43+
const N: usize = 4,
44+
> where
45+
A: core::hash::Hash + std::cmp::Eq + Default,
46+
LM: Ord + IntoIterator<Item = isize>,
47+
[A; N]: Default,
48+
[B; C]: Default,
49+
[i32; N]: Default,
50+
[B; N]: Default,
51+
dyn Fn(&B): PartialEq + Clone + core::fmt::Debug,
52+
(dyn std::cmp::PartialEq<A> + Send + 'static): Debug + Clone + PartialEq,
53+
{
54+
F1(()),
55+
F2([A; N]),
56+
F3([i32; N]),
57+
F4(BTreeMap<LM, BTreeSet<<LM as IntoIterator>::Item>>),
58+
F5(Option<(A, Option<&'a <LM as IntoIterator>::Item>)>),
59+
F6(HashMap<A, BTreeSet<LM>>),
60+
F8(BTreeSet<Wrapping<D>>, BTreeSet<Wrapping<B>>),
61+
F9 {},
62+
F10 { subfield1: u64, subfield2: Test },
63+
r#F11(Option<&'b Option<usize>>),
64+
F12(TestSkip<A>, TestSkip<A>),
65+
F13((TestSkip<A>, TestSkip<B>)),
66+
}

tests/integration.rs

Lines changed: 18 additions & 103 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,10 @@
11
#![allow(unused_imports)]
2+
3+
mod derives;
4+
mod enums;
5+
mod types;
6+
pub use types::{RandValue, Test, TestEnum, TestSkip};
7+
28
#[cfg(not(feature = "nanoserde"))]
39
use std::hash::Hash;
410
use std::{
@@ -51,17 +57,6 @@ fn test_example() {
5157
assert_ne!(diffed, second);
5258
}
5359

54-
#[cfg(not(feature = "nanoserde"))]
55-
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
56-
#[derive(Debug, PartialEq, Clone, Difference, Default)]
57-
pub struct Test {
58-
test1: i32,
59-
test2: String,
60-
test3: Vec<i32>,
61-
test4: f32,
62-
test5: Option<usize>,
63-
}
64-
6560
#[cfg(not(feature = "nanoserde"))]
6661
#[test]
6762
fn test_derive() {
@@ -87,98 +82,6 @@ fn test_derive() {
8782
assert_eq!(diffed, second);
8883
}
8984

90-
// Trying to come up with all the edge cases that might be relevant
91-
#[allow(dead_code)]
92-
#[cfg(not(any(feature = "serde", feature = "nanoserde")))]
93-
#[derive(Difference)]
94-
pub struct TestDeriveAll<
95-
'a,
96-
'b: 'a,
97-
A: PartialEq + 'static,
98-
const C: usize,
99-
B,
100-
D,
101-
LM: Ord = Option<isize>,
102-
const N: usize = 4,
103-
> where
104-
A: core::hash::Hash + std::cmp::Eq + Default,
105-
LM: Ord + IntoIterator<Item = isize>,
106-
[A; N]: Default,
107-
[B; C]: Default,
108-
[i32; N]: Default,
109-
[B; N]: Default,
110-
dyn Fn(&B): PartialEq + Clone + core::fmt::Debug,
111-
(dyn core::fmt::Debug + Send + 'static): Debug,
112-
{
113-
f1: (),
114-
f2: [A; N],
115-
f3: [i32; N],
116-
f4: BTreeMap<LM, BTreeSet<<LM as IntoIterator>::Item>>,
117-
f5: Option<(A, Option<&'a <LM as IntoIterator>::Item>)>,
118-
f6: HashMap<A, BTreeSet<LM>>,
119-
f7: Box<(Vec<LM>, HashSet<A>, [i128; u8::MIN as usize])>,
120-
f8: BTreeSet<Wrapping<D>>,
121-
#[difference(skip)]
122-
f9: [B; C],
123-
f10: [B; N],
124-
r#f11: Option<&'b Option<usize>>,
125-
#[difference(skip)]
126-
f12: Option<Box<dyn Fn()>>,
127-
#[difference(skip)]
128-
f13: Vec<fn(A, &(dyn core::fmt::Debug + Sync + 'static)) -> !>,
129-
#[difference(skip)]
130-
f14: Vec<Box<dyn FnMut(A, LM) -> Box<dyn Fn(i32) -> i32>>>,
131-
#[difference(skip)]
132-
f15: Vec<fn()>,
133-
}
134-
135-
#[cfg(not(any(feature = "serde", feature = "nanoserde")))]
136-
#[derive(PartialEq, Difference, Clone)]
137-
pub enum TestDeriveAllEnum<
138-
'a,
139-
'b: 'a,
140-
A: PartialEq + 'static,
141-
const C: usize,
142-
B,
143-
D,
144-
LM: Ord = Option<isize>,
145-
const N: usize = 4,
146-
> where
147-
A: core::hash::Hash + std::cmp::Eq + Default,
148-
LM: Ord + IntoIterator<Item = isize>,
149-
[A; N]: Default,
150-
[B; C]: Default,
151-
[i32; N]: Default,
152-
[B; N]: Default,
153-
dyn Fn(&B): PartialEq + Clone + core::fmt::Debug,
154-
(dyn std::cmp::PartialEq<A> + Send + 'static): Debug + Clone + PartialEq,
155-
{
156-
F1(()),
157-
F2([A; N]),
158-
F3([i32; N]),
159-
F4(BTreeMap<LM, BTreeSet<<LM as IntoIterator>::Item>>),
160-
F5(Option<(A, Option<&'a <LM as IntoIterator>::Item>)>),
161-
F6(HashMap<A, BTreeSet<LM>>),
162-
F8(BTreeSet<Wrapping<D>>, BTreeSet<Wrapping<B>>),
163-
F9 {},
164-
F10 { subfield1: u64 },
165-
r#F11(Option<&'b Option<usize>>),
166-
F12,
167-
}
168-
169-
#[cfg(not(feature = "nanoserde"))]
170-
#[derive(Debug, PartialEq, Clone, Difference)]
171-
struct TestSkip<A>
172-
where
173-
A: PartialEq,
174-
{
175-
test1: A,
176-
test2: String,
177-
#[difference(skip)]
178-
test3skip: Vec<i32>,
179-
test4: f32,
180-
}
181-
18285
#[cfg(not(feature = "nanoserde"))]
18386
#[test]
18487
fn test_derive_with_skip() {
@@ -352,6 +255,18 @@ fn test_generics_skip() {
352255
assert_eq!(diffed.test5, second.test5);
353256
}
354257

258+
#[test]
259+
fn test_enums() {
260+
let mut follower = TestEnum::next();
261+
let mut leader: TestEnum;
262+
for _ in 0..100 {
263+
leader = TestEnum::next();
264+
let diff = follower.diff(&leader);
265+
follower.apply_mut(diff);
266+
assert_eq!(leader, follower)
267+
}
268+
}
269+
355270
#[cfg(not(feature = "nanoserde"))]
356271
mod derive_inner {
357272
use super::{StructDiff, Test};

tests/types.rs

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
use generators::{fill, rand_string};
2+
use nanorand::{Rng, WyRand};
3+
use structdiff::{Difference, StructDiff};
4+
5+
pub trait RandValue {
6+
fn next() -> Self;
7+
}
8+
9+
#[cfg(not(feature = "nanoserde"))]
10+
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
11+
#[derive(Debug, PartialEq, Clone, Difference, Default)]
12+
pub struct Test {
13+
pub test1: i32,
14+
pub test2: String,
15+
pub test3: Vec<i32>,
16+
pub test4: f32,
17+
pub test5: Option<usize>,
18+
}
19+
20+
#[cfg(not(feature = "nanoserde"))]
21+
#[derive(Debug, PartialEq, Clone, Difference)]
22+
pub struct TestSkip<A>
23+
where
24+
A: PartialEq,
25+
{
26+
pub test1: A,
27+
pub test2: String,
28+
#[difference(skip)]
29+
pub test3skip: Vec<i32>,
30+
pub test4: f32,
31+
}
32+
33+
#[derive(Debug, PartialEq, Clone, Difference, Default)]
34+
pub enum TestEnum {
35+
#[default]
36+
F0,
37+
F1(()),
38+
F2(String),
39+
F3 {
40+
field1: String,
41+
field2: (),
42+
},
43+
F4(Test),
44+
}
45+
46+
impl RandValue for Test {
47+
fn next() -> Self {
48+
let mut rng = WyRand::new();
49+
Test {
50+
test1: rng.generate(),
51+
test2: rand_string(&mut rng),
52+
test3: fill(&mut rng),
53+
test4: f32::from_bits(rng.generate::<u32>()),
54+
test5: match rng.generate::<bool>() {
55+
true => Some(rng.generate()),
56+
false => None,
57+
},
58+
}
59+
}
60+
}
61+
62+
impl RandValue for TestEnum {
63+
fn next() -> Self {
64+
let mut rng = WyRand::new();
65+
match rng.generate_range(0..5) {
66+
0 => Self::F0,
67+
1 => Self::F1(()),
68+
2 => Self::F2(rand_string(&mut rng)),
69+
3 => Self::F3 {
70+
field1: rand_string(&mut rng),
71+
field2: (),
72+
},
73+
_ => Self::F4(Test::next()),
74+
}
75+
}
76+
}
77+
78+
mod generators {
79+
use nanorand::{Rng, WyRand};
80+
81+
pub(super) fn rand_string(rng: &mut WyRand) -> String {
82+
let base = vec![(); rng.generate::<u8>() as usize];
83+
base.into_iter()
84+
.map(|_| rng.generate::<u8>() as u32)
85+
.filter_map(char::from_u32)
86+
.collect::<String>()
87+
}
88+
89+
pub(super) fn fill<V, T>(rng: &mut WyRand) -> T
90+
where
91+
V: nanorand::RandomGen<nanorand::WyRand, 8>,
92+
T: FromIterator<V>,
93+
{
94+
let base = vec![(); rng.generate::<u8>() as usize];
95+
base.into_iter().map(|_| rng.generate::<V>()).collect::<T>()
96+
}
97+
}

0 commit comments

Comments
 (0)