Skip to content

Commit cf9ac6f

Browse files
committed
refactor: refine the unmarshal json process and tests
1 parent cb6c71a commit cf9ac6f

File tree

3 files changed

+155
-97
lines changed

3 files changed

+155
-97
lines changed

map.go

Lines changed: 55 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import (
55
"encoding/json"
66
"errors"
77
"fmt"
8+
"reflect"
89
)
910

1011
var (
@@ -130,34 +131,74 @@ func (m *OrderedMap[K, V]) initialize() {
130131
m.pos = 0
131132
}
132133

133-
func (m *OrderedMap[K, V]) decodeKeyAndValue(decoder *json.Decoder) error {
134-
key, err := decodeKey(decoder)
134+
func (m *OrderedMap[K, V]) decodeKey(decoder *json.Decoder) (K, error) {
135+
var zero K
136+
token, err := decoder.Token()
135137
if err != nil {
136-
return fmt.Errorf("failed to decode key: %w", err)
138+
return zero, fmt.Errorf("failed to get token as key: %w", err)
139+
}
140+
if delim, ok := token.(json.Delim); ok {
141+
switch delim {
142+
case leftCurlyBrace:
143+
return zero, ErrNestedObject
144+
case leftBracket:
145+
return zero, ErrNestedArray
146+
case rightCurlyBrace, rightBracket:
147+
return zero, ErrEndOfJSON
148+
}
137149
}
138-
k, err := assertType[K](any(key))
150+
return assertType[K](token)
151+
}
152+
153+
func (m *OrderedMap[K, V]) decodeValue(decoder *json.Decoder) (V, error) {
154+
var zero V
155+
v, err := decodeValueAsAny(decoder)
139156
if err != nil {
140-
return fmt.Errorf("invalid key type: %w", err)
157+
return zero, err
158+
}
159+
if v == nil {
160+
return zero, nil
141161
}
162+
return assertType[V](v)
163+
}
142164

143-
value, err := decodeValue(decoder)
165+
func (m *OrderedMap[K, V]) decodeKeyAndValue(decoder *json.Decoder) error {
166+
key, err := m.decodeKey(decoder)
167+
if err != nil {
168+
return fmt.Errorf("failed to decode key: %w", err)
169+
}
170+
value, err := m.decodeValue(decoder)
144171
if err != nil {
145172
return fmt.Errorf("failed to decode value: %w", err)
146173
}
147-
var zero V
148-
if value == nil {
149-
m.Set(k, zero)
150-
return nil
174+
m.Set(key, value)
175+
return nil
176+
}
177+
178+
func (m *OrderedMap[K, V]) validateKeyValueType() error {
179+
var key K
180+
if reflect.ValueOf(key).Kind() != reflect.String {
181+
return fmt.Errorf("key type must be string")
151182
}
152-
v, err := assertType[V](value)
153-
if err != nil {
154-
return fmt.Errorf("invalid value type: %w", err)
183+
184+
var value V
185+
switch reflect.ValueOf(value).Kind() {
186+
case reflect.Pointer:
187+
return fmt.Errorf("unsupported pointer, use any")
188+
case reflect.Map:
189+
return fmt.Errorf("unsupported map, use any")
190+
case reflect.Struct:
191+
return fmt.Errorf("unsupported struct, use any")
192+
case reflect.Array:
193+
return fmt.Errorf("unsupported array, use slice")
155194
}
156-
m.Set(k, v)
157195
return nil
158196
}
159197

160198
func (m *OrderedMap[K, V]) UnmarshalJSON(b []byte) error {
199+
if err := m.validateKeyValueType(); err != nil {
200+
return fmt.Errorf("failed to validate type: %w", err)
201+
}
161202
m.initialize()
162203
decoder := json.NewDecoder(bytes.NewReader(b))
163204
token, err := decoder.Token()

map_test.go

Lines changed: 69 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -163,7 +163,7 @@ func TestToMap(t *testing.T) {
163163
}
164164
}
165165

166-
func TestUnmarhalAndMarshalJSON(t *testing.T) {
166+
func TestUnmarhalValueAsAnyAndMarshalJSON(t *testing.T) {
167167
t.Parallel()
168168

169169
tests := []struct {
@@ -225,32 +225,51 @@ func TestUnmarhalAndMarshalJSON(t *testing.T) {
225225
}
226226
}
227227

228-
func TestUnmarhalAndMarshalJSONForSlice(t *testing.T) {
228+
func TestUnmarhalAndMarshalJSON(t *testing.T) {
229229
t.Parallel()
230230

231231
tests := []struct {
232-
name string
233-
json string
232+
name string
233+
json string
234+
unmarshal func(string) (string, error)
234235
}{
235236
{
236-
name: "empty array",
237+
name: "float64",
238+
json: `{"test":3.14}`,
239+
unmarshal: func(data string) (string, error) {
240+
var m orderedmap.OrderedMap[string, float64]
241+
err := json.Unmarshal(json.RawMessage(data), &m)
242+
return m.String(), err
243+
},
244+
},
245+
{
246+
name: "empty slice",
237247
json: `{"a1":[]}`,
248+
unmarshal: func(data string) (string, error) {
249+
var m orderedmap.OrderedMap[string, []string]
250+
err := json.Unmarshal(json.RawMessage(data), &m)
251+
return m.String(), err
252+
},
238253
},
239254
{
240-
name: "strings array",
255+
name: "string slice",
241256
json: `{"a1":["t1","t3","t2"]}`,
257+
unmarshal: func(data string) (string, error) {
258+
var m orderedmap.OrderedMap[string, []string]
259+
err := json.Unmarshal(json.RawMessage(data), &m)
260+
return m.String(), err
261+
},
242262
},
243263
}
244264

245265
for _, tt := range tests {
246266
t.Run(tt.name, func(t *testing.T) {
247267
t.Parallel()
248-
var m orderedmap.OrderedMap[string, []string]
249-
if err := json.Unmarshal(json.RawMessage(tt.json), &m); err != nil {
268+
actual, err := tt.unmarshal(tt.json)
269+
if err != nil {
250270
t.Error(err)
251271
return
252272
}
253-
actual := m.String()
254273
if diff := cmp.Diff(tt.json, actual); diff != "" {
255274
t.Error(diff)
256275
return
@@ -284,16 +303,16 @@ func TestErrorUnmarhalAndMarshalJSON(t *testing.T) {
284303
var m orderedmap.OrderedMap[string, int]
285304
return json.Unmarshal(json.RawMessage(data), &m)
286305
},
287-
expected: errors.New("failed to decode key/value: invalid value type: failed to assert 5 (float64) as int"),
306+
expected: errors.New("failed to decode key/value: failed to decode value: failed to assert 5 (float64) as int"),
288307
},
289308
{
290-
name: "wrong key type",
291-
json: `{"a":"test"}`,
309+
name: "not string key type",
310+
json: `{"3":"test"}`,
292311
unmarshal: func(data string) error {
293312
var m orderedmap.OrderedMap[int, string]
294313
return json.Unmarshal(json.RawMessage(data), &m)
295314
},
296-
expected: errors.New("failed to decode key/value: invalid key type: failed to assert a (string) as int"),
315+
expected: errors.New("failed to validate type: key type must be string"),
297316
},
298317
{
299318
name: "wrong value type",
@@ -302,7 +321,7 @@ func TestErrorUnmarhalAndMarshalJSON(t *testing.T) {
302321
m := orderedmap.New[string, json.RawMessage]()
303322
return json.Unmarshal([]byte(data), m)
304323
},
305-
expected: errors.New("failed to decode key/value: invalid value type: failed to assert b (string) as slice"),
324+
expected: errors.New("failed to decode key/value: failed to decode value: failed to assert b (string) as slice"),
306325
},
307326
{
308327
name: "wrong the type of slice",
@@ -311,25 +330,56 @@ func TestErrorUnmarhalAndMarshalJSON(t *testing.T) {
311330
var m orderedmap.OrderedMap[string, []int]
312331
return json.Unmarshal(json.RawMessage(data), &m)
313332
},
314-
expected: errors.New("failed to decode key/value: invalid value type: failed to convert slice: failed to assert 2 (float64) as int"),
333+
expected: errors.New("failed to decode key/value: failed to decode value: failed to convert slice: failed to assert 2 (float64) as int"),
334+
},
335+
{
336+
name: "unsupported the map type",
337+
json: `{"value":{"k":1}}`,
338+
unmarshal: func(data string) error {
339+
var m orderedmap.OrderedMap[string, map[string]int]
340+
return json.Unmarshal(json.RawMessage(data), &m)
341+
},
342+
expected: errors.New("failed to validate type: unsupported map, use any"),
343+
},
344+
{
345+
name: "unsupported the struct type",
346+
json: `{"value":{"k":1}}`,
347+
unmarshal: func(data string) error {
348+
type KeyValue struct {
349+
Key string
350+
Value int
351+
}
352+
var m orderedmap.OrderedMap[string, KeyValue]
353+
return json.Unmarshal(json.RawMessage(data), &m)
354+
},
355+
expected: errors.New("failed to validate type: unsupported struct, use any"),
315356
},
316357
{
317358
name: "unsupported the pointer type",
318-
json: `{"values": 5}`,
359+
json: `{"value": 5}`,
319360
unmarshal: func(data string) error {
320361
var m orderedmap.OrderedMap[string, *int]
321362
return json.Unmarshal(json.RawMessage(data), &m)
322363
},
323-
expected: errors.New("failed to decode key/value: invalid value type: failed to assert 5 (float64) as *int"),
364+
expected: errors.New("failed to validate type: unsupported pointer, use any"),
324365
},
325366
{
326367
name: "unsupported the pointer slice type",
327-
json: `{"values": 5}`,
368+
json: `{"value": 5}`,
328369
unmarshal: func(data string) error {
329370
var m orderedmap.OrderedMap[string, *[]int]
330371
return json.Unmarshal(json.RawMessage(data), &m)
331372
},
332-
expected: errors.New("failed to decode key/value: invalid value type: failed to assert 5 (float64) as *[]int"),
373+
expected: errors.New("failed to validate type: unsupported pointer, use any"),
374+
},
375+
{
376+
name: "unsupported the array type",
377+
json: `{"a1":["t1","t3"]}`,
378+
unmarshal: func(data string) error {
379+
var m orderedmap.OrderedMap[string, [2]string]
380+
return json.Unmarshal(json.RawMessage(data), &m)
381+
},
382+
expected: errors.New("failed to validate type: unsupported array, use slice"),
333383
},
334384
}
335385

util.go

Lines changed: 31 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,35 @@ import (
44
"encoding/json"
55
"errors"
66
"fmt"
7-
"log/slog"
87
"reflect"
98
)
109

1110
func isSlice(v any) bool {
12-
if !reflect.ValueOf(v).IsValid() {
13-
return false
11+
return reflect.ValueOf(v).Kind() == reflect.Slice
12+
}
13+
14+
func assertType[T any](value any) (T, error) {
15+
var zero T
16+
if isSlice(zero) {
17+
v, ok := value.([]any)
18+
if !ok {
19+
return zero, fmt.Errorf("failed to assert %v (%T) as slice", value, value)
20+
}
21+
values, err := convertValuesForSlice(zero, v)
22+
if err != nil {
23+
return zero, fmt.Errorf("failed to convert slice: %w", err)
24+
}
25+
typedValues, ok := any(values).(T)
26+
if !ok {
27+
return zero, fmt.Errorf("failed to convert typed slice (%T)", values)
28+
}
29+
return typedValues, nil
30+
}
31+
v, ok := value.(T)
32+
if !ok {
33+
return zero, fmt.Errorf("failed to assert %v (%T) as %T", value, value, zero)
1434
}
15-
return reflect.TypeOf(v).Kind() == reflect.Slice
35+
return v, nil
1636
}
1737

1838
func convertValuesForSlice(zero any, anyValues []any) (any, error) {
@@ -101,46 +121,15 @@ func isObject(delim json.Delim) bool {
101121
return delim == leftCurlyBrace
102122
}
103123

104-
func decodeKey(decoder *json.Decoder) (string, error) {
105-
token, err := decoder.Token()
106-
if err != nil {
107-
return "", fmt.Errorf("failed to get token as key: %w", err)
108-
}
109-
if delim, ok := token.(json.Delim); ok {
110-
switch delim {
111-
case leftCurlyBrace:
112-
return "", ErrNestedObject
113-
case leftBracket:
114-
return "", ErrNestedArray
115-
case rightCurlyBrace, rightBracket:
116-
return "", ErrEndOfJSON
117-
}
118-
}
119-
if key, ok := token.(string); ok {
120-
return key, nil
121-
}
122-
return "", fmt.Errorf("key should be string, but not %v", token)
123-
}
124-
125124
func decodeObject(decoder *json.Decoder) (any, error) {
126125
m := New[string, any]()
127126
for {
128-
key, err := decodeKey(decoder)
129-
if err != nil {
127+
if err := m.decodeKeyAndValue(decoder); err != nil {
130128
if errors.Is(err, ErrEndOfJSON) {
131129
return m, nil
132-
} else if errors.Is(err, ErrNestedObject) {
133-
return decodeObject(decoder)
134-
} else if errors.Is(err, ErrNestedArray) {
135-
return decodeArray(decoder)
136130
}
137-
return nil, fmt.Errorf("failed to get key: %w", err)
131+
return nil, fmt.Errorf("failed to decode key/value: %w", err)
138132
}
139-
value, err := decodeValue(decoder)
140-
if err != nil {
141-
return nil, fmt.Errorf("failed to get value: %w", err)
142-
}
143-
m.Set(key, value)
144133
}
145134
}
146135

@@ -182,16 +171,18 @@ func decodeArray(decoder *json.Decoder) ([]any, error) {
182171

183172
func handleToken(token json.Token) (any, error) {
184173
// TODO: An abstraction layer for handling a token if it needed
174+
if token == nil {
175+
return token, nil
176+
}
185177
switch t := token.(type) {
186178
case string, float64, int, int64, uint, uint64, bool:
187179
return token, nil
188180
default:
189-
slog.Debug("unexpected token type", "token", t)
181+
return nil, fmt.Errorf("unexpected token type: %v", t)
190182
}
191-
return token, nil
192183
}
193184

194-
func decodeValue(decoder *json.Decoder) (any, error) {
185+
func decodeValueAsAny(decoder *json.Decoder) (any, error) {
195186
token, err := decoder.Token()
196187
if err != nil {
197188
return nil, fmt.Errorf("failed to get token as value: %w", err)
@@ -208,27 +199,3 @@ func decodeValue(decoder *json.Decoder) (any, error) {
208199
}
209200
return handleToken(token)
210201
}
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)