@@ -70,6 +70,113 @@ public void testCreateUserOnlyUserId() {
7070 Assert .assertEquals (user .getUserId (), "user-4567" );
7171 }
7272
73+ @ Test
74+ public void testFromEvaluationContextWithUserId () {
75+ Map <String , Value > apiAttrs = new LinkedHashMap ();
76+ apiAttrs .put ("userId" , new Value ("test-userId-123" ));
77+
78+ // ensure fallback to userId when target key and user_id are null
79+ EvaluationContext ctx = new MutableContext (null , apiAttrs );
80+ DevCycleUser user = DevCycleUser .fromEvaluationContext (ctx );
81+ Assert .assertEquals (user .getUserId (), "test-userId-123" );
82+
83+ // ensure fallback to userId when target key and user_id are empty
84+ ctx = new MutableContext ("" , apiAttrs );
85+ user = DevCycleUser .fromEvaluationContext (ctx );
86+ Assert .assertEquals (user .getUserId (), "test-userId-123" );
87+ }
88+
89+ @ Test
90+ public void testFromEvaluationContextUserIdPriorityOrder () {
91+ Map <String , Value > apiAttrs = new LinkedHashMap ();
92+ apiAttrs .put ("user_id" , new Value ("user_id_value" ));
93+ apiAttrs .put ("userId" , new Value ("userId_value" ));
94+
95+ // Test priority: targetingKey > user_id > userId
96+ // When all three are present, targetingKey should win
97+ EvaluationContext ctx = new MutableContext ("targetingKey_value" , apiAttrs );
98+ DevCycleUser user = DevCycleUser .fromEvaluationContext (ctx );
99+ Assert .assertEquals (user .getUserId (), "targetingKey_value" );
100+
101+ // When targetingKey is null, user_id should win over userId
102+ ctx = new MutableContext (null , apiAttrs );
103+ user = DevCycleUser .fromEvaluationContext (ctx );
104+ Assert .assertEquals (user .getUserId (), "user_id_value" );
105+
106+ // When targetingKey is empty, user_id should win over userId
107+ ctx = new MutableContext ("" , apiAttrs );
108+ user = DevCycleUser .fromEvaluationContext (ctx );
109+ Assert .assertEquals (user .getUserId (), "user_id_value" );
110+
111+ // When only userId is present, it should be used
112+ Map <String , Value > userIdOnlyAttrs = new LinkedHashMap ();
113+ userIdOnlyAttrs .put ("userId" , new Value ("userId_only_value" ));
114+ ctx = new MutableContext (null , userIdOnlyAttrs );
115+ user = DevCycleUser .fromEvaluationContext (ctx );
116+ Assert .assertEquals (user .getUserId (), "userId_only_value" );
117+ }
118+
119+ @ Test
120+ public void testFromEvaluationContextUserIdExcludedFromCustomData () {
121+ Map <String , Value > apiAttrs = new LinkedHashMap ();
122+ apiAttrs .put ("userId" , new Value ("test-userId-123" ));
123+ apiAttrs .put ("customField" , new Value ("customValue" ));
124+
125+ // When userId is used as the user ID, it should be excluded from custom data
126+ EvaluationContext ctx = new MutableContext (null , apiAttrs );
127+ DevCycleUser user = DevCycleUser .fromEvaluationContext (ctx );
128+
129+ Assert .assertEquals (user .getUserId (), "test-userId-123" );
130+ Assert .assertNotNull (user .getCustomData ());
131+ Assert .assertEquals (user .getCustomData ().size (), 1 );
132+ Assert .assertEquals (user .getCustomData ().get ("customField" ), "customValue" );
133+ Assert .assertFalse (user .getCustomData ().containsKey ("userId" ));
134+ }
135+
136+ @ Test
137+ public void testFromEvaluationContextAllUserIdFieldsExcludedFromCustomData () {
138+ Map <String , Value > apiAttrs = new LinkedHashMap ();
139+ apiAttrs .put ("user_id" , new Value ("user_id_value" ));
140+ apiAttrs .put ("userId" , new Value ("userId_value" ));
141+ apiAttrs .put ("customField" , new Value ("customValue" ));
142+
143+ // All user ID fields should be excluded from custom data regardless of which is used
144+ EvaluationContext ctx = new MutableContext (null , apiAttrs );
145+ DevCycleUser user = DevCycleUser .fromEvaluationContext (ctx );
146+
147+ Assert .assertEquals (user .getUserId (), "user_id_value" );
148+ Assert .assertNotNull (user .getCustomData ());
149+ Assert .assertEquals (user .getCustomData ().size (), 1 );
150+ Assert .assertEquals (user .getCustomData ().get ("customField" ), "customValue" );
151+ Assert .assertFalse (user .getCustomData ().containsKey ("userId" ));
152+ Assert .assertFalse (user .getCustomData ().containsKey ("user_id" ));
153+ Assert .assertFalse (user .getCustomData ().containsKey ("targetingKey" ));
154+ }
155+
156+ @ Test
157+ public void testFromEvaluationContextInvalidUserIdTypes () {
158+ Map <String , Value > apiAttrs = new LinkedHashMap ();
159+
160+ // Test with non-string userId value - should be ignored
161+ apiAttrs .put ("userId" , new Value (123 ));
162+ EvaluationContext ctx = new MutableContext (null , apiAttrs );
163+
164+ try {
165+ DevCycleUser .fromEvaluationContext (ctx );
166+ Assert .fail ("Expected TargetingKeyMissingError" );
167+ } catch (TargetingKeyMissingError e ) {
168+ // expected
169+ }
170+
171+ // Test with non-string user_id value but valid userId string - should use userId
172+ apiAttrs .put ("user_id" , new Value (456 ));
173+ apiAttrs .put ("userId" , new Value ("valid-userId" ));
174+ ctx = new MutableContext (null , apiAttrs );
175+
176+ DevCycleUser user = DevCycleUser .fromEvaluationContext (ctx );
177+ Assert .assertEquals (user .getUserId (), "valid-userId" );
178+ }
179+
73180 @ Test
74181 public void testCreateUserWithAttributes () {
75182 Map <String , Value > apiAttrs = new LinkedHashMap ();
0 commit comments