use cml_rs::generator::CmlGenerator;
use cml_rs::parser::CmlParser;
use cml_rs::validator::CmlValidator;
#[test]
fn test_full_pipeline_minimal() {
let xml = r#"<cml profile="core" version="0.2" encoding="utf-8">
<header>
<title>Test Document</title>
</header>
<body>
<paragraph>Hello, world!</paragraph>
</body>
<footer>
</footer>
</cml>"#;
let doc = CmlParser::parse_str(xml).expect("Parse failed");
CmlValidator::validate(&doc).expect("Validation failed");
let generated = CmlGenerator::generate(&doc).expect("Generation failed");
let doc2 = CmlParser::parse_str(&generated).expect("Re-parse failed");
CmlValidator::validate(&doc2).expect("Re-validation failed");
assert_eq!(doc, doc2);
}
#[test]
fn test_full_pipeline_complex() {
let xml = r#"<cml profile="law:constitution" version="0.2" encoding="utf-8" id="complex-doc">
<header>
<title>Complex Document</title>
<author role="editor">Editor Name</author>
<author role="contributor">Contributor Name</author>
<date type="created" when="2025-01-01"/>
<date type="modified" when="2025-12-22T10:30:00Z"/>
<identifier scheme="doi">10.1234/complex</identifier>
<identifier scheme="isbn">978-0-123456-78-9</identifier>
<version>2.1</version>
<description>A complex test document with multiple features.</description>
<provenance>Created from original drafts</provenance>
<source>https://example.org/source</source>
<meta name="classification" value="public"/>
<meta name="language" value="en"/>
</header>
<body>
<section id="intro">
<heading size="1">Introduction</heading>
<paragraph>This document contains <em>various</em> <bo>elements</bo> to test roundtrip functionality.</paragraph>
<aside side="right" type="note">
<paragraph>This is a side note.</paragraph>
</aside>
</section>
<section id="content">
<heading size="1">Main Content</heading>
<quote source="Famous Person" ref="quote-1">
<paragraph>A memorable quotation goes here.</paragraph>
</quote>
<list type="ordered" style="roman">
<item>First major point</item>
<item>Second major point with <rf ref="intro" role="section">reference to intro</rf></item>
<item>Third point with <lk ref="https://example.org">external link</lk></item>
</list>
<table id="summary-table">
<header>
<row>
<column sort="asc"><cell>Category</cell></column>
<column><cell>Value (<curr type="USD">amount</curr>)</cell></column>
</row>
</header>
<body>
<row>
<column><cell>Budget</cell></column>
<column><cell><curr type="USD" format="symbol">1000000</curr></cell></column>
</row>
</body>
<footer>
<caption>Summary of values</caption>
</footer>
</table>
<code lang="python" copyable="true">def hello():
print("Hello, CML!")</code>
</section>
</body>
<footer>
<signatures>
<signature when="2025-12-22T15:00:00Z" role="author">Primary Author</signature>
</signatures>
<citations>
<citation ref="quote-1" type="speech">Person, F. (2020). Famous Speech. <em>Speech Collection</em>.</citation>
</citations>
<annotations>
<note type="editorial">Document reviewed and approved.</note>
</annotations>
</footer>
</cml>"#;
let doc = CmlParser::parse_str(xml).expect("Parse failed");
CmlValidator::validate(&doc).expect("Validation failed");
let generated = CmlGenerator::generate(&doc).expect("Generation failed");
assert!(!generated.starts_with("<?xml"));
assert!(generated.starts_with("<cml"));
let doc2 = CmlParser::parse_str(&generated).expect("Re-parse failed");
CmlValidator::validate(&doc2).expect("Re-validation failed");
assert_eq!(doc, doc2);
}
#[test]
fn test_validation_catches_invalid_version() {
let xml = r#"<cml profile="core" version="1.0" encoding="utf-8">
<header>
<title>Test</title>
</header>
<body>
<paragraph>Test</paragraph>
</body>
<footer>
</footer>
</cml>"#;
let doc = CmlParser::parse_str(xml).expect("Parse should succeed");
let result = CmlValidator::validate(&doc);
assert!(result.is_err());
assert!(result.unwrap_err().to_string().contains("version"));
}
#[test]
fn test_validation_catches_duplicate_ids() {
let xml = r#"<cml profile="core" version="0.2" encoding="utf-8">
<header>
<title>Test</title>
</header>
<body>
<paragraph id="para-1">First</paragraph>
<paragraph id="para-1">Second</paragraph>
</body>
<footer>
</footer>
</cml>"#;
let doc = CmlParser::parse_str(xml).expect("Parse should succeed");
let result = CmlValidator::validate(&doc);
assert!(result.is_err());
assert!(result.unwrap_err().to_string().contains("Duplicate ID"));
}
#[test]
fn test_validation_catches_invalid_reference() {
let xml = r#"<cml profile="core" version="0.2" encoding="utf-8">
<header>
<title>Test</title>
</header>
<body>
<paragraph>Reference to <rf ref="nonexistent-id">nowhere</rf></paragraph>
</body>
<footer>
</footer>
</cml>"#;
let doc = CmlParser::parse_str(xml).expect("Parse should succeed");
let result = CmlValidator::validate(&doc);
assert!(result.is_err());
assert!(result
.unwrap_err()
.to_string()
.contains("Reference not found"));
}
#[test]
fn test_validation_accepts_pathless_references() {
let xml = r#"<cml profile="core" version="0.2" encoding="utf-8">
<header>
<title>Test</title>
</header>
<body>
<paragraph>Reference to <rf ref="president:47">President 47</rf></paragraph>
</body>
<footer>
</footer>
</cml>"#;
let doc = CmlParser::parse_str(xml).expect("Parse failed");
CmlValidator::validate(&doc).expect("Validation should succeed");
}
#[test]
fn test_validation_accepts_external_urls() {
let xml = r#"<cml profile="core" version="0.2" encoding="utf-8">
<header>
<title>Test</title>
</header>
<body>
<paragraph>External <lk ref="https://example.org">link</lk></paragraph>
</body>
<footer>
</footer>
</cml>"#;
let doc = CmlParser::parse_str(xml).expect("Parse failed");
CmlValidator::validate(&doc).expect("Validation should succeed");
}
#[test]
fn test_validation_catches_invalid_heading_size() {
let xml = r#"<cml profile="core" version="0.2" encoding="utf-8">
<header>
<title>Test</title>
</header>
<body>
<heading size="7">Invalid</heading>
</body>
<footer>
</footer>
</cml>"#;
let doc = CmlParser::parse_str(xml).expect("Parse should succeed");
let result = CmlValidator::validate(&doc);
assert!(result.is_err());
assert!(result.unwrap_err().to_string().contains("heading size"));
}
#[test]
fn test_all_inline_elements() {
let xml = r#"<cml profile="core" version="0.2" encoding="utf-8">
<header>
<title>Inline Elements Test</title>
</header>
<body>
<paragraph>
This is <em>emphasized</em> and <bo>bold</bo> and <un>underlined</un> and <st>struck</st> text.
With <snip char="$">npm install</snip> and <key>Ctrl+C</key> elements.
Reference: <rf ref="president:47">President 47</rf>.
Topic: <tg ref="constitution">Constitutional Law</tg>.
Link: <lk ref="https://example.org">Example Site</lk>.
Currency: <curr type="USD">1500000</curr> and <curr type="EUR" format="symbol">350000</curr>.
Break<end kind="line"/>here.
</paragraph>
</body>
<footer>
</footer>
</cml>"#;
let doc = CmlParser::parse_str(xml).expect("Parse failed");
CmlValidator::validate(&doc).expect("Validation failed");
let generated = CmlGenerator::generate(&doc).expect("Generation failed");
let doc2 = CmlParser::parse_str(&generated).expect("Re-parse failed");
CmlValidator::validate(&doc2).expect("Re-validation failed");
assert_eq!(doc, doc2);
}
#[test]
fn test_all_block_elements() {
let xml = r#"<cml profile="core" version="0.2" encoding="utf-8">
<header>
<title>Block Elements Test</title>
</header>
<body>
<section id="sec-1">
<heading size="1">Section</heading>
<paragraph>Section content</paragraph>
</section>
<heading size="2">Standalone Heading</heading>
<paragraph>Regular paragraph</paragraph>
<aside side="left" type="note">
<paragraph>Aside content</paragraph>
</aside>
<quote source="Author" ref="president:47">
<paragraph>Quote content</paragraph>
</quote>
<list type="ordered" style="numeric">
<item>Item 1</item>
<item>Item 2</item>
</list>
<table id="table-1">
<header>
<row>
<column><cell>Header</cell></column>
</row>
</header>
<body>
<row>
<column><cell>Data</cell></column>
</row>
</body>
<footer>
<caption>Table caption</caption>
</footer>
</table>
<code lang="rust" copyable="true">fn main() {}</code>
<break type="scene"/>
</body>
<footer>
</footer>
</cml>"#;
let doc = CmlParser::parse_str(xml).expect("Parse failed");
CmlValidator::validate(&doc).expect("Validation failed");
let generated = CmlGenerator::generate(&doc).expect("Generation failed");
let doc2 = CmlParser::parse_str(&generated).expect("Re-parse failed");
CmlValidator::validate(&doc2).expect("Re-validation failed");
assert_eq!(doc, doc2);
}
#[test]
fn test_nested_structures() {
let xml = r#"<cml profile="core" version="0.2" encoding="utf-8">
<header>
<title>Nested Structures Test</title>
</header>
<body>
<section id="outer">
<heading size="1">Outer Section</heading>
<section id="inner">
<heading size="2">Inner Section</heading>
<paragraph>Nested content</paragraph>
</section>
</section>
<list type="unordered">
<item>First level
<list type="ordered" style="alpha">
<item>Nested first</item>
<item>Nested second</item>
</list>
</item>
<item>Another first level</item>
</list>
<paragraph>Text with <em type="stress"><bo>nested bold emphasis</bo></em> elements.</paragraph>
</body>
<footer>
</footer>
</cml>"#;
let doc = CmlParser::parse_str(xml).expect("Parse failed");
CmlValidator::validate(&doc).expect("Validation failed");
let generated = CmlGenerator::generate(&doc).expect("Generation failed");
let doc2 = CmlParser::parse_str(&generated).expect("Re-parse failed");
CmlValidator::validate(&doc2).expect("Re-validation failed");
assert_eq!(doc, doc2);
}