Skip to content

Commit 7d2ac0d

Browse files
committed
improve tests
1 parent b5c4901 commit 7d2ac0d

10 files changed

Lines changed: 318 additions & 382 deletions

File tree

darn_core/src/darn.rs

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1527,15 +1527,25 @@ pub enum SyncError {
15271527
#[cfg(test)]
15281528
mod tests {
15291529
use super::*;
1530+
use std::sync::Once;
1531+
1532+
/// Ensure a global signer exists before any workspace test runs.
1533+
///
1534+
/// In CI there is no `~/.config/darn/signer/` so `Darn::init` would
1535+
/// fail with `InvalidKeyLength`. This one-time setup generates a
1536+
/// signer if none exists. It's idempotent and thread-safe.
1537+
static ENSURE_SIGNER: Once = Once::new();
15301538

15311539
fn with_temp_home<F, R>(f: F) -> R
15321540
where
15331541
F: FnOnce(&Path) -> R,
15341542
{
1543+
ENSURE_SIGNER.call_once(|| {
1544+
let signer_dir = config::global_signer_dir().expect("resolve signer dir");
1545+
crate::signer::load_or_generate(&signer_dir).expect("ensure signer exists");
1546+
});
1547+
15351548
let dir = tempfile::tempdir().expect("create tempdir");
1536-
// Note: We can't easily override HOME in tests, so these tests
1537-
// will use the real global signer. Integration tests would be
1538-
// better for testing with isolated HOME.
15391549
f(dir.path())
15401550
}
15411551

darn_core/src/directory.rs

Lines changed: 54 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -523,11 +523,13 @@ pub enum DeserializeError {
523523
InvalidSchema(String),
524524
}
525525

526+
#[allow(clippy::panic)]
526527
#[allow(clippy::panic)]
527528
#[cfg(test)]
528529
mod tests {
529530
use super::*;
530531

532+
use bolero::check;
531533
use testresult::TestResult;
532534

533535
/// Generate a random 16-byte ID (zero-padded to 32) matching our convention
@@ -612,64 +614,68 @@ mod tests {
612614
assert!(removed.is_none());
613615
}
614616

617+
#[allow(clippy::expect_used)]
615618
#[test]
616-
fn automerge_roundtrip_empty() -> TestResult {
617-
let dir = Directory::new("empty");
618-
619-
let am = dir.to_automerge()?;
620-
let loaded = Directory::from_automerge(&am)?;
621-
622-
assert_eq!(loaded.name, "empty");
623-
assert!(loaded.is_empty());
624-
Ok(())
625-
}
626-
627-
#[test]
628-
fn automerge_roundtrip_with_entries() -> TestResult {
629-
let mut dir = Directory::root();
630-
let file_id = random_id()?;
631-
let folder_id = random_id()?;
632-
633-
dir.add_file("README.md", file_id);
634-
dir.add_folder("src", folder_id);
635-
636-
let am = dir.to_automerge()?;
637-
let loaded = Directory::from_automerge(&am)?;
619+
fn directory_automerge_roundtrip() {
620+
check!()
621+
.with_type::<(String, Vec<(String, bool, [u8; 16])>)>()
622+
.for_each(|(name, entries)| {
623+
let mut dir = Directory::new(name);
624+
for (entry_name, is_folder, id_bytes) in entries {
625+
// Pad 16 bytes to 32 (our automerge-repo convention)
626+
let mut full = [0u8; 32];
627+
full[..16].copy_from_slice(id_bytes);
628+
let id = SedimentreeId::new(full);
629+
630+
if *is_folder {
631+
dir.add_folder(entry_name, id);
632+
} else {
633+
dir.add_file(entry_name, id);
634+
}
635+
}
638636

639-
assert_eq!(loaded.name, "");
640-
assert_eq!(loaded.len(), 2);
637+
let am = dir.to_automerge().expect("to_automerge");
638+
let loaded = Directory::from_automerge(&am).expect("from_automerge");
641639

642-
let readme = loaded.get("README.md").ok_or("README.md not found")?;
643-
assert_eq!(readme.entry_type, EntryType::File);
644-
assert_eq!(readme.sedimentree_id, file_id);
640+
assert_eq!(loaded.name, dir.name);
641+
assert_eq!(loaded.len(), dir.len());
645642

646-
let src = loaded.get("src").ok_or("src not found")?;
647-
assert_eq!(src.entry_type, EntryType::Folder);
648-
assert_eq!(src.sedimentree_id, folder_id);
649-
Ok(())
643+
for entry in &dir.entries {
644+
let found = loaded.get(&entry.name).expect("entry should exist");
645+
assert_eq!(found.entry_type, entry.entry_type);
646+
assert_eq!(found.sedimentree_id, entry.sedimentree_id);
647+
}
648+
});
650649
}
651650

651+
#[allow(clippy::expect_used)]
652652
#[test]
653-
fn bs58check_roundtrip() -> TestResult {
654-
let mut payload = [0u8; 16];
655-
getrandom::getrandom(&mut payload)?;
656-
657-
let encoded = bs58check_encode(&payload);
658-
let decoded = bs58check_decode(&encoded)?;
659-
assert_eq!(decoded, payload);
660-
Ok(())
653+
fn bs58check_roundtrip() {
654+
check!()
655+
.with_type::<[u8; 16]>()
656+
.for_each(|payload: &[u8; 16]| {
657+
let encoded = bs58check_encode(payload);
658+
let decoded = bs58check_decode(&encoded).expect("decode");
659+
assert_eq!(&decoded, payload);
660+
});
661661
}
662662

663+
#[allow(clippy::expect_used)]
663664
#[test]
664-
fn sedimentree_url_roundtrip() -> TestResult {
665-
let id = random_id()?;
666-
let url = sedimentree_id_to_url(id);
667-
668-
assert!(url.starts_with("automerge:"));
669-
670-
let recovered = url_to_sedimentree_id(&url)?;
671-
assert_eq!(recovered, id);
672-
Ok(())
665+
fn sedimentree_url_roundtrip() {
666+
check!()
667+
.with_type::<[u8; 16]>()
668+
.for_each(|id_bytes: &[u8; 16]| {
669+
let mut full = [0u8; 32];
670+
full[..16].copy_from_slice(id_bytes);
671+
let id = SedimentreeId::new(full);
672+
673+
let url = sedimentree_id_to_url(id);
674+
assert!(url.starts_with("automerge:"));
675+
676+
let recovered = url_to_sedimentree_id(&url).expect("parse url");
677+
assert_eq!(recovered, id);
678+
});
673679
}
674680

675681
#[test]

darn_core/src/discover.rs

Lines changed: 19 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -518,34 +518,29 @@ where
518518
(final_results, final_errors, cancel.is_cancelled())
519519
}
520520

521-
#[allow(clippy::expect_used, clippy::unwrap_used, clippy::panic)]
521+
#[allow(clippy::panic)]
522522
#[cfg(test)]
523523
mod tests {
524524
use super::*;
525+
use bolero::check;
525526

526527
#[test]
527-
fn sharded_cache_insert_and_get() {
528-
let cache = ShardedDirCache::new();
529-
let path = PathBuf::from("src/foo/bar");
530-
let id = SedimentreeId::new([42; 32]);
531-
532-
assert!(cache.get(&path).is_none());
533-
534-
cache.insert(path.clone(), id);
535-
536-
assert_eq!(cache.get(&path), Some(id));
537-
}
538-
539-
#[test]
540-
fn sharded_cache_different_paths_different_shards() {
541-
let cache = ShardedDirCache::new();
542-
543-
// Insert many paths to exercise multiple shards
544-
for i in 0..100_u8 {
545-
let path = PathBuf::from(format!("dir{i}/file.txt"));
546-
let id = SedimentreeId::new([i; 32]);
547-
cache.insert(path.clone(), id);
548-
assert_eq!(cache.get(&path), Some(id));
549-
}
528+
fn sharded_cache_insert_then_get() {
529+
check!()
530+
.with_type::<Vec<(String, [u8; 32])>>()
531+
.for_each(|entries: &Vec<(String, [u8; 32])>| {
532+
let cache = ShardedDirCache::new();
533+
534+
for (path_str, id_bytes) in entries {
535+
let path = PathBuf::from(path_str);
536+
let id = SedimentreeId::new(*id_bytes);
537+
cache.insert(path.clone(), id);
538+
assert_eq!(
539+
cache.get(&path),
540+
Some(id),
541+
"get after insert should return the value"
542+
);
543+
}
544+
});
550545
}
551546
}

0 commit comments

Comments
 (0)