Skip to content

Commit 10d249f

Browse files
committed
test(cli): add JSON contract tests for skills doctor + release check
1 parent 2a6042d commit 10d249f

2 files changed

Lines changed: 102 additions & 2 deletions

File tree

crates/loopforge-cli/src/dispatch/release.rs

Lines changed: 50 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,10 @@ pub(super) fn run(command: ReleaseCommand) -> anyhow::Result<()> {
1313
} => {
1414
let report = run_release_check(&repo_root, tag.as_deref(), run_tests)?;
1515
if json {
16-
println!("{}", serde_json::to_string_pretty(&report)?);
16+
println!(
17+
"{}",
18+
serde_json::to_string_pretty(&build_release_check_json(&report)?)?
19+
);
1720
} else {
1821
println!("{}", format_release_check_report(&report));
1922
}
@@ -24,3 +27,49 @@ pub(super) fn run(command: ReleaseCommand) -> anyhow::Result<()> {
2427
}
2528
}
2629
}
30+
31+
fn build_release_check_json(
32+
report: &crate::release_check::ReleaseCheckReport,
33+
) -> anyhow::Result<serde_json::Value> {
34+
Ok(serde_json::to_value(report)?)
35+
}
36+
37+
#[cfg(test)]
38+
mod tests {
39+
use super::*;
40+
use crate::release_check::{ReleaseCheckItem, ReleaseCheckReport};
41+
use serde_json::json;
42+
43+
#[test]
44+
fn build_release_check_json_keeps_expected_shape() {
45+
let report = ReleaseCheckReport {
46+
ok: false,
47+
tag: "v1.2.3".to_string(),
48+
checks: vec![
49+
ReleaseCheckItem {
50+
id: "alpha".to_string(),
51+
ok: true,
52+
message: "ok".to_string(),
53+
},
54+
ReleaseCheckItem {
55+
id: "beta".to_string(),
56+
ok: false,
57+
message: "missing".to_string(),
58+
},
59+
],
60+
};
61+
62+
let out = build_release_check_json(&report).unwrap();
63+
assert_eq!(
64+
out,
65+
json!({
66+
"ok": false,
67+
"tag": "v1.2.3",
68+
"checks": [
69+
{ "id": "alpha", "ok": true, "message": "ok" },
70+
{ "id": "beta", "ok": false, "message": "missing" },
71+
],
72+
})
73+
);
74+
}
75+
}

crates/loopforge-cli/src/dispatch/skills/doctor.rs

Lines changed: 52 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,10 @@ use crate::skills;
55
pub(super) fn run_doctor(workspace: PathBuf, json: bool, strict: bool) -> anyhow::Result<()> {
66
let report = skills::doctor(&workspace)?;
77
if json {
8-
println!("{}", serde_json::to_string_pretty(&report)?);
8+
println!(
9+
"{}",
10+
serde_json::to_string_pretty(&build_skills_doctor_json(&report)?)?
11+
);
912
} else {
1013
println!("discovered_skills: {}", report.discovered_count);
1114
if report.issues.is_empty() {
@@ -38,3 +41,51 @@ pub(super) fn run_doctor(workspace: PathBuf, json: bool, strict: bool) -> anyhow
3841
}
3942
Ok(())
4043
}
44+
45+
fn build_skills_doctor_json(
46+
report: &skills::SkillsDoctorReport,
47+
) -> anyhow::Result<serde_json::Value> {
48+
Ok(serde_json::to_value(report)?)
49+
}
50+
51+
#[cfg(test)]
52+
mod tests {
53+
use super::*;
54+
use crate::skills::{SkillsDoctorIssue, SkillsDoctorLevel, SkillsDoctorReport};
55+
use serde_json::json;
56+
57+
#[test]
58+
fn build_skills_doctor_json_keeps_expected_shape_and_omits_missing_paths() {
59+
let report = SkillsDoctorReport {
60+
ok: false,
61+
discovered_count: 2,
62+
issues: vec![
63+
SkillsDoctorIssue {
64+
level: SkillsDoctorLevel::Warn,
65+
id: "warn.test".to_string(),
66+
message: "warning".to_string(),
67+
path: None,
68+
},
69+
SkillsDoctorIssue {
70+
level: SkillsDoctorLevel::Error,
71+
id: "error.test".to_string(),
72+
message: "error".to_string(),
73+
path: Some("/tmp/skill.toml".to_string()),
74+
},
75+
],
76+
};
77+
78+
let out = build_skills_doctor_json(&report).unwrap();
79+
assert_eq!(
80+
out,
81+
json!({
82+
"ok": false,
83+
"discovered_count": 2,
84+
"issues": [
85+
{ "level": "warn", "id": "warn.test", "message": "warning" },
86+
{ "level": "error", "id": "error.test", "message": "error", "path": "/tmp/skill.toml" },
87+
]
88+
})
89+
);
90+
}
91+
}

0 commit comments

Comments
 (0)