cli + tui to publish to leaflet (wip) & manage tasks, notes & watch/read lists 馃崈
charm leaflet readability golang
at main 118 lines 3.5 kB view raw
1package handlers 2 3import ( 4 "errors" 5 "strings" 6 "testing" 7) 8 9type renderMarkdownTC struct { 10 name string 11 content string 12 err bool 13 contains []string 14} 15 16type fakeRenderer struct { 17 fail bool 18} 19 20func (f fakeRenderer) Render(s string) (string, error) { 21 if f.fail { 22 return "", errors.New("render error") 23 } 24 return "fake:" + s, nil 25} 26 27var defaultRenderer = newRenderer 28 29func TestRenderMarkdown(t *testing.T) { 30 tt := []renderMarkdownTC{ 31 {name: "simple text", content: "Hello, world!", err: false, contains: []string{"Hello, world!"}}, 32 {name: "markdown heading", content: "# Main Title", err: false, contains: []string{"Main Title"}}, 33 {name: "markdown with emphasis", content: "This is **bold** and *italic* text", err: false, contains: []string{"bold", "italic"}}, 34 {name: "markdown list", content: "- Item 1\n- Item 2\n- Item 3", err: false, contains: []string{"Item 1", "Item 2", "Item 3"}}, 35 {name: "code block", content: "```go\nfunc main() {\n fmt.Println(\"Hello\")\n}\n```", err: false, contains: []string{"main", "fmt.Println"}}, 36 {name: "empty string", content: "", err: false, contains: []string{}}, 37 {name: "only whitespace", content: " \n\t \n ", err: false, contains: []string{}}, 38 {name: "mixed content", content: "# Title\n\nSome **bold** text and a [link](https://example.com)\n\n- List item", 39 err: false, contains: []string{"Title", "bold", "example.com", "List item"}}, 40 } 41 42 for _, tc := range tt { 43 t.Run(tc.name, func(t *testing.T) { 44 defer func() { newRenderer = defaultRenderer }() 45 46 result, err := renderMarkdown(tc.content) 47 if tc.err && err == nil { 48 t.Fatalf("expected error, got nil") 49 } 50 if !tc.err && err != nil { 51 t.Fatalf("unexpected error: %v", err) 52 } 53 54 for _, want := range tc.contains { 55 if !strings.Contains(result, want) { 56 t.Fatalf("result should contain %q, got:\n%s", want, result) 57 } 58 } 59 }) 60 } 61 62 t.Run("WordWrap", func(t *testing.T) { 63 defer func() { newRenderer = defaultRenderer }() 64 text := strings.Repeat("This is a very long line that should be wrapped at 80 characters. ", 5) 65 result, err := renderMarkdown(text) 66 if err != nil { 67 t.Fatalf("unexpected error: %v", err) 68 } 69 70 lines := strings.Split(result, "\n") 71 for i, line := range lines { 72 cleaned := removeANSI(line) 73 if len(cleaned) > 85 { 74 t.Fatalf("Line at index %d is too long (%d chars): %q", i, len(cleaned), cleaned) 75 } 76 } 77 }) 78 79 t.Run("RendererCreationFails", func(t *testing.T) { 80 newRenderer = func() (MarkdownRenderer, error) { 81 return nil, errors.New("forced renderer creation error") 82 } 83 _, err := renderMarkdown("test") 84 if err == nil || !strings.Contains(err.Error(), "failed to create markdown renderer") { 85 t.Fatalf("expected creation error, got %v", err) 86 } 87 }) 88 89 t.Run("RenderFails", func(t *testing.T) { 90 newRenderer = func() (MarkdownRenderer, error) { 91 return fakeRenderer{fail: true}, nil 92 } 93 _, err := renderMarkdown("test") 94 if err == nil || !strings.Contains(err.Error(), "failed to render markdown") { 95 t.Fatalf("expected render error, got %v", err) 96 } 97 }) 98} 99 100func removeANSI(s string) string { 101 result := "" 102 inEscapeCh := false 103 for i := 0; i < len(s); i++ { 104 if s[i] == '\x1b' && i+1 < len(s) && s[i+1] == '[' { 105 inEscapeCh = true 106 i++ 107 continue 108 } 109 if inEscapeCh { 110 if (s[i] >= 'A' && s[i] <= 'Z') || (s[i] >= 'a' && s[i] <= 'z') { 111 inEscapeCh = false 112 } 113 continue 114 } 115 result += string(s[i]) 116 } 117 return result 118}