1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
|
// SPDX-FileCopyrightText: 2026 Stefan Majewsky <majewsky@gmx.net>
// SPDX-License-Identifier: Apache-2.0
package columnar_test
import (
"encoding/json"
"sync"
"testing"
"go.xyrillian.de/gg/columnar"
. "go.xyrillian.de/gg/internal/test"
"go.xyrillian.de/gg/jsonmatch"
)
func testSuccessfulJSONRoundtrip[V any](t *testing.T, list []V, encoded jsonmatch.Diffable) {
buf, err := json.Marshal(columnar.List[V](list))
if err != nil {
t.Fatal(err)
}
for _, diff := range encoded.DiffAgainst(buf) {
t.Error(diff.String())
}
var unmarshaled columnar.List[V]
err = json.Unmarshal(buf, &unmarshaled)
if err != nil {
t.Fatal(err)
}
AssertEqual(t, []V(unmarshaled), list)
}
func TestJSONRoundtripBasic(t *testing.T) {
// try the example from the package docstring
type Person struct {
ID int `json:"id"`
FirstName string `json:"first_name"`
LastName string `json:"last_name"`
Married bool `json:"married"`
}
testSuccessfulJSONRoundtrip(t,
[]Person{
{ID: 1, FirstName: "Alice", LastName: "Allison", Married: false},
{ID: 2, FirstName: "Bob", LastName: "Burger", Married: true},
{ID: 3, FirstName: "Carol", LastName: "Callagher", Married: true},
},
jsonmatch.Object{
"id": jsonmatch.Array{1, 2, 3},
"first_name": jsonmatch.Array{"Alice", "Bob", "Carol"},
"last_name": jsonmatch.Array{"Allison", "Burger", "Callagher"},
"married": jsonmatch.Array{false, true, true},
},
)
}
func TestJSONRoundtripWithSpecialFields(t *testing.T) {
type Point struct {
X float64 `json:"x"`
Y float64 `json:"y"`
}
type Event struct {
*Point `json:"location"` // embedded field, also with pointer
Name string // without tag -> uses field name as key
nameMutex sync.RWMutex //nolint:unused // not exported -> ignored
}
testSuccessfulJSONRoundtrip(t,
[]Event{
{Point: &Point{X: 0, Y: 0}, Name: "origin"},
{Point: &Point{X: 2, Y: 4}, Name: "somewhere"},
},
jsonmatch.Object{
"location": jsonmatch.Array{jsonmatch.Object{"x": 0, "y": 0}, jsonmatch.Object{"x": 2, "y": 4}},
"Name": jsonmatch.Array{"origin", "somewhere"},
},
)
}
func TestJSONRoundtripResolvesPointers(t *testing.T) {
type Record struct {
Foo int
Bar int
}
testSuccessfulJSONRoundtrip(t,
[]***Record{
PointerTo(PointerTo(PointerTo(Record{1, 2}))),
PointerTo(PointerTo(PointerTo(Record{2, 4}))),
PointerTo(PointerTo(PointerTo(Record{3, 6}))),
},
jsonmatch.Object{
"Foo": jsonmatch.Array{1, 2, 3},
"Bar": jsonmatch.Array{2, 4, 6},
},
)
}
func TestJSONRoundtripErrors(t *testing.T) {
type nothingPublic struct {
foo int
bar int
}
_, err := json.Marshal(columnar.List[nothingPublic]{{1, 2}})
AssertEqual(t, err.Error(), `json: error calling MarshalJSON for type columnar.List[go.xyrillian.de/gg/columnar_test.nothingPublic·5]: columnar_test.nothingPublic has no exported fields`)
err = json.Unmarshal([]byte(`{}`), PointerTo(columnar.List[nothingPublic]{}))
AssertEqual(t, err.Error(), `columnar_test.nothingPublic has no exported fields`)
}
func TestJSONUnmarshalFromInconsistentLengths(t *testing.T) {
type Record struct {
Foo int
Bar int
}
err := json.Unmarshal([]byte(`{"Foo":[1,2],"Bar":[3,4,5]}`), PointerTo(columnar.List[Record]{}))
AssertEqual(t, err.Error(), `cannot unmarshal from columns with inconsistent lengths [2 3]`)
}
|