Skip to content

Commit f9d8015

Browse files
fix: reorder attribute merge to apply user attributes first
1 parent 72ae46c commit f9d8015

File tree

2 files changed

+62
-1
lines changed

2 files changed

+62
-1
lines changed

src/main/kotlin/com/mparticle/kits/RoktKit.kt

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -212,7 +212,7 @@ class RoktKit :
212212
filterUser: FilteredMParticleUser?,
213213
attributes: Map<String, String>,
214214
): Map<String, String> {
215-
val finalAttributes = filterAttributes(attributes, configuration)
215+
val finalAttributes = mutableMapOf<String, String>()
216216

217217
filterUser?.userAttributes?.let { userAttrs ->
218218
for ((key, value) in userAttrs) {
@@ -222,6 +222,8 @@ class RoktKit :
222222
}
223223
}
224224

225+
finalAttributes.putAll(filterAttributes(attributes, configuration))
226+
225227
filterUser?.id?.toString()?.let { mpid ->
226228
finalAttributes[MPID] = mpid
227229
} ?: Logger.warning("RoktKit: No user ID available for placement")

src/test/kotlin/com/mparticle/kits/RoktKitTests.kt

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,65 @@ class RoktKitTests {
122122
assertEquals("123", result["attr_non_string"])
123123
}
124124

125+
126+
@Test
127+
fun test_prepareFinalAttributes_handlesSameKeysInAttributesAndUserAttributes() {
128+
val mockFilterUser = mock(FilteredMParticleUser::class.java)
129+
Mockito.`when`(mockFilterUser.userIdentities).thenReturn(HashMap())
130+
131+
// Include a null value and a non-null non-string value to verify toString() behavior
132+
val userAttributes = HashMap<String, Any?>()
133+
userAttributes["attr_non_null_string"] = "value"
134+
userAttributes["attr_null"] = null
135+
userAttributes["attr_non_string"] = 123
136+
userAttributes["user_key"] = "1231545"
137+
Mockito.`when`(mockFilterUser.userAttributes).thenReturn(userAttributes)
138+
// Set up the configuration with our test filters
139+
val jsonObject = JSONObject()
140+
try {
141+
val filteredKey: String = KitUtils.hashForFiltering("ShouldFilter").toString()
142+
val filteredKey2: String = KitUtils.hashForFiltering("ShouldFilter_key_2").toString()
143+
jsonObject.put(filteredKey, 0)
144+
jsonObject.put(filteredKey2, 1)
145+
} catch (e: Exception) {
146+
println("Exception occurred: ${e.message}")
147+
}
148+
val json = JSONObject()
149+
json.put("ua", jsonObject)
150+
151+
152+
roktKit.configuration = MockKitConfiguration.createKitConfiguration(JSONObject().put("hs", json))
153+
val method: Method = RoktKit::class.java.getDeclaredMethod(
154+
"prepareFinalAttributes",
155+
FilteredMParticleUser::class.java,
156+
Map::class.java,
157+
)
158+
method.isAccessible = true
159+
160+
val inputAttributes: Map<String, String> = mapOf(
161+
"key1" to "value1",
162+
"key2" to "value2",
163+
"key3" to "value3",
164+
"user_key" to "2223333",
165+
)
166+
val result = method.invoke(roktKit, mockFilterUser, inputAttributes) as Map<*, *>
167+
assertEquals(7, result.size)
168+
169+
assertTrue(result.containsKey("user_key"))
170+
//It should always use the value from attributes
171+
assertEquals("2223333", result["user_key"])
172+
assertTrue(result.containsKey("key1"))
173+
assertTrue(result.containsKey("key2"))
174+
assertTrue(result.containsKey("key3"))
175+
assertTrue(result.containsKey("attr_non_null_string"))
176+
assertEquals("value", result["attr_non_null_string"])
177+
178+
assertFalse(result.containsKey("attr_null"))
179+
180+
assertTrue(result.containsKey("attr_non_string"))
181+
assertEquals("123", result["attr_non_string"])
182+
}
183+
125184
private inner class TestKitManager :
126185
KitManagerImpl(context, null, TestCoreCallbacks(), mock(MParticleOptions::class.java)) {
127186
var attributes = HashMap<String, String>()

0 commit comments

Comments
 (0)