1
0

feat: add highlevel test

This commit is contained in:
2026-05-28 21:34:42 +08:00
parent 53b40a4d2f
commit 119a4d0341
3 changed files with 323 additions and 158 deletions

View File

@@ -55,6 +55,7 @@ pub enum ProgramError {
// region: Program
/// Program is a complete and immutable program representer
#[derive(Debug)]
pub struct Program {
app_paths_key: lowlevel::AppPathsKey,
applications_key: lowlevel::ApplicationsKey,
@@ -640,6 +641,7 @@ struct ProgramProgIdExtKey {
/// Exposed struct representing this program provided method for opening specific file extension.
///
/// The data including the extension name, diaplay name and icon.
#[derive(Debug)]
pub struct ProgramSelfExtStatus {
ext: concept::Ext,
name: String,
@@ -680,6 +682,7 @@ impl ProgramSelfExtStatus {
/// Exposed struct representing the default associated program of specific file extension.
///
/// The data including the diaplay name and icon.
#[derive(Debug)]
pub struct ProgramExtStatus {
name: String,
icon: concept::IconRc,

View File

@@ -1,7 +1,169 @@
use wfassoc::highlevel::*;
mod common;
#[test]
fn test() {
common::check_sandbox();
static IDENTIFIER: &str = "Passoc";
static APP_PATH: &str = r"C:\Passoc\passoc.exe";
static CLSID: &str = "{59031a47-3f72-44a7-89c5-5595fe6b30ee}";
static EXT_BODY: &str = "pacfg";
fn make_valid_schema() -> Schema {
let mut schema = Schema::new();
schema.set_identifier(IDENTIFIER);
schema.set_path(APP_PATH);
schema.set_clsid(CLSID);
schema.add_str("main_name", "Passoc Application").unwrap();
schema.add_str("ext_name", "Pacfg File").unwrap();
schema.add_icon("main_icon", r"notepad.exe,0").unwrap();
schema.add_icon("ext_icon", r"notepad.exe,0").unwrap();
schema.add_behavior("main_behavior", "notepad.exe %1").unwrap();
schema.add_behavior("ext_behavior", "notepad.exe %1").unwrap();
schema.set_name(Some("main_name"));
schema.set_icon(Some("main_icon"));
schema.set_behavior(Some("main_behavior"));
schema.add_ext(EXT_BODY, "ext_name", "ext_icon", "ext_behavior").unwrap();
schema
}
// region: Schema
#[test]
fn test_schema() {
common::check_sandbox();
// valid schema -> valid program
let schema = make_valid_schema();
let rv = schema.into_program();
assert!(rv.is_ok());
// missing identifier
let mut schema = Schema::new();
schema.set_path(APP_PATH);
let rv = schema.into_program();
assert!(rv.is_err());
// invalid path
let mut schema = Schema::new();
schema.set_identifier(IDENTIFIER);
schema.set_path(r"C:\");
let rv = schema.into_program();
assert!(rv.is_err());
// prepare a schema for following test
let mut schema = Schema::new();
schema.set_identifier(IDENTIFIER);
schema.set_path(APP_PATH);
// duplicate detection on add_str
let rv = schema.add_str("k", "v1");
assert!(rv.is_ok());
let rv = schema.add_str("k", "v2");
assert!(rv.is_err());
// duplicate detection on add_icon
let rv = schema.add_icon("k", "v1");
assert!(rv.is_ok());
let rv = schema.add_icon("k", "v2");
assert!(rv.is_err());
// duplicate detection on add_behavior
let rv = schema.add_behavior("k", "v1");
assert!(rv.is_ok());
let rv = schema.add_behavior("k", "v2");
assert!(rv.is_err());
// duplicate detection on add_ext
let rv = schema.add_ext(EXT_BODY, "k", "k", "k");
assert!(rv.is_ok());
let rv = schema.add_ext(EXT_BODY, "k", "k", "k");
assert!(rv.is_err());
// ext referencing non-existent map entry
schema.add_str("k2", "v").unwrap();
schema.add_icon("k2", "v").unwrap();
let rv = schema.add_ext("pacfg2", "nonexistent", "k2", "k2");
assert!(rv.is_ok());
let rv = schema.into_program();
assert!(rv.is_err());
}
// endregion
// region: Program
#[test]
fn test_program() {
common::check_sandbox();
fn tester(scope: Scope, view: View) {
// build program
let schema = make_valid_schema();
let rv = schema.into_program();
assert!(rv.is_ok());
let mut program = rv.unwrap();
// cleanup before test
let rv = program.unregister(scope);
assert!(rv.is_ok());
// initially not registered
let rv = program.is_registered(scope);
assert!(rv.is_ok());
assert_eq!(rv.unwrap(), false);
// register
let rv = program.register(scope);
assert!(rv.is_ok());
// should be registered now
let rv = program.is_registered(scope);
assert!(rv.is_ok());
assert_eq!(rv.unwrap(), true);
// link_ext first so ext key exists before register
let rv = program.link_ext(scope, 0);
assert!(rv.is_ok());
// query_ext after link + register
let rv = program.query_ext(view, 0);
assert!(rv.is_ok());
assert!(rv.unwrap().is_some());
// unlink_ext
let rv = program.unlink_ext(scope, 0);
assert!(rv.is_ok());
// query_ext should return None
let rv = program.query_ext(view, 0);
assert!(rv.is_ok());
assert!(rv.unwrap().is_none());
// resolve_name, resolve_icon
let rv = program.resolve_name();
assert!(rv.is_ok());
let rv = program.resolve_icon();
assert!(rv.is_ok());
// exts_len, find_ext, resolve_ext
assert_eq!(program.exts_len(), 1);
assert_eq!(program.find_ext(EXT_BODY), Some(0));
let rv = program.resolve_ext(0);
assert!(rv.is_ok());
// bad index
let rv = program.resolve_ext(1);
assert!(rv.is_err());
let rv = program.link_ext(scope, 1);
assert!(rv.is_err());
let rv = program.query_ext(view, 1);
assert!(rv.is_err());
// cleanup
let rv = program.unregister(scope);
assert!(rv.is_ok());
}
tester(Scope::User, View::User);
tester(Scope::System, View::System);
}
// endregion

View File

@@ -17,6 +17,161 @@ static VERB: LazyLock<ShellVerb> = LazyLock::new(|| {
ShellVerb::new(verb, cmdline)
});
// 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<StrResVariant> =
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
// region: ExtKey
#[test]
@@ -173,158 +328,3 @@ fn test_prog_id_key() {
}
// 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<StrResVariant> =
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