Skip to content

Commit 49e332e

Browse files
authored
Merge pull request #10 from tkc/copilot/improve-test-coverage
Add comprehensive tests across all packages
2 parents 1cb8c35 + 6c0a0f4 commit 49e332e

6 files changed

Lines changed: 1279 additions & 59 deletions

File tree

go.mod

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ go 1.22
44

55
require (
66
github.com/fsnotify/fsnotify v1.7.0
7-
github.com/spf13/cast v1.6.0
87
github.com/stretchr/testify v1.8.4
98
)
109

go.sum

Lines changed: 0 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -1,72 +1,14 @@
1-
github.com/alecthomas/assert v0.0.0-20170929043011-405dbfeb8e38/go.mod h1:r7bzyVFMNntcxPZXK3/+KdruV1H5KSlyVY0gc+NgInI=
2-
github.com/alecthomas/colour v0.0.0-20160524082231-60882d9e2721/go.mod h1:QO9JBoKquHd+jz9nshCh40fOfO+JzsoXy8qTHF68zU0=
3-
github.com/alecthomas/repr v0.0.0-20181024024818-d37bc2a10ba1/go.mod h1:xTS7Pm1pD1mvyM075QCDSRqH6qRLXylzS24ZTpRiSzQ=
4-
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc h1:cAKDfWh5VpdgMhJosfJnn5/FoN2SRZ4p7fJNX58YPaU=
5-
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
6-
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751 h1:JYp7IbQjafoB+tBA3gMyHYHrpOtNuDiK/uB5uXxq5wM=
7-
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
8-
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf h1:qet1QNfXsQxTZqLG4oE62mJzwPIB8+Tee4RNCL9ulrY=
9-
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
10-
github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d h1:UQZhZ2O0vMHr2cI+DC1Mbh0TJxzA3RcLoMsFw+aXw7E=
11-
github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho=
12-
github.com/creack/pty v1.1.9 h1:uDmaGzcdjhF4i/plgjmEsriH11Y0o7RKapEf/LDaM3w=
13-
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
14-
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
15-
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
16-
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
171
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
182
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
19-
github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8=
20-
github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0=
213
github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA=
224
github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM=
23-
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
24-
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
25-
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
26-
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
27-
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
28-
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
29-
github.com/kyoh86/scopelint v0.2.0 h1:suOCh1T05nIY8srcI266aqwf3RLtO8kniZOTaAnzRyg=
30-
github.com/kyoh86/scopelint v0.2.0/go.mod h1:veFgnmDG8sPR5nFaXGX2mEIOXKHjWpGo79v/NaiTcRE=
31-
github.com/mattn/go-isatty v0.0.6/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
32-
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e h1:aoZm08cpOy4WuID//EZDgcC4zIxODThtZNPirFr42+A=
33-
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
34-
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
35-
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
365
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
376
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
38-
github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8=
39-
github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs=
40-
github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=
41-
github.com/spf13/cast v1.3.1 h1:nFm6S0SMdyzrzcmThSipiEubIDy8WEXKNZ0UOgiRpng=
42-
github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
43-
github.com/spf13/cast v1.6.0 h1:GEiTHELF+vaR5dhz3VqZfFSzZjYbgeKDpBxQVS4GYJ0=
44-
github.com/spf13/cast v1.6.0/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo=
45-
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
46-
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
47-
github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c=
48-
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
49-
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
50-
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
51-
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
52-
github.com/stretchr/testify v1.5.1 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H4=
53-
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
54-
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
55-
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
567
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
578
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
58-
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
59-
golang.org/x/sys v0.4.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
609
golang.org/x/sys v0.18.0 h1:DBdB3niSjOA/O0blCZBqDefyWNYveAYMNF1Wum0DYQ4=
6110
golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
62-
gopkg.in/alecthomas/kingpin.v2 v2.2.5 h1:qskSCq465uEvC3oGocwvZNsO3RF3SpLVLumOAhL0bXo=
63-
gopkg.in/alecthomas/kingpin.v2 v2.2.5/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
64-
gopkg.in/alecthomas/kingpin.v2 v2.2.6 h1:jMFz6MfLP0/4fUyZle81rXUoxOBFi19VUFKVDOQfozc=
65-
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
6611
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
6712
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
68-
gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
69-
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
70-
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
7113
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
7214
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

