248 lines
7.1 KiB
Rust
248 lines
7.1 KiB
Rust
//! Integration tests for the `config` command.
|
|
|
|
use std::fs;
|
|
|
|
use assert_cmd::Command;
|
|
use predicates::prelude::*;
|
|
use serde_json::json;
|
|
use tempfile::tempdir;
|
|
|
|
fn cargo_command() -> Command {
|
|
Command::cargo_bin("config").expect("binary")
|
|
}
|
|
|
|
#[test]
|
|
fn no_args_prints_quick_help_card() {
|
|
let mut command = cargo_command();
|
|
command
|
|
.assert()
|
|
.code(2)
|
|
.stdout(predicate::str::is_empty())
|
|
.stderr(predicate::str::contains(
|
|
"error: provide a subcommand: get, set, delete, or ls",
|
|
))
|
|
.stderr(predicate::str::contains("config - Mercury Toolbox"))
|
|
.stderr(predicate::str::contains("Usage:"))
|
|
.stderr(predicate::str::contains("get [PATH] [POINTER]"))
|
|
.stderr(predicate::str::contains(
|
|
"config [OPTIONS] inspect [PATH] [POINTER]",
|
|
))
|
|
.stderr(predicate::str::contains(
|
|
"Type 'config --help' for the full command reference.",
|
|
));
|
|
}
|
|
|
|
#[test]
|
|
fn get_reads_toml_pointer_as_json() {
|
|
let temp = tempdir().expect("tempdir");
|
|
let path = temp.path().join("sample.toml");
|
|
fs::write(
|
|
&path,
|
|
"[package]\nname = \"toolbox\"\nversion = \"3.0.0\"\n",
|
|
)
|
|
.expect("fixture");
|
|
|
|
let mut command = cargo_command();
|
|
command
|
|
.arg("--json")
|
|
.arg("get")
|
|
.arg(&path)
|
|
.arg("/package/version")
|
|
.assert()
|
|
.success()
|
|
.stdout(predicate::str::contains("\"format\":\"toml\""))
|
|
.stdout(predicate::str::contains("\"pointer\":\"/package/version\""))
|
|
.stdout(predicate::str::contains("\"value\":\"3.0.0\""));
|
|
}
|
|
|
|
#[test]
|
|
fn set_then_get_updates_json_number_value() {
|
|
let temp = tempdir().expect("tempdir");
|
|
let path = temp.path().join("config.json");
|
|
fs::write(&path, "{\"retries\":1}\n").expect("fixture");
|
|
|
|
let mut set = cargo_command();
|
|
set.arg("set")
|
|
.arg(&path)
|
|
.arg("/retries")
|
|
.arg("5")
|
|
.arg("--json")
|
|
.arg("--value-type")
|
|
.arg("number")
|
|
.assert()
|
|
.success()
|
|
.stdout(predicate::str::contains("\"changed\":true"));
|
|
|
|
let mut get = cargo_command();
|
|
get.arg("--json")
|
|
.arg("get")
|
|
.arg(&path)
|
|
.arg("/retries")
|
|
.assert()
|
|
.success()
|
|
.stdout(predicate::str::contains("\"value\":5"));
|
|
}
|
|
|
|
#[test]
|
|
fn delete_removes_env_key() {
|
|
let temp = tempdir().expect("tempdir");
|
|
let path = temp.path().join(".env");
|
|
fs::write(&path, "KEEP=yes\nDROP=no\n").expect("fixture");
|
|
|
|
let mut command = cargo_command();
|
|
command
|
|
.arg("delete")
|
|
.arg(&path)
|
|
.arg("/DROP")
|
|
.assert()
|
|
.success()
|
|
.stdout(predicate::str::contains("op=delete"));
|
|
|
|
let content = fs::read_to_string(&path).expect("updated");
|
|
assert!(content.contains("KEEP=yes"));
|
|
assert!(!content.contains("DROP=no"));
|
|
}
|
|
|
|
#[test]
|
|
fn ls_lists_ini_section_entries() {
|
|
let temp = tempdir().expect("tempdir");
|
|
let path = temp.path().join("settings.ini");
|
|
fs::write(&path, "mode=dev\n[server]\nport=8080\nhost=127.0.0.1\n").expect("fixture");
|
|
|
|
let mut command = cargo_command();
|
|
command
|
|
.arg("--json")
|
|
.arg("ls")
|
|
.arg(&path)
|
|
.arg("/server")
|
|
.assert()
|
|
.success()
|
|
.stdout(predicate::str::contains("\"key\":\"host\""))
|
|
.stdout(predicate::str::contains("\"key\":\"port\""));
|
|
}
|
|
|
|
#[test]
|
|
fn ls_accepts_single_stdin_path_stream() {
|
|
let temp = tempdir().expect("tempdir");
|
|
let path = temp.path().join("config.json");
|
|
fs::write(&path, "{\"mode\":\"dev\",\"nested\":{\"ok\":true}}\n").expect("fixture");
|
|
|
|
let mut command = cargo_command();
|
|
command
|
|
.arg("--json")
|
|
.arg("ls")
|
|
.write_stdin(format!("{}\n", path.display()))
|
|
.assert()
|
|
.success()
|
|
.stdout(predicate::str::contains("\"pointer\":\"/\""))
|
|
.stdout(predicate::str::contains("\"key\":\"mode\""))
|
|
.stdout(predicate::str::contains("\"key\":\"nested\""));
|
|
}
|
|
|
|
#[test]
|
|
fn help_includes_new_subcommands_and_flags() {
|
|
let mut command = cargo_command();
|
|
command
|
|
.arg("--help")
|
|
.assert()
|
|
.success()
|
|
.stdout(predicate::str::contains("get [PATH] [POINTER]"))
|
|
.stdout(predicate::str::contains("set <PATH> <POINTER> <VALUE>"))
|
|
.stdout(predicate::str::contains("--value-type"))
|
|
.stdout(predicate::str::contains("--format"))
|
|
.stdout(predicate::str::contains("config"));
|
|
}
|
|
|
|
#[test]
|
|
fn ls_on_scalar_pointer_returns_no_results_exit_code() {
|
|
let temp = tempdir().expect("tempdir");
|
|
let path = temp.path().join("config.json");
|
|
fs::write(&path, "{\"mode\":\"dev\"}\n").expect("fixture");
|
|
|
|
let mut command = cargo_command();
|
|
command
|
|
.arg("ls")
|
|
.arg(&path)
|
|
.arg("/mode")
|
|
.assert()
|
|
.code(1)
|
|
.stdout(predicate::str::contains("entries=0"));
|
|
}
|
|
|
|
#[test]
|
|
fn delete_missing_json_key_returns_no_results_and_preserves_file() {
|
|
let temp = tempdir().expect("tempdir");
|
|
let path = temp.path().join("config.json");
|
|
fs::write(&path, "{\"present\":true}\n").expect("fixture");
|
|
|
|
let mut command = cargo_command();
|
|
command
|
|
.arg("--json")
|
|
.arg("delete")
|
|
.arg(&path)
|
|
.arg("/missing")
|
|
.assert()
|
|
.code(1)
|
|
.stdout(predicate::str::contains("\"changed\":false"))
|
|
.stdout(predicate::str::contains("\"pointer\":\"/missing\""));
|
|
|
|
let content = fs::read_to_string(&path).expect("updated");
|
|
let parsed: serde_json::Value = serde_json::from_str(&content).expect("valid json");
|
|
assert_eq!(parsed, json!({"present": true}));
|
|
}
|
|
|
|
#[test]
|
|
fn set_creates_nested_json_arrays_and_objects() {
|
|
let temp = tempdir().expect("tempdir");
|
|
let path = temp.path().join("config.json");
|
|
fs::write(&path, "{}\n").expect("fixture");
|
|
|
|
let mut command = cargo_command();
|
|
command
|
|
.arg("--json")
|
|
.arg("set")
|
|
.arg(&path)
|
|
.arg("/pkg/deps/0/name")
|
|
.arg("serde")
|
|
.assert()
|
|
.success()
|
|
.stdout(predicate::str::contains("\"changed\":true"));
|
|
|
|
let content = fs::read_to_string(&path).expect("updated");
|
|
let parsed: serde_json::Value = serde_json::from_str(&content).expect("valid json");
|
|
assert_eq!(parsed, json!({"pkg": {"deps": [{"name": "serde"}]}}));
|
|
}
|
|
|
|
#[test]
|
|
fn env_set_rejects_nested_pointer_and_non_scalar_json_values() {
|
|
let temp = tempdir().expect("tempdir");
|
|
let path = temp.path().join(".env");
|
|
fs::write(&path, "KEEP=yes\n").expect("fixture");
|
|
|
|
let mut nested_pointer = cargo_command();
|
|
nested_pointer
|
|
.arg("set")
|
|
.arg(&path)
|
|
.arg("/A/B")
|
|
.arg("x")
|
|
.assert()
|
|
.code(3)
|
|
.stderr(predicate::str::contains(
|
|
"env write operations only support root keys like /NAME",
|
|
));
|
|
|
|
let mut object_value = cargo_command();
|
|
object_value
|
|
.arg("set")
|
|
.arg(&path)
|
|
.arg("/OBJ")
|
|
.arg("{\"nested\":true}")
|
|
.arg("--value-type")
|
|
.arg("json")
|
|
.assert()
|
|
.code(3)
|
|
.stderr(predicate::str::contains(
|
|
"env/ini writes require scalar string|number|bool values",
|
|
));
|
|
}
|