shape_runtime/renderers/
mod.rs1pub mod html;
7pub mod json;
8pub mod markdown;
9pub mod plain;
10pub mod terminal;
11
12#[cfg(test)]
13mod cross_renderer_tests {
14 use crate::content_renderer::ContentRenderer;
15 use crate::renderers::{
16 html::HtmlRenderer, json::JsonRenderer, markdown::MarkdownRenderer, plain::PlainRenderer,
17 terminal::TerminalRenderer,
18 };
19 use shape_value::content::*;
20
21 fn sample_tree() -> ContentNode {
23 ContentNode::Fragment(vec![
24 ContentNode::plain("Hello ")
25 .with_bold()
26 .with_fg(Color::Named(NamedColor::Red)),
27 ContentNode::plain("world").with_italic(),
28 ContentNode::Table(ContentTable {
29 headers: vec!["Name".into(), "Value".into()],
30 rows: vec![
31 vec![ContentNode::plain("alpha"), ContentNode::plain("1")],
32 vec![ContentNode::plain("beta"), ContentNode::plain("2")],
33 ],
34 border: BorderStyle::Rounded,
35 max_rows: None,
36 column_types: Some(vec!["string".into(), "number".into()]),
37 total_rows: None,
38 sortable: true,
39 }),
40 ContentNode::Code {
41 language: Some("rust".into()),
42 source: "fn main() {}".into(),
43 },
44 ])
45 }
46
47 #[test]
48 fn terminal_contains_ansi_codes() {
49 let tree = sample_tree();
50 let output = TerminalRenderer::new().render(&tree);
51 assert!(
52 output.contains("\x1b["),
53 "terminal output should contain ANSI codes"
54 );
55 assert!(output.contains("Hello"));
56 assert!(output.contains("world"));
57 assert!(output.contains("alpha"));
58 }
59
60 #[test]
61 fn html_contains_tags() {
62 let tree = sample_tree();
63 let output = HtmlRenderer::new().render(&tree);
64 assert!(output.contains("<span"), "HTML should contain <span> tags");
65 assert!(output.contains("<table>"), "HTML should contain <table>");
66 assert!(
67 output.contains("<pre><code"),
68 "HTML should contain <pre><code>"
69 );
70 assert!(output.contains("Hello"));
71 }
72
73 #[test]
74 fn plain_has_no_escape_codes() {
75 let tree = sample_tree();
76 let output = PlainRenderer.render(&tree);
77 assert!(
78 !output.contains("\x1b["),
79 "plain output should not contain ANSI codes"
80 );
81 assert!(
82 !output.contains("<span"),
83 "plain output should not contain HTML tags"
84 );
85 assert!(output.contains("Hello"));
86 assert!(output.contains("alpha"));
87 }
88
89 #[test]
90 fn markdown_uses_gfm_tables() {
91 let tree = sample_tree();
92 let output = MarkdownRenderer.render(&tree);
93 assert!(
94 output.contains("| Name"),
95 "markdown should use pipe table syntax"
96 );
97 assert!(
98 output.contains("```rust"),
99 "markdown should use fenced code blocks"
100 );
101 assert!(output.contains("Hello"));
102 }
103
104 #[test]
105 fn json_is_valid_json() {
106 let tree = sample_tree();
107 let output = JsonRenderer.render(&tree);
108 let parsed: serde_json::Value =
109 serde_json::from_str(&output).expect("JSON renderer output should be valid JSON");
110 assert!(parsed.get("type").is_some(), "JSON should have 'type' key");
111 }
112
113 #[test]
114 fn all_renderers_agree_on_text_content() {
115 let node = ContentNode::plain("consistent");
116 let terminal = TerminalRenderer::new().render(&node);
117 let html = HtmlRenderer::new().render(&node);
118 let plain = PlainRenderer.render(&node);
119 let markdown = MarkdownRenderer.render(&node);
120
121 assert!(terminal.contains("consistent"));
123 assert!(html.contains("consistent"));
124 assert!(plain.contains("consistent"));
125 assert!(markdown.contains("consistent"));
126 }
127}