master
go 228 lines 5.34 KB
Raw
1 // SPDX-License-Identifier: GPL-3.0-or-later
2
3 package topologyv1
4
5 import (
6 "testing"
7
8 "github.com/stretchr/testify/assert"
9 "github.com/stretchr/testify/require"
10 )
11
12 func TestNewTableValidatesEncodings(t *testing.T) {
13 table, err := NewTable(3,
14 []Column{
15 NewColumn("kind", "string"),
16 NewColumn("name", "string"),
17 NewColumn("state", "string"),
18 },
19 []ColumnEncoding{
20 Const("process"),
21 Values("web", "db", "cache"),
22 Dict(StringValues("running", "stopped"), 0, 0, 1),
23 },
24 )
25
26 require.NoError(t, err)
27 assert.Equal(t, 3, table.Rows)
28 assert.Len(t, table.Columns, 3)
29 assert.Len(t, table.Values, 3)
30 }
31
32 func TestNewTableRejectsColumnValueMismatch(t *testing.T) {
33 _, err := NewTable(1,
34 []Column{
35 NewColumn("id", "string"),
36 NewColumn("name", "string"),
37 },
38 []ColumnEncoding{
39 Values("actor-1"),
40 },
41 )
42
43 require.Error(t, err)
44 assert.Contains(t, err.Error(), "columns/values length mismatch")
45 }
46
47 func TestNewTableRejectsDecodedLengthMismatch(t *testing.T) {
48 _, err := NewTable(2,
49 []Column{NewColumn("name", "string")},
50 []ColumnEncoding{Values("only-one")},
51 )
52
53 require.Error(t, err)
54 assert.Contains(t, err.Error(), "decoded length mismatch")
55 }
56
57 func TestNewTableRejectsDictIndexOutOfBounds(t *testing.T) {
58 _, err := NewTable(2,
59 []Column{NewColumn("state", "string")},
60 []ColumnEncoding{Dict(StringValues("up"), 0, 1)},
61 )
62
63 require.Error(t, err)
64 assert.Contains(t, err.Error(), "out of bounds")
65 }
66
67 func TestNewTableRejectsNilEncoding(t *testing.T) {
68 _, err := NewTable(1,
69 []Column{NewColumn("id", "string")},
70 []ColumnEncoding{nil},
71 )
72
73 require.Error(t, err)
74 assert.Contains(t, err.Error(), "is nil")
75 }
76
77 func TestNewTableRejectsDuplicateColumnIDs(t *testing.T) {
78 _, err := NewTable(1,
79 []Column{
80 NewColumn("id", "string"),
81 NewColumn("id", "string"),
82 },
83 []ColumnEncoding{
84 Const("actor-1"),
85 Const("actor-2"),
86 },
87 )
88
89 require.Error(t, err)
90 assert.Contains(t, err.Error(), "duplicates column")
91 }
92
93 func TestNewTableRejectsColumnValueContractMismatch(t *testing.T) {
94 cases := map[string]struct {
95 column Column
96 value ColumnEncoding
97 want string
98 }{
99 "non nullable null": {
100 column: NewColumn("name", "string"),
101 value: Const(nil),
102 want: "not nullable",
103 },
104 "string ref without dictionary": {
105 column: NewColumn("name", "string_ref"),
106 value: Const(0),
107 want: "requires dictionary",
108 },
109 "string ref value must be integer": {
110 column: NewColumn("name", "string_ref", WithDictionary("strings")),
111 value: Const("node-a"),
112 want: "dictionary reference",
113 },
114 "actor ref must be non negative integer": {
115 column: NewColumn("actor", "actor_ref"),
116 value: Const(-1),
117 want: "actor_ref reference",
118 },
119 "dictionary only belongs on reference columns": {
120 column: Column{ID: "name", Type: "string", Dictionary: "strings"},
121 value: Const("node-a"),
122 want: "dictionary with non-reference type",
123 },
124 "unsupported type rejected even when nullable": {
125 column: Column{ID: "name", Type: "unknown", Nullable: true},
126 value: Const(nil),
127 want: "unsupported type",
128 },
129 "uint must be non negative": {
130 column: NewColumn("socket_count", "uint"),
131 value: Const(-1),
132 want: "non-negative integer",
133 },
134 }
135
136 for name, tc := range cases {
137 t.Run(name, func(t *testing.T) {
138 _, err := NewTable(1, []Column{tc.column}, []ColumnEncoding{tc.value})
139 require.Error(t, err)
140 assert.Contains(t, err.Error(), tc.want)
141 })
142 }
143 }
144
145 func TestNewTableAllowsNullableNull(t *testing.T) {
146 table, err := NewTable(1,
147 []Column{NewColumn("name", "string", WithNullable())},
148 []ColumnEncoding{Const(nil)},
149 )
150
151 require.NoError(t, err)
152 assert.Equal(t, 1, table.Rows)
153 }
154
155 func TestTableBuilderBuildsValuesTable(t *testing.T) {
156 builder := NewTableBuilder(
157 NewColumn("id", "string"),
158 NewColumn("connected", "bool"),
159 )
160
161 row := builder.Add("actor-1", true)
162 builder.Add("actor-2", false)
163 table, err := builder.Table()
164
165 require.NoError(t, err)
166 assert.Equal(t, 0, row)
167 assert.Equal(t, 2, builder.Rows())
168 assert.Equal(t, 2, table.Rows)
169 require.Len(t, table.Values, 2)
170 assert.Equal(t, Values("actor-1", "actor-2"), table.Values[0])
171 assert.Equal(t, Values(true, false), table.Values[1])
172 }
173
174 func TestTableBuilderRejectsRowWidthMismatch(t *testing.T) {
175 builder := NewTableBuilder(
176 NewColumn("id", "string"),
177 NewColumn("name", "string"),
178 )
179
180 row := builder.Add("actor-1")
181 _, err := builder.Table()
182
183 require.Error(t, err)
184 assert.Equal(t, 0, row)
185 assert.Contains(t, err.Error(), "row has 1 values for 2 columns")
186 }
187
188 func TestTableBuilderBuildsEmptyZeroColumnTable(t *testing.T) {
189 builder := NewTableBuilder()
190
191 table, err := builder.Table()
192
193 require.NoError(t, err)
194 assert.Equal(t, EmptyTable(), table)
195 }
196
197 func TestStringDictionaryDeduplicatesValues(t *testing.T) {
198 dict := NewStringDictionary()
199
200 first := dict.Ref("alpha")
201 second := dict.Ref("beta")
202 again := dict.Ref("alpha")
203
204 assert.Equal(t, 0, first)
205 assert.Equal(t, 1, second)
206 assert.Equal(t, first, again)
207 assert.Equal(t, []any{"alpha", "beta"}, dict.Values())
208 }
209
210 func TestNilStringDictionaryReturnsEmptyValues(t *testing.T) {
211 var dict *StringDictionary
212
213 assert.Equal(t, []any{}, dict.Values())
214 }
215
216 func TestEmptyStringDictionaryReturnsEmptyValues(t *testing.T) {
217 dict := NewStringDictionary()
218
219 assert.Equal(t, []any{}, dict.Values())
220 }
221
222 func TestNilStringDictionaryRefPanics(t *testing.T) {
223 var dict *StringDictionary
224
225 assert.Panics(t, func() {
226 dict.Ref("alpha")
227 })
228 }