//! Full CLI coverage, host side: exports only as named text files of known kinds, app-folder paths only inside the //! folder, only folders and the gallery page open, new-folder methods and big reads stay out of the generic paths. use std::path::Path; use storebound_desktop::COMMANDS; use storebound_desktop::policy::{export_file_name, openable, project_relative, NEW_FOLDER_METHODS, NO_CACHE_METHODS, PERSONAL_EXPORT_NOTE}; #[test] fn export_names() { assert_eq!(export_file_name("Prism Puddle prices 2026-10-11", "csv").as_deref(), Some("Prism Puddle prices 2026-10-11.csv")); assert_eq!(export_file_name("x.csv", "csv").as_deref(), Some("x.csv")); assert_eq!(export_file_name("../../etc/passwd", "md").as_deref(), Some("-..-etc-passwd.md")); assert_eq!(export_file_name(".hidden", "txt").as_deref(), Some("hidden.txt")); assert!(export_file_name("a", "exe").is_none()); assert!(export_file_name("a", "html").is_none()); assert!(export_file_name(" ", "csv").is_none()); let long = "a".repeat(400); assert!(export_file_name(&long, "csv").unwrap().len() <= 124); for n in ["a/b", "a\\b", "a:b", "a\nb"] { let f = export_file_name(n, "csv").unwrap(); assert!(!f.contains(['/', '\\', ':', '\n']), "{f}"); } assert!(PERSONAL_EXPORT_NOTE.contains("personal data")); } #[test] fn app_folder_paths() { assert!(project_relative("store/renders").is_some()); assert!(project_relative("store/renders/index.html").is_some()); for bad in ["", "/etc", "../x", "store/../../x", "./store", "a\\b", "a\u{0}b"] { assert!(project_relative(bad).is_none(), "{bad}"); } assert!(openable(Path::new("store/renders/index.html"), false)); assert!(openable(Path::new("store/renders"), true)); assert!(!openable(Path::new("store/renders/run.sh"), false)); assert!(openable(Path::new(".storebound/reports/readiness-2026-10-18.html"), false)); assert!(!openable(Path::new(".storebound/reports/readiness-2026-10-18.sh"), false)); assert!(!openable(Path::new(".storebound/credentials.json"), false)); assert!(!openable(Path::new("other/reports/readiness-2026-10-18.html"), false)); assert!(!openable(Path::new("store/prices.csv"), false)); } #[test] fn new_folder_methods_and_big_reads() { assert_eq!(NEW_FOLDER_METHODS, &["project.init", "import.fastlane"]); assert_eq!(NO_CACHE_METHODS, &["project.render", "art.thumb"]); for c in ["project_import_fastlane", "export_save", "price_sheet_pick", "image_pick", "project_reveal"] { assert!(COMMANDS.contains(&c), "{c}"); } }