-
Notifications
You must be signed in to change notification settings - Fork 0
feat: add --json flag to list command #1
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 1 commit
8186d91
8e81d14
041f5a3
25dbe03
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -34,6 +34,9 @@ enum Commands { | |
| /// Compact mode: show only binary name instead of full path | ||
| #[arg(short, long)] | ||
| compact: bool, | ||
| /// Output as JSON array | ||
| #[arg(long)] | ||
| json: bool, | ||
| }, | ||
| /// Grant a TCC permission (inserts new entry) | ||
| Grant { | ||
|
|
@@ -204,10 +207,12 @@ mod tests { | |
| client, | ||
| service, | ||
| compact, | ||
| json, | ||
| } => { | ||
| assert_eq!(client.as_deref(), Some("apple")); | ||
| assert_eq!(service.as_deref(), Some("Camera")); | ||
| assert!(!compact); | ||
| assert!(!json); | ||
| } | ||
| _ => panic!("expected List"), | ||
| } | ||
|
|
@@ -222,6 +227,15 @@ mod tests { | |
| } | ||
| } | ||
|
|
||
| #[test] | ||
| fn parse_list_json() { | ||
| let cli = parse(&["tcc", "list", "--json"]).unwrap(); | ||
| match cli.command { | ||
| Commands::List { json, .. } => assert!(json), | ||
| _ => panic!("expected List"), | ||
| } | ||
| } | ||
|
|
||
| #[test] | ||
| fn parse_services() { | ||
| let cli = parse(&["tcc", "services"]).unwrap(); | ||
|
|
@@ -401,10 +415,21 @@ fn main() { | |
| client, | ||
| service, | ||
| compact, | ||
| json, | ||
| } => { | ||
| let db = make_db(target); | ||
| match db.list(client.as_deref(), service.as_deref()) { | ||
| Ok(entries) => print_entries(&entries, compact), | ||
| Ok(entries) => { | ||
| if json { | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. SUGGESTION: When a user passes both
|
||
| println!( | ||
| "{}", | ||
| serde_json::to_string_pretty(&entries) | ||
| .expect("failed to serialize entries") | ||
| ); | ||
| } else { | ||
| print_entries(&entries, compact); | ||
| } | ||
| } | ||
| Err(e) => { | ||
| eprintln!("{}: {}", "Error".red().bold(), e); | ||
| process::exit(1); | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,3 +1,4 @@ | ||
| use serde_json::Value; | ||
| use std::process::Command; | ||
|
|
||
| /// Helper: run the `tccutil-rs` binary with given args, returning (stdout, stderr, success). | ||
|
|
@@ -129,3 +130,53 @@ fn version_flag_prints_version() { | |
| "version output should mention tccutil-rs" | ||
| ); | ||
| } | ||
|
|
||
| // ── tccutil-rs list --json ────────────────────────────────────────── | ||
|
|
||
| #[test] | ||
| fn list_json_outputs_valid_json_array() { | ||
| let (stdout, _stderr, success) = run_tcc(&["--user", "list", "--json"]); | ||
| assert!(success, "tccutil-rs --user list --json should exit 0"); | ||
|
|
||
| let parsed: Value = serde_json::from_str(&stdout).expect("output should be valid JSON"); | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. WARNING: Field-presence assertions are vacuously skipped when the DB is empty If the user TCC database has no entries (common in CI), Consider adding a guard or using a fixture DB to ensure at least one entry is present when the field-structure assertions need to run. |
||
| assert!(parsed.is_array(), "JSON output should be an array"); | ||
|
|
||
| // If there are entries, verify expected fields exist | ||
| if let Some(arr) = parsed.as_array() { | ||
| for entry in arr { | ||
| assert!(entry.get("service_raw").is_some(), "missing service_raw"); | ||
| assert!( | ||
| entry.get("service_display").is_some(), | ||
| "missing service_display" | ||
| ); | ||
| assert!(entry.get("client").is_some(), "missing client"); | ||
| assert!(entry.get("auth_value").is_some(), "missing auth_value"); | ||
| assert!( | ||
| entry.get("last_modified").is_some(), | ||
| "missing last_modified" | ||
| ); | ||
| assert!(entry.get("is_system").is_some(), "missing is_system"); | ||
| } | ||
| } | ||
| } | ||
|
|
||
| #[test] | ||
| fn list_json_with_client_filter_only_contains_matching_entries() { | ||
| let (stdout, _stderr, success) = run_tcc(&["--user", "list", "--json", "--client", "apple"]); | ||
| assert!( | ||
| success, | ||
| "tccutil-rs --user list --json --client apple should exit 0" | ||
| ); | ||
|
|
||
| let parsed: Value = serde_json::from_str(&stdout).expect("output should be valid JSON"); | ||
| let arr = parsed.as_array().expect("should be an array"); | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. WARNING: Vacuous test — filter correctness is never verified when the DB is empty If no TCC entries match Consider adding an explicit check: // Ensure the test is meaningful only when entries exist
if !arr.is_empty() {
for entry in arr {
let client = entry["client"].as_str().expect("client should be a string");
assert!(
client.to_lowercase().contains("apple"),
"filtered entry should contain 'apple', got: {}",
client
);
}
}
// Or document the vacuous-pass behaviour explicitly:
// assert!(arr.is_empty() || arr.iter().all(|e| ...));Alternatively, use a fixture/mock DB so the test always has data to validate against. |
||
|
|
||
| for entry in arr { | ||
| let client = entry["client"].as_str().expect("client should be a string"); | ||
| assert!( | ||
| client.to_lowercase().contains("apple"), | ||
| "filtered entry should contain 'apple', got: {}", | ||
| client | ||
| ); | ||
| } | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
WARNING: Redundant
serde_jsonin[dev-dependencies]serde_jsonis already declared as a regular[dependencies]entry (line 20), which is available to tests automatically. Listing it again under[dev-dependencies]is harmless but unnecessary — Cargo will simply unify the two entries. The duplicate line can be removed.