diff --git a/Cargo.lock b/Cargo.lock index 50fcba1b6..ac875b957 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -184,6 +184,7 @@ dependencies = [ "mockall", "mockall_double", "predicates", + "regex", "serde_json", "sha2", "thiserror", diff --git a/crates/cargo-wdk/Cargo.toml b/crates/cargo-wdk/Cargo.toml index db5084b43..39570ea89 100644 --- a/crates/cargo-wdk/Cargo.toml +++ b/crates/cargo-wdk/Cargo.toml @@ -31,6 +31,7 @@ wdk-build.workspace = true assert_cmd.workspace = true assert_fs.workspace = true predicates.workspace = true +regex.workspace = true sha2.workspace = true [lints.rust] diff --git a/crates/cargo-wdk/src/actions/build/package_task.rs b/crates/cargo-wdk/src/actions/build/package_task.rs index 2503a1654..11f47a8f0 100644 --- a/crates/cargo-wdk/src/actions/build/package_task.rs +++ b/crates/cargo-wdk/src/actions/build/package_task.rs @@ -26,6 +26,7 @@ use crate::{actions::build::error::PackageTaskError, providers::error::FileError const MISSING_SAMPLE_FLAG_WDK_BUILD_NUMBER_RANGE: RangeFrom = 25798..; const WDR_TEST_CERT_STORE: &str = "WDRTestCertStore"; const WDR_LOCAL_TEST_CERT: &str = "WDRLocalTestCert"; +const STAMPINF_VERSION_ENV_VAR: &str = "STAMPINF_VERSION"; #[derive(Debug)] pub struct PackageTaskParams<'a> { @@ -313,9 +314,23 @@ impl<'a> PackageTask<'a> { &arch, "-c", &cat_file_path, - "-v", - "*", ]; + + match std::env::var(STAMPINF_VERSION_ENV_VAR) { + Ok(version) if !version.trim().is_empty() => { + // When STAMPINF_VERSION is set to a non-empty, non-whitespace value, we + // intentionally omit -v so stampinf reads it and populates + // DriverVer. (Whitespace-only values are ignored.) + debug!( + DriverVer = version, + "Using {STAMPINF_VERSION_ENV_VAR} env var to set DriverVer" + ); + } + _ => { + args.extend(["-v", "*"]); + } + } + if !wdf_version_flags.is_empty() { args.append(&mut wdf_version_flags.iter().map(String::as_str).collect()); } @@ -514,7 +529,10 @@ impl<'a> PackageTask<'a> { } #[cfg(test)] mod tests { - use std::path::PathBuf; + use std::{ + path::PathBuf, + process::{ExitStatus, Output}, + }; use wdk_build::{CpuArchitecture, KmdfConfig}; @@ -632,4 +650,69 @@ mod tests { PackageTask::new(package_task_params, &wdk_build, &command_exec, &fs); } + + #[test] + fn stampinf_version_overrides_with_env_var() { + // verify both with and without the env var set scenarios + let scenarios = [ + ("env_set", Some("1.2.3.4"), true), + ("env_empty", Some(""), false), + ("env_spaces", Some(" "), false), + ("env_unset", None, false), + ]; + + for (name, env_val, expect_skip_v) in scenarios { + let result = + crate::test_utils::with_env(&[(STAMPINF_VERSION_ENV_VAR, env_val)], || { + let package_name = "driver"; + let working_dir = PathBuf::from("C:/abs/driver"); + let target_dir = PathBuf::from("C:/abs/driver/target/debug"); + let arch = CpuArchitecture::Amd64; + + let params = PackageTaskParams { + package_name, + working_dir: &working_dir, + target_dir: &target_dir, + target_arch: &arch, + driver_model: DriverConfig::Kmdf(KmdfConfig::default()), + sample_class: false, + verify_signature: false, + }; + + let wdk_build = WdkBuild::default(); + let fs = Fs::default(); + let mut command_exec = CommandExec::default(); + + command_exec + .expect_run() + .withf(move |cmd: &str, args: &[&str], _, _| { + if cmd != "stampinf" { + return false; + } + let has_v = args.contains(&"-v"); + if expect_skip_v { + !has_v + } else { + args.windows(2).any(|w| w == ["-v", "*"]) + } + }) + .once() + .return_once(|_, _, _, _| { + Ok(Output { + status: ExitStatus::default(), + stdout: vec![], + stderr: vec![], + }) + }); + + let task = PackageTask::new(params, &wdk_build, &command_exec, &fs); + task.run_stampinf() + }); + + assert!( + result.is_ok(), + "scenario {name} failed (env_set={env_val:?})" + ); + } + } } diff --git a/crates/cargo-wdk/src/actions/build/tests.rs b/crates/cargo-wdk/src/actions/build/tests.rs index 56d622c8f..992c614a0 100644 --- a/crates/cargo-wdk/src/actions/build/tests.rs +++ b/crates/cargo-wdk/src/actions/build/tests.rs @@ -58,57 +58,20 @@ pub fn given_a_driver_project_when_default_values_are_provided_then_it_builds_su let wdk_metadata = get_cargo_metadata_wdk_metadata(driver_type, 1, 33); let (workspace_member, package) = get_cargo_metadata_package(&cwd, driver_name, driver_version, Some(wdk_metadata)); - let expected_certmgr_output = Output { - status: ExitStatus::default(), - stdout: r"==============No Certificates ========== - ==============No CTLs ========== - ==============No CRLs ========== - ============================================== - CertMgr Succeeded" - .as_bytes() - .to_vec(), - stderr: vec![], - }; let test_build_action = &TestBuildAction::new(cwd.clone(), profile, target_arch, sample_class) .set_up_standalone_driver_project((workspace_member, package)) - .expect_detect_wdk_build_number(25100u32) - .expect_root_manifest_exists(&cwd, true) - .expect_cargo_build(driver_name, &cwd, None) - .expect_final_package_dir_exists(driver_name, &cwd, true) - .expect_inx_file_exists(driver_name, &cwd, true) - .expect_rename_driver_binary_dll_to_sys(driver_name, &cwd) - .expect_copy_driver_binary_sys_to_package_folder(driver_name, &cwd, true) - .expect_copy_pdb_file_to_package_folder(driver_name, &cwd, true) - .expect_copy_inx_file_to_package_folder(driver_name, &cwd, true, &cwd) - .expect_copy_map_file_to_package_folder(driver_name, &cwd, true) - .expect_stampinf(driver_name, &cwd, None) - .expect_inf2cat(driver_name, &cwd, None) - .expect_self_signed_cert_file_exists(&cwd, false) - .expect_certmgr_exists_check(Some(expected_certmgr_output)) - .expect_makecert(&cwd, None) - .expect_copy_self_signed_cert_file_to_package_folder(driver_name, &cwd, true) - .expect_signtool_sign_driver_binary_sys_file(driver_name, &cwd, None) - .expect_signtool_sign_cat_file(driver_name, &cwd, None) - .expect_infverif(driver_name, &cwd, "KMDF", None); - - let build_action = BuildAction::new( - &BuildActionParams { - working_dir: &cwd, - profile: profile.as_ref(), - target_arch, - verify_signature, - is_sample_class: sample_class, - verbosity_level: clap_verbosity_flag::Verbosity::new(1, 0), - }, - test_build_action.mock_wdk_build_provider(), - test_build_action.mock_run_command(), - test_build_action.mock_fs_provider(), - test_build_action.mock_metadata_provider(), + .expect_default_build_task_steps(driver_name) + .expect_default_package_task_steps(driver_name, "KMDF", verify_signature); + + assert_build_action_run_with_env_is_success( + &cwd, + profile, + target_arch, + verify_signature, + sample_class, + test_build_action, ); - assert!(build_action.is_ok()); - let run_result = build_action.expect("Failed to init build action").run(); - assert!(run_result.is_ok()); } #[test] @@ -128,57 +91,19 @@ pub fn given_a_driver_project_when_profile_is_release_then_it_builds_successfull let (workspace_member, package) = get_cargo_metadata_package(&cwd, driver_name, driver_version, Some(wdk_metadata)); - let expected_certmgr_output = Output { - status: ExitStatus::default(), - stdout: r"==============No Certificates ========== - ==============No CTLs ========== - ==============No CRLs ========== - ============================================== - CertMgr Succeeded" - .as_bytes() - .to_vec(), - stderr: vec![], - }; - let test_build_action = &TestBuildAction::new(cwd.clone(), profile, target_arch, sample_class) .set_up_standalone_driver_project((workspace_member, package)) - .expect_detect_wdk_build_number(25100u32) - .expect_root_manifest_exists(&cwd, true) - .expect_cargo_build(driver_name, &cwd, None) - .expect_final_package_dir_exists(driver_name, &cwd, true) - .expect_inx_file_exists(driver_name, &cwd, true) - .expect_rename_driver_binary_dll_to_sys(driver_name, &cwd) - .expect_copy_driver_binary_sys_to_package_folder(driver_name, &cwd, true) - .expect_copy_pdb_file_to_package_folder(driver_name, &cwd, true) - .expect_copy_inx_file_to_package_folder(driver_name, &cwd, true, &cwd) - .expect_copy_map_file_to_package_folder(driver_name, &cwd, true) - .expect_stampinf(driver_name, &cwd, None) - .expect_inf2cat(driver_name, &cwd, None) - .expect_self_signed_cert_file_exists(&cwd, false) - .expect_certmgr_exists_check(Some(expected_certmgr_output)) - .expect_makecert(&cwd, None) - .expect_copy_self_signed_cert_file_to_package_folder(driver_name, &cwd, true) - .expect_signtool_sign_driver_binary_sys_file(driver_name, &cwd, None) - .expect_signtool_sign_cat_file(driver_name, &cwd, None) - .expect_infverif(driver_name, &cwd, "KMDF", None); - - let build_action = BuildAction::new( - &BuildActionParams { - working_dir: &cwd, - profile: profile.as_ref(), - target_arch, - verify_signature, - is_sample_class: sample_class, - verbosity_level: clap_verbosity_flag::Verbosity::new(1, 0), - }, - test_build_action.mock_wdk_build_provider(), - test_build_action.mock_run_command(), - test_build_action.mock_fs_provider(), - test_build_action.mock_metadata_provider(), + .expect_default_build_task_steps(driver_name) + .expect_default_package_task_steps(driver_name, "KMDF", verify_signature); + + assert_build_action_run_with_env_is_success( + &cwd, + profile, + target_arch, + verify_signature, + sample_class, + test_build_action, ); - assert!(build_action.is_ok()); - let run_result = build_action.expect("Failed to init build action").run(); - assert!(run_result.is_ok()); } #[test] @@ -198,57 +123,19 @@ pub fn given_a_driver_project_when_target_arch_is_arm64_then_it_builds_successfu let (workspace_member, package) = get_cargo_metadata_package(&cwd, driver_name, driver_version, Some(wdk_metadata)); - let expected_certmgr_output = Output { - status: ExitStatus::default(), - stdout: r"==============No Certificates ========== - ==============No CTLs ========== - ==============No CRLs ========== - ============================================== - CertMgr Succeeded" - .as_bytes() - .to_vec(), - stderr: vec![], - }; - let test_build_action = &TestBuildAction::new(cwd.clone(), profile, target_arch, sample_class) .set_up_standalone_driver_project((workspace_member, package)) - .expect_detect_wdk_build_number(25100u32) - .expect_root_manifest_exists(&cwd, true) - .expect_cargo_build(driver_name, &cwd, None) - .expect_final_package_dir_exists(driver_name, &cwd, true) - .expect_inx_file_exists(driver_name, &cwd, true) - .expect_rename_driver_binary_dll_to_sys(driver_name, &cwd) - .expect_copy_driver_binary_sys_to_package_folder(driver_name, &cwd, true) - .expect_copy_pdb_file_to_package_folder(driver_name, &cwd, true) - .expect_copy_inx_file_to_package_folder(driver_name, &cwd, true, &cwd) - .expect_copy_map_file_to_package_folder(driver_name, &cwd, true) - .expect_stampinf(driver_name, &cwd, None) - .expect_inf2cat(driver_name, &cwd, None) - .expect_self_signed_cert_file_exists(&cwd, false) - .expect_certmgr_exists_check(Some(expected_certmgr_output)) - .expect_makecert(&cwd, None) - .expect_copy_self_signed_cert_file_to_package_folder(driver_name, &cwd, true) - .expect_signtool_sign_driver_binary_sys_file(driver_name, &cwd, None) - .expect_signtool_sign_cat_file(driver_name, &cwd, None) - .expect_infverif(driver_name, &cwd, "KMDF", None); - - let build_action = BuildAction::new( - &BuildActionParams { - working_dir: &cwd, - profile: profile.as_ref(), - target_arch, - verify_signature, - is_sample_class: sample_class, - verbosity_level: clap_verbosity_flag::Verbosity::new(1, 0), - }, - test_build_action.mock_wdk_build_provider(), - test_build_action.mock_run_command(), - test_build_action.mock_fs_provider(), - test_build_action.mock_metadata_provider(), + .expect_default_build_task_steps(driver_name) + .expect_default_package_task_steps(driver_name, "KMDF", verify_signature); + + assert_build_action_run_with_env_is_success( + &cwd, + profile, + target_arch, + verify_signature, + sample_class, + test_build_action, ); - assert!(build_action.is_ok()); - let run_result = build_action.expect("Failed to init build action").run(); - assert!(run_result.is_ok()); } #[test] @@ -269,57 +156,19 @@ pub fn given_a_driver_project_when_profile_is_release_and_target_arch_is_arm64_t let (workspace_member, package) = get_cargo_metadata_package(&cwd, driver_name, driver_version, Some(wdk_metadata)); - let expected_certmgr_output = Output { - status: ExitStatus::default(), - stdout: r"==============No Certificates ========== - ==============No CTLs ========== - ==============No CRLs ========== - ============================================== - CertMgr Succeeded" - .as_bytes() - .to_vec(), - stderr: vec![], - }; - let test_build_action = &TestBuildAction::new(cwd.clone(), profile, target_arch, sample_class) .set_up_standalone_driver_project((workspace_member, package)) - .expect_detect_wdk_build_number(25100u32) - .expect_root_manifest_exists(&cwd, true) - .expect_cargo_build(driver_name, &cwd, None) - .expect_final_package_dir_exists(driver_name, &cwd, true) - .expect_inx_file_exists(driver_name, &cwd, true) - .expect_rename_driver_binary_dll_to_sys(driver_name, &cwd) - .expect_copy_driver_binary_sys_to_package_folder(driver_name, &cwd, true) - .expect_copy_pdb_file_to_package_folder(driver_name, &cwd, true) - .expect_copy_inx_file_to_package_folder(driver_name, &cwd, true, &cwd) - .expect_copy_map_file_to_package_folder(driver_name, &cwd, true) - .expect_stampinf(driver_name, &cwd, None) - .expect_inf2cat(driver_name, &cwd, None) - .expect_self_signed_cert_file_exists(&cwd, false) - .expect_certmgr_exists_check(Some(expected_certmgr_output)) - .expect_makecert(&cwd, None) - .expect_copy_self_signed_cert_file_to_package_folder(driver_name, &cwd, true) - .expect_signtool_sign_driver_binary_sys_file(driver_name, &cwd, None) - .expect_signtool_sign_cat_file(driver_name, &cwd, None) - .expect_infverif(driver_name, &cwd, "KMDF", None); - - let build_action = BuildAction::new( - &BuildActionParams { - working_dir: &cwd, - profile: profile.as_ref(), - target_arch, - verify_signature, - is_sample_class: sample_class, - verbosity_level: clap_verbosity_flag::Verbosity::new(1, 0), - }, - test_build_action.mock_wdk_build_provider(), - test_build_action.mock_run_command(), - test_build_action.mock_fs_provider(), - test_build_action.mock_metadata_provider(), + .expect_default_build_task_steps(driver_name) + .expect_default_package_task_steps(driver_name, "KMDF", verify_signature); + + assert_build_action_run_with_env_is_success( + &cwd, + profile, + target_arch, + verify_signature, + sample_class, + test_build_action, ); - assert!(build_action.is_ok()); - let run_result = build_action.expect("Failed to init build action").run(); - assert!(run_result.is_ok()); } #[test] @@ -339,59 +188,20 @@ pub fn given_a_driver_project_when_sample_class_is_true_then_it_builds_successfu let (workspace_member, package) = get_cargo_metadata_package(&cwd, driver_name, driver_version, Some(wdk_metadata)); - let expected_certmgr_output = Output { - status: ExitStatus::default(), - stdout: r"==============No Certificates ========== - ==============No CTLs ========== - ==============No CRLs ========== - ============================================== - CertMgr Succeeded" - .as_bytes() - .to_vec(), - stderr: vec![], - }; - let test_build_action = &TestBuildAction::new(cwd.clone(), profile, target_arch, sample_class) .set_up_standalone_driver_project((workspace_member, package)) - .expect_detect_wdk_build_number(25100u32) - .expect_root_manifest_exists(&cwd, true) - .expect_cargo_build(driver_name, &cwd, None) - .expect_final_package_dir_exists(driver_name, &cwd, true) - .expect_inx_file_exists(driver_name, &cwd, true) - .expect_rename_driver_binary_dll_to_sys(driver_name, &cwd) - .expect_copy_driver_binary_sys_to_package_folder(driver_name, &cwd, true) - .expect_copy_pdb_file_to_package_folder(driver_name, &cwd, true) - .expect_copy_inx_file_to_package_folder(driver_name, &cwd, true, &cwd) - .expect_copy_map_file_to_package_folder(driver_name, &cwd, true) - .expect_stampinf(driver_name, &cwd, None) - .expect_inf2cat(driver_name, &cwd, None) - .expect_self_signed_cert_file_exists(&cwd, false) - .expect_certmgr_exists_check(Some(expected_certmgr_output)) - .expect_makecert(&cwd, None) - .expect_copy_self_signed_cert_file_to_package_folder(driver_name, &cwd, true) - .expect_signtool_sign_driver_binary_sys_file(driver_name, &cwd, None) - .expect_signtool_sign_cat_file(driver_name, &cwd, None) - .expect_infverif(driver_name, &cwd, "KMDF", None) + .expect_default_build_task_steps(driver_name) + .expect_default_package_task_steps(driver_name, driver_type, verify_signature) .expect_detect_wdk_build_number(25100u32); - let build_action = BuildAction::new( - &BuildActionParams { - working_dir: &cwd, - profile: profile.as_ref(), - target_arch, - verify_signature, - is_sample_class: sample_class, - verbosity_level: clap_verbosity_flag::Verbosity::new(1, 0), - }, - test_build_action.mock_wdk_build_provider(), - test_build_action.mock_run_command(), - test_build_action.mock_fs_provider(), - test_build_action.mock_metadata_provider(), + assert_build_action_run_with_env_is_success( + &cwd, + profile, + target_arch, + verify_signature, + sample_class, + test_build_action, ); - assert!(build_action.is_ok()); - let run_result = build_action.expect("Failed to init build action").run(); - - assert!(run_result.is_ok()); } #[test] @@ -411,60 +221,19 @@ pub fn given_a_driver_project_when_verify_signature_is_true_then_it_builds_succe let (workspace_member, package) = get_cargo_metadata_package(&cwd, driver_name, driver_version, Some(wdk_metadata)); - let expected_certmgr_output = Output { - status: ExitStatus::default(), - stdout: r"==============No Certificates ========== - ==============No CTLs ========== - ==============No CRLs ========== - ============================================== - CertMgr Succeeded" - .as_bytes() - .to_vec(), - stderr: vec![], - }; - let test_build_action = &TestBuildAction::new(cwd.clone(), profile, target_arch, sample_class) .set_up_standalone_driver_project((workspace_member, package)) - .expect_detect_wdk_build_number(25100u32) - .expect_root_manifest_exists(&cwd, true) - .expect_cargo_build(driver_name, &cwd, None) - .expect_final_package_dir_exists(driver_name, &cwd, true) - .expect_inx_file_exists(driver_name, &cwd, true) - .expect_rename_driver_binary_dll_to_sys(driver_name, &cwd) - .expect_copy_driver_binary_sys_to_package_folder(driver_name, &cwd, true) - .expect_copy_pdb_file_to_package_folder(driver_name, &cwd, true) - .expect_copy_inx_file_to_package_folder(driver_name, &cwd, true, &cwd) - .expect_copy_map_file_to_package_folder(driver_name, &cwd, true) - .expect_stampinf(driver_name, &cwd, None) - .expect_inf2cat(driver_name, &cwd, None) - .expect_self_signed_cert_file_exists(&cwd, false) - .expect_certmgr_exists_check(Some(expected_certmgr_output)) - .expect_makecert(&cwd, None) - .expect_copy_self_signed_cert_file_to_package_folder(driver_name, &cwd, true) - .expect_signtool_sign_driver_binary_sys_file(driver_name, &cwd, None) - .expect_signtool_sign_cat_file(driver_name, &cwd, None) - .expect_signtool_verify_driver_binary_sys_file(driver_name, &cwd, None) - .expect_signtool_verify_cat_file(driver_name, &cwd, None) - .expect_infverif(driver_name, &cwd, "KMDF", None); - - let build_action = BuildAction::new( - &BuildActionParams { - working_dir: &cwd, - profile: profile.as_ref(), - target_arch, - verify_signature, - is_sample_class: sample_class, - verbosity_level: clap_verbosity_flag::Verbosity::new(1, 0), - }, - test_build_action.mock_wdk_build_provider(), - test_build_action.mock_run_command(), - test_build_action.mock_fs_provider(), - test_build_action.mock_metadata_provider(), + .expect_default_build_task_steps(driver_name) + .expect_default_package_task_steps(driver_name, driver_type, verify_signature); + + assert_build_action_run_with_env_is_success( + &cwd, + profile, + target_arch, + verify_signature, + sample_class, + test_build_action, ); - assert!(build_action.is_ok()); - let run_result = build_action.expect("Failed to init build action").run(); - - assert!(run_result.is_ok()); } #[test] @@ -517,9 +286,7 @@ pub fn given_a_driver_project_when_self_signed_exists_then_it_should_skip_callin let test_build_action = &TestBuildAction::new(cwd.clone(), profile, target_arch, sample_class) .set_up_standalone_driver_project((workspace_member, package)) - .expect_detect_wdk_build_number(25100u32) - .expect_root_manifest_exists(&cwd, true) - .expect_cargo_build(driver_name, &cwd, None) + .expect_default_build_task_steps(driver_name) .expect_final_package_dir_exists(driver_name, &cwd, true) .expect_inx_file_exists(driver_name, &cwd, true) .expect_rename_driver_binary_dll_to_sys(driver_name, &cwd) @@ -539,24 +306,14 @@ pub fn given_a_driver_project_when_self_signed_exists_then_it_should_skip_callin .expect_signtool_verify_cat_file(driver_name, &cwd, None) .expect_infverif(driver_name, &cwd, "KMDF", None); - let build_action = BuildAction::new( - &BuildActionParams { - working_dir: &cwd, - profile: profile.as_ref(), - target_arch, - verify_signature, - is_sample_class: sample_class, - verbosity_level: clap_verbosity_flag::Verbosity::new(1, 0), - }, - test_build_action.mock_wdk_build_provider(), - test_build_action.mock_run_command(), - test_build_action.mock_fs_provider(), - test_build_action.mock_metadata_provider(), + assert_build_action_run_with_env_is_success( + &cwd, + profile, + target_arch, + verify_signature, + sample_class, + test_build_action, ); - assert!(build_action.is_ok()); - let run_result = build_action.expect("Failed to init build action").run(); - - assert!(run_result.is_ok()); } #[test] @@ -565,7 +322,7 @@ pub fn given_a_driver_project_when_final_package_dir_exists_then_it_should_skip_ let cwd = PathBuf::from("C:\\tmp"); let profile = None; let target_arch = TargetArch::Default(CpuArchitecture::Amd64); - let verify_signature = true; + let verify_signature = false; let sample_class = false; // Driver project data @@ -575,23 +332,11 @@ pub fn given_a_driver_project_when_final_package_dir_exists_then_it_should_skip_ let wdk_metadata = get_cargo_metadata_wdk_metadata(driver_type, 1, 33); let (workspace_member, package) = get_cargo_metadata_package(&cwd, driver_name, driver_version, Some(wdk_metadata)); - let expected_certmgr_output = Output { - status: ExitStatus::default(), - stdout: r"==============No Certificates ========== - ==============No CTLs ========== - ==============No CRLs ========== - ============================================== - CertMgr Succeeded" - .as_bytes() - .to_vec(), - stderr: vec![], - }; + let expected_certmgr_output = get_certmgr_success_output(); let test_build_action = &TestBuildAction::new(cwd.clone(), profile, target_arch, sample_class) .set_up_standalone_driver_project((workspace_member, package)) - .expect_detect_wdk_build_number(25100u32) - .expect_root_manifest_exists(&cwd, true) - .expect_cargo_build(driver_name, &cwd, None) + .expect_default_build_task_steps(driver_name) .expect_final_package_dir_exists(driver_name, &cwd, false) .expect_dir_created(driver_name, &cwd, true) .expect_inx_file_exists(driver_name, &cwd, true) @@ -608,28 +353,16 @@ pub fn given_a_driver_project_when_final_package_dir_exists_then_it_should_skip_ .expect_copy_self_signed_cert_file_to_package_folder(driver_name, &cwd, true) .expect_signtool_sign_driver_binary_sys_file(driver_name, &cwd, None) .expect_signtool_sign_cat_file(driver_name, &cwd, None) - .expect_signtool_verify_driver_binary_sys_file(driver_name, &cwd, None) - .expect_signtool_verify_cat_file(driver_name, &cwd, None) .expect_infverif(driver_name, &cwd, "KMDF", None); - let build_action = BuildAction::new( - &BuildActionParams { - working_dir: &cwd, - profile: profile.as_ref(), - target_arch, - verify_signature, - is_sample_class: sample_class, - verbosity_level: clap_verbosity_flag::Verbosity::new(1, 0), - }, - test_build_action.mock_wdk_build_provider(), - test_build_action.mock_run_command(), - test_build_action.mock_fs_provider(), - test_build_action.mock_metadata_provider(), + assert_build_action_run_with_env_is_success( + &cwd, + profile, + target_arch, + verify_signature, + sample_class, + test_build_action, ); - assert!(build_action.is_ok()); - let run_result = build_action.expect("Failed to init build action").run(); - - assert!(run_result.is_ok()); } #[test] @@ -651,24 +384,16 @@ pub fn given_a_driver_project_when_inx_file_do_not_exist_then_package_should_fai let test_build_action = &TestBuildAction::new(cwd.clone(), profile, target_arch, sample_class) .set_up_standalone_driver_project((workspace_member, package)) - .expect_detect_wdk_build_number(25100u32) - .expect_root_manifest_exists(&cwd, true) - .expect_cargo_build(driver_name, &cwd, None) + .expect_default_build_task_steps(driver_name) .expect_inx_file_exists(driver_name, &cwd, false); - let build_action = BuildAction::new( - &BuildActionParams { - working_dir: &cwd, - profile: profile.as_ref(), - target_arch, - verify_signature, - is_sample_class: sample_class, - verbosity_level: clap_verbosity_flag::Verbosity::new(1, 0), - }, - test_build_action.mock_wdk_build_provider(), - test_build_action.mock_run_command(), - test_build_action.mock_fs_provider(), - test_build_action.mock_metadata_provider(), + let build_action = initialize_build_action( + &cwd, + profile.as_ref(), + target_arch, + verify_signature, + sample_class, + test_build_action, ); assert!(build_action.is_ok()); let run_result = build_action.expect("Failed to init build action").run(); @@ -698,27 +423,19 @@ pub fn given_a_driver_project_when_copy_of_an_artifact_fails_then_the_package_sh let test_build_action = &TestBuildAction::new(cwd.clone(), profile, target_arch, sample_class) .set_up_standalone_driver_project((workspace_member, package)) - .expect_detect_wdk_build_number(25100u32) - .expect_root_manifest_exists(&cwd, true) - .expect_cargo_build(driver_name, &cwd, None) + .expect_default_build_task_steps(driver_name) .expect_final_package_dir_exists(driver_name, &cwd, true) .expect_inx_file_exists(driver_name, &cwd, true) .expect_rename_driver_binary_dll_to_sys(driver_name, &cwd) .expect_copy_driver_binary_sys_to_package_folder(driver_name, &cwd, false); - let build_action = BuildAction::new( - &BuildActionParams { - working_dir: &cwd, - profile: profile.as_ref(), - target_arch, - verify_signature, - is_sample_class: sample_class, - verbosity_level: clap_verbosity_flag::Verbosity::new(1, 0), - }, - test_build_action.mock_wdk_build_provider(), - test_build_action.mock_run_command(), - test_build_action.mock_fs_provider(), - test_build_action.mock_metadata_provider(), + let build_action = initialize_build_action( + &cwd, + profile.as_ref(), + target_arch, + verify_signature, + sample_class, + test_build_action, ); assert!(build_action.is_ok()); let run_result = build_action.expect("Failed to init build action").run(); @@ -754,9 +471,7 @@ pub fn given_a_driver_project_when_stampinf_command_execution_fails_then_package let test_build_action = &TestBuildAction::new(cwd.clone(), profile, target_arch, sample_class) .set_up_standalone_driver_project((workspace_member, package)) - .expect_detect_wdk_build_number(25100u32) - .expect_root_manifest_exists(&cwd, true) - .expect_cargo_build(driver_name, &cwd, None) + .expect_default_build_task_steps(driver_name) .expect_final_package_dir_exists(driver_name, &cwd, true) .expect_inx_file_exists(driver_name, &cwd, true) .expect_rename_driver_binary_dll_to_sys(driver_name, &cwd) @@ -766,22 +481,16 @@ pub fn given_a_driver_project_when_stampinf_command_execution_fails_then_package .expect_copy_map_file_to_package_folder(driver_name, &cwd, true) .expect_stampinf(driver_name, &cwd, Some(expected_stampinf_output)); - let build_action = BuildAction::new( - &BuildActionParams { - working_dir: &cwd, - profile: profile.as_ref(), - target_arch, - verify_signature, - is_sample_class: sample_class, - verbosity_level: clap_verbosity_flag::Verbosity::new(1, 0), - }, - test_build_action.mock_wdk_build_provider(), - test_build_action.mock_run_command(), - test_build_action.mock_fs_provider(), - test_build_action.mock_metadata_provider(), + let build_action = initialize_build_action( + &cwd, + profile.as_ref(), + target_arch, + verify_signature, + sample_class, + test_build_action, ); assert!(build_action.is_ok()); - let run_result = build_action.expect("Failed to init build action").run(); + let run_result = run_build_action(build_action); assert!(matches!( run_result.as_ref().expect_err("expected error"), @@ -814,9 +523,7 @@ pub fn given_a_driver_project_when_inf2cat_command_execution_fails_then_package_ let test_build_action = &TestBuildAction::new(cwd.clone(), profile, target_arch, sample_class) .set_up_standalone_driver_project((workspace_member, package)) - .expect_detect_wdk_build_number(25100u32) - .expect_root_manifest_exists(&cwd, true) - .expect_cargo_build(driver_name, &cwd, None) + .expect_default_build_task_steps(driver_name) .expect_final_package_dir_exists(driver_name, &cwd, true) .expect_inx_file_exists(driver_name, &cwd, true) .expect_rename_driver_binary_dll_to_sys(driver_name, &cwd) @@ -827,22 +534,16 @@ pub fn given_a_driver_project_when_inf2cat_command_execution_fails_then_package_ .expect_stampinf(driver_name, &cwd, None) .expect_inf2cat(driver_name, &cwd, Some(expected_inf2cat_output)); - let build_action = BuildAction::new( - &BuildActionParams { - working_dir: &cwd, - profile: profile.as_ref(), - target_arch, - verify_signature, - is_sample_class: sample_class, - verbosity_level: clap_verbosity_flag::Verbosity::new(1, 0), - }, - test_build_action.mock_wdk_build_provider(), - test_build_action.mock_run_command(), - test_build_action.mock_fs_provider(), - test_build_action.mock_metadata_provider(), + let build_action = initialize_build_action( + &cwd, + profile.as_ref(), + target_arch, + verify_signature, + sample_class, + test_build_action, ); assert!(build_action.is_ok()); - let run_result = build_action.expect("Failed to init build action").run(); + let run_result = run_build_action(build_action); assert!(matches!( run_result.as_ref().expect_err("expected error"), @@ -875,9 +576,7 @@ pub fn given_a_driver_project_when_certmgr_command_execution_fails_then_package_ let test_build_action = &TestBuildAction::new(cwd.clone(), profile, target_arch, sample_class) .set_up_standalone_driver_project((workspace_member, package)) - .expect_detect_wdk_build_number(25100u32) - .expect_root_manifest_exists(&cwd, true) - .expect_cargo_build(driver_name, &cwd, None) + .expect_default_build_task_steps(driver_name) .expect_final_package_dir_exists(driver_name, &cwd, true) .expect_inx_file_exists(driver_name, &cwd, true) .expect_rename_driver_binary_dll_to_sys(driver_name, &cwd) @@ -890,22 +589,16 @@ pub fn given_a_driver_project_when_certmgr_command_execution_fails_then_package_ .expect_self_signed_cert_file_exists(&cwd, false) .expect_certmgr_exists_check(Some(expected_output)); - let build_action = BuildAction::new( - &BuildActionParams { - working_dir: &cwd, - profile: profile.as_ref(), - target_arch, - verify_signature, - is_sample_class: sample_class, - verbosity_level: clap_verbosity_flag::Verbosity::new(1, 0), - }, - test_build_action.mock_wdk_build_provider(), - test_build_action.mock_run_command(), - test_build_action.mock_fs_provider(), - test_build_action.mock_metadata_provider(), + let build_action = initialize_build_action( + &cwd, + profile.as_ref(), + target_arch, + verify_signature, + sample_class, + test_build_action, ); assert!(build_action.is_ok()); - let run_result = build_action.expect("Failed to init build action").run(); + let run_result = run_build_action(build_action); assert!(matches!( run_result.as_ref().expect_err("expected error"), @@ -938,9 +631,7 @@ pub fn given_a_driver_project_when_makecert_command_execution_fails_then_package let test_build_action = &TestBuildAction::new(cwd.clone(), profile, target_arch, sample_class) .set_up_standalone_driver_project((workspace_member, package)) - .expect_detect_wdk_build_number(25100u32) - .expect_root_manifest_exists(&cwd, true) - .expect_cargo_build(driver_name, &cwd, None) + .expect_default_build_task_steps(driver_name) .expect_final_package_dir_exists(driver_name, &cwd, true) .expect_inx_file_exists(driver_name, &cwd, true) .expect_rename_driver_binary_dll_to_sys(driver_name, &cwd) @@ -954,22 +645,16 @@ pub fn given_a_driver_project_when_makecert_command_execution_fails_then_package .expect_certmgr_exists_check(None) .expect_makecert(&cwd, Some(expected_output)); - let build_action = BuildAction::new( - &BuildActionParams { - working_dir: &cwd, - profile: profile.as_ref(), - target_arch, - verify_signature, - is_sample_class: sample_class, - verbosity_level: clap_verbosity_flag::Verbosity::new(1, 0), - }, - test_build_action.mock_wdk_build_provider(), - test_build_action.mock_run_command(), - test_build_action.mock_fs_provider(), - test_build_action.mock_metadata_provider(), + let build_action = initialize_build_action( + &cwd, + profile.as_ref(), + target_arch, + verify_signature, + sample_class, + test_build_action, ); assert!(build_action.is_ok()); - let run_result = build_action.expect("Failed to init build action").run(); + let run_result = run_build_action(build_action); assert!(matches!( run_result.as_ref().expect_err("expected error"), @@ -1002,9 +687,7 @@ pub fn given_a_driver_project_when_signtool_command_execution_fails_then_package let test_build_action = &TestBuildAction::new(cwd.clone(), profile, target_arch, sample_class) .set_up_standalone_driver_project((workspace_member, package)) - .expect_detect_wdk_build_number(25100u32) - .expect_root_manifest_exists(&cwd, true) - .expect_cargo_build(driver_name, &cwd, None) + .expect_default_build_task_steps(driver_name) .expect_final_package_dir_exists(driver_name, &cwd, true) .expect_inx_file_exists(driver_name, &cwd, true) .expect_rename_driver_binary_dll_to_sys(driver_name, &cwd) @@ -1020,22 +703,16 @@ pub fn given_a_driver_project_when_signtool_command_execution_fails_then_package .expect_copy_self_signed_cert_file_to_package_folder(driver_name, &cwd, true) .expect_signtool_sign_driver_binary_sys_file(driver_name, &cwd, Some(expected_output)); - let build_action = BuildAction::new( - &BuildActionParams { - working_dir: &cwd, - profile: profile.as_ref(), - target_arch, - verify_signature, - is_sample_class: sample_class, - verbosity_level: clap_verbosity_flag::Verbosity::new(1, 0), - }, - test_build_action.mock_wdk_build_provider(), - test_build_action.mock_run_command(), - test_build_action.mock_fs_provider(), - test_build_action.mock_metadata_provider(), + let build_action = initialize_build_action( + &cwd, + profile.as_ref(), + target_arch, + verify_signature, + sample_class, + test_build_action, ); assert!(build_action.is_ok()); - let run_result = build_action.expect("Failed to init build action").run(); + let run_result = run_build_action(build_action); assert!(matches!( run_result.as_ref().expect_err("expected error"), @@ -1068,9 +745,7 @@ pub fn given_a_driver_project_when_infverif_command_execution_fails_then_package let test_build_action = &TestBuildAction::new(cwd.clone(), profile, target_arch, sample_class) .set_up_standalone_driver_project((workspace_member, package)) - .expect_detect_wdk_build_number(25100u32) - .expect_root_manifest_exists(&cwd, true) - .expect_cargo_build(driver_name, &cwd, None) + .expect_default_build_task_steps(driver_name) .expect_final_package_dir_exists(driver_name, &cwd, true) .expect_inx_file_exists(driver_name, &cwd, true) .expect_rename_driver_binary_dll_to_sys(driver_name, &cwd) @@ -1088,22 +763,16 @@ pub fn given_a_driver_project_when_infverif_command_execution_fails_then_package .expect_signtool_sign_cat_file(driver_name, &cwd, None) .expect_infverif(driver_name, &cwd, "KMDF", Some(expected_output)); - let build_action = BuildAction::new( - &BuildActionParams { - working_dir: &cwd, - profile: profile.as_ref(), - target_arch, - verify_signature, - is_sample_class: sample_class, - verbosity_level: clap_verbosity_flag::Verbosity::new(1, 0), - }, - test_build_action.mock_wdk_build_provider(), - test_build_action.mock_run_command(), - test_build_action.mock_fs_provider(), - test_build_action.mock_metadata_provider(), + let build_action = initialize_build_action( + &cwd, + profile.as_ref(), + target_arch, + verify_signature, + sample_class, + test_build_action, ); assert!(build_action.is_ok()); - let run_result = build_action.expect("Failed to init build action").run(); + let run_result = run_build_action(build_action); assert!(matches!( run_result.as_ref().expect_err("expected error"), @@ -1129,28 +798,16 @@ pub fn given_a_non_driver_project_when_default_values_are_provided_with_no_wdk_m let test_build_action = &TestBuildAction::new(cwd.clone(), profile, target_arch, sample_class) .set_up_standalone_driver_project((workspace_member, package)) - .expect_detect_wdk_build_number(25100u32) - .expect_root_manifest_exists(&cwd, true) - .expect_cargo_build(driver_name, &cwd, None); - - let build_action = BuildAction::new( - &BuildActionParams { - working_dir: &cwd, - profile: profile.as_ref(), - target_arch, - verify_signature, - is_sample_class: sample_class, - verbosity_level: clap_verbosity_flag::Verbosity::new(1, 0), - }, - test_build_action.mock_wdk_build_provider(), - test_build_action.mock_run_command(), - test_build_action.mock_fs_provider(), - test_build_action.mock_metadata_provider(), + .expect_default_build_task_steps(driver_name); + + assert_build_action_run_is_success( + &cwd, + profile, + target_arch, + verify_signature, + sample_class, + test_build_action, ); - assert!(build_action.is_ok()); - let run_result = build_action.expect("Failed to init build action").run(); - - assert!(run_result.is_ok()); } #[test] @@ -1169,23 +826,15 @@ pub fn given_a_invalid_driver_project_with_partial_wdk_metadata_when_valid_defau let test_build_action = &TestBuildAction::new(cwd.clone(), profile, target_arch, sample_class) .set_up_with_custom_toml(&cargo_toml_metadata) - .expect_detect_wdk_build_number(25100u32) - .expect_root_manifest_exists(&cwd, true) - .expect_cargo_build(driver_name, &cwd, None); - - let build_action = BuildAction::new( - &BuildActionParams { - working_dir: &cwd, - profile: profile.as_ref(), - target_arch, - verify_signature, - is_sample_class: sample_class, - verbosity_level: clap_verbosity_flag::Verbosity::new(1, 0), - }, - test_build_action.mock_wdk_build_provider(), - test_build_action.mock_run_command(), - test_build_action.mock_fs_provider(), - test_build_action.mock_metadata_provider(), + .expect_default_build_task_steps(driver_name); + + let build_action = initialize_build_action( + &cwd, + profile.as_ref(), + target_arch, + verify_signature, + sample_class, + test_build_action, ); assert!(build_action.is_ok()); let run_result = build_action.expect("Failed to init build action").run(); @@ -1235,18 +884,6 @@ pub fn given_a_workspace_with_multiple_driver_and_non_driver_projects_when_defau let (workspace_member_3, package_3) = get_cargo_metadata_package(&cwd.join(non_driver), non_driver, non_driver_version, None); - let expected_certmgr_output = Output { - status: ExitStatus::default(), - stdout: r"==============No Certificates ========== - ==============No CTLs ========== - ==============No CRLs ========== - ============================================== - CertMgr Succeeded" - .as_bytes() - .to_vec(), - stderr: vec![], - }; - let test_build_action = &TestBuildAction::new(cwd.clone(), profile, target_arch, sample_class) .set_up_workspace_with_multiple_driver_projects( &cwd, @@ -1260,65 +897,29 @@ pub fn given_a_workspace_with_multiple_driver_and_non_driver_projects_when_defau .expect_detect_wdk_build_number(25100u32) .expect_root_manifest_exists(&cwd, true) .expect_cargo_build(driver_name_1, &cwd.join(driver_name_1), None) - .expect_final_package_dir_exists(driver_name_1, &cwd, true) - .expect_inx_file_exists(driver_name_1, &cwd.join(driver_name_1), true) - .expect_rename_driver_binary_dll_to_sys(driver_name_1, &cwd) - .expect_copy_driver_binary_sys_to_package_folder(driver_name_1, &cwd, true) - .expect_copy_pdb_file_to_package_folder(driver_name_1, &cwd, true) - .expect_copy_inx_file_to_package_folder(driver_name_1, &cwd.join(driver_name_1), true, &cwd) - .expect_copy_map_file_to_package_folder(driver_name_1, &cwd, true) - .expect_stampinf(driver_name_1, &cwd, None) - .expect_inf2cat(driver_name_1, &cwd, None) - .expect_self_signed_cert_file_exists(&cwd, false) - .expect_certmgr_exists_check(Some(expected_certmgr_output.clone())) - .expect_makecert(&cwd, None) - .expect_copy_self_signed_cert_file_to_package_folder(driver_name_1, &cwd, true) - .expect_signtool_sign_driver_binary_sys_file(driver_name_1, &cwd, None) - .expect_signtool_sign_cat_file(driver_name_1, &cwd, None) - .expect_signtool_verify_driver_binary_sys_file(driver_name_1, &cwd, None) - .expect_signtool_verify_cat_file(driver_name_1, &cwd, None) - .expect_infverif(driver_name_1, &cwd, "KMDF", None) + .expect_default_package_task_steps_for_workspace( + driver_name_1, + driver_type, + verify_signature, + ) // Second driver project .expect_cargo_build(driver_name_2, &cwd.join(driver_name_2), None) - .expect_final_package_dir_exists(driver_name_2, &cwd, true) - .expect_inx_file_exists(driver_name_2, &cwd.join(driver_name_2), true) - .expect_rename_driver_binary_dll_to_sys(driver_name_2, &cwd) - .expect_copy_driver_binary_sys_to_package_folder(driver_name_2, &cwd, true) - .expect_copy_pdb_file_to_package_folder(driver_name_2, &cwd, true) - .expect_copy_inx_file_to_package_folder(driver_name_2, &cwd.join(driver_name_2), true, &cwd) - .expect_copy_map_file_to_package_folder(driver_name_2, &cwd, true) - .expect_stampinf(driver_name_2, &cwd, None) - .expect_inf2cat(driver_name_2, &cwd, None) - .expect_self_signed_cert_file_exists(&cwd, false) - .expect_certmgr_exists_check(Some(expected_certmgr_output)) - .expect_makecert(&cwd, None) - .expect_copy_self_signed_cert_file_to_package_folder(driver_name_2, &cwd, true) - .expect_signtool_sign_driver_binary_sys_file(driver_name_2, &cwd, None) - .expect_signtool_sign_cat_file(driver_name_2, &cwd, None) - .expect_signtool_verify_driver_binary_sys_file(driver_name_2, &cwd, None) - .expect_signtool_verify_cat_file(driver_name_2, &cwd, None) - .expect_infverif(driver_name_2, &cwd, "KMDF", None) + .expect_default_package_task_steps_for_workspace( + driver_name_2, + driver_type, + verify_signature, + ) // Non-driver project .expect_cargo_build(non_driver, &cwd.join(non_driver), None); - let build_action = BuildAction::new( - &BuildActionParams { - working_dir: &cwd, - profile: profile.as_ref(), - target_arch, - verify_signature, - is_sample_class: sample_class, - verbosity_level: clap_verbosity_flag::Verbosity::new(1, 0), - }, - test_build_action.mock_wdk_build_provider(), - test_build_action.mock_run_command(), - test_build_action.mock_fs_provider(), - test_build_action.mock_metadata_provider(), + assert_build_action_run_with_env_is_success( + &cwd, + profile, + target_arch, + verify_signature, + sample_class, + test_build_action, ); - assert!(build_action.is_ok()); - let run_result = build_action.expect("Failed to init build action").run(); - - assert!(run_result.is_ok()); } #[test] @@ -1360,17 +961,7 @@ pub fn given_a_workspace_with_multiple_driver_and_non_driver_projects_when_cwd_i None, ); - let expected_certmgr_output = Output { - status: ExitStatus::default(), - stdout: r"==============No Certificates ========== - ==============No CTLs ========== - ==============No CRLs ========== - ============================================== - CertMgr Succeeded" - .as_bytes() - .to_vec(), - stderr: vec![], - }; + let expected_certmgr_output = get_certmgr_success_output(); let test_build_action = &TestBuildAction::new(cwd.clone(), profile, target_arch, sample_class) // Even when cwd is changed to driver project inside the workspace, cargo metadata read is // going to be for the whole workspace @@ -1409,24 +1000,14 @@ pub fn given_a_workspace_with_multiple_driver_and_non_driver_projects_when_cwd_i .expect_signtool_verify_cat_file(driver_name_1, &workspace_root_dir, None) .expect_infverif(driver_name_1, &workspace_root_dir, "KMDF", None); - let build_action = BuildAction::new( - &BuildActionParams { - working_dir: &cwd, - profile: profile.as_ref(), - target_arch, - verify_signature, - is_sample_class: sample_class, - verbosity_level: clap_verbosity_flag::Verbosity::new(1, 0), - }, - test_build_action.mock_wdk_build_provider(), - test_build_action.mock_run_command(), - test_build_action.mock_fs_provider(), - test_build_action.mock_metadata_provider(), + assert_build_action_run_with_env_is_success( + &cwd, + profile, + target_arch, + verify_signature, + sample_class, + test_build_action, ); - assert!(build_action.is_ok()); - let run_result = build_action.expect("Failed to init build action").run(); - - assert!(run_result.is_ok()); } #[test] @@ -1463,18 +1044,6 @@ pub fn given_a_workspace_with_multiple_driver_and_non_driver_projects_when_verif let (workspace_member_3, package_3) = get_cargo_metadata_package(&cwd.join(non_driver), non_driver, non_driver_version, None); - let expected_certmgr_output = Output { - status: ExitStatus::default(), - stdout: r"==============No Certificates ========== - ==============No CTLs ========== - ==============No CRLs ========== - ============================================== - CertMgr Succeeded" - .as_bytes() - .to_vec(), - stderr: vec![], - }; - let test_build_action = &TestBuildAction::new(cwd.clone(), profile, target_arch, sample_class) .set_up_workspace_with_multiple_driver_projects( &cwd, @@ -1488,61 +1057,29 @@ pub fn given_a_workspace_with_multiple_driver_and_non_driver_projects_when_verif .expect_detect_wdk_build_number(25100u32) .expect_root_manifest_exists(&cwd, true) .expect_cargo_build(driver_name_1, &cwd.join(driver_name_1), None) - .expect_final_package_dir_exists(driver_name_1, &cwd, true) - .expect_inx_file_exists(driver_name_1, &cwd.join(driver_name_1), true) - .expect_rename_driver_binary_dll_to_sys(driver_name_1, &cwd) - .expect_copy_driver_binary_sys_to_package_folder(driver_name_1, &cwd, true) - .expect_copy_pdb_file_to_package_folder(driver_name_1, &cwd, true) - .expect_copy_inx_file_to_package_folder(driver_name_1, &cwd.join(driver_name_1), true, &cwd) - .expect_copy_map_file_to_package_folder(driver_name_1, &cwd, true) - .expect_stampinf(driver_name_1, &cwd, None) - .expect_inf2cat(driver_name_1, &cwd, None) - .expect_self_signed_cert_file_exists(&cwd, false) - .expect_certmgr_exists_check(Some(expected_certmgr_output.clone())) - .expect_makecert(&cwd, None) - .expect_copy_self_signed_cert_file_to_package_folder(driver_name_1, &cwd, true) - .expect_signtool_sign_driver_binary_sys_file(driver_name_1, &cwd, None) - .expect_signtool_sign_cat_file(driver_name_1, &cwd, None) - .expect_infverif(driver_name_1, &cwd, "KMDF", None) + .expect_default_package_task_steps_for_workspace( + driver_name_1, + driver_type, + verify_signature, + ) // Second driver project .expect_cargo_build(driver_name_2, &cwd.join(driver_name_2), None) - .expect_final_package_dir_exists(driver_name_2, &cwd, true) - .expect_inx_file_exists(driver_name_2, &cwd.join(driver_name_2), true) - .expect_rename_driver_binary_dll_to_sys(driver_name_2, &cwd) - .expect_copy_driver_binary_sys_to_package_folder(driver_name_2, &cwd, true) - .expect_copy_pdb_file_to_package_folder(driver_name_2, &cwd, true) - .expect_copy_inx_file_to_package_folder(driver_name_2, &cwd.join(driver_name_2), true, &cwd) - .expect_copy_map_file_to_package_folder(driver_name_2, &cwd, true) - .expect_stampinf(driver_name_2, &cwd, None) - .expect_inf2cat(driver_name_2, &cwd, None) - .expect_self_signed_cert_file_exists(&cwd, false) - .expect_certmgr_exists_check(Some(expected_certmgr_output)) - .expect_makecert(&cwd, None) - .expect_copy_self_signed_cert_file_to_package_folder(driver_name_2, &cwd, true) - .expect_signtool_sign_driver_binary_sys_file(driver_name_2, &cwd, None) - .expect_signtool_sign_cat_file(driver_name_2, &cwd, None) - .expect_infverif(driver_name_2, &cwd, "KMDF", None) + .expect_default_package_task_steps_for_workspace( + driver_name_2, + driver_type, + verify_signature, + ) // Non-driver project .expect_cargo_build(non_driver, &cwd.join(non_driver), None); - let build_action = BuildAction::new( - &BuildActionParams { - working_dir: &cwd, - profile: profile.as_ref(), - target_arch, - verify_signature, - is_sample_class: sample_class, - verbosity_level: clap_verbosity_flag::Verbosity::new(1, 0), - }, - test_build_action.mock_wdk_build_provider(), - test_build_action.mock_run_command(), - test_build_action.mock_fs_provider(), - test_build_action.mock_metadata_provider(), + assert_build_action_run_with_env_is_success( + &cwd, + profile, + target_arch, + verify_signature, + sample_class, + test_build_action, ); - assert!(build_action.is_ok()); - let run_result = build_action.expect("Failed to init build action").run(); - - assert!(run_result.is_ok()); } #[test] @@ -1599,24 +1136,14 @@ pub fn given_a_workspace_with_multiple_driver_and_non_driver_projects_when_cwd_i .expect_root_manifest_exists(&cwd, true) .expect_cargo_build(non_driver, &cwd, None); - let build_action = BuildAction::new( - &BuildActionParams { - working_dir: &cwd, - profile: profile.as_ref(), - target_arch, - verify_signature, - is_sample_class: sample_class, - verbosity_level: clap_verbosity_flag::Verbosity::new(1, 0), - }, - test_build_action.mock_wdk_build_provider(), - test_build_action.mock_run_command(), - test_build_action.mock_fs_provider(), - test_build_action.mock_metadata_provider(), + assert_build_action_run_is_success( + &cwd, + profile, + target_arch, + verify_signature, + sample_class, + test_build_action, ); - assert!(build_action.is_ok()); - let run_result = build_action.expect("Failed to init build action").run(); - - assert!(run_result.is_ok()); } #[test] @@ -1665,19 +1192,13 @@ pub fn given_a_workspace_with_multiple_distinct_wdk_configurations_at_each_works .expect_cargo_build(driver_name_1, &cwd.join(driver_name_1), None) .expect_cargo_build(driver_name_2, &cwd.join(driver_name_2), None); - let build_action = BuildAction::new( - &BuildActionParams { - working_dir: &cwd, - profile: profile.as_ref(), - target_arch, - verify_signature, - is_sample_class: sample_class, - verbosity_level: clap_verbosity_flag::Verbosity::new(1, 0), - }, - test_build_action.mock_wdk_build_provider(), - test_build_action.mock_run_command(), - test_build_action.mock_fs_provider(), - test_build_action.mock_metadata_provider(), + let build_action = initialize_build_action( + &cwd, + profile.as_ref(), + target_arch, + verify_signature, + sample_class, + test_build_action, ); assert!(build_action.is_ok()); let run_result = build_action.expect("Failed to init build action").run(); @@ -1738,19 +1259,13 @@ pub fn given_a_workspace_with_multiple_distinct_wdk_configurations_at_root_and_w .expect_cargo_build(driver_name_1, &cwd.join(driver_name_1), None) .expect_cargo_build(driver_name_2, &cwd.join(driver_name_2), None); - let build_action = BuildAction::new( - &BuildActionParams { - working_dir: &cwd, - profile: profile.as_ref(), - target_arch, - verify_signature, - is_sample_class: sample_class, - verbosity_level: clap_verbosity_flag::Verbosity::new(1, 0), - }, - test_build_action.mock_wdk_build_provider(), - test_build_action.mock_run_command(), - test_build_action.mock_fs_provider(), - test_build_action.mock_metadata_provider(), + let build_action = initialize_build_action( + &cwd, + profile.as_ref(), + target_arch, + verify_signature, + sample_class, + test_build_action, ); assert!(build_action.is_ok()); let run_result = build_action.expect("Failed to init build action").run(); @@ -1792,24 +1307,14 @@ pub fn given_a_workspace_only_with_non_driver_projects_when_cwd_is_workspace_roo .expect_detect_wdk_build_number(25100u32) .expect_cargo_build(non_driver, &cwd.join(non_driver), None); - let build_action = BuildAction::new( - &BuildActionParams { - working_dir: &cwd, - profile: profile.as_ref(), - target_arch, - verify_signature, - is_sample_class: sample_class, - verbosity_level: clap_verbosity_flag::Verbosity::new(1, 0), - }, - test_build_action.mock_wdk_build_provider(), - test_build_action.mock_run_command(), - test_build_action.mock_fs_provider(), - test_build_action.mock_metadata_provider(), + assert_build_action_run_is_success( + &cwd, + profile, + target_arch, + verify_signature, + sample_class, + test_build_action, ); - assert!(build_action.is_ok()); - let run_result = build_action.expect("Failed to init build action").run(); - - assert!(run_result.is_ok()); } #[test] @@ -1844,10 +1349,49 @@ pub fn given_a_workspace_only_with_non_driver_projects_when_cwd_is_workspace_mem .expect_detect_wdk_build_number(25100u32) .expect_cargo_build(non_driver, &cwd, None); - let build_action = BuildAction::new( + assert_build_action_run_is_success( + &cwd, + profile, + target_arch, + verify_signature, + sample_class, + test_build_action, + ); +} + +fn assert_build_action_run_is_success( + cwd: &PathBuf, + profile: Option, + target_arch: TargetArch, + verify_signature: bool, + sample_class: bool, + test_build_action: &TestBuildAction, +) { + let build_action = initialize_build_action( + cwd, + profile.as_ref(), + target_arch, + verify_signature, + sample_class, + test_build_action, + ); + assert!(build_action.is_ok()); + let run_result = build_action.expect("Failed to init build action").run(); + assert!(run_result.is_ok()); +} + +fn initialize_build_action<'a>( + cwd: &'a PathBuf, + profile: Option<&'a Profile>, + target_arch: TargetArch, + verify_signature: bool, + sample_class: bool, + test_build_action: &'a TestBuildAction, +) -> Result, anyhow::Error> { + BuildAction::new( &BuildActionParams { - working_dir: &cwd, - profile: profile.as_ref(), + working_dir: cwd, + profile, target_arch, verify_signature, is_sample_class: sample_class, @@ -1857,13 +1401,51 @@ pub fn given_a_workspace_only_with_non_driver_projects_when_cwd_is_workspace_mem test_build_action.mock_run_command(), test_build_action.mock_fs_provider(), test_build_action.mock_metadata_provider(), + ) +} + +fn get_certmgr_success_output() -> Output { + Output { + status: ExitStatus::default(), + stdout: r"==============No Certificates ========== + ==============No CTLs ========== + ==============No CRLs ========== + ============================================== + CertMgr Succeeded" + .as_bytes() + .to_vec(), + stderr: vec![], + } +} + +fn assert_build_action_run_with_env_is_success( + cwd: &PathBuf, + profile: Option, + target_arch: TargetArch, + verify_signature: bool, + sample_class: bool, + test_build_action: &TestBuildAction, +) { + let build_action = initialize_build_action( + cwd, + profile.as_ref(), + target_arch, + verify_signature, + sample_class, + test_build_action, ); assert!(build_action.is_ok()); - let run_result = build_action.expect("Failed to init build action").run(); - + let run_result = run_build_action(build_action); assert!(run_result.is_ok()); } +fn run_build_action( + build_action: Result, anyhow::Error>, +) -> Result<(), BuildActionError> { + let build_action = build_action.expect("Failed to init build action"); + crate::test_utils::with_env::<&str, &str, _, _>(&[], || build_action.run()) +} + /// Helper functions //////////////////////////////////////////////////////////////////////////////// struct TestBuildAction { @@ -1880,121 +1462,6 @@ struct TestBuildAction { mock_metadata_provider: MetadataProvider, } -// Presence of method ensures specific mock expectation is set -// Dir argument in any method means to operate on the relevant dir -// Output argument in any method means to override return output from default -// success with no stdout/stderr -trait TestSetupPackageExpectations { - fn expect_root_manifest_exists(self, root_dir: &Path, does_exist: bool) -> Self; - fn expect_self_signed_cert_file_exists(self, driver_dir: &Path, does_exist: bool) -> Self; - fn expect_final_package_dir_exists( - self, - driver_name: &str, - driver_dir: &Path, - does_exist: bool, - ) -> Self; - fn expect_dir_created(self, driver_name: &str, driver_dir: &Path, created: bool) -> Self; - fn expect_cargo_build( - self, - driver_name: &str, - driver_dir: &Path, - override_output: Option, - ) -> Self; - fn expect_inx_file_exists(self, driver_name: &str, driver_dir: &Path, does_exist: bool) - -> Self; - fn expect_rename_driver_binary_dll_to_sys(self, driver_name: &str, driver_dir: &Path) -> Self; - fn expect_copy_driver_binary_sys_to_package_folder( - self, - driver_name: &str, - driver_dir: &Path, - is_success: bool, - ) -> Self; - fn expect_copy_pdb_file_to_package_folder( - self, - driver_name: &str, - driver_dir: &Path, - is_success: bool, - ) -> Self; - fn expect_copy_inx_file_to_package_folder( - self, - driver_name: &str, - driver_dir: &Path, - is_success: bool, - workspace_root_dir: &Path, - ) -> Self; - fn expect_copy_map_file_to_package_folder( - self, - driver_name: &str, - driver_dir: &Path, - is_success: bool, - ) -> Self; - fn expect_copy_self_signed_cert_file_to_package_folder( - self, - driver_name: &str, - driver_dir: &Path, - is_success: bool, - ) -> Self; - - fn expect_stampinf( - self, - driver_name: &str, - driver_dir: &Path, - override_output: Option, - ) -> Self; - fn expect_inf2cat( - self, - driver_name: &str, - driver_dir: &Path, - override_output: Option, - ) -> Self; - fn expect_certmgr_exists_check(self, override_output: Option) -> Self; - fn expect_certmgr_create_cert_from_store( - self, - driver_dir: &Path, - override_output: Option, - ) -> Self; - fn expect_makecert(self, driver_dir: &Path, override_output: Option) -> Self; - - fn expect_signtool_sign_driver_binary_sys_file( - self, - driver_name: &str, - driver_dir: &Path, - override_output: Option, - ) -> Self; - fn expect_signtool_sign_cat_file( - self, - driver_name: &str, - driver_dir: &Path, - override_output: Option, - ) -> Self; - fn expect_signtool_verify_driver_binary_sys_file( - self, - driver_name: &str, - driver_dir: &Path, - override_output: Option, - ) -> Self; - fn expect_signtool_verify_cat_file( - self, - driver_name: &str, - driver_dir: &Path, - override_output: Option, - ) -> Self; - - fn expect_detect_wdk_build_number(self, expected_wdk_build_number: u32) -> Self; - fn expect_infverif( - self, - driver_name: &str, - driver_dir: &Path, - driver_type: &str, - override_output: Option, - ) -> Self; - - fn mock_wdk_build_provider(&self) -> &WdkBuild; - fn mock_run_command(&self) -> &CommandExec; - fn mock_fs_provider(&self) -> &Fs; - fn mock_metadata_provider(&self) -> &MetadataProvider; -} - impl TestBuildAction { fn new( cwd: PathBuf, @@ -2023,7 +1490,7 @@ impl TestBuildAction { fn set_up_standalone_driver_project( mut self, package_metadata: (TestMetadataWorkspaceMemberId, TestMetadataPackage), - ) -> impl TestSetupPackageExpectations { + ) -> Self { let cargo_toml_metadata = get_cargo_metadata( &self.cwd, vec![package_metadata.1], @@ -2047,7 +1514,7 @@ impl TestBuildAction { workspace_root_dir: &Path, workspace_additional_metadata: Option, package_metadata_list: Vec<(TestMetadataWorkspaceMemberId, TestMetadataPackage)>, - ) -> impl TestSetupPackageExpectations { + ) -> Self { let cargo_toml_metadata = get_cargo_metadata( workspace_root_dir, package_metadata_list.iter().map(|p| p.1.clone()).collect(), @@ -2071,10 +1538,7 @@ impl TestBuildAction { self } - fn set_up_with_custom_toml( - mut self, - cargo_toml_metadata: &str, - ) -> impl TestSetupPackageExpectations { + fn set_up_with_custom_toml(mut self, cargo_toml_metadata: &str) -> Self { let cargo_toml_metadata = serde_json::from_str::(cargo_toml_metadata) .expect("Failed to parse cargo metadata in set_up_with_custom_toml"); @@ -2102,7 +1566,86 @@ impl TestBuildAction { } } -impl TestSetupPackageExpectations for TestBuildAction { +// Presence of method ensures specific mock expectation is set +// Dir argument in any method means to operate on the relevant dir +// Output argument in any method means to override return output from default +// is_success boolean means success result of copy operation +// does_exist boolean means existence of the file or dir +// is_created boolean means whether the dir was created or not +impl TestBuildAction { + fn expect_default_build_task_steps(self, driver_name: &str) -> Self { + let cwd = self.cwd.clone(); + self.expect_detect_wdk_build_number(25100u32) + .expect_root_manifest_exists(&cwd, true) + .expect_cargo_build(driver_name, &cwd, None) + } + + fn expect_default_package_task_steps( + self, + driver_name: &str, + driver_type: &str, + verify_signature: bool, + ) -> Self { + let cwd = self.cwd.clone(); + let expected_certmgr_output = get_certmgr_success_output(); + let expectations = self + .expect_final_package_dir_exists(driver_name, &cwd, true) + .expect_inx_file_exists(driver_name, &cwd, true) + .expect_rename_driver_binary_dll_to_sys(driver_name, &cwd) + .expect_copy_driver_binary_sys_to_package_folder(driver_name, &cwd, true) + .expect_copy_pdb_file_to_package_folder(driver_name, &cwd, true) + .expect_copy_inx_file_to_package_folder(driver_name, &cwd, true, &cwd) + .expect_copy_map_file_to_package_folder(driver_name, &cwd, true) + .expect_stampinf(driver_name, &cwd, None) + .expect_inf2cat(driver_name, &cwd, None) + .expect_self_signed_cert_file_exists(&cwd, false) + .expect_certmgr_exists_check(Some(expected_certmgr_output)) + .expect_makecert(&cwd, None) + .expect_copy_self_signed_cert_file_to_package_folder(driver_name, &cwd, true) + .expect_signtool_sign_driver_binary_sys_file(driver_name, &cwd, None) + .expect_signtool_sign_cat_file(driver_name, &cwd, None) + .expect_infverif(driver_name, &cwd, driver_type, None); + if !verify_signature { + return expectations; + } + expectations + .expect_signtool_verify_driver_binary_sys_file(driver_name, &cwd, None) + .expect_signtool_verify_cat_file(driver_name, &cwd, None) + } + + fn expect_default_package_task_steps_for_workspace( + self, + driver_name: &str, + driver_type: &str, + verify_signature: bool, + ) -> Self { + let cwd = self.cwd.clone(); + let expected_certmgr_output = get_certmgr_success_output(); + let expectations = self + .expect_final_package_dir_exists(driver_name, &cwd, true) + .expect_inx_file_exists(driver_name, &cwd.join(driver_name), true) + .expect_rename_driver_binary_dll_to_sys(driver_name, &cwd) + .expect_copy_driver_binary_sys_to_package_folder(driver_name, &cwd, true) + .expect_copy_pdb_file_to_package_folder(driver_name, &cwd, true) + .expect_copy_inx_file_to_package_folder(driver_name, &cwd.join(driver_name), true, &cwd) + .expect_copy_map_file_to_package_folder(driver_name, &cwd, true) + .expect_stampinf(driver_name, &cwd, None) + .expect_inf2cat(driver_name, &cwd, None) + .expect_self_signed_cert_file_exists(&cwd, false) + .expect_certmgr_exists_check(Some(expected_certmgr_output)) + .expect_makecert(&cwd, None) + .expect_copy_self_signed_cert_file_to_package_folder(driver_name, &cwd, true) + .expect_signtool_sign_driver_binary_sys_file(driver_name, &cwd, None) + .expect_signtool_sign_cat_file(driver_name, &cwd, None) + .expect_infverif(driver_name, &cwd, driver_type, None); + if !verify_signature { + return expectations; + } + expectations + .expect_signtool_verify_driver_binary_sys_file(driver_name, &cwd, None) + .expect_signtool_verify_cat_file(driver_name, &cwd, None) + } + fn expect_root_manifest_exists(mut self, root_dir: &Path, does_exist: bool) -> Self { self.mock_fs_provider .expect_exists() @@ -3024,19 +2567,19 @@ impl TestSetupPackageExpectations for TestBuildAction { self } - fn mock_wdk_build_provider(&self) -> &WdkBuild { + const fn mock_wdk_build_provider(&self) -> &WdkBuild { &self.mock_wdk_build_provider } - fn mock_run_command(&self) -> &CommandExec { + const fn mock_run_command(&self) -> &CommandExec { &self.mock_run_command } - fn mock_fs_provider(&self) -> &Fs { + const fn mock_fs_provider(&self) -> &Fs { &self.mock_fs_provider } - fn mock_metadata_provider(&self) -> &MetadataProvider { + const fn mock_metadata_provider(&self) -> &MetadataProvider { &self.mock_metadata_provider } } diff --git a/crates/cargo-wdk/src/main.rs b/crates/cargo-wdk/src/main.rs index daaf55e02..d4d3bef8b 100644 --- a/crates/cargo-wdk/src/main.rs +++ b/crates/cargo-wdk/src/main.rs @@ -16,6 +16,9 @@ use clap::Parser; use cli::Cli; use tracing::error; +#[cfg(test)] +mod test_utils; + /// Main function for the [`cargo-wdk`][crate] CLI application. /// /// The main function parses the CLI input, sets up tracing and executes the diff --git a/crates/cargo-wdk/src/test_utils.rs b/crates/cargo-wdk/src/test_utils.rs new file mode 100644 index 000000000..0ddfe938b --- /dev/null +++ b/crates/cargo-wdk/src/test_utils.rs @@ -0,0 +1,63 @@ +use std::{collections::HashMap, ffi::OsStr, sync::Mutex}; + +/// This is a helper function used in child module unit tests. +/// +/// Runs function after modifying environment variables, and returns the +/// function's return value. +/// +/// The environment is guaranteed to be not modified during the execution +/// of the function, and the environment is reset to its original state +/// after execution of the function. No testing asserts should be called in +/// the function, since a failing test will poison the mutex, and cause all +/// remaining tests to fail. +/// +/// # Panics +/// +/// Panics if called with duplicate environment variable keys. +pub fn with_env(env_vars_key_value_pairs: &[(K, Option)], f: F) -> R +where + K: AsRef + std::cmp::Eq + std::hash::Hash, + V: AsRef, + F: FnOnce() -> R, +{ + // Tests can execute in multiple threads in the same process, so mutex must be + // used to guard access to the environment variables + static ENV_MUTEX: Mutex<()> = Mutex::new(()); + + let _mutex_guard = ENV_MUTEX.lock().unwrap(); + let mut original_env_vars = HashMap::new(); + + // set requested environment variables + for (key, value) in env_vars_key_value_pairs { + if let Ok(original_value) = std::env::var(key) { + let insert_result = original_env_vars.insert(key, original_value); + assert!( + insert_result.is_none(), + "Duplicate environment variable keys were provided" + ); + } + + // Remove the env var if value is None + if let Some(value) = value { + std::env::set_var(key, value); + } else { + std::env::remove_var(key); + } + } + + let f_return_value = f(); + + // reset all set environment variables + for (key, _) in env_vars_key_value_pairs { + original_env_vars.get(key).map_or_else( + || { + std::env::remove_var(key); + }, + |value| { + std::env::set_var(key, value); + }, + ); + } + + f_return_value +} diff --git a/crates/cargo-wdk/tests/build_command_test.rs b/crates/cargo-wdk/tests/build_command_test.rs index 839261873..0c88954ca 100644 --- a/crates/cargo-wdk/tests/build_command_test.rs +++ b/crates/cargo-wdk/tests/build_command_test.rs @@ -1,6 +1,5 @@ //! System level tests for cargo wdk build flow -#![allow(clippy::literal_string_with_formatting_args)] -mod common; +mod test_utils; use std::{ fs, path::{Path, PathBuf}, @@ -8,18 +7,21 @@ use std::{ }; use assert_cmd::prelude::*; -use common::{set_crt_static_flag, with_file_lock}; use sha2::{Digest, Sha256}; +use test_utils::{set_crt_static_flag, with_env, with_file_lock}; + +const STAMPINF_VERSION_ENV_VAR: &str = "STAMPINF_VERSION"; #[test] fn mixed_package_kmdf_workspace_builds_successfully() { - with_file_lock(|| { - let stdout = run_build_cmd("tests/mixed-package-kmdf-workspace"); - - assert!(stdout.contains("Building package driver")); - assert!(stdout.contains("Building package non_driver_crate")); - verify_driver_package_files("tests/mixed-package-kmdf-workspace", "driver", "sys"); + let stdout = with_file_lock(|| { + run_cargo_clean("tests/mixed-package-kmdf-workspace"); + run_build_cmd("tests/mixed-package-kmdf-workspace") }); + + assert!(stdout.contains("Building package driver")); + assert!(stdout.contains("Building package non_driver_crate")); + verify_driver_package_files("tests/mixed-package-kmdf-workspace", "driver", "sys", None); } #[test] @@ -54,39 +56,48 @@ fn kmdf_driver_builds_successfully() { assert!(output.status.success()); } - with_file_lock(|| build_driver_project("kmdf")); + with_file_lock(|| clean_and_build_driver_project("kmdf", None)); } #[test] fn umdf_driver_builds_successfully() { - with_file_lock(|| build_driver_project("umdf")); + with_file_lock(|| clean_and_build_driver_project("umdf", None)); } #[test] fn wdm_driver_builds_successfully() { - with_file_lock(|| build_driver_project("wdm")); + with_file_lock(|| clean_and_build_driver_project("wdm", None)); +} + +#[test] +fn wdm_driver_builds_successfully_with_given_version() { + with_env(&[(STAMPINF_VERSION_ENV_VAR, Some("5.1.0"))], || { + clean_and_build_driver_project("wdm", Some("5.1.0.0")); + }); } #[test] fn emulated_workspace_builds_successfully() { - with_file_lock(|| { - let emulated_workspace_path = "tests/emulated-workspace"; - let stdout = run_build_cmd(emulated_workspace_path); + let emulated_workspace_path = "tests/emulated-workspace"; + let umdf_driver_workspace_path = format!("{emulated_workspace_path}/umdf-driver-workspace"); + let stdout = with_file_lock(|| { + run_cargo_clean(&umdf_driver_workspace_path); + run_build_cmd(emulated_workspace_path) + }); - assert!(stdout.contains("Building package driver_1")); - assert!(stdout.contains("Building package driver_2")); - assert!(stdout.contains("Build completed successfully")); + assert!(stdout.contains("Building package driver_1")); + assert!(stdout.contains("Building package driver_2")); + assert!(stdout.contains("Build completed successfully")); - let umdf_driver_workspace_path = format!("{emulated_workspace_path}/umdf-driver-workspace"); - verify_driver_package_files(&umdf_driver_workspace_path, "driver_1", "dll"); - verify_driver_package_files(&umdf_driver_workspace_path, "driver_2", "dll"); - }); + verify_driver_package_files(&umdf_driver_workspace_path, "driver_1", "dll", None); + verify_driver_package_files(&umdf_driver_workspace_path, "driver_2", "dll", None); } -fn build_driver_project(driver_type: &str) { +fn clean_and_build_driver_project(driver_type: &str, driver_version: Option<&str>) { let driver_name = format!("{driver_type}-driver"); let driver_path = format!("tests/{driver_name}"); + run_cargo_clean(&driver_path); let stdout = run_build_cmd(&driver_path); assert!(stdout.contains(&format!("Building package {driver_name}"))); @@ -97,7 +108,18 @@ fn build_driver_project(driver_type: &str) { _ => panic!("Unsupported driver type: {driver_type}"), }; - verify_driver_package_files(&driver_path, &driver_name, driver_binary_extension); + verify_driver_package_files( + &driver_path, + &driver_name, + driver_binary_extension, + driver_version, + ); +} + +fn run_cargo_clean(driver_path: &str) { + let mut cmd = Command::new("cargo"); + cmd.args(["clean"]).current_dir(driver_path); + cmd.assert().success(); } fn run_build_cmd(driver_path: &str) -> String { @@ -117,6 +139,7 @@ fn verify_driver_package_files( driver_or_workspace_path: &str, driver_name: &str, driver_binary_extension: &str, + driver_version: Option<&str>, ) { let driver_name = driver_name.replace('-', "_"); let debug_folder_path = format!("{driver_or_workspace_path}/target/debug"); @@ -146,6 +169,8 @@ fn verify_driver_package_files( &format!("{package_path}/WDRLocalTestCert.cer"), &format!("{debug_folder_path}/WDRLocalTestCert.cer"), ); + + assert_driver_ver(&package_path, &driver_name, driver_version); } fn assert_dir_exists(path: &str) { @@ -175,6 +200,38 @@ fn assert_file_hash(path1: &str, path2: &str) { ); } +fn assert_driver_ver(package_path: &str, driver_name: &str, driver_version: Option<&str>) { + // Read the INF file as raw bytes and produce a best-effort UTF-8 string. + let file_content = + fs::read(format!("{package_path}/{driver_name}.inf")).expect("Unable to read inf file"); + let file_content = if file_content.starts_with(&[0xFF, 0xFE]) { + // Handle UTF-16 LE (BOM 0xFF 0xFE). + let file_content = file_content + .chunks(2) + .map(|pair| u16::from_le_bytes([pair[0], pair[1]])) + .collect::>(); + String::from_utf16_lossy(&file_content) + } else { + // Otherwise, treat the content as UTF-8; our test setups do not include + // UTF16-BE encoded .inx files. + String::from_utf8_lossy(&file_content).to_string() + }; + + // Example: DriverVer = 09/13/2023,1.0.0.0 + let driver_version_regex = + driver_version.map_or_else(|| r"\d+\.\d+\.\d+\.\d+".to_string(), regex::escape); + let re = regex::Regex::new(&format!( + r"^DriverVer\s+=\s+\d+/\d+/\d+,{driver_version_regex}$" + )) + .unwrap(); + + let line = file_content + .lines() + .find(|line| line.starts_with("DriverVer")) + .expect("DriverVer line not found in inf file"); + assert!(re.captures(line).is_some()); +} + // Helper to hash a file fn digest_file>(path: P) -> String { let file_contents = fs::read(path).expect("Failed to read file"); diff --git a/crates/cargo-wdk/tests/common.rs b/crates/cargo-wdk/tests/common.rs deleted file mode 100644 index 345bdfeda..000000000 --- a/crates/cargo-wdk/tests/common.rs +++ /dev/null @@ -1,45 +0,0 @@ -//! Common methods for tests. - -#![allow(clippy::literal_string_with_formatting_args)] - -use fs4::fs_std::FileExt; - -/// Sets the `RUSTFLAGS` environment variable to include `+crt-static`. -/// -/// # Panics -/// * Panics if `RUSTFLAGS` is not set and setting it fails. -/// -/// FIXME: This is needed for tests as "cargo make wdk-pre-commit-hook-flow" -/// somehow seems to mess with `RUSTFLAGS`. -pub fn set_crt_static_flag() { - if let Ok(rustflags) = std::env::var("RUSTFLAGS") { - let updated_rust_flags = format!("{rustflags} -C target-feature=+crt-static"); - std::env::set_var("RUSTFLAGS", updated_rust_flags); - println!("RUSTFLAGS set, adding the +crt-static: {rustflags:?}"); - } else { - std::env::set_var("RUSTFLAGS", "-C target-feature=+crt-static"); - println!( - "No RUSTFLAGS set, setting it to: {:?}", - std::env::var("RUSTFLAGS").expect("RUSTFLAGS not set") - ); - } -} - -/// Acquires an exclusive lock on a file and executes the provided closure. -/// This is useful for ensuring that only one instance of a test can run at a -/// time. -/// -/// # Panics -/// * Panics if the lock file cannot be created. -/// * Panics if the lock cannot be acquired. -/// * Panics if the lock cannot be released. -pub fn with_file_lock(f: F) -where - F: FnOnce(), -{ - let lock_file = std::fs::File::create("cargo-wdk-test.lock") - .expect("Unable to create lock file for cargo-wdk tests"); - FileExt::lock_exclusive(&lock_file).expect("Unable to cargo-wdk-test.lock file"); - f(); - FileExt::unlock(&lock_file).expect("Unable to unlock cargo-wdk-test.lock file"); -} diff --git a/crates/cargo-wdk/tests/new_command_test.rs b/crates/cargo-wdk/tests/new_command_test.rs index 6821ce392..f551dfad7 100644 --- a/crates/cargo-wdk/tests/new_command_test.rs +++ b/crates/cargo-wdk/tests/new_command_test.rs @@ -1,12 +1,11 @@ //! System level tests for cargo wdk new flow -#![allow(clippy::literal_string_with_formatting_args)] -mod common; +mod test_utils; use std::path::PathBuf; use assert_cmd::Command; use assert_fs::{assert::PathAssert, prelude::PathChild, TempDir}; -use common::{set_crt_static_flag, with_file_lock}; use mockall::PredicateBooleanExt; +use test_utils::{set_crt_static_flag, with_file_lock}; #[test] fn kmdf_driver_is_created_successfully() { @@ -60,17 +59,14 @@ fn help_works() { } fn project_is_created(driver_type: &str) { - with_file_lock(|| { - let (stdout, _stderr) = create_and_build_new_driver_project(driver_type); - assert!(stdout.contains( - "Required directive Provider missing, empty, or invalid in [Version] section." - )); - assert!(stdout - .contains("Required directive Class missing, empty, or invalid in [Version] section.")); - assert!(stdout - .contains("Invalid ClassGuid \"\", expecting {XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX}.")); - assert!(stdout.contains("INF is NOT VALID")); - }); + let (stdout, _stderr) = with_file_lock(|| create_and_build_new_driver_project(driver_type)); + assert!(stdout + .contains("Required directive Provider missing, empty, or invalid in [Version] section.")); + assert!(stdout + .contains("Required directive Class missing, empty, or invalid in [Version] section.")); + assert!(stdout + .contains("Invalid ClassGuid \"\", expecting {XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX}.")); + assert!(stdout.contains("INF is NOT VALID")); } fn test_command_invocation( @@ -79,7 +75,7 @@ fn test_command_invocation( command_succeeds: bool, assert: F, ) { - with_file_lock(|| { + let mut cmd = with_file_lock(|| { let mut args = args .iter() .map(ToString::to_string) @@ -96,21 +92,22 @@ fn test_command_invocation( let mut cmd = Command::cargo_bin("cargo-wdk").expect("unable to find cargo-wdk binary"); cmd.args(args); - - let cmd_assertion = cmd.assert(); - let cmd_assertion = if command_succeeds { - cmd_assertion.success() - } else { - cmd_assertion.failure() - }; - let output = cmd_assertion.get_output(); - let stdout = String::from_utf8_lossy(&output.stdout); - println!("stdout: {stdout}"); - let stderr = String::from_utf8_lossy(&output.stderr); - println!("stderr: {stderr}"); - - assert(&stdout, &stderr); + cmd }); + + let cmd_assertion = cmd.assert(); + let cmd_assertion = if command_succeeds { + cmd_assertion.success() + } else { + cmd_assertion.failure() + }; + let output = cmd_assertion.get_output(); + let stdout = String::from_utf8_lossy(&output.stdout); + println!("stdout: {stdout}"); + let stderr = String::from_utf8_lossy(&output.stderr); + println!("stderr: {stderr}"); + + assert(&stdout, &stderr); } fn create_and_build_new_driver_project(driver_type: &str) -> (String, String) { diff --git a/crates/cargo-wdk/tests/test_utils/mod.rs b/crates/cargo-wdk/tests/test_utils/mod.rs new file mode 100644 index 000000000..e266d6d9f --- /dev/null +++ b/crates/cargo-wdk/tests/test_utils/mod.rs @@ -0,0 +1,112 @@ +//! Utility methods for tests. +//! Note: The current layout (`tests/test_utils/mod.rs`) is intentional; using a +//! subdirectory prevents Cargo from treating this as an independent integration +//! test crate and instead lets other tests import it as a regular module. + +use std::{collections::HashMap, ffi::OsStr}; + +use fs4::fs_std::FileExt; + +/// Sets the `RUSTFLAGS` environment variable to include `+crt-static`. +/// +/// # Panics +/// * Panics if `RUSTFLAGS` is not set and setting it fails. +/// +/// FIXME: This is needed for tests as "cargo make wdk-pre-commit-hook-flow" +/// somehow seems to mess with `RUSTFLAGS`. +pub fn set_crt_static_flag() { + if let Ok(rustflags) = std::env::var("RUSTFLAGS") { + let updated_rust_flags = format!("{rustflags} -C target-feature=+crt-static"); + std::env::set_var("RUSTFLAGS", updated_rust_flags); + println!("RUSTFLAGS set, adding the +crt-static: {rustflags:?}"); + } else { + std::env::set_var("RUSTFLAGS", "-C target-feature=+crt-static"); + println!( + "No RUSTFLAGS set, setting it to: {:?}", + std::env::var("RUSTFLAGS").expect("RUSTFLAGS not set") + ); + } +} + +/// Acquires an exclusive lock on a file and executes the provided closure. +/// This is useful for ensuring that only one instance of a test can run at a +/// time. +/// +/// # Panics +/// * Panics if the lock file cannot be created. +/// * Panics if the lock cannot be acquired. +/// * Panics if the lock cannot be released. +pub fn with_file_lock(f: F) -> R +where + F: FnOnce() -> R, +{ + let lock_file = std::fs::File::create("cargo-wdk-test.lock") + .expect("Unable to create lock file for cargo-wdk tests"); + FileExt::lock_exclusive(&lock_file).expect("Unable to cargo-wdk-test.lock file"); + let result = f(); + FileExt::unlock(&lock_file).expect("Unable to unlock cargo-wdk-test.lock file"); + result +} + +#[allow( + dead_code, + reason = "This method is used only in build_command_test.rs; appears unused in other \ + integration test crates when running with --all-targets." +)] +/// Runs function after modifying environment variables, and returns the +/// function's return value. +/// +/// The environment is guaranteed to be not modified during the execution +/// of the function, and the environment is reset to its original state +/// after execution of the function. No testing asserts should be called in +/// the function, since a failing test will poison the mutex, and cause all +/// remaining tests to fail. +/// +/// # Panics +/// +/// * Panics if called with duplicate environment variable keys. +/// * If the lock file cannot be created/locked/released. +pub fn with_env(env_vars_key_value_pairs: &[(K, Option)], f: F) -> R +where + K: AsRef + std::cmp::Eq + std::hash::Hash, + V: AsRef, + F: FnOnce() -> R, +{ + with_file_lock(|| { + let mut original_env_vars = HashMap::new(); + + // set requested environment variables + for (key, value) in env_vars_key_value_pairs { + if let Ok(original_value) = std::env::var(key) { + let insert_result = original_env_vars.insert(key, original_value); + assert!( + insert_result.is_none(), + "Duplicate environment variable keys were provided" + ); + } + + // Remove the env var if value is None + if let Some(value) = value { + std::env::set_var(key, value); + } else { + std::env::remove_var(key); + } + } + + let result = f(); + + // reset all set environment variables + for (key, _) in env_vars_key_value_pairs { + original_env_vars.get(key).map_or_else( + || { + std::env::remove_var(key); + }, + |value| { + std::env::set_var(key, value); + }, + ); + } + + result + }) +}