A minimal email TUI where you read with Markdown and write in Neovim. neomd.ssp.sh/docs
email markdown neovim tui
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at main 281 lines 8.7 kB view raw
1package render 2 3import ( 4 "strings" 5 "testing" 6) 7 8func TestToHTML_Bold(t *testing.T) { 9 out, err := ToHTML("**bold** text") 10 if err != nil { 11 t.Fatalf("ToHTML returned error: %v", err) 12 } 13 if !strings.Contains(out, "<strong>bold</strong>") { 14 t.Errorf("expected <strong>bold</strong> in output, got:\n%s", out) 15 } 16} 17 18func TestToHTML_HTMLWrapper(t *testing.T) { 19 out, err := ToHTML("hello") 20 if err != nil { 21 t.Fatalf("ToHTML returned error: %v", err) 22 } 23 if !strings.HasPrefix(out, "<!DOCTYPE html>") { 24 t.Errorf("expected output to start with <!DOCTYPE html>, got:\n%.80s...", out) 25 } 26 if !strings.Contains(out, "<body>") { 27 t.Errorf("expected <body> in output") 28 } 29} 30 31func TestToHTML_GFMTable(t *testing.T) { 32 md := "| A | B |\n|---|---|\n| 1 | 2 |\n" 33 out, err := ToHTML(md) 34 if err != nil { 35 t.Fatalf("ToHTML returned error: %v", err) 36 } 37 if !strings.Contains(out, "<table>") { 38 t.Errorf("expected <table> in output, got:\n%s", out) 39 } 40} 41 42func TestToHTML_CodeBlock(t *testing.T) { 43 md := "```go\nfmt.Println(\"hi\")\n```\n" 44 out, err := ToHTML(md) 45 if err != nil { 46 t.Fatalf("ToHTML returned error: %v", err) 47 } 48 if !strings.Contains(out, "<pre>") { 49 t.Errorf("expected <pre> in output, got:\n%s", out) 50 } 51} 52 53func TestToHTML_Empty(t *testing.T) { 54 out, err := ToHTML("") 55 if err != nil { 56 t.Fatalf("ToHTML returned error for empty input: %v", err) 57 } 58 if !strings.HasPrefix(out, "<!DOCTYPE html>") { 59 t.Errorf("expected DOCTYPE even for empty input, got:\n%.80s...", out) 60 } 61} 62 63func TestToANSI_Smoke(t *testing.T) { 64 _, err := ToANSI("# Hello\n\nSome **bold** text.", "dark", 80) 65 if err != nil { 66 t.Fatalf("ToANSI returned error: %v", err) 67 } 68} 69 70func TestToHTML_Callout_Note(t *testing.T) { 71 md := "> [!note]\n> This is a note callout\n" 72 out, err := ToHTML(md) 73 if err != nil { 74 t.Fatalf("ToHTML returned error: %v", err) 75 } 76 // Print actual HTML for debugging 77 t.Logf("Actual HTML output:\n%s", out) 78 if !strings.Contains(out, "callout") { 79 t.Errorf("expected 'callout' class in output, got:\n%s", out) 80 } 81 if !strings.Contains(out, "callout-note") { 82 t.Errorf("expected 'callout-note' class in output, got:\n%s", out) 83 } 84 if !strings.Contains(out, "This is a note callout") { 85 t.Errorf("expected callout content in output, got:\n%s", out) 86 } 87} 88 89func TestToHTML_Callout_WithTitle(t *testing.T) { 90 md := "> [!warning] Custom Warning Title\n> This is a warning\n" 91 out, err := ToHTML(md) 92 if err != nil { 93 t.Fatalf("ToHTML returned error: %v", err) 94 } 95 if !strings.Contains(out, "callout-warning") { 96 t.Errorf("expected 'callout-warning' class in output, got:\n%s", out) 97 } 98 if !strings.Contains(out, "Custom Warning Title") { 99 t.Errorf("expected custom title in output, got:\n%s", out) 100 } 101 if !strings.Contains(out, "This is a warning") { 102 t.Errorf("expected callout content in output, got:\n%s", out) 103 } 104} 105 106func TestToHTML_Callout_MultiParagraph(t *testing.T) { 107 md := "> [!tip]\n> First paragraph\n> \n> Second paragraph\n" 108 out, err := ToHTML(md) 109 if err != nil { 110 t.Fatalf("ToHTML returned error: %v", err) 111 } 112 if !strings.Contains(out, "callout-tip") { 113 t.Errorf("expected 'callout-tip' class in output, got:\n%s", out) 114 } 115 if !strings.Contains(out, "First paragraph") { 116 t.Errorf("expected first paragraph in output, got:\n%s", out) 117 } 118 if !strings.Contains(out, "Second paragraph") { 119 t.Errorf("expected second paragraph in output, got:\n%s", out) 120 } 121} 122 123func TestToHTML_Callout_Types(t *testing.T) { 124 tests := []struct { 125 name string 126 callType string 127 wantClass string 128 }{ 129 {"note", "note", "callout-note"}, 130 {"tip", "tip", "callout-tip"}, 131 {"important", "important", "callout-important"}, 132 {"warning", "warning", "callout-warning"}, 133 {"caution", "caution", "callout-caution"}, 134 } 135 136 for _, tt := range tests { 137 t.Run(tt.name, func(t *testing.T) { 138 md := "> [!" + tt.callType + "]\n> Test content\n" 139 out, err := ToHTML(md) 140 if err != nil { 141 t.Fatalf("ToHTML returned error: %v", err) 142 } 143 if !strings.Contains(out, tt.wantClass) { 144 t.Errorf("expected '%s' class in output, got:\n%s", tt.wantClass, out) 145 } 146 }) 147 } 148} 149 150func TestToHTML_Callout_NoSpaceSyntax(t *testing.T) { 151 // Test if >[!note] works without space after > 152 md := ">[!note] No Space Test\n>This tests the syntax without space\n" 153 out, err := ToHTML(md) 154 if err != nil { 155 t.Fatalf("ToHTML returned error: %v", err) 156 } 157 // Check if it rendered as callout or as regular blockquote 158 if strings.Contains(out, "callout-note") { 159 // Success: >[!note] (no space) DOES work as callout 160 if !strings.Contains(out, "No Space Test") { 161 t.Errorf("expected title in callout output, got:\n%s", out) 162 } 163 if !strings.Contains(out, "This tests the syntax without space") { 164 t.Errorf("expected content in callout output, got:\n%s", out) 165 } 166 } else { 167 // Failure: rendered as blockquote instead 168 t.Errorf(">[!note] without space did not render as callout. Use '> [!note]' (with space) instead. Got:\n%s", out) 169 } 170} 171 172func TestFormatCalloutsForPlainText_WithTitle(t *testing.T) { 173 input := "> [!tip] Good News\n> We're ahead of schedule!\n" 174 expected := "💡 Good News\nWe're ahead of schedule!\n" 175 got := FormatCalloutsForPlainText(input) 176 if got != expected { 177 t.Errorf("FormatCalloutsForPlainText with title:\nwant: %q\ngot: %q", expected, got) 178 } 179} 180 181func TestFormatCalloutsForPlainText_NoTitle(t *testing.T) { 182 input := "> [!note]\n> This is a note\n" 183 expected := "📘 Note\nThis is a note\n" 184 got := FormatCalloutsForPlainText(input) 185 if got != expected { 186 t.Errorf("FormatCalloutsForPlainText without title:\nwant: %q\ngot: %q", expected, got) 187 } 188} 189 190func TestFormatCalloutsForPlainText_MultipleCallouts(t *testing.T) { 191 input := "> [!warning] Action Required\n> Please review by Friday.\n\n> [!note]\n> Please read\n" 192 expected := "⚠️ Action Required\nPlease review by Friday.\n\n📘 Note\nPlease read\n" 193 got := FormatCalloutsForPlainText(input) 194 if got != expected { 195 t.Errorf("FormatCalloutsForPlainText with multiple callouts:\nwant: %q\ngot: %q", expected, got) 196 } 197} 198 199func TestFormatCalloutsForPlainText_NoSpaceAfterArrow(t *testing.T) { 200 input := ">[!tip] Title\n>Content here\n" 201 got := FormatCalloutsForPlainText(input) 202 if !strings.Contains(got, "💡 Title") { 203 t.Errorf("FormatCalloutsForPlainText should handle >[!type] without space:\ngot: %q", got) 204 } 205 if !strings.Contains(got, "Content here") { 206 t.Errorf("FormatCalloutsForPlainText should unquote content:\ngot: %q", got) 207 } 208 // Should NOT contain > markers 209 if strings.Contains(got, ">") { 210 t.Errorf("FormatCalloutsForPlainText should remove blockquote markers:\ngot: %q", got) 211 } 212} 213 214func TestFormatCalloutsForPlainText_AllTypes(t *testing.T) { 215 tests := []struct { 216 callType string 217 wantIcon string 218 }{ 219 {"note", "📘"}, 220 {"tip", "💡"}, 221 {"warning", "⚠️"}, 222 {"danger", "🚨"}, 223 {"success", "✅"}, 224 {"info", "ℹ️"}, 225 {"question", "❓"}, 226 {"bug", "🐛"}, 227 {"example", "📝"}, 228 } 229 230 for _, tt := range tests { 231 t.Run(tt.callType, func(t *testing.T) { 232 input := "> [!" + tt.callType + "] Title\n> Content\n" 233 got := FormatCalloutsForPlainText(input) 234 if !strings.Contains(got, tt.wantIcon) { 235 t.Errorf("expected icon %s for type %s, got: %q", tt.wantIcon, tt.callType, got) 236 } 237 }) 238 } 239} 240 241func TestFormatCalloutsForPlainText_PreservesNonCallouts(t *testing.T) { 242 input := "Regular text\n\n> Regular blockquote\n> without callout\n\n> [!note] Callout\n> With content\n" 243 got := FormatCalloutsForPlainText(input) 244 245 // Should preserve regular text and non-callout blockquotes 246 if !strings.Contains(got, "Regular text") { 247 t.Error("should preserve regular text") 248 } 249 if !strings.Contains(got, "> Regular blockquote") { 250 t.Error("should preserve regular blockquotes") 251 } 252 // Should format the callout (no blockquote marker) 253 if !strings.Contains(got, "📘 Callout") { 254 t.Error("should format callout syntax") 255 } 256 if !strings.Contains(got, "With content") { 257 t.Error("should include callout content") 258 } 259} 260 261func TestFormatCalloutsForPlainText_MultiParagraphCallout(t *testing.T) { 262 input := "> [!tip] Title\n> First paragraph\n> \n> Second paragraph\n" 263 got := FormatCalloutsForPlainText(input) 264 265 if !strings.Contains(got, "💡 Title") { 266 t.Errorf("should have emoji title, got: %q", got) 267 } 268 if !strings.Contains(got, "First paragraph") { 269 t.Errorf("should have first paragraph, got: %q", got) 270 } 271 if !strings.Contains(got, "Second paragraph") { 272 t.Errorf("should have second paragraph, got: %q", got) 273 } 274 // Should not have > markers 275 lines := strings.Split(got, "\n") 276 for _, line := range lines { 277 if strings.TrimSpace(line) != "" && strings.HasPrefix(strings.TrimSpace(line), ">") { 278 t.Errorf("should not have > markers in callout content, got line: %q", line) 279 } 280 } 281}