Skip to content

Commit 0a02bac

Browse files
Add some core lightweight tests
1 parent 47fcd63 commit 0a02bac

File tree

2 files changed

+342
-1
lines changed

2 files changed

+342
-1
lines changed

src/broadcast/destination.rs

Lines changed: 92 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ use aws_sdk_kinesis::{types::ShardIteratorType, Client as KinesisClient};
77
use bytes::Bytes;
88
use hex::ToHex;
99
use serde::{ser::SerializeSeq, Deserialize, Deserializer, Serialize, Serializer};
10-
use tracing::{info, trace, warn};
10+
use tracing::{info, warn};
1111
use utxorpc::spec::sync::BlockRef;
1212

1313
#[derive(Serialize, Deserialize, Debug)]
@@ -262,3 +262,94 @@ where
262262
.collect()
263263
})
264264
}
265+
266+
#[cfg(test)]
267+
mod tests {
268+
use super::*;
269+
270+
#[test]
271+
fn test_point_to_string() {
272+
let point = BlockRef {
273+
index: 12345,
274+
hash: bytes::Bytes::from(vec![0xde, 0xad, 0xbe, 0xef]),
275+
};
276+
let result = point_to_string(&point);
277+
assert_eq!(result, "12345/deadbeef");
278+
}
279+
280+
#[test]
281+
fn test_string_to_point() {
282+
let input = "12345/deadbeef".to_string();
283+
let result = string_to_point(input).unwrap();
284+
assert_eq!(result.index, 12345);
285+
assert_eq!(result.hash, bytes::Bytes::from(vec![0xde, 0xad, 0xbe, 0xef]));
286+
}
287+
288+
#[test]
289+
fn test_point_roundtrip() {
290+
let original = BlockRef {
291+
index: 98765,
292+
hash: bytes::Bytes::from(vec![
293+
0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef,
294+
]),
295+
};
296+
let serialized = point_to_string(&original);
297+
let deserialized = string_to_point(serialized).unwrap();
298+
assert_eq!(original.index, deserialized.index);
299+
assert_eq!(original.hash, deserialized.hash);
300+
}
301+
302+
#[test]
303+
fn test_string_to_point_invalid_format() {
304+
let result = string_to_point("invalid".to_string());
305+
assert!(result.is_err());
306+
}
307+
308+
#[test]
309+
fn test_string_to_point_invalid_hex() {
310+
let result = string_to_point("12345/notvalidhex".to_string());
311+
assert!(result.is_err());
312+
}
313+
314+
#[test]
315+
fn test_string_to_point_invalid_index() {
316+
let result = string_to_point("notanumber/deadbeef".to_string());
317+
assert!(result.is_err());
318+
}
319+
320+
#[test]
321+
fn test_destination_serde_roundtrip() {
322+
let dest = Destination {
323+
pk: "test-dest".to_string(),
324+
stream_arn: "arn:aws:kinesis:us-east-1:123456789:stream/test".to_string(),
325+
shard_id: "shard-0".to_string(),
326+
filter: None,
327+
sequence_number: Some("12345".to_string()),
328+
last_seen_point: BlockRef {
329+
index: 100,
330+
hash: bytes::Bytes::from(vec![0xaa, 0xbb, 0xcc, 0xdd]),
331+
},
332+
recovery_points: vec![
333+
BlockRef {
334+
index: 90,
335+
hash: bytes::Bytes::from(vec![0x11, 0x22, 0x33, 0x44]),
336+
},
337+
BlockRef {
338+
index: 95,
339+
hash: bytes::Bytes::from(vec![0x55, 0x66, 0x77, 0x88]),
340+
},
341+
],
342+
enabled: true,
343+
skip_repair: false,
344+
};
345+
346+
let json = serde_json::to_string(&dest).unwrap();
347+
let deserialized: Destination = serde_json::from_str(&json).unwrap();
348+
349+
assert_eq!(dest.pk, deserialized.pk);
350+
assert_eq!(dest.last_seen_point.index, deserialized.last_seen_point.index);
351+
assert_eq!(dest.last_seen_point.hash, deserialized.last_seen_point.hash);
352+
assert_eq!(dest.recovery_points.len(), deserialized.recovery_points.len());
353+
assert_eq!(dest.recovery_points[0].index, deserialized.recovery_points[0].index);
354+
}
355+
}

