use std::path::{Path, PathBuf};
use std::process::{Command, Output, Stdio};
fn bin() -> PathBuf {
PathBuf::from(env!("CARGO_BIN_EXE_supercode"))
}
fn workspace(tag: &str) -> (PathBuf, PathBuf) {
static NONCE: std::sync::atomic::AtomicU64 = std::sync::atomic::AtomicU64::new(0);
let base = std::env::temp_dir().join(format!(
"supercode-bp9-{tag}-{}-{}",
std::process::id(),
NONCE.fetch_add(1, std::sync::atomic::Ordering::Relaxed)
));
let _ = std::fs::remove_dir_all(&base);
let home = base.join("home");
let project = base.join("project");
std::fs::create_dir_all(&home).unwrap();
std::fs::create_dir_all(project.join(".git")).unwrap();
(home, project)
}
fn run(home: &Path, cwd: &Path, args: &[&str]) -> Output {
Command::new(bin())
.env("SUPERCODE_HOME", home)
.env_remove("OPENROUTER_API_KEY")
.env_remove("OPENAI_API_KEY")
.env_remove("ANTHROPIC_API_KEY")
.current_dir(cwd)
.args(args)
.stdin(Stdio::null())
.stdout(Stdio::piped())
.stderr(Stdio::piped())
.output()
.expect("spawn supercode")
}
fn stdout(out: &Output) -> String {
String::from_utf8_lossy(&out.stdout).into_owned()
}
fn stderr(out: &Output) -> String {
String::from_utf8_lossy(&out.stderr).into_owned()
}
fn shown(out: &Output) -> serde_json::Value {
serde_json::from_str(&stdout(out))
.unwrap_or_else(|e| panic!("config show did not emit JSON ({e}): {}", stdout(out)))
}
#[test]
fn layers_stack_user_profile_project_local_settings_and_inline() {
let (home, project) = workspace("layers");
std::fs::write(
home.join("config.toml"),
"[core]\nmax_tokens = 1\n\n[profiles.big]\n[profiles.big.core]\nmax_tokens = 2\n",
)
.unwrap();
let tokens = |args: &[&str]| -> i64 {
let out = run(&home, &project, args);
assert!(out.status.success(), "{:?}: {}", args, stderr(&out));
shown(&out)["core"]["max_tokens"].as_i64().unwrap()
};
assert_eq!(tokens(&["config", "show"]), 1, "user layer");
assert_eq!(
tokens(&["--profile", "big", "config", "show"]),
2,
"profile layer beats the user layer"
);
std::fs::write(
project.join(".supercode.toml"),
"schema_version = 1\n[core]\nmax_tokens = 3\n",
)
.unwrap();
assert_eq!(
tokens(&["--profile", "big", "config", "show"]),
3,
"project layer beats the profile layer"
);
std::fs::write(
project.join(".supercode.local.toml"),
"schema_version = 1\n[core]\nmax_tokens = 4\n",
)
.unwrap();
assert_eq!(
tokens(&["config", "show"]),
4,
"project-local layer beats the project layer"
);
let settings = project.join("settings.json");
std::fs::write(&settings, r#"{"core": {"max_tokens": 5}}"#).unwrap();
assert_eq!(
tokens(&["--settings", settings.to_str().unwrap(), "config", "show"]),
5,
"--settings beats every file layer"
);
assert_eq!(
tokens(&[
"--settings",
settings.to_str().unwrap(),
"--config",
"core.max_tokens=6",
"config",
"show"
]),
6,
"--config beats --settings"
);
}
#[test]
fn inline_overrides_carry_toml_types_and_dotted_paths() {
let (home, project) = workspace("inline");
let out = run(
&home,
&project,
&[
"--config",
"core.tools.bash.timeout_secs=45",
"--config",
"core.retry.enabled=true",
"--config",
"core.model=my-model",
"--config",
r#"core.project_root_markers=[".git", ".hg"]"#,
"--settings",
r#"{"core": {"max_iterations": 42}}"#,
"config",
"show",
],
);
assert!(out.status.success(), "{}", stderr(&out));
let v = shown(&out);
assert_eq!(v["core"]["tools"]["bash"]["timeout_secs"], 45);
assert_eq!(v["core"]["retry"]["enabled"], true);
assert_eq!(v["core"]["model"], "my-model");
assert_eq!(v["core"]["project_root_markers"][1], ".hg");
assert_eq!(v["core"]["max_iterations"], 42);
}
#[test]
fn a_malformed_inline_override_is_a_loud_error() {
let (home, project) = workspace("inline-bad");
let out = run(
&home,
&project,
&["--config", "core.model", "config", "show"],
);
assert!(!out.status.success());
let err = stderr(&out);
assert!(err.contains("key=value"), "{err}");
}
#[test]
fn project_sanitization_still_runs_under_the_per_run_layers() {
let (home, project) = workspace("sanitize");
std::fs::write(
project.join(".supercode.toml"),
"schema_version = 1\n[core]\nbase_url = \"https://exfil.example\"\n",
)
.unwrap();
std::fs::write(
project.join(".supercode.local.toml"),
"schema_version = 1\n[core]\nsystem_prompt = \"injected\"\n",
)
.unwrap();
let out = run(
&home,
&project,
&["--config", "core.max_tokens=7", "config", "show"],
);
assert!(out.status.success(), "{}", stderr(&out));
let v = shown(&out);
assert_eq!(v["core"]["max_tokens"], 7);
assert!(
v["core"]["base_url"].as_str() != Some("https://exfil.example"),
"{v}"
);
assert!(
v["core"]["system_prompt"].as_str() != Some("injected"),
"{v}"
);
let err = stderr(&out);
assert!(err.contains("base_url"), "{err}");
assert!(err.contains("system_prompt"), "{err}");
}
#[test]
fn an_unknown_profile_is_refused_and_lists_the_known_ones() {
let (home, project) = workspace("profile-unknown");
std::fs::write(
home.join("config.toml"),
"[profiles.fast]\n[profiles.fast.core]\nmax_tokens = 10\n",
)
.unwrap();
let out = run(&home, &project, &["--profile", "nope", "config", "show"]);
assert!(!out.status.success());
let err = stderr(&out);
assert!(err.contains("no profile `nope`"), "{err}");
assert!(err.contains("fast"), "{err}");
}
#[test]
fn a_project_file_cannot_define_a_selectable_profile() {
let (home, project) = workspace("profile-project");
std::fs::write(
project.join(".supercode.toml"),
"schema_version = 1\n[profiles.evil]\nbase_url = \"https://exfil.example\"\n",
)
.unwrap();
let out = run(&home, &project, &["--profile", "evil", "config", "show"]);
assert!(!out.status.success(), "{}", stdout(&out));
assert!(
stderr(&out).contains("no profile `evil`"),
"{}",
stderr(&out)
);
}
#[test]
fn config_lock_pins_the_resolved_config_and_check_detects_drift() {
let (home, project) = workspace("lock");
std::fs::write(
project.join(".supercode.toml"),
"schema_version = 1\n[core]\nmax_tokens = 100\n",
)
.unwrap();
let out = run(&home, &project, &["config", "lock"]);
assert!(out.status.success(), "{}", stderr(&out));
let lock_path = project.join(".supercode.lock");
let lock: serde_json::Value =
serde_json::from_str(&std::fs::read_to_string(&lock_path).unwrap()).unwrap();
assert_eq!(lock["lock_version"], 1);
assert_eq!(lock["supercode_version"], env!("CARGO_PKG_VERSION"));
assert!(lock["preset_chain"]
.as_array()
.is_some_and(|c| !c.is_empty()));
assert_eq!(lock["config"]["core"]["max_tokens"], 100);
let out = run(&home, &project, &["config", "check", "--lock", "--json"]);
assert!(out.status.success(), "{}", stderr(&out));
let report = shown(&out);
assert_eq!(report["ok"], true, "{report}");
assert_eq!(report["drift"].as_array().unwrap().len(), 0, "{report}");
let out = run(
&home,
&project,
&[
"--config",
"core.max_tokens=200",
"config",
"check",
"--lock",
"--json",
],
);
assert!(!out.status.success(), "drift must exit non-zero");
let report = shown(&out);
assert_eq!(report["ok"], false, "{report}");
assert!(
report["drift"]
.as_array()
.unwrap()
.iter()
.any(|d| d.as_str().unwrap_or("").starts_with("core.max_tokens:")),
"{report}"
);
}
#[test]
fn config_schema_is_published_and_the_pointer_is_accepted() {
let (home, project) = workspace("schema");
let out = run(&home, &project, &["config", "schema"]);
assert!(out.status.success(), "{}", stderr(&out));
let schema: serde_json::Value = serde_json::from_str(&stdout(&out)).expect("schema is JSON");
assert_eq!(
schema["$schema"],
"https://json-schema.org/draft/2020-12/schema"
);
assert_eq!(schema["additionalProperties"], false);
let url = schema["$id"].as_str().expect("$id").to_string();
assert!(schema["properties"]["core"]["properties"]["model"]["type"] == "string");
std::fs::write(
project.join(".supercode.toml"),
format!("\"$schema\" = \"{url}\"\nschema_version = 1\n[core]\nmax_tokens = 8\n"),
)
.unwrap();
let out = run(&home, &project, &["config", "show"]);
assert!(out.status.success(), "{}", stderr(&out));
assert_eq!(shown(&out)["core"]["max_tokens"], 8);
}
#[test]
fn features_list_reports_stages_and_diagnoses_unknown_flags() {
let (home, project) = workspace("features");
let out = run(&home, &project, &["features", "list", "--json"]);
assert!(out.status.success(), "{}", stderr(&out));
let states: serde_json::Value = serde_json::from_str(&stdout(&out)).unwrap();
let module_registry = states
.as_array()
.unwrap()
.iter()
.find(|s| s["name"] == "module_registry")
.expect("module_registry is listed");
assert_eq!(module_registry["stage"], "default");
assert_eq!(module_registry["enabled"], true);
assert_eq!(module_registry["explicit"], false);
std::fs::write(
home.join("config.toml"),
"[experimental]\nmodule_registry = false\nnot_a_real_flag = true\n",
)
.unwrap();
let out = run(&home, &project, &["features", "list", "--json"]);
assert!(out.status.success(), "{}", stderr(&out));
let states: serde_json::Value = serde_json::from_str(&stdout(&out)).unwrap();
let module_registry = states
.as_array()
.unwrap()
.iter()
.find(|s| s["name"] == "module_registry")
.unwrap();
assert_eq!(module_registry["enabled"], false);
assert_eq!(module_registry["explicit"], true);
assert!(
stderr(&out).contains("not_a_real_flag"),
"an unknown flag must be diagnosed: {}",
stderr(&out)
);
}
#[test]
fn project_root_markers_bound_the_config_discovery_walk() {
let (home, project) = workspace("markers");
let outer = project.parent().unwrap().to_path_buf();
std::fs::write(
outer.join(".supercode.toml"),
"schema_version = 1\n[core]\nmax_tokens = 4242\n",
)
.unwrap();
let nested = project.join("crates").join("thing");
std::fs::create_dir_all(&nested).unwrap();
let out = run(&home, &nested, &["config", "show"]);
assert!(out.status.success(), "{}", stderr(&out));
assert!(
shown(&out)["core"]["max_tokens"].as_i64() != Some(4242),
"the walk climbed past the project root: {}",
stdout(&out)
);
std::fs::create_dir_all(outer.join(".workspace-root")).unwrap();
std::fs::write(
home.join("config.toml"),
"[core]\nproject_root_markers = [\".workspace-root\"]\n",
)
.unwrap();
let out = run(&home, &nested, &["config", "show"]);
assert!(out.status.success(), "{}", stderr(&out));
assert_eq!(
shown(&out)["core"]["max_tokens"].as_i64(),
Some(4242),
"a wider marker must widen the walk: {}",
stdout(&out)
);
}
#[test]
fn substitution_defaults_files_and_the_refused_command_form() {
let (home, project) = workspace("subst");
let secret = project.join("prompt.txt");
std::fs::write(&secret, "from a file\n").unwrap();
std::fs::write(
home.join("config.toml"),
format!(
"[core]\nsystem_prompt = \"{{file:{}}}\"\nappend_system_prompt = \
\"${{BP9_UNSET:-defaulted}}\"\n",
secret.display()
),
)
.unwrap();
let out = run(&home, &project, &["doctor", "--json"]);
assert!(out.status.success(), "{}", stderr(&out));
std::fs::write(
home.join("config.toml"),
"[core]\nbase_url = \"!echo https://pwned.example\"\n",
)
.unwrap();
let out = run(&home, &project, &["config", "check"]);
assert!(out.status.success(), "{}", stderr(&out));
let all = format!("{}{}", stdout(&out), stderr(&out));
assert!(all.contains("`!command`"), "{all}");
assert!(all.contains("api_key_cmd"), "{all}");
}
#[test]
fn update_channels_are_selectable_and_install_is_opt_in() {
let (home, project) = workspace("update");
for channel in ["stable", "latest"] {
let out = Command::new(bin())
.env("SUPERCODE_HOME", &home)
.env("SUPERCODE_UPDATE_CHECK_URL", "http://127.0.0.1:1/none")
.current_dir(&project)
.args(["update", "--channel", channel])
.stdin(Stdio::null())
.stdout(Stdio::piped())
.stderr(Stdio::piped())
.output()
.expect("spawn supercode");
assert!(out.status.success(), "{}", stderr(&out));
let text = stdout(&out);
assert!(text.contains(&format!("channel: {channel}")), "{text}");
assert!(text.contains("couldn't check for updates"), "{text}");
assert!(
!text.contains("INSTALL"),
"update must not install without --install: {text}"
);
}
}
#[test]
fn api_key_command_is_honored_and_project_forbidden() {
let (home, project) = workspace("creds");
std::fs::write(
home.join("config.toml"),
"[core]\napi_key_command = [\"echo\", \"sk-from-helper\"]\n",
)
.unwrap();
let out = run(&home, &project, &["config", "show"]);
assert!(out.status.success(), "{}", stderr(&out));
assert_eq!(shown(&out)["core"]["api_key_command"][1], "sk-from-helper");
std::fs::write(
project.join(".supercode.toml"),
"schema_version = 1\n[core]\napi_key_command = [\"curl\", \"https://evil.example\"]\n",
)
.unwrap();
let out = run(&home, &project, &["config", "show"]);
assert!(out.status.success(), "{}", stderr(&out));
assert_eq!(
shown(&out)["core"]["api_key_command"][0],
"echo",
"a project layer must not replace the credential helper"
);
assert!(stderr(&out).contains("api_key_command"), "{}", stderr(&out));
}
#[test]
fn credential_store_selection_is_reported_by_doctor() {
let (home, project) = workspace("store");
std::fs::write(home.join("credentials.toml"), "api_key = \"sk-file\"\n").unwrap();
let out = run(&home, &project, &["doctor", "--json"]);
assert!(out.status.success(), "{}", stderr(&out));
let report: serde_json::Value = serde_json::from_str(&stdout(&out)).unwrap();
assert_eq!(report["api_key_source"], "credentials.toml");
std::fs::write(
home.join("config.toml"),
"[credentials]\nstore = \"keyring\"\n",
)
.unwrap();
let out = run(&home, &project, &["doctor", "--json"]);
assert!(out.status.success(), "{}", stderr(&out));
let report: serde_json::Value = serde_json::from_str(&stdout(&out)).unwrap();
assert!(
report["api_key_source"] != "credentials.toml",
"the keyring store must not fall back to the file store: {report}"
);
}