...

Source file src/github.com/launchdarkly/go-sdk-common/v3/ldcontext/context_test.go

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

     1  package ldcontext
     2  
     3  import (
     4  	"encoding/json"
     5  	"sort"
     6  	"testing"
     7  
     8  	"github.com/launchdarkly/go-sdk-common/v3/ldattr"
     9  	"github.com/launchdarkly/go-sdk-common/v3/lderrors"
    10  	"github.com/launchdarkly/go-sdk-common/v3/ldvalue"
    11  
    12  	"github.com/launchdarkly/go-test-helpers/v3/jsonhelpers"
    13  
    14  	"github.com/stretchr/testify/assert"
    15  )
    16  
    17  // Note, matchers.JSONEqual is preferred in these tests when checking ldvalue.Value values, rather
    18  // than assert.Equal or assert.JSONEq, because its failure output is easier to read.
    19  
    20  func TestUninitializedContext(t *testing.T) {
    21  	var c Context
    22  	assert.False(t, c.IsDefined())
    23  	assert.Equal(t, lderrors.ErrContextUninitialized{}, c.Err())
    24  }
    25  
    26  func TestMultiple(t *testing.T) {
    27  	sc := New("my-key")
    28  	mc := NewMulti(New("my-key"), NewWithKind("org", "my-key"))
    29  	assert.False(t, sc.Multiple())
    30  	assert.True(t, mc.Multiple())
    31  }
    32  
    33  func TestGetOptionalAttributeNames(t *testing.T) {
    34  	sorted := func(values []string) []string {
    35  		ret := append([]string(nil), values...)
    36  		sort.Strings(ret)
    37  		return ret
    38  	}
    39  
    40  	t.Run("none", func(t *testing.T) {
    41  		c := New("my-key")
    42  		an := c.GetOptionalAttributeNames(nil)
    43  		assert.Len(t, an, 0)
    44  	})
    45  
    46  	t.Run("meta not included", func(t *testing.T) {
    47  		c := NewBuilder("my-key").Private("x").Anonymous(true).Build()
    48  		an := c.GetOptionalAttributeNames(nil)
    49  		assert.Len(t, an, 0)
    50  	})
    51  
    52  	t.Run("name", func(t *testing.T) {
    53  		c := NewBuilder("my-key").Name("x").Build()
    54  		an := c.GetOptionalAttributeNames(nil)
    55  		assert.Equal(t, []string{"name"}, an)
    56  	})
    57  
    58  	t.Run("others", func(t *testing.T) {
    59  		c := NewBuilder("my-key").SetString("email", "x").SetBool("happy", true).Build()
    60  		an := c.GetOptionalAttributeNames(nil)
    61  		sort.Strings(an)
    62  		assert.Equal(t, []string{"email", "happy"}, an)
    63  	})
    64  
    65  	t.Run("none for multi-context", func(t *testing.T) {
    66  		c := NewMulti(NewWithKind("kind1", "key1"), NewWithKind("otherkind", "otherkey"))
    67  		an := c.GetOptionalAttributeNames(nil)
    68  		assert.Len(t, an, 0)
    69  	})
    70  
    71  	t.Run("capacity of preallocated slice can be reused", func(t *testing.T) {
    72  		c := NewBuilder("my-key").SetString("email", "x").SetBool("happy", true).Build()
    73  		preallocSlice := make([]string, 2, 2)
    74  		emptySlice := preallocSlice[0:0]
    75  		an := c.GetOptionalAttributeNames(emptySlice)
    76  		assert.Equal(t, []string{"email", "happy"}, sorted(an))
    77  		preallocSlice[0] = "x"
    78  		assert.Equal(t, "x", an[0])
    79  	})
    80  
    81  	t.Run("preallocated slice is overwritten rather than appended to", func(t *testing.T) {
    82  		c := NewBuilder("my-key").SetString("email", "x").SetBool("happy", true).Build()
    83  		preallocSlice := make([]string, 2, 2)
    84  		an := c.GetOptionalAttributeNames(preallocSlice)
    85  		assert.Equal(t, []string{"email", "happy"}, sorted(an))
    86  		preallocSlice[0] = "x"
    87  		assert.Equal(t, "x", an[0])
    88  	})
    89  
    90  	t.Run("preallocated slice without enough capacity is not reused", func(t *testing.T) {
    91  		c := NewBuilder("my-key").SetString("email", "x").SetBool("happy", true).Build()
    92  		preallocSlice := make([]string, 1, 1)
    93  		emptySlice := preallocSlice[0:0]
    94  		an := c.GetOptionalAttributeNames(emptySlice)
    95  		assert.Equal(t, []string{"email", "happy"}, sorted(an))
    96  		preallocSlice[0] = "x"
    97  		assert.NotEqual(t, "x", an[0])
    98  	})
    99  }
   100  
   101  func TestGetValue(t *testing.T) {
   102  	t.Run("equivalent to GetValueForRef for simple attribute name", func(t *testing.T) {
   103  		c := NewBuilder("my-key").Kind("org").Name("x").SetString("my-attr", "y").SetString("/starts-with-slash", "z").Build()
   104  		expectAttributeFoundForName(t, ldvalue.String("org"), c, "kind")
   105  		expectAttributeFoundForName(t, ldvalue.String("my-key"), c, "key")
   106  		expectAttributeFoundForName(t, ldvalue.String("x"), c, "name")
   107  		expectAttributeFoundForName(t, ldvalue.String("y"), c, "my-attr")
   108  		expectAttributeFoundForName(t, ldvalue.String("z"), c, "/starts-with-slash")
   109  		expectAttributeNotFoundForName(t, c, "/kind")
   110  		expectAttributeNotFoundForName(t, c, "/key")
   111  		expectAttributeNotFoundForName(t, c, "/name")
   112  		expectAttributeNotFoundForName(t, c, "/my-attr")
   113  		expectAttributeNotFoundForName(t, c, "other")
   114  
   115  		expectAttributeNotFoundForName(t, c, "")
   116  		expectAttributeNotFoundForName(t, c, "/")
   117  
   118  		mc := NewMulti(c, NewWithKind("otherkind", "otherkey"))
   119  		expectAttributeFoundForName(t, ldvalue.String("multi"), mc, "kind")
   120  		expectAttributeNotFoundForName(t, mc, "/kind")
   121  		expectAttributeNotFoundForName(t, mc, "key")
   122  	})
   123  
   124  	t.Run("does not allow querying of subpath/element", func(t *testing.T) {
   125  		objValue := ldvalue.ObjectBuild().Set("a", ldvalue.Int(1)).Build()
   126  		arrayValue := ldvalue.ArrayOf(ldvalue.Int(1))
   127  		c := makeBasicBuilder().SetValue("obj-attr", objValue).SetValue("array-attr", arrayValue).Build()
   128  		expectAttributeFoundForName(t, objValue, c, "obj-attr")
   129  		expectAttributeFoundForName(t, arrayValue, c, "array-attr")
   130  		expectAttributeNotFoundForName(t, c, "/obj-attr/a")
   131  		expectAttributeNotFoundForName(t, c, "/array-attr/0")
   132  	})
   133  }
   134  func TestGetValueForRefSpecialTopLevelAttributes(t *testing.T) {
   135  	t.Run("kind", func(t *testing.T) {
   136  		t.Run("single-kind", func(t *testing.T) {
   137  			c := NewWithKind("org", "my-key")
   138  			expectAttributeFoundForRef(t, ldvalue.String("org"), c, "kind")
   139  		})
   140  
   141  		t.Run("multi-kind", func(t *testing.T) {
   142  			c := NewMulti(New("my-key"), NewWithKind("otherkind", "otherkey"))
   143  			expectAttributeFoundForRef(t, ldvalue.String("multi"), c, "kind")
   144  		})
   145  	})
   146  
   147  	t.Run("key", func(t *testing.T) {
   148  		t.Run("single-kind", func(t *testing.T) {
   149  			c := New("my-key")
   150  			expectAttributeFoundForRef(t, ldvalue.String("my-key"), c, "key")
   151  		})
   152  
   153  		t.Run("multi-kind", func(t *testing.T) {
   154  			c := NewMulti(New("my-key"), NewWithKind("otherkind", "otherkey"))
   155  			expectAttributeNotFoundForRef(t, c, "key")
   156  		})
   157  	})
   158  
   159  	t.Run("name", func(t *testing.T) {
   160  		t.Run("single-kind, defined", func(t *testing.T) {
   161  			c := makeBasicBuilder().Name("my-name").Build()
   162  			expectAttributeFoundForRef(t, ldvalue.String("my-name"), c, "name")
   163  		})
   164  
   165  		t.Run("single-kind, undefined", func(t *testing.T) {
   166  			c := makeBasicBuilder().Build()
   167  			expectAttributeNotFoundForRef(t, c, "name")
   168  		})
   169  
   170  		t.Run("multi-kind", func(t *testing.T) {
   171  			c := NewMulti(makeBasicBuilder().Name("my-name").Build(), NewWithKind("otherkind", "otherkey"))
   172  			expectAttributeNotFoundForRef(t, c, "name")
   173  		})
   174  	})
   175  
   176  	t.Run("anonymous", func(t *testing.T) {
   177  		t.Run("single-kind, defined, true", func(t *testing.T) {
   178  			c := makeBasicBuilder().Anonymous(true).Build()
   179  			expectAttributeFoundForRef(t, ldvalue.Bool(true), c, "anonymous")
   180  		})
   181  
   182  		t.Run("single-kind, defined, false", func(t *testing.T) {
   183  			c := makeBasicBuilder().Anonymous(false).Build()
   184  			expectAttributeFoundForRef(t, ldvalue.Bool(false), c, "anonymous")
   185  		})
   186  
   187  		t.Run("single-kind, undefined", func(t *testing.T) {
   188  			c := makeBasicBuilder().Build()
   189  			expectAttributeFoundForRef(t, ldvalue.Bool(false), c, "anonymous")
   190  		})
   191  
   192  		t.Run("multi-kind", func(t *testing.T) {
   193  			c := NewMulti(makeBasicBuilder().Anonymous(true).Build(), NewWithKind("otherkind", "otherkey"))
   194  			expectAttributeNotFoundForRef(t, c, "anonymous")
   195  		})
   196  	})
   197  }
   198  
   199  func TestGetValueForRefCannotGetMetaProperties(t *testing.T) {
   200  	t.Run("privateAttributes", func(t *testing.T) {
   201  		t.Run("single-kind, defined", func(t *testing.T) {
   202  			c := makeBasicBuilder().Private("attr").Build()
   203  			expectAttributeNotFoundForRef(t, c, "privateAttributes")
   204  		})
   205  
   206  		t.Run("single-kind, undefined", func(t *testing.T) {
   207  			c := makeBasicBuilder().Build()
   208  			expectAttributeNotFoundForRef(t, c, "privateAttributes")
   209  		})
   210  
   211  		t.Run("multi-kind", func(t *testing.T) {
   212  			c := NewMultiBuilder().Add(makeBasicBuilder().Private("attr").Build()).Build()
   213  			expectAttributeNotFoundForRef(t, c, "privateAttributes")
   214  		})
   215  	})
   216  }
   217  
   218  func TestGetValueForRefCustomAttributeSingleKind(t *testing.T) {
   219  	t.Run("simple attribute name", func(t *testing.T) {
   220  		expected := ldvalue.String("abc")
   221  		c := makeBasicBuilder().SetValue("my-attr", expected).Build()
   222  		expectAttributeFoundForRef(t, expected, c, "my-attr")
   223  	})
   224  
   225  	t.Run("simple attribute name not found", func(t *testing.T) {
   226  		c := makeBasicBuilder().Build()
   227  		expectAttributeNotFoundForRef(t, c, "my-attr")
   228  	})
   229  
   230  	t.Run("property in object", func(t *testing.T) {
   231  		expected := ldvalue.String("abc")
   232  		object := ldvalue.ObjectBuild().Set("my-prop", expected).Build()
   233  		c := makeBasicBuilder().SetValue("my-attr", object).Build()
   234  		expectAttributeFoundForRef(t, expected, c, "/my-attr/my-prop")
   235  	})
   236  
   237  	t.Run("property in raw JSON object", func(t *testing.T) {
   238  		expected := ldvalue.String("abc")
   239  		object := ldvalue.Raw(json.RawMessage(`{"my-prop": "abc"}`))
   240  		c := makeBasicBuilder().SetValue("my-attr", object).Build()
   241  		expectAttributeFoundForRef(t, expected, c, "/my-attr/my-prop")
   242  	})
   243  
   244  	t.Run("property in object not found", func(t *testing.T) {
   245  		expected := ldvalue.String("abc")
   246  		object := ldvalue.ObjectBuild().Set("my-prop", expected).Build()
   247  		c := makeBasicBuilder().SetValue("my-attr", object).Build()
   248  		expectAttributeNotFoundForRef(t, c, "/my-attr/other-prop")
   249  	})
   250  
   251  	t.Run("property in nested object", func(t *testing.T) {
   252  		expected := ldvalue.String("abc")
   253  		object := ldvalue.ObjectBuild().Set("my-prop", ldvalue.ObjectBuild().Set("sub-prop", expected).Build()).Build()
   254  		c := makeBasicBuilder().SetValue("my-attr", object).Build()
   255  		expectAttributeFoundForRef(t, expected, c, "/my-attr/my-prop/sub-prop")
   256  	})
   257  
   258  	t.Run("property in value that is not an object", func(t *testing.T) {
   259  		c := makeBasicBuilder().SetValue("my-attr", ldvalue.String("xyz")).Build()
   260  		expectAttributeNotFoundForRef(t, c, "/my-attr/my-prop")
   261  	})
   262  
   263  	t.Run("property whose name is a numeric string", func(t *testing.T) {
   264  		expected := ldvalue.String("good")
   265  		object := ldvalue.ObjectBuild().Set("1", expected).Build()
   266  		c := makeBasicBuilder().SetValue("my-attr", object).Build()
   267  		expectAttributeFoundForRef(t, expected, c, "/my-attr/1")
   268  	})
   269  
   270  	t.Run("property not applicable to array", func(t *testing.T) {
   271  		array := ldvalue.ArrayOf(ldvalue.String("bad"), ldvalue.String("worse"))
   272  		c := makeBasicBuilder().SetValue("my-attr", array).Build()
   273  		expectAttributeNotFoundForRef(t, c, "/my-attr/1")
   274  	})
   275  
   276  	t.Run("property not applicable to simple value", func(t *testing.T) {
   277  		c := makeBasicBuilder().SetValue("my-attr", ldvalue.String("xyz")).Build()
   278  		expectAttributeNotFoundForRef(t, c, "/my-attr/a")
   279  	})
   280  }
   281  
   282  func TestContextString(t *testing.T) {
   283  	c := makeBasicBuilder().Name("x").Anonymous(true).SetString("attr", "value").Build()
   284  	j, _ := json.Marshal(c)
   285  	s := c.String()
   286  	jsonhelpers.AssertEqual(t, j, s)
   287  }
   288  
   289  func TestGetValueForInvalidRef(t *testing.T) {
   290  	c := makeBasicBuilder().Build()
   291  	expectAttributeNotFoundForRef(t, c, "/")
   292  }
   293  
   294  func TestIndividualContextCount(t *testing.T) {
   295  	t.Run("single", func(t *testing.T) {
   296  		c := New("my-key")
   297  		assert.Equal(t, 1, c.IndividualContextCount())
   298  	})
   299  
   300  	t.Run("multi", func(t *testing.T) {
   301  		sub1, sub2 := NewWithKind("kind1", "key1"), NewWithKind("kind2", "key2")
   302  		c := NewMulti(sub1, sub2)
   303  		assert.Equal(t, 2, c.IndividualContextCount())
   304  	})
   305  }
   306  
   307  func TestIndividualContextByIndex(t *testing.T) {
   308  	t.Run("single", func(t *testing.T) {
   309  		c := New("my-key")
   310  
   311  		assert.Equal(t, c, c.IndividualContextByIndex(0))
   312  		assert.Equal(t, Context{}, c.IndividualContextByIndex(1))
   313  		assert.Equal(t, Context{}, c.IndividualContextByIndex(-1))
   314  	})
   315  
   316  	t.Run("multi", func(t *testing.T) {
   317  		sub1, sub2 := NewWithKind("kind1", "key1"), NewWithKind("kind2", "key2")
   318  		c := NewMulti(sub1, sub2)
   319  		// We know that these are internally sorted by kind
   320  
   321  		assert.Equal(t, sub1, c.IndividualContextByIndex(0))
   322  		assert.Equal(t, sub2, c.IndividualContextByIndex(1))
   323  		assert.Equal(t, Context{}, c.IndividualContextByIndex(2))
   324  		assert.Equal(t, Context{}, c.IndividualContextByIndex(-1))
   325  	})
   326  }
   327  
   328  func TestIndividualContextByKind(t *testing.T) {
   329  	t.Run("single", func(t *testing.T) {
   330  		c := NewWithKind("kind1", "my-key")
   331  
   332  		assert.Equal(t, c, c.IndividualContextByKind("kind1"))
   333  		assert.Equal(t, Context{}, c.IndividualContextByKind("other"))
   334  	})
   335  
   336  	t.Run("multi", func(t *testing.T) {
   337  		sub1, sub2 := NewWithKind("kind1", "key1"), NewWithKind("kind2", "key2")
   338  		c := NewMulti(sub1, sub2)
   339  
   340  		assert.Equal(t, sub1, c.IndividualContextByKind("kind1"))
   341  		assert.Equal(t, sub2, c.IndividualContextByKind("kind2"))
   342  		assert.Equal(t, Context{}, c.IndividualContextByKind("other"))
   343  	})
   344  
   345  	t.Run("default", func(t *testing.T) {
   346  		sub1, sub2 := New("userkey"), NewWithKind("kind2", "key2")
   347  		c := NewMulti(sub1, sub2)
   348  
   349  		assert.Equal(t, sub1, c.IndividualContextByKind(""))
   350  	})
   351  }
   352  
   353  func TestIndividualContextKeyByKind(t *testing.T) {
   354  	t.Run("single", func(t *testing.T) {
   355  		c := NewWithKind("kind1", "my-key")
   356  
   357  		assert.Equal(t, "my-key", c.IndividualContextKeyByKind("kind1"))
   358  		assert.Equal(t, "", c.IndividualContextKeyByKind("other"))
   359  	})
   360  
   361  	t.Run("multi", func(t *testing.T) {
   362  		sub1, sub2 := NewWithKind("kind1", "key1"), NewWithKind("kind2", "key2")
   363  		c := NewMulti(sub1, sub2)
   364  
   365  		assert.Equal(t, "key1", c.IndividualContextKeyByKind("kind1"))
   366  		assert.Equal(t, "key2", c.IndividualContextKeyByKind("kind2"))
   367  		assert.Equal(t, "", c.IndividualContextKeyByKind("other"))
   368  	})
   369  
   370  	t.Run("default", func(t *testing.T) {
   371  		sub1, sub2 := New("userkey"), NewWithKind("kind2", "key2")
   372  		c := NewMulti(sub1, sub2)
   373  
   374  		assert.Equal(t, "userkey", c.IndividualContextKeyByKind(""))
   375  	})
   376  }
   377  
   378  func TestGetAllIndividualContexts(t *testing.T) {
   379  	t.Run("single", func(t *testing.T) {
   380  		c := NewWithKind("kind1", "my-key")
   381  
   382  		assert.Equal(t, []Context{c}, c.GetAllIndividualContexts(nil))
   383  	})
   384  
   385  	t.Run("multi", func(t *testing.T) {
   386  		sub1, sub2 := NewWithKind("kind1", "key1"), NewWithKind("kind2", "key2")
   387  		c := NewMulti(sub1, sub2)
   388  		// We know that these are internally sorted by kind
   389  
   390  		assert.Equal(t, []Context{sub1, sub2}, c.GetAllIndividualContexts(nil))
   391  	})
   392  
   393  	t.Run("capacity of preallocated slice can be reused", func(t *testing.T) {
   394  		sub1, sub2 := NewWithKind("kind1", "key1"), NewWithKind("kind2", "key2")
   395  		c := NewMulti(sub1, sub2)
   396  
   397  		preallocSlice := make([]Context, 2, 2)
   398  		emptySlice := preallocSlice[0:0]
   399  		all := c.GetAllIndividualContexts(emptySlice)
   400  		assert.Equal(t, []Context{sub1, sub2}, all)
   401  		preallocSlice[0] = New("different")
   402  		assert.Equal(t, preallocSlice[0], all[0])
   403  	})
   404  
   405  	t.Run("preallocated slice is overwritten rather than appended to", func(t *testing.T) {
   406  		sub1, sub2 := NewWithKind("kind1", "key1"), NewWithKind("kind2", "key2")
   407  		c := NewMulti(sub1, sub2)
   408  
   409  		preallocSlice := make([]Context, 2, 2)
   410  		all := c.GetAllIndividualContexts(preallocSlice)
   411  		assert.Equal(t, []Context{sub1, sub2}, all)
   412  		preallocSlice[0] = New("different")
   413  		assert.Equal(t, preallocSlice[0], all[0])
   414  	})
   415  
   416  	t.Run("preallocated slice without enough capacity is not reused", func(t *testing.T) {
   417  		sub1, sub2 := NewWithKind("kind1", "key1"), NewWithKind("kind2", "key2")
   418  		c := NewMulti(sub1, sub2)
   419  
   420  		preallocSlice := make([]Context, 1, 1)
   421  		emptySlice := preallocSlice[0:0]
   422  		all := c.GetAllIndividualContexts(emptySlice)
   423  		assert.Equal(t, []Context{sub1, sub2}, all)
   424  		preallocSlice[0] = New("different")
   425  		assert.NotEqual(t, preallocSlice[0], all[0])
   426  	})
   427  }
   428  
   429  func TestCanGetSecondaryKeyIfPrivatelySet(t *testing.T) {
   430  	c1, c2 := New("key1"), New("key2")
   431  	c2.secondary = ldvalue.NewOptionalString("x")
   432  	assert.Equal(t, ldvalue.OptionalString{}, c1.Secondary())
   433  	assert.Equal(t, c2.secondary, c2.Secondary())
   434  }
   435  
   436  func TestContextEqual(t *testing.T) {
   437  	// Each top-level element in makeInstances is a slice of factories that should produce contexts equal to
   438  	// each other, and unequal to the contexts produced by the factories in any other slice.
   439  	makeInstances := [][]func() Context{
   440  		{func() Context { return Context{} }},
   441  		{func() Context { return New("a") }},
   442  		{func() Context { return New("b") }},
   443  		{func() Context { return NewWithKind("k1", "a") }},
   444  		{func() Context { return NewWithKind("k2", "a") }},
   445  		{func() Context { return NewBuilder("a").Name("b").Build() }},
   446  		{func() Context { return NewBuilder("a").Name("c").Build() }},
   447  		{func() Context { return NewBuilder("a").Anonymous(true).Build() }},
   448  		{func() Context { return NewBuilder("a").SetBool("b", true).Build() }},
   449  		{func() Context { return NewBuilder("a").SetBool("b", false).Build() }},
   450  		{func() Context { return NewBuilder("a").SetInt("b", 0).Build() }},
   451  		{func() Context { return NewBuilder("a").SetInt("b", 1).Build() }},
   452  		{func() Context { return NewBuilder("a").SetString("b", "").Build() }},
   453  		{func() Context { return NewBuilder("a").SetString("b", "c").Build() }},
   454  		{func() Context { return NewBuilder("a").SetBool("b", true).SetBool("c", false).Build() },
   455  			func() Context { return NewBuilder("a").SetBool("c", false).SetBool("b", true).Build() }},
   456  		{func() Context { return NewBuilder("a").Name("b").Private("name").Build() }},
   457  		{func() Context { return NewBuilder("a").Name("b").SetBool("c", true).Private("name").Build() }},
   458  		{func() Context { return NewBuilder("a").Name("b").SetBool("c", true).Private("name", "c").Build() },
   459  			func() Context { return NewBuilder("a").Name("b").SetBool("c", true).Private("c", "name").Build() }},
   460  		{func() Context { return NewBuilder("a").Name("b").SetBool("c", true).Private("name", "d").Build() }},
   461  		{func() Context { return NewMulti(NewWithKind("k1", "a"), NewWithKind("k2", "b")) },
   462  			func() Context { return NewMulti(NewWithKind("k2", "b"), NewWithKind("k1", "a")) }},
   463  		{func() Context { return NewMulti(NewWithKind("k1", "a"), NewWithKind("k2", "c")) }},
   464  		{func() Context { return NewMulti(NewWithKind("k1", "a"), NewWithKind("k3", "b")) }},
   465  		{func() Context {
   466  			return NewMulti(NewWithKind("k1", "a"), NewWithKind("k2", "b"), NewWithKind("k3", "c"))
   467  		}},
   468  	}
   469  	for i, equalGroup := range makeInstances {
   470  		for _, factory1 := range equalGroup {
   471  			c1 := factory1()
   472  			for _, factory2 := range equalGroup {
   473  				c2 := factory2()
   474  				assert.True(t, c1.Equal(c2), "%s should have equaled %s", c1, c2)
   475  			}
   476  			for j, unequalGroup := range makeInstances {
   477  				if i == j {
   478  					continue
   479  				}
   480  				c2 := unequalGroup[0]()
   481  				assert.False(t, c1.Equal(c2), "%s should not have equaled %s", c1, c2)
   482  			}
   483  		}
   484  	}
   485  }
   486  
   487  func expectAttributeFoundForName(t *testing.T, expected ldvalue.Value, c Context, attrName string) {
   488  	t.Helper()
   489  	value := c.GetValue(attrName)
   490  	assert.True(t, value.IsDefined(), "attribute %q should have been found, but was not", attrName)
   491  	jsonhelpers.AssertEqual(t, expected, value)
   492  }
   493  
   494  func expectAttributeNotFoundForName(t *testing.T, c Context, attrName string) {
   495  	t.Helper()
   496  	value := c.GetValue(attrName)
   497  	assert.False(t, value.IsDefined(), "attribute %q should not have been found, but was", attrName)
   498  	jsonhelpers.AssertEqual(t, `null`, value)
   499  }
   500  
   501  func expectAttributeFoundForRef(t *testing.T, expected ldvalue.Value, c Context, attrRefString string) {
   502  	t.Helper()
   503  	value := c.GetValueForRef(ldattr.NewRef(attrRefString))
   504  	assert.True(t, value.IsDefined(), "attribute %q should have been found, but was not", attrRefString)
   505  	jsonhelpers.AssertEqual(t, expected, value)
   506  }
   507  
   508  func expectAttributeNotFoundForRef(t *testing.T, c Context, attrRefString string) {
   509  	t.Helper()
   510  	value := c.GetValueForRef(ldattr.NewRef(attrRefString))
   511  	assert.False(t, value.IsDefined(), "attribute %q should not have been found, but was", attrRefString)
   512  	jsonhelpers.AssertEqual(t, `null`, value)
   513  }
   514  

View as plain text