package lduser import ( "testing" "github.com/launchdarkly/go-sdk-common/v3/ldcontext" "github.com/launchdarkly/go-sdk-common/v3/ldvalue" "github.com/stretchr/testify/assert" ) func TestConstructors(t *testing.T) { assert.Equal(t, ldcontext.New("some-key"), NewUser("some-key")) assert.Equal(t, ldcontext.NewBuilder("some-key").Anonymous(true).Build(), NewAnonymousUser("some-key")) } func TestUserBuilderSetsOnlyKeyByDefault(t *testing.T) { c := NewUserBuilder("some-key").Build() assert.Equal(t, ldcontext.Kind("user"), c.Kind()) assert.Equal(t, "some-key", c.Key()) assert.False(t, c.Secondary().IsDefined()) assert.False(t, c.Anonymous()) assert.Len(t, c.GetOptionalAttributeNames(nil), 0) assert.Equal(t, 0, c.PrivateAttributeCount()) } func TestUserBuilderCanSetStringAttributes(t *testing.T) { for a, setter := range optionalStringSetters { t.Run(string(a), func(t *testing.T) { builder := NewUserBuilder("some-key") setter(builder, "value") c := builder.Build() assert.Equal(t, ldcontext.Kind("user"), c.Kind()) assert.Equal(t, "some-key", c.Key()) assert.Equal(t, ldvalue.NewOptionalString("value"), optionalStringGetters[a](c), a) for a1 := range optionalStringSetters { if a1 != a { assertStringAttrNotSet(t, a1, c) } } }) } } func TestUserBuilderCanSetAnonymous(t *testing.T) { user0 := NewUserBuilder("some-key").Build() assert.False(t, user0.Anonymous()) user1 := NewUserBuilder("some-key").Anonymous(true).Build() assert.True(t, user1.Anonymous()) user2 := NewUserBuilder("some-key").Anonymous(false).Build() assert.False(t, user2.Anonymous()) } func TestUserBuilderCanSetPrivateAttributes(t *testing.T) { for a, setter := range optionalStringSetters { t.Run(string(a), func(t *testing.T) { builder := NewUserBuilder("some-key") setter(builder, "value").AsPrivateAttribute() c := builder.Build() assert.Equal(t, "some-key", c.Key()) assert.Equal(t, ldvalue.NewOptionalString("value"), optionalStringGetters[a](c)) value := c.GetValue(string(a)) if a == "secondary" { // "secondary" is no longer addressable as an attribute in evaluations assert.False(t, value.IsDefined()) } else { assert.Equal(t, ldvalue.String("value"), value) } for a1 := range optionalStringSetters { if a1 != a { assertStringAttrNotSet(t, a1, c) } } if string(a) == "secondary" { assert.Len(t, sortedOptionalAttributes(c), 0) } else { assert.Equal(t, []string{string(a)}, sortedOptionalAttributes(c)) } assert.Equal(t, []string{string(a)}, sortedPrivateAttributes(c)) }) } t.Run("custom", func(t *testing.T) { builder := NewUserBuilder("some-key") builder.Custom("my-attr", ldvalue.String("value")).AsPrivateAttribute() c := builder.Build() value := c.GetValue("my-attr") assert.Equal(t, ldvalue.String("value"), value) assert.Equal(t, []string{"my-attr"}, sortedPrivateAttributes(c)) }) t.Run("custom with leading slash", func(t *testing.T) { builder := NewUserBuilder("some-key") builder.Custom("/my-attr", ldvalue.String("value")).AsPrivateAttribute() c := builder.Build() value := c.GetValue("/my-attr") assert.Equal(t, ldvalue.String("value"), value) assert.Equal(t, []string{"/~1my-attr"}, sortedPrivateAttributes(c)) }) } func TestUserBuilderCanMakeAttributeNonPrivate(t *testing.T) { builder := NewUserBuilder("some-key") builder.Country("us").AsNonPrivateAttribute() builder.Email("e").AsPrivateAttribute() builder.Name("n").AsPrivateAttribute() builder.Email("f").AsNonPrivateAttribute() c := builder.Build() value := c.GetValue("email") assert.Equal(t, ldvalue.String("f"), value) assert.Equal(t, []string{"name"}, sortedPrivateAttributes(c)) } func TestUserBuilderCanSetCustomAttributes(t *testing.T) { c := NewUserBuilder("some-key").Custom("first", ldvalue.Int(1)).Custom("second", ldvalue.String("two")).Build() value := c.GetValue("first") assert.Equal(t, 1, value.IntValue()) value = c.GetValue("second") assert.Equal(t, "two", value.StringValue()) value = c.GetValue("no") assert.Equal(t, ldvalue.Null(), value) assert.Equal(t, []string{"first", "second"}, sortedOptionalAttributes(c)) assert.Len(t, sortedPrivateAttributes(c), 0) } func TestUserBuilderCanSetCustomAttributesAsMap(t *testing.T) { valueMap := ldvalue.ValueMapBuild().Set("first", ldvalue.Int(1)).Set("second", ldvalue.String("two")).Build() c := NewUserBuilder("some-key").CustomAll(valueMap).Build() value := c.GetValue("first") assert.Equal(t, ldvalue.Int(1), value) value = c.GetValue("second") assert.Equal(t, ldvalue.String("two"), value) assert.Equal(t, []string{"first", "second"}, sortedOptionalAttributes(c)) } func TestUserBuilderCustomAllReplacesAllCustomAttributes(t *testing.T) { valueMap := ldvalue.ValueMapBuild().Set("second", ldvalue.String("two")).Build() c1 := NewUserBuilder("some-key").Email("my-email").Custom("first", ldvalue.Int(1)). CustomAll(valueMap).Build() assert.Equal(t, []string{"email", "second"}, sortedOptionalAttributes(c1)) c2 := NewUserBuilder("some-key").Email("my-email").Custom("first", ldvalue.Int(1)). CustomAll(ldvalue.ValueMap{}).Build() assert.Equal(t, []string{"email"}, sortedOptionalAttributes(c2)) } func TestUserBuilderCanSetAttributesAfterSettingAttributeThatCanBePrivate(t *testing.T) { // This tests that chaining methods off of UserBuilderCanMakeAttributePrivate works correctly. builder := NewUserBuilder("some-key").Name("original-name").Key("new-key") c := builder.Build() assert.Equal(t, "new-key", c.Key()) } func TestUserBuilderGenericSetAttribute(t *testing.T) { t.Run("key", func(t *testing.T) { builder := NewUserBuilder("some-key") value := "value" builder.SetAttribute(KeyAttribute, ldvalue.String(value)) assert.Equal(t, value, builder.Build().Key()) // setting key to wrong type is a no-op builder.SetAttribute(KeyAttribute, ldvalue.Null()) assert.Equal(t, value, builder.Build().Key()) builder.SetAttribute(KeyAttribute, ldvalue.Bool(true)) assert.Equal(t, value, builder.Build().Key()) builder.SetAttribute(KeyAttribute, ldvalue.String(value)).AsPrivateAttribute() assert.Len(t, sortedPrivateAttributes(builder.Build()), 0) }) for a, getter := range optionalStringGetters { t.Run(string(a), func(t *testing.T) { builder := NewUserBuilder("some-key") valueStr := ldvalue.NewOptionalString("value") value := valueStr.AsValue() builder.SetAttribute(a, value) assert.Equal(t, valueStr, getter(builder.Build())) // setting optional string attribute to wrong type is a no-op builder.SetAttribute(a, ldvalue.Bool(true)) assert.Equal(t, valueStr, getter(builder.Build())) for a1 := range optionalStringGetters { if a1 != a { assertStringAttrNotSet(t, a1, builder.Build()) } } assert.Len(t, sortedPrivateAttributes(builder.Build()), 0) builder.SetAttribute(a, ldvalue.Null()) assert.Equal(t, ldvalue.OptionalString{}, getter(builder.Build())) builder.SetAttribute(a, value).AsPrivateAttribute() assert.Equal(t, []string{string(a)}, sortedPrivateAttributes(builder.Build())) }) } t.Run("anonymous", func(t *testing.T) { builder := NewUserBuilder("some-key") builder.SetAttribute(AnonymousAttribute, ldvalue.Bool(false)) assert.False(t, builder.Build().Anonymous()) builder.SetAttribute(AnonymousAttribute, ldvalue.Bool(true)) assert.True(t, builder.Build().Anonymous()) // setting anonymous to wrong type is a no-op builder.SetAttribute(AnonymousAttribute, ldvalue.String("x")) assert.True(t, builder.Build().Anonymous()) builder.SetAttribute(AnonymousAttribute, ldvalue.Null()) assert.False(t, builder.Build().Anonymous()) }) t.Run("custom", func(t *testing.T) { builder := NewUserBuilder("some-key") name := "thing" value := ldvalue.Int(2) builder.SetAttribute(UserAttribute(name), value) c0 := builder.Build() v := c0.GetValue(name) assert.Equal(t, value, v) assert.Equal(t, []string{name}, sortedOptionalAttributes(c0)) assert.Len(t, sortedPrivateAttributes(c0), 0) builder.SetAttribute(UserAttribute(name), ldvalue.Null()) c1 := builder.Build() v = c1.GetValue(name) assert.Equal(t, ldvalue.Null(), v) assert.Len(t, sortedOptionalAttributes(c1), 0) assert.Len(t, sortedPrivateAttributes(c1), 0) builder.SetAttribute(UserAttribute(name), value).AsPrivateAttribute() c2 := builder.Build() assert.Equal(t, []string{name}, sortedPrivateAttributes(c2)) }) } func TestUserBuilderCanCopyFromExistingUserWithOnlyKey(t *testing.T) { user0 := NewUser("some-key") user1 := NewUserBuilderFromUser(user0).Build() assert.Equal(t, user0, user1) } func TestUserBuilderCanCopyFromExistingUserWithAllAttributes(t *testing.T) { user0 := NewUserBuilder("some-key"). Name("name"). FirstName("firstName"). LastName("lastName"). Email("email").AsPrivateAttribute(). Country("country"). Avatar("avatar"). IP("ip"). Custom("attr", ldvalue.String("value")). Anonymous(true). Build() user1 := NewUserBuilderFromUser(user0).Build() assert.Equal(t, user0, user1) }