#![allow(
clippy::print_stderr,
clippy::unwrap_used,
clippy::expect_used,
clippy::panic
)]
use std::ffi::OsStr;
use std::fs;
use std::path::Path;
use std::process::Command;
use tempfile::TempDir;
fn clean_environment_command(bin: impl AsRef<OsStr>) -> Command {
let mut cmd = Command::new(bin);
cmd.env_clear()
.env("PATH", std::env::var("PATH").unwrap_or_default())
.env("HOME", std::env::var("HOME").unwrap_or_default())
.env("USER", std::env::var("USER").unwrap_or_default());
cmd
}
fn create_test_dir() -> TempDir {
tempfile::Builder::new()
.prefix("cuenv_test_")
.tempdir()
.expect("Failed to create temp directory")
}
fn init_cue_module(dir: &Path) {
fs::create_dir_all(dir.join("cue.mod")).unwrap();
fs::write(
dir.join("cue.mod/module.cue"),
r#"module: "test.example/test"
language: version: "v0.9.0"
"#,
)
.unwrap();
}
fn find_in_path(name: &str) -> String {
let path_var = std::env::var("PATH").unwrap_or_default();
for dir in path_var.split(':') {
let candidate = std::path::PathBuf::from(dir).join(name);
if candidate.is_file() {
return candidate.to_string_lossy().to_string();
}
}
panic!("Could not find `{name}` in PATH");
}
fn run_cuenv(args: &[&str]) -> (String, String, bool) {
let cuenv_bin = env!("CARGO_BIN_EXE_cuenv");
let output = clean_environment_command(cuenv_bin)
.args(args)
.output()
.expect("Failed to run cuenv");
let stdout = String::from_utf8_lossy(&output.stdout).to_string();
let stderr = String::from_utf8_lossy(&output.stderr).to_string();
let success = output.status.success();
(stdout, stderr, success)
}
#[test]
fn test_task_list_with_shorthand() {
let temp_dir = create_test_dir();
init_cue_module(temp_dir.path());
let cue_content = r#"package test
name: "test"
env: {
TEST_VAR: "test_value"
}
tasks: {
test_task: {
command: "echo"
args: ["test"]
}
another_task: {
command: "echo"
args: ["another"]
}
}"#;
fs::write(temp_dir.path().join("env.cue"), cue_content).unwrap();
let (stdout, _stderr, success) = run_cuenv(&[
"t",
"-p",
temp_dir.path().to_str().unwrap(),
"--package",
"test",
]);
assert!(success, "Command should succeed");
assert!(stdout.contains("Tasks:"), "Should show tasks header");
assert!(stdout.contains("test_task"), "Should list test_task");
assert!(stdout.contains("another_task"), "Should list another_task");
}
#[test]
fn test_task_execution() {
let temp_dir = create_test_dir();
init_cue_module(temp_dir.path());
let cue_content = r#"package test
name: "test"
env: {
GREETING: "Hello"
NAME: "World"
}
tasks: {
greet: {
command: "echo"
args: ["Hello from task"]
}
}"#;
fs::write(temp_dir.path().join("env.cue"), cue_content).unwrap();
let (stdout, _, success) = run_cuenv(&[
"task",
"-p",
temp_dir.path().to_str().unwrap(),
"--package",
"test",
"greet",
]);
assert!(success, "Command should succeed");
assert!(
stdout.contains("Hello from task"),
"Should execute the task"
);
assert!(
stdout.contains("Task 'greet' succeeded"),
"Should show completion message"
);
}
#[test]
fn test_task_with_environment_propagation() {
let temp_dir = create_test_dir();
init_cue_module(temp_dir.path());
let cue_content = r#"package test
name: "test"
env: {
TEST_ENV_VAR: "propagated_value"
}
tasks: {
check_env: {
command: "printenv"
args: ["TEST_ENV_VAR"]
}
}"#;
fs::write(temp_dir.path().join("env.cue"), cue_content).unwrap();
let (stdout, _, success) = run_cuenv(&[
"t", "-p",
temp_dir.path().to_str().unwrap(),
"--package",
"test",
"check_env",
]);
assert!(success, "Command should succeed");
assert!(
stdout.contains("propagated_value"),
"Environment variable should be propagated"
);
}
#[test]
fn test_exec_command_with_shorthand() {
let temp_dir = create_test_dir();
init_cue_module(temp_dir.path());
let cue_content = r#"package test
name: "test"
env: {
EXEC_TEST: "exec_value"
}"#;
fs::write(temp_dir.path().join("env.cue"), cue_content).unwrap();
let (stdout, _, success) = run_cuenv(&[
"x",
"-p",
temp_dir.path().to_str().unwrap(),
"--package",
"test",
"printenv",
"EXEC_TEST",
]);
assert!(success, "Command should succeed");
assert!(
stdout.contains("exec_value"),
"Environment variable should be available to exec command"
);
}
#[test]
fn test_exec_with_arguments() {
let temp_dir = create_test_dir();
init_cue_module(temp_dir.path());
let cue_content = r#"package test
name: "test"
env: {
PREFIX: "Test"
}"#;
fs::write(temp_dir.path().join("env.cue"), cue_content).unwrap();
let (stdout, _, success) = run_cuenv(&[
"exec",
"-p",
temp_dir.path().to_str().unwrap(),
"--package",
"test",
"echo",
"arg1",
"arg2",
"arg3",
]);
assert!(success, "Command should succeed");
assert!(
stdout.contains("arg1 arg2 arg3"),
"All arguments should be passed"
);
}
#[test]
fn test_task_sequential_list() {
let temp_dir = create_test_dir();
init_cue_module(temp_dir.path());
let cue_content = r#"package test
name: "test"
env: {
COUNTER: "0"
}
tasks: {
sequence: [
{
command: "echo"
args: ["First"]
},
{
command: "echo"
args: ["Second"]
},
{
command: "echo"
args: ["Third"]
}
]
}"#;
fs::write(temp_dir.path().join("env.cue"), cue_content).unwrap();
let (stdout, _, success) = run_cuenv(&[
"task",
"-p",
temp_dir.path().to_str().unwrap(),
"--package",
"test",
"sequence",
]);
assert!(success, "Command should succeed");
assert!(stdout.contains("First"), "First task should run");
assert!(stdout.contains("Second"), "Second task should run");
assert!(stdout.contains("Third"), "Third task should run");
let first_pos = stdout.find("First").unwrap();
let second_pos = stdout.find("Second").unwrap();
let third_pos = stdout.find("Third").unwrap();
assert!(first_pos < second_pos, "First should come before Second");
assert!(second_pos < third_pos, "Second should come before Third");
}
#[test]
fn test_task_nested_groups() {
let temp_dir = create_test_dir();
init_cue_module(temp_dir.path());
let cue_content = r#"package test
name: "test"
env: {}
tasks: {
nested: {
type: "group"
subtask1: {
command: "echo"
args: ["Subtask 1"]
}
subtask2: {
command: "echo"
args: ["Subtask 2"]
}
}
}"#;
fs::write(temp_dir.path().join("env.cue"), cue_content).unwrap();
let (stdout, _, success) = run_cuenv(&[
"task",
"-p",
temp_dir.path().to_str().unwrap(),
"--package",
"test",
"nested",
]);
assert!(success, "Command should succeed");
assert!(
stdout.contains("Subtask 1") || stdout.contains("Subtask 2"),
"At least one subtask should run"
);
}
#[test]
fn test_nested_task_paths_and_aliases() {
let temp_dir = create_test_dir();
init_cue_module(temp_dir.path());
let cue_content = r#"package test
name: "test"
env: {}
let _t = tasks
tasks: {
bun: {
type: "group"
install: {
command: "echo"
args: ["bun install"]
}
test: {
command: "echo"
args: ["bun test"]
dependsOn: [_t.bun.install]
}
}
}
"#;
fs::write(temp_dir.path().join("env.cue"), cue_content).unwrap();
let (stdout, _, success) = run_cuenv(&[
"task",
"-p",
temp_dir.path().to_str().unwrap(),
"--package",
"test",
]);
assert!(success, "Listing nested tasks should succeed");
assert!(stdout.contains("bun"), "Should list parent group");
assert!(
stdout.contains("install"),
"Should list nested task install"
);
let (stdout, _, success) = run_cuenv(&[
"task",
"-p",
temp_dir.path().to_str().unwrap(),
"--package",
"test",
"bun.install",
]);
assert!(success, "Should run nested task via dotted syntax");
assert!(stdout.contains("bun install"));
let (stdout, _, success) = run_cuenv(&[
"task",
"-p",
temp_dir.path().to_str().unwrap(),
"--package",
"test",
"bun:install",
]);
assert!(success, "Should run nested task via colon syntax");
assert!(stdout.contains("bun install"));
let (stdout, _, success) = run_cuenv(&[
"task",
"-p",
temp_dir.path().to_str().unwrap(),
"--package",
"test",
"bun.test",
]);
assert!(success, "Dependent nested task should run");
assert!(
stdout.contains("bun install"),
"Dependency should execute using canonical path"
);
assert!(stdout.contains("bun test"));
}
#[test]
fn test_nonexistent_task_error() {
let temp_dir = create_test_dir();
init_cue_module(temp_dir.path());
let cue_content = r#"package test
name: "test"
env: {}
tasks: {
existing: {
command: "echo"
args: ["test"]
}
}"#;
fs::write(temp_dir.path().join("env.cue"), cue_content).unwrap();
let (_, stderr, success) = run_cuenv(&[
"task",
"-p",
temp_dir.path().to_str().unwrap(),
"--package",
"test",
"nonexistent",
]);
assert!(!success, "Command should fail");
assert!(
stderr.contains("not found") || stderr.contains("Task execution failed"),
"Should report task not found"
);
}
#[test]
fn test_exec_command_exit_code() {
let temp_dir = create_test_dir();
init_cue_module(temp_dir.path());
let cue_content = r"package test
env: {}";
fs::write(temp_dir.path().join("env.cue"), cue_content).unwrap();
let (_, _, success) = run_cuenv(&[
"exec",
"-p",
temp_dir.path().to_str().unwrap(),
"--package",
"test",
"false", ]);
assert!(!success, "Command should fail when executed command fails");
}
#[cfg(test)]
mod testexamples {
use super::*;
#[test]
fn test_task_basic_example() {
let manifest_dir = env!("CARGO_MANIFEST_DIR");
let project_root = Path::new(manifest_dir).parent().unwrap().parent().unwrap();
let example_path = project_root.join("examples/task-basic");
if !example_path.exists() {
eprintln!("Skipping test - example path doesn't exist: {example_path:?}");
return;
}
let (stdout, _, success) = run_cuenv(&[
"t",
"-p",
example_path.to_str().unwrap(),
"--package",
"examples",
]);
assert!(success, "Should list tasks successfully");
assert!(
stdout.contains("interpolate"),
"Should list interpolate task"
);
assert!(stdout.contains("propagate"), "Should list propagate task");
assert!(stdout.contains("greetAll"), "Should list greetAll task");
let (stdout, _, success) = run_cuenv(&[
"t",
"-p",
example_path.to_str().unwrap(),
"--package",
"examples",
"interpolate",
]);
assert!(success, "Should run interpolate task");
assert!(
stdout.contains("Jack O'Neill"),
"Should interpolate environment variable"
);
let (stdout, _, success) = run_cuenv(&[
"t",
"-p",
example_path.to_str().unwrap(),
"--package",
"examples",
"propagate",
]);
assert!(success, "Should run propagate task");
assert!(
stdout.contains("Jack O'Neill"),
"Should propagate environment variable"
);
let (stdout, _, success) = run_cuenv(&[
"x",
"-p",
example_path.to_str().unwrap(),
"--package",
"examples",
"printenv",
"NAME",
]);
assert!(success, "Should run exec command");
assert!(
stdout.contains("Jack O'Neill"),
"Should have environment variable available"
);
}
#[test]
fn test_complex_task_dependency_chain() {
let temp_dir = create_test_dir();
init_cue_module(temp_dir.path());
let cue_content = r#"package test
name: "test"
env: {
COUNTER: "0"
}
let _t = tasks
tasks: {
init: {
command: "echo"
args: ["Initializing..."]
}
build: {
command: "echo"
args: ["Building after init"]
dependsOn: [_t.init]
}
test: {
command: "echo"
args: ["Testing after build"]
dependsOn: [_t.build]
}
deploy: {
command: "echo"
args: ["Deploying after test"]
dependsOn: [_t.test]
}
}"#;
fs::write(temp_dir.path().join("env.cue"), cue_content).unwrap();
let (stdout, stderr, success) = run_cuenv(&[
"task",
"-p",
temp_dir.path().to_str().unwrap(),
"--package",
"test",
"deploy",
]);
assert!(
success,
"Command should succeed, stdout: {stdout}, stderr: {stderr}"
);
assert!(
stdout.contains("Initializing"),
"Init task should run, stdout: {stdout}"
);
assert!(stdout.contains("Building"), "Build task should run");
assert!(stdout.contains("Testing"), "Test task should run");
assert!(stdout.contains("Deploying"), "Deploy task should run");
let init_pos = stdout.find("Initializing").unwrap();
let build_pos = stdout.find("Building").unwrap();
let test_pos = stdout.find("Testing").unwrap();
let deploy_pos = stdout.find("Deploying").unwrap();
assert!(init_pos < build_pos, "Init should run before build");
assert!(build_pos < test_pos, "Build should run before test");
assert!(test_pos < deploy_pos, "Test should run before deploy");
}
#[test]
fn test_task_failure_handling() {
let temp_dir = create_test_dir();
init_cue_module(temp_dir.path());
let cue_content = r#"package test
name: "test"
env: {}
tasks: {
failing_task: {
command: "false" // Command that always fails
args: []
}
}"#;
fs::write(temp_dir.path().join("env.cue"), cue_content).unwrap();
let (_, stderr, success) = run_cuenv(&[
"task",
"-p",
temp_dir.path().to_str().unwrap(),
"--package",
"test",
"failing_task",
]);
assert!(!success, "Command should fail");
assert!(
stderr.contains("failed") || stderr.contains("error"),
"Should report failure"
);
}
#[test]
fn test_mixed_task_types() {
let temp_dir = create_test_dir();
init_cue_module(temp_dir.path());
let cue_content = r#"package test
name: "test"
env: {
PREFIX: "MIX"
}
tasks: {
single_task: {
command: "echo"
args: [env.PREFIX, "single"]
}
sequential_tasks: [
{
command: "echo"
args: [env.PREFIX, "seq1"]
},
{
command: "echo"
args: [env.PREFIX, "seq2"]
}
]
parallel_tasks: {
type: "group"
par1: {
command: "echo"
args: [env.PREFIX, "par1"]
}
par2: {
command: "echo"
args: [env.PREFIX, "par2"]
}
}
}"#;
fs::write(temp_dir.path().join("env.cue"), cue_content).unwrap();
let (stdout, _, success) = run_cuenv(&[
"task",
"-p",
temp_dir.path().to_str().unwrap(),
"--package",
"test",
"single_task",
]);
assert!(success);
assert!(stdout.contains("MIX single"));
let (stdout, _, success) = run_cuenv(&[
"task",
"-p",
temp_dir.path().to_str().unwrap(),
"--package",
"test",
"sequential_tasks",
]);
assert!(success);
assert!(stdout.contains("MIX seq1"));
assert!(stdout.contains("MIX seq2"));
let (stdout, _, success) = run_cuenv(&[
"task",
"-p",
temp_dir.path().to_str().unwrap(),
"--package",
"test",
"parallel_tasks",
]);
assert!(success);
assert!(stdout.contains("MIX par1") || stdout.contains("MIX par2"));
}
#[test]
fn test_special_characters_in_environment() {
let temp_dir = create_test_dir();
init_cue_module(temp_dir.path());
let cue_content = r#"package test
name: "test"
env: {
SPECIAL_CHARS: "Hello $USER & $(whoami) | `date` > /dev/null"
QUOTES: "He said \"Hello world\" and 'goodbye'"
SPACES: "Value with spaces"
}
tasks: {
test_special: {
command: "printenv"
args: ["SPECIAL_CHARS"]
}
test_quotes: {
command: "printenv"
args: ["QUOTES"]
}
test_spaces: {
command: "printenv"
args: ["SPACES"]
}
}"#;
fs::write(temp_dir.path().join("env.cue"), cue_content).unwrap();
let (stdout, _, success) = run_cuenv(&[
"task",
"-p",
temp_dir.path().to_str().unwrap(),
"--package",
"test",
"test_special",
]);
assert!(success);
assert!(stdout.contains("Hello $USER & $(whoami)"));
let (stdout, _, success) = run_cuenv(&[
"task",
"-p",
temp_dir.path().to_str().unwrap(),
"--package",
"test",
"test_quotes",
]);
assert!(success);
assert!(stdout.contains("\"Hello world\""));
let (stdout, _, success) = run_cuenv(&[
"task",
"-p",
temp_dir.path().to_str().unwrap(),
"--package",
"test",
"test_spaces",
]);
assert!(success);
assert!(stdout.contains("Value with spaces"));
}
#[test]
fn test_exec_with_complex_args() {
let temp_dir = create_test_dir();
init_cue_module(temp_dir.path());
let cue_content = r#"package test
name: "test"
env: {
TEST_VAR: "test_value"
}"#;
fs::write(temp_dir.path().join("env.cue"), cue_content).unwrap();
let (stdout, _, success) = run_cuenv(&[
"exec",
"-p",
temp_dir.path().to_str().unwrap(),
"--package",
"test",
"echo",
"arg with spaces",
"arg\"with\"quotes",
"arg'with'single'quotes",
"$TEST_VAR",
"$(echo 'command substitution')",
]);
assert!(success, "Command should succeed");
assert!(stdout.contains("arg with spaces"));
assert!(stdout.contains("arg\"with\"quotes"));
assert!(stdout.contains("arg'with'single'quotes"));
assert!(stdout.contains("$TEST_VAR"));
assert!(stdout.contains("$(echo 'command substitution')"));
}
}
#[test]
fn test_task_label_execution_is_path_scoped() {
let temp_dir = create_test_dir();
init_cue_module(temp_dir.path());
let project_a = temp_dir.path().join("project-a");
fs::create_dir_all(&project_a).unwrap();
fs::write(
project_a.join("env.cue"),
r#"package cuenv
name: "project-a"
env: {}
tasks: {
projen: {
command: "sh"
args: ["-c", "echo A-PROJEN"]
labels: ["projen"]
}
}
"#,
)
.unwrap();
let project_b = temp_dir.path().join("project-b");
fs::create_dir_all(&project_b).unwrap();
fs::write(
project_b.join("env.cue"),
r#"package cuenv
name: "project-b"
env: {}
tasks: {
generate: {
command: "sh"
args: ["-c", "echo B-PROJEN"]
labels: ["projen"]
}
}
"#,
)
.unwrap();
let (stdout, stderr, success) = run_cuenv(&[
"task",
"-p",
project_a.to_str().unwrap(),
"--package",
"cuenv",
"-l",
"projen",
]);
assert!(
success,
"Expected success.\n--- stdout ---\n{stdout}\n--- stderr ---\n{stderr}"
);
assert!(stdout.contains("A-PROJEN"));
assert!(
!stdout.contains("B-PROJEN"),
"Label execution must be scoped to the selected path"
);
}
#[test]
fn test_task_label_multiple_labels_and_semantics() {
let temp_dir = create_test_dir();
init_cue_module(temp_dir.path());
fs::write(
temp_dir.path().join("env.cue"),
r#"package test
name: "test"
env: {}
tasks: {
unit_tests: {
command: "sh"
args: ["-c", "echo UNIT-TESTS"]
labels: ["test", "unit"]
}
e2e_tests: {
command: "sh"
args: ["-c", "echo E2E-TESTS"]
labels: ["test"]
}
build: {
command: "sh"
args: ["-c", "echo BUILD"]
labels: ["build"]
}
}
"#,
)
.unwrap();
let (stdout, stderr, success) = run_cuenv(&[
"task",
"-p",
temp_dir.path().to_str().unwrap(),
"--package",
"test",
"-l",
"test",
"-l",
"unit",
]);
assert!(
success,
"Expected success.\n--- stdout ---\n{stdout}\n--- stderr ---\n{stderr}"
);
assert!(
stdout.contains("UNIT-TESTS"),
"Should execute unit_tests (has both labels)"
);
assert!(
!stdout.contains("E2E-TESTS"),
"Should NOT execute e2e_tests (missing 'unit' label)"
);
assert!(
!stdout.contains("BUILD"),
"Should NOT execute build (has neither label)"
);
}
#[test]
fn test_task_label_error_conflicting_task_name_and_label() {
let temp_dir = create_test_dir();
init_cue_module(temp_dir.path());
fs::write(
temp_dir.path().join("env.cue"),
r#"package test
name: "test"
env: {}
tasks: {
mytask: {
command: "echo"
args: ["hello"]
labels: ["test"]
}
}
"#,
)
.unwrap();
let (_stdout, stderr, success) = run_cuenv(&[
"task",
"-p",
temp_dir.path().to_str().unwrap(),
"--package",
"test",
"mytask",
"-l",
"test",
]);
assert!(
!success,
"Expected failure when specifying both task name and label"
);
assert!(
stderr.contains("Cannot specify both a task name") && stderr.contains("--label"),
"Error message should mention conflict. Got: {stderr}"
);
}
#[test]
fn test_task_label_error_trailing_args_become_task_name() {
let temp_dir = create_test_dir();
init_cue_module(temp_dir.path());
fs::write(
temp_dir.path().join("env.cue"),
r#"package test
name: "test"
env: {}
tasks: {
mytask: {
command: "echo"
labels: ["test"]
}
}
"#,
)
.unwrap();
let (_stdout, stderr, success) = run_cuenv(&[
"task",
"-p",
temp_dir.path().to_str().unwrap(),
"--package",
"test",
"-l",
"test",
"--",
"arg1",
"arg2",
]);
assert!(
!success,
"Expected failure when using trailing args with label selection"
);
assert!(
stderr.contains("Cannot specify both a task name") && stderr.contains("--label"),
"Error message should mention conflict (trailing arg becomes task name). Got: {stderr}"
);
}
#[test]
fn test_task_label_error_no_matching_tasks() {
let temp_dir = create_test_dir();
init_cue_module(temp_dir.path());
fs::write(
temp_dir.path().join("env.cue"),
r#"package test
name: "test"
env: {}
tasks: {
mytask: {
command: "echo"
args: ["hello"]
labels: ["existing"]
}
}
"#,
)
.unwrap();
let (_stdout, stderr, success) = run_cuenv(&[
"task",
"-p",
temp_dir.path().to_str().unwrap(),
"--package",
"test",
"-l",
"nonexistent",
]);
assert!(!success, "Expected failure when no tasks match label");
assert!(
stderr.contains("No tasks with labels") && stderr.contains("nonexistent"),
"Error message should mention no matching tasks. Got: {stderr}"
);
}
#[test]
fn test_task_label_error_empty_labels() {
let temp_dir = create_test_dir();
init_cue_module(temp_dir.path());
fs::write(
temp_dir.path().join("env.cue"),
r#"package test
name: "test"
env: {}
tasks: {
mytask: {
command: "echo"
labels: ["test"]
}
}
"#,
)
.unwrap();
let (_stdout, stderr, success) = run_cuenv(&[
"task",
"-p",
temp_dir.path().to_str().unwrap(),
"--package",
"test",
"-l",
" ",
]);
assert!(!success, "Expected failure with empty/whitespace labels");
assert!(
stderr.contains("empty") || stderr.contains("whitespace"),
"Error message should mention empty/whitespace labels. Got: {stderr}"
);
}
#[test]
fn test_exec_hermetic_path_no_host_pollution() {
let temp_dir = create_test_dir();
init_cue_module(temp_dir.path());
let cue_content = r#"package test
name: "test"
env: {
PATH: "/cuenv/tools/bin"
}"#;
fs::write(temp_dir.path().join("env.cue"), cue_content).unwrap();
let printenv = find_in_path("printenv");
let (stdout, _stderr, success) = run_cuenv(&[
"exec",
"-p",
temp_dir.path().to_str().unwrap(),
"--package",
"test",
&printenv,
"PATH",
]);
assert!(success, "Command should succeed");
let path = stdout.trim();
assert_eq!(
path, "/cuenv/tools/bin",
"PATH should be exactly what was set in env.cue, not polluted with host PATH. Got: {path}"
);
assert!(
!path.contains("/usr/bin"),
"PATH should not contain /usr/bin (host pollution)"
);
assert!(
!path.contains("/usr/local"),
"PATH should not contain /usr/local (host pollution)"
);
assert!(
!path.contains("/opt/homebrew"),
"PATH should not contain /opt/homebrew (host pollution)"
);
}
#[test]
fn test_task_hermetic_path_no_host_pollution() {
let temp_dir = create_test_dir();
init_cue_module(temp_dir.path());
let printenv = find_in_path("printenv");
let cue_content = format!(
r#"package test
name: "test"
env: {{
PATH: "/cuenv/tools/bin"
}}
tasks: {{
show_path: {{
command: "{printenv}"
args: ["PATH"]
}}
}}"#
);
fs::write(temp_dir.path().join("env.cue"), cue_content).unwrap();
let (stdout, _stderr, success) = run_cuenv(&[
"task",
"-p",
temp_dir.path().to_str().unwrap(),
"--package",
"test",
"show_path",
]);
assert!(success, "Command should succeed");
let path_line = stdout
.lines()
.find(|line| line.starts_with("/cuenv/tools/bin") || line.contains("PATH"))
.unwrap_or("");
assert!(
path_line.contains("/cuenv/tools/bin"),
"PATH should contain our custom path. Got output: {stdout}"
);
assert!(
!path_line.contains("/usr/bin"),
"PATH should not contain /usr/bin (host pollution). Got: {path_line}"
);
assert!(
!path_line.contains("/usr/local"),
"PATH should not contain /usr/local (host pollution). Got: {path_line}"
);
}