1 package ldvalue
2
3 import (
4 "encoding/json"
5 "errors"
6 "testing"
7
8 helpers "github.com/launchdarkly/go-test-helpers/v3"
9
10 "github.com/stretchr/testify/assert"
11 )
12
13 func TestValueTypes(t *testing.T) {
14 assert.Equal(t, nullAsJSON, NullType.String())
15 assert.Equal(t, "bool", BoolType.String())
16 assert.Equal(t, "number", NumberType.String())
17 assert.Equal(t, "string", StringType.String())
18 assert.Equal(t, "array", ArrayType.String())
19 assert.Equal(t, "object", ObjectType.String())
20 assert.Equal(t, "raw", RawType.String())
21 assert.Equal(t, "unknown", ValueType(99).String())
22 }
23
24 func TestNullValue(t *testing.T) {
25 v := Null()
26
27 assert.Equal(t, NullType, v.Type())
28 assert.False(t, v.IsDefined())
29 assert.True(t, v.IsNull())
30 assert.False(t, v.IsBool())
31 assert.False(t, v.IsNumber())
32 assert.False(t, v.IsInt())
33 assert.False(t, v.IsString())
34
35 assert.Equal(t, Null(), v)
36 assert.Equal(t, Value{}, v)
37
38
39 assert.False(t, v.BoolValue())
40 assert.Equal(t, 0, v.IntValue())
41 assert.Equal(t, float64(0), v.Float64Value())
42 assert.Equal(t, "", v.StringValue())
43 assert.Equal(t, OptionalString{}, v.AsOptionalString())
44 assert.Equal(t, 0, v.Count())
45 assert.Equal(t, Null(), v.GetByIndex(0))
46 assert.Equal(t, Null(), v.GetByKey("x"))
47 }
48
49 func TestBoolValue(t *testing.T) {
50 tv := Bool(true)
51
52 assert.Equal(t, BoolType, tv.Type())
53 assert.True(t, tv.BoolValue())
54 assert.True(t, tv.IsDefined())
55 assert.False(t, tv.IsNull())
56 assert.True(t, tv.IsBool())
57 assert.False(t, tv.IsNumber())
58 assert.False(t, tv.IsInt())
59 assert.False(t, tv.IsString())
60
61 assert.Equal(t, Bool(true), tv)
62 assert.NotEqual(t, Bool(false), tv)
63
64
65 assert.Equal(t, 0, tv.IntValue())
66 assert.Equal(t, float64(0), tv.Float64Value())
67 assert.Equal(t, "", tv.StringValue())
68 assert.Equal(t, OptionalString{}, tv.AsOptionalString())
69 assert.Equal(t, 0, tv.Count())
70 assert.Equal(t, Null(), tv.GetByIndex(0))
71 assert.Equal(t, Null(), tv.GetByKey("x"))
72
73 fv := Bool(false)
74
75 assert.Equal(t, BoolType, fv.Type())
76 assert.False(t, fv.BoolValue())
77 assert.True(t, fv.IsDefined())
78 assert.False(t, fv.IsNull())
79 assert.False(t, fv.IsNumber())
80 assert.False(t, fv.IsInt())
81
82 assert.Equal(t, Bool(false), fv)
83 assert.NotEqual(t, Bool(true), fv)
84 }
85
86 func TestIntValue(t *testing.T) {
87 v := Int(2)
88
89 assert.Equal(t, NumberType, v.Type())
90 assert.Equal(t, 2, v.IntValue())
91 assert.Equal(t, float64(2), v.Float64Value())
92 assert.True(t, v.IsDefined())
93 assert.False(t, v.IsNull())
94 assert.False(t, v.IsBool())
95 assert.True(t, v.IsNumber())
96 assert.True(t, v.IsInt())
97 assert.False(t, v.IsString())
98
99 assert.Equal(t, Int(2), v)
100 assert.Equal(t, Float64(2), v)
101 assert.NotEqual(t, Float64(2.5), v)
102
103
104 assert.False(t, v.BoolValue())
105 assert.Equal(t, "", v.StringValue())
106 assert.Equal(t, OptionalString{}, v.AsOptionalString())
107 assert.Equal(t, 0, v.Count())
108 assert.Equal(t, Null(), v.GetByIndex(0))
109 assert.Equal(t, Null(), v.GetByKey("x"))
110 }
111
112 func TestFloat64Value(t *testing.T) {
113 v := Float64(2.75)
114
115 assert.Equal(t, NumberType, v.Type())
116 assert.Equal(t, 2, v.IntValue())
117 assert.Equal(t, 2.75, v.Float64Value())
118 assert.True(t, v.IsDefined())
119 assert.False(t, v.IsNull())
120 assert.False(t, v.IsBool())
121 assert.True(t, v.IsNumber())
122 assert.False(t, v.IsInt())
123 assert.False(t, v.IsString())
124
125 floatButReallyInt := Float64(2.0)
126 assert.Equal(t, NumberType, floatButReallyInt.Type())
127 assert.Equal(t, 2, floatButReallyInt.IntValue())
128 assert.Equal(t, 2.0, floatButReallyInt.Float64Value())
129 assert.False(t, floatButReallyInt.IsNull())
130 assert.True(t, floatButReallyInt.IsNumber())
131 assert.True(t, floatButReallyInt.IsInt())
132
133 assert.Equal(t, Float64(2.75), v)
134 assert.NotEqual(t, Float64(2.5), v)
135
136
137 assert.False(t, v.BoolValue())
138 assert.Equal(t, "", v.StringValue())
139 assert.Equal(t, OptionalString{}, v.AsOptionalString())
140 assert.Equal(t, 0, v.Count())
141 assert.Equal(t, Null(), v.GetByIndex(0))
142 assert.Equal(t, Null(), v.GetByKey("x"))
143 }
144
145 func TestStringValue(t *testing.T) {
146 v := String("abc")
147
148 assert.Equal(t, StringType, v.Type())
149 assert.Equal(t, "abc", v.StringValue())
150 assert.Equal(t, NewOptionalString("abc"), v.AsOptionalString())
151 assert.True(t, v.IsDefined())
152 assert.False(t, v.IsNull())
153 assert.False(t, v.IsBool())
154 assert.False(t, v.IsNumber())
155 assert.False(t, v.IsInt())
156 assert.True(t, v.IsString())
157 assert.Equal(t, v, String("abc"))
158
159 assert.Equal(t, String("abc"), v)
160 assert.NotEqual(t, String("def"), v)
161
162
163 assert.False(t, v.BoolValue())
164 assert.Equal(t, 0, v.IntValue())
165 assert.Equal(t, float64(0), v.Float64Value())
166 assert.Equal(t, 0, v.Count())
167 assert.Equal(t, Null(), v.GetByIndex(0))
168 assert.Equal(t, Null(), v.GetByKey("x"))
169 }
170
171 func TestRawValue(t *testing.T) {
172 rawJSON := json.RawMessage(`[1]`)
173 v := Raw(rawJSON)
174 assert.Equal(t, RawType, v.Type())
175 assert.Equal(t, rawJSON, v.AsRaw())
176 assert.Equal(t, string(rawJSON), v.JSONString())
177
178
179 assert.True(t, Raw(json.RawMessage(`null`)).IsNull())
180 assert.True(t, Raw(json.RawMessage(`true`)).IsBool())
181 assert.True(t, Raw(json.RawMessage(`"a"`)).IsString())
182 assert.True(t, Raw(json.RawMessage(`1.5`)).IsNumber())
183 assert.True(t, Raw(json.RawMessage(`1`)).IsInt())
184 assert.True(t, Raw(json.RawMessage(`true`)).BoolValue())
185 assert.Equal(t, "a", Raw(json.RawMessage(`"a"`)).StringValue())
186 assert.Equal(t, NewOptionalString("a"), Raw(json.RawMessage(`"a"`)).AsOptionalString())
187 assert.Equal(t, 1.5, Raw(json.RawMessage(`1.5`)).Float64Value())
188 assert.Equal(t, 1, Raw(json.RawMessage(`1.5`)).IntValue())
189 }
190
191 func TestConvertPrimitivesFromArbitraryValue(t *testing.T) {
192 t.Run("nil", func(t *testing.T) {
193 assert.Equal(t, Null(), CopyArbitraryValue(nil))
194 })
195 t.Run("Value", func(t *testing.T) {
196 originalValue := Int(1)
197 assert.Equal(t, originalValue, CopyArbitraryValue(originalValue))
198 assert.Equal(t, originalValue, CopyArbitraryValue(&originalValue))
199 assert.Equal(t, Null(), CopyArbitraryValue((*Value)(nil)))
200 })
201 t.Run("OptionalString", func(t *testing.T) {
202 s := NewOptionalString("value")
203 sv := String("value")
204 assert.Equal(t, sv, CopyArbitraryValue(s))
205 assert.Equal(t, sv, CopyArbitraryValue(&s))
206 assert.Equal(t, Null(), CopyArbitraryValue(OptionalString{}))
207 assert.Equal(t, Null(), CopyArbitraryValue(&OptionalString{}))
208 assert.Equal(t, Null(), CopyArbitraryValue((*OptionalString)(nil)))
209 })
210 t.Run("bool", func(t *testing.T) {
211 assert.Equal(t, Bool(true), CopyArbitraryValue(true))
212 assert.Equal(t, Bool(false), CopyArbitraryValue(false))
213 assert.Equal(t, Bool(true), CopyArbitraryValue(helpers.AsPointer(true)))
214 assert.Equal(t, Bool(false), CopyArbitraryValue(helpers.AsPointer(false)))
215 assert.Equal(t, Null(), CopyArbitraryValue((*bool)(nil)))
216 })
217 t.Run("int8", func(t *testing.T) {
218 var n int8 = 1
219 assert.Equal(t, Int(1), CopyArbitraryValue(n))
220 assert.Equal(t, Int(1), CopyArbitraryValue(&n))
221 assert.Equal(t, Null(), CopyArbitraryValue((*int8)(nil)))
222 })
223 t.Run("uint8", func(t *testing.T) {
224 var n uint8 = 1
225 assert.Equal(t, Int(1), CopyArbitraryValue(n))
226 assert.Equal(t, Int(1), CopyArbitraryValue(&n))
227 assert.Equal(t, Null(), CopyArbitraryValue((*uint8)(nil)))
228 })
229 t.Run("int16", func(t *testing.T) {
230 var n int16 = 1
231 assert.Equal(t, Int(1), CopyArbitraryValue(n))
232 assert.Equal(t, Int(1), CopyArbitraryValue(&n))
233 assert.Equal(t, Null(), CopyArbitraryValue((*int16)(nil)))
234 })
235 t.Run("uint16", func(t *testing.T) {
236 var n uint16 = 1
237 assert.Equal(t, Int(1), CopyArbitraryValue(n))
238 assert.Equal(t, Int(1), CopyArbitraryValue(&n))
239 assert.Equal(t, Null(), CopyArbitraryValue((*uint16)(nil)))
240 })
241 t.Run("int", func(t *testing.T) {
242 var n int = 1
243 assert.Equal(t, Int(1), CopyArbitraryValue(n))
244 assert.Equal(t, Int(1), CopyArbitraryValue(&n))
245 assert.Equal(t, Null(), CopyArbitraryValue((*int)(nil)))
246 })
247 t.Run("uint", func(t *testing.T) {
248 var n uint = 1
249 assert.Equal(t, Int(1), CopyArbitraryValue(n))
250 assert.Equal(t, Int(1), CopyArbitraryValue(&n))
251 assert.Equal(t, Null(), CopyArbitraryValue((*uint)(nil)))
252 })
253 t.Run("int32", func(t *testing.T) {
254 var n int32 = 1
255 assert.Equal(t, Int(1), CopyArbitraryValue(n))
256 assert.Equal(t, Int(1), CopyArbitraryValue(&n))
257 assert.Equal(t, Null(), CopyArbitraryValue((*int32)(nil)))
258 })
259 t.Run("uint32", func(t *testing.T) {
260 var n uint32 = 1
261 assert.Equal(t, Int(1), CopyArbitraryValue(n))
262 assert.Equal(t, Int(1), CopyArbitraryValue(&n))
263 assert.Equal(t, Null(), CopyArbitraryValue((*uint32)(nil)))
264 })
265 t.Run("float32", func(t *testing.T) {
266 var n float32 = 2.5
267 assert.Equal(t, Float64(2.5), CopyArbitraryValue(n))
268 assert.Equal(t, Float64(2.5), CopyArbitraryValue(&n))
269 assert.Equal(t, Null(), CopyArbitraryValue((*float32)(nil)))
270 })
271 t.Run("float64", func(t *testing.T) {
272 var n float64 = 2.5
273 assert.Equal(t, Float64(2.5), CopyArbitraryValue(n))
274 assert.Equal(t, Float64(2.5), CopyArbitraryValue(&n))
275 assert.Equal(t, Null(), CopyArbitraryValue((*float64)(nil)))
276 })
277 t.Run("string", func(t *testing.T) {
278 s := "x"
279 assert.Equal(t, String(s), CopyArbitraryValue(s))
280 assert.Equal(t, String(s), CopyArbitraryValue(&s))
281 assert.Equal(t, Null(), CopyArbitraryValue((*string)(nil)))
282 })
283 t.Run("[]interface{}", func(t *testing.T) {
284 a := []interface{}{2, []interface{}{"x"}}
285 av := ArrayOf(Int(2), ArrayOf(String("x")))
286 assert.Equal(t, av, CopyArbitraryValue(a))
287 assert.Equal(t, av, CopyArbitraryValue(&a))
288 assert.Equal(t, Null(), CopyArbitraryValue((*[]interface{})(nil)))
289 })
290 t.Run("[]Value", func(t *testing.T) {
291 a := []Value{Int(2), ArrayOf(String("x"))}
292 av := ArrayOf(Int(2), ArrayOf(String("x")))
293 assert.Equal(t, av, CopyArbitraryValue(a))
294 assert.Equal(t, av, CopyArbitraryValue(&a))
295 assert.Equal(t, Null(), CopyArbitraryValue((*[]Value)(nil)))
296 })
297 t.Run("map[string]interface{}", func(t *testing.T) {
298 m := map[string]interface{}{"x": []interface{}{2}}
299 mv := ObjectBuild().Set("x", ArrayOf(Int(2))).Build()
300 assert.Equal(t, mv, CopyArbitraryValue(m))
301 assert.Equal(t, mv, CopyArbitraryValue(&m))
302 assert.Equal(t, Null(), CopyArbitraryValue((*map[string]interface{})(nil)))
303 })
304 t.Run("map[string]Value", func(t *testing.T) {
305 m := map[string]Value{"x": ArrayOf(Int(2))}
306 mv := ObjectBuild().Set("x", ArrayOf(Int(2))).Build()
307 assert.Equal(t, mv, CopyArbitraryValue(m))
308 assert.Equal(t, mv, CopyArbitraryValue(&m))
309 assert.Equal(t, Null(), CopyArbitraryValue((*map[string]Value)(nil)))
310 })
311 t.Run("arbitrary struct", func(t *testing.T) {
312 s := struct {
313 X int `json:"x"`
314 }{X: 2}
315 v := CopyArbitraryValue(s)
316 assert.Equal(t, ObjectBuild().Set("x", Int(2)).Build(), v)
317 })
318 t.Run("raw", func(t *testing.T) {
319 j := json.RawMessage("[3]")
320 jv := Raw(json.RawMessage("[3]"))
321 assert.Equal(t, jv, CopyArbitraryValue(j))
322 assert.Equal(t, jv, CopyArbitraryValue(&j))
323 assert.Equal(t, Null(), CopyArbitraryValue((*json.RawMessage)(nil)))
324 })
325 }
326
327 func TestFromJSONMarshal(t *testing.T) {
328 s := struct {
329 X int `json:"x"`
330 }{X: 2}
331 v := FromJSONMarshal(s)
332 assert.Equal(t, ObjectBuild().Set("x", Int(2)).Build(), v)
333 }
334
335 func TestConvertPrimitivesToArbitraryValue(t *testing.T) {
336 assert.Nil(t, Null().AsArbitraryValue())
337 assert.Equal(t, true, Bool(true).AsArbitraryValue())
338 assert.Equal(t, false, Bool(false).AsArbitraryValue())
339 assert.Equal(t, float64(2), Int(2).AsArbitraryValue())
340 assert.Equal(t, "x", String("x").AsArbitraryValue())
341 assert.Equal(t, json.RawMessage("[3]"), Raw(json.RawMessage("[3]")).AsArbitraryValue())
342 }
343
344 func TestEqualPrimitives(t *testing.T) {
345 valueFns := []func() Value{
346 func() Value { return Null() },
347 func() Value { return Bool(false) },
348 func() Value { return Bool(true) },
349 func() Value { return Int(1) },
350 func() Value { return Float64(2.5) },
351 func() Value { return String("") },
352 func() Value { return String("1") },
353 }
354 for i, fn0 := range valueFns {
355 v0 := fn0()
356 for j, fn1 := range valueFns {
357 v1 := fn1()
358 if i == j {
359 valuesShouldBeEqual(t, v0, v1)
360 } else {
361 valuesShouldNotBeEqual(t, v0, v1)
362 }
363 }
364 }
365 }
366
367 func TestEqualPrimitivesAndRawRepresentations(t *testing.T) {
368 valueFns := []func() Value{
369 func() Value { return Null() },
370 func() Value { return Bool(false) },
371 func() Value { return Bool(true) },
372 func() Value { return Int(1) },
373 func() Value { return Float64(2.5) },
374 func() Value { return String("") },
375 func() Value { return String("1") },
376 }
377 for i, fn0 := range valueFns {
378 v0 := fn0()
379 v0Raw := Raw([]byte(v0.JSONString()))
380 valuesShouldBeEqual(t, v0, v0Raw)
381 for j, fn1 := range valueFns {
382 if i != j {
383 v1 := fn1()
384 v1Raw := Raw([]byte(v1.JSONString()))
385 valuesShouldNotBeEqual(t, v0, v1Raw)
386 valuesShouldNotBeEqual(t, v1, v0Raw)
387 }
388 }
389 }
390 }
391
392 func valuesShouldBeEqual(t *testing.T, value0 Value, value1 Value) {
393 t.Helper()
394 assert.True(t, value0.Equal(value1), "%s should equal %s", value0, value1)
395 assert.True(t, value1.Equal(value0), "%s should equal %s conversely", value1, value0)
396 }
397
398 func valuesShouldNotBeEqual(t *testing.T, value0 Value, value1 Value) {
399 t.Helper()
400 assert.False(t, value0.Equal(value1), "%s should not equal %s", value0, value1)
401 assert.False(t, value1.Equal(value0), "%s should not equal %s", value1, value0)
402 }
403
404 func TestValueWithInvalidType(t *testing.T) {
405
406
407 v := Value{valueType: ValueType(99)}
408
409 assert.False(t, v.IsNull())
410 assert.False(t, v.IsNumber())
411 assert.False(t, v.IsInt())
412 assert.False(t, v.BoolValue())
413 assert.Equal(t, 0, v.IntValue())
414 assert.Equal(t, float64(0), v.Float64Value())
415 assert.Equal(t, "", v.StringValue())
416 assert.Equal(t, OptionalString{}, v.AsOptionalString())
417 assert.Equal(t, 0, v.Count())
418 assert.Equal(t, Null(), v.GetByIndex(0))
419 assert.Equal(t, Null(), v.GetByKey("x"))
420 assert.Nil(t, v.AsArbitraryValue())
421 assert.Nil(t, v.AsRaw())
422 }
423
424 func TestValueAsPointer(t *testing.T) {
425 v := String("value")
426 assert.Equal(t, &v, v.AsPointer())
427
428 assert.Nil(t, Null().AsPointer())
429 }
430
431 func TestConvertArbitraryValueThatFailsToSerialize(t *testing.T) {
432 assert.Equal(t, Null(), CopyArbitraryValue(unserializableValue{}))
433 assert.Equal(t, Null(), FromJSONMarshal(unserializableValue{}))
434 }
435
436 type unserializableValue struct{}
437
438 func (u unserializableValue) MarshalJSON() ([]byte, error) {
439 return nil, errors.New("no")
440 }
441
View as plain text