Add path data to the selected nodes for reconstruction via set

This commit is contained in:
2025-03-25 16:50:42 +01:00
parent 396992b3d0
commit 20bab894e3
4 changed files with 515 additions and 237 deletions

View File

@@ -5,12 +5,12 @@ import (
"testing"
)
func TestGet(t *testing.T) {
func TestGetWithPathsBasic(t *testing.T) {
tests := []struct {
name string
data map[string]interface{}
path string
expected []interface{}
expected []JSONNode
}{
{
name: "simple property",
@@ -18,8 +18,10 @@ func TestGet(t *testing.T) {
"name": "John",
"age": 30,
},
path: "$.name",
expected: []interface{}{"John"},
path: "$.name",
expected: []JSONNode{
{Value: "John", Path: "$.name"},
},
},
{
name: "nested property",
@@ -29,8 +31,10 @@ func TestGet(t *testing.T) {
"age": 30,
},
},
path: "$.user.name",
expected: []interface{}{"John"},
path: "$.user.name",
expected: []JSONNode{
{Value: "John", Path: "$.user.name"},
},
},
{
name: "array access",
@@ -40,8 +44,10 @@ func TestGet(t *testing.T) {
map[string]interface{}{"name": "Jane", "age": 25},
},
},
path: "$.users[1].name",
expected: []interface{}{"Jane"},
path: "$.users[1].name",
expected: []JSONNode{
{Value: "Jane", Path: "$.users[1].name"},
},
},
{
name: "wildcard",
@@ -51,8 +57,11 @@ func TestGet(t *testing.T) {
map[string]interface{}{"name": "Jane", "age": 25},
},
},
path: "$.users[*].name",
expected: []interface{}{"John", "Jane"},
path: "$.users[*].name",
expected: []JSONNode{
{Value: "John", Path: "$.users[0].name"},
{Value: "Jane", Path: "$.users[1].name"},
},
},
{
name: "recursive descent",
@@ -67,8 +76,11 @@ func TestGet(t *testing.T) {
"email": "admin@example.com",
},
},
path: "$..email",
expected: []interface{}{"john@example.com", "admin@example.com"},
path: "$..email",
expected: []JSONNode{
{Value: "john@example.com", Path: "$.user.profile.email"},
{Value: "admin@example.com", Path: "$.admin.email"},
},
},
{
name: "nonexistent path",
@@ -78,7 +90,7 @@ func TestGet(t *testing.T) {
},
},
path: "$.user.email",
expected: nil,
expected: []JSONNode{},
},
}
@@ -86,36 +98,44 @@ func TestGet(t *testing.T) {
t.Run(tt.name, func(t *testing.T) {
result := Get(tt.data, tt.path)
// For nonexistent path, we expect either nil or empty slice
// For nonexistent path, we expect empty slice
if tt.name == "nonexistent path" {
if len(result) > 0 {
t.Errorf("Get() returned %v, expected empty result", result)
t.Errorf("GetWithPaths() 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))
t.Errorf("GetWithPaths() 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)
// For each expected item, check if it exists in the results by both value and path
for _, expected := range tt.expected {
found := false
for _, r := range result {
if reflect.DeepEqual(r.Value, expected.Value) && r.Path == expected.Path {
found = true
break
}
}
if !found {
t.Errorf("GetWithPaths() missing expected value: %v with path: %s", expected.Value, expected.Path)
}
}
} else {
// Otherwise check exact equality
if !reflect.DeepEqual(result, tt.expected) {
t.Errorf("Get() = %v, expected %v", result, tt.expected)
// Otherwise check exact equality of both values and paths
for i, expected := range tt.expected {
if !reflect.DeepEqual(result[i].Value, expected.Value) {
t.Errorf("GetWithPaths() value at [%d] = %v, expected %v", i, result[i].Value, expected.Value)
}
if result[i].Path != expected.Path {
t.Errorf("GetWithPaths() path at [%d] = %s, expected %s", i, result[i].Path, expected.Path)
}
}
}
})
@@ -430,3 +450,114 @@ func TestSetAll(t *testing.T) {
}
})
}
func TestGetWithPathsExtended(t *testing.T) {
tests := []struct {
name string
data map[string]interface{}
path string
expected []JSONNode
}{
{
name: "simple property",
data: map[string]interface{}{
"name": "John",
"age": 30,
},
path: "$.name",
expected: []JSONNode{
{Value: "John", Path: "$.name"},
},
},
{
name: "nested property",
data: map[string]interface{}{
"user": map[string]interface{}{
"name": "John",
"age": 30,
},
},
path: "$.user.name",
expected: []JSONNode{
{Value: "John", Path: "$.user.name"},
},
},
{
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: []JSONNode{
{Value: "Jane", Path: "$.users[1].name"},
},
},
{
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: []JSONNode{
{Value: "John", Path: "$.users[0].name"},
{Value: "Jane", Path: "$.users[1].name"},
},
},
{
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: []JSONNode{
{Value: "john@example.com", Path: "$.user.profile.email"},
{Value: "admin@example.com", Path: "$.admin.email"},
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
result := Get(tt.data, tt.path)
// Check if lengths match
if len(result) != len(tt.expected) {
t.Errorf("GetWithPaths() returned %d items, expected %d", len(result), len(tt.expected))
return
}
// For each expected item, find its match in the results and verify both value and path
for _, expected := range tt.expected {
found := false
for _, r := range result {
// Check if value matches
if reflect.DeepEqual(r.Value, expected.Value) {
found = true
// Check if path matches
if r.Path != expected.Path {
t.Errorf("Path mismatch for value %v: got %s, expected %s", r.Value, r.Path, expected.Path)
}
break
}
}
if !found {
t.Errorf("Expected node with value %v and path %s not found in results", expected.Value, expected.Path)
}
}
})
}
}