src/broadcast/filter.rs

Lines changed: 250 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,3 +126,253 @@ impl FilterConfig {
126126
}
127127
}
128128
}
129+
130+
#[cfg(test)]
131+
mod tests {
132+
use super::*;
133+
134+
#[test]
135+
fn test_token_filter_policy_match() {
136+
let policy_id = vec![0x01, 0x02, 0x03];
137+
let filter = TokenFilter::Policy { policy: policy_id.clone() };
138+
139+
let assets = vec![
140+
Multiasset {
141+
policy_id: policy_id.clone().into(),
142+
assets: vec![],
143+
redeemer: None,
144+
}
145+
];
146+
147+
assert!(filter.applies(&assets));
148+
}
149+
150+
#[test]
151+
fn test_token_filter_policy_no_match() {
152+
let filter = TokenFilter::Policy { policy: vec![0x01, 0x02, 0x03] };
153+
154+
let assets = vec![
155+
Multiasset {
156+
policy_id: vec![0xff, 0xee, 0xdd].into(),
157+
assets: vec![],
158+
redeemer: None,
159+
}
160+
];
161+
162+
assert!(!filter.applies(&assets));
163+
}
164+
165+
#[test]
166+
fn test_token_filter_asset_id_match() {
167+
let policy_id = vec![0x01, 0x02, 0x03];
168+
let asset_name = vec![0x04, 0x05];
169+
let filter = TokenFilter::AssetId {
170+
policy: policy_id.clone(),
171+
asset_name: asset_name.clone(),
172+
};
173+
174+
let assets = vec![
175+
Multiasset {
176+
policy_id: policy_id.clone().into(),
177+
assets: vec![
178+
utxorpc::spec::cardano::Asset {
179+
name: asset_name.clone().into(),
180+
output_coin: 100,
181+
mint_coin: 0,
182+
}
183+
],
184+
redeemer: None,
185+
}
186+
];
187+
188+
assert!(filter.applies(&assets));
189+
}
190+
191+
#[test]
192+
fn test_token_filter_asset_id_wrong_policy() {
193+
let filter = TokenFilter::AssetId {
194+
policy: vec![0x01, 0x02, 0x03],
195+
asset_name: vec![0x04, 0x05],
196+
};
197+
198+
let assets = vec![
199+
Multiasset {
200+
policy_id: vec![0xff, 0xee, 0xdd].into(),
201+
assets: vec![
202+
utxorpc::spec::cardano::Asset {
203+
name: vec![0x04, 0x05].into(),
204+
output_coin: 100,
205+
mint_coin: 0,
206+
}
207+
],
208+
redeemer: None,
209+
}
210+
];
211+
212+
assert!(!filter.applies(&assets));
213+
}
214+
215+
#[test]
216+
fn test_token_filter_asset_id_wrong_name() {
217+
let policy_id = vec![0x01, 0x02, 0x03];
218+
let filter = TokenFilter::AssetId {
219+
policy: policy_id.clone(),
220+
asset_name: vec![0x04, 0x05],
221+
};
222+
223+
let assets = vec![
224+
Multiasset {
225+
policy_id: policy_id.clone().into(),
226+
assets: vec![
227+
utxorpc::spec::cardano::Asset {
228+
name: vec![0xff, 0xee].into(),
229+
output_coin: 100,
230+
mint_coin: 0,
231+
}
232+
],
233+
redeemer: None,
234+
}
235+
];
236+
237+
assert!(!filter.applies(&assets));
238+
}
239+
240+
#[test]
241+
fn test_token_filter_empty_assets() {
242+
let filter = TokenFilter::Policy { policy: vec![0x01, 0x02, 0x03] };
243+
assert!(!filter.applies(&[]));
244+
}
245+
246+
#[test]
247+
fn test_filter_config_all_match() {
248+
let policy1 = vec![0x01, 0x02, 0x03];
249+
let policy2 = vec![0x04, 0x05, 0x06];
250+
251+
let filter = FilterConfig::All(vec![
252+
Box::new(FilterConfig::Mint(TokenFilter::Policy { policy: policy1.clone() })),
253+
Box::new(FilterConfig::Mint(TokenFilter::Policy { policy: policy2.clone() })),
254+
]);
255+
256+
let tx = Tx {
257+
mint: vec![
258+
Multiasset { policy_id: policy1.into(), assets: vec![], redeemer: None },
259+
Multiasset { policy_id: policy2.into(), assets: vec![], redeemer: None },
260+
],
261+
..Default::default()
262+
};
263+
264+
assert!(filter.applies(&tx));
265+
}
266+
267+
#[test]
268+
fn test_filter_config_all_no_match() {
269+
let policy1 = vec![0x01, 0x02, 0x03];
270+
let policy2 = vec![0x04, 0x05, 0x06];
271+
272+
let filter = FilterConfig::All(vec![
273+
Box::new(FilterConfig::Mint(TokenFilter::Policy { policy: policy1.clone() })),
274+
Box::new(FilterConfig::Mint(TokenFilter::Policy { policy: policy2.clone() })),
275+
]);
276+
277+
// Only has policy1, missing policy2
278+
let tx = Tx {
279+
mint: vec![
280+
Multiasset { policy_id: policy1.into(), assets: vec![], redeemer: None },
281+
],
282+
..Default::default()
283+
};
284+
285+
assert!(!filter.applies(&tx));
286+
}
287+
288+
#[test]
289+
fn test_filter_config_any_match() {
290+
let policy1 = vec![0x01, 0x02, 0x03];
291+
let policy2 = vec![0x04, 0x05, 0x06];
292+
293+
let filter = FilterConfig::Any(vec![
294+
Box::new(FilterConfig::Mint(TokenFilter::Policy { policy: policy1.clone() })),
295+
Box::new(FilterConfig::Mint(TokenFilter::Policy { policy: policy2 })),
296+
]);
297+
298+
// Only has policy1, but that's enough for Any
299+
let tx = Tx {
300+
mint: vec![
301+
Multiasset { policy_id: policy1.into(), assets: vec![], redeemer: None },
302+
],
303+
..Default::default()
304+
};
305+
306+
assert!(filter.applies(&tx));
307+
}
308+
309+
#[test]
310+
fn test_filter_config_any_no_match() {
311+
let filter = FilterConfig::Any(vec![
312+
Box::new(FilterConfig::Mint(TokenFilter::Policy { policy: vec![0x01, 0x02, 0x03] })),
313+
Box::new(FilterConfig::Mint(TokenFilter::Policy { policy: vec![0x04, 0x05, 0x06] })),
314+
]);
315+
316+
// Has neither policy
317+
let tx = Tx {
318+
mint: vec![
319+
Multiasset { policy_id: vec![0xff, 0xee, 0xdd].into(), assets: vec![], redeemer: None },
320+
],
321+
..Default::default()
322+
};
323+
324+
assert!(!filter.applies(&tx));
325+
}
326+
327+
#[test]
328+
fn test_filter_config_mint() {
329+
let policy_id = vec![0xaa, 0xbb, 0xcc];
330+
let filter = FilterConfig::Mint(TokenFilter::Policy { policy: policy_id.clone() });
331+
332+
let tx = Tx {
333+
mint: vec![
334+
Multiasset { policy_id: policy_id.into(), assets: vec![], redeemer: None },
335+
],
336+
..Default::default()
337+
};
338+
339+
assert!(filter.applies(&tx));
340+
}
341+
342+
#[test]
343+
fn test_filter_config_withdraw() {
344+
let credential = vec![0x11, 0x22, 0x33];
345+
let filter = FilterConfig::Withdraw { credential: credential.clone() };
346+
347+
let tx = Tx {
348+
withdrawals: vec![
349+
utxorpc::spec::cardano::Withdrawal {
350+
reward_account: credential.into(),
351+
coin: 1000,
352+
redeemer: None,
353+
}
354+
],
355+
..Default::default()
356+
};
357+
358+
assert!(filter.applies(&tx));
359+
}
360+
361+
#[test]
362+
fn test_filter_config_withdraw_no_match() {
363+
let filter = FilterConfig::Withdraw { credential: vec![0x11, 0x22, 0x33] };
364+
365+
let tx = Tx {
366+
withdrawals: vec![
367+
utxorpc::spec::cardano::Withdrawal {
368+
reward_account: vec![0xff, 0xee, 0xdd].into(),
369+
coin: 1000,
370+
redeemer: None,
371+
}
372+
],
373+
..Default::default()
374+
};
375+
376+
assert!(!filter.applies(&tx));
377+
}
378+
}

0 commit comments

Comments
 (0)