forked from Crockan/MercuryToolbox
chore(release): prepare public source release
This commit is contained in:
@@ -0,0 +1,29 @@
|
||||
[package]
|
||||
name = "config"
|
||||
version.workspace = true
|
||||
edition.workspace = true
|
||||
rust-version.workspace = true
|
||||
license.workspace = true
|
||||
authors.workspace = true
|
||||
readme.workspace = true
|
||||
publish.workspace = true
|
||||
description = "Summarize common config file formats into compact AI-friendly key paths."
|
||||
keywords.workspace = true
|
||||
categories.workspace = true
|
||||
|
||||
[lints]
|
||||
workspace = true
|
||||
|
||||
[dependencies]
|
||||
configsupport = { path = "../configsupport" }
|
||||
common = { path = "../common" }
|
||||
lexopt.workspace = true
|
||||
serde.workspace = true
|
||||
serde_json = { workspace = true, features = ["preserve_order"] }
|
||||
serde_yaml = "0.9.34"
|
||||
toml = "0.8.23"
|
||||
|
||||
[dev-dependencies]
|
||||
assert_cmd.workspace = true
|
||||
predicates.workspace = true
|
||||
tempfile.workspace = true
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,5 @@
|
||||
//! Binary entry point for `config`.
|
||||
|
||||
fn main() {
|
||||
std::process::exit(config::main_entry());
|
||||
}
|
||||
@@ -0,0 +1,247 @@
|
||||
//! 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",
|
||||
));
|
||||
}
|
||||
Reference in New Issue
Block a user