use super::*;
use crate::task::On;
fn record(id: &str) -> String {
format!(r#"{{"id":"{id}","title":"T","created":5,"updated":9,"body":"b\n"}}"#)
}
#[test]
fn a_single_show_object_parses_verbatim() {
let got = records(&record("bl-0001")).unwrap();
let (id, task) = &got[0];
assert_eq!(id, "bl-0001");
assert_eq!(task.title, "T");
assert_eq!((task.created, task.updated), (5, 9));
assert_eq!(task.body, "b\n");
}
#[test]
fn a_list_array_flattens_and_a_stream_concatenates() {
let text = format!("[{},{}]\n{}\n", record("bl-a"), record("bl-b"), record("bl-c"));
let ids: Vec<String> = records(&text).unwrap().into_iter().map(|(id, _)| id).collect();
assert_eq!(ids, ["bl-a", "bl-b", "bl-c"]);
}
#[test]
fn the_canonical_fields_and_extras_round_trip() {
let text = r#"{
"id": "bl-full", "title": "Full", "created": 1, "updated": 2,
"claimant": "ann", "parent": "bl-p", "priority": 3,
"tags": ["epic"], "blockers": [{"id": "bl-b", "on": "claim"}],
"state": "in-review", "body": ""
}"#;
let (_, task) = records(text).unwrap().pop().unwrap();
assert_eq!(task.claimant.as_deref(), Some("ann"));
assert_eq!(task.parent.as_deref(), Some("bl-p"));
assert_eq!(task.priority, Some(3));
assert_eq!(task.tags, ["epic"]);
assert_eq!(task.blockers[0].id, "bl-b");
assert_eq!(task.blockers[0].on, On::Claim);
assert_eq!(task.extra["state"].as_str(), Some("in-review"));
}
#[test]
fn a_record_with_null_scalars_parses_as_absent() {
let text = r#"{"id":"bl-n","title":"N","created":1,"updated":1,
"claimant":null,"parent":null,"priority":null,"tags":[],"blockers":[],"body":""}"#;
let (_, task) = records(text).unwrap().pop().unwrap();
assert_eq!(task.claimant, None);
assert_eq!(task.parent, None);
assert_eq!(task.priority, None);
assert!(task.extra.is_empty());
}
#[test]
fn a_missing_body_defaults_empty_and_a_nonstring_body_is_refused() {
let (_, task) = records(r#"{"id":"bl-x","title":"T","created":1,"updated":1}"#).unwrap().pop().unwrap();
assert_eq!(task.body, "");
let err = records(r#"{"id":"bl-x","title":"T","created":1,"updated":1,"body":3}"#).unwrap_err();
assert!(err.to_string().contains("\"body\" must be a string"), "{err}");
}
#[test]
fn refusals_name_the_defect() {
for (text, want) in [
("not json", "bad JSON on stdin"),
("[3]", "must be a JSON object"),
(r#"{"title":"no id"}"#, "needs an \"id\""),
(r#"{"id":"has space","title":"T"}"#, "invalid id"),
(r#"{"id":7,"title":"T"}"#, "invalid id"),
(r#"{"id":"bl-t","title":"T"}"#, "bl-t"),
] {
let err = records(text).unwrap_err();
assert!(err.to_string().contains(want), "{text} → {err}");
}
}