use serde_json::{Value, json};
use crate::science::wire::{reply, rows_of};
use crate::science::{Attempt, Outcome, Verdict};
fn bare() -> Attempt {
Attempt {
diff: crate::workdiff::Attempt {
project: "p".to_owned(),
ball_id: "bl-1".to_owned(),
handle: None,
delivered: None,
change: crate::workdiff::Change::Unreadable,
},
base: None,
conversation: None,
goal: None,
pins: Vec::new(),
governing: None,
usage: crate::budgets::BudgetSpend::default(),
cost: None,
wall_secs: 0,
steps: 0,
response: None,
verdicts: Vec::new(),
compacted: 0,
outcome: Outcome::Pending,
}
}
#[test]
fn an_unbound_row_omits_what_it_cannot_say() {
let body = reply(&[bare()]);
let row = &body["rows"][0];
for key in ["base", "conversation", "goal", "governing", "response"] {
assert!(row.get(key).is_none(), "{key} rides only when there is one");
}
assert!(
row.get("compacted").is_none(),
"an intact record has no compaction to speak of (bl-fde5)"
);
assert_eq!(row["outcome"], json!({ "state": "pending" }));
assert_eq!(body["kind"], "science");
}
#[test]
fn a_rejection_by_nobody_round_trips() {
let mut row = bare();
row.outcome = Outcome::Rejected { by: None };
row.verdicts = vec![Verdict {
sender: "judge".to_owned(),
body: "no".to_owned(),
}];
let body = reply(&[row.clone()]);
assert!(body["rows"][0]["outcome"].get("by").is_none());
assert_eq!(read(&body).unwrap(), vec![row]);
}
#[test]
fn a_malformed_body_refuses_by_name() {
let cases = [
(json!({ "rows": [1] }), "not an object"),
(json!({ "rows": [{}] }), "missing diff"),
(
json!({ "rows": [{ "diff": diff(), "pins": [], "usage": 1 }] }),
"not an object",
),
(
json!({ "rows": [{ "diff": diff(), "pins": [] }] }),
"missing usage",
),
(
json!({ "rows": [{ "diff": diff(), "pins": [], "usage": usage(),
"wall_secs": 0, "steps": 0, "verdicts": [{}] }] }),
"sender",
),
(
json!({ "rows": [{ "diff": diff(), "pins": [], "usage": usage(),
"wall_secs": 0, "steps": 0, "verdicts": [] }] }),
"missing outcome",
),
(
json!({ "rows": [row_with(json!({ "state": "adopted" }))] }),
"unknown state \"adopted\"",
),
(
json!({ "rows": [row_with(json!(7))] }),
"outcome: not an object",
),
(
json!({ "rows": [row_with(json!({ "state": "accepted" }))] }),
"commit",
),
(
json!({ "rows": [{ "diff": diff(), "pins": [], "usage": usage(),
"wall_secs": 0, "steps": 0, "verdicts": [1] }] }),
"verdict: not an object",
),
];
for (body, needle) in cases {
let err = read(&body).expect_err("a malformed row refuses");
assert!(err.contains(needle), "{err:?} should name {needle:?}");
}
}
#[test]
fn every_outcome_arm_round_trips() {
for outcome in [
Outcome::Accepted {
commit: "abc".to_owned(),
},
Outcome::Rejected {
by: Some("at-1".to_owned()),
},
Outcome::Reworked,
Outcome::Pending,
] {
let mut row = bare();
row.outcome = outcome;
row.base = Some("bbb".to_owned());
row.conversation = Some("a-1".to_owned());
row.goal = Some("do it".to_owned());
row.governing = Some("cfg".to_owned());
row.response = Some("done".to_owned());
row.pins = vec!["instructions/00-A.md=/p/A.md".to_owned()];
row.wall_secs = 12;
row.steps = 3;
row.compacted = 7;
assert_eq!(read(&reply(&[row.clone()])).unwrap(), vec![row]);
}
}
fn read(body: &Value) -> Result<Vec<Attempt>, String> {
rows_of(body.as_object().unwrap())
}
fn diff() -> Value {
crate::workdiff::wire::attempt_row(&bare().diff)
}
fn usage() -> Value {
json!({ "input_tokens": 0, "output_tokens": 0,
"cache_read_tokens": 0, "cache_write_tokens": 0 })
}
fn row_with(outcome: Value) -> Value {
json!({ "diff": diff(), "pins": [], "usage": usage(),
"wall_secs": 0, "steps": 0, "verdicts": [], "outcome": outcome })
}