use super::policy::Clock;
pub(crate) const CORPUS_CLOCK: Clock = Clock::at(1_786_492_800_000);
pub(crate) fn document(name: &str) -> &'static str {
match name {
"ids.json" => include_str!("../../fixtures/documents/ids.json"),
"ids.yaml" => include_str!("../../fixtures/documents/ids.yaml"),
"ids.toml" => include_str!("../../fixtures/documents/ids.toml"),
"ids.ini" => include_str!("../../fixtures/documents/ids.ini"),
"ids.env" => include_str!("../../fixtures/documents/ids.env"),
"ids.csv" => include_str!("../../fixtures/documents/ids.csv"),
"ids.txt" => include_str!("../../fixtures/documents/ids.txt"),
"comments.toml" => include_str!("../../fixtures/documents/comments.toml"),
"ambiguous.json" => include_str!("../../fixtures/documents/ambiguous.json"),
"context.json" => include_str!("../../fixtures/documents/context.json"),
"timestamps.json" => include_str!("../../fixtures/documents/timestamps.json"),
other => panic!("the corpus has no document named {other}"),
}
}
#[cfg(test)]
mod tests {
use serde::Deserialize;
use serde_json::Value;
use super::{CORPUS_CLOCK, document};
use crate::extract::{Kind, Options, Reason, SUPPORTED_FORMATS, extract};
const CORPUS: &str = include_str!("../../fixtures/extraction.json");
#[derive(Debug, Deserialize)]
struct Corpus {
now: i64,
documents: Vec<Case>,
ambiguity: Vec<Refused>,
timestamps: Vec<Decoded>,
}
#[derive(Debug, Deserialize)]
struct Case {
name: String,
file: String,
#[serde(rename = "fileType")]
file_type: String,
expected: Vec<Value>,
}
#[derive(Debug, Deserialize)]
struct Refused {
value: String,
reason: Reason,
}
#[derive(Debug, Deserialize)]
struct Decoded {
value: String,
kind: Kind,
timestamp: String,
}
fn corpus() -> Corpus {
serde_json::from_str(CORPUS).expect("the corpus is valid JSON")
}
fn options() -> Options {
Options {
clock: CORPUS_CLOCK,
kind: None,
}
}
fn rows(file: &str, format: &str) -> Vec<Value> {
extract(document(file), format, options())
.iter()
.map(|found| serde_json::to_value(found).expect("a row serializes"))
.collect()
}
#[test]
fn the_corpus_clock_matches_the_constant() {
assert_eq!(corpus().now, CORPUS_CLOCK.now_ms);
}
#[test]
fn every_corpus_document_reproduces() {
let corpus = corpus();
assert!(!corpus.documents.is_empty(), "the corpus is empty");
for case in corpus.documents {
assert_eq!(
rows(&case.file, &case.file_type),
case.expected,
"{}",
case.name
);
}
}
#[test]
fn the_corpus_covers_every_reader() {
let corpus = corpus();
for format in SUPPORTED_FORMATS {
assert!(
corpus.documents.iter().any(|case| case.file_type == format),
"no corpus case reads {format}"
);
}
}
#[test]
fn the_corpus_names_every_kind() {
let corpus = corpus();
let named: Vec<&Value> = corpus
.documents
.iter()
.flat_map(|case| &case.expected)
.filter(|row| row["valid"] == true)
.collect();
for kind in ["uuid", "ulid", "nanoid", "objectid", "snowflake"] {
assert!(
named.iter().any(|row| row["kind"] == kind),
"no corpus case names a {kind}"
);
}
}
#[test]
fn every_ambiguity_case_is_refused_for_the_reason_it_pins() {
let corpus = corpus();
let found = rows("ambiguous.json", "json");
assert_eq!(
found.len(),
corpus.ambiguity.len(),
"the ambiguity document and its pinned reasons have drifted apart"
);
for (row, pinned) in found.iter().zip(&corpus.ambiguity) {
assert_eq!(row["value"], pinned.value);
assert_eq!(row["valid"], false, "{} was named", pinned.value);
assert_eq!(
row["refused"],
serde_json::to_value(pinned.reason).expect("serializes"),
"{}",
pinned.value
);
assert!(
row["detail"].as_str().is_some_and(|text| text.len() > 20),
"{} was refused without saying why",
pinned.value
);
}
for reason in [
Reason::AmbiguousKind,
Reason::Malformed,
Reason::NilOrMax,
Reason::VersionClaimMismatch,
Reason::TimestampImplausible,
] {
assert!(
corpus.ambiguity.iter().any(|case| case.reason == reason),
"no ambiguity case produces {reason:?}"
);
}
}
#[test]
fn the_same_run_is_named_or_refused_by_the_field_it_sits_in() {
let keyed = rows("context.json", "json");
let value = keyed[0]["value"].clone();
assert!(
keyed.iter().all(|row| row["value"] == value),
"the document must hold one value four times"
);
let verdicts: Vec<(&str, bool)> = keyed
.iter()
.map(|row| {
(
row["key"].as_str().unwrap_or_default(),
row["valid"] == true,
)
})
.collect();
assert_eq!(
verdicts,
[
("record._id", true),
("mirror.documentId", true),
("checksum", false),
("manifest.[0]", false),
]
);
for row in keyed.iter().filter(|row| row["valid"] == false) {
assert_eq!(row["refused"], "ambiguous_kind", "{row}");
assert!(row["kind"].is_null(), "a kind was named anyway: {row}");
assert_eq!(
row["timestamp"], "2026-08-12T00:00:00.000Z",
"the decode rides on the refusal so a reader can disagree: {row}"
);
}
let bare = rows("context.json", "text");
assert_eq!(bare.len(), keyed.len(), "the same runs, without key paths");
assert!(
bare.iter().all(|row| row["valid"] == false),
"a document with no keys names no field an identifier: {bare:?}"
);
}
#[test]
fn every_pinned_timestamp_decodes() {
let corpus = corpus();
let found = rows("timestamps.json", "json");
assert_eq!(found.len(), corpus.timestamps.len());
for (row, pinned) in found.iter().zip(&corpus.timestamps) {
assert_eq!(row["value"], pinned.value);
assert_eq!(row["valid"], true, "{} was refused", pinned.value);
assert_eq!(
row["kind"],
serde_json::to_value(pinned.kind).expect("serializes"),
"{}",
pinned.value
);
assert_eq!(row["timestamp"], pinned.timestamp, "{}", pinned.value);
}
}
#[test]
fn every_time_bearing_kind_has_a_pinned_decode() {
let corpus = corpus();
for kind in [Kind::Uuid, Kind::Ulid, Kind::ObjectId, Kind::Snowflake] {
assert!(
corpus.timestamps.iter().any(|case| case.kind == kind),
"no pinned decode for {kind:?}"
);
}
}
#[test]
fn the_formats_agree_on_which_runs_are_identifiers() {
let values = |file: &str, format: &str| -> Vec<Value> {
rows(file, format)
.into_iter()
.map(|row| row["value"].clone())
.collect()
};
assert_eq!(values("ids.json", "json"), values("ids.yaml", "yaml"));
for file in [("ids.toml", "toml"), ("ids.ini", "ini")] {
for value in values(file.0, file.1) {
assert!(
values("ids.json", "json").contains(&value),
"{value} is in {} and not in ids.json",
file.0
);
}
}
}
}