use okf::yaml::Value;
use okf::{Date, Document, DocumentError, TrustTier};
fn with_frontmatter(frontmatter: &str) -> Document {
Document::parse(&format!("---\n{frontmatter}\n---\n")).unwrap()
}
#[test]
fn roundtrip_preserves_frontmatter_and_body() {
let src = "---\n\
type: BigQuery Table\n\
title: Sample\n\
description: A sample table.\n\
tags: [a, b]\n\
timestamp: 2026-05-27T00:00:00+00:00\n\
---\n\
\n\
# Sample\n\
\n\
Body text.\n";
let doc = Document::parse(src).unwrap();
assert_eq!(doc.frontmatter.type_().as_deref(), Some("BigQuery Table"));
assert_eq!(doc.frontmatter.tags(), vec!["a", "b"]);
assert!(doc.body.starts_with("# Sample"));
let serialized = doc.serialize();
let reparsed = Document::parse(&serialized).unwrap();
assert_eq!(reparsed.frontmatter, doc.frontmatter);
assert_eq!(reparsed.body.trim(), doc.body.trim());
}
#[test]
fn parse_no_frontmatter_treats_all_as_body() {
let src = "# Hello\n\nNo frontmatter here.\n";
let doc = Document::parse(src).unwrap();
assert!(doc.frontmatter.is_empty());
assert!(doc.body.contains("Hello"));
}
#[test]
fn unterminated_frontmatter_raises() {
let src = "---\ntype: X\nstill in frontmatter\n";
let err = Document::parse(src).unwrap_err();
assert_eq!(err, DocumentError::UnterminatedFrontmatter);
}
#[test]
fn validate_rejects_missing_type() {
let doc = with_frontmatter("title: Y");
let err = doc.validate().unwrap_err();
assert!(err.to_string().contains("type"), "{err}");
}
#[test]
fn validate_accepts_type_only() {
assert!(with_frontmatter("type: X").validate().is_ok());
}
#[test]
fn an_empty_type_does_not_count_as_present() {
assert!(with_frontmatter("type: \"\"").validate().is_err());
}
#[test]
fn missing_recommended_is_the_producer_checklist_not_a_rejection() {
let sparse = with_frontmatter("type: X\ntitle: Y");
assert_eq!(sparse.missing_recommended(), ["description", "generated"]);
assert!(sparse.validate().is_ok());
let full = with_frontmatter(
"type: X\ntitle: Y\ndescription: Z\n\
generated: { by: reference_agent/gemini-2.5-pro, at: 2026-06-20T22:53:05Z }",
);
assert!(full.missing_recommended().is_empty());
}
#[test]
fn a_legacy_timestamp_stands_in_for_generated() {
let doc =
with_frontmatter("type: X\ntitle: Y\ndescription: Z\ntimestamp: 2026-05-27T00:00:00+00:00");
assert!(doc.missing_recommended().is_empty());
assert_eq!(
doc.frontmatter.content_changed_at().unwrap().raw,
"2026-05-27T00:00:00+00:00"
);
}
#[test]
fn an_attested_computation_should_carry_a_runtime() {
let without = with_frontmatter(
"type: Attested Computation\ntitle: Revenue\ndescription: Recognized revenue.\n\
generated: { by: human:ahormati, at: 2026-06-20T22:53:05Z }",
);
assert_eq!(without.missing_recommended(), ["runtime"]);
assert!(without.validate().is_ok());
let with = with_frontmatter(
"type: Attested Computation\ntitle: Revenue\ndescription: Recognized revenue.\n\
runtime: bigquery\n\
generated: { by: human:ahormati, at: 2026-06-20T22:53:05Z }",
);
assert!(with.missing_recommended().is_empty());
}
#[test]
fn a_bare_verified_mapping_is_read_as_a_one_element_list() {
let doc =
with_frontmatter("type: X\nverified: { by: human:ahormati, at: 2026-06-25T09:00:00Z }");
let events = doc.frontmatter.verified();
assert_eq!(events.len(), 1);
assert_eq!(events[0].by.as_ref().unwrap().as_str(), "human:ahormati");
assert_eq!(events[0].at.as_ref().unwrap().raw, "2026-06-25T09:00:00Z");
assert!(with_frontmatter("type: X")
.frontmatter
.verified()
.is_empty());
}
#[test]
fn trust_tiers_derive_from_the_verifying_actors() {
let tier = |frontmatter: &str| with_frontmatter(frontmatter).frontmatter.trust_tier();
assert_eq!(tier("type: X"), TrustTier::Unverified);
assert_eq!(tier("type: X").to_string(), "unverified");
let machine = tier("type: X\nverified: [{ by: process:finance-nightly, at: x }]");
assert_eq!(machine, TrustTier::MachineConfirmed);
assert_eq!(machine.to_string(), "machine-confirmed");
let both = tier(
"type: X\nverified:\n - { by: process:finance-nightly, at: x }\n \
- { by: human:ahormati, at: y }",
);
assert_eq!(both, TrustTier::HumanReviewed);
assert_eq!(both.to_string(), "human-reviewed");
assert_eq!(
tier("type: X\nverified: { by: human:ahormati, at: z }"),
TrustTier::HumanReviewed
);
}
#[test]
fn staleness_compares_stale_after_against_a_given_day() {
let today = Date::new(2026, 9, 23).unwrap();
let stale = |frontmatter: &str| with_frontmatter(frontmatter).frontmatter.is_stale_on(today);
assert!(
stale("type: X\nstale_after: 2026-09-23"),
"stale on the day itself"
);
assert!(!stale("type: X\nstale_after: 2026-09-24"));
assert!(!stale("type: X"));
assert!(!stale("type: X\nstale_after: not-a-date"));
}
#[test]
fn unknown_keys_are_preserved_on_roundtrip() {
let src = "---\ntype: X\ncustom_key: custom value\nnested:\n a: 1\n b: 2\n---\nbody\n";
let doc = Document::parse(src).unwrap();
assert!(doc.frontmatter.get("custom_key").is_some());
let extensions = doc.frontmatter.extension_keys();
assert!(extensions.contains(&"custom_key"));
assert!(extensions.contains(&"nested"));
let reparsed = Document::parse(&doc.serialize()).unwrap();
assert_eq!(reparsed.frontmatter, doc.frontmatter);
assert_eq!(
reparsed.frontmatter.get("nested"),
Some(&Value::parse("{a: 1, b: 2}").unwrap())
);
}
#[test]
fn empty_frontmatter_block_is_empty_mapping() {
let doc = Document::parse("---\n---\nbody\n").unwrap();
assert!(doc.frontmatter.is_empty());
assert_eq!(doc.body, "body");
assert!(doc.serialize().ends_with("body\n"));
}
#[test]
fn a_datetime_valued_stale_after_is_compared_on_its_date() {
let doc = with_frontmatter("type: X\nstale_after: '2026-09-23T00:00:00Z'");
let field = doc.frontmatter.stale_after().unwrap();
assert!(!field.is_valid(), "still reported as not a plain date");
assert_eq!(field.effective_date(), Date::new(2026, 9, 23));
assert!(doc.frontmatter.is_stale_on(Date::new(2026, 9, 23).unwrap()));
assert!(!doc.frontmatter.is_stale_on(Date::new(2026, 9, 22).unwrap()));
}
#[test]
fn reorder_preferred_matches_the_reference_key_order() {
let mut doc = with_frontmatter(
"custom_key: keep me\nsources: []\ntitle: Orders\ntype: BigQuery Table\nstatus: stable",
);
doc.frontmatter.reorder_preferred();
let keys: Vec<&str> = doc.frontmatter.as_mapping().keys().collect();
assert_eq!(keys, ["type", "title", "status", "sources", "custom_key"]);
assert_eq!(
doc.frontmatter.get("custom_key").unwrap().as_str(),
Some("keep me")
);
assert_eq!(doc.frontmatter.as_mapping().len(), 5);
}
#[test]
fn section_reads_the_lines_under_a_conventional_heading() {
let doc = Document::parse(
"---\ntype: BigQuery Table\n---\n\n\
Prose.\n\n\
# Schema\n\n\
- `id` STRING: the order id\n\
\n\
## Nested\n\
- `total` NUMERIC: order total\n\n\
# Examples\n\
\x20 SELECT 1\n",
)
.unwrap();
assert_eq!(
doc.section("# Schema"),
[
"- `id` STRING: the order id",
"## Nested",
"- `total` NUMERIC: order total",
]
);
assert_eq!(doc.section("# Examples"), [" SELECT 1"]);
assert!(doc.section("# Computation").is_empty());
assert!(doc.section("Schema").is_empty());
}