#![allow(clippy::unwrap_used)]
#![allow(clippy::disallowed_methods)]
use presentar_yaml::Scene;
use std::fs;
use std::path::Path;
#[test]
fn test_all_prs_examples_valid() {
let examples_dir = Path::new(env!("CARGO_MANIFEST_DIR"))
.parent()
.expect("parent dir")
.parent()
.expect("workspace dir")
.join("examples")
.join("prs");
assert!(
examples_dir.exists(),
"Examples directory not found: {}",
examples_dir.display()
);
let mut tested = 0;
let mut errors = Vec::new();
for entry in fs::read_dir(&examples_dir).expect("Failed to read examples directory") {
let entry = entry.expect("Failed to read directory entry");
let path = entry.path();
if path.extension().is_some_and(|ext| ext == "prs") {
let filename = path.file_name().expect("filename").to_string_lossy();
let content = fs::read_to_string(&path)
.unwrap_or_else(|e| panic!("Failed to read {filename}: {e}"));
match Scene::from_yaml(&content) {
Ok(scene) => {
assert!(
!scene.metadata.name.is_empty(),
"{filename}: metadata.name is empty"
);
assert!(
!scene.prs_version.is_empty(),
"{filename}: prs_version is empty"
);
tested += 1;
println!("OK: {filename}");
}
Err(e) => {
errors.push(format!("{filename}: {e}"));
}
}
}
}
assert!(
errors.is_empty(),
"Failed to parse {} .prs file(s):\n{}",
errors.len(),
errors.join("\n")
);
assert!(tested > 0, "No .prs files found in examples/prs directory");
println!("\nValidated {tested} .prs example files");
}
mod individual_examples {
use super::*;
fn load_example(name: &str) -> Scene {
let path = Path::new(env!("CARGO_MANIFEST_DIR"))
.parent()
.expect("parent dir")
.parent()
.expect("workspace dir")
.join("examples")
.join("prs")
.join(name);
let content =
fs::read_to_string(&path).unwrap_or_else(|e| panic!("Failed to read {name}: {e}"));
Scene::from_yaml(&content).unwrap_or_else(|e| panic!("Failed to parse {name}: {e}"))
}
#[test]
fn test_minimal_example() {
let scene = load_example("minimal.prs");
assert_eq!(scene.metadata.name, "hello-world");
assert_eq!(scene.widgets.len(), 1);
}
#[test]
fn test_sentiment_demo_has_resources() {
let scene = load_example("sentiment-demo.prs");
assert_eq!(scene.metadata.name, "sentiment-analysis-demo");
assert!(!scene.resources.models.is_empty());
assert!(scene.resources.models.contains_key("sentiment_model"));
}
#[test]
fn test_image_classifier_has_bindings() {
let scene = load_example("image-classifier.prs");
assert_eq!(scene.metadata.name, "image-classifier");
assert!(!scene.bindings.is_empty());
}
#[test]
fn test_data_explorer_has_dataset() {
let scene = load_example("data-explorer.prs");
assert_eq!(scene.metadata.name, "data-explorer");
assert!(scene.resources.datasets.contains_key("sales"));
}
#[test]
fn test_parameter_tuner_has_sliders() {
let scene = load_example("parameter-tuner.prs");
assert_eq!(scene.metadata.name, "parameter-tuner");
let slider_count = scene
.widgets
.iter()
.filter(|w| w.widget_type == presentar_yaml::WidgetType::Slider)
.count();
assert_eq!(slider_count, 3, "Expected 3 slider widgets");
}
}
mod qa_checklist {
use super::*;
fn validate_qa_checklist(scene: &Scene, filename: &str) -> Vec<String> {
let mut issues = Vec::new();
if !scene.prs_version.contains('.') {
issues.push(format!("{filename}: prs_version should be semver format"));
}
if scene.metadata.name.chars().any(|c| c.is_ascii_uppercase()) {
issues.push(format!("{filename}: metadata.name should be kebab-case"));
}
let mut ids = std::collections::HashSet::new();
for widget in &scene.widgets {
if !ids.insert(&widget.id) {
issues.push(format!("{filename}: duplicate widget id '{}'", widget.id));
}
}
for (name, model) in &scene.resources.models {
if model.source.primary().starts_with("https://") && model.hash.is_none() {
issues.push(format!("{filename}: remote model '{name}' missing hash"));
}
}
if let Some(theme) = &scene.theme {
if let Some(preset) = &theme.preset {
if !["light", "dark"].contains(&preset.as_str()) {
issues.push(format!("{filename}: unknown theme preset '{preset}'"));
}
}
}
issues
}
#[test]
fn test_all_examples_pass_qa_checklist() {
let examples_dir = Path::new(env!("CARGO_MANIFEST_DIR"))
.parent()
.expect("parent dir")
.parent()
.expect("workspace dir")
.join("examples")
.join("prs");
let mut all_issues = Vec::new();
for entry in fs::read_dir(&examples_dir).expect("Failed to read examples directory") {
let entry = entry.expect("Failed to read directory entry");
let path = entry.path();
if path.extension().is_some_and(|ext| ext == "prs") {
let filename = path.file_name().expect("filename").to_string_lossy();
let content = fs::read_to_string(&path).expect("Failed to read file");
if let Ok(scene) = Scene::from_yaml(&content) {
let issues = validate_qa_checklist(&scene, &filename);
all_issues.extend(issues);
}
}
}
assert!(
all_issues.is_empty(),
"QA checklist failures:\n{}",
all_issues.join("\n")
);
}
}