#![expect(clippy::expect_used, reason = "tests assert by panicking")]
use std::path::Path;
use davinci_test_support::schema as schema_check;
use vize_l0::dump::remarks::{RemarkLog, RemarksSchemaMismatch};
use vize_l0::dump::{Dump, Error as DumpError, Mode as DumpMode};
use vize_l0::pass::RemarkKind;
use vize_l0::pass::observer::{RecordedArg, RecordedRemark, RemarkArgValue};
use vize_l0::{Span, String};
fn arg(key: &str, value: RemarkArgValue) -> RecordedArg {
RecordedArg {
key: String::from(key),
value,
}
}
fn text(value: &str) -> RemarkArgValue {
RemarkArgValue::Str(String::from(value))
}
fn sample() -> RemarkLog {
RemarkLog::new(vec![
RecordedRemark {
stage: String::from("s2"),
pass: String::from("hoist-static"),
kind: RemarkKind::Missed,
name: String::from("static-subtree"),
span: Span::new(0, 120),
args: vec![
arg("tag", text("section")),
arg("blocker", text("child")),
arg("op", text("ui.component")),
],
},
RecordedRemark {
stage: String::from("s2"),
pass: String::from("hoist-static"),
kind: RemarkKind::Applied,
name: String::from("static-props"),
span: Span::new(0, 120),
args: vec![arg("tag", text("section"))],
},
RecordedRemark {
stage: String::from("s3"),
pass: String::from("partition"),
kind: RemarkKind::Analysis,
name: String::from("region-size"),
span: Span::new(7, 7),
args: vec![
arg("ops", RemarkArgValue::Int(-3)),
arg("static", RemarkArgValue::Bool(false)),
arg("label", text("a \"b\" c\\d\ne\u{1}f \u{3042}")),
],
},
])
}
const SAMPLE_FULL: &str = "[remarks]\n\n[remarks.entries]\n\
s2.hoist-static missed static-subtree @0:120 tag=\"section\" blocker=\"child\" op=\"ui.component\"\n\
s2.hoist-static applied static-props @0:120 tag=\"section\"\n\
s3.partition analysis region-size @7:7 ops=-3 static=false label=\"a \\\"b\\\" c\\\\d\\ne\\u0001f \u{3042}\"\n\n";
#[test]
fn the_page_prints_canonically_and_round_trips() {
let log = sample();
let printed = log.print_to_string(DumpMode::Full);
assert_eq!(printed.as_str(), SAMPLE_FULL);
assert_eq!(RemarkLog::parse(SAMPLE_FULL), Ok(log));
let reparsed = RemarkLog::parse(SAMPLE_FULL).expect("canonical text parses");
assert_eq!(
reparsed.print_to_string(DumpMode::Full).as_str(),
SAMPLE_FULL
);
}
#[test]
fn an_empty_log_is_the_bare_header() {
let empty = RemarkLog::default();
assert_eq!(
empty.print_to_string(DumpMode::Full).as_str(),
"[remarks]\n\n"
);
assert_eq!(RemarkLog::parse("[remarks]\n\n"), Ok(empty));
}
#[test]
fn display_elides_spans_only() {
assert_eq!(
sample().print_to_string(DumpMode::Display).as_str(),
"[remarks]\n\n[remarks.entries]\n\
s2.hoist-static missed static-subtree tag=\"section\" blocker=\"child\" op=\"ui.component\"\n\
s2.hoist-static applied static-props tag=\"section\"\n\
s3.partition analysis region-size ops=-3 static=false label=\"a \\\"b\\\" c\\\\d\\ne\\u0001f \u{3042}\"\n\n"
);
}
#[test]
fn a_unicode_escape_normalizes_on_the_first_print() {
let input = "[remarks]\n\n[remarks.entries]\ns2.p applied n @1:2 k=\"\\u0041\\u3042\"\n\n";
let log = RemarkLog::parse(input).expect("escaped text parses");
assert_eq!(
log.print_to_string(DumpMode::Full).as_str(),
"[remarks]\n\n[remarks.entries]\ns2.p applied n @1:2 k=\"A\u{3042}\"\n\n"
);
}
fn reject(entry: &str) -> DumpError {
let input = vize_l0::cstr!("[remarks]\n\n[remarks.entries]\n{entry}\n");
RemarkLog::parse(input.as_str()).expect_err("malformed entry must fail")
}
#[test]
fn every_malformed_entry_is_rejected_with_its_line_and_reason() {
let cases: [(&str, &str); 14] = [
(
"hoist applied n @1:2",
"remark origin `hoist` is not `stage.pass`",
),
(
"L2.p applied n @1:2",
"stage `L2` is not a lowercase kebab-case identifier",
),
(
"s2.p- applied n @1:2",
"pass `p-` is not a lowercase kebab-case identifier",
),
(
"s2.p done n @1:2",
"unknown remark kind `done` (expected applied, missed, analysis)",
),
(
"s2.p applied N @1:2",
"remark name `N` is not a lowercase kebab-case identifier",
),
(
"s2.p applied n 1:2",
"remark span `1:2` is not `@start:end` with start <= end",
),
(
"s2.p applied n @3:2",
"remark span `@3:2` is not `@start:end` with start <= end",
),
(
"s2.p applied n @01:2",
"remark span `@01:2` is not `@start:end` with start <= end",
),
(
"s2.p applied n @1:2 k",
"remark argument `k` is missing `=`",
),
(
"s2.p applied n @1:2 k=1 k=2",
"duplicate remark argument `k`",
),
(
"s2.p applied n @1:2 k=01",
"remark value `01` is not a string, integer, or boolean",
),
(
"s2.p applied n @1:2 k=-0",
"remark value `-0` is not a string, integer, or boolean",
),
(
"s2.p applied n @1:2 k=\"x\"y",
"unexpected `y` after a string value",
),
("s2.p applied n @1:2 k=\"x", "unterminated string value"),
];
for (entry, message) in cases {
assert_eq!(
reject(entry),
DumpError::new(4, String::from(message)),
"{entry}"
);
}
assert_eq!(
RemarkLog::parse("[remarks]\ncount=1\n"),
Err(DumpError::new(2, String::from("unknown field `count`")))
);
assert_eq!(
RemarkLog::parse("[remarks]\n\n[remarks.notes]\n"),
Err(DumpError::new(
3,
String::from("unknown section [remarks.notes]")
))
);
assert_eq!(
RemarkLog::parse(""),
Err(DumpError::new(0, String::from("missing [remarks] header")))
);
}
fn load_schema() -> serde_json::Value {
let path =
Path::new(env!("CARGO_MANIFEST_DIR")).join("../../docs/davinci/plan/remarks.schema.json");
let text = std::fs::read_to_string(path).expect("committed schema reads");
serde_json::from_str(&text).expect("committed schema is valid JSON")
}
#[test]
fn the_json_document_is_exact_and_schema_valid() {
let json = sample().to_json("typed-remarks-test");
let parsed: serde_json::Value = serde_json::from_str(json.as_str()).expect("valid JSON");
assert_eq!(schema_check::validate(&load_schema(), &parsed, "$"), Ok(()));
assert_eq!(
parsed,
serde_json::json!({
"schema_version": 1,
"command": "typed-remarks-test",
"remarks": [
{
"stage": "s2", "pass": "hoist-static", "kind": "missed",
"name": "static-subtree", "span": { "start": 0, "end": 120 },
"args": [
{ "key": "tag", "value": "section" },
{ "key": "blocker", "value": "child" },
{ "key": "op", "value": "ui.component" },
],
},
{
"stage": "s2", "pass": "hoist-static", "kind": "applied",
"name": "static-props", "span": { "start": 0, "end": 120 },
"args": [{ "key": "tag", "value": "section" }],
},
{
"stage": "s3", "pass": "partition", "kind": "analysis",
"name": "region-size", "span": { "start": 7, "end": 7 },
"args": [
{ "key": "ops", "value": -3 },
{ "key": "static", "value": false },
{ "key": "label", "value": "a \"b\" c\\d\ne\u{1}f \u{3042}" },
],
},
],
})
);
assert_eq!(
json.as_str().split('\n').count(),
2,
"one line plus newline"
);
}
#[test]
fn the_schema_refuses_version_and_shape_drift() {
let schema = load_schema();
let mut parsed: serde_json::Value =
serde_json::from_str(sample().to_json("typed-remarks-test").as_str()).expect("valid JSON");
parsed["remarks"][0]["kind"] = serde_json::Value::from("hoisted");
let error = schema_check::validate(&schema, &parsed, "$").expect_err("bad kind fails");
assert_eq!(
error.message().as_str(),
"schema violation at `$.remarks[0].kind`: string does not match pattern \
`^(applied|missed|analysis)$`"
);
parsed["remarks"][0]["kind"] = serde_json::Value::from("missed");
parsed["remarks"][0]["args"][0]["value"] = serde_json::json!(1.5);
let error = schema_check::validate(&schema, &parsed, "$").expect_err("float fails");
assert_eq!(
error.message().as_str(),
"schema violation at `$.remarks[0].args[0].value`: expected \
[string,integer,boolean], found number"
);
assert_eq!(RemarkLog::negotiate_schema_version(1), Ok(()));
assert_eq!(
RemarkLog::negotiate_schema_version(2),
Err(RemarksSchemaMismatch {
expected: 1,
found: 2,
})
);
}
#[test]
fn counts_read_the_log() {
let log = sample();
assert_eq!(RemarkKind::ALL.map(|kind| log.count(kind)), [1, 1, 1]);
}