Skip to content

Commit 78eb8ce

Browse files
committed
test: cover packaged cli behavior
1 parent 80ca98f commit 78eb8ce

3 files changed

Lines changed: 119 additions & 1 deletion

File tree

crates/agenthint/tests/cli.rs

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
use std::collections::HashMap;
2+
use std::process::Command;
3+
4+
use serde_json::Value;
5+
6+
fn fixture_path(name: &str) -> String {
7+
format!("{}/../../fixtures/{name}", env!("CARGO_MANIFEST_DIR"))
8+
}
9+
10+
#[test]
11+
fn cli_matches_shared_fixtures() {
12+
let fixtures: Value =
13+
serde_json::from_str(&std::fs::read_to_string(fixture_path("cli-cases.json")).unwrap())
14+
.unwrap();
15+
let fixtures = fixtures.as_array().unwrap();
16+
17+
for fixture in fixtures {
18+
let name = fixture["name"].as_str().unwrap();
19+
let args = fixture["args"]
20+
.as_array()
21+
.unwrap()
22+
.iter()
23+
.map(|arg| arg.as_str().unwrap())
24+
.collect::<Vec<_>>();
25+
let env = fixture["env"]
26+
.as_object()
27+
.unwrap()
28+
.iter()
29+
.map(|(key, value)| (key.as_str(), value.as_str().unwrap()))
30+
.collect::<HashMap<_, _>>();
31+
32+
let output = Command::new(env!("CARGO_BIN_EXE_agenthint"))
33+
.args(args)
34+
.env_clear()
35+
.envs(env)
36+
.output()
37+
.unwrap();
38+
39+
assert_eq!(
40+
output.status.code(),
41+
Some(fixture["status"].as_i64().unwrap() as i32),
42+
"{name}"
43+
);
44+
45+
let stdout = String::from_utf8(output.stdout).unwrap();
46+
47+
if let Some(expected) = fixture["stdout"].as_str() {
48+
assert_eq!(stdout, expected, "{name}");
49+
}
50+
51+
if let Some(expected_values) = fixture["stdoutContains"].as_array() {
52+
for expected in expected_values {
53+
assert!(stdout.contains(expected.as_str().unwrap()), "{name}");
54+
}
55+
}
56+
}
57+
}
58+
59+
#[test]
60+
fn cli_rejects_invalid_usage() {
61+
let output = Command::new(env!("CARGO_BIN_EXE_agenthint"))
62+
.arg("bogus")
63+
.env_clear()
64+
.output()
65+
.unwrap();
66+
67+
assert_eq!(output.status.code(), Some(2));
68+
assert!(output.stdout.is_empty());
69+
assert!(
70+
String::from_utf8(output.stderr)
71+
.unwrap()
72+
.contains("invalid usage: bogus")
73+
);
74+
}

python/agenthint/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -264,7 +264,7 @@ def _setup_advice(result: AgentHintResult, *, json_shape: bool = False) -> dict[
264264
message = "Detection is heuristic. Prefer setting AI_AGENT for a stable explicit signal."
265265
return {
266266
"kind": "heuristic",
267-
"message": message if json_shape else f"setup: {message}",
267+
"message": message if json_shape else f"setup: {message[:1].lower()}{message[1:]}",
268268
"hint": _setup_hint(result.agent),
269269
}
270270

test/python_test.py

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,26 @@
11
import json
2+
import subprocess
3+
import sys
24
import unittest
5+
from importlib.resources import files
36
from pathlib import Path
47

58
from agenthint import detect_agent, format_json
69

710

11+
def run_cli(args, env):
12+
python_path = str(Path("python").resolve())
13+
subprocess_env = {"PYTHONPATH": python_path, **env}
14+
15+
return subprocess.run(
16+
[sys.executable, "-m", "agenthint.cli", *args],
17+
env=subprocess_env,
18+
text=True,
19+
capture_output=True,
20+
check=False,
21+
)
22+
23+
824
class AgentHintPythonTest(unittest.TestCase):
925
def test_matches_shared_detection_fixtures(self):
1026
fixtures = json.loads(Path("fixtures/detection-cases.json").read_text())
@@ -43,6 +59,34 @@ def test_json_uses_camel_case_shape(self):
4359
},
4460
)
4561

62+
def test_cli_matches_shared_fixtures(self):
63+
fixtures = json.loads(Path("fixtures/cli-cases.json").read_text())
64+
65+
for fixture in fixtures:
66+
with self.subTest(fixture["name"]):
67+
result = run_cli(fixture["args"], fixture["env"])
68+
69+
self.assertEqual(result.returncode, fixture["status"])
70+
71+
if fixture.get("stdout") is not None:
72+
self.assertEqual(result.stdout, fixture["stdout"])
73+
74+
for expected in fixture.get("stdoutContains", []):
75+
self.assertIn(expected, result.stdout)
76+
77+
def test_cli_rejects_invalid_usage(self):
78+
result = run_cli(["bogus"], {})
79+
80+
self.assertEqual(result.returncode, 2)
81+
self.assertEqual(result.stdout, "")
82+
self.assertIn("invalid usage: bogus", result.stderr)
83+
84+
def test_package_includes_detection_rules(self):
85+
rules = json.loads(files("agenthint").joinpath("detection-rules.json").read_text(encoding="utf8"))
86+
87+
self.assertIn("environmentRules", rules)
88+
self.assertIn("parentProcessRules", rules)
89+
4690

4791
if __name__ == "__main__":
4892
unittest.main()

0 commit comments

Comments
 (0)