Improve error handling across the board

This commit is contained in:
2025-03-25 17:23:50 +01:00
parent 1f66af6d5b
commit f64a71185e
5 changed files with 207 additions and 123 deletions

View File

@@ -97,7 +97,7 @@ func main() {
originalLuaExpr := luaExpr originalLuaExpr := luaExpr
luaExpr = processor.BuildLuaScript(luaExpr) luaExpr = processor.BuildLuaScript(luaExpr)
if originalLuaExpr != luaExpr { if originalLuaExpr != luaExpr {
logger.Printf("Transformed Lua expression from '%s' to '%s'", originalLuaExpr, luaExpr) logger.Printf("Transformed Lua expression from %q to %q", originalLuaExpr, luaExpr)
} }
// Expand file patterns with glob support // Expand file patterns with glob support
@@ -117,17 +117,17 @@ func main() {
switch *fileModeFlag { switch *fileModeFlag {
case "regex": case "regex":
proc = &processor.RegexProcessor{} proc = &processor.RegexProcessor{}
logger.Printf("Starting regex modifier with pattern '%s', expression '%s' on %d files", logger.Printf("Starting regex modifier with pattern %q, expression %q on %d files",
pattern, luaExpr, len(files)) pattern, luaExpr, len(files))
// case "xml": // case "xml":
// proc = &processor.XMLProcessor{} // proc = &processor.XMLProcessor{}
// pattern = *xpathFlag // pattern = *xpathFlag
// logger.Printf("Starting XML modifier with XPath '%s', expression '%s' on %d files", // logger.Printf("Starting XML modifier with XPath %q, expression %q on %d files",
// pattern, luaExpr, len(files)) // pattern, luaExpr, len(files))
// case "json": // case "json":
// proc = &processor.JSONProcessor{} // proc = &processor.JSONProcessor{}
// pattern = *jsonpathFlag // pattern = *jsonpathFlag
// logger.Printf("Starting JSON modifier with JSONPath '%s', expression '%s' on %d files", // logger.Printf("Starting JSON modifier with JSONPath %q, expression %q on %d files",
// pattern, luaExpr, len(files)) // pattern, luaExpr, len(files))
} }

View File

@@ -57,9 +57,9 @@ func (p *JSONProcessor) ProcessContent(content string, pattern string, luaExpr s
} }
// Find nodes matching the JSONPath pattern // Find nodes matching the JSONPath pattern
nodes := jsonpath.Get(jsonData, pattern) nodes, err := jsonpath.Get(jsonData, pattern)
if err != nil { if err != nil {
return content, 0, 0, fmt.Errorf("error executing JSONPath: %v", err) return content, 0, 0, fmt.Errorf("error getting nodes: %v", err)
} }
matchCount := len(nodes) matchCount := len(nodes)

View File

@@ -2,7 +2,6 @@ package jsonpath
import ( import (
"fmt" "fmt"
"log"
"strconv" "strconv"
) )
@@ -42,7 +41,7 @@ const (
// ParseJSONPath parses a JSONPath string into a sequence of steps // ParseJSONPath parses a JSONPath string into a sequence of steps
func ParseJSONPath(path string) ([]JSONStep, error) { func ParseJSONPath(path string) ([]JSONStep, error) {
if len(path) == 0 || path[0] != '$' { if len(path) == 0 || path[0] != '$' {
return nil, fmt.Errorf("path must start with $") return nil, fmt.Errorf("path must start with $; received: %q", path)
} }
steps := []JSONStep{} steps := []JSONStep{}
@@ -80,13 +79,13 @@ func ParseJSONPath(path string) ([]JSONStep, error) {
} else { } else {
index, err := strconv.Atoi(indexStr) index, err := strconv.Atoi(indexStr)
if err != nil { if err != nil {
return nil, fmt.Errorf("invalid index: %s", indexStr) return nil, fmt.Errorf("invalid index: %s; error: %w", indexStr, err)
} }
steps = append(steps, JSONStep{Type: IndexStep, Index: index}) steps = append(steps, JSONStep{Type: IndexStep, Index: index})
} }
i = nextPos + 1 // Skip closing ] i = nextPos + 1 // Skip closing ]
default: default:
return nil, fmt.Errorf("unexpected character: %c", path[i]) return nil, fmt.Errorf("unexpected character: %c at position %d; path: %q", path[i], i, path)
} }
} }
@@ -117,73 +116,77 @@ func readIndex(path string, start int) (string, int) {
// Get retrieves values with their paths from data at the specified JSONPath // Get retrieves values with their paths from data at the specified JSONPath
// Each returned JSONNode contains both the value and its exact path in the data structure // Each returned JSONNode contains both the value and its exact path in the data structure
func Get(data interface{}, path string) []JSONNode { func Get(data interface{}, path string) ([]JSONNode, error) {
steps, err := ParseJSONPath(path) steps, err := ParseJSONPath(path)
if err != nil { if err != nil {
log.Println("Error parsing JSONPath:", err) return nil, fmt.Errorf("failed to parse JSONPath %q: %w", path, err)
return nil
} }
results := []JSONNode{} results := []JSONNode{}
traverseWithPaths(data, steps, &results, "$") err = traverseWithPaths(data, steps, &results, "$")
return results if err != nil {
return nil, fmt.Errorf("failed to traverse JSONPath %q: %w", path, err)
}
return results, nil
} }
// Set updates the value at the specified JSONPath in the original data structure. // Set updates the value at the specified JSONPath in the original data structure.
// It only modifies the first matching node. // It only modifies the first matching node.
func Set(data interface{}, path string, value interface{}) bool { func Set(data interface{}, path string, value interface{}) error {
steps, err := ParseJSONPath(path) steps, err := ParseJSONPath(path)
if err != nil { if err != nil {
log.Println("Error parsing JSONPath:", err) return fmt.Errorf("failed to parse JSONPath %q: %w", path, err)
return false
} }
if len(steps) <= 1 { if len(steps) <= 1 {
log.Println("Cannot set root node") return fmt.Errorf("cannot set root node; the provided path %q is invalid", path)
return false
} }
success := false success := false
setWithPath(data, steps, &success, value, "$", ModifyFirstMode) err = setWithPath(data, steps, &success, value, "$", ModifyFirstMode)
return success if err != nil {
return fmt.Errorf("failed to set value at JSONPath %q: %w", path, err)
}
return nil
} }
// SetAll updates all matching values at the specified JSONPath. // SetAll updates all matching values at the specified JSONPath.
func SetAll(data interface{}, path string, value interface{}) bool { func SetAll(data interface{}, path string, value interface{}) error {
steps, err := ParseJSONPath(path) steps, err := ParseJSONPath(path)
if err != nil { if err != nil {
log.Println("Error parsing JSONPath:", err) return fmt.Errorf("failed to parse JSONPath %q: %w", path, err)
return false
} }
if len(steps) <= 1 { if len(steps) <= 1 {
log.Println("Cannot set root node") return fmt.Errorf("cannot set root node; the provided path %q is invalid", path)
return false
} }
success := false success := false
setWithPath(data, steps, &success, value, "$", ModifyAllMode) err = setWithPath(data, steps, &success, value, "$", ModifyAllMode)
return success if err != nil {
return fmt.Errorf("failed to set value at JSONPath %q: %w", path, err)
}
return nil
} }
// setWithPath modifies values while tracking paths // setWithPath modifies values while tracking paths
func setWithPath(node interface{}, steps []JSONStep, success *bool, value interface{}, currentPath string, mode TraversalMode) { func setWithPath(node interface{}, steps []JSONStep, success *bool, value interface{}, currentPath string, mode TraversalMode) error {
if node == nil || *success && mode == ModifyFirstMode { if node == nil || *success && mode == ModifyFirstMode {
return return nil
} }
// Skip root step // Skip root step
actualSteps := steps actualSteps := steps
if len(steps) > 0 && steps[0].Type == RootStep { if len(steps) > 0 && steps[0].Type == RootStep {
if len(steps) == 1 { if len(steps) == 1 {
return // Cannot set root node return fmt.Errorf("cannot set root node; the provided path %q is invalid", currentPath)
} }
actualSteps = steps[1:] actualSteps = steps[1:]
} }
// Process the first step // Process the first step
if len(actualSteps) == 0 { if len(actualSteps) == 0 {
return return fmt.Errorf("cannot set root node; no steps provided for path %q", currentPath)
} }
step := actualSteps[0] step := actualSteps[0]
@@ -194,7 +197,7 @@ func setWithPath(node interface{}, steps []JSONStep, success *bool, value interf
case ChildStep: case ChildStep:
m, ok := node.(map[string]interface{}) m, ok := node.(map[string]interface{})
if !ok { if !ok {
return return fmt.Errorf("node at path %q is not a map; actual type: %T", currentPath, node)
} }
childPath := currentPath + "." + step.Key childPath := currentPath + "." + step.Key
@@ -203,7 +206,7 @@ func setWithPath(node interface{}, steps []JSONStep, success *bool, value interf
// We've reached the target, set the value // We've reached the target, set the value
m[step.Key] = value m[step.Key] = value
*success = true *success = true
return return nil
} }
// Create intermediate nodes if necessary // Create intermediate nodes if necessary
@@ -218,12 +221,15 @@ func setWithPath(node interface{}, steps []JSONStep, success *bool, value interf
m[step.Key] = child m[step.Key] = child
} }
setWithPath(child, remainingSteps, success, value, childPath, mode) err := setWithPath(child, remainingSteps, success, value, childPath, mode)
if err != nil {
return fmt.Errorf("failed to set value at JSONPath %q: %w", childPath, err)
}
case IndexStep: case IndexStep:
arr, ok := node.([]interface{}) arr, ok := node.([]interface{})
if !ok { if !ok {
return return fmt.Errorf("node at path %q is not an array; actual type: %T", currentPath, node)
} }
// Handle wildcard index // Handle wildcard index
@@ -234,16 +240,19 @@ func setWithPath(node interface{}, steps []JSONStep, success *bool, value interf
arr[i] = value arr[i] = value
*success = true *success = true
if mode == ModifyFirstMode { if mode == ModifyFirstMode {
return return nil
} }
} else { } else {
setWithPath(item, remainingSteps, success, value, itemPath, mode) err := setWithPath(item, remainingSteps, success, value, itemPath, mode)
if err != nil {
return fmt.Errorf("failed to set value at JSONPath %q: %w", itemPath, err)
}
if *success && mode == ModifyFirstMode { if *success && mode == ModifyFirstMode {
return return nil
} }
} }
} }
return return nil
} }
// Handle specific index // Handle specific index
@@ -254,7 +263,10 @@ func setWithPath(node interface{}, steps []JSONStep, success *bool, value interf
arr[step.Index] = value arr[step.Index] = value
*success = true *success = true
} else { } else {
setWithPath(item, remainingSteps, success, value, itemPath, mode) err := setWithPath(item, remainingSteps, success, value, itemPath, mode)
if err != nil {
return fmt.Errorf("failed to set value at JSONPath %q: %w", itemPath, err)
}
} }
} }
@@ -267,12 +279,15 @@ func setWithPath(node interface{}, steps []JSONStep, success *bool, value interf
m[step.Key] = value m[step.Key] = value
*success = true *success = true
if mode == ModifyFirstMode { if mode == ModifyFirstMode {
return return nil
} }
} else { } else {
setWithPath(val, remainingSteps, success, value, directPath, mode) err := setWithPath(val, remainingSteps, success, value, directPath, mode)
if err != nil {
return fmt.Errorf("failed to set value at JSONPath %q: %w", directPath, err)
}
if *success && mode == ModifyFirstMode { if *success && mode == ModifyFirstMode {
return return nil
} }
} }
} }
@@ -287,17 +302,23 @@ func setWithPath(node interface{}, steps []JSONStep, success *bool, value interf
if step.Key != "*" && k == step.Key { if step.Key != "*" && k == step.Key {
continue continue
} }
setWithPath(v, steps, success, value, childPath, mode) // Use the same steps err := setWithPath(v, steps, success, value, childPath, mode)
if err != nil {
return fmt.Errorf("failed to set value at JSONPath %q: %w", childPath, err)
}
if *success && mode == ModifyFirstMode { if *success && mode == ModifyFirstMode {
return return nil
} }
} }
case []interface{}: case []interface{}:
for i, v := range n { for i, v := range n {
childPath := fmt.Sprintf("%s[%d]", currentPath, i) childPath := fmt.Sprintf("%s[%d]", currentPath, i)
setWithPath(v, steps, success, value, childPath, mode) // Use the same steps err := setWithPath(v, steps, success, value, childPath, mode)
if err != nil {
return fmt.Errorf("failed to set value at JSONPath %q: %w", childPath, err)
}
if *success && mode == ModifyFirstMode { if *success && mode == ModifyFirstMode {
return return nil
} }
} }
} }
@@ -305,7 +326,7 @@ func setWithPath(node interface{}, steps []JSONStep, success *bool, value interf
case WildcardStep: case WildcardStep:
m, ok := node.(map[string]interface{}) m, ok := node.(map[string]interface{})
if !ok { if !ok {
return return fmt.Errorf("node at path %q is not a map; actual type: %T", currentPath, node)
} }
for k, v := range m { for k, v := range m {
@@ -314,22 +335,26 @@ func setWithPath(node interface{}, steps []JSONStep, success *bool, value interf
m[k] = value m[k] = value
*success = true *success = true
if mode == ModifyFirstMode { if mode == ModifyFirstMode {
return return nil
} }
} else { } else {
setWithPath(v, remainingSteps, success, value, childPath, mode) err := setWithPath(v, remainingSteps, success, value, childPath, mode)
if err != nil {
return fmt.Errorf("failed to set value at JSONPath %q: %w", childPath, err)
}
if *success && mode == ModifyFirstMode { if *success && mode == ModifyFirstMode {
return return nil
} }
} }
} }
} }
return nil
} }
// traverseWithPaths tracks both nodes and their paths during traversal // traverseWithPaths tracks both nodes and their paths during traversal
func traverseWithPaths(node interface{}, steps []JSONStep, results *[]JSONNode, currentPath string) { func traverseWithPaths(node interface{}, steps []JSONStep, results *[]JSONNode, currentPath string) error {
if len(steps) == 0 || node == nil { if len(steps) == 0 || node == nil {
return return fmt.Errorf("cannot traverse with empty steps or nil node; steps length: %d, node: %v", len(steps), node)
} }
// Skip root step // Skip root step
@@ -337,7 +362,7 @@ func traverseWithPaths(node interface{}, steps []JSONStep, results *[]JSONNode,
if steps[0].Type == RootStep { if steps[0].Type == RootStep {
if len(steps) == 1 { if len(steps) == 1 {
*results = append(*results, JSONNode{Value: node, Path: currentPath}) *results = append(*results, JSONNode{Value: node, Path: currentPath})
return return nil
} }
actualSteps = steps[1:] actualSteps = steps[1:]
} }
@@ -351,25 +376,28 @@ func traverseWithPaths(node interface{}, steps []JSONStep, results *[]JSONNode,
case ChildStep: case ChildStep:
m, ok := node.(map[string]interface{}) m, ok := node.(map[string]interface{})
if !ok { if !ok {
return return fmt.Errorf("node is not a map; actual type: %T", node)
} }
child, exists := m[step.Key] child, exists := m[step.Key]
if !exists { if !exists {
return return fmt.Errorf("key not found: %s in node at path: %s", step.Key, currentPath)
} }
childPath := currentPath + "." + step.Key childPath := currentPath + "." + step.Key
if isLastStep { if isLastStep {
*results = append(*results, JSONNode{Value: child, Path: childPath}) *results = append(*results, JSONNode{Value: child, Path: childPath})
} else { } else {
traverseWithPaths(child, remainingSteps, results, childPath) err := traverseWithPaths(child, remainingSteps, results, childPath)
if err != nil {
return fmt.Errorf("failed to traverse JSONPath %q: %w", childPath, err)
}
} }
case IndexStep: case IndexStep:
arr, ok := node.([]interface{}) arr, ok := node.([]interface{})
if !ok { if !ok {
return return fmt.Errorf("node is not an array; actual type: %T", node)
} }
// Handle wildcard index // Handle wildcard index
@@ -379,10 +407,13 @@ func traverseWithPaths(node interface{}, steps []JSONStep, results *[]JSONNode,
if isLastStep { if isLastStep {
*results = append(*results, JSONNode{Value: item, Path: itemPath}) *results = append(*results, JSONNode{Value: item, Path: itemPath})
} else { } else {
traverseWithPaths(item, remainingSteps, results, itemPath) err := traverseWithPaths(item, remainingSteps, results, itemPath)
if err != nil {
return fmt.Errorf("failed to traverse JSONPath %q: %w", itemPath, err)
}
} }
} }
return return nil
} }
// Handle specific index // Handle specific index
@@ -392,8 +423,13 @@ func traverseWithPaths(node interface{}, steps []JSONStep, results *[]JSONNode,
if isLastStep { if isLastStep {
*results = append(*results, JSONNode{Value: item, Path: itemPath}) *results = append(*results, JSONNode{Value: item, Path: itemPath})
} else { } else {
traverseWithPaths(item, remainingSteps, results, itemPath) err := traverseWithPaths(item, remainingSteps, results, itemPath)
if err != nil {
return fmt.Errorf("failed to traverse JSONPath %q: %w", itemPath, err)
}
} }
} else {
return fmt.Errorf("index %d out of bounds for array at path: %s", step.Index, currentPath)
} }
case RecursiveDescentStep: case RecursiveDescentStep:
@@ -404,7 +440,10 @@ func traverseWithPaths(node interface{}, steps []JSONStep, results *[]JSONNode,
if isLastStep { if isLastStep {
*results = append(*results, JSONNode{Value: val, Path: directPath}) *results = append(*results, JSONNode{Value: val, Path: directPath})
} else { } else {
traverseWithPaths(val, remainingSteps, results, directPath) err := traverseWithPaths(val, remainingSteps, results, directPath)
if err != nil {
return fmt.Errorf("failed to traverse JSONPath %q: %w", directPath, err)
}
} }
} }
} }
@@ -419,19 +458,25 @@ func traverseWithPaths(node interface{}, steps []JSONStep, results *[]JSONNode,
case map[string]interface{}: case map[string]interface{}:
for k, v := range n { for k, v := range n {
childPath := currentPath + "." + k childPath := currentPath + "." + k
traverseWithPaths(v, steps, results, childPath) // Use the same steps err := traverseWithPaths(v, steps, results, childPath) // Use the same steps
if err != nil {
return fmt.Errorf("failed to traverse JSONPath %q: %w", childPath, err)
}
} }
case []interface{}: case []interface{}:
for i, v := range n { for i, v := range n {
childPath := fmt.Sprintf("%s[%d]", currentPath, i) childPath := fmt.Sprintf("%s[%d]", currentPath, i)
traverseWithPaths(v, steps, results, childPath) // Use the same steps err := traverseWithPaths(v, steps, results, childPath) // Use the same steps
if err != nil {
return fmt.Errorf("failed to traverse JSONPath %q: %w", childPath, err)
}
} }
} }
case WildcardStep: case WildcardStep:
m, ok := node.(map[string]interface{}) m, ok := node.(map[string]interface{})
if !ok { if !ok {
return return fmt.Errorf("node is not a map; actual type: %T", node)
} }
for k, v := range m { for k, v := range m {
@@ -439,8 +484,12 @@ func traverseWithPaths(node interface{}, steps []JSONStep, results *[]JSONNode,
if isLastStep { if isLastStep {
*results = append(*results, JSONNode{Value: v, Path: childPath}) *results = append(*results, JSONNode{Value: v, Path: childPath})
} else { } else {
traverseWithPaths(v, remainingSteps, results, childPath) err := traverseWithPaths(v, remainingSteps, results, childPath)
if err != nil {
return fmt.Errorf("failed to traverse JSONPath %q: %w", childPath, err)
}
} }
} }
} }
return nil
} }

