1
2
3
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",
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
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
109 {Error, Error, true},
110
111
112 {someGlobalError, Error, true},
113 {someIOError, Error, true},
114 {someSyntacticError, Error, true},
115 {someSemanticError, Error, true},
116
117
118 {Error, someGlobalError, false},
119 {Error, someIOError, false},
120 {Error, someSyntacticError, false},
121 {Error, someSemanticError, false},
122
123
124 {someGlobalError, someGlobalError, true},
125 {someIOError, someIOError, true},
126 {someSyntacticError, someSyntacticError, true},
127 {someSemanticError, someSemanticError, true},
128
129
130 {someGlobalError, someIOError, false},
131 {someIOError, someSyntacticError, false},
132 {someSyntacticError, someSemanticError, false},
133 {someSemanticError, someGlobalError, false},
134
135
136 {someGlobalError, otherGlobalError, false},
137 {someIOError, otherIOError, false},
138 {someSyntacticError, otherSyntacticError, false},
139 {someSemanticError, otherSemanticError, false},
140
141
142 {Error, nil, false},
143 {nil, Error, false},
144 {io.ErrShortWrite, Error, false},
145 {Error, io.ErrShortWrite, false},
146
147
148 {&ioError{err: fmt.Errorf("%w", io.ErrShortWrite)}, io.ErrShortWrite, true},
149 {&ioError{err: io.ErrShortWrite}, io.ErrShortWrite, true},
150 {&ioError{err: io.ErrShortWrite}, io.EOF, false},
151 {&SemanticError{Err: fmt.Errorf("%w", strconv.ErrRange)}, strconv.ErrRange, true},
152 {&SemanticError{Err: strconv.ErrRange}, strconv.ErrRange, true},
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
162
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 }
190
View as plain text