...

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

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

     1  package ldvalue
     2  
     3  import (
     4  	"fmt"
     5  	"testing"
     6  
     7  	"github.com/stretchr/testify/assert"
     8  )
     9  
    10  func TestNilValueArray(t *testing.T) {
    11  	a := ValueArray{}
    12  	assert.False(t, a.IsDefined())
    13  	assert.Equal(t, 0, a.Count())
    14  	assert.Equal(t, Null(), a.Get(0))
    15  }
    16  
    17  func TestCopyValueArray(t *testing.T) {
    18  	s := []Value{String("a"), String("b")}
    19  	a1 := CopyValueArray(s)
    20  	assert.Equal(t, s, a1.data)
    21  	shouldNotBeSameSlice(t, s, a1.data)
    22  
    23  	a2 := CopyValueArray(nil)
    24  	assert.Nil(t, a2.data)
    25  
    26  	s3 := []Value{}
    27  	a3 := CopyValueArray(s3)
    28  	assert.Equal(t, []Value{}, a3.data)
    29  }
    30  
    31  func TestCopyArbitraryValueArray(t *testing.T) {
    32  	a1 := CopyArbitraryValueArray([]interface{}{"a", "b"})
    33  	assert.Equal(t, []Value{String("a"), String("b")}, a1.data)
    34  
    35  	a2 := CopyArbitraryValueArray(nil)
    36  	assert.Nil(t, a2.data)
    37  
    38  	a3 := CopyArbitraryValueArray([]interface{}{})
    39  	assert.Equal(t, []Value{}, a3.data)
    40  }
    41  
    42  func TestValueArrayOf(t *testing.T) {
    43  	item0 := String("a")
    44  	item1 := Int(1)
    45  	a1 := ValueArrayOf(item0, item1)
    46  
    47  	assert.Equal(t, 2, a1.Count())
    48  	assert.True(t, a1.IsDefined())
    49  
    50  	a2 := ValueArrayOf()
    51  	assert.Equal(t, 0, a2.Count())
    52  	assert.True(t, a2.IsDefined())
    53  }
    54  
    55  func TestValueArrayBuild(t *testing.T) {
    56  	item0 := String("a")
    57  	item1 := Int(1)
    58  	builder := ValueArrayBuild().Add(item0).Add(item1)
    59  	a := builder.Build()
    60  
    61  	assert.True(t, a.IsDefined())
    62  	assert.Equal(t, 2, a.Count())
    63  	assert.Equal(t, ValueArrayOf(item0, item1), a)
    64  
    65  	item2 := Bool(true)
    66  	builder.Add(item2)
    67  	valueAfterModifyingBuilder := builder.Build()
    68  
    69  	assert.Equal(t, 3, valueAfterModifyingBuilder.Count())
    70  	assert.Equal(t, item2, valueAfterModifyingBuilder.Get(2))
    71  
    72  	assert.Equal(t, 2, a.Count()) // verifies builder's copy-on-write behavior
    73  
    74  	assert.Equal(t, ValueArrayOf(), ValueArrayBuild().Build())
    75  
    76  	assert.Equal(t, a, ValueArrayBuildWithCapacity(3).Add(item0).Add(item1).Build())
    77  }
    78  
    79  func TestValueArrayBuildFromArray(t *testing.T) {
    80  	a0 := ValueArrayOf(String("a"), String("b"))
    81  
    82  	a1 := ValueArrayBuildFromArray(a0).Build()
    83  	assert.Equal(t, a0, a1)
    84  	shouldBeSameSlice(t, a0.data, a1.data)
    85  
    86  	// test copy-on-write behavior
    87  	a3 := ValueArrayOf(String("a"))
    88  	a4 := ValueArrayBuildFromArray(a3).Add(String("b")).Build()
    89  	assert.Equal(t, ValueArrayOf(String("a"), String("b")), a4)
    90  	shouldNotBeSameSlice(t, a3.data, a4.data)
    91  	a5 := ValueArrayBuild().AddAllFromValueArray(a3).Add(String("b")).Build()
    92  	assert.NotEqual(t, a3, a5)
    93  	shouldNotBeSameSlice(t, a3.data, a5.data)
    94  	assert.Equal(t, a4, a5)
    95  }
    96  
    97  func TestValueArrayBuilderSafety(t *testing.T) {
    98  	// empty instance is safe to use
    99  	var emptyInstance ValueArrayBuilder
   100  	emptyInstance.Add(Int(1))
   101  	assert.Equal(t, ValueArrayBuild().Add(Int(1)).Build(), emptyInstance.Build())
   102  
   103  	// nil pointer is safe to use
   104  	var nilPtr *ValueArrayBuilder
   105  	assert.Nil(t, nilPtr.Add(Int(1)))
   106  	assert.Nil(t, nilPtr.AddAllFromValueArray(ValueArray{}))
   107  	assert.Equal(t, ValueArray{}, nilPtr.Build())
   108  }
   109  
   110  func TestValueArrayGetByIndex(t *testing.T) {
   111  	item0 := String("a")
   112  	item1 := Int(1)
   113  	a := ValueArrayOf(item0, item1)
   114  
   115  	assert.Equal(t, item0, a.Get(0))
   116  	assert.Equal(t, item1, a.Get(1))
   117  	assert.Equal(t, Null(), a.Get(-1))
   118  	assert.Equal(t, Null(), a.Get(2))
   119  
   120  	item, ok := a.TryGet(0)
   121  	assert.True(t, ok)
   122  	assert.Equal(t, item0, item)
   123  	item, ok = a.TryGet(2)
   124  	assert.False(t, ok)
   125  	assert.Equal(t, Null(), item)
   126  }
   127  
   128  func TestConvertValueArrayToArbitraryValues(t *testing.T) {
   129  	a := ValueArrayBuild().Add(String("a")).Add(String("b")).Build()
   130  	expected := []interface{}{"a", "b"}
   131  	assert.Equal(t, expected, a.AsArbitraryValueSlice())
   132  }
   133  
   134  func TestConvertValueArrayFromArbitraryValuesAndBackAgain(t *testing.T) {
   135  	slice0 := []interface{}{"a", "b"}
   136  	a := CopyArbitraryValueArray(slice0)
   137  	slice1 := a.AsArbitraryValueSlice()
   138  	assert.Equal(t, slice0, slice1)
   139  	// Verify that the slice was deep-copied
   140  	slice0[0] = "c"
   141  	assert.NotEqual(t, slice0, slice1)
   142  }
   143  
   144  func TestValueArrayEqual(t *testing.T) {
   145  	valueFns := []func() ValueArray{
   146  		func() ValueArray { return ValueArray{} },
   147  		func() ValueArray { return ValueArrayBuild().Build() },
   148  		func() ValueArray { return ValueArrayBuild().Add(String("a")).Build() },
   149  	}
   150  	for i, fn0 := range valueFns {
   151  		v0 := fn0()
   152  		for j, fn1 := range valueFns {
   153  			v1 := fn1()
   154  			if i == j {
   155  				assert.True(t, v0.Equal(v1), "%s should equal %s", v0, v1)
   156  				assert.True(t, v0.Equal(v1), "%s should equal %s conversely", v1, v0)
   157  			} else {
   158  				assert.False(t, v0.Equal(v1), "%s should not equal %s", v0, v1)
   159  				assert.False(t, v1.Equal(v0), "%s should not equal %s", v1, v0)
   160  			}
   161  		}
   162  	}
   163  }
   164  
   165  func TestValueArrayAsValue(t *testing.T) {
   166  	assert.Equal(t, Null(), ValueArray{}.AsValue())
   167  
   168  	a := ValueArrayOf(String("a"), String("b"))
   169  	v := a.AsValue()
   170  	assert.Equal(t, ArrayOf(String("a"), String("b")), v)
   171  	shouldBeSameSlice(t, a.data, v.arrayValue.data)
   172  }
   173  
   174  func TestValueArrayAsSlice(t *testing.T) {
   175  	assert.Nil(t, ValueArray{}.AsSlice())
   176  
   177  	a := ValueArrayOf(String("a"), String("b"))
   178  	s := a.AsSlice()
   179  	assert.Equal(t, []Value{String("a"), String("b")}, s)
   180  	shouldNotBeSameSlice(t, a.data, s)
   181  }
   182  
   183  func TestValueArrayAsArbitraryValueSlice(t *testing.T) {
   184  	assert.Nil(t, ValueArray{}.AsArbitraryValueSlice())
   185  
   186  	a := ValueArrayOf(String("a"), String("b"))
   187  	s := a.AsArbitraryValueSlice()
   188  	assert.Equal(t, []interface{}{"a", "b"}, s)
   189  }
   190  
   191  func TestValueArrayTransform(t *testing.T) {
   192  	fnNoChanges := func(index int, value Value) (Value, bool) {
   193  		return value, true
   194  	}
   195  	fnAbsoluteValuesAndNoOddNumbers := func(index int, value Value) (Value, bool) {
   196  		if value.IntValue()%2 == 1 {
   197  			return value, false // first return value should be ignored since second one is false
   198  		}
   199  		if value.IntValue() < 0 {
   200  			return Int(-value.IntValue()), true
   201  		}
   202  		return value, true
   203  	}
   204  	fnTransformUsingIndex := func(index int, value Value) (Value, bool) {
   205  		return String(fmt.Sprintf("%d=%s", index, value.StringValue())), true
   206  	}
   207  
   208  	array1 := ValueArrayOf(Int(2), Int(4), Int(6))
   209  	array1a := array1.Transform(fnNoChanges)
   210  	array1b := array1.Transform(fnAbsoluteValuesAndNoOddNumbers)
   211  	// Should have no changes...
   212  	assert.Equal(t, array1, array1a)
   213  	assert.Equal(t, array1, array1b)
   214  	// ...and should be wrapping the *same* slice, not a copy
   215  	shouldBeSameSlice(t, array1.data, array1a.data)
   216  	shouldBeSameSlice(t, array1.data, array1b.data)
   217  
   218  	array2 := ValueArrayOf(Int(2), Int(4), Int(1), Int(-6))
   219  	array2a := array2.Transform(fnNoChanges)
   220  	array2b := array2.Transform(fnAbsoluteValuesAndNoOddNumbers)
   221  	// array2a should have no changes, and should be wrapping the same slice
   222  	assert.Equal(t, array2, array2a)
   223  	shouldBeSameSlice(t, array2.data, array2a.data)
   224  	// array2b should have a transformed slice
   225  	assert.Equal(t, ValueArrayOf(Int(2), Int(4), Int(6)), array2b)
   226  
   227  	// Same as the array2 tests, except that the first change is a modification, not a deletion
   228  	array3 := ValueArrayOf(Int(2), Int(4), Int(-6), Int(1))
   229  	array3a := array3.Transform(fnNoChanges)
   230  	array3b := array3.Transform(fnAbsoluteValuesAndNoOddNumbers)
   231  	// array3a should have no changes, and should be wrapping the same slice
   232  	assert.Equal(t, array3, array3a)
   233  	shouldBeSameSlice(t, array3.data, array3a.data)
   234  	// array3b should have a transformed slice
   235  	assert.Equal(t, ValueArrayOf(Int(2), Int(4), Int(6)), array3b)
   236  
   237  	// Edge case where the very first element is dropped
   238  	array4 := ValueArrayOf(Int(1), Int(2), Int(4))
   239  	array4b := array4.Transform(fnAbsoluteValuesAndNoOddNumbers)
   240  	assert.Equal(t, ValueArrayOf(Int(2), Int(4)), array4b)
   241  
   242  	// Edge case where the only element is dropped
   243  	array5 := ValueArrayOf(Int(1))
   244  	assert.Equal(t, ValueArrayOf(), array5.Transform(fnAbsoluteValuesAndNoOddNumbers))
   245  
   246  	// Transformation function that uses the index parameter
   247  	array6 := ValueArrayOf(String("a"), String("b"))
   248  	assert.Equal(t, ValueArrayOf(String("0=a"), String("1=b")), array6.Transform(fnTransformUsingIndex))
   249  
   250  	shouldNotCallThis := func(index int, value Value) (Value, bool) {
   251  		assert.Fail(t, "should not have called function")
   252  		return value, true
   253  	}
   254  	assert.Equal(t, ValueArray{}, ValueArray{}.Transform(shouldNotCallThis))
   255  	assert.Equal(t, ValueArrayOf(), ValueArrayOf().Transform(shouldNotCallThis))
   256  }
   257  
   258  func shouldBeSameSlice(t *testing.T, s0 []Value, s1 []Value) {
   259  	old := s0[0]
   260  	s0[0] = String("temp-value")
   261  	assert.Equal(t, s0, s1, "ValueArrays should be sharing same slice but it was copied instead")
   262  	s0[0] = old
   263  }
   264  
   265  func shouldNotBeSameSlice(t *testing.T, s0 []Value, s1 []Value) {
   266  	old := s0[0]
   267  	s0[0] = String("temp-value")
   268  	assert.NotEqual(t, s0, s1, "ValueArrays should not be sharing same slice but they are")
   269  	s0[0] = old
   270  }
   271  

View as plain text