wyvern-schema 0.5.0

Wyvern JSON types, validation, and error messages
Documentation
//! Integration coverage for wizard validation rules (d.1).

use serde_json::json;
use wyvern_schema::{validate, Command, ValidationError, WizardCommand, WizardPageLayout};

#[test]
fn validation_wizard_minimal_passes() {
    let cmd = validate(&json!({
        "type": "wizard",
        "page": {
            "id": "start",
            "title": "Start",
            "html": "pages/start.html"
        }
    }))
    .expect("valid");
    match cmd {
        Command::Wizard(WizardCommand {
            page,
            config,
            width,
            height,
            workflow,
        }) => {
            assert_eq!(page.id, "start");
            assert_eq!(page.title, "Start");
            assert_eq!(page.html, "pages/start.html");
            assert!(page.layout.is_none());
            assert_eq!(config, json!({}));
            assert!(width.is_none());
            assert!(height.is_none());
            assert!(workflow.is_none());
        }
        other => panic!("expected Wizard, got {other:?}"),
    }
}

#[test]
fn validation_wizard_layout_dialog_and_workspace() {
    for (wire, expected) in [
        ("dialog", WizardPageLayout::Dialog),
        ("workspace", WizardPageLayout::Workspace),
    ] {
        let cmd = validate(&json!({
            "type": "wizard",
            "page": {
                "id": "p",
                "title": "P",
                "html": "p.html",
                "layout": wire
            },
            "config": { "theme": "dark" },
            "width": 640,
            "height": 480
        }))
        .expect("valid");
        let Command::Wizard(w) = cmd else {
            panic!("expected Wizard");
        };
        assert_eq!(w.page.layout, Some(expected));
        assert_eq!(w.config["theme"], "dark");
        assert_eq!(w.width, Some(640));
        assert_eq!(w.height, Some(480));
    }
}

#[test]
fn validation_wizard_missing_page_fails() {
    let err = validate(&json!({"type": "wizard"})).unwrap_err();
    assert!(matches!(
        err,
        ValidationError::Validation { ref field, .. } if field == "page"
    ));
}

#[test]
fn validation_wizard_missing_page_id_fails() {
    let err = validate(&json!({
        "type": "wizard",
        "page": { "title": "T", "html": "a.html" }
    }))
    .unwrap_err();
    assert!(matches!(
        err,
        ValidationError::Validation { ref field, .. } if field == "page.id"
    ));
}

#[test]
fn validation_wizard_empty_html_fails() {
    let err = validate(&json!({
        "type": "wizard",
        "page": { "id": "a", "title": "T", "html": "" }
    }))
    .unwrap_err();
    assert!(matches!(
        err,
        ValidationError::Validation { ref field, .. } if field == "page.html"
    ));
}

#[test]
fn validation_wizard_invalid_layout_fails() {
    let err = validate(&json!({
        "type": "wizard",
        "page": {
            "id": "a",
            "title": "T",
            "html": "a.html",
            "layout": "fullscreen"
        }
    }))
    .unwrap_err();
    match err {
        ValidationError::Validation { field, message } => {
            assert_eq!(field, "page.layout");
            assert!(message.contains("dialog") && message.contains("workspace"));
        }
        other => panic!("unexpected {other:?}"),
    }
}

#[test]
fn validation_wizard_workflow_optional_and_populated() {
    let missing = validate(&json!({
        "type": "wizard",
        "page": { "id": "a", "title": "T", "html": "a.html" }
    }))
    .expect("valid without workflow");
    let Command::Wizard(without) = missing else {
        panic!("expected Wizard");
    };
    assert!(without.workflow.is_none());

    let with = validate(&json!({
        "type": "wizard",
        "page": { "id": "a", "title": "T", "html": "a.html" },
        "workflow": {
            "pre": "{wyvern_share}/scripts/ext/pre.py",
            "post": "{wyvern_share}/scripts/ext/post.py"
        }
    }))
    .expect("valid with workflow");
    let Command::Wizard(with) = with else {
        panic!("expected Wizard");
    };
    let workflow = with.workflow.expect("workflow present");
    assert_eq!(
        workflow.pre.as_deref(),
        Some("{wyvern_share}/scripts/ext/pre.py")
    );
    assert_eq!(
        workflow.post.as_deref(),
        Some("{wyvern_share}/scripts/ext/post.py")
    );
}

#[test]
fn validation_wizard_unknown_field_fails() {
    let err = validate(&json!({
        "type": "wizard",
        "page": { "id": "a", "title": "T", "html": "a.html" },
        "page_html": "nope"
    }))
    .unwrap_err();
    assert!(matches!(
        err,
        ValidationError::Validation { ref field, .. } if field == "page_html"
    ));
}