package jsonpath import ( "reflect" "testing" ) func TestGet(t *testing.T) { tests := []struct { name string data map[string]interface{} path string expected []interface{} }{ { name: "simple property", data: map[string]interface{}{ "name": "John", "age": 30, }, path: "$.name", expected: []interface{}{"John"}, }, { name: "nested property", data: map[string]interface{}{ "user": map[string]interface{}{ "name": "John", "age": 30, }, }, path: "$.user.name", expected: []interface{}{"John"}, }, { name: "array access", data: map[string]interface{}{ "users": []interface{}{ map[string]interface{}{"name": "John", "age": 30}, map[string]interface{}{"name": "Jane", "age": 25}, }, }, path: "$.users[1].name", expected: []interface{}{"Jane"}, }, { name: "wildcard", data: map[string]interface{}{ "users": []interface{}{ map[string]interface{}{"name": "John", "age": 30}, map[string]interface{}{"name": "Jane", "age": 25}, }, }, path: "$.users[*].name", expected: []interface{}{"John", "Jane"}, }, { name: "recursive descent", data: map[string]interface{}{ "user": map[string]interface{}{ "name": "John", "profile": map[string]interface{}{ "email": "john@example.com", }, }, "admin": map[string]interface{}{ "email": "admin@example.com", }, }, path: "$..email", expected: []interface{}{"john@example.com", "admin@example.com"}, }, { name: "nonexistent path", data: map[string]interface{}{ "user": map[string]interface{}{ "name": "John", }, }, path: "$.user.email", expected: nil, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { result := Get(tt.data, tt.path) // For nonexistent path, we expect either nil or empty slice if tt.name == "nonexistent path" { if len(result) > 0 { t.Errorf("Get() returned %v, expected empty result", result) } return } // Check if lengths match if len(result) != len(tt.expected) { t.Errorf("Get() returned %d items, expected %d", len(result), len(tt.expected)) return } // For wildcard results, we need to check containment rather than exact order if tt.name == "wildcard" || tt.name == "recursive descent" { expectedMap := make(map[interface{}]bool) for _, v := range tt.expected { expectedMap[v] = true } for _, v := range result { if !expectedMap[v] { t.Errorf("Get() result contains unexpected value: %v", v) } } } else { // Otherwise check exact equality if !reflect.DeepEqual(result, tt.expected) { t.Errorf("Get() = %v, expected %v", result, tt.expected) } } }) } } func TestSet(t *testing.T) { t.Run("simple property", func(t *testing.T) { data := map[string]interface{}{ "name": "John", "age": 30, } success := Set(data, "$.name", "Jane") if !success { t.Errorf("Set() returned false, expected true") } if data["name"] != "Jane" { t.Errorf("Set() failed: expected name to be 'Jane', got %v", data["name"]) } }) t.Run("nested property", func(t *testing.T) { data := map[string]interface{}{ "user": map[string]interface{}{ "name": "John", "age": 30, }, } success := Set(data, "$.user.name", "Jane") if !success { t.Errorf("Set() returned false, expected true") } user, ok := data["user"].(map[string]interface{}) if !ok { t.Fatalf("User is not a map") } if user["name"] != "Jane" { t.Errorf("Set() failed: expected user.name to be 'Jane', got %v", user["name"]) } }) t.Run("array element", func(t *testing.T) { data := map[string]interface{}{ "users": []interface{}{ map[string]interface{}{"name": "John", "age": 30}, map[string]interface{}{"name": "Jane", "age": 25}, }, } success := Set(data, "$.users[0].name", "Bob") if !success { t.Errorf("Set() returned false, expected true") } users, ok := data["users"].([]interface{}) if !ok { t.Fatalf("Users is not a slice") } user0, ok := users[0].(map[string]interface{}) if !ok { t.Fatalf("User is not a map") } if user0["name"] != "Bob" { t.Errorf("Set() failed: expected users[0].name to be 'Bob', got %v", user0["name"]) } }) t.Run("complex value", func(t *testing.T) { data := map[string]interface{}{ "user": map[string]interface{}{ "name": "John", "profile": map[string]interface{}{ "email": "john@example.com", }, }, } newProfile := map[string]interface{}{ "email": "john.doe@example.com", "phone": "123-456-7890", } success := Set(data, "$.user.profile", newProfile) if !success { t.Errorf("Set() returned false, expected true") } userMap, ok := data["user"].(map[string]interface{}) if !ok { t.Fatalf("User is not a map") } profile, ok := userMap["profile"].(map[string]interface{}) if !ok { t.Fatalf("Profile is not a map") } if profile["email"] != "john.doe@example.com" || profile["phone"] != "123-456-7890" { t.Errorf("Set() failed: expected profile to be updated with new values") } }) t.Run("create new property", func(t *testing.T) { data := map[string]interface{}{ "user": map[string]interface{}{ "name": "John", }, } success := Set(data, "$.user.email", "john@example.com") if !success { t.Errorf("Set() returned false, expected true") } userMap, ok := data["user"].(map[string]interface{}) if !ok { t.Fatalf("User is not a map") } if email, exists := userMap["email"]; !exists || email != "john@example.com" { t.Errorf("Set() failed: expected user.email to be 'john@example.com', got %v", userMap["email"]) } }) t.Run("create nested properties", func(t *testing.T) { data := map[string]interface{}{ "user": map[string]interface{}{ "name": "John", }, } success := Set(data, "$.user.contact.email", "john@example.com") if !success { t.Errorf("Set() returned false, expected true") } userMap, ok := data["user"].(map[string]interface{}) if !ok { t.Fatalf("User is not a map") } contact, ok := userMap["contact"].(map[string]interface{}) if !ok { t.Fatalf("Contact is not a map") } if email, exists := contact["email"]; !exists || email != "john@example.com" { t.Errorf("Set() failed: expected user.contact.email to be 'john@example.com', got %v", contact["email"]) } }) t.Run("create array and element", func(t *testing.T) { data := map[string]interface{}{ "user": map[string]interface{}{ "name": "John", }, } // This should create an empty addresses array, but won't be able to set index 0 // since the array is empty success := Set(data, "$.user.addresses[0].street", "123 Main St") // This shouldn't succeed because we can't create array elements that don't exist if success { t.Errorf("Set() returned true, expected false for out-of-bounds array index") } }) t.Run("multiple targets (should only update first)", func(t *testing.T) { data := map[string]interface{}{ "users": []interface{}{ map[string]interface{}{"active": true}, map[string]interface{}{"active": true}, }, } success := Set(data, "$.users[*].active", false) if !success { t.Errorf("Set() returned false, expected true") } users, ok := data["users"].([]interface{}) if !ok { t.Fatalf("Users is not a slice") } user0, ok := users[0].(map[string]interface{}) if !ok { t.Fatalf("User0 is not a map") } user1, ok := users[1].(map[string]interface{}) if !ok { t.Fatalf("User1 is not a map") } // Only the first one should be changed if active, exists := user0["active"]; !exists || active != false { t.Errorf("Set() failed: expected users[0].active to be false, got %v", user0["active"]) } // The second one should remain unchanged if active, exists := user1["active"]; !exists || active != true { t.Errorf("Set() incorrectly modified users[1].active: expected true, got %v", user1["active"]) } }) t.Run("setting on root should fail", func(t *testing.T) { data := map[string]interface{}{ "name": "John", } success := Set(data, "$", "Jane") if success { t.Errorf("Set() returned true, expected false for setting on root") } // Data should be unchanged if data["name"] != "John" { t.Errorf("Data was modified when setting on root") } }) } func TestSetAll(t *testing.T) { t.Run("simple property", func(t *testing.T) { data := map[string]interface{}{ "name": "John", "age": 30, } success := SetAll(data, "$.name", "Jane") if !success { t.Errorf("SetAll() returned false, expected true") } if data["name"] != "Jane" { t.Errorf("SetAll() failed: expected name to be 'Jane', got %v", data["name"]) } }) t.Run("all array elements", func(t *testing.T) { data := map[string]interface{}{ "users": []interface{}{ map[string]interface{}{"active": true}, map[string]interface{}{"active": true}, }, } success := SetAll(data, "$.users[*].active", false) if !success { t.Errorf("SetAll() returned false, expected true") } users, ok := data["users"].([]interface{}) if !ok { t.Fatalf("Users is not a slice") } // Both elements should be updated for i, user := range users { userMap, ok := user.(map[string]interface{}) if !ok { t.Fatalf("User%d is not a map", i) } if active, exists := userMap["active"]; !exists || active != false { t.Errorf("SetAll() failed: expected users[%d].active to be false, got %v", i, userMap["active"]) } } }) t.Run("recursive descent", func(t *testing.T) { data := map[string]interface{}{ "user": map[string]interface{}{ "profile": map[string]interface{}{ "active": true, }, }, "admin": map[string]interface{}{ "profile": map[string]interface{}{ "active": true, }, }, } success := SetAll(data, "$..active", false) if !success { t.Errorf("SetAll() returned false, expected true") } // Check user profile userProfile, ok := data["user"].(map[string]interface{})["profile"].(map[string]interface{}) if !ok { t.Fatalf("Failed to access user.profile") } if active, exists := userProfile["active"]; !exists || active != false { t.Errorf("SetAll() didn't update user.profile.active, got: %v", active) } // Check admin profile adminProfile, ok := data["admin"].(map[string]interface{})["profile"].(map[string]interface{}) if !ok { t.Fatalf("Failed to access admin.profile") } if active, exists := adminProfile["active"]; !exists || active != false { t.Errorf("SetAll() didn't update admin.profile.active, got: %v", active) } }) }