// file: crates/ksp-config-lib/unit_tests/bootstrap.rs // version: 2 #[test] fn defaults_use_hardcoded_ksp_roots() { let result = crate::ConfigBootstrapOptions::defaults(); assert!(result.is_ok(), "default bootstrap paths should be valid: {result:?}"); if let std::result::Result::Ok(options) = result { assert_eq!(options.cfg_path(), std::path::Path::new(crate::DEFAULT_CFG_PATH)); assert_eq!(options.schema_path(), std::path::Path::new(crate::DEFAULT_SCHEMA_PATH)); } } #[test] fn cfg_path_override_keeps_schema_default() { let defaults = crate::ConfigBootstrapOptions::defaults(); assert!(defaults.is_ok(), "default bootstrap paths should be valid: {defaults:?}"); if let std::result::Result::Ok(options) = defaults { let result = options.with_cfg_path("custom-config"); assert!(result.is_ok(), "cfg path override should be valid: {result:?}"); if let std::result::Result::Ok(options) = result { assert_eq!(options.cfg_path(), std::path::Path::new("custom-config")); assert_eq!(options.schema_path(), std::path::Path::new(crate::DEFAULT_SCHEMA_PATH)); } } } #[test] fn schema_path_override_keeps_cfg_default() { let defaults = crate::ConfigBootstrapOptions::defaults(); assert!(defaults.is_ok(), "default bootstrap paths should be valid: {defaults:?}"); if let std::result::Result::Ok(options) = defaults { let result = options.with_schema_path("custom-schemas"); assert!(result.is_ok(), "schema path override should be valid: {result:?}"); if let std::result::Result::Ok(options) = result { assert_eq!(options.cfg_path(), std::path::Path::new(crate::DEFAULT_CFG_PATH)); assert_eq!(options.schema_path(), std::path::Path::new("custom-schemas")); } } } #[test] fn cfg_cli_override_keeps_schema_default() { let args = [std::ffi::OsString::from("ksp-app"), std::ffi::OsString::from("--cfgpath=cli-config")]; let result = crate::ConfigBootstrapOptions::from_args(&args); assert!(result.is_ok(), "cfg CLI override should parse: {result:?}"); if let std::result::Result::Ok(options) = result { assert_eq!(options.cfg_path(), std::path::Path::new("cli-config")); assert_eq!(options.schema_path(), std::path::Path::new(crate::DEFAULT_SCHEMA_PATH)); } } #[test] fn schema_cli_override_keeps_cfg_default() { let args = [std::ffi::OsString::from("ksp-app"), std::ffi::OsString::from("--schemapath=cli-schemas")]; let result = crate::ConfigBootstrapOptions::from_args(&args); assert!(result.is_ok(), "schema CLI override should parse: {result:?}"); if let std::result::Result::Ok(options) = result { assert_eq!(options.cfg_path(), std::path::Path::new(crate::DEFAULT_CFG_PATH)); assert_eq!(options.schema_path(), std::path::Path::new("cli-schemas")); } } #[test] fn parser_accepts_inline_and_separate_forms_and_last_value_wins() { let args = [ std::ffi::OsString::from("ksp-app"), std::ffi::OsString::from("--cfgpath=first-config"), std::ffi::OsString::from("--unrelated"), std::ffi::OsString::from("--cfgpath"), std::ffi::OsString::from("second-config"), std::ffi::OsString::from("--schemapath=first-schemas"), std::ffi::OsString::from("--schemapath"), std::ffi::OsString::from("second-schemas"), ]; let result = crate::ConfigBootstrapOptions::from_args(&args); assert!(result.is_ok(), "bootstrap arguments should parse: {result:?}"); if let std::result::Result::Ok(options) = result { assert_eq!(options.cfg_path(), std::path::Path::new("second-config")); assert_eq!(options.schema_path(), std::path::Path::new("second-schemas")); } } #[test] fn parser_reports_missing_separate_value() { let args = [std::ffi::OsString::from("ksp-app"), std::ffi::OsString::from("--cfgpath")]; let result = crate::ConfigBootstrapOptions::from_args(&args); assert!(result.is_err(), "missing value must be rejected"); if let std::result::Result::Err(error) = result { assert_eq!(error.code(), crate::ERROR_CODE_BOOTSTRAP_ARGUMENT_MISSING_VALUE); } } #[test] fn parser_reports_another_option_as_missing_separate_value() { let args = [std::ffi::OsString::from("ksp-app"), std::ffi::OsString::from("--cfgpath"), std::ffi::OsString::from("--other-option")]; let result = crate::ConfigBootstrapOptions::from_args(&args); assert!(result.is_err(), "another option must not become a bootstrap path value"); if let std::result::Result::Err(error) = result { assert_eq!(error.code(), crate::ERROR_CODE_BOOTSTRAP_ARGUMENT_MISSING_VALUE); } } #[test] fn empty_inline_path_is_rejected() { let args = [std::ffi::OsString::from("ksp-app"), std::ffi::OsString::from("--schemapath=")]; let result = crate::ConfigBootstrapOptions::from_args(&args); assert!(result.is_err(), "empty path must be rejected"); if let std::result::Result::Err(error) = result { assert_eq!(error.code(), crate::ERROR_CODE_BOOTSTRAP_INVALID_PATH); } } #[test] fn explicit_programmatic_paths_do_not_depend_on_default_roots() { let result = crate::ConfigBootstrapOptions::from_paths("programmatic-config", "programmatic-schemas"); assert!(result.is_ok(), "explicit programmatic paths should be valid: {result:?}"); if let std::result::Result::Ok(options) = result { assert_eq!(options.cfg_path(), std::path::Path::new("programmatic-config")); assert_eq!(options.schema_path(), std::path::Path::new("programmatic-schemas")); } } #[test] fn existing_non_directory_path_is_rejected() { let fixture = unique_fixture_path("existing-file"); let create = std::fs::write(fixture.as_path(), b"fixture"); assert!(create.is_ok(), "fixture file should be creatable: {create:?}"); let result = crate::ConfigBootstrapOptions::from_paths(fixture.as_path(), "programmatic-schemas"); let remove = std::fs::remove_file(fixture.as_path()); assert!(remove.is_ok(), "fixture file should be removable: {remove:?}"); assert!(result.is_err(), "existing file must not be accepted as a bootstrap directory"); if let std::result::Result::Err(error) = result { assert_eq!(error.code(), crate::ERROR_CODE_BOOTSTRAP_INVALID_PATH); } } fn unique_fixture_path(name: &str) -> std::path::PathBuf { let mut path = std::env::temp_dir(); path.push(format!("ksp-config-lib-{name}-{}", std::process::id())); return path; }