use super::*;
#[derive(Debug, PartialEq, serde::Serialize, serde::Deserialize)]
struct Sample {
name: String,
count: i64,
enabled: bool,
optional: Option<String>,
items: Vec<String>,
}
fn sample() -> Sample {
Sample {
name: "router".to_string(),
count: 42,
enabled: true,
optional: None,
items: vec!["one".to_string(), "two".to_string()],
}
}
#[test]
fn state_round_trips_through_links_notation() {
let encoded = encode(&sample()).expect("encode");
let decoded: Sample = decode(&encoded).expect("decode");
assert_eq!(decoded, sample());
}
#[test]
fn the_encoded_form_is_readable() {
let encoded = encode(&sample()).expect("encode");
assert!(encoded.contains("name \"router\""), "{encoded}");
assert!(encoded.contains("count 42"), "{encoded}");
assert!(encoded.contains("enabled true"), "{encoded}");
assert!(!encoded.contains("\"42\""), "{encoded}");
assert!(!encoded.contains("base64"), "{encoded}");
}
#[test]
fn json_written_by_an_earlier_release_still_loads() {
let json = serde_json::to_string(&sample()).expect("serialize");
let decoded: Sample = decode(&json).expect("JSON still decodes");
assert_eq!(decoded, sample());
}
#[test]
fn every_value_shape_converts_both_ways() {
let value = serde_json::json!({
"null": null,
"bool": false,
"int": -7,
"float": 1.5,
"string": "text",
"array": [1, "two", true],
"nested": {"inner": {"deep": 1}}
});
assert_eq!(from_lino(&to_lino(&value)), value);
}
#[test]
fn a_control_character_is_carried_without_base64ing_everything() {
let value = serde_json::json!({"plain": "readable", "raw": "a\u{0007}b"});
let encoded = lino_objects_codec::encode(&to_lino(&value));
assert!(encoded.contains("plain \"readable\""), "{encoded}");
let decoded = lino_objects_codec::decode(&encoded).expect("decode");
assert_eq!(from_lino(&decoded), value);
}
#[test]
fn a_links_document_is_not_misread_as_json() {
let encoded = encode(&sample()).expect("encode");
assert!(
encoded.trim_start().starts_with('('),
"links notation opens with a paren: {encoded}"
);
let decoded: Sample = decode(&encoded).expect("links notation decodes");
assert_eq!(decoded, sample());
}
#[test]
fn an_empty_collection_survives_both_encodings() {
let empty: Vec<Sample> = Vec::new();
let encoded = encode(&empty).expect("encode");
let decoded: Vec<Sample> = decode(&encoded).expect("decode");
assert!(decoded.is_empty(), "an empty list stays empty: {encoded}");
let decoded: Vec<Sample> = decode("[]").expect("decode JSON");
assert!(decoded.is_empty());
}
#[test]
fn a_vendor_document_survives_this_module_unchanged() {
let credential = serde_json::json!({
"claudeAiOauth": {
"accessToken": "sk-ant-oat01-example",
"refreshToken": "sk-ant-ort01-example",
"expiresAt": 4_102_444_800_000_i64,
"scopes": ["user:inference", "user:profile"],
}
});
let written = serde_json::to_string_pretty(&credential).expect("serialize");
let read: serde_json::Value = decode(&written).expect("a vendor file still decodes");
assert_eq!(read, credential, "a vendor document must not be reshaped");
let codex = serde_json::json!({
"OPENAI_API_KEY": null,
"tokens": {"id_token": "header.payload.signature", "account_id": "acct_1"},
"last_refresh": "2026-08-26T00:00:00Z",
});
let round_tripped: serde_json::Value =
decode(&serde_json::to_string(&codex).expect("serialize")).expect("decode");
assert_eq!(
round_tripped, codex,
"fields this crate does not model must survive untouched"
);
}
#[test]
fn a_record_round_trips_on_a_single_readable_line() {
let record = serde_json::json!({
"phase": "client_request",
"uri": "/v1/messages?beta=true",
"model": "claude-opus-5",
"status": 200,
"streamed": true,
"detail": null,
"frames": [1, 2, 3],
});
let line = encode_line(&record).expect("encode");
assert_eq!(line.lines().count(), 1, "one record is one line: {line}");
assert!(line.contains("claude-opus-5"), "{line}");
assert!(line.contains("/v1/messages?beta=true"), "{line}");
assert!(!line.contains("base64"), "{line}");
assert!(!line.contains("Y2xhdWRl"), "no base64 of 'claude': {line}");
let decoded = decode_line(&line).expect("decode");
assert_eq!(decoded, record, "the record survives the round trip");
}
#[test]
fn a_newline_in_a_body_does_not_break_the_record() {
let record = serde_json::json!({
"body": "event: message_start\ndata: {\"model\":\"claude-opus-5\"}\n\n",
"quote": "he said \"hello\"",
"backslash": "C:\\path",
});
let line = encode_line(&record).expect("encode");
assert_eq!(line.lines().count(), 1, "still one line: {line}");
assert!(line.contains("claude-opus-5"), "{line}");
let decoded = decode_line(&line).expect("decode");
assert_eq!(decoded, record, "escapes are undone exactly");
}
#[test]
fn a_json_line_from_an_earlier_release_still_reads() {
let record = serde_json::json!({"phase": "client_request", "uri": "/v1/messages"});
let json = serde_json::to_string(&record).expect("serialize");
assert_eq!(
decode_line(&json).expect("JSON still decodes"),
record,
"a line an earlier release wrote must keep reading"
);
assert_eq!(decode_line(" "), None);
assert_eq!(decode_line("(unterminated"), None);
}
#[test]
fn an_array_of_objects_round_trips() {
let record = serde_json::json!({
"body": {
"model": "gpt-5",
"messages": [{"role": "user", "content": "hi"}, {"role": "assistant", "content": "yo"}],
"tools": [{"type": "function", "function": {"name": "lookup"}}],
},
"mixed": [1, "two", true, null],
"empty": [],
});
let line = encode_line(&record).expect("encode");
assert_eq!(line.lines().count(), 1, "one line: {line}");
assert_eq!(
decode_line(&line).expect("decode"),
record,
"an array of objects survives the round trip"
);
}
fn arbitrary_json() -> impl proptest::strategy::Strategy<Value = serde_json::Value> {
use proptest::prelude::*;
let leaf = prop_oneof![
Just(serde_json::Value::Null),
any::<bool>().prop_map(serde_json::Value::Bool),
any::<i64>().prop_map(|number| serde_json::json!(number)),
"[a-zA-Z0-9 ..\"\\\\\n\r/:_-]{0,24}".prop_map(serde_json::Value::String),
];
leaf.prop_recursive(4, 24, 4, |inner| {
prop_oneof![
proptest::collection::vec(inner.clone(), 0..4).prop_map(serde_json::Value::Array),
proptest::collection::hash_map("[a-z_]{1,8}", inner, 0..4)
.prop_map(|fields| serde_json::Value::Object(fields.into_iter().collect())),
]
})
}
proptest::proptest! {
#[test]
fn any_record_survives_the_line_round_trip(record in arbitrary_json()) {
let line = encode_line(&record).expect("encode");
proptest::prop_assert_eq!(
line.lines().count(),
1,
"every record is one line: {}",
line
);
let decoded = decode_line(&line).expect("decode");
proptest::prop_assert_eq!(decoded, record);
}
}