diff --git a/README.en.md b/README.en.md index a2ab834..cc1365a 100644 --- a/README.en.md +++ b/README.en.md @@ -105,6 +105,9 @@ ostool build --config custom-build.toml # Temporarily override Cargo package / binary target ostool build --config custom-build.toml --package paging-test --bin basic +# Temporarily build a Cargo test target +ostool build --config custom-build.toml --package paging-test --test kernel_axtest + # Build in specified working directory ostool --workdir /path/to/project build ``` @@ -124,7 +127,7 @@ ostool run qemu --dtb-dump # Run with specific Qemu config file ostool run qemu --qemu-config my-qemu.toml -# Run after temporarily overriding Cargo package / binary target +# Run after temporarily overriding Cargo package / binary/test target ostool run qemu --package paging-test --bin basic # Run with U-Boot @@ -142,7 +145,7 @@ ostool board ls # Run on a remote board ostool board run -# Run a specific Cargo binary target on a remote board +# Run a specific Cargo binary/test target on a remote board ostool board run --package paging-test --bin basic ``` @@ -175,6 +178,11 @@ package = "my-os-kernel" # set it here or pass `--bin ` when the package has multiple binaries. bin = "my-os-kernel" +# Test target name. Use this for executable `[[test]]` targets, such as +# `harness = false` kernel tests. This is mutually exclusive with `bin`; +# it can also be selected with `--test `. +# test = "my-os-kernel-axtest" + # Enabled features features = ["page-alloc-4g"] @@ -205,7 +213,7 @@ post_build_cmds = ["make post-process"] to_bin = true ``` -Command-line `--package`/`--bin` overrides are applied to the final Cargo +Command-line `--package`/`--bin`/`--test` overrides are applied to the final Cargo selection before `${package}` variable expansion and someboot `build-info.toml` argument injection. diff --git a/README.md b/README.md index e38ddd5..553dcc5 100644 --- a/README.md +++ b/README.md @@ -105,6 +105,9 @@ ostool build --config custom-build.toml # 临时覆盖 Cargo package / binary target ostool build --config custom-build.toml --package paging-test --bin basic +# 临时构建 Cargo test target +ostool build --config custom-build.toml --package paging-test --test kernel_axtest + # 在指定工作目录中构建 ostool --workdir /path/to/project build ``` @@ -124,7 +127,7 @@ ostool run qemu --dtb-dump # 指定 Qemu 配置文件运行 ostool run qemu --qemu-config my-qemu.toml -# 临时覆盖 Cargo package / binary target 后运行 +# 临时覆盖 Cargo package / binary/test target 后运行 ostool run qemu --package paging-test --bin basic # 使用 U-Boot 运行 @@ -142,7 +145,7 @@ ostool board ls # 在远端开发板上运行 ostool board run -# 在远端开发板上运行指定 Cargo binary target +# 在远端开发板上运行指定 Cargo binary/test target ostool board run --package paging-test --bin basic ``` @@ -175,6 +178,10 @@ package = "my-os-kernel" # 包内有多个 binary 时建议设置,或在命令行传 `--bin `。 bin = "my-os-kernel" +# test target 名称。用于构建可执行 `[[test]]` 目标,例如 `harness = false` +# 的内核测试;与 `bin` 互斥,也可在命令行传 `--test `。 +# test = "my-os-kernel-axtest" + # 启用的特性 features = ["page-alloc-4g"] @@ -204,7 +211,7 @@ post_build_cmds = ["make post-process"] to_bin = false ``` -命令行 `--package`/`--bin` 会先覆盖 `.build.toml` 中的 Cargo 包/二进制选择,再用于 +命令行 `--package`/`--bin`/`--test` 会先覆盖 `.build.toml` 中的 Cargo 包/目标选择,再用于 `${package}` 变量展开和 someboot `build-info.toml` 自动参数注入。 #### 自定义构建系统示例 diff --git a/ostool/src/board/config.rs b/ostool/src/board/config.rs index 6e32594..0b9f79d 100644 --- a/ostool/src/board/config.rs +++ b/ostool/src/board/config.rs @@ -400,11 +400,12 @@ dtb_file = "${package}/board.dtb" crate::build::activate_build_config( &mut invocation, &BuildConfig { - system: BuildSystem::Cargo(Cargo { + system: BuildSystem::Cargo(Box::new(Cargo { env: HashMap::new(), target: "aarch64-unknown-none".into(), package: "kernel".into(), bin: None, + test: None, features: vec![], log: None, extra_config: None, @@ -414,7 +415,7 @@ dtb_file = "${package}/board.dtb" pre_build_cmds: vec![], post_build_cmds: vec![], to_bin: false, - }), + })), }, None, ) diff --git a/ostool/src/board/mod.rs b/ostool/src/board/mod.rs index 4cc1513..1d1bf58 100644 --- a/ostool/src/board/mod.rs +++ b/ostool/src/board/mod.rs @@ -257,7 +257,7 @@ pub async fn cargo_run_board( run_board( invocation, &BuildConfig { - system: BuildSystem::Cargo(cargo.clone()), + system: BuildSystem::Cargo(Box::new(cargo.clone())), }, build_config_path, board_config, diff --git a/ostool/src/build/artifact_selector.rs b/ostool/src/build/artifact_selector.rs index 05bf094..75be97e 100644 --- a/ostool/src/build/artifact_selector.rs +++ b/ostool/src/build/artifact_selector.rs @@ -52,6 +52,7 @@ impl CargoExecutableArtifact { pub(crate) fn select_executable_artifact( executable_artifacts: &[CargoExecutableArtifact], explicit_bin: Option<&str>, + explicit_test: Option<&str>, default_run: Option<&str>, package: &str, ) -> anyhow::Result { @@ -68,10 +69,21 @@ pub(crate) fn select_executable_artifact( }); } + if let Some(test) = explicit_test { + return executable_artifacts + .iter() + .rev() + .find(|candidate| candidate.target_name() == test) + .map(|candidate| candidate.artifact().clone()) + .ok_or_else(|| { + anyhow!( + "test target `{test}` was not built for package `{package}`; check system.Cargo.test or --test" + ) + }); + } + if executable_artifacts.is_empty() { - bail!( - "no executable bin artifact found in cargo JSON output for package `{package}`; ostool currently resolves only Cargo bin targets" - ); + bail!("no executable artifact found in cargo JSON output for package `{package}`"); } if let Some(candidate) = executable_artifacts @@ -123,17 +135,18 @@ mod tests { fn select( artifacts: &[CargoExecutableArtifact], explicit_bin: Option<&str>, + explicit_test: Option<&str>, default_run: Option<&str>, package: &str, ) -> anyhow::Result { - select_executable_artifact(artifacts, explicit_bin, default_run, package) + select_executable_artifact(artifacts, explicit_bin, explicit_test, default_run, package) } #[test] fn select_executable_artifact_uses_explicit_bin_first() { let artifacts = vec![candidate("kernel"), candidate("kernel-qemu")]; - let selected = select(&artifacts, Some("kernel-qemu"), None, "kernel").unwrap(); + let selected = select(&artifacts, Some("kernel-qemu"), None, None, "kernel").unwrap(); assert_eq!( selected.elf_path(), @@ -145,7 +158,7 @@ mod tests { fn select_executable_artifact_errors_when_explicit_bin_was_not_built() { let artifacts = vec![candidate("kernel")]; - let err = select(&artifacts, Some("missing-bin"), None, "kernel").unwrap_err(); + let err = select(&artifacts, Some("missing-bin"), None, None, "kernel").unwrap_err(); assert!( err.to_string() @@ -153,11 +166,35 @@ mod tests { ); } + #[test] + fn select_executable_artifact_uses_explicit_test_target() { + let artifacts = vec![candidate("kernel"), candidate("axtest_kernel")]; + + let selected = select(&artifacts, None, Some("axtest_kernel"), None, "kernel").unwrap(); + + assert_eq!( + selected.elf_path(), + Path::new("/tmp/ostool-target/debug/axtest_kernel") + ); + } + + #[test] + fn select_executable_artifact_errors_when_explicit_test_was_not_built() { + let artifacts = vec![candidate("kernel")]; + + let err = select(&artifacts, None, Some("missing-test"), None, "kernel").unwrap_err(); + + assert!( + err.to_string() + .contains("test target `missing-test` was not built") + ); + } + #[test] fn select_executable_artifact_prefers_package_name_before_default_run() { let artifacts = vec![candidate("helper"), candidate("kernel")]; - let selected = select(&artifacts, None, Some("helper"), "kernel").unwrap(); + let selected = select(&artifacts, None, None, Some("helper"), "kernel").unwrap(); assert_eq!( selected.elf_path(), @@ -169,7 +206,7 @@ mod tests { fn select_executable_artifact_uses_default_run_without_package_name_binary() { let artifacts = vec![candidate("helper"), candidate("boot-test")]; - let selected = select(&artifacts, None, Some("boot-test"), "kernel").unwrap(); + let selected = select(&artifacts, None, None, Some("boot-test"), "kernel").unwrap(); assert_eq!( selected.elf_path(), @@ -181,7 +218,7 @@ mod tests { fn select_executable_artifact_uses_single_binary_as_fallback() { let artifacts = vec![candidate("helper")]; - let selected = select(&artifacts, None, None, "kernel").unwrap(); + let selected = select(&artifacts, None, None, None, "kernel").unwrap(); assert_eq!( selected.elf_path(), @@ -191,16 +228,16 @@ mod tests { #[test] fn select_executable_artifact_errors_on_empty_cargo_output() { - let err = select(&[], None, None, "kernel").unwrap_err(); + let err = select(&[], None, None, None, "kernel").unwrap_err(); - assert!(err.to_string().contains("no executable bin artifact found")); + assert!(err.to_string().contains("no executable artifact found")); } #[test] fn select_executable_artifact_errors_on_ambiguous_multiple_binaries() { let artifacts = vec![candidate("kernel-qemu"), candidate("kernel-uboot")]; - let err = select(&artifacts, None, None, "kernel").unwrap_err(); + let err = select(&artifacts, None, None, None, "kernel").unwrap_err(); let rendered = err.to_string(); assert!(rendered.contains("multiple binary targets")); diff --git a/ostool/src/build/cargo_pipeline.rs b/ostool/src/build/cargo_pipeline.rs index b933dd7..1b2f4a5 100644 --- a/ostool/src/build/cargo_pipeline.rs +++ b/ostool/src/build/cargo_pipeline.rs @@ -12,7 +12,7 @@ use std::{ }; use anyhow::{Context, anyhow, bail}; -use cargo_metadata::{Message, PackageId}; +use cargo_metadata::{Message, PackageId, TargetKind}; use colored::Colorize; use crate::{ @@ -73,6 +73,12 @@ impl CargoBuildOutcome { } } +fn is_executable_target_kind(kinds: &[TargetKind]) -> bool { + kinds + .iter() + .any(|kind| matches!(kind, TargetKind::Bin | TargetKind::Test)) +} + #[derive(Debug, Clone)] struct CargoBuildPlan { command: String, @@ -81,6 +87,7 @@ struct CargoBuildPlan { extra_config_path: Option, package: String, bin: Option, + test: Option, target: String, target_dir: PathBuf, features: Vec, @@ -116,6 +123,10 @@ impl CargoBuildPlan { cmd.arg("--bin"); cmd.arg(bin); } + if let Some(test) = &self.test { + cmd.arg("--test"); + cmd.arg(test); + } cmd.arg("--target"); cmd.arg(&self.target); cmd.arg("-Z"); @@ -163,6 +174,10 @@ impl CargoBuildPlan { args.push("--bin".into()); args.push(bin.clone()); } + if let Some(test) = &self.test { + args.push("--test".into()); + args.push(test.clone()); + } args.push("--target".into()); args.push(self.target.clone()); args.push("-Z".into()); @@ -292,7 +307,7 @@ impl<'a> CargoBuildPipeline<'a> { match message { Message::CompilerArtifact(artifact) => { if artifact.package_id == target_pkg_id - && artifact.target.is_bin() + && is_executable_target_kind(&artifact.target.kind) && let Some(executable) = artifact.executable { let elf_path = executable.into_std_path_buf(); @@ -333,6 +348,7 @@ impl<'a> CargoBuildPipeline<'a> { let resolved = select_executable_artifact( &executable_artifacts, self.config.bin.as_deref(), + self.config.test.as_deref(), default_run.as_deref(), &self.config.package, )?; @@ -346,6 +362,9 @@ impl<'a> CargoBuildPipeline<'a> { } async fn build_cargo_plan(&mut self) -> anyhow::Result { + if self.config.bin.is_some() && self.config.test.is_some() { + bail!("system.Cargo.bin and system.Cargo.test are mutually exclusive"); + } let features = self.build_features(); let extra_config_path = self.cargo_extra_config().await?; let someboot_args = self.detect_someboot_args(&features)?; @@ -370,6 +389,7 @@ impl<'a> CargoBuildPipeline<'a> { extra_config_path, package: self.config.package.clone(), bin: self.config.bin.clone(), + test: self.config.test.clone(), target: self.config.target.clone(), target_dir: self.input.build_dir.clone(), features, @@ -673,7 +693,11 @@ mod tests { ) } - async fn cargo_plan_args(root: &Path, config: &Cargo, debug: bool) -> Vec { + async fn cargo_plan_args_result( + root: &Path, + config: &Cargo, + debug: bool, + ) -> anyhow::Result> { let invocation = Invocation::new(InvocationOptions::new( Some(root.to_path_buf()), None, @@ -683,7 +707,11 @@ mod tests { .unwrap(); let input = cargo_input_for(&invocation, config, debug); let mut builder = CargoBuildPipeline::build(input, config).skip_objcopy(true); - builder.build_cargo_plan().await.unwrap().args() + builder.build_cargo_plan().await.map(|plan| plan.args()) + } + + async fn cargo_plan_args(root: &Path, config: &Cargo, debug: bool) -> Vec { + cargo_plan_args_result(root, config, debug).await.unwrap() } fn feature_arg(args: &[String]) -> Option<&str> { @@ -773,6 +801,49 @@ mod tests { assert!(release_args.iter().any(|arg| arg == "--release")); } + #[tokio::test] + async fn build_cargo_plan_uses_test_target_selector() { + let temp = tempfile::tempdir().unwrap(); + write_log_workspace(temp.path(), false); + let config = Cargo { + package: "app".into(), + target: "x86_64-unknown-none".into(), + test: Some("kernel_axtest".into()), + profile: Some(CargoBuildProfile::Debug), + ..Default::default() + }; + + let args = cargo_plan_args(temp.path(), &config, false).await; + + assert!( + args.windows(2) + .any(|window| window == ["--test", "kernel_axtest"]) + ); + assert!(!args.iter().any(|arg| arg == "--bin")); + } + + #[tokio::test] + async fn build_cargo_plan_rejects_bin_and_test_target_together() { + let temp = tempfile::tempdir().unwrap(); + write_log_workspace(temp.path(), false); + let config = Cargo { + package: "app".into(), + target: "x86_64-unknown-none".into(), + bin: Some("kernel".into()), + test: Some("kernel_axtest".into()), + ..Default::default() + }; + + let err = cargo_plan_args_result(temp.path(), &config, false) + .await + .unwrap_err(); + + assert!( + err.to_string() + .contains("system.Cargo.bin and system.Cargo.test") + ); + } + #[tokio::test] async fn build_cargo_plan_profile_overrides_debug_flag() { let temp = tempfile::tempdir().unwrap(); diff --git a/ostool/src/build/config.rs b/ostool/src/build/config.rs index 2bc8d35..15648fe 100644 --- a/ostool/src/build/config.rs +++ b/ostool/src/build/config.rs @@ -40,7 +40,7 @@ pub struct BuildConfig { impl Default for BuildConfig { fn default() -> Self { Self { - system: BuildSystem::Cargo(Cargo::default()), + system: BuildSystem::Cargo(Box::default()), } } } @@ -51,7 +51,7 @@ pub enum BuildSystem { /// Use custom shell commands for building. Custom(Custom), /// Use Cargo for building. - Cargo(Cargo), + Cargo(Box), } /// Configuration for custom (non-Cargo) build systems. @@ -90,6 +90,13 @@ pub struct Cargo { /// field or pass `--bin` on the command line. #[serde(default)] pub bin: Option, + /// Test target name to build within the selected package. + /// + /// This is intended for executable `[[test]]` targets that set + /// `harness = false`, such as kernel tests run by QEMU or a board runner. + /// It is mutually exclusive with [`Cargo::bin`]. + #[serde(default)] + pub test: Option, /// Cargo features to enable. pub features: Vec, /// Log level feature to automatically enable. diff --git a/ostool/src/build/mod.rs b/ostool/src/build/mod.rs index 577d63b..4349075 100644 --- a/ostool/src/build/mod.rs +++ b/ostool/src/build/mod.rs @@ -162,18 +162,19 @@ impl CargoRunnerKind { pub(crate) struct CargoSelector { package: Option, bin: Option, + test: Option, } impl CargoSelector { /// Creates a Cargo selector from optional CLI overrides. #[cfg(test)] - pub(crate) fn new(package: Option, bin: Option) -> Self { - Self { package, bin } + pub(crate) fn new(package: Option, bin: Option, test: Option) -> Self { + Self { package, bin, test } } /// Returns whether no selector override was supplied. fn is_empty(&self) -> bool { - self.package.is_none() && self.bin.is_none() + self.package.is_none() && self.bin.is_none() && self.test.is_none() } } @@ -187,7 +188,7 @@ fn apply_cargo_selector( } let config::BuildSystem::Cargo(cargo_config) = &mut config.system else { - bail!("--package/--bin can only be used with system.Cargo build configs"); + bail!("--package/--bin/--test can only be used with system.Cargo build configs"); }; if let Some(package) = &selector.package { @@ -195,6 +196,11 @@ fn apply_cargo_selector( } if let Some(bin) = &selector.bin { cargo_config.bin = Some(bin.clone()); + cargo_config.test = None; + } + if let Some(test) = &selector.test { + cargo_config.bin = None; + cargo_config.test = Some(test.clone()); } Ok(()) } @@ -352,7 +358,7 @@ pub async fn cargo_build( activate_build_config( invocation, &BuildConfig { - system: BuildSystem::Cargo(config.clone()), + system: BuildSystem::Cargo(Box::new(config.clone())), }, config_path, )?; @@ -420,7 +426,7 @@ pub async fn cargo_run( activate_build_config( invocation, &BuildConfig { - system: BuildSystem::Cargo(config.clone()), + system: BuildSystem::Cargo(Box::new(config.clone())), }, config_path, )?; @@ -713,17 +719,17 @@ mod tests { let layout = resolve_project_layout(Some(temp.path().to_path_buf())).unwrap(); let config_path = temp.path().join(".build.toml"); let config = BuildConfig { - system: BuildSystem::Cargo(Cargo { + system: BuildSystem::Cargo(Box::new(Cargo { package: "placeholder".into(), ..Default::default() - }), + })), }; let active = activate_build_context( &layout, config, Some(config_path.clone()), - &CargoSelector::new(Some("kernel".into()), Some("kernel-qemu".into())), + &CargoSelector::new(Some("kernel".into()), Some("kernel-qemu".into()), None), ) .unwrap(); @@ -752,10 +758,10 @@ mod tests { )) .unwrap(); let config = BuildConfig { - system: BuildSystem::Cargo(Cargo { + system: BuildSystem::Cargo(Box::new(Cargo { package: "kernel".into(), ..Default::default() - }), + })), }; let config_path = temp.path().join(".build.toml"); @@ -792,13 +798,13 @@ mod tests { &layout, config, None, - &CargoSelector::new(Some("kernel".into()), None), + &CargoSelector::new(Some("kernel".into()), None, None), ) .unwrap_err(); assert!( err.to_string() - .contains("--package/--bin can only be used with system.Cargo") + .contains("--package/--bin/--test can only be used with system.Cargo") ); } } diff --git a/ostool/src/main.rs b/ostool/src/main.rs index 3c695e0..0d7a3e1 100644 --- a/ostool/src/main.rs +++ b/ostool/src/main.rs @@ -101,13 +101,16 @@ struct CargoSelectorArgs { #[arg(long)] package: Option, /// Select a Cargo binary target within the selected package - #[arg(long)] + #[arg(long, conflicts_with = "test")] bin: Option, + /// Select a Cargo test target within the selected package + #[arg(long, conflicts_with = "bin")] + test: Option, } impl CargoSelectorArgs { fn is_empty(&self) -> bool { - self.package.is_none() && self.bin.is_none() + self.package.is_none() && self.bin.is_none() && self.test.is_none() } } @@ -416,7 +419,7 @@ async fn load_build_config( Ok(LoadedBuildConfig { config, path }) } -/// Applies `--package` and `--bin` overrides to Cargo build configs. +/// Applies `--package`, `--bin`, and `--test` overrides to Cargo build configs. fn apply_cargo_selector( invocation: &mut Invocation, build_config: &mut build::config::BuildConfig, @@ -425,7 +428,9 @@ fn apply_cargo_selector( ) -> Result<()> { if !selector.is_empty() { let build::config::BuildSystem::Cargo(cargo_config) = &mut build_config.system else { - anyhow::bail!("--package/--bin can only be used with system.Cargo build configs"); + anyhow::bail!( + "--package/--bin/--test can only be used with system.Cargo build configs" + ); }; if let Some(package) = &selector.package { @@ -433,6 +438,11 @@ fn apply_cargo_selector( } if let Some(bin) = &selector.bin { cargo_config.bin = Some(bin.clone()); + cargo_config.test = None; + } + if let Some(test) = &selector.test { + cargo_config.bin = None; + cargo_config.test = Some(test.clone()); } } @@ -535,6 +545,31 @@ mod tests { ); assert_eq!(cargo_selector.package.as_deref(), Some("kernel")); assert_eq!(cargo_selector.bin.as_deref(), Some("kernel-qemu")); + assert!(cargo_selector.test.is_none()); + } + other => panic!("unexpected command: {other:?}"), + } + } + + #[test] + fn parse_build_with_test_selector() { + let cli = Cli::try_parse_from([ + "ostool", + "build", + "--config", + "kernel.build.toml", + "--package", + "kernel", + "--test", + "axtest_kernel", + ]) + .unwrap(); + + match cli.command { + SubCommands::Build { cargo_selector, .. } => { + assert_eq!(cargo_selector.package.as_deref(), Some("kernel")); + assert!(cargo_selector.bin.is_none()); + assert_eq!(cargo_selector.test.as_deref(), Some("axtest_kernel")); } other => panic!("unexpected command: {other:?}"), } @@ -570,6 +605,7 @@ mod tests { ); assert_eq!(args.cargo_selector.package.as_deref(), Some("kernel")); assert_eq!(args.cargo_selector.bin.as_deref(), Some("kernel-qemu")); + assert!(args.cargo_selector.test.is_none()); assert_eq!( args.qemu.qemu_config.as_deref(), Some(std::path::Path::new("kernel.qemu.toml")) @@ -609,6 +645,7 @@ mod tests { ); assert_eq!(args.cargo_selector.package.as_deref(), Some("kernel")); assert_eq!(args.cargo_selector.bin.as_deref(), Some("kernel-uboot")); + assert!(args.cargo_selector.test.is_none()); assert_eq!( args.uboot.uboot_config.as_deref(), Some(std::path::Path::new("kernel.uboot.toml")) @@ -738,6 +775,7 @@ mod tests { ); assert!(args.cargo_selector.package.is_none()); assert!(args.cargo_selector.bin.is_none()); + assert!(args.cargo_selector.test.is_none()); assert_eq!(args.board_type.as_deref(), Some("rk3568")); assert_eq!(args.server.server.as_deref(), Some("10.0.0.2")); assert_eq!(args.server.port, Some(9000)); @@ -766,6 +804,7 @@ mod tests { }) => { assert_eq!(args.cargo_selector.package.as_deref(), Some("kernel")); assert_eq!(args.cargo_selector.bin.as_deref(), Some("kernel-board")); + assert!(args.cargo_selector.test.is_none()); } other => panic!("unexpected command: {other:?}"), } @@ -775,11 +814,11 @@ mod tests { fn apply_cargo_selector_overrides_cargo_build_config() { let (_temp, mut invocation) = test_invocation(); let mut build_config = build::config::BuildConfig { - system: build::config::BuildSystem::Cargo(build::config::Cargo { + system: build::config::BuildSystem::Cargo(Box::new(build::config::Cargo { package: "default-package".into(), bin: None, ..Default::default() - }), + })), }; apply_cargo_selector( @@ -789,6 +828,7 @@ mod tests { &CargoSelectorArgs { package: Some("kernel".into()), bin: Some("kernel-qemu".into()), + test: None, }, ) .unwrap(); @@ -797,6 +837,7 @@ mod tests { build::config::BuildSystem::Cargo(cargo) => { assert_eq!(cargo.package, "kernel"); assert_eq!(cargo.bin.as_deref(), Some("kernel-qemu")); + assert!(cargo.test.is_none()); } other => panic!("unexpected build system: {other:?}"), } @@ -820,16 +861,50 @@ mod tests { &CargoSelectorArgs { package: Some("kernel".into()), bin: None, + test: None, }, ) .unwrap_err(); assert!( err.to_string() - .contains("--package/--bin can only be used with system.Cargo") + .contains("--package/--bin/--test can only be used with system.Cargo") ); } + #[test] + fn apply_cargo_selector_overrides_test_target() { + let (_temp, mut invocation) = test_invocation(); + let mut build_config = build::config::BuildConfig { + system: build::config::BuildSystem::Cargo(Box::new(build::config::Cargo { + package: "default-package".into(), + bin: Some("old-bin".into()), + ..Default::default() + })), + }; + + apply_cargo_selector( + &mut invocation, + &mut build_config, + _temp.path().join(".build.toml").as_path(), + &CargoSelectorArgs { + package: Some("kernel".into()), + bin: None, + test: Some("axtest_kernel".into()), + }, + ) + .unwrap(); + + match &build_config.system { + build::config::BuildSystem::Cargo(cargo) => { + assert_eq!(cargo.package, "kernel"); + assert!(cargo.bin.is_none()); + assert_eq!(cargo.test.as_deref(), Some("axtest_kernel")); + } + other => panic!("unexpected build system: {other:?}"), + } + } + #[tokio::test] async fn cargo_selector_updates_scope_before_board_config_load() { let temp = tempfile::tempdir().unwrap(); @@ -870,11 +945,11 @@ dtb_file = "${package}/board.dtb" let mut invocation = Invocation::new(InvocationOptions::new(Some(app_dir), None, None, false)).unwrap(); let mut build_config = build::config::BuildConfig { - system: build::config::BuildSystem::Cargo(build::config::Cargo { + system: build::config::BuildSystem::Cargo(Box::new(build::config::Cargo { package: "app".into(), target: "aarch64-unknown-none".into(), ..Default::default() - }), + })), }; apply_cargo_selector( @@ -884,6 +959,7 @@ dtb_file = "${package}/board.dtb" &CargoSelectorArgs { package: Some("kernel".into()), bin: Some("kernel-board".into()), + test: None, }, ) .unwrap(); @@ -981,6 +1057,7 @@ fail_regex = [] &CargoSelectorArgs { package: Some("kernel".into()), bin: Some("kernel-board".into()), + test: None, }, ) .unwrap(); diff --git a/ostool/src/run/qemu.rs b/ostool/src/run/qemu.rs index 53dd2b1..d9b4b83 100644 --- a/ostool/src/run/qemu.rs +++ b/ostool/src/run/qemu.rs @@ -995,6 +995,7 @@ fail_regex = [] target: "aarch64-unknown-none".into(), package: "kernel".into(), bin: None, + test: None, features: vec![], log: None, extra_config: None, @@ -1092,6 +1093,7 @@ fail_regex = [] target: "riscv64gc-unknown-none-elf".into(), package: "sample".into(), bin: None, + test: None, features: vec![], log: None, extra_config: None, @@ -1295,11 +1297,12 @@ fail_regex = [] crate::build::activate_build_config( &mut invocation, &BuildConfig { - system: BuildSystem::Cargo(Cargo { + system: BuildSystem::Cargo(Box::new(Cargo { env: HashMap::new(), target: "aarch64-unknown-none".into(), package: "sample".into(), bin: None, + test: None, features: vec![], log: None, extra_config: None, @@ -1309,7 +1312,7 @@ fail_regex = [] pre_build_cmds: vec![], post_build_cmds: vec![], to_bin: false, - }), + })), }, None, ) diff --git a/ostool/src/run/uboot.rs b/ostool/src/run/uboot.rs index f857223..832be35 100644 --- a/ostool/src/run/uboot.rs +++ b/ostool/src/run/uboot.rs @@ -1840,11 +1840,12 @@ timeout = 0 crate::build::activate_build_config( &mut invocation, &BuildConfig { - system: BuildSystem::Cargo(Cargo { + system: BuildSystem::Cargo(Box::new(Cargo { env: HashMap::new(), target: "aarch64-unknown-none".into(), package: "sample".into(), bin: None, + test: None, features: vec![], log: None, extra_config: None, @@ -1854,7 +1855,7 @@ timeout = 0 pre_build_cmds: vec![], post_build_cmds: vec![], to_bin: false, - }), + })), }, None, ) @@ -2029,11 +2030,12 @@ baud_rate = "115200" crate::build::activate_build_config( &mut invocation, &BuildConfig { - system: BuildSystem::Cargo(Cargo { + system: BuildSystem::Cargo(Box::new(Cargo { env: HashMap::new(), target: "aarch64-unknown-none".into(), package: "kernel".into(), bin: None, + test: None, features: vec![], log: None, extra_config: None, @@ -2043,7 +2045,7 @@ baud_rate = "115200" pre_build_cmds: vec![], post_build_cmds: vec![], to_bin: false, - }), + })), }, None, ) diff --git a/ostool/tests/ui/pass_module_level_apis.rs b/ostool/tests/ui/pass_module_level_apis.rs index ca480a5..0aa255d 100644 --- a/ostool/tests/ui/pass_module_level_apis.rs +++ b/ostool/tests/ui/pass_module_level_apis.rs @@ -23,7 +23,7 @@ fn main() { ..Cargo::default() }; let cargo_build = BuildConfig { - system: BuildSystem::Cargo(cargo.clone()), + system: BuildSystem::Cargo(Box::new(cargo.clone())), }; let custom_build = BuildConfig { system: BuildSystem::Custom(Custom {