cli + tui to publish to leaflet (wip) & manage tasks, notes & watch/read lists 馃崈
charm
leaflet
readability
golang
1package main
2
3import (
4 "bytes"
5 "context"
6 "errors"
7 "strings"
8 "testing"
9
10 "github.com/charmbracelet/fang"
11 "github.com/spf13/cobra"
12 "github.com/stormlightlabs/noteleaf/internal/handlers"
13 "github.com/stormlightlabs/noteleaf/internal/store"
14)
15
16func executeCommand(t *testing.T, cmd *cobra.Command, args ...string) string {
17 buf := &bytes.Buffer{}
18 cmd.SetOut(buf)
19 cmd.SetArgs(args)
20 if err := cmd.Execute(); err != nil {
21 t.Fatalf("command %q failed: %v", args, err)
22 }
23 return buf.String()
24}
25
26func TestNewApp(t *testing.T) {
27 t.Run("Success", func(t *testing.T) {
28 origDB := store.NewDatabase
29 origConfig := store.LoadConfig
30 defer func() {
31 store.NewDatabase = origDB
32 store.LoadConfig = origConfig
33 }()
34
35 store.NewDatabase = func() (*store.Database, error) { return &store.Database{}, nil }
36 store.LoadConfig = func() (*store.Config, error) { return &store.Config{}, nil }
37
38 app, err := NewApp()
39 if err != nil {
40 t.Fatalf("expected no error, got %v", err)
41 }
42 if app.db == nil || app.config == nil {
43 t.Fatalf("expected db and config to be initialized")
44 }
45 })
46
47 t.Run("DBError", func(t *testing.T) {
48 origDB := store.NewDatabase
49 defer func() { store.NewDatabase = origDB }()
50 store.NewDatabase = func() (*store.Database, error) { return nil, errors.New("db boom") }
51
52 _, err := NewApp()
53 if err == nil || !strings.Contains(err.Error(), "failed to initialize database") {
54 t.Errorf("expected db init error, got %v", err)
55 }
56 })
57
58 t.Run("ConfigError", func(t *testing.T) {
59 origDB := store.NewDatabase
60 origConfig := store.LoadConfig
61 defer func() {
62 store.NewDatabase = origDB
63 store.LoadConfig = origConfig
64 }()
65 store.NewDatabase = func() (*store.Database, error) { return &store.Database{}, nil }
66 store.LoadConfig = func() (*store.Config, error) { return nil, errors.New("config boom") }
67
68 _, err := NewApp()
69 if err == nil || !strings.Contains(err.Error(), "failed to load configuration") {
70 t.Errorf("expected config load error, got %v", err)
71 }
72 })
73}
74
75func TestRootCmd(t *testing.T) {
76 t.Run("Help", func(t *testing.T) {
77 root := rootCmd()
78 root.SetArgs([]string{})
79 if err := root.Execute(); err != nil {
80 t.Fatalf("expected no error, got %v", err)
81 }
82 })
83
84 t.Run("PrintArgs", func(t *testing.T) {
85 root := rootCmd()
86 root.SetArgs([]string{"hello", "world"})
87 buf := &bytes.Buffer{}
88 root.SetOut(buf)
89
90 if err := root.Execute(); err != nil {
91 t.Fatalf("unexpected error: %v", err)
92 }
93 if got := buf.String(); !strings.Contains(got, "hello world") {
94 t.Errorf("expected output to contain 'hello world', got %q", got)
95 }
96 })
97}
98
99func TestStatusCmd(t *testing.T) {
100 output := executeCommand(t, statusCmd(), nil...)
101 if output == "" {
102 t.Errorf("expected some status output, got empty string")
103 }
104}
105
106func TestResetCmd(t *testing.T) {
107 _ = executeCommand(t, resetCmd(), nil...)
108}
109
110func TestSetupCmd(t *testing.T) {
111 _ = executeCommand(t, setupCmd(), nil...)
112}
113
114func TestConfCmd(t *testing.T) {
115 cmd := confCmd()
116 buf := &bytes.Buffer{}
117 cmd.SetOut(buf)
118 cmd.SetArgs([]string{"path"})
119
120 if err := cmd.Execute(); err != nil {
121 t.Errorf("config path command failed: %v", err)
122 }
123}
124
125func TestRun(t *testing.T) {
126 t.Run("Success", func(t *testing.T) {
127 code := run()
128 if code != 0 {
129 t.Errorf("expected exit code 0, got %d", code)
130 }
131 })
132
133 t.Run("TaskHandlerError", func(t *testing.T) {
134 orig := newTaskHandler
135 defer func() { newTaskHandler = orig }()
136 newTaskHandler = func() (*handlers.TaskHandler, error) { return nil, errors.New("boom") }
137
138 if code := run(); code != 1 {
139 t.Errorf("expected exit code 1, got %d", code)
140 }
141 })
142
143 t.Run("MovieHandlerError", func(t *testing.T) {
144 orig := newMovieHandler
145 defer func() { newMovieHandler = orig }()
146 newMovieHandler = func() (*handlers.MovieHandler, error) { return nil, errors.New("boom") }
147
148 if code := run(); code != 1 {
149 t.Errorf("expected exit code 1, got %d", code)
150 }
151 })
152
153 t.Run("TVHandlerError", func(t *testing.T) {
154 orig := newTVHandler
155 defer func() { newTVHandler = orig }()
156 newTVHandler = func() (*handlers.TVHandler, error) { return nil, errors.New("boom") }
157
158 if code := run(); code != 1 {
159 t.Errorf("expected exit code 1, got %d", code)
160 }
161 })
162
163 t.Run("NoteHandlerError", func(t *testing.T) {
164 orig := newNoteHandler
165 defer func() { newNoteHandler = orig }()
166 newNoteHandler = func() (*handlers.NoteHandler, error) { return nil, errors.New("boom") }
167
168 if code := run(); code != 1 {
169 t.Errorf("expected exit code 1, got %d", code)
170 }
171 })
172
173 t.Run("BookHandlerError", func(t *testing.T) {
174 orig := newBookHandler
175 defer func() { newBookHandler = orig }()
176 newBookHandler = func() (*handlers.BookHandler, error) { return nil, errors.New("boom") }
177
178 if code := run(); code != 1 {
179 t.Errorf("expected exit code 1, got %d", code)
180 }
181 })
182
183 t.Run("ArticleHandlerError", func(t *testing.T) {
184 orig := newArticleHandler
185 defer func() { newArticleHandler = orig }()
186 newArticleHandler = func() (*handlers.ArticleHandler, error) { return nil, errors.New("boom") }
187
188 if code := run(); code != 1 {
189 t.Errorf("expected exit code 1, got %d", code)
190 }
191 })
192
193 t.Run("FangExecuteError", func(t *testing.T) {
194 orig := exc
195 defer func() { exc = orig }()
196 exc = func(ctx context.Context, cmd *cobra.Command, opts ...fang.Option) error {
197 return errors.New("fang failed")
198 }
199
200 if code := run(); code != 1 {
201 t.Errorf("expected exit code 1, got %d", code)
202 }
203 })
204}