use camino::Utf8PathBuf;
use dapctl::diff::plan::{Entry, PathWarning, PathWarningKind};
use dapctl::diff::{check_path_limits, EntryKind, Plan};
fn mk_entry(kind: EntryKind, path: &str, size_bytes: u64) -> Entry {
Entry {
kind,
path: Utf8PathBuf::from(path),
size_bytes,
transcode_from: None,
}
}
fn fat32_fs() -> dapctl::dap::Filesystem {
dapctl::dap::Filesystem {
preferred: "exFAT".into(),
supported: vec!["FAT32".into(), "exFAT".into()],
max_filename_bytes: 255,
max_path_bytes: 4096,
case_sensitive: false,
}
}
fn tight_fs() -> dapctl::dap::Filesystem {
dapctl::dap::Filesystem {
preferred: "FAT32".into(),
supported: vec!["FAT32".into()],
max_filename_bytes: 64,
max_path_bytes: 128,
case_sensitive: false,
}
}
#[test]
fn plan_json_all_entry_kinds() {
let plan = Plan {
entries: vec![
mk_entry(
EntryKind::New,
"Tool/Lateralus/01 - The Grudge.flac",
90_508_288,
),
mk_entry(
EntryKind::Modified,
"Radiohead/OK Computer/06 - Karma Police.flac",
33_685_504,
),
mk_entry(
EntryKind::Orphan,
"Nickelback/How You Remind Me.mp3",
5_242_880,
),
mk_entry(
EntryKind::Same,
"Portishead/Dummy/03 - Strangers.flac",
52_428_800,
),
],
warnings: vec![],
};
insta::assert_json_snapshot!(&plan);
}
#[test]
fn plan_json_with_warnings() {
let long_name = "A".repeat(260);
let path = format!("Artist/Album/{long_name}.flac");
let plan = Plan {
entries: vec![mk_entry(EntryKind::New, &path, 45_000_000)],
warnings: vec![PathWarning {
path: Utf8PathBuf::from(&path),
kind: PathWarningKind::FilenameTooLong,
length_bytes: 265, limit_bytes: 255,
}],
};
insta::assert_json_snapshot!(&plan);
}
#[test]
fn no_warnings_for_normal_paths() {
let entries = vec![
mk_entry(EntryKind::New, "Artist/Album/01 - Track.flac", 1000),
mk_entry(
EntryKind::Modified,
"Other Artist/Record/02 - Song.flac",
2000,
),
];
let warnings = check_path_limits(&entries, &fat32_fs(), "/Music");
assert!(
warnings.is_empty(),
"expected no warnings, got {warnings:?}"
);
}
#[test]
fn warns_on_filename_too_long() {
let long = "A".repeat(260); let entries = vec![mk_entry(
EntryKind::New,
&format!("Artist/Album/{long}.flac"),
1000,
)];
let warnings = check_path_limits(&entries, &fat32_fs(), "/Music");
assert_eq!(warnings.len(), 1);
assert_eq!(warnings[0].kind, PathWarningKind::FilenameTooLong);
assert!(warnings[0].length_bytes > 255);
insta::assert_debug_snapshot!(warnings);
}
#[test]
fn warns_on_path_too_long() {
let seg = "d".repeat(30);
let entries = vec![mk_entry(
EntryKind::New,
&format!("{seg}/{seg}/{seg}/{seg}/t.flac"),
1000,
)];
let warnings = check_path_limits(&entries, &tight_fs(), "/Music");
assert_eq!(warnings.len(), 1);
assert_eq!(warnings[0].kind, PathWarningKind::PathTooLong);
insta::assert_debug_snapshot!(warnings);
}
#[test]
fn only_one_warning_per_entry() {
let long = "B".repeat(70); let entries = vec![mk_entry(EntryKind::New, &format!("Dir/{long}.flac"), 1000)];
let warnings = check_path_limits(&entries, &tight_fs(), "/Music");
assert_eq!(warnings.len(), 1, "expected exactly one warning per entry");
assert_eq!(warnings[0].kind, PathWarningKind::FilenameTooLong);
}
#[test]
fn skips_orphan_and_same_entries() {
let long = "X".repeat(260);
let entries = vec![
mk_entry(EntryKind::Orphan, &format!("Dir/{long}.flac"), 1000),
mk_entry(EntryKind::Same, &format!("Dir/{long}.flac"), 1000),
];
let warnings = check_path_limits(&entries, &fat32_fs(), "/Music");
assert!(
warnings.is_empty(),
"orphan/same entries must not generate warnings"
);
}
#[test]
fn all_builtin_profiles_parse() {
for (id, toml_str) in dapctl::dap::builtin::ALL {
let result: Result<dapctl::dap::DapProfile, _> = toml::from_str(toml_str);
assert!(
result.is_ok(),
"builtin profile {id:?} failed to parse: {:?}",
result.err()
);
}
}
#[test]
fn builtin_profile_count_at_least_seven() {
assert!(
dapctl::dap::builtin::ALL.len() >= 7,
"expected at least 7 builtin profiles, found {}",
dapctl::dap::builtin::ALL.len()
);
}
#[test]
fn builtin_profile_ids_snapshot() {
let mut ids: Vec<&str> = dapctl::dap::builtin::ALL
.iter()
.map(|(id, _)| *id)
.collect();
ids.sort();
insta::assert_debug_snapshot!(ids);
}