55package kotlinx.rpc.protobuf.test
66
77import invoke
8- import kotlinx.rpc.protobuf.test.invoke
98import test.submsg.Other
109import test.submsg.invoke
1110import kotlin.collections.iterator
@@ -16,19 +15,6 @@ import kotlin.test.assertTrue
1615
1716class CopyTest {
1817
19- @Test
20- fun `test list copy - should be real copy` () {
21- val userList = mutableListOf (1 ,2 ,3 )
22- val original = Repeated {
23- listInt32 = userList
24- }
25- val copy = original.copy()
26- userList.add(4 )
27-
28- assertEquals(listOf (1 ,2 ,3 ,4 ), original.listInt32)
29- assertEquals(listOf (1 ,2 ,3 ), copy.listInt32)
30- }
31-
3218 @Test
3319 fun `copy primitives and bytes - equality and independence` () {
3420 val bytesSrc = byteArrayOf(1 , 2 , 3 )
@@ -70,6 +56,8 @@ class CopyTest {
7056 }
7157 val cp = orig.copy()
7258
59+ assertEquals(orig, cp)
60+
7361 // Lists are distinct instances
7462 assertTrue(orig.listMessage != = cp.listMessage)
7563 // Elements are deep-copied
@@ -158,4 +146,132 @@ class CopyTest {
158146 assertEquals(1 , cp2.RequiredPresence )
159147 assertEquals(5f , cp2.OptionalPresence )
160148 }
149+
150+ @Test
151+ fun `copy with user-provided mutable map - mutation after copy should not affect copy` () {
152+ val userMap = mutableMapOf (" a" to 10L , " b" to 20L )
153+ val original = TestMap {
154+ primitives = userMap
155+ }
156+
157+ val copy = original.copy()
158+
159+ // Mutate user's map after copy - should not affect copy
160+ userMap[" c" ] = 30L
161+ userMap[" a" ] = 999L
162+
163+ assertEquals(mapOf (" a" to 10L , " b" to 20L , " c" to 30L , " a" to 999L ), original.primitives)
164+ assertEquals(mapOf (" a" to 10L , " b" to 20L ), copy.primitives)
165+ }
166+
167+ @Test
168+ fun `copy with user-provided bytes - mutation after copy should not affect copy` () {
169+ val userBytes = byteArrayOf(1 , 2 , 3 )
170+ val original = AllPrimitives {
171+ bytes = userBytes
172+ }
173+ val copy = original.copy()
174+ userBytes[0 ] = 99
175+ assertEquals(listOf<Byte >(99 , 2 , 3 ), original.bytes?.toList())
176+ assertEquals(listOf<Byte >(1 , 2 , 3 ), copy.bytes?.toList())
177+ }
178+
179+ @Test
180+ fun `copy with nested messages - user mutation after copy should not affect copy` () {
181+ val userMessages = mutableMapOf (
182+ 1 to PresenceCheck { RequiredPresence = 1 },
183+ 2 to PresenceCheck { RequiredPresence = 2 }
184+ )
185+ val original = TestMap {
186+ messages = userMessages
187+ }
188+
189+ val copy = original.copy()
190+
191+ // Mutate user's map after copy
192+ userMessages[3 ] = PresenceCheck { RequiredPresence = 3 }
193+
194+ // Original has all 3, copy should only have original 2
195+ assertEquals(3 , original.messages.size)
196+ assertEquals(2 , copy.messages.size)
197+ assertEquals(setOf (1 , 2 , 3 ), original.messages.keys)
198+ assertEquals(setOf (1 , 2 ), copy.messages.keys)
199+ }
200+
201+ @Test
202+ fun `copy with bytes - mutating source array after construction should not affect copy` () {
203+ val bytesSrc = byteArrayOf(1 , 2 , 3 )
204+ val msg = AllPrimitives {
205+ bytes = bytesSrc
206+ }
207+
208+ val copy = msg.copy()
209+
210+ // Mutate source array after message creation
211+ bytesSrc[0 ] = 99
212+ bytesSrc[1 ] = 88
213+
214+ // Neither original nor copy should be affected
215+ assertEquals(listOf<Byte >(99 , 88 , 3 ), msg.bytes?.toList())
216+ assertEquals(listOf<Byte >(1 , 2 , 3 ), copy.bytes?.toList())
217+ }
218+
219+ @Test
220+ fun `copy with empty collections` () {
221+ val msg = Repeated {
222+ listInt32 = emptyList()
223+ listMessage = emptyList()
224+ }
225+
226+ val copy = msg.copy()
227+
228+ assertTrue(copy.listInt32.isEmpty())
229+ assertTrue(copy.listMessage.isEmpty())
230+
231+ // Verify they are distinct instances
232+ assertTrue(msg.listInt32 != = copy.listInt32)
233+ assertTrue(msg.listMessage != = copy.listMessage)
234+ }
235+
236+ @Test
237+ fun `copy with nested message in list - mutations after copy don't affect copy` () {
238+ val nestedList = mutableListOf (
239+ Repeated .Other { a = 1 },
240+ Repeated .Other { a = 2 }
241+ )
242+ val original = Repeated {
243+ listMessage = nestedList
244+ }
245+
246+ val copy = original.copy()
247+
248+ // Mutate the user's list after copy
249+ nestedList.add(Repeated .Other { a = 3 })
250+
251+ assertEquals(3 , original.listMessage.size)
252+ assertEquals(2 , copy.listMessage.size)
253+ assertEquals(listOf (1 , 2 , 3 ), original.listMessage.map { it.a })
254+ assertEquals(listOf (1 , 2 ), copy.listMessage.map { it.a })
255+ }
256+
257+ @Test
258+ fun `copy lambda modifications don't affect original` () {
259+ val original = AllPrimitives {
260+ int32 = 10
261+ string = " original"
262+ }
263+
264+ val modified = original.copy {
265+ int32 = 20
266+ string = " modified"
267+ }
268+
269+ // Original should remain unchanged
270+ assertEquals(10 , original.int32)
271+ assertEquals(" original" , original.string)
272+
273+ // Modified should have new values
274+ assertEquals(20 , modified.int32)
275+ assertEquals(" modified" , modified.string)
276+ }
161277}
0 commit comments