@@ -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