use proto_core::test_utils::*;
use starbase_sandbox::predicates::prelude::*;
mod exec {
use super::*;
#[test]
fn errors_if_no_command() {
let sandbox = create_empty_proto_sandbox();
let assert = sandbox.run_bin(|cmd| {
cmd.arg("exec");
});
assert.failure().stderr(predicate::str::contains(
"A command is required for execution.",
));
}
#[test]
fn errors_for_invalid_context() {
let sandbox = create_empty_proto_sandbox();
let assert = sandbox.run_bin(|cmd| {
cmd.args(["exec", "foo bar", "--", "echo"]);
});
assert.failure().stderr(predicate::str::contains(
"Invalid identifier format for `foo bar`.",
));
}
#[test]
fn errors_for_invalid_spec() {
let sandbox = create_empty_proto_sandbox();
let assert = sandbox.run_bin(|cmd| {
cmd.args(["exec", "tool@a b c", "--", "echo"]);
});
assert.failure().stderr(predicate::str::contains(
"Invalid version or requirement in tool specification a b c.",
));
}
#[test]
fn errors_use_reporter_output_in_agent_environments() {
let sandbox = create_empty_proto_sandbox();
let assert = sandbox.run_bin(|cmd| {
cmd.arg("exec")
.env("CODEX_CI", "1")
.env_remove("PROTO_REPORTER");
});
let stdout = assert.stdout();
let records = stdout
.lines()
.map(|line| serde_json::from_str::<serde_json::Value>(line).unwrap())
.collect::<Vec<_>>();
assert.failure();
assert!(records.iter().any(|record| {
record.get("type").and_then(|value| value.as_str()) == Some("error")
&& record
.get("message")
.and_then(|value| value.as_str())
.is_some_and(|message| message.contains("A command is required for execution."))
}));
}
#[test]
fn can_execute_without_tools() {
let sandbox = create_empty_proto_sandbox();
let assert = sandbox.run_bin(|cmd| {
cmd.args(["exec", "--", "echo", "hello"]);
});
assert.success().stdout(predicate::str::contains("hello"));
}
#[test]
fn one_tool() {
let sandbox = create_empty_proto_sandbox();
sandbox
.run_bin(|cmd| {
cmd.args(["install", "node", "20"]);
})
.success();
let assert = sandbox.run_bin(|cmd| {
cmd.args(["exec", "node", "--", "node", "--version"]);
});
assert
.success()
.stdout(predicate::str::contains("v20.20.2"));
}
#[test]
fn many_tools() {
let sandbox = create_empty_proto_sandbox();
sandbox.create_file(
".prototools",
r#"
node = "20"
bun = "1.2"
"#,
);
sandbox
.run_bin(|cmd| {
cmd.arg("install");
})
.success();
let assert = sandbox.run_bin(|cmd| {
cmd.args([
"exec",
"node",
"bun",
"--shell",
"bash",
"--raw",
"--",
"node --version && bun --version",
]);
});
assert
.inner
.stdout(predicate::str::contains("v20.20.2").and(predicate::str::contains("1.2.23")));
}
#[test]
fn can_use_all_config_tools() {
let sandbox = create_empty_proto_sandbox();
sandbox.create_file(
".prototools",
r#"
node = "20"
bun = "1.2"
"#,
);
sandbox
.run_bin(|cmd| {
cmd.arg("install");
})
.success();
let assert = sandbox.run_bin(|cmd| {
cmd.args([
"exec",
"--tools-from-config",
"--shell",
"bash",
"--raw",
"--",
"node --version && bun --version",
]);
});
assert
.inner
.stdout(predicate::str::contains("v20.20.2").and(predicate::str::contains("1.2.23")));
}
#[test]
fn can_scope_by_version_part() {
let sandbox = create_empty_proto_sandbox();
sandbox
.run_bin(|cmd| {
cmd.args(["install", "node", "20.19.5"]);
})
.success();
sandbox
.run_bin(|cmd| {
cmd.args(["install", "node", "20.18.3"]);
})
.success();
let assert = sandbox.run_bin(|cmd| {
cmd.args(["exec", "node@20", "--", "node", "--version"]);
});
assert
.success()
.stdout(predicate::str::contains("v20.19.5"));
let assert = sandbox.run_bin(|cmd| {
cmd.args(["exec", "node@20.18", "--", "node", "--version"]);
});
assert
.success()
.stdout(predicate::str::contains("v20.18.3"));
}
}