package smartconfig import ( "testing" ) func TestGjsonPathEdgeCasesRefactored(t *testing.T) { config := loadConfig(t, ` empty_string: "" null_value: null zero: 0 false_bool: false empty_map: {} empty_array: [] special_keys: "key.with.dots": "dotted key value" "key with spaces": "spaced key value" "key[with]brackets": "bracketed key value" "123": "numeric key" "": "empty key" deeply: nested: structure: with: many: levels: value: "deep value" arrays: nested: - - - value: "triple nested array" mixed: - name: "first" items: - id: 1 - id: 2 - name: "second" items: - id: 3 - id: 4 types: very_large_number: 9223372036854775807 very_small_number: -9223372036854775808 special_values: inf: .inf neg_inf: -.inf nan: .nan `) t.Run("Empty and null values", func(t *testing.T) { // Empty string val, err := config.GetString("empty_string") assertNoError(t, err) assertString(t, val, "") // Zero value zero, err := config.GetInt("zero") assertNoError(t, err) assertInt(t, zero, 0) // False boolean falseBool, err := config.GetBool("false_bool") assertNoError(t, err) assertBool(t, falseBool, false) // Null value should fail for typed getters _, err = config.GetString("null_value") assertError(t, err) _, err = config.GetInt("null_value") assertError(t, err) _, err = config.GetBool("null_value") assertError(t, err) }) t.Run("Empty collections", func(t *testing.T) { // Empty map emptyMap, exists := config.Get("empty_map") assertExists(t, exists) m := assertType[map[string]interface{}](t, emptyMap) if len(m) != 0 { t.Errorf("empty_map should have 0 elements, has %d", len(m)) } // Empty array emptyArray, exists := config.Get("empty_array") assertExists(t, exists) a := assertType[[]interface{}](t, emptyArray) if len(a) != 0 { t.Errorf("empty_array should have 0 elements, has %d", len(a)) } }) t.Run("Deep nesting", func(t *testing.T) { deepValue, err := config.GetString("deeply.nested.structure.with.many.levels.value") assertNoError(t, err) assertString(t, deepValue, "deep value") }) t.Run("Complex arrays", func(t *testing.T) { // Triple nested array val, err := config.GetString("arrays.nested.0.0.0.value") assertNoError(t, err) assertString(t, val, "triple nested array") // Mixed structure navigation id1, err := config.GetInt("arrays.mixed.0.items.0.id") assertNoError(t, err) assertInt(t, id1, 1) id4, err := config.GetInt("arrays.mixed.1.items.1.id") assertNoError(t, err) assertInt(t, id4, 4) }) t.Run("Large numbers", func(t *testing.T) { largeNum, err := config.GetInt("types.very_large_number") assertNoError(t, err) assertInt(t, largeNum, 9223372036854775807) smallNum, err := config.GetInt("types.very_small_number") assertNoError(t, err) assertInt(t, smallNum, -9223372036854775808) }) t.Run("Special float values", func(t *testing.T) { // These special float values should be converted to strings inf, err := config.GetString("special_values.inf") assertNoError(t, err) assertString(t, inf, "Infinity") negInf, err := config.GetString("special_values.neg_inf") assertNoError(t, err) assertString(t, negInf, "-Infinity") nan, err := config.GetString("special_values.nan") assertNoError(t, err) assertString(t, nan, "NaN") }) t.Run("Non-existent paths", func(t *testing.T) { paths := []string{ "nonexistent", "nonexistent.nested.key", "deeply.nonexistent", "arrays.mixed.999.name", "arrays.mixed.-1.name", } for _, path := range paths { t.Run(path, func(t *testing.T) { _, err := config.GetString(path) assertError(t, err) _, err = config.GetInt(path) assertError(t, err) _, exists := config.Get(path) assertNotExists(t, exists) }) } }) t.Run("Invalid path syntax", func(t *testing.T) { // These paths have invalid syntax paths := []string{ "", // Empty path "...", // Only dots "key.", // Trailing dot ".key", // Leading dot "key..value", // Double dots } for _, path := range paths { t.Run(path, func(t *testing.T) { _, err := config.GetString(path) assertError(t, err) _, exists := config.Get(path) assertNotExists(t, exists) }) } }) } func TestTypeConversions(t *testing.T) { config := loadConfig(t, ` string_number: "123" string_bool: "true" string_float: "45.67" string_bytes: "1GB" not_a_number: "abc" not_a_bool: "yes" partial_number: "123abc" object: key: value array: - item1 - item2 `) t.Run("Valid conversions", func(t *testing.T) { // String to int num, err := config.GetInt("string_number") assertNoError(t, err) assertInt(t, num, 123) // String to bool b, err := config.GetBool("string_bool") assertNoError(t, err) assertBool(t, b, true) // String to float f, err := config.GetFloat("string_float") assertNoError(t, err) assertFloat(t, f, 45.67) // String to bytes bytes, err := config.GetBytes("string_bytes") assertNoError(t, err) assertUint64(t, bytes, 1000000000) // 1GB in decimal }) t.Run("Invalid conversions", func(t *testing.T) { // Invalid string to int _, err := config.GetInt("not_a_number") assertError(t, err) // Invalid string to bool _, err = config.GetBool("not_a_bool") assertError(t, err) // Partial number _, err = config.GetInt("partial_number") assertError(t, err) // Object as string (should fail) _, err = config.GetString("object") assertError(t, err) // Array as int (should fail) _, err = config.GetInt("array") assertError(t, err) }) } func TestConcurrentAccess(t *testing.T) { config := loadConfig(t, ` concurrent: value1: "test1" value2: "test2" nested: value3: "test3" `) // Run multiple goroutines accessing the config done := make(chan bool, 10) for i := 0; i < 10; i++ { go func(id int) { for j := 0; j < 100; j++ { switch id % 3 { case 0: val, err := config.GetString("concurrent.value1") if err != nil || val != "test1" { t.Errorf("concurrent access failed: %v, %v", val, err) } case 1: val, err := config.GetString("concurrent.value2") if err != nil || val != "test2" { t.Errorf("concurrent access failed: %v, %v", val, err) } case 2: val, err := config.GetString("concurrent.nested.value3") if err != nil || val != "test3" { t.Errorf("concurrent access failed: %v, %v", val, err) } } } done <- true }(i) } // Wait for all goroutines for i := 0; i < 10; i++ { <-done } }