package jsonpath import ( "reflect" "testing" ) var testData = map[string]interface{}{ "store": map[string]interface{}{ "book": []interface{}{ map[string]interface{}{ "title": "The Fellowship of the Ring", "price": 22.99, }, map[string]interface{}{ "title": "The Two Towers", "price": 23.45, }, }, "bicycle": map[string]interface{}{ "color": "red", "price": 199.95, }, }, } func TestParser(t *testing.T) { tests := []struct { path string steps []JSONStep wantErr bool }{ { path: "$.store.bicycle.color", steps: []JSONStep{ {Type: RootStep}, {Type: ChildStep, Key: "store"}, {Type: ChildStep, Key: "bicycle"}, {Type: ChildStep, Key: "color"}, }, }, { path: "$..price", steps: []JSONStep{ {Type: RootStep}, {Type: RecursiveDescentStep, Key: "price"}, }, }, { path: "$.store.book[*].title", steps: []JSONStep{ {Type: RootStep}, {Type: ChildStep, Key: "store"}, {Type: ChildStep, Key: "book"}, {Type: IndexStep, Index: -1}, // Wildcard {Type: ChildStep, Key: "title"}, }, }, { path: "$.store.book[0]", steps: []JSONStep{ {Type: RootStep}, {Type: ChildStep, Key: "store"}, {Type: ChildStep, Key: "book"}, {Type: IndexStep, Index: 0}, }, }, { path: "invalid.path", wantErr: true, }, { path: "$.store.book[abc]", wantErr: true, }, } for _, tt := range tests { t.Run(tt.path, func(t *testing.T) { steps, err := ParseJSONPath(tt.path) if (err != nil) != tt.wantErr { t.Fatalf("ParseJSONPath() error = %v, wantErr %v", err, tt.wantErr) } if !tt.wantErr && !reflect.DeepEqual(steps, tt.steps) { t.Errorf("ParseJSONPath() steps = %+v, want %+v", steps, tt.steps) } }) } } func TestEvaluator(t *testing.T) { tests := []struct { name string path string expected []interface{} }{ { name: "simple_property_access", path: "$.store.bicycle.color", expected: []interface{}{"red"}, }, { name: "array_index_access", path: "$.store.book[0].title", expected: []interface{}{"The Fellowship of the Ring"}, }, { name: "wildcard_array_access", path: "$.store.book[*].title", expected: []interface{}{ "The Fellowship of the Ring", "The Two Towers", }, }, { name: "recursive_price_search", path: "$..price", expected: []interface{}{ 22.99, 23.45, 199.95, }, }, { name: "wildcard_recursive", path: "$..*", expected: []interface{}{ // testData["store"], // Root element // Store children testData["store"].(map[string]interface{})["book"], testData["store"].(map[string]interface{})["bicycle"], // Books testData["store"].(map[string]interface{})["book"].([]interface{})[0], testData["store"].(map[string]interface{})["book"].([]interface{})[1], // Book contents "The Fellowship of the Ring", 22.99, "The Two Towers", 23.45, // Bicycle testData["store"].(map[string]interface{})["bicycle"].(map[string]interface{})["color"], testData["store"].(map[string]interface{})["bicycle"].(map[string]interface{})["price"], "red", 199.95, }, }, { name: "invalid_index", path: "$.store.book[5]", expected: []interface{}{}, }, { name: "nonexistent_property", path: "$.store.nonexistent", expected: []interface{}{}, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { steps, err := ParseJSONPath(tt.path) if err != nil { t.Fatalf("Parse error: %v", err) } result := EvaluateJSONPath(testData, steps) // Special handling for wildcard recursive test if tt.name == "wildcard_recursive" { if len(result) != len(tt.expected) { t.Errorf("Expected %d items, got %d", len(tt.expected), len(result)) } return } if len(result) != len(tt.expected) { t.Errorf("Expected %d items, got %d", len(tt.expected), len(result)) } expectedSet := make(map[interface{}]bool, len(tt.expected)) for _, expected := range tt.expected { expectedSet[expected] = true } for _, resultItem := range result { if !expectedSet[resultItem] { t.Errorf("Expected %v, got %v", tt.expected, resultItem) } } // if !reflect.DeepEqual(result, tt.expected) { // t.Errorf("EvaluateJSONPath() = %v, want %v", result, tt.expected) // } }) } } func TestEdgeCases(t *testing.T) { t.Run("empty_data", func(t *testing.T) { steps, _ := ParseJSONPath("$.a.b") result := EvaluateJSONPath(nil, steps) if len(result) > 0 { t.Errorf("Expected empty result, got %v", result) } }) t.Run("empty_path", func(t *testing.T) { _, err := ParseJSONPath("") if err == nil { t.Error("Expected error for empty path") } }) t.Run("numeric_keys", func(t *testing.T) { data := map[string]interface{}{ "42": "answer", } steps, _ := ParseJSONPath("$.42") result := EvaluateJSONPath(data, steps) if result[0] != "answer" { t.Errorf("Expected 'answer', got %v", result) } }) }