diff --git a/wfassoc/tests/common.rs b/wfassoc/tests/common.rs new file mode 100644 index 0000000..c66a0a8 --- /dev/null +++ b/wfassoc/tests/common.rs @@ -0,0 +1,16 @@ +/// Check whether we are in sandbox. +/// +/// # Panics +/// +/// Panic if we are not in sandbox (we can not perform dangerous test). +/// Return if we are in sandbox environment. +pub fn check_sandbox() { + assert!( + std::env::var("SANDBOXIE").is_ok(), + concat!( + "Non-sandbox environment detected. ", + "Executing these test in non-sandbox environment is VERY dangerous. ", + "Please set \"SANDBOXIE\" environment variable to explicitly indicate you are running these test in sandbox environment." + ) + ) +} diff --git a/wfassoc/tests/highlevel.rs b/wfassoc/tests/highlevel.rs new file mode 100644 index 0000000..28251e1 --- /dev/null +++ b/wfassoc/tests/highlevel.rs @@ -0,0 +1,7 @@ +use wfassoc::highlevel::*; +mod common; + +#[test] +fn test() { + common::check_sandbox(); +} diff --git a/wfassoc/tests/lowlevel.rs b/wfassoc/tests/lowlevel.rs new file mode 100644 index 0000000..51ce5b7 --- /dev/null +++ b/wfassoc/tests/lowlevel.rs @@ -0,0 +1,330 @@ +use std::ops::Deref; +use std::str::FromStr; +use std::sync::LazyLock; +use wfassoc::lowlevel::*; +use wfassoc::win32::concept; +mod common; + +static EXT: LazyLock = LazyLock::new(|| concept::Ext::from_str(".pacfg").unwrap()); +static APP_FILE: LazyLock = + LazyLock::new(|| concept::FileName::from_str("passoc.exe").unwrap()); +static PROG_ID: LazyLock = LazyLock::new(|| "Passoc.Pacfg".into()); +static ICON: LazyLock = + LazyLock::new(|| r"%SystemRoot%\System32\imageres.dll,-72".into()); +static VERB: LazyLock = LazyLock::new(|| { + let verb = concept::Verb::from_str("open").unwrap(); + let cmdline = concept::CmdLine::from_str("notepad.exe %1").unwrap(); + ShellVerb::new(verb, cmdline) +}); + +// region: ExtKey + +#[test] +fn test_ext_key() { + common::check_sandbox(); + + fn tester(scope: Scope, view: View) { + let mut key = ExtKey::new(EXT.clone()); + + // delete and ensure + let rv = key.delete(scope); + assert!(rv.is_ok()); + let rv = key.is_exist(view); + assert!(rv.is_ok()); + assert_eq!(rv.unwrap(), false); + let rv = key.ensure(scope); + assert!(rv.is_ok()); + assert_eq!(rv.unwrap(), true); + let rv = key.is_exist(view); + assert!(rv.is_ok()); + assert_eq!(rv.unwrap(), true); + let rv = key.ensure(scope); + assert!(rv.is_ok()); + assert_eq!(rv.unwrap(), false); + + // get/set default + let rv = key.set_default(scope, Some(&PROG_ID)); + assert!(rv.is_ok()); + let rv = key.get_default(view); + assert!(rv.is_ok()); + assert_eq!(rv.unwrap(), Some(PROG_ID.clone())); + let rv = key.set_default(scope, None); + assert!(rv.is_ok()); + let rv = key.get_default(view); + assert!(rv.is_ok()); + assert_eq!(rv.unwrap(), None); + + // test open with progids + let rv = key.is_in_open_with_progids(view, &PROG_ID); + assert!(rv.is_ok()); + assert_eq!(rv.unwrap(), false); + + let rv = key.add_into_open_with_progids(scope, &PROG_ID); + assert!(rv.is_ok()); + let rv = key.is_in_open_with_progids(view, &PROG_ID); + assert!(rv.is_ok()); + assert_eq!(rv.unwrap(), true); + + let rv = key.get_open_with_progids(view); + assert!(rv.is_ok()); + assert_eq!(rv.unwrap(), Some(vec![PROG_ID.clone()])); + + let rv = key.remove_from_open_with_progids(scope, &PROG_ID); + assert!(rv.is_ok()); + let rv = key.is_in_open_with_progids(view, &PROG_ID); + assert!(rv.is_ok()); + assert_eq!(rv.unwrap(), false); + + // clean up + let rv = key.delete(scope); + assert!(rv.is_ok()); + } + + tester(Scope::User, View::User); + tester(Scope::System, View::System); +} + +// endregion + +// region: ProgIdKey + +#[test] +fn test_prog_id_key() { + common::check_sandbox(); + + static LEGACY_NAME: LazyLock = LazyLock::new(|| "Passoc Pacfg File".into()); + static FRIENDLY_TYPE_NAME: LazyLock = + LazyLock::new(|| "Passoc Pacfg File Type".into()); + + fn tester(scope: Scope, view: View) { + let mut key = ProgIdKey::new(PROG_ID.clone()); + + // delete and ensure + let rv = key.delete(scope); + assert!(rv.is_ok()); + let rv = key.is_exist(view); + assert!(rv.is_ok()); + assert_eq!(rv.unwrap(), false); + let rv = key.ensure(scope); + assert!(rv.is_ok()); + assert_eq!(rv.unwrap(), true); + let rv = key.is_exist(view); + assert!(rv.is_ok()); + assert_eq!(rv.unwrap(), true); + let rv = key.ensure(scope); + assert!(rv.is_ok()); + assert_eq!(rv.unwrap(), false); + + // get/set default (friendly name, legacy) + let rv = key.set_default(scope, Some(&LEGACY_NAME)); + assert!(rv.is_ok()); + let rv = key.get_default(view); + assert!(rv.is_ok()); + assert_eq!(rv.unwrap(), Some(LEGACY_NAME.clone())); + let rv = key.set_default(scope, None); + assert!(rv.is_ok()); + let rv = key.get_default(view); + assert!(rv.is_ok()); + assert_eq!(rv.unwrap(), None); + + // get/set friendly type name + let rv = key.set_friendly_type_name(scope, Some(&FRIENDLY_TYPE_NAME)); + assert!(rv.is_ok()); + let rv = key.get_friendly_type_name(view); + assert!(rv.is_ok()); + assert_eq!(rv.unwrap(), Some(FRIENDLY_TYPE_NAME.clone())); + let rv = key.set_friendly_type_name(scope, None); + assert!(rv.is_ok()); + let rv = key.get_friendly_type_name(view); + assert!(rv.is_ok()); + assert_eq!(rv.unwrap(), None); + + // get/set shell verb + let rv = key.set_shell_verb(scope, Some(&VERB)); + assert!(rv.is_ok()); + let rv = key.get_shell_verb(view); + assert!(rv.is_ok()); + assert_eq!(rv.unwrap(), Some(VERB.clone())); + let rv = key.set_shell_verb(scope, None); + assert!(rv.is_ok()); + let rv = key.get_shell_verb(view); + assert!(rv.is_ok()); + assert_eq!(rv.unwrap(), None); + + // get/set default icon + let rv = key.set_default_icon(scope, Some(&ICON)); + assert!(rv.is_ok()); + let rv = key.get_default_icon(view); + assert!(rv.is_ok()); + assert_eq!(rv.unwrap(), Some(ICON.clone())); + let rv = key.set_default_icon(scope, None); + assert!(rv.is_ok()); + let rv = key.get_default_icon(view); + assert!(rv.is_ok()); + assert_eq!(rv.unwrap(), None); + + // clean up + let rv = key.delete(scope); + assert!(rv.is_ok()); + } + + tester(Scope::User, View::User); + tester(Scope::System, View::System); +} + +// endregion + +// region: AppPathsKey + +#[test] +fn test_app_paths_key() { + common::check_sandbox(); + + static APP_PATH: &str = r"C:\Program Files\Passoc\passoc.exe"; + static APP_DIR: &str = r"C:\Program Files\Passoc"; + + fn tester(scope: Scope) { + let mut key = AppPathsKey::new(APP_FILE.clone()); + + // delete and ensure + let rv = key.delete(scope); + assert!(rv.is_ok()); + let rv = key.is_exist(scope); + assert!(rv.is_ok()); + assert_eq!(rv.unwrap(), false); + let rv = key.ensure(scope); + assert!(rv.is_ok()); + assert_eq!(rv.unwrap(), true); + let rv = key.is_exist(scope); + assert!(rv.is_ok()); + assert_eq!(rv.unwrap(), true); + let rv = key.ensure(scope); + assert!(rv.is_ok()); + assert_eq!(rv.unwrap(), false); + + // get/set default + let rv = key.set_default(scope, APP_PATH); + assert!(rv.is_ok()); + let rv = key.get_default(scope); + assert!(rv.is_ok()); + assert_eq!(rv.unwrap(), APP_PATH); + + // get/set path + let rv = key.set_path(scope, APP_DIR); + assert!(rv.is_ok()); + let rv = key.get_path(scope); + assert!(rv.is_ok()); + assert_eq!(rv.unwrap(), APP_DIR); + + // clean up + let rv = key.delete(scope); + assert!(rv.is_ok()); + } + + tester(Scope::User); + tester(Scope::System); +} + +// endregion + +// region: ApplicationsKey + +#[test] +fn test_applications_key() { + common::check_sandbox(); + + static FRIENDLY_APP_NAME: LazyLock = + LazyLock::new(|| "Passoc Application".into()); + + fn tester(scope: Scope, view: View) { + let mut key = ApplicationsKey::new(APP_FILE.clone()); + + // delete and ensure + let rv = key.delete(scope); + assert!(rv.is_ok()); + let rv = key.is_exist(view); + assert!(rv.is_ok()); + assert_eq!(rv.unwrap(), false); + let rv = key.ensure(scope); + assert!(rv.is_ok()); + assert_eq!(rv.unwrap(), true); + let rv = key.is_exist(view); + assert!(rv.is_ok()); + assert_eq!(rv.unwrap(), true); + let rv = key.ensure(scope); + assert!(rv.is_ok()); + assert_eq!(rv.unwrap(), false); + + // get/set shell verb + let rv = key.set_shell_verb(scope, Some(&VERB)); + assert!(rv.is_ok()); + let rv = key.get_shell_verb(view); + assert!(rv.is_ok()); + assert_eq!(rv.unwrap(), Some(VERB.clone())); + let rv = key.set_shell_verb(scope, None); + assert!(rv.is_ok()); + let rv = key.get_shell_verb(view); + assert!(rv.is_ok()); + assert_eq!(rv.unwrap(), None); + + // get/set default icon + let rv = key.set_default_icon(scope, Some(&ICON)); + assert!(rv.is_ok()); + let rv = key.get_default_icon(view); + assert!(rv.is_ok()); + assert_eq!(rv.unwrap(), Some(ICON.clone())); + let rv = key.set_default_icon(scope, None); + assert!(rv.is_ok()); + let rv = key.get_default_icon(view); + assert!(rv.is_ok()); + assert_eq!(rv.unwrap(), None); + + // get/set friendly app name + let rv = key.set_friendly_app_name(scope, Some(&FRIENDLY_APP_NAME)); + assert!(rv.is_ok()); + let rv = key.get_friendly_app_name(view); + assert!(rv.is_ok()); + assert_eq!(rv.unwrap(), Some(FRIENDLY_APP_NAME.clone())); + let rv = key.set_friendly_app_name(scope, None); + assert!(rv.is_ok()); + let rv = key.get_friendly_app_name(view); + assert!(rv.is_ok()); + assert_eq!(rv.unwrap(), None); + + // get/set supported types + let rv = key.set_supported_types(scope, Some(&vec![EXT.deref()])); + assert!(rv.is_ok()); + let rv = key.get_supported_types(view); + assert!(rv.is_ok()); + assert_eq!(rv.unwrap(), Some(vec![EXT.clone()])); + let rv = key.set_supported_types(scope, None); + assert!(rv.is_ok()); + let rv = key.get_supported_types(view); + assert!(rv.is_ok()); + assert_eq!(rv.unwrap(), None); + + // get/set no open with + let rv = key.get_no_open_with(view); + assert!(rv.is_ok()); + assert_eq!(rv.unwrap(), false); + let rv = key.set_no_open_with(scope, true); + assert!(rv.is_ok()); + let rv = key.get_no_open_with(view); + assert!(rv.is_ok()); + assert_eq!(rv.unwrap(), true); + let rv = key.set_no_open_with(scope, false); + assert!(rv.is_ok()); + let rv = key.get_no_open_with(view); + assert!(rv.is_ok()); + assert_eq!(rv.unwrap(), false); + + // clean up + let rv = key.delete(scope); + assert!(rv.is_ok()); + } + + tester(Scope::User, View::User); + tester(Scope::System, View::System); +} + +// endregion