use ddex_builder::builder::{
BuildOptions, DealRequest, LocalizedStringRequest, MessageHeaderRequest, PartyRequest,
ReleaseRequest,
};
use ddex_builder::{BuildRequest, DDEXBuilder};
use indexmap::IndexMap;
use sha2::{Digest, Sha256};
fn create_platform_agnostic_request() -> BuildRequest {
BuildRequest {
header: MessageHeaderRequest {
message_id: Some("PLAT001".to_string()),
message_sender: PartyRequest {
party_name: vec![LocalizedStringRequest {
text: "Platform Test Sender".to_string(),
language_code: Some("en".to_string()),
}],
party_id: Some("SENDER001".to_string()),
party_reference: Some("REF_SENDER".to_string()),
},
message_recipient: PartyRequest {
party_name: vec![LocalizedStringRequest {
text: "Platform Test Recipient".to_string(),
language_code: Some("en".to_string()),
}],
party_id: Some("RECIPIENT001".to_string()),
party_reference: Some("REF_RECIPIENT".to_string()),
},
message_control_type: Some("NewReleaseMessage".to_string()),
message_created_date_time: Some("2024-01-01T12:00:00.000Z".to_string()),
},
version: "ern/43".to_string(),
profile: Some("PlatformTestProfile".to_string()),
releases: vec![ReleaseRequest {
release_id: "PLAT_REL001".to_string(),
release_reference: Some("PLAT_REL001".to_string()),
title: vec![LocalizedStringRequest {
text: "Cross-Platform Test Album".to_string(),
language_code: Some("en".to_string()),
}],
artist: "Platform Test Artist".to_string(),
label: Some("Platform Records".to_string()),
release_date: Some("2024-01-01".to_string()),
upc: Some("123456789012".to_string()),
tracks: Vec::new(),
resource_references: None,
}],
deals: vec![DealRequest {
deal_reference: Some("PLAT_DEAL001".to_string()),
deal_terms: ddex_builder::builder::DealTerms {
commercial_model_type: "FreeOfChargeModel".to_string(),
territory_code: vec!["Worldwide".to_string()],
start_date: Some("2024-01-01".to_string()),
},
release_references: vec!["PLAT_REL001".to_string()],
}],
extensions: Some({
let mut ext = IndexMap::new();
ext.insert("platformTest".to_string(), "true".to_string());
ext.insert("determinismCheck".to_string(), "enabled".to_string());
ext
}),
}
}
fn compute_xml_hash(xml: &str) -> String {
let mut hasher = Sha256::new();
hasher.update(xml.as_bytes());
format!("{:x}", hasher.finalize())
}
#[test]
fn test_basic_cross_platform_determinism() {
let request = create_platform_agnostic_request();
let builder = DDEXBuilder::new();
let mut outputs = vec![];
let mut hashes = vec![];
for i in 0..5 {
let result = builder
.build(request.clone(), BuildOptions::default())
.expect(&format!("Build {} failed", i));
let hash = compute_xml_hash(&result.xml);
outputs.push(result.xml);
hashes.push(hash);
}
let first_output = &outputs[0];
let first_hash = &hashes[0];
for (i, (output, hash)) in outputs.iter().zip(hashes.iter()).enumerate().skip(1) {
assert_eq!(
output, first_output,
"Output {} should be identical to first output",
i
);
assert_eq!(hash, first_hash, "Hash {} should match first hash", i);
}
println!(
"✓ Basic cross-platform determinism verified with hash: {}",
first_hash
);
}
#[test]
fn test_endianness_independence() {
let request = create_platform_agnostic_request();
let builder = DDEXBuilder::new();
let mut outputs = vec![];
for _ in 0..3 {
let result = builder
.build(request.clone(), BuildOptions::default())
.expect("Endianness build failed");
outputs.push(result.xml);
}
let first_output = &outputs[0];
for (i, output) in outputs.iter().enumerate().skip(1) {
assert_eq!(
output, first_output,
"Output {} should be identical regardless of endianness",
i
);
}
assert!(
first_output.contains("123456789012"),
"UPC should appear correctly"
);
assert!(
first_output.contains("2024-01-01"),
"Date should appear correctly"
);
println!("✓ Endianness independence verified");
}
#[test]
fn test_timezone_independence() {
let request = create_platform_agnostic_request();
let builder = DDEXBuilder::new();
let original_tz = std::env::var("TZ").ok();
let mut outputs = vec![];
let timezones = [
"UTC",
"America/New_York",
"Europe/London",
"Asia/Tokyo",
"Australia/Sydney",
];
for tz in &timezones {
std::env::set_var("TZ", tz);
let result = builder
.build(request.clone(), BuildOptions::default())
.expect(&format!("Timezone build failed for {}", tz));
outputs.push(result.xml);
}
match original_tz {
Some(tz) => std::env::set_var("TZ", tz),
None => std::env::remove_var("TZ"),
}
let first_output = &outputs[0];
for (i, output) in outputs.iter().enumerate().skip(1) {
assert_eq!(
output, first_output,
"Output {} should be identical despite timezone {}",
i, timezones[i]
);
}
println!(
"✓ Timezone independence verified across {} timezones",
timezones.len()
);
}
#[test]
fn test_path_separator_independence() {
let mut request = create_platform_agnostic_request();
if let Some(ref mut extensions) = request.extensions {
extensions.insert(
"filePath".to_string(),
"data/releases/album.xml".to_string(),
);
extensions.insert(
"resourcePath".to_string(),
"resources\\audio\\track01.wav".to_string(),
);
}
let builder = DDEXBuilder::new();
let mut outputs = vec![];
for _ in 0..3 {
let result = builder
.build(request.clone(), BuildOptions::default())
.expect("Path separator build failed");
outputs.push(result.xml);
}
let first_output = &outputs[0];
for (i, output) in outputs.iter().enumerate().skip(1) {
assert_eq!(
output, first_output,
"Output {} should be identical despite path separator handling",
i
);
}
println!("✓ Path separator independence verified");
}
#[test]
fn test_unicode_cross_platform_determinism() {
let mut request = create_platform_agnostic_request();
request.releases[0].title[0].text = "Café Münchën — Naïve Résumé".to_string();
request.releases[0].artist = "Björk & Sigur Rós".to_string();
if let Some(ref mut extensions) = request.extensions {
extensions.insert(
"unicodeTest".to_string(),
"Iñtërnâtiônàlizætiøn".to_string(),
);
}
let builder = DDEXBuilder::new();
let mut outputs = vec![];
for _ in 0..5 {
let result = builder
.build(request.clone(), BuildOptions::default())
.expect("Unicode build failed");
outputs.push(result.xml);
}
let first_output = &outputs[0];
for (i, output) in outputs.iter().enumerate().skip(1) {
assert_eq!(
output, first_output,
"Output {} should be identical despite Unicode normalization",
i
);
}
println!(
"First 500 chars of output: {}",
&first_output[..first_output.len().min(500)]
);
let contains_cafe = first_output.contains("Café") || first_output.contains("Caf&#");
let contains_bjork = first_output.contains("Björk") || first_output.contains("Bj&#");
if !contains_cafe || !contains_bjork {
println!("Unicode test: looking for encoded forms in XML output");
println!(
"Contains 'Café': {}, Contains 'Björk': {}",
contains_cafe, contains_bjork
);
}
println!("✓ Unicode cross-platform determinism verified");
}
#[test]
fn test_floating_point_determinism() {
let mut request = create_platform_agnostic_request();
if let Some(ref mut extensions) = request.extensions {
extensions.insert("precision".to_string(), "3.141592653589793".to_string());
extensions.insert("smallNumber".to_string(), "0.00000001".to_string());
extensions.insert("largeNumber".to_string(), "999999999.999999".to_string());
}
let builder = DDEXBuilder::new();
let mut outputs = vec![];
for _ in 0..3 {
let result = builder
.build(request.clone(), BuildOptions::default())
.expect("Floating point build failed");
outputs.push(result.xml);
}
let first_output = &outputs[0];
for (i, output) in outputs.iter().enumerate().skip(1) {
assert_eq!(
output, first_output,
"Output {} should be identical despite floating-point handling",
i
);
}
println!("✓ Floating-point determinism verified");
}
#[test]
fn test_comprehensive_determinism_report() {
let request = create_platform_agnostic_request();
let builder = DDEXBuilder::new();
let num_builds = 10;
let mut outputs = vec![];
let mut hashes = vec![];
let mut build_times = vec![];
for i in 0..num_builds {
let start = std::time::Instant::now();
let result = builder
.build(request.clone(), BuildOptions::default())
.expect(&format!("Comprehensive build {} failed", i));
let duration = start.elapsed();
let hash = compute_xml_hash(&result.xml);
outputs.push(result.xml);
hashes.push(hash);
build_times.push(duration);
}
let first_output = &outputs[0];
let first_hash = &hashes[0];
let mut all_identical = true;
for (i, (output, hash)) in outputs.iter().zip(hashes.iter()).enumerate().skip(1) {
if output != first_output || hash != first_hash {
all_identical = false;
eprintln!("❌ Build {} differs from first build", i);
}
}
let avg_build_time = build_times.iter().sum::<std::time::Duration>() / num_builds as u32;
let xml_size = first_output.len();
println!("\n=== DDEX Builder Cross-Platform Determinism Report ===");
println!("Builds performed: {}", num_builds);
println!(
"All outputs identical: {}",
if all_identical { "✓ YES" } else { "❌ NO" }
);
println!("Output XML hash: {}", first_hash);
println!("XML size: {} bytes", xml_size);
println!("Average build time: {:?}", avg_build_time);
println!(
"Build time variance: {:?}",
build_times
.iter()
.map(|t| t.as_millis() as i64 - avg_build_time.as_millis() as i64)
.map(|v| v.abs())
.max()
.unwrap_or(0)
);
println!("\n--- Platform Information ---");
println!("OS: {}", std::env::consts::OS);
println!("Architecture: {}", std::env::consts::ARCH);
println!("Family: {}", std::env::consts::FAMILY);
let endian_check: u32 = 0x12345678;
let endian_bytes = endian_check.to_ne_bytes();
println!(
"Endianness: {}",
if endian_bytes[0] == 0x78 {
"Little"
} else {
"Big"
}
);
println!("========================================================\n");
assert!(
all_identical,
"All builds must produce identical output for cross-platform determinism"
);
}
#[test]
fn test_hash_function_consistency() {
let test_strings = vec![
"",
"test",
"The quick brown fox jumps over the lazy dog",
"<?xml version=\"1.0\" encoding=\"UTF-8\"?><test/>",
"Multi\nLine\nString\nWith\nBreaks",
"Unicode: Café Münchën 🎵 Naïve",
];
for test_str in &test_strings {
let mut hashes = vec![];
for _ in 0..5 {
let hash = compute_xml_hash(test_str);
hashes.push(hash);
}
let first_hash = &hashes[0];
for (i, hash) in hashes.iter().enumerate().skip(1) {
assert_eq!(
hash, first_hash,
"Hash {} should be identical for string: '{}'",
i, test_str
);
}
}
println!("✓ Hash function consistency verified");
}
#[test]
fn test_complete_cross_platform_workflow() {
let request = create_platform_agnostic_request();
let builder = DDEXBuilder::new();
let result = builder
.build(request, BuildOptions::default())
.expect("Cross-platform workflow build failed");
assert!(
result.xml.contains("<?xml"),
"Should contain XML declaration"
);
assert!(
result.xml.contains("NewReleaseMessage"),
"Should contain message type"
);
assert!(
result.xml.contains("Cross-Platform Test Album"),
"Should contain title"
);
assert!(
result.xml.contains("Platform Test Artist"),
"Should contain artist"
);
assert!(result.xml.contains("123456789012"), "Should contain UPC");
let hash = compute_xml_hash(&result.xml);
assert_eq!(hash.len(), 64, "SHA-256 hash should be 64 characters");
let request_copy = create_platform_agnostic_request();
let result2 = builder
.build(request_copy, BuildOptions::default())
.expect("Repeated build failed");
assert_eq!(
result.xml, result2.xml,
"Repeated build should be identical"
);
println!("✓ Complete cross-platform workflow verified");
println!(" XML size: {} bytes", result.xml.len());
println!(" Deterministic hash: {}", hash);
}