diff --git a/mcdc_supplement_test.go b/mcdc_supplement_test.go index d5b8b54..c6944ea 100644 --- a/mcdc_supplement_test.go +++ b/mcdc_supplement_test.go @@ -338,16 +338,13 @@ func TestDeleteSupplementalEdgeCases(t *testing.T) { // MCDC SYS-REQ-009: N/A func TestSetSupplementalArrayInsertionCoverage(t *testing.T) { t.Run("append into existing top level array path", func(t *testing.T) { - // When setting an index beyond the current array length for a - // primitive (non-object) array, the code overwrites rather than - // appends because createInsertComponent with object=true wraps - // the value. This is the actual parser behavior. + // Setting an index beyond the current array length appends the value. got, err := Set([]byte(`{"top":[1]}`), []byte(`2`), "top", "[1]") if err != nil { t.Fatalf("Set array append returned error: %v", err) } - if string(got) != `{"top":[2]}` { - t.Fatalf("Set array append result = %s, want %s", string(got), `{"top":[2]}`) + if string(got) != `{"top":[1,2]}` { + t.Fatalf("Set array append result = %s, want %s", string(got), `{"top":[1,2]}`) } }) diff --git a/parser.go b/parser.go index d8df167..af6e35f 100644 --- a/parser.go +++ b/parser.go @@ -883,9 +883,12 @@ func Set(data []byte, setValue []byte, keys ...string) (value []byte, err error) depthOffset := endOffset if depth != 0 { // if subpath is a non-empty object, add to it - // or if subpath is a non-empty array, add to it - if (data[startOffset] == '{' && data[startOffset+1+nextToken(data[startOffset+1:])] != '}') || - (data[startOffset] == '[' && data[startOffset+1+nextToken(data[startOffset+1:])] == '{') && keys[depth:][0][0] == 91 { + // or if subpath is a non-empty array and next key is an index, append to it + nextInside := data[startOffset+1+nextToken(data[startOffset+1:])] + nextKeyIsIndex := len(keys[depth:]) > 0 && len(keys[depth:][0]) > 0 && keys[depth:][0][0] == '[' + canExtendObject := data[startOffset] == '{' && nextInside != '}' + canExtendArray := data[startOffset] == '[' && nextInside != ']' && nextKeyIsIndex + if canExtendObject || canExtendArray { depthOffset-- startOffset = depthOffset // otherwise, over-write it with a new object diff --git a/set_spec_test.go b/set_spec_test.go index 12fefd5..10f9b8e 100644 --- a/set_spec_test.go +++ b/set_spec_test.go @@ -52,3 +52,26 @@ func TestFuzzSetHarnessCoverage(t *testing.T) { t.Fatalf("expected FuzzSet failure path to return 0, got %d", got) } } + + +// Regression for issue #267: Set with successive array indexes must append scalars. +func TestSetAppendsScalarToExistingArrayByIndex(t *testing.T) { + value := []byte(`{}`) + var err error + value, err = Set(value, []byte(`1`), "test", "[0]") + if err != nil { + t.Fatalf("Set [0]: %v", err) + } + value, err = Set(value, []byte(`2`), "test", "[1]") + if err != nil { + t.Fatalf("Set [1]: %v", err) + } + value, err = Set(value, []byte(`3`), "test", "[2]") + if err != nil { + t.Fatalf("Set [2]: %v", err) + } + expected := `{"test":[1,2,3]}` + if string(value) != expected { + t.Fatalf("Set result mismatch: expected %s, got %s", expected, string(value)) + } +}