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 }