Skip to content

Commit 87a479d

Browse files
committed
fix: return proper errors with type assertion failure #1
1 parent 7d43ea5 commit 87a479d

File tree

3 files changed

+153
-36
lines changed

3 files changed

+153
-36
lines changed

map.go

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -133,21 +133,27 @@ func (m *OrderedMap[K, V]) initialize() {
133133
func (m *OrderedMap[K, V]) decodeKeyAndValue(decoder *json.Decoder) error {
134134
key, err := decodeKey(decoder)
135135
if err != nil {
136-
return fmt.Errorf("failed to get key: %w", err)
136+
return fmt.Errorf("failed to decode key: %w", err)
137137
}
138+
k, err := assertType[K](any(key))
139+
if err != nil {
140+
return fmt.Errorf("invalid key type: %w", err)
141+
}
142+
138143
value, err := decodeValue(decoder)
139144
if err != nil {
140-
return fmt.Errorf("failed to get value: %w", err)
145+
return fmt.Errorf("failed to decode value: %w", err)
141146
}
142-
var v V
147+
var zero V
143148
if value == nil {
144-
// nothing to do
145-
} else if isValueAndTypeAreSlice(v, value) {
146-
v = any(convertValuesForSlice(new(V), value.([]any))).(V)
147-
} else {
148-
v = value.(V)
149+
m.Set(k, zero)
150+
return nil
151+
}
152+
v, err := assertType[V](value)
153+
if err != nil {
154+
return fmt.Errorf("invalid value type: %w", err)
149155
}
150-
m.Set(any(key).(K), v)
156+
m.Set(k, v)
151157
return nil
152158
}
153159

map_test.go

Lines changed: 66 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -263,24 +263,83 @@ func TestErrorUnmarhalAndMarshalJSON(t *testing.T) {
263263
t.Parallel()
264264

265265
tests := []struct {
266-
name string
267-
json string
268-
expected error
266+
name string
267+
json string
268+
unmarshal func(string) error
269+
expected error
269270
}{
270271
{
271-
name: "simple array",
272-
json: `["test",3,9007199254740992,3.14,true]`,
272+
name: "simple array",
273+
json: `["test",3,9007199254740992,3.14,true]`,
274+
unmarshal: func(data string) error {
275+
var m orderedmap.OrderedMap[string, any]
276+
return json.Unmarshal(json.RawMessage(data), &m)
277+
},
273278
expected: errors.New("expects JSON object, but not: ["),
274279
},
280+
{
281+
name: "json number",
282+
json: `{"value": 5}`,
283+
unmarshal: func(data string) error {
284+
var m orderedmap.OrderedMap[string, int]
285+
return json.Unmarshal(json.RawMessage(data), &m)
286+
},
287+
expected: errors.New("failed to decode key/value: invalid value type: failed to assert 5 (float64) as int"),
288+
},
289+
{
290+
name: "wrong key type",
291+
json: `{"a":"test"}`,
292+
unmarshal: func(data string) error {
293+
var m orderedmap.OrderedMap[int, string]
294+
return json.Unmarshal(json.RawMessage(data), &m)
295+
},
296+
expected: errors.New("failed to decode key/value: invalid key type: failed to assert a (string) as int"),
297+
},
298+
{
299+
name: "wrong value type",
300+
json: `{"a":"b"}`,
301+
unmarshal: func(data string) error {
302+
m := orderedmap.New[string, json.RawMessage]()
303+
return json.Unmarshal([]byte(data), m)
304+
},
305+
expected: errors.New("failed to decode key/value: invalid value type: failed to assert b (string) as slice"),
306+
},
307+
{
308+
name: "wrong the type of slice",
309+
json: `{"values": [2,3,4]}`,
310+
unmarshal: func(data string) error {
311+
var m orderedmap.OrderedMap[string, []int]
312+
return json.Unmarshal(json.RawMessage(data), &m)
313+
},
314+
expected: errors.New("failed to decode key/value: invalid value type: failed to convert slice: failed to assert 2 (float64) as int"),
315+
},
316+
{
317+
name: "unsupported the pointer type",
318+
json: `{"values": 5}`,
319+
unmarshal: func(data string) error {
320+
var m orderedmap.OrderedMap[string, *int]
321+
return json.Unmarshal(json.RawMessage(data), &m)
322+
},
323+
expected: errors.New("failed to decode key/value: invalid value type: failed to assert 5 (float64) as *int"),
324+
},
325+
{
326+
name: "unsupported the pointer slice type",
327+
json: `{"values": 5}`,
328+
unmarshal: func(data string) error {
329+
var m orderedmap.OrderedMap[string, *[]int]
330+
return json.Unmarshal(json.RawMessage(data), &m)
331+
},
332+
expected: errors.New("failed to decode key/value: invalid value type: failed to assert 5 (float64) as *[]int"),
333+
},
275334
}
276335

277336
for _, tt := range tests {
278337
t.Run(tt.name, func(t *testing.T) {
279338
t.Parallel()
280-
var m orderedmap.OrderedMap[string, any]
281-
err := json.Unmarshal(json.RawMessage(tt.json), &m)
339+
err := tt.unmarshal(tt.json)
282340
if err == nil {
283341
t.Error("expects an error occurred, but no error")
342+
return
284343
}
285344
if diff := cmp.Diff(tt.expected.Error(), err.Error()); diff != "" {
286345
t.Error(diff)

util.go

Lines changed: 72 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -15,57 +15,85 @@ func isSlice(v any) bool {
1515
return reflect.TypeOf(v).Kind() == reflect.Slice
1616
}
1717

18-
func isValueAndTypeAreSlice(typ any, value any) bool {
19-
return isSlice(typ) && isSlice(value)
20-
}
18+
func convertValuesForSlice(zero any, anyValues []any) (any, error) {
19+
if zero == nil {
20+
return nil, errors.New("zero cannot be nil")
21+
}
2122

22-
func convertValuesForSlice(typ any, anyValues []any) any {
23-
elem := reflect.TypeOf(typ).Elem().Elem()
23+
elem := reflect.TypeOf(zero).Elem()
2424
switch kind := elem.Kind(); kind {
2525
case reflect.Bool:
2626
values := make([]bool, 0, len(anyValues))
2727
for _, v := range anyValues {
28-
values = append(values, v.(bool))
28+
vv, ok := v.(bool)
29+
if !ok {
30+
return nil, fmt.Errorf("failed to assert %v (%T) as bool", v, v)
31+
}
32+
values = append(values, vv)
2933
}
30-
return values
34+
return values, nil
3135
case reflect.Int:
3236
values := make([]int, 0, len(anyValues))
3337
for _, v := range anyValues {
34-
values = append(values, v.(int))
38+
vv, ok := v.(int)
39+
if !ok {
40+
return nil, fmt.Errorf("failed to assert %v (%T) as int", v, v)
41+
}
42+
values = append(values, vv)
3543
}
36-
return values
44+
return values, nil
3745
case reflect.Int64:
3846
values := make([]int64, 0, len(anyValues))
3947
for _, v := range anyValues {
40-
values = append(values, v.(int64))
48+
vv, ok := v.(int64)
49+
if !ok {
50+
return nil, fmt.Errorf("failed to assert %v (%T) as int64", v, v)
51+
}
52+
values = append(values, vv)
4153
}
42-
return values
54+
return values, nil
4355
case reflect.Uint:
4456
values := make([]uint, 0, len(anyValues))
4557
for _, v := range anyValues {
46-
values = append(values, v.(uint))
58+
vv, ok := v.(uint)
59+
if !ok {
60+
return nil, fmt.Errorf("failed to assert %v (%T) as uint", v, v)
61+
}
62+
values = append(values, vv)
4763
}
48-
return values
64+
return values, nil
4965
case reflect.Uint64:
5066
values := make([]uint64, 0, len(anyValues))
5167
for _, v := range anyValues {
52-
values = append(values, v.(uint64))
68+
vv, ok := v.(uint64)
69+
if !ok {
70+
return nil, fmt.Errorf("failed to assert %v (%T) as uint64", v, v)
71+
}
72+
values = append(values, vv)
5373
}
54-
return values
74+
return values, nil
5575
case reflect.Float64:
5676
values := make([]float64, 0, len(anyValues))
5777
for _, v := range anyValues {
58-
values = append(values, v.(float64))
78+
vv, ok := v.(float64)
79+
if !ok {
80+
return nil, fmt.Errorf("failed to assert %v (%T) as float64", v, v)
81+
}
82+
values = append(values, vv)
5983
}
60-
return values
84+
return values, nil
6185
case reflect.String:
6286
values := make([]string, 0, len(anyValues))
6387
for _, v := range anyValues {
64-
values = append(values, v.(string))
88+
vv, ok := v.(string)
89+
if !ok {
90+
return nil, fmt.Errorf("failed to assert %v (%T) as string", v, v)
91+
}
92+
values = append(values, vv)
6593
}
66-
return values
94+
return values, nil
6795
default:
68-
panic(fmt.Errorf("unsupported type to convert: %s", kind))
96+
return nil, fmt.Errorf("unsupported type to convert: %s", kind)
6997
}
7098
}
7199

@@ -180,3 +208,27 @@ func decodeValue(decoder *json.Decoder) (any, error) {
180208
}
181209
return handleToken(token)
182210
}
211+
212+
func assertType[T any](value any) (T, error) {
213+
var zero T
214+
if isSlice(zero) {
215+
v, ok := value.([]any)
216+
if !ok {
217+
return zero, fmt.Errorf("failed to assert %v (%T) as slice", value, value)
218+
}
219+
values, err := convertValuesForSlice(zero, v)
220+
if err != nil {
221+
return zero, fmt.Errorf("failed to convert slice: %w", err)
222+
}
223+
typedValues, ok := any(values).(T)
224+
if !ok {
225+
return zero, fmt.Errorf("failed to convert typed slice (%T)", values)
226+
}
227+
return typedValues, nil
228+
}
229+
v, ok := value.(T)
230+
if !ok {
231+
return zero, fmt.Errorf("failed to assert %v (%T) as %T", value, value, zero)
232+
}
233+
return v, nil
234+
}

0 commit comments

Comments
 (0)