diff --git a/audit.go b/audit.go index 5dd2a14..4e2d282 100644 --- a/audit.go +++ b/audit.go @@ -2,7 +2,7 @@ package comsarif import ( "bytes" - "encoding/json" + "encoding/json/v2" "errors" "fmt" "io" diff --git a/composer_lock.go b/composer_lock.go index a2f93ea..65121f7 100644 --- a/composer_lock.go +++ b/composer_lock.go @@ -2,7 +2,7 @@ package comsarif import ( "bytes" - "encoding/json" + "encoding/json/jsontext" "errors" "fmt" "io" @@ -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) @@ -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) } } @@ -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 } @@ -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 @@ -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 } diff --git a/composer_lock_test.go b/composer_lock_test.go index 54e25ec..43baac1 100644 --- a/composer_lock_test.go +++ b/composer_lock_test.go @@ -1,7 +1,7 @@ package comsarif import ( - "encoding/json" + "encoding/json/jsontext" "maps" "slices" "strings" @@ -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) { @@ -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 { @@ -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 { @@ -143,45 +143,10 @@ 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 { @@ -189,8 +154,8 @@ func TestLocatePackageRegion(t *testing.T) { newlines = append(newlines, i) } } - dec := json.NewDecoder(strings.NewReader(objJSON)) - _, _ = dec.Token() + dec := jsontext.NewDecoder(strings.NewReader(objJSON)) + _, _ = dec.ReadToken() return dec, data, newlines } @@ -243,7 +208,7 @@ 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 { @@ -251,8 +216,8 @@ func TestLocatePackageRegion_Errors(t *testing.T) { newlines = append(newlines, i) } } - dec := json.NewDecoder(strings.NewReader(objJSON)) - _, _ = dec.Token() + dec := jsontext.NewDecoder(strings.NewReader(objJSON)) + _, _ = dec.ReadToken() return dec, data, newlines } @@ -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 { @@ -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) @@ -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") @@ -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 {