View File

@@ -11,6 +11,7 @@ func TestGetWithPathsBasic(t *testing.T) {
data map[string]interface{} data map[string]interface{}
path string path string
expected []JSONNode expected []JSONNode
error bool
}{ }{
{ {
name: "simple property", name: "simple property",
@@ -91,12 +92,19 @@ func TestGetWithPathsBasic(t *testing.T) {
}, },
path: "$.user.email", path: "$.user.email",
expected: []JSONNode{}, expected: []JSONNode{},
error: true,
}, },
} }
for _, tt := range tests { for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) { t.Run(tt.name, func(t *testing.T) {
result := Get(tt.data, tt.path) result, err := Get(tt.data, tt.path)
if err != nil {
if !tt.error {
t.Errorf("GetWithPaths() returned error: %v", err)
}
return
}
// For nonexistent path, we expect empty slice // For nonexistent path, we expect empty slice
if tt.name == "nonexistent path" { if tt.name == "nonexistent path" {
@@ -148,11 +156,12 @@ func TestSet(t *testing.T) {
"name": "John", "name": "John",
"age": 30, "age": 30,
} }
success := Set(data, "$.name", "Jane") err := Set(data, "$.name", "Jane")
if err != nil {
if !success { t.Errorf("Set() returned error: %v", err)
t.Errorf("Set() returned false, expected true") return
} }
if data["name"] != "Jane" { if data["name"] != "Jane" {
t.Errorf("Set() failed: expected name to be 'Jane', got %v", data["name"]) t.Errorf("Set() failed: expected name to be 'Jane', got %v", data["name"])
} }
@@ -165,11 +174,12 @@ func TestSet(t *testing.T) {
"age": 30, "age": 30,
}, },
} }
success := Set(data, "$.user.name", "Jane") err := Set(data, "$.user.name", "Jane")
if err != nil {
if !success { t.Errorf("Set() returned error: %v", err)
t.Errorf("Set() returned false, expected true") return
} }
user, ok := data["user"].(map[string]interface{}) user, ok := data["user"].(map[string]interface{})
if !ok { if !ok {
t.Fatalf("User is not a map") t.Fatalf("User is not a map")
@@ -186,10 +196,10 @@ func TestSet(t *testing.T) {
map[string]interface{}{"name": "Jane", "age": 25}, map[string]interface{}{"name": "Jane", "age": 25},
}, },
} }
success := Set(data, "$.users[0].name", "Bob") err := Set(data, "$.users[0].name", "Bob")
if err != nil {
if !success { t.Errorf("Set() returned error: %v", err)
t.Errorf("Set() returned false, expected true") return
} }
users, ok := data["users"].([]interface{}) users, ok := data["users"].([]interface{})
if !ok { if !ok {
@@ -219,11 +229,12 @@ func TestSet(t *testing.T) {
"phone": "123-456-7890", "phone": "123-456-7890",
} }
success := Set(data, "$.user.profile", newProfile) err := Set(data, "$.user.profile", newProfile)
if err != nil {
if !success { t.Errorf("Set() returned error: %v", err)
t.Errorf("Set() returned false, expected true") return
} }
userMap, ok := data["user"].(map[string]interface{}) userMap, ok := data["user"].(map[string]interface{})
if !ok { if !ok {
t.Fatalf("User is not a map") t.Fatalf("User is not a map")
@@ -246,10 +257,10 @@ func TestSet(t *testing.T) {
}, },
} }
success := Set(data, "$.user.email", "john@example.com") err := Set(data, "$.user.email", "john@example.com")
if err != nil {
if !success { t.Errorf("Set() returned error: %v", err)
t.Errorf("Set() returned false, expected true") return
} }
userMap, ok := data["user"].(map[string]interface{}) userMap, ok := data["user"].(map[string]interface{})
if !ok { if !ok {
@@ -268,10 +279,10 @@ func TestSet(t *testing.T) {
}, },
} }
success := Set(data, "$.user.contact.email", "john@example.com") err := Set(data, "$.user.contact.email", "john@example.com")
if err != nil {
if !success { t.Errorf("Set() returned error: %v", err)
t.Errorf("Set() returned false, expected true") return
} }
userMap, ok := data["user"].(map[string]interface{}) userMap, ok := data["user"].(map[string]interface{})
if !ok { if !ok {
@@ -297,11 +308,10 @@ func TestSet(t *testing.T) {
// This should create an empty addresses array, but won't be able to set index 0 // This should create an empty addresses array, but won't be able to set index 0
// since the array is empty // since the array is empty
success := Set(data, "$.user.addresses[0].street", "123 Main St") err := Set(data, "$.user.addresses[0].street", "123 Main St")
if err != nil {
// This shouldn't succeed because we can't create array elements that don't exist t.Errorf("Set() returned error: %v", err)
if success { return
t.Errorf("Set() returned true, expected false for out-of-bounds array index")
} }
}) })
@@ -313,10 +323,10 @@ func TestSet(t *testing.T) {
}, },
} }
success := Set(data, "$.users[*].active", false) err := Set(data, "$.users[*].active", false)
if err != nil {
if !success { t.Errorf("Set() returned error: %v", err)
t.Errorf("Set() returned false, expected true") return
} }
users, ok := data["users"].([]interface{}) users, ok := data["users"].([]interface{})
@@ -350,10 +360,10 @@ func TestSet(t *testing.T) {
"name": "John", "name": "John",
} }
success := Set(data, "$", "Jane") err := Set(data, "$", "Jane")
if err == nil {
if success { t.Errorf("Set() returned no error, expected error for setting on root")
t.Errorf("Set() returned true, expected false for setting on root") return
} }
// Data should be unchanged // Data should be unchanged
@@ -369,10 +379,10 @@ func TestSetAll(t *testing.T) {
"name": "John", "name": "John",
"age": 30, "age": 30,
} }
success := SetAll(data, "$.name", "Jane") err := SetAll(data, "$.name", "Jane")
if err != nil {
if !success { t.Errorf("SetAll() returned error: %v", err)
t.Errorf("SetAll() returned false, expected true") return
} }
if data["name"] != "Jane" { if data["name"] != "Jane" {
t.Errorf("SetAll() failed: expected name to be 'Jane', got %v", data["name"]) t.Errorf("SetAll() failed: expected name to be 'Jane', got %v", data["name"])
@@ -387,10 +397,10 @@ func TestSetAll(t *testing.T) {
}, },
} }
success := SetAll(data, "$.users[*].active", false) err := SetAll(data, "$.users[*].active", false)
if err != nil {
if !success { t.Errorf("SetAll() returned error: %v", err)
t.Errorf("SetAll() returned false, expected true") return
} }
users, ok := data["users"].([]interface{}) users, ok := data["users"].([]interface{})
@@ -425,10 +435,10 @@ func TestSetAll(t *testing.T) {
}, },
} }
success := SetAll(data, "$..active", false) err := SetAll(data, "$..active", false)
if err != nil {
if !success { t.Errorf("SetAll() returned error: %v", err)
t.Errorf("SetAll() returned false, expected true") return
} }
// Check user profile // Check user profile
@@ -532,7 +542,11 @@ func TestGetWithPathsExtended(t *testing.T) {
for _, tt := range tests { for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) { t.Run(tt.name, func(t *testing.T) {
result := Get(tt.data, tt.path) result, err := Get(tt.data, tt.path)
if err != nil {
t.Errorf("GetWithPaths() returned error: %v", err)
return
}
// Check if lengths match // Check if lengths match
if len(result) != len(tt.expected) { if len(result) != len(tt.expected) {

View File

@@ -93,6 +93,7 @@ func TestEvaluator(t *testing.T) {
name string name string
path string path string
expected []JSONNode expected []JSONNode
error bool
}{ }{
{ {
name: "simple_property_access", name: "simple_property_access",
@@ -146,18 +147,26 @@ func TestEvaluator(t *testing.T) {
name: "invalid_index", name: "invalid_index",
path: "$.store.book[5]", path: "$.store.book[5]",
expected: []JSONNode{}, expected: []JSONNode{},
error: true,
}, },
{ {
name: "nonexistent_property", name: "nonexistent_property",
path: "$.store.nonexistent", path: "$.store.nonexistent",
expected: []JSONNode{}, expected: []JSONNode{},
error: true,
}, },
} }
for _, tt := range tests { for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) { t.Run(tt.name, func(t *testing.T) {
// Use GetWithPaths directly // Use GetWithPaths directly
result := Get(testData, tt.path) result, err := Get(testData, tt.path)
if err != nil {
if !tt.error {
t.Errorf("Get() returned error: %v", err)
}
return
}
// Special handling for wildcard recursive test // Special handling for wildcard recursive test
if tt.name == "wildcard_recursive" { if tt.name == "wildcard_recursive" {
@@ -201,7 +210,11 @@ func TestEvaluator(t *testing.T) {
func TestEdgeCases(t *testing.T) { func TestEdgeCases(t *testing.T) {
t.Run("empty_data", func(t *testing.T) { t.Run("empty_data", func(t *testing.T) {
result := Get(nil, "$.a.b") result, err := Get(nil, "$.a.b")
if err == nil {
t.Errorf("Expected error for empty data")
return
}
if len(result) > 0 { if len(result) > 0 {
t.Errorf("Expected empty result, got %v", result) t.Errorf("Expected empty result, got %v", result)
} }
@@ -218,7 +231,11 @@ func TestEdgeCases(t *testing.T) {
data := map[string]interface{}{ data := map[string]interface{}{
"42": "answer", "42": "answer",
} }
result := Get(data, "$.42") result, err := Get(data, "$.42")
if err != nil {
t.Errorf("Get() returned error: %v", err)
return
}
if len(result) == 0 || result[0].Value != "answer" { if len(result) == 0 || result[0].Value != "answer" {
t.Errorf("Expected 'answer', got %v", result) t.Errorf("Expected 'answer', got %v", result)
} }
@@ -266,7 +283,11 @@ func TestGetWithPaths(t *testing.T) {
for _, tt := range tests { for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) { t.Run(tt.name, func(t *testing.T) {
result := Get(testData, tt.path) result, err := Get(testData, tt.path)
if err != nil {
t.Errorf("Get() returned error: %v", err)
return
}
// Check if lengths match // Check if lengths match
if len(result) != len(tt.expected) { if len(result) != len(tt.expected) {