use super::commands::*;
use super::score::*;
use std::path::PathBuf;
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn score_args_parse_defaults() {
let cmd = Commands::Score(ScoreArgs {
file: PathBuf::from("forjar.yaml"),
status: "qualified".to_string(),
idempotency: "strong".to_string(),
budget_ms: 0,
json: false,
state_dir: PathBuf::from("state"),
});
match cmd {
Commands::Score(ScoreArgs {
status,
idempotency,
budget_ms,
..
}) => {
assert_eq!(status, "qualified");
assert_eq!(idempotency, "strong");
assert_eq!(budget_ms, 0);
}
_ => panic!("expected Score"),
}
}
#[test]
fn score_valid_config_file() {
let dir = tempfile::tempdir().unwrap();
let file = dir.path().join("forjar.yaml");
std::fs::write(
&file,
r#"
version: "1.0"
name: test-score
description: "A well-described config for scoring"
machines:
m:
hostname: m
addr: 127.0.0.1
resources:
pkg:
type: package
machine: m
provider: apt
packages: [curl]
version: "7.0"
cfg:
type: file
machine: m
path: /etc/app.conf
content: "key=value"
mode: "0644"
owner: root
depends_on: [pkg]
"#,
)
.unwrap();
let sd = dir.path().join("state");
std::fs::create_dir_all(&sd).unwrap();
let _result = cmd_score(&file, "qualified", "strong", 0, false, &sd);
}
#[test]
fn score_json_output() {
let dir = tempfile::tempdir().unwrap();
let file = dir.path().join("forjar.yaml");
std::fs::write(
&file,
r#"
version: "1.0"
name: test
resources:
f:
type: file
path: /tmp/x
mode: "0644"
owner: root
content: hello
"#,
)
.unwrap();
let sd = dir.path().join("state");
std::fs::create_dir_all(&sd).unwrap();
let _result = cmd_score(&file, "qualified", "strong", 0, true, &sd);
}
#[test]
fn score_blocked_status_returns_error() {
let dir = tempfile::tempdir().unwrap();
let file = dir.path().join("forjar.yaml");
std::fs::write(
&file,
r#"
version: "1.0"
name: test
resources: {}
"#,
)
.unwrap();
let sd = dir.path().join("state");
std::fs::create_dir_all(&sd).unwrap();
let result = cmd_score(&file, "blocked", "strong", 0, false, &sd);
assert!(result.is_err());
assert!(result.unwrap_err().contains("grade F"));
}
#[test]
fn score_pending_status_returns_error() {
let dir = tempfile::tempdir().unwrap();
let file = dir.path().join("forjar.yaml");
std::fs::write(
&file,
r#"
version: "1.0"
name: test
resources: {}
"#,
)
.unwrap();
let sd = dir.path().join("state");
std::fs::create_dir_all(&sd).unwrap();
let result = cmd_score(&file, "pending", "strong", 0, false, &sd);
assert!(result.is_err());
}
#[test]
fn score_nonexistent_file_returns_error() {
let sd = PathBuf::from("/tmp/forjar-test-nonexistent-state");
let result = cmd_score(
&PathBuf::from("/nonexistent/forjar.yaml"),
"qualified",
"strong",
0,
false,
&sd,
);
assert!(result.is_err());
}
#[test]
fn score_rich_config_scores_higher() {
let dir = tempfile::tempdir().unwrap();
let file = dir.path().join("forjar.yaml");
std::fs::write(
&file,
r#"
version: "1.0"
name: production-web
description: "Full production web server configuration"
params:
domain: example.com
machines:
web:
hostname: web
addr: 10.0.0.1
resources:
pkg:
type: package
machine: web
provider: apt
packages: [nginx]
version: "1.24"
tags: [web, production]
resource_group: infra
cfg:
type: file
machine: web
path: /etc/nginx/nginx.conf
content: "server { listen 80; server_name {{params.domain}}; }"
mode: "0644"
owner: root
depends_on: [pkg]
tags: [web, config]
policy:
failure: continue_independent
ssh_retries: 3
pre_apply: "echo pre"
post_apply: "echo post"
notify:
on_success: "echo ok"
on_failure: "echo fail"
on_drift: "echo drift"
outputs:
domain:
value: "{{params.domain}}"
"#,
)
.unwrap();
let sd = dir.path().join("state");
std::fs::create_dir_all(&sd).unwrap();
let result = cmd_score(&file, "qualified", "strong", 0, false, &sd);
assert!(result.is_err() || result.is_ok());
}
#[test]
fn test_fj3020_score_with_runtime_events() {
let dir = tempfile::tempdir().unwrap();
let file = dir.path().join("forjar.yaml");
std::fs::write(
&file,
r#"
version: "1.0"
name: runtime-test
description: "Config with runtime events for scoring"
machines:
m:
hostname: m
addr: 127.0.0.1
resources:
f:
type: file
machine: m
path: /tmp/test
content: "hello"
mode: "0644"
owner: root
"#,
)
.unwrap();
let sd = dir.path().join("state");
let machine_dir = sd.join("m");
std::fs::create_dir_all(&machine_dir).unwrap();
let events = concat!(
r#"{"ts":"2026-03-08T12:00:00Z","event":"apply_started","machine":"m","run_id":"r-001","forjar_version":"1.1.1"}"#,
"\n",
r#"{"ts":"2026-03-08T12:00:01Z","event":"resource_converged","machine":"m","resource":"f","duration_seconds":0.5,"hash":"abc123"}"#,
"\n",
r#"{"ts":"2026-03-08T12:00:02Z","event":"apply_completed","machine":"m","run_id":"r-001","resources_converged":1,"resources_unchanged":0,"resources_failed":0,"total_seconds":2.0}"#,
"\n",
r#"{"ts":"2026-03-08T12:01:00Z","event":"apply_started","machine":"m","run_id":"r-002","forjar_version":"1.1.1"}"#,
"\n",
r#"{"ts":"2026-03-08T12:01:01Z","event":"apply_completed","machine":"m","run_id":"r-002","resources_converged":0,"resources_unchanged":1,"resources_failed":0,"total_seconds":0.5}"#,
"\n",
);
std::fs::write(machine_dir.join("events.jsonl"), events).unwrap();
std::fs::write(machine_dir.join("state.lock.yaml"), "schema: '1'\nmachine: m\nhostname: m\ngenerated_at: now\ngenerator: test\nblake3_version: '1'\nresources: {}\n").unwrap();
let result = cmd_score(&file, "qualified", "strong", 0, true, &sd);
let _ = result; }
#[test]
fn test_fj2920_score_via_output_writer() {
use crate::cli::output::TestWriter;
let dir = tempfile::tempdir().unwrap();
let file = dir.path().join("forjar.yaml");
std::fs::write(
&file,
r#"
version: "1.0"
name: writer-test
description: "Test OutputWriter adoption"
machines:
m:
hostname: m
addr: 127.0.0.1
resources:
f:
type: file
machine: m
path: /tmp/test
content: "hello"
mode: "0644"
owner: root
"#,
)
.unwrap();
let sd = dir.path().join("state");
std::fs::create_dir_all(&sd).unwrap();
let mut w = TestWriter::new();
let _ = cmd_score_with_writer(&file, "qualified", "strong", 0, true, &sd, &mut w);
let json_out = w.stdout_text();
assert!(
json_out.contains("composite"),
"JSON score output should be captured by TestWriter: {json_out:?}"
);
assert!(
json_out.contains("grade"),
"should contain grade: {json_out:?}"
);
}
#[test]
fn test_fj3020_score_no_events_still_works() {
let dir = tempfile::tempdir().unwrap();
let file = dir.path().join("forjar.yaml");
std::fs::write(
&file,
r#"
version: "1.0"
name: test
resources: {}
"#,
)
.unwrap();
let sd = dir.path().join("state");
std::fs::create_dir_all(&sd).unwrap();
let result = cmd_score(&file, "qualified", "strong", 0, false, &sd);
assert!(result.is_err());
}
}