Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion audit.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ package comsarif

import (
"bytes"
"encoding/json"
"encoding/json/v2"
"errors"
"fmt"
"io"
Expand Down
72 changes: 18 additions & 54 deletions composer_lock.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ package comsarif

import (
"bytes"
"encoding/json"
"encoding/json/jsontext"
"errors"
"fmt"
"io"
Expand Down Expand Up @@ -52,13 +52,13 @@ func parseRegions(data []byte) (regions, error) {
}
}

decoder := json.NewDecoder(bytes.NewReader(data))
decoder := jsontext.NewDecoder(bytes.NewReader(data))
if err := expectDelim(decoder, '{'); err != nil {
return nil, fmt.Errorf("parse composer.lock: %v", err)
}

regs := make(regions)
for decoder.More() {
for decoder.PeekKind() != jsontext.KindEndObject {
key, err := nextJSONString(decoder)
if err != nil {
return nil, fmt.Errorf("parse composer.lock: parse top level object key: %v", err)
Expand All @@ -70,7 +70,7 @@ func parseRegions(data []byte) (regions, error) {
return nil, fmt.Errorf("parse composer.lock: parse top level %s array: %v", key, err)
}
default:
if err = skipJSONValue(decoder); err != nil {
if err = decoder.SkipValue(); err != nil {
return nil, fmt.Errorf("parse composer.lock: %v", err)
}
}
Expand All @@ -83,12 +83,12 @@ func parseRegions(data []byte) (regions, error) {
return regs, nil
}

func parsePackageArray(decoder *json.Decoder, data []byte, newlines []int, regions regions) error {
func parsePackageArray(decoder *jsontext.Decoder, data []byte, newlines []int, regions regions) error {
if err := expectDelim(decoder, '['); err != nil {
return err
}

for decoder.More() {
for decoder.PeekKind() != jsontext.KindEndArray {
if err := expectDelim(decoder, '{'); err != nil {
return err
}
Expand All @@ -111,18 +111,18 @@ func parsePackageArray(decoder *json.Decoder, data []byte, newlines []int, regio
return expectDelim(decoder, ']')
}

func locatePackageRegion(decoder *json.Decoder, data []byte, newlines []int) (string, region, error) {
func locatePackageRegion(decoder *jsontext.Decoder, data []byte, newlines []int) (string, region, error) {
var name string
var offset int64

for decoder.More() {
for decoder.PeekKind() != jsontext.KindEndObject {
key, err := nextJSONString(decoder)
if err != nil {
return "", region{}, fmt.Errorf("parse package field key: %v", err)
}

if key != "name" {
if err := skipJSONValue(decoder); err != nil {
if err := decoder.SkipValue(); err != nil {
return "", region{}, err
}
continue
Expand Down Expand Up @@ -167,64 +167,28 @@ func locatePackageRegion(decoder *json.Decoder, data []byte, newlines []int) (st
return name, r, nil
}

func expectDelim(decoder *json.Decoder, want json.Delim) error {
tok, err := decoder.Token()
func expectDelim(decoder *jsontext.Decoder, want jsontext.Kind) error {
tok, err := decoder.ReadToken()
if err != nil {
return err
}

delim, ok := tok.(json.Delim)
if !ok || delim != want {
return fmt.Errorf("expected %q, got %T %v", want, tok, tok)
if tok.Kind() != want {
return fmt.Errorf("expected %q, got %v", want, tok)
}

return nil
}

func nextJSONString(decoder *json.Decoder) (string, error) {
tok, err := decoder.Token()
func nextJSONString(decoder *jsontext.Decoder) (string, error) {
tok, err := decoder.ReadToken()
if err != nil {
return "", err
}

val, ok := tok.(string)
if !ok {
return "", fmt.Errorf("expected JSON string literals, got %T %v", tok, tok)
if tok.Kind() != jsontext.KindString {
return "", fmt.Errorf("expected JSON string literals, got %v", tok)
}

return val, nil
}

func skipJSONValue(decoder *json.Decoder) error {
tok, err := decoder.Token()
if err != nil {
return err
}

delim, ok := tok.(json.Delim)
if !ok {
return nil
}

switch delim {
case '{':
for decoder.More() {
if _, err := decoder.Token(); err != nil {
return err
}
if err := skipJSONValue(decoder); err != nil {
return err
}
}
return expectDelim(decoder, '}')
case '[':
for decoder.More() {
if err := skipJSONValue(decoder); err != nil {
return err
}
}
return expectDelim(decoder, ']')
default:
return nil
}
return tok.String(), nil
}
106 changes: 38 additions & 68 deletions composer_lock_test.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package comsarif

import (
"encoding/json"
"encoding/json/jsontext"
"maps"
"slices"
"strings"
Expand All @@ -11,8 +11,8 @@ import (
"github.com/google/go-cmp/cmp/cmpopts"
)

func newDecoder(s string) *json.Decoder {
return json.NewDecoder(strings.NewReader(s))
func newDecoder(s string) *jsontext.Decoder {
return jsontext.NewDecoder(strings.NewReader(s))
}

func TestExpectDelim(t *testing.T) {
Expand All @@ -21,18 +21,18 @@ func TestExpectDelim(t *testing.T) {
tests := []struct {
name string
content string
want json.Delim
want jsontext.Kind
}{
{"open_brace", `{}`, '{'},
{"open_bracket", `[]`, '['},
{"close_brace_after_open", `{}`, '{'},
{"close_bracket_after_open", `[]`, '['},
{"nested_open_brace", `{ }`, '{'},
{"open_brace_with_content", `{"key":"val"}`, '{'},
{"open_bracket_with_content", `[1,2,3]`, '['},
{"close_bracket_delim", `[]`, '['},
{"close_brace_delim", `{}`, '{'},
{"whitespace_before_brace", ` { }`, '{'},
{"open_brace", `{}`, jsontext.KindBeginObject},
{"open_bracket", `[]`, jsontext.KindBeginArray},
{"close_brace_after_open", `{}`, jsontext.KindBeginObject},
{"close_bracket_after_open", `[]`, jsontext.KindBeginArray},
{"nested_open_brace", `{ }`, jsontext.KindBeginObject},
{"open_brace_with_content", `{"key":"val"}`, jsontext.KindBeginObject},
{"open_bracket_with_content", `[1,2,3]`, jsontext.KindBeginArray},
{"close_bracket_delim", `[]`, jsontext.KindBeginArray},
{"close_brace_delim", `{}`, jsontext.KindBeginObject},
{"whitespace_before_brace", ` { }`, jsontext.KindBeginObject},
}

for _, tt := range tests {
Expand All @@ -52,18 +52,18 @@ func TestExpectDelim_Errors(t *testing.T) {
tests := []struct {
name string
content string
want json.Delim
want jsontext.Kind
}{
{"empty_input", ``, '{'},
{"string_instead_of_delim", `"hello"`, '{'},
{"number_instead_of_delim", `42`, '{'},
{"bool_instead_of_delim", `true`, '{'},
{"null_instead_of_delim", `null`, '{'},
{"wrong_delim_brace_vs_bracket", `[`, '{'},
{"wrong_delim_bracket_vs_brace", `{`, '['},
{"close_instead_of_open", `}`, '{'},
{"close_bracket_instead_of_open_brace", `]`, '{'},
{"float_instead_of_delim", `3.14`, '{'},
{"empty_input", ``, jsontext.KindBeginObject},
{"string_instead_of_delim", `"hello"`, jsontext.KindBeginObject},
{"number_instead_of_delim", `42`, jsontext.KindBeginObject},
{"bool_instead_of_delim", `true`, jsontext.KindBeginObject},
{"null_instead_of_delim", `null`, jsontext.KindBeginObject},
{"wrong_delim_brace_vs_bracket", `[`, jsontext.KindBeginObject},
{"wrong_delim_bracket_vs_brace", `{`, jsontext.KindBeginArray},
{"close_instead_of_open", `}`, jsontext.KindBeginObject},
{"close_bracket_instead_of_open_brace", `]`, jsontext.KindBeginObject},
{"float_instead_of_delim", `3.14`, jsontext.KindBeginObject},
}

for _, tt := range tests {
Expand Down Expand Up @@ -143,54 +143,19 @@ func TestNextJSONString_Errors(t *testing.T) {
}
}

func TestSkipJSONValue(t *testing.T) {
t.Parallel()

tests := []struct {
name string
content string
wantErr bool
}{
{"skip_string", `"hello" "next"`, false},
{"skip_number", `42 "next"`, false},
{"skip_bool_true", `true "next"`, false},
{"skip_bool_false", `false "next"`, false},
{"skip_null", `null "next"`, false},
{"skip_empty_object", `{} "next"`, false},
{"skip_empty_array", `[] "next"`, false},
{"skip_nested_object", `{"a":{"b":1}} "next"`, false},
{"skip_nested_array", `[[1,2],[3,4]] "next"`, false},
{"skip_deep_nesting", `{"a":{"b":{"c":[1,2,3]}}} "next"`, false},
{"empty_input", ``, true},
{"truncated_object", `{"a":`, true},
{"truncated_array", `[1,`, true},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
t.Parallel()
dec := newDecoder(tt.content)
err := skipJSONValue(dec)
if (err != nil) != tt.wantErr {
t.Fatalf("skipJSONValue() error = %v, wantErr %v", err, tt.wantErr)
}
})
}
}

func TestLocatePackageRegion(t *testing.T) {
t.Parallel()

makeDecoderInObject := func(objJSON string) (*json.Decoder, []byte, []int) {
makeDecoderInObject := func(objJSON string) (*jsontext.Decoder, []byte, []int) {
data := []byte(objJSON)
var newlines []int
for i, b := range data {
if b == '\n' {
newlines = append(newlines, i)
}
}
dec := json.NewDecoder(strings.NewReader(objJSON))
_, _ = dec.Token()
dec := jsontext.NewDecoder(strings.NewReader(objJSON))
_, _ = dec.ReadToken()
return dec, data, newlines
}

Expand Down Expand Up @@ -243,16 +208,16 @@ func TestLocatePackageRegion(t *testing.T) {
func TestLocatePackageRegion_Errors(t *testing.T) {
t.Parallel()

makeDecoderInObject := func(objJSON string) (*json.Decoder, []byte, []int) {
makeDecoderInObject := func(objJSON string) (*jsontext.Decoder, []byte, []int) {
data := []byte(objJSON)
var newlines []int
for i, b := range data {
if b == '\n' {
newlines = append(newlines, i)
}
}
dec := json.NewDecoder(strings.NewReader(objJSON))
_, _ = dec.Token()
dec := jsontext.NewDecoder(strings.NewReader(objJSON))
_, _ = dec.ReadToken()
return dec, data, newlines
}

Expand All @@ -270,6 +235,8 @@ func TestLocatePackageRegion_Errors(t *testing.T) {
{"empty_object_no_fields", `{}`},
{"only_nested_object_no_name", `{"extra":{"a":"b"},"info":{"c":"d"}}`},
{"name_value_is_false", `{"name":false}`},
{"truncated_nested_object_value", `{"extra":{"a":`},
{"truncated_array_value", `{"keywords":["a",`},
}

for _, tt := range tests {
Expand Down Expand Up @@ -314,7 +281,7 @@ func TestParsePackageArray(t *testing.T) {
newlines = append(newlines, i)
}
}
dec := json.NewDecoder(strings.NewReader(tt.content))
dec := jsontext.NewDecoder(strings.NewReader(tt.content))
regs := make(regions)
if err := parsePackageArray(dec, data, newlines, regs); err != nil {
t.Fatalf("parsePackageArray() unexpected error: %v", err)
Expand Down Expand Up @@ -359,7 +326,7 @@ func TestParsePackageArray_Errors(t *testing.T) {
newlines = append(newlines, i)
}
}
dec := json.NewDecoder(strings.NewReader(tt.content))
dec := jsontext.NewDecoder(strings.NewReader(tt.content))
regs := make(regions)
if err := parsePackageArray(dec, data, newlines, regs); err == nil {
t.Fatal("parsePackageArray() unexpected success")
Expand Down Expand Up @@ -511,6 +478,9 @@ func TestNewRegions_Errors(t *testing.T) {
{"package_with_empty_name", `{"packages":[{"name":""}]}`},
{"package_name_is_number", `{"packages":[{"name":42}]}`},
{"duplicate_package_within_same_array", `{"packages":[{"name":"vendor/foo"},{"name":"vendor/foo"}]}`},
{"truncated_unknown_string_value", `{"content-hash":`},
{"truncated_unknown_object_value", `{"extra":{"a":`},
{"truncated_unknown_array_value", `{"aliases":["a",`},
}

for _, tt := range tests {
Expand Down
Loading