k8s.io/kube-openapi@v0.0.0-20240228011516-70dd3763d340/pkg/internal/third_party/go-json-experiment/json/errors_test.go (about)

     1  // Copyright 2020 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package json
     6  
     7  import (
     8  	"archive/tar"
     9  	"bytes"
    10  	"errors"
    11  	"fmt"
    12  	"io"
    13  	"reflect"
    14  	"strconv"
    15  	"strings"
    16  	"testing"
    17  )
    18  
    19  func TestSemanticError(t *testing.T) {
    20  	tests := []struct {
    21  		err  error
    22  		want string
    23  	}{{
    24  		err:  &SemanticError{},
    25  		want: "json: cannot handle",
    26  	}, {
    27  		err:  &SemanticError{JSONKind: 'n'},
    28  		want: "json: cannot handle JSON null",
    29  	}, {
    30  		err:  &SemanticError{action: "unmarshal", JSONKind: 't'},
    31  		want: "json: cannot unmarshal JSON boolean",
    32  	}, {
    33  		err:  &SemanticError{action: "unmarshal", JSONKind: 'x'},
    34  		want: "json: cannot unmarshal", // invalid token kinds are ignored
    35  	}, {
    36  		err:  &SemanticError{action: "marshal", JSONKind: '"'},
    37  		want: "json: cannot marshal JSON string",
    38  	}, {
    39  		err:  &SemanticError{GoType: reflect.TypeOf(bool(false))},
    40  		want: "json: cannot handle Go value of type bool",
    41  	}, {
    42  		err:  &SemanticError{action: "marshal", GoType: reflect.TypeOf(int(0))},
    43  		want: "json: cannot marshal Go value of type int",
    44  	}, {
    45  		err:  &SemanticError{action: "unmarshal", GoType: reflect.TypeOf(uint(0))},
    46  		want: "json: cannot unmarshal Go value of type uint",
    47  	}, {
    48  		err:  &SemanticError{JSONKind: '0', GoType: reflect.TypeOf(tar.Header{})},
    49  		want: "json: cannot handle JSON number with Go value of type tar.Header",
    50  	}, {
    51  		err:  &SemanticError{action: "marshal", JSONKind: '{', GoType: reflect.TypeOf(bytes.Buffer{})},
    52  		want: "json: cannot marshal JSON object from Go value of type bytes.Buffer",
    53  	}, {
    54  		err:  &SemanticError{action: "unmarshal", JSONKind: ']', GoType: reflect.TypeOf(strings.Reader{})},
    55  		want: "json: cannot unmarshal JSON array into Go value of type strings.Reader",
    56  	}, {
    57  		err:  &SemanticError{action: "unmarshal", JSONKind: '{', GoType: reflect.TypeOf(float64(0)), ByteOffset: 123},
    58  		want: "json: cannot unmarshal JSON object into Go value of type float64 after byte offset 123",
    59  	}, {
    60  		err:  &SemanticError{action: "marshal", JSONKind: 'f', GoType: reflect.TypeOf(complex128(0)), ByteOffset: 123, JSONPointer: "/foo/2/bar/3"},
    61  		want: "json: cannot marshal JSON boolean from Go value of type complex128 within JSON value at \"/foo/2/bar/3\"",
    62  	}, {
    63  		err:  &SemanticError{action: "unmarshal", JSONKind: '}', GoType: reflect.TypeOf((*io.Reader)(nil)).Elem(), ByteOffset: 123, JSONPointer: "/foo/2/bar/3", Err: errors.New("some underlying error")},
    64  		want: "json: cannot unmarshal JSON object into Go value of type io.Reader within JSON value at \"/foo/2/bar/3\": some underlying error",
    65  	}, {
    66  		err:  &SemanticError{Err: errors.New("some underlying error")},
    67  		want: "json: cannot handle: some underlying error",
    68  	}, {
    69  		err:  &SemanticError{ByteOffset: 123},
    70  		want: "json: cannot handle after byte offset 123",
    71  	}, {
    72  		err:  &SemanticError{JSONPointer: "/foo/2/bar/3"},
    73  		want: "json: cannot handle within JSON value at \"/foo/2/bar/3\"",
    74  	}}
    75  
    76  	for _, tt := range tests {
    77  		got := tt.err.Error()
    78  		// Cleanup the error of non-deterministic rendering effects.
    79  		if strings.HasPrefix(got, errorPrefix+"unable to ") {
    80  			got = errorPrefix + "cannot " + strings.TrimPrefix(got, errorPrefix+"unable to ")
    81  		}
    82  		if got != tt.want {
    83  			t.Errorf("%#v.Error mismatch:\ngot  %v\nwant %v", tt.err, got, tt.want)
    84  		}
    85  	}
    86  }
    87  
    88  func TestErrorsIs(t *testing.T) {
    89  	const (
    90  		someGlobalError  = jsonError("some global error")
    91  		otherGlobalError = jsonError("other global error")
    92  	)
    93  
    94  	var (
    95  		someIOError         = &ioError{action: "write", err: io.ErrShortWrite}
    96  		otherIOError        = &ioError{action: "read", err: io.ErrUnexpectedEOF}
    97  		someSyntacticError  = &SyntacticError{str: "some syntactic error"}
    98  		otherSyntacticError = &SyntacticError{str: "other syntactic error"}
    99  		someSemanticError   = &SemanticError{action: "unmarshal", JSONKind: '0', GoType: reflect.TypeOf(int(0)), Err: strconv.ErrRange}
   100  		otherSemanticError  = &SemanticError{action: "marshal", GoType: reflect.TypeOf(complex128(0))}
   101  	)
   102  
   103  	tests := []struct {
   104  		err    error
   105  		target error
   106  		want   bool
   107  	}{
   108  		// Top-level Error should match itself (identity).
   109  		{Error, Error, true},
   110  
   111  		// All sub-error values should match the top-level Error value.
   112  		{someGlobalError, Error, true},
   113  		{someIOError, Error, true},
   114  		{someSyntacticError, Error, true},
   115  		{someSemanticError, Error, true},
   116  
   117  		// Top-level Error should not match any other sub-error value.
   118  		{Error, someGlobalError, false},
   119  		{Error, someIOError, false},
   120  		{Error, someSyntacticError, false},
   121  		{Error, someSemanticError, false},
   122  
   123  		// Sub-error values should match itself (identity).
   124  		{someGlobalError, someGlobalError, true},
   125  		{someIOError, someIOError, true},
   126  		{someSyntacticError, someSyntacticError, true},
   127  		{someSemanticError, someSemanticError, true},
   128  
   129  		// Sub-error values should not match each other.
   130  		{someGlobalError, someIOError, false},
   131  		{someIOError, someSyntacticError, false},
   132  		{someSyntacticError, someSemanticError, false},
   133  		{someSemanticError, someGlobalError, false},
   134  
   135  		// Sub-error values should not match other error values of same type.
   136  		{someGlobalError, otherGlobalError, false},
   137  		{someIOError, otherIOError, false},
   138  		{someSyntacticError, otherSyntacticError, false},
   139  		{someSemanticError, otherSemanticError, false},
   140  
   141  		// Error should not match any other random error.
   142  		{Error, nil, false},
   143  		{nil, Error, false},
   144  		{io.ErrShortWrite, Error, false},
   145  		{Error, io.ErrShortWrite, false},
   146  
   147  		// Wrapped errors should be matched.
   148  		{&ioError{err: fmt.Errorf("%w", io.ErrShortWrite)}, io.ErrShortWrite, true}, // doubly wrapped
   149  		{&ioError{err: io.ErrShortWrite}, io.ErrShortWrite, true},                   // singly wrapped
   150  		{&ioError{err: io.ErrShortWrite}, io.EOF, false},
   151  		{&SemanticError{Err: fmt.Errorf("%w", strconv.ErrRange)}, strconv.ErrRange, true}, // doubly wrapped
   152  		{&SemanticError{Err: strconv.ErrRange}, strconv.ErrRange, true},                   // singly wrapped
   153  		{&SemanticError{Err: strconv.ErrRange}, io.EOF, false},
   154  	}
   155  
   156  	for _, tt := range tests {
   157  		got := errors.Is(tt.err, tt.target)
   158  		if got != tt.want {
   159  			t.Errorf("errors.Is(%#v, %#v) = %v, want %v", tt.err, tt.target, got, tt.want)
   160  		}
   161  		// If the type supports the Is method,
   162  		// it should behave the same way if called directly.
   163  		if iserr, ok := tt.err.(interface{ Is(error) bool }); ok {
   164  			got := iserr.Is(tt.target)
   165  			if got != tt.want {
   166  				t.Errorf("%#v.Is(%#v) = %v, want %v", tt.err, tt.target, got, tt.want)
   167  			}
   168  		}
   169  	}
   170  }
   171  
   172  func TestQuoteRune(t *testing.T) {
   173  	tests := []struct{ in, want string }{
   174  		{"x", `'x'`},
   175  		{"\n", `'\n'`},
   176  		{"'", `'\''`},
   177  		{"\xff", `'\xff'`},
   178  		{"💩", `'💩'`},
   179  		{"💩"[:1], `'\xf0'`},
   180  		{"\uffff", `'\uffff'`},
   181  		{"\U00101234", `'\U00101234'`},
   182  	}
   183  	for _, tt := range tests {
   184  		got := quoteRune([]byte(tt.in))
   185  		if got != tt.want {
   186  			t.Errorf("quoteRune(%q) = %s, want %s", tt.in, got, tt.want)
   187  		}
   188  	}
   189  }