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