use std::ptr;
use super::*;
#[test]
fn name_eq_example() {
let mut desc = Descriptor::default();
desc.name.set(b"test");
assert_eq!(name_eq(&desc, b"test"), Some(&b""[..]));
assert_eq!(name_eq(&desc, b"test/a/b"), Some(&b"a/b"[..]));
assert_eq!(name_eq(&desc, b"testing"), None);
assert_eq!(name_eq(&desc, b"te"), None);
}
#[test]
fn next_sibling_example() {
let dir = [
Descriptor::dir(b"Foo", 2),
Descriptor::file(b"Bar"),
Descriptor::file(b"Baz"),
Descriptor::dir(b"Sub", 1),
Descriptor::dir(b"Dir", 0),
Descriptor::file(b"File"),
];
let results = [true, false, false, true, false, true];
let mut i = 0;
let end = dir.len();
while i < end {
let desc = &dir[i];
let next_i = next_sibling(desc, i, end);
println!("processing dir[{}] out of {}", i, end);
assert!(results[i]);
i = next_i;
}
}
#[test]
fn test_to_string() {
let dir = [
Descriptor::dir(b"Foo", 2),
Descriptor::file(b"Bar"),
Descriptor::file(b"Baz"),
Descriptor::dir(b"Sub", 1),
Descriptor::dir(b"Dir", 0),
Descriptor::file(b"File"),
];
let expected = "\
./
+- Foo/
| | Bar
| ` Baz
|
+- Sub/
| `- Dir/
|
` File
";
let result = DirFmt::new(".", &dir, &TreeArt::ASCII).to_string();
println!("\n{}", result);
assert_eq!(expected, result);
}
#[test]
fn test_find_empty() {
assert_eq!(find(&[], b"path"), &[]);
}
#[test]
fn test_find_desc01() {
let mut dir = Vec::new();
create(&mut dir, b"A/B/C");
let result1 = find_desc(&dir, b"A/B/C");
let result2 = find_desc(&dir, b"A/B/D");
assert_eq!(result1.unwrap().name(), b"C");
assert!(result2.is_none());
}
#[test]
fn test_find() {
let dir = [
Descriptor::file(b"before"),
Descriptor::dir(b"a", 3),
Descriptor::dir(b"b", 2),
Descriptor::dir(b"c", 1),
Descriptor::file(b"file"),
];
assert!(ptr::eq(find(&dir, b"before"), &dir[0..1]));
assert!(ptr::eq(find(&dir, b"a"), &dir[1..]));
assert!(ptr::eq(find(&dir[2..], b"b"), &dir[2..]));
assert_eq!(find(&dir, "file".as_ref()).len(), 0);
assert!(ptr::eq(find(&dir[4..], b"file"), &dir[4..]));
assert_eq!(find_desc(&dir, b"a\\b\\c\\file").map(|x| x as *const _), Some(&dir[4] as *const _));
}
#[test]
fn test_find_skips_file_when_more_path_remains() {
let dir = [
Descriptor::file(b"mods"),
Descriptor::dir(b"mods", 2),
Descriptor::file(b"config.txt"),
Descriptor::file(b"notes.txt"),
Descriptor::file(b"after"),
];
assert_eq!(find_desc(&dir, b"mods/config.txt").map(Descriptor::name), Some(&b"config.txt"[..]));
assert_eq!(find(&dir, b"mods/missing.txt"), &[]);
assert_eq!(find(&dir, b"after"), &dir[4..5]);
assert_eq!(find(&dir, b"mods")[0].name(), b"mods");
assert!(find_dir(&dir, b"mods").is_some());
assert_eq!(find_dir(&dir, b"mods/config.txt"), Some(&[][..]));
}
#[test]
fn test_find_encrypted_skips_file_and_reports_missing_paths() {
let ref key = [42, 13];
let mut directory = Directory::from(vec![
Descriptor::file(b"mods"),
Descriptor::dir(b"mods", 2),
Descriptor::file(b"config.txt"),
Descriptor::file(b"notes.txt"),
Descriptor::file(b"after"),
]);
let mut section = Section {
offset: 0,
size: directory.as_blocks().len() as u32,
nonce: Block::default(),
mac: Block::default(),
};
crate::crypt::encrypt_section(directory.as_blocks_mut(), &mut section, key);
let found = find_encrypted(directory.as_ref(), b"mods/config.txt", §ion, key).expect("encrypted file should be found");
assert_eq!(found.name(), b"config.txt");
assert!(found.is_file());
assert!(find_encrypted(directory.as_ref(), b"mods/missing.txt", §ion, key).is_none());
assert_eq!(find_encrypted(directory.as_ref(), b"after", §ion, key).unwrap().name(), b"after");
assert!(find_encrypted(directory.as_ref(), b"", §ion, key).is_none());
}
#[test]
fn test_create_simple() {
let path = b"stuff.txt";
let mut dir = Vec::new();
create(&mut dir, path);
assert_eq!(dir.len(), 1);
let file = &dir[0];
assert_eq!(file.content_type, 0);
assert_eq!(file.content_size, 0);
assert_eq!(file.section, Section::default());
assert_eq!(file.name(), path);
}
#[test]
fn test_create_simple_dirs() {
let path1 = b"A/FOO";
let path2 = b"A/BAR";
let mut dir = Vec::new();
create(&mut dir, path1);
create(&mut dir, path2);
let result = [
Descriptor::dir(b"A", 2),
Descriptor::dir(b"FOO", 0),
Descriptor::dir(b"BAR", 0),
];
assert_eq!(dir, result);
}
#[test]
fn test_create_reuses_existing_descriptor() {
let mut dir = Vec::new();
let first_ptr = {
let first = create(&mut dir, b"save.bin");
first.content_type = 9;
first.content_size = 33;
first as *mut Descriptor
};
let (second_ptr, second_content_type, second_content_size) = {
let second = create(&mut dir, b"save.bin");
(second as *mut Descriptor, second.content_type, second.content_size)
};
assert_eq!(first_ptr, second_ptr);
assert_eq!(dir.len(), 1);
assert_eq!(second_content_type, 9);
assert_eq!(second_content_size, 33);
}
#[test]
fn test_create_supports_trailing_separators_and_file_name_conflicts() {
let mut dir = vec![Descriptor::file(b"config")];
let created = create(&mut dir, b"config/user/");
assert!(created.is_dir());
assert_eq!(created.name(), b"user");
assert_eq!(dir, vec![
Descriptor::dir(b"config", 1),
Descriptor::dir(b"user", 0),
Descriptor::file(b"config"),
]);
}
#[test]
fn test_remove_missing_path_returns_none() {
let mut dir = Vec::new();
create(&mut dir, b"assets/logo.png");
let snapshot = dir.clone();
assert!(remove(&mut dir, b"assets/missing.png").is_none());
assert_eq!(dir, snapshot);
}
#[test]
fn test_fsck_reports_invalid_file_metadata() {
let mut invalid_name_len = Descriptor::file(b"len");
invalid_name_len.name.buffer[NAME_BUF_LEN - 1] = 255;
let mut invalid_utf8 = Descriptor::file(b"utf8");
invalid_utf8.name.buffer[..2].copy_from_slice(&[0xff, 0xfe]);
invalid_utf8.name.buffer[NAME_BUF_LEN - 1] = 2;
let mut overlaps_header = Descriptor::file(b"header");
overlaps_header.content_size = 1;
overlaps_header.section = Section { offset: 0, size: 1, nonce: Block::default(), mac: Block::default() };
let mut size_too_large = Descriptor::file(b"big");
size_too_large.content_size = 1;
size_too_large.section = Section { offset: Header::BLOCKS_LEN as u32, size: 9, nonce: Block::default(), mac: Block::default() };
let mut overlaps_directory = Descriptor::file(b"directory");
overlaps_directory.content_size = 1;
overlaps_directory.section = Section { offset: 8, size: 1, nonce: Block::default(), mac: Block::default() };
let mut content_too_large = Descriptor::file(b"content");
content_too_large.content_size = BLOCK_SIZE as u32 + 1;
content_too_large.section = Section { offset: Header::BLOCKS_LEN as u32, size: 1, nonce: Block::default(), mac: Block::default() };
let dir = [invalid_name_len, invalid_utf8, overlaps_header, size_too_large, overlaps_directory, content_too_large];
let mut log = String::new();
assert!(!fsck(&dir, 8, &mut log));
assert!(log.contains("invalid name length"));
assert!(log.contains("invalid name ("));
assert!(log.contains("overlaps the header"));
assert!(log.contains("size too large"));
assert!(log.contains("overlaps the directory"));
assert!(log.contains("larger than its section"));
}
#[test]
fn test_fsck_reports_nested_errors_and_invalid_child_counts() {
let mut nested_bad = Descriptor::file(b"broken.bin");
nested_bad.content_size = 1;
nested_bad.section = Section { offset: 0, size: 1, nonce: Block::default(), mac: Block::default() };
let nested = [Descriptor::dir(b"root", 1), nested_bad];
let mut nested_log = String::new();
assert!(!fsck(&nested, 8, &mut nested_log));
assert!(nested_log.contains("/root/broken.bin: invalid file section"));
let malformed = [Descriptor::dir(b"root", 2), Descriptor::file(b"child")];
let mut malformed_log = String::new();
assert!(!fsck(&malformed, 8, &mut malformed_log));
assert!(malformed_log.contains("invalid directory: too many children"));
}