use std::{fs, path::PathBuf};
struct ExplainedBlock {
info: &'static str,
marker: &'static str,
reason: &'static str,
}
const EXPLAINED_BLOCKS: &[ExplainedBlock] = &[ExplainedBlock {
info: "",
marker: "Corrective statement C1, challenging original O1",
reason: "Illustrative reporting example, not a JSON payload. Plain-text diagram \
of a proposed correction-envelope report, not a specified schema.",
}];
const EXPECTED_BLOCK_COUNT: usize = 2;
struct Block {
info: String,
body: String,
line: usize,
}
fn draft_path() -> PathBuf {
let docs = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("../../docs");
let mut found: Vec<PathBuf> = fs::read_dir(&docs)
.expect("the workspace carries a docs directory")
.map(|entry| entry.expect("docs directory is readable").path())
.filter(|path| {
let name = path
.file_name()
.and_then(|name| name.to_str())
.unwrap_or("");
name.starts_with("draft-wilder-scitt-physical-site-engage-receipt-")
&& name.ends_with(".md")
})
.collect();
found.sort();
assert_eq!(
found.len(),
1,
"expected exactly one revision of the profile document in docs/, found {found:?}"
);
found.remove(0)
}
fn fenced_blocks(draft: &str) -> Vec<Block> {
let mut blocks = Vec::new();
let mut open: Option<(String, usize, Vec<String>)> = None;
for (index, raw) in draft.lines().enumerate() {
let line_no = index + 1;
if let Some(rest) = raw.strip_prefix("~~~") {
match open.take() {
None => open = Some((rest.trim().to_string(), line_no, Vec::new())),
Some((info, start, body)) => blocks.push(Block {
info,
body: body.join("\n"),
line: start,
}),
}
} else if let Some((_, _, body)) = open.as_mut() {
body.push(raw.to_string());
}
}
assert!(
open.is_none(),
"an unclosed ~~~ fence in the profile document; xml2rfc would not \
survive this either"
);
blocks
}
#[test]
fn no_backtick_fences_have_appeared() {
let draft = fs::read_to_string(draft_path()).expect("the profile document is readable");
let backticked: Vec<usize> = draft
.lines()
.enumerate()
.filter(|(_, line)| line.starts_with("```"))
.map(|(index, _)| index + 1)
.collect();
assert!(
backticked.is_empty(),
"the document has grown ``` fences at lines {backticked:?}. This test \
suite enumerates ~~~ fences only, so those examples are invisible to \
it. Convert them to ~~~ or teach fenced_blocks() to read both."
);
}
#[test]
fn the_document_carries_the_expected_number_of_examples() {
let draft = fs::read_to_string(draft_path()).expect("the profile document is readable");
let blocks = fenced_blocks(&draft);
assert_eq!(
blocks.len(),
EXPECTED_BLOCK_COUNT,
"the profile document now has {} fenced blocks, not {EXPECTED_BLOCK_COUNT}. \
This is not a failure of the document -- it is a prompt. Update \
EXPECTED_BLOCK_COUNT and decide how the new block is accounted for: \
it parses as a Payload, or it goes in EXPLAINED_BLOCKS with a reason.",
blocks.len()
);
}
#[test]
fn every_json_example_validates_against_the_reference_parser() {
let draft = fs::read_to_string(draft_path()).expect("the profile document is readable");
let blocks = fenced_blocks(&draft);
for block in &blocks {
if let Some(explained) = EXPLAINED_BLOCKS
.iter()
.find(|candidate| candidate.info == block.info && block.body.contains(candidate.marker))
{
let _ = explained.reason;
continue;
}
if block.info != "json" {
let trimmed = block.body.trim_start();
assert!(
!trimmed.starts_with('{') && !trimmed.starts_with('['),
"the fenced block at line {} looks like JSON but is labelled \
`{}`. Label it `json` so it gets validated.",
block.line,
if block.info.is_empty() {
"(nothing)"
} else {
&block.info
}
);
continue;
}
pask_wire::Payload::from_json(block.body.as_bytes()).unwrap_or_else(|error| {
panic!(
"the json example at line {} of the profile document does not \
validate against the reference parser: {error}\n\n\
The document may only describe what the code does. Either \
regenerate the example with `cargo run -p pask-wire-cli -- \
canonical-example`, or add it to EXPLAINED_BLOCKS with a \
reason the parser is not the right judge of it.",
block.line
)
});
}
}
#[test]
fn no_explanation_outlives_the_block_it_explained() {
let draft = fs::read_to_string(draft_path()).expect("the profile document is readable");
let blocks = fenced_blocks(&draft);
for explained in EXPLAINED_BLOCKS {
let matched = blocks
.iter()
.any(|block| block.info == explained.info && block.body.contains(explained.marker));
assert!(
matched,
"EXPLAINED_BLOCKS carries an entry for a `{}` block containing {:?}, \
and no such block is in the document. The explanation has outlived \
its example. Remove the entry.\n\nIts stated reason was: {}",
explained.info, explained.marker, explained.reason
);
}
}