katana-document-viewer 0.1.4

KatanA document viewer artifact, render evaluation, and export foundation.
Documentation
use super::{
    DiagramRenderTestSupport, ErrorDiagramEngine, PanicDiagramEngine, RecordingDiagramEngine,
};
use crate::artifact::ArtifactFormat;
use crate::forge_diagram_render_types::DiagramRenderingBackend;
use crate::{
    BuildProfile, BuildRequest, ExportFormat, ExportRequest, ForgePipeline, KdvThemeSnapshot,
};
use std::sync::{Arc, Mutex};

#[test]
fn diagram_renderer_panic_is_recorded_as_diagnostic() -> Result<(), Box<dyn std::error::Error>> {
    let pipeline = ForgePipeline::new(DiagramRenderingBackend::new(PanicDiagramEngine));
    let graph = pipeline.build(&BuildRequest {
        snapshot: DiagramRenderTestSupport::snapshot_from_markdown(
            "```mermaid\ngraph TD\n  A --> B\n```",
        )?,
        profile: BuildProfile::markdown_export(),
        theme: KdvThemeSnapshot::katana_light(),
    })?;

    assert!(graph.rendered_diagrams.is_empty());
    assert!(
        graph
            .diagnostics
            .messages
            .iter()
            .any(|message| message.contains("diagram renderer panicked"))
    );
    Ok(())
}

#[test]
fn diagram_renderer_receives_app_supplied_complete_theme() -> Result<(), Box<dyn std::error::Error>>
{
    let captured_themes = Arc::new(Mutex::new(Vec::new()));
    let pipeline = ForgePipeline::new(DiagramRenderingBackend::new(RecordingDiagramEngine {
        themes: captured_themes.clone(),
    }));
    let graph = pipeline.build(&BuildRequest {
        snapshot: DiagramRenderTestSupport::snapshot_from_markdown(
            "```plantuml\n@startuml\nAlice -> Bob\n@enduml\n```",
        )?,
        profile: BuildProfile::markdown_export(),
        theme: DiagramRenderTestSupport::app_supplied_dark_theme(),
    })?;

    assert_eq!(graph.rendered_diagrams.len(), 1);
    let themes = captured_themes
        .lock()
        .map_err(|error| format!("theme capture lock failed: {error}"))?;
    let captured = themes.first().ok_or("captured KRR theme is missing")?;
    DiagramRenderTestSupport::assert_app_supplied_theme_forwarded(captured);
    Ok(())
}

#[test]
fn diagram_renderer_records_render_error_without_panic() -> Result<(), Box<dyn std::error::Error>> {
    let pipeline = ForgePipeline::new(DiagramRenderingBackend::new(ErrorDiagramEngine));
    let graph = pipeline.build(&BuildRequest {
        snapshot: DiagramRenderTestSupport::snapshot_from_markdown(
            "```mermaid\ngraph TD\n  A --> B\n```",
        )?,
        profile: BuildProfile::markdown_export(),
        theme: KdvThemeSnapshot::katana_light(),
    })?;

    assert_eq!(graph.rendered_diagrams.len(), 0);
    assert_eq!(
        graph.diagnostics.messages,
        vec!["render failed".to_string()]
    );
    Ok(())
}

#[test]
fn diagram_renderer_walks_nested_list_items() {
    let pipeline = DiagramRenderingBackend::new(RecordingDiagramEngine {
        themes: Arc::new(Mutex::new(Vec::new())),
    });
    let root = DiagramRenderTestSupport::nested_list_root_with_diagram();

    let mut rendered_diagrams = Vec::new();
    let mut messages = Vec::new();
    pipeline.collect_node(
        &root,
        "document-id",
        &KdvThemeSnapshot::katana_light(),
        &mut rendered_diagrams,
        &mut messages,
    );

    assert_eq!(rendered_diagrams.len(), 1);
    assert!(messages.is_empty());
}

#[test]
fn diagram_renderer_exports_payload() -> Result<(), Box<dyn std::error::Error>> {
    let pipeline = ForgePipeline::new(DiagramRenderingBackend::new(RecordingDiagramEngine {
        themes: Arc::new(Mutex::new(Vec::new())),
    }));
    let graph = pipeline.build(&BuildRequest {
        snapshot: DiagramRenderTestSupport::snapshot_from_markdown(
            "```mermaid\ngraph TD\n  A --> B\n```",
        )?,
        profile: BuildProfile::markdown_export(),
        theme: KdvThemeSnapshot::katana_light(),
    })?;

    let output = pipeline.export(&ExportRequest {
        graph,
        format: ExportFormat::Html,
        theme: KdvThemeSnapshot::katana_light(),
    })?;

    assert_eq!(output.artifact.manifest.format, ArtifactFormat::Html);
    assert_eq!(output.artifact.manifest.backend, "katana-document-viewer");
    assert!(!output.artifact.bytes.bytes.is_empty());

    Ok(())
}