src/config/config_test.go

Lines changed: 272 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -261,3 +261,275 @@ func TestWatchConfig(t *testing.T) {
261261
// We can't easily test the file watching functionality in a unit test
262262
// but we can at least verify the watcher is set up without errors
263263
}
264+
265+
func TestLoadConfig_Defaults(t *testing.T) {
266+
tempDir, err := os.MkdirTemp("", "defaults-test")
267+
assert.NoError(t, err)
268+
defer os.RemoveAll(tempDir)
269+
270+
jsonFile := filepath.Join(tempDir, "test.json")
271+
err = os.WriteFile(jsonFile, []byte(`{}`), 0644)
272+
assert.NoError(t, err)
273+
274+
// Config with no port, logLevel, or logFormat
275+
configPath := filepath.Join(tempDir, "config.json")
276+
configContent := `{
277+
"endpoints": [
278+
{
279+
"method": "GET",
280+
"status": 200,
281+
"path": "/test",
282+
"jsonPath": "` + jsonFile + `"
283+
}
284+
]
285+
}`
286+
err = os.WriteFile(configPath, []byte(configContent), 0644)
287+
assert.NoError(t, err)
288+
289+
cfg, err := LoadConfig(configPath)
290+
assert.NoError(t, err)
291+
assert.Equal(t, 3000, cfg.Port, "default port should be 3000")
292+
assert.Equal(t, "info", cfg.LogLevel, "default logLevel should be info")
293+
assert.Equal(t, "text", cfg.LogFormat, "default logFormat should be text")
294+
}
295+
296+
func TestLoadConfig_InvalidJSON(t *testing.T) {
297+
tempDir, err := os.MkdirTemp("", "invalid-json-test")
298+
assert.NoError(t, err)
299+
defer os.RemoveAll(tempDir)
300+
301+
configPath := filepath.Join(tempDir, "config.json")
302+
err = os.WriteFile(configPath, []byte(`{invalid json}`), 0644)
303+
assert.NoError(t, err)
304+
305+
_, err = LoadConfig(configPath)
306+
assert.Error(t, err)
307+
assert.Contains(t, err.Error(), "error parsing config file")
308+
}
309+
310+
func TestLoadConfig_FileNotFound(t *testing.T) {
311+
_, err := LoadConfig("/nonexistent/path/config.json")
312+
assert.Error(t, err)
313+
assert.Contains(t, err.Error(), "error reading config file")
314+
}
315+
316+
func TestLoadConfig_WithHost(t *testing.T) {
317+
tempDir, err := os.MkdirTemp("", "host-test")
318+
assert.NoError(t, err)
319+
defer os.RemoveAll(tempDir)
320+
321+
jsonFile := filepath.Join(tempDir, "test.json")
322+
err = os.WriteFile(jsonFile, []byte(`{}`), 0644)
323+
assert.NoError(t, err)
324+
325+
configPath := filepath.Join(tempDir, "config.json")
326+
configContent := `{
327+
"host": "localhost",
328+
"port": 9090,
329+
"endpoints": [
330+
{
331+
"method": "GET",
332+
"status": 200,
333+
"path": "/test",
334+
"jsonPath": "` + jsonFile + `"
335+
}
336+
]
337+
}`
338+
err = os.WriteFile(configPath, []byte(configContent), 0644)
339+
assert.NoError(t, err)
340+
341+
cfg, err := LoadConfig(configPath)
342+
assert.NoError(t, err)
343+
assert.Equal(t, "localhost", cfg.Host)
344+
assert.Equal(t, 9090, cfg.Port)
345+
}
346+
347+
func TestConfig_GetEndpoints(t *testing.T) {
348+
cfg := &Config{
349+
Endpoints: []Endpoint{
350+
{Method: "GET", Path: "/a"},
351+
{Method: "POST", Path: "/b"},
352+
},
353+
}
354+
355+
endpoints := cfg.GetEndpoints()
356+
assert.Len(t, endpoints, 2)
357+
assert.Equal(t, "/a", endpoints[0].Path)
358+
assert.Equal(t, "/b", endpoints[1].Path)
359+
360+
// Modifying returned slice should not affect original
361+
endpoints[0].Path = "/modified"
362+
assert.Equal(t, "/a", cfg.Endpoints[0].Path)
363+
}
364+
365+
func TestConfig_GetPort(t *testing.T) {
366+
cfg := &Config{Port: 4000}
367+
assert.Equal(t, 4000, cfg.GetPort())
368+
}
369+
370+
func TestConfig_GetHost(t *testing.T) {
371+
cfg := &Config{Host: "example.com"}
372+
assert.Equal(t, "example.com", cfg.GetHost())
373+
}
374+
375+
func TestConfig_GetLogConfig(t *testing.T) {
376+
cfg := &Config{
377+
LogLevel: "debug",
378+
LogFormat: "json",
379+
LogPath: "/var/log/server.log",
380+
}
381+
382+
level, format, path := cfg.GetLogConfig()
383+
assert.Equal(t, "debug", level)
384+
assert.Equal(t, "json", format)
385+
assert.Equal(t, "/var/log/server.log", path)
386+
}
387+
388+
func TestConfig_Validate_DifferentMethodsSamePath(t *testing.T) {
389+
tempDir, err := os.MkdirTemp("", "methods-test")
390+
assert.NoError(t, err)
391+
defer os.RemoveAll(tempDir)
392+
393+
jsonFile := filepath.Join(tempDir, "test.json")
394+
err = os.WriteFile(jsonFile, []byte(`{}`), 0644)
395+
assert.NoError(t, err)
396+
397+
cfg := Config{
398+
Endpoints: []Endpoint{
399+
{Method: "GET", Path: "/users", JsonPath: jsonFile, Status: 200},
400+
{Method: "POST", Path: "/users", JsonPath: jsonFile, Status: 201},
401+
{Method: "PUT", Path: "/users", JsonPath: jsonFile, Status: 200},
402+
{Method: "DELETE", Path: "/users", JsonPath: jsonFile, Status: 204},
403+
},
404+
}
405+
406+
err = cfg.Validate()
407+
assert.NoError(t, err, "different HTTP methods on the same path should be allowed")
408+
}
409+
410+
func TestConfig_Validate_MultipleEndpoints(t *testing.T) {
411+
tempDir, err := os.MkdirTemp("", "multi-ep-test")
412+
assert.NoError(t, err)
413+
defer os.RemoveAll(tempDir)
414+
415+
jsonFile := filepath.Join(tempDir, "test.json")
416+
err = os.WriteFile(jsonFile, []byte(`{}`), 0644)
417+
assert.NoError(t, err)
418+
419+
cfg := Config{
420+
Endpoints: []Endpoint{
421+
{Method: "GET", Path: "/users", JsonPath: jsonFile, Status: 200},
422+
{Method: "GET", Path: "/posts", JsonPath: jsonFile, Status: 200},
423+
{Method: "GET", Path: "/comments", JsonPath: jsonFile, Status: 200},
424+
},
425+
}
426+
427+
err = cfg.Validate()
428+
assert.NoError(t, err)
429+
}
430+
431+
func TestConfig_Validate_EndpointWithType(t *testing.T) {
432+
tempDir, err := os.MkdirTemp("", "type-test")
433+
assert.NoError(t, err)
434+
defer os.RemoveAll(tempDir)
435+
436+
jsonFile := filepath.Join(tempDir, "test.json")
437+
err = os.WriteFile(jsonFile, []byte(`{}`), 0644)
438+
assert.NoError(t, err)
439+
440+
cfg := Config{
441+
Endpoints: []Endpoint{
442+
{Type: "api", Method: "GET", Path: "/test", JsonPath: jsonFile, Status: 200},
443+
},
444+
}
445+
446+
err = cfg.Validate()
447+
assert.NoError(t, err)
448+
}
449+
450+
func TestConfig_Reload_InvalidConfig(t *testing.T) {
451+
tempDir, err := os.MkdirTemp("", "reload-invalid-test")
452+
assert.NoError(t, err)
453+
defer os.RemoveAll(tempDir)
454+
455+
jsonFile := filepath.Join(tempDir, "test.json")
456+
err = os.WriteFile(jsonFile, []byte(`{}`), 0644)
457+
assert.NoError(t, err)
458+
459+
// Create initial valid config
460+
configPath := filepath.Join(tempDir, "config.json")
461+
initialConfig := `{
462+
"port": 8080,
463+
"endpoints": [
464+
{
465+
"method": "GET",
466+
"status": 200,
467+
"path": "/test",
468+
"jsonPath": "` + jsonFile + `"
469+
}
470+
]
471+
}`
472+
err = os.WriteFile(configPath, []byte(initialConfig), 0644)
473+
assert.NoError(t, err)
474+
475+
cfg, err := LoadConfig(configPath)
476+
assert.NoError(t, err)
477+
assert.Equal(t, 8080, cfg.Port)
478+
479+
// Overwrite with invalid JSON
480+
err = os.WriteFile(configPath, []byte(`{invalid}`), 0644)
481+
assert.NoError(t, err)
482+
483+
// Reload should fail
484+
err = cfg.Reload(configPath)
485+
assert.Error(t, err)
486+
// Original config should remain unchanged
487+
assert.Equal(t, 8080, cfg.Port)
488+
}
489+
490+
func TestLoadConfig_WithLogPath(t *testing.T) {
491+
tempDir, err := os.MkdirTemp("", "logpath-test")
492+
assert.NoError(t, err)
493+
defer os.RemoveAll(tempDir)
494+
495+
jsonFile := filepath.Join(tempDir, "test.json")
496+
err = os.WriteFile(jsonFile, []byte(`{}`), 0644)
497+
assert.NoError(t, err)
498+
499+
configPath := filepath.Join(tempDir, "config.json")
500+
configContent := `{
501+
"port": 3000,
502+
"logLevel": "warn",
503+
"logFormat": "json",
504+
"logPath": "/tmp/test-server.log",
505+
"endpoints": [
506+
{
507+
"method": "GET",
508+
"status": 200,
509+
"path": "/test",
510+
"jsonPath": "` + jsonFile + `"
511+
}
512+
]
513+
}`
514+
err = os.WriteFile(configPath, []byte(configContent), 0644)
515+
assert.NoError(t, err)
516+
517+
cfg, err := LoadConfig(configPath)
518+
assert.NoError(t, err)
519+
assert.Equal(t, "warn", cfg.LogLevel)
520+
assert.Equal(t, "json", cfg.LogFormat)
521+
assert.Equal(t, "/tmp/test-server.log", cfg.LogPath)
522+
}
523+
524+
func TestConfig_Validate_EmptyJsonPath(t *testing.T) {
525+
// Endpoint with no jsonPath and no folder should still pass validation
526+
// (jsonPath check is only for non-empty jsonPath)
527+
cfg := Config{
528+
Endpoints: []Endpoint{
529+
{Method: "POST", Path: "/webhook", Status: 200},
530+
},
531+
}
532+
533+
err := cfg.Validate()
534+
assert.NoError(t, err)
535+
}

0 commit comments

Comments
 (0)