1- // Copyright © 2021 Kaleido, Inc.
1+ // Copyright © 2024 Kaleido, Inc.
22//
33// SPDX-License-Identifier: Apache-2.0
44//
@@ -18,6 +18,7 @@ package core
1818
1919import (
2020 "context"
21+ "reflect"
2122 "testing"
2223
2324 "github.com/hyperledger/firefly-common/pkg/fftypes"
@@ -97,6 +98,63 @@ func TestOperationTypes(t *testing.T) {
9798 assert .False (t , op .IsBlockchainOperation ())
9899}
99100
101+ func TestOperationDeepCopy (t * testing.T ) {
102+ op := & Operation {
103+ ID : fftypes .NewUUID (),
104+ Namespace : "ns1" ,
105+ Transaction : fftypes .NewUUID (),
106+ Type : OpTypeBlockchainInvoke ,
107+ Status : OpStatusInitialized ,
108+ Plugin : "fake" ,
109+ Input : fftypes.JSONObject {"key" : "value" },
110+ Output : fftypes.JSONObject {"result" : "success" },
111+ Error : "error message" ,
112+ Created : fftypes .Now (),
113+ Updated : fftypes .Now (),
114+ Retry : fftypes .NewUUID (),
115+ }
116+
117+ copyOp := op .DeepCopy ()
118+ shallowCopy := op // Shallow copy for showcasing that DeepCopy is a deep copy
119+
120+ // Ensure the data was copied correctly
121+ assert .Equal (t , op .ID , copyOp .ID )
122+ assert .Equal (t , op .Namespace , copyOp .Namespace )
123+ assert .Equal (t , op .Transaction , copyOp .Transaction )
124+ assert .Equal (t , op .Type , copyOp .Type )
125+ assert .Equal (t , op .Status , copyOp .Status )
126+ assert .Equal (t , op .Plugin , copyOp .Plugin )
127+ assert .Equal (t , op .Input , copyOp .Input )
128+ assert .Equal (t , op .Output , copyOp .Output )
129+ assert .Equal (t , op .Error , copyOp .Error )
130+ assert .Equal (t , op .Created , copyOp .Created )
131+ assert .Equal (t , op .Updated , copyOp .Updated )
132+ assert .Equal (t , op .Retry , copyOp .Retry )
133+
134+ // Modify the original and ensure the copy is not modified
135+ * op .ID = * fftypes .NewUUID ()
136+ assert .NotEqual (t , copyOp .ID , op .ID )
137+
138+ * op .Created = * fftypes .Now ()
139+ assert .NotEqual (t , copyOp .Created , op .Created )
140+
141+ // Ensure the copy is a deep copy by comparing the pointers of the fields
142+ assert .NotSame (t , copyOp .ID , op .ID )
143+ assert .NotSame (t , copyOp .Created , op .Created )
144+ assert .NotSame (t , copyOp .Updated , op .Updated )
145+ assert .NotSame (t , copyOp .Transaction , op .Transaction )
146+ assert .NotSame (t , copyOp .Retry , op .Retry )
147+ assert .NotSame (t , copyOp .Input , op .Input )
148+ assert .NotSame (t , copyOp .Output , op .Output )
149+
150+ // showcasing that the shallow copy is a shallow copy and the copied object value changed as well the pointer has the same address as the original
151+ assert .Equal (t , shallowCopy .ID , op .ID )
152+ assert .Same (t , shallowCopy .ID , op .ID )
153+
154+ // Ensure no new fields are added to the Operation struct
155+ // If a new field is added, this test will fail and the DeepCopy function should be updated
156+ assert .Equal (t , 12 , reflect .TypeOf (Operation {}).NumField ())
157+ }
100158func TestParseNamespacedOpID (t * testing.T ) {
101159
102160 ctx := context .Background ()
@@ -124,3 +182,113 @@ func TestParseNamespacedOpID(t *testing.T) {
124182 assert .Equal (t , "ns1" , ns )
125183
126184}
185+
186+ func TestDeepCopyMapNil (t * testing.T ) {
187+ original := map [string ]interface {}(nil )
188+ copy := deepCopyMap (original )
189+ assert .Nil (t , copy )
190+ }
191+
192+ func TestDeepCopyMapEmpty (t * testing.T ) {
193+ original := map [string ]interface {}{}
194+ copy := deepCopyMap (original )
195+ assert .NotNil (t , copy )
196+ assert .Empty (t , copy )
197+ }
198+
199+ func TestDeepCopyMapSimple (t * testing.T ) {
200+ original := map [string ]interface {}{
201+ "key1" : "value1" ,
202+ "key2" : 42 ,
203+ }
204+ copy := deepCopyMap (original )
205+ assert .Equal (t , original , copy )
206+ }
207+
208+ func TestDeepCopyMapNestedMap (t * testing.T ) {
209+ original := map [string ]interface {}{
210+ "key1" : map [string ]interface {}{
211+ "nestedKey1" : "nestedValue1" ,
212+ },
213+ }
214+ copy := deepCopyMap (original )
215+ assert .Equal (t , original , copy )
216+ assert .NotSame (t , original ["key1" ], copy ["key1" ])
217+ }
218+
219+ func TestDeepCopyMapNestedSlice (t * testing.T ) {
220+ original := map [string ]interface {}{
221+ "key1" : []interface {}{"value1" , 42 },
222+ }
223+ copy := deepCopyMap (original )
224+ assert .Equal (t , original , copy )
225+ assert .NotSame (t , original ["key1" ], copy ["key1" ])
226+ }
227+
228+ func TestDeepCopyMapMixed (t * testing.T ) {
229+ original := map [string ]interface {}{
230+ "key1" : "value1" ,
231+ "key2" : map [string ]interface {}{
232+ "nestedKey1" : "nestedValue1" ,
233+ },
234+ "key3" : []interface {}{"value1" , 42 },
235+ }
236+ copy := deepCopyMap (original )
237+ assert .Equal (t , original , copy )
238+ assert .NotSame (t , original ["key2" ], copy ["key2" ])
239+ assert .NotSame (t , original ["key3" ], copy ["key3" ])
240+ }
241+
242+ func TestDeepCopySliceNil (t * testing.T ) {
243+ original := []interface {}(nil )
244+ copy := deepCopySlice (original )
245+ assert .Nil (t , copy )
246+ }
247+
248+ func TestDeepCopySliceEmpty (t * testing.T ) {
249+ original := []interface {}{}
250+ copy := deepCopySlice (original )
251+ assert .NotNil (t , copy )
252+ assert .Empty (t , copy )
253+ }
254+
255+ func TestDeepCopySliceSimple (t * testing.T ) {
256+ original := []interface {}{"value1" , 42 }
257+ copy := deepCopySlice (original )
258+ assert .Equal (t , original , copy )
259+ }
260+
261+ func TestDeepCopySliceNestedMap (t * testing.T ) {
262+ original := []interface {}{
263+ map [string ]interface {}{
264+ "nestedKey1" : "nestedValue1" ,
265+ },
266+ }
267+ copy := deepCopySlice (original )
268+ assert .Equal (t , original , copy )
269+ assert .NotSame (t , original [0 ], copy [0 ])
270+ }
271+
272+ func TestDeepCopySliceNestedSlice (t * testing.T ) {
273+ original := []interface {}{
274+ []interface {}{"value1" , 42 },
275+ }
276+ copy := deepCopySlice (original )
277+ assert .Equal (t , original , copy )
278+ assert .NotSame (t , original [0 ], copy [0 ])
279+ }
280+
281+ func TestDeepCopySliceMixed (t * testing.T ) {
282+ original := []interface {}{
283+ "value1" ,
284+ 42 ,
285+ map [string ]interface {}{
286+ "nestedKey1" : "nestedValue1" ,
287+ },
288+ []interface {}{"value2" , 43 },
289+ }
290+ copy := deepCopySlice (original )
291+ assert .Equal (t , original , copy )
292+ assert .NotSame (t , original [2 ], copy [2 ])
293+ assert .NotSame (t , original [3 ], copy [3 ])
294+ }
0 commit comments