...

Source file src/github.com/launchdarkly/go-sdk-common/v3/ldvalue/value_base_test.go

Documentation: github.com/launchdarkly/go-sdk-common/v3/ldvalue

     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  	// treating a null as a non-null produces empty values
    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  	// treating a bool as a non-bool produces empty values
    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  	// treating a number as a non-number produces empty values
   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  	// treating a number as a non-number produces empty values
   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  	// treating a string as a non-string produces empty values
   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  	// inspecting the value in any way causes it to be parsed and treated as a regular value
   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  	// Application code has no way to construct a Value like this, but we'll still prove
   406  	// that we would handle it gracefully if we did it somehow
   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