github.com/prebid/prebid-server/v2@v2.18.0/ortb/clone_test.go (about) 1 package ortb 2 3 import ( 4 "encoding/json" 5 "reflect" 6 "testing" 7 8 "github.com/prebid/openrtb/v20/adcom1" 9 "github.com/prebid/openrtb/v20/openrtb2" 10 "github.com/prebid/prebid-server/v2/util/ptrutil" 11 "github.com/stretchr/testify/assert" 12 ) 13 14 func TestCloneDataSlice(t *testing.T) { 15 t.Run("nil", func(t *testing.T) { 16 result := CloneDataSlice(nil) 17 assert.Nil(t, result) 18 }) 19 20 t.Run("empty", func(t *testing.T) { 21 given := []openrtb2.Data{} 22 result := CloneDataSlice(given) 23 assert.Empty(t, result) 24 assert.NotSame(t, given, result) 25 }) 26 27 t.Run("one", func(t *testing.T) { 28 given := []openrtb2.Data{ 29 {ID: "1", Ext: json.RawMessage(`{"anyField":1}`)}, 30 } 31 result := CloneDataSlice(given) 32 assert.Equal(t, given, result, "equality") 33 assert.NotSame(t, given[0], result[0], "item-pointer") 34 assert.NotSame(t, given[0].Ext, result[0].Ext, "item-pointer-ext") 35 }) 36 37 t.Run("many", func(t *testing.T) { 38 given := []openrtb2.Data{ 39 {ID: "1", Ext: json.RawMessage(`{"anyField":1}`)}, 40 {ID: "2", Ext: json.RawMessage(`{"anyField":2}`)}, 41 } 42 result := CloneDataSlice(given) 43 assert.Equal(t, given, result, "equality") 44 assert.NotSame(t, given[0], result[0], "item0-pointer") 45 assert.NotSame(t, given[0].Ext, result[0].Ext, "item0-pointer-ext") 46 assert.NotSame(t, given[1], result[1], "item1-pointer") 47 assert.NotSame(t, given[1].Ext, result[1].Ext, "item1-pointer-ext") 48 }) 49 } 50 51 func TestCloneData(t *testing.T) { 52 t.Run("populated", func(t *testing.T) { 53 given := openrtb2.Data{ 54 ID: "anyID", 55 Name: "anyName", 56 Segment: []openrtb2.Segment{{ID: "1", Ext: json.RawMessage(`{"anyField":1}`)}}, 57 Ext: json.RawMessage(`{"anyField":1}`), 58 } 59 result := CloneData(given) 60 assert.Equal(t, given, result, "equality") 61 assert.NotSame(t, given, result, "pointer") 62 assert.NotSame(t, given.Segment, result.Segment, "segment") 63 assert.NotSame(t, given.Segment[0], result.Segment[0], "segment-item") 64 assert.NotSame(t, given.Segment[0].Ext, result.Segment[0].Ext, "segment-item-ext") 65 assert.NotSame(t, given.Ext, result.Ext, "ext") 66 }) 67 68 t.Run("assumptions", func(t *testing.T) { 69 assert.ElementsMatch(t, discoverPointerFields(reflect.TypeOf(openrtb2.Data{})), 70 []string{ 71 "Segment", 72 "Ext", 73 }) 74 }) 75 } 76 77 func TestCloneSegmentSlice(t *testing.T) { 78 t.Run("nil", func(t *testing.T) { 79 result := CloneSegmentSlice(nil) 80 assert.Nil(t, result) 81 }) 82 83 t.Run("empty", func(t *testing.T) { 84 given := []openrtb2.Segment{} 85 result := CloneSegmentSlice(given) 86 assert.Empty(t, result) 87 assert.NotSame(t, given, result) 88 }) 89 90 t.Run("one", func(t *testing.T) { 91 given := []openrtb2.Segment{ 92 {ID: "1", Ext: json.RawMessage(`{"anyField":1}`)}, 93 } 94 result := CloneSegmentSlice(given) 95 assert.Equal(t, given, result, "equality") 96 assert.NotSame(t, given[0], result[0], "item-pointer") 97 assert.NotSame(t, given[0].Ext, result[0].Ext, "item-pointer-ext") 98 }) 99 100 t.Run("many", func(t *testing.T) { 101 given := []openrtb2.Segment{ 102 {Ext: json.RawMessage(`{"anyField":1}`)}, 103 {Ext: json.RawMessage(`{"anyField":2}`)}, 104 } 105 result := CloneSegmentSlice(given) 106 assert.Equal(t, given, result, "equality") 107 assert.NotSame(t, given[0], result[0], "item0-pointer") 108 assert.NotSame(t, given[0].Ext, result[0].Ext, "item0-pointer-ext") 109 assert.NotSame(t, given[1], result[1], "item1-pointer") 110 assert.NotSame(t, given[1].Ext, result[1].Ext, "item1-pointer-ext") 111 }) 112 } 113 114 func TestCloneSegment(t *testing.T) { 115 t.Run("populated", func(t *testing.T) { 116 given := openrtb2.Segment{ 117 ID: "anyID", 118 Name: "anyName", 119 Value: "anyValue", 120 Ext: json.RawMessage(`{"anyField":1}`), 121 } 122 result := CloneSegment(given) 123 assert.Equal(t, given, result, "equality") 124 assert.NotSame(t, given, result, "pointer") 125 assert.NotSame(t, given.Ext, result.Ext, "ext") 126 }) 127 128 t.Run("assumptions", func(t *testing.T) { 129 assert.ElementsMatch(t, discoverPointerFields(reflect.TypeOf(openrtb2.Segment{})), 130 []string{ 131 "Ext", 132 }) 133 }) 134 } 135 136 func TestCloneUser(t *testing.T) { 137 t.Run("nil", func(t *testing.T) { 138 result := CloneUser(nil) 139 assert.Nil(t, result) 140 }) 141 142 t.Run("empty", func(t *testing.T) { 143 given := &openrtb2.User{} 144 result := CloneUser(given) 145 assert.Empty(t, result) 146 assert.NotSame(t, given, result) 147 }) 148 149 t.Run("populated", func(t *testing.T) { 150 given := &openrtb2.User{ 151 ID: "anyID", 152 BuyerUID: "anyBuyerUID", 153 Yob: 1, 154 Gender: "anyGender", 155 Keywords: "anyKeywords", 156 KwArray: []string{"key1"}, 157 CustomData: "anyCustomData", 158 Geo: &openrtb2.Geo{Lat: ptrutil.ToPtr(1.2), Lon: ptrutil.ToPtr(2.3), Ext: json.RawMessage(`{"geo":1}`)}, 159 Data: []openrtb2.Data{{ID: "1", Ext: json.RawMessage(`{"data":1}`)}}, 160 Consent: "anyConsent", 161 EIDs: []openrtb2.EID{{Source: "1", Ext: json.RawMessage(`{"eid":1}`)}}, 162 Ext: json.RawMessage(`{"anyField":1}`), 163 } 164 result := CloneUser(given) 165 assert.Equal(t, given, result, "equality") 166 assert.NotSame(t, given, result, "pointer") 167 assert.NotSame(t, given.KwArray, result.KwArray, "cat") 168 assert.NotSame(t, given.Geo, result.Geo, "geo") 169 assert.NotSame(t, given.Geo.Ext, result.Geo.Ext, "geo-ext") 170 assert.NotSame(t, given.Data[0], result.Data[0], "data-item") 171 assert.NotSame(t, given.Data[0].Ext, result.Data[0].Ext, "data-item-ext") 172 assert.NotSame(t, given.EIDs[0], result.EIDs[0], "eids-item") 173 assert.NotSame(t, given.EIDs[0].Ext, result.EIDs[0].Ext, "eids-item-ext") 174 assert.NotSame(t, given.Ext, result.Ext, "ext") 175 }) 176 177 t.Run("assumptions", func(t *testing.T) { 178 assert.ElementsMatch(t, discoverPointerFields(reflect.TypeOf(openrtb2.User{})), 179 []string{ 180 "KwArray", 181 "Geo", 182 "Data", 183 "EIDs", 184 "Ext", 185 }) 186 }) 187 } 188 189 func TestCloneDevice(t *testing.T) { 190 t.Run("nil", func(t *testing.T) { 191 result := CloneDevice(nil) 192 assert.Nil(t, result) 193 }) 194 195 t.Run("empty", func(t *testing.T) { 196 given := &openrtb2.Device{} 197 result := CloneDevice(given) 198 assert.Empty(t, result) 199 assert.NotSame(t, given, result) 200 }) 201 202 t.Run("populated", func(t *testing.T) { 203 var n int8 = 1 204 np := &n 205 ct := adcom1.ConnectionWIFI 206 207 given := &openrtb2.Device{ 208 Geo: &openrtb2.Geo{Lat: ptrutil.ToPtr(1.2), Lon: ptrutil.ToPtr(2.3), Ext: json.RawMessage(`{"geo":1}`)}, 209 DNT: np, 210 Lmt: np, 211 UA: "UserAgent", 212 SUA: &openrtb2.UserAgent{Mobile: np, Model: "iPad"}, 213 IP: "127.0.0.1", 214 IPv6: "2001::", 215 DeviceType: adcom1.DeviceTablet, 216 Make: "Apple", 217 Model: "iPad", 218 OS: "macOS", 219 OSV: "1.2.3", 220 HWV: "mini", 221 H: 20, 222 W: 30, 223 PPI: 100, 224 PxRatio: 200, 225 JS: ptrutil.ToPtr[int8](2), 226 GeoFetch: ptrutil.ToPtr[int8](4), 227 FlashVer: "1.22.33", 228 Language: "En", 229 LangB: "ENG", 230 Carrier: "AT&T", 231 MCCMNC: "111-222", 232 ConnectionType: &ct, 233 IFA: "IFA", 234 DIDSHA1: "DIDSHA1", 235 DIDMD5: "DIDMD5", 236 DPIDSHA1: "DPIDSHA1", 237 DPIDMD5: "DPIDMD5", 238 MACSHA1: "MACSHA1", 239 MACMD5: "MACMD5", 240 Ext: json.RawMessage(`{"anyField":1}`), 241 } 242 result := CloneDevice(given) 243 assert.Equal(t, given, result, "equality") 244 assert.NotSame(t, given, result, "pointer") 245 assert.NotSame(t, given.Geo, result.Geo, "geo") 246 assert.NotSame(t, given.Geo.Ext, result.Geo.Ext, "geo-ext") 247 assert.NotSame(t, given.DNT, result.DNT, "dnt") 248 assert.NotSame(t, given.Lmt, result.Lmt, "lmt") 249 assert.NotSame(t, given.SUA, result.SUA, "sua") 250 assert.NotSame(t, given.JS, result.JS, "js") 251 assert.NotSame(t, given.GeoFetch, result.GeoFetch, "geofetch") 252 assert.NotSame(t, given.ConnectionType, result.ConnectionType, "connectionType") 253 assert.NotSame(t, given.Ext, result.Ext, "ext") 254 }) 255 256 t.Run("assumptions", func(t *testing.T) { 257 assert.ElementsMatch(t, discoverPointerFields(reflect.TypeOf(openrtb2.Device{})), 258 []string{ 259 "Geo", 260 "DNT", 261 "Lmt", 262 "SUA", 263 "JS", 264 "GeoFetch", 265 "ConnectionType", 266 "Ext", 267 }) 268 }) 269 } 270 271 func TestCloneUserAgent(t *testing.T) { 272 t.Run("nil", func(t *testing.T) { 273 result := CloneUserAgent(nil) 274 assert.Nil(t, result) 275 }) 276 277 t.Run("empty", func(t *testing.T) { 278 given := &openrtb2.UserAgent{} 279 result := CloneUserAgent(given) 280 assert.Empty(t, result) 281 assert.NotSame(t, given, result) 282 }) 283 284 t.Run("populated", func(t *testing.T) { 285 var n int8 = 1 286 np := &n 287 288 given := &openrtb2.UserAgent{ 289 Browsers: []openrtb2.BrandVersion{{Brand: "Apple"}}, 290 Platform: &openrtb2.BrandVersion{Brand: "Apple"}, 291 Mobile: np, 292 Architecture: "X86", 293 Bitness: "64", 294 Model: "iPad", 295 Source: adcom1.UASourceLowEntropy, 296 Ext: json.RawMessage(`{"anyField":1}`), 297 } 298 result := CloneUserAgent(given) 299 assert.Equal(t, given, result, "equality") 300 assert.NotSame(t, given, result, "pointer") 301 assert.NotSame(t, given.Browsers, result.Browsers, "browsers") 302 assert.NotSame(t, given.Platform, result.Platform, "platform") 303 assert.NotSame(t, given.Mobile, result.Mobile, "mobile") 304 assert.NotSame(t, given.Architecture, result.Architecture, "architecture") 305 assert.NotSame(t, given.Ext, result.Ext, "ext") 306 }) 307 308 t.Run("assumptions", func(t *testing.T) { 309 assert.ElementsMatch(t, discoverPointerFields(reflect.TypeOf(openrtb2.UserAgent{})), 310 []string{ 311 "Browsers", 312 "Platform", 313 "Mobile", 314 "Ext", 315 }) 316 }) 317 } 318 319 func TestCloneBrandVersionSlice(t *testing.T) { 320 t.Run("nil", func(t *testing.T) { 321 result := CloneBrandVersionSlice(nil) 322 assert.Nil(t, result) 323 }) 324 325 t.Run("empty", func(t *testing.T) { 326 given := []openrtb2.BrandVersion{} 327 result := CloneBrandVersionSlice(given) 328 assert.Empty(t, result) 329 assert.NotSame(t, given, result) 330 }) 331 332 t.Run("one", func(t *testing.T) { 333 given := []openrtb2.BrandVersion{ 334 {Brand: "1", Version: []string{"s1", "s2"}, Ext: json.RawMessage(`{"anyField":1}`)}, 335 } 336 result := CloneBrandVersionSlice(given) 337 assert.Equal(t, given, result, "equality") 338 assert.NotSame(t, given[0], result[0], "item-pointer") 339 assert.NotSame(t, given[0].Ext, result[0].Ext, "item-pointer-ext") 340 }) 341 342 t.Run("many", func(t *testing.T) { 343 given := []openrtb2.BrandVersion{ 344 {Brand: "1", Version: []string{"s1", "s2"}, Ext: json.RawMessage(`{"anyField":1}`)}, 345 {Brand: "2", Version: []string{"s3", "s4"}, Ext: json.RawMessage(`{"anyField":1}`)}, 346 {Brand: "3", Version: []string{"s5", "s6"}, Ext: json.RawMessage(`{"anyField":1}`)}, 347 } 348 result := CloneBrandVersionSlice(given) 349 assert.Equal(t, given, result, "equality") 350 assert.NotSame(t, given[0], result[0], "item0-pointer") 351 assert.NotSame(t, given[0].Ext, result[0].Ext, "item0-pointer-ext") 352 assert.NotSame(t, given[1], result[1], "item1-pointer") 353 assert.NotSame(t, given[1].Ext, result[1].Ext, "item1-pointer-ext") 354 assert.NotSame(t, given[2], result[2], "item1-pointer") 355 assert.NotSame(t, given[2].Ext, result[2].Ext, "item1-pointer-ext") 356 }) 357 } 358 359 func TestCloneBrandVersion(t *testing.T) { 360 t.Run("nil", func(t *testing.T) { 361 result := CloneBrandVersion(nil) 362 assert.Nil(t, result) 363 }) 364 365 t.Run("empty", func(t *testing.T) { 366 given := &openrtb2.BrandVersion{} 367 result := CloneBrandVersion(given) 368 assert.Empty(t, result) 369 assert.NotSame(t, given, result) 370 }) 371 372 t.Run("populated", func(t *testing.T) { 373 given := &openrtb2.BrandVersion{ 374 Brand: "Apple", 375 Version: []string{"s1"}, 376 Ext: json.RawMessage(`{"anyField":1}`), 377 } 378 result := CloneBrandVersion(given) 379 assert.Equal(t, given, result, "equality") 380 assert.NotSame(t, given, result, "pointer") 381 assert.NotSame(t, given.Ext, result.Ext, "ext") 382 }) 383 384 t.Run("assumptions", func(t *testing.T) { 385 assert.ElementsMatch(t, discoverPointerFields(reflect.TypeOf(openrtb2.BrandVersion{})), 386 []string{ 387 "Version", 388 "Ext", 389 }) 390 }) 391 } 392 393 func TestCloneSource(t *testing.T) { 394 t.Run("nil", func(t *testing.T) { 395 result := CloneSource(nil) 396 assert.Nil(t, result) 397 }) 398 399 t.Run("empty", func(t *testing.T) { 400 given := &openrtb2.Source{} 401 result := CloneSource(given) 402 assert.Empty(t, result) 403 assert.NotSame(t, given, result) 404 }) 405 406 t.Run("populated", func(t *testing.T) { 407 408 given := &openrtb2.Source{ 409 FD: ptrutil.ToPtr[int8](1), 410 TID: "Tid", 411 PChain: "PChain", 412 SChain: &openrtb2.SupplyChain{ 413 Complete: 1, 414 Nodes: []openrtb2.SupplyChainNode{ 415 {ASI: "asi", Ext: json.RawMessage(`{"anyField":1}`)}, 416 }, 417 Ext: json.RawMessage(`{"anyField":2}`), 418 }, 419 Ext: json.RawMessage(`{"anyField":1}`), 420 } 421 result := CloneSource(given) 422 assert.Equal(t, given, result, "equality") 423 assert.NotSame(t, given, result, "pointer") 424 assert.NotSame(t, given.FD, result.FD, "fd") 425 assert.NotSame(t, given.SChain, result.SChain, "schain") 426 assert.NotSame(t, given.SChain.Ext, result.SChain.Ext, "schain.ext") 427 assert.NotSame(t, given.Ext, result.Ext, "ext") 428 assert.NotSame(t, given.SChain.Nodes[0].Ext, result.SChain.Nodes[0].Ext, "schain.nodes.ext") 429 }) 430 431 t.Run("assumptions", func(t *testing.T) { 432 assert.ElementsMatch(t, discoverPointerFields(reflect.TypeOf(openrtb2.Source{})), 433 []string{ 434 "FD", 435 "SChain", 436 "Ext", 437 }) 438 }) 439 } 440 441 func TestCloneSChain(t *testing.T) { 442 t.Run("nil", func(t *testing.T) { 443 result := CloneSource(nil) 444 assert.Nil(t, result) 445 }) 446 447 t.Run("empty", func(t *testing.T) { 448 given := &openrtb2.SupplyChain{} 449 result := CloneSChain(given) 450 assert.Empty(t, result) 451 assert.NotSame(t, given, result) 452 }) 453 454 t.Run("populated", func(t *testing.T) { 455 given := &openrtb2.SupplyChain{ 456 Complete: 1, 457 Nodes: []openrtb2.SupplyChainNode{ 458 {ASI: "asi", Ext: json.RawMessage(`{"anyField":1}`)}, 459 }, 460 Ext: json.RawMessage(`{"anyField":1}`), 461 } 462 result := CloneSChain(given) 463 assert.Equal(t, given, result, "equality") 464 assert.NotSame(t, given, result, "pointer") 465 assert.NotSame(t, given.Nodes, result.Nodes, "nodes") 466 assert.NotSame(t, given.Nodes[0].Ext, result.Nodes[0].Ext, "nodes.ext") 467 assert.NotSame(t, given.Ext, result.Ext, "ext") 468 }) 469 470 t.Run("assumptions", func(t *testing.T) { 471 assert.ElementsMatch(t, discoverPointerFields(reflect.TypeOf(openrtb2.SupplyChain{})), 472 []string{ 473 "Nodes", 474 "Ext", 475 }) 476 }) 477 } 478 479 func TestCloneSupplyChainNodes(t *testing.T) { 480 var n int8 = 1 481 np := &n 482 t.Run("nil", func(t *testing.T) { 483 result := CloneSupplyChainNodes(nil) 484 assert.Nil(t, result) 485 }) 486 487 t.Run("empty", func(t *testing.T) { 488 given := []openrtb2.SupplyChainNode{} 489 result := CloneSupplyChainNodes(given) 490 assert.Empty(t, result) 491 assert.NotSame(t, given, result) 492 }) 493 494 t.Run("one", func(t *testing.T) { 495 given := []openrtb2.SupplyChainNode{ 496 {ASI: "asi", HP: np, Ext: json.RawMessage(`{"anyField":1}`)}, 497 } 498 result := CloneSupplyChainNodes(given) 499 assert.Equal(t, given, result, "equality") 500 assert.NotSame(t, given[0], result[0], "item-pointer") 501 assert.NotSame(t, given[0].HP, result[0].HP, "item-pointer-hp") 502 assert.NotSame(t, given[0].Ext, result[0].Ext, "item-pointer-ext") 503 }) 504 505 t.Run("many", func(t *testing.T) { 506 given := []openrtb2.SupplyChainNode{ 507 {ASI: "asi", HP: np, Ext: json.RawMessage(`{"anyField":1}`)}, 508 {ASI: "asi", HP: np, Ext: json.RawMessage(`{"anyField":1}`)}, 509 {ASI: "asi", HP: np, Ext: json.RawMessage(`{"anyField":1}`)}, 510 } 511 result := CloneSupplyChainNodes(given) 512 assert.Equal(t, given, result, "equality") 513 assert.NotSame(t, given[0], result[0], "item0-pointer") 514 assert.NotSame(t, given[0].Ext, result[0].Ext, "item0-pointer-ext") 515 assert.NotSame(t, given[0].HP, result[0].HP, "item0-pointer-hp") 516 assert.NotSame(t, given[1], result[1], "item1-pointer") 517 assert.NotSame(t, given[1].Ext, result[1].Ext, "item1-pointer-ext") 518 assert.NotSame(t, given[1].HP, result[1].HP, "item1-pointer-hp") 519 assert.NotSame(t, given[2], result[2], "item2-pointer") 520 assert.NotSame(t, given[2].Ext, result[2].Ext, "item2-pointer-ext") 521 assert.NotSame(t, given[2].HP, result[2].HP, "item2-pointer-hp") 522 }) 523 } 524 525 func TestCloneSupplyChainNode(t *testing.T) { 526 t.Run("populated", func(t *testing.T) { 527 var n int8 = 1 528 np := &n 529 530 given := openrtb2.SupplyChainNode{ 531 ASI: "asi", 532 HP: np, 533 Ext: json.RawMessage(`{"anyField":1}`), 534 } 535 result := CloneSupplyChainNode(given) 536 assert.Equal(t, given, result, "equality") 537 assert.NotSame(t, given, result, "pointer") 538 assert.NotSame(t, given.Ext, result.Ext, "ext") 539 assert.NotSame(t, given.HP, result.HP, "hp") 540 }) 541 542 t.Run("assumptions", func(t *testing.T) { 543 assert.ElementsMatch(t, discoverPointerFields(reflect.TypeOf(openrtb2.SupplyChainNode{})), 544 []string{ 545 "HP", 546 "Ext", 547 }) 548 }) 549 } 550 551 func TestCloneGeo(t *testing.T) { 552 t.Run("nil", func(t *testing.T) { 553 result := CloneGeo(nil) 554 assert.Nil(t, result) 555 }) 556 557 t.Run("empty", func(t *testing.T) { 558 given := &openrtb2.Geo{} 559 result := CloneGeo(given) 560 assert.Empty(t, result) 561 assert.NotSame(t, given, result) 562 }) 563 564 t.Run("populated", func(t *testing.T) { 565 given := &openrtb2.Geo{ 566 Lat: ptrutil.ToPtr(1.234), 567 Lon: ptrutil.ToPtr(5.678), 568 Type: adcom1.LocationGPS, 569 Accuracy: 1, 570 LastFix: 2, 571 IPService: adcom1.LocationServiceIP2Location, 572 Country: "anyCountry", 573 Region: "anyRegion", 574 RegionFIPS104: "anyRegionFIPS104", 575 Metro: "anyMetro", 576 City: "anyCity", 577 ZIP: "anyZIP", 578 UTCOffset: 3, 579 Ext: json.RawMessage(`{"anyField":1}`), 580 } 581 result := CloneGeo(given) 582 assert.Equal(t, given, result, "equality") 583 assert.NotSame(t, given, result, "pointer") 584 assert.NotSame(t, given.Lat, result.Lat, "lat") 585 assert.NotSame(t, given.Lon, result.Lon, "lon") 586 assert.NotSame(t, given.Ext, result.Ext, "ext") 587 }) 588 589 t.Run("assumptions", func(t *testing.T) { 590 assert.ElementsMatch(t, discoverPointerFields(reflect.TypeOf(openrtb2.Geo{})), 591 []string{ 592 "Lat", 593 "Lon", 594 "Ext", 595 }) 596 }) 597 } 598 599 func TestCloneEIDSlice(t *testing.T) { 600 t.Run("nil", func(t *testing.T) { 601 result := CloneEIDSlice(nil) 602 assert.Nil(t, result) 603 }) 604 605 t.Run("empty", func(t *testing.T) { 606 given := []openrtb2.EID{} 607 result := CloneEIDSlice(given) 608 assert.Empty(t, result) 609 assert.NotSame(t, given, result) 610 }) 611 612 t.Run("one", func(t *testing.T) { 613 given := []openrtb2.EID{ 614 {Source: "1", Ext: json.RawMessage(`{"anyField":1}`)}, 615 } 616 result := CloneEIDSlice(given) 617 assert.Equal(t, given, result, "equality") 618 assert.NotSame(t, given[0], result[0], "item-pointer") 619 assert.NotSame(t, given[0].Ext, result[0].Ext, "item-pointer-ext") 620 }) 621 622 t.Run("many", func(t *testing.T) { 623 given := []openrtb2.EID{ 624 {Source: "1", Ext: json.RawMessage(`{"anyField":1}`)}, 625 {Source: "2", Ext: json.RawMessage(`{"anyField":2}`)}, 626 } 627 result := CloneEIDSlice(given) 628 assert.Equal(t, given, result, "equality") 629 assert.NotSame(t, given[0], result[0], "item0-pointer") 630 assert.NotSame(t, given[0].Ext, result[0].Ext, "item0-pointer-ext") 631 assert.NotSame(t, given[1], result[1], "item1-pointer") 632 assert.NotSame(t, given[1].Ext, result[1].Ext, "item1-pointer-ext") 633 }) 634 } 635 636 func TestCloneEID(t *testing.T) { 637 t.Run("populated", func(t *testing.T) { 638 given := openrtb2.EID{ 639 Source: "anySource", 640 UIDs: []openrtb2.UID{{ID: "1", Ext: json.RawMessage(`{"uid":1}`)}}, 641 Ext: json.RawMessage(`{"anyField":1}`), 642 } 643 result := CloneEID(given) 644 assert.Equal(t, given, result, "equality") 645 assert.NotSame(t, given, result, "pointer") 646 assert.NotSame(t, given.UIDs, result.UIDs, "uids") 647 assert.NotSame(t, given.UIDs[0], result.UIDs[0], "uids-item") 648 assert.NotSame(t, given.UIDs[0].Ext, result.UIDs[0].Ext, "uids-item-ext") 649 assert.NotSame(t, given.Ext, result.Ext, "ext") 650 }) 651 652 t.Run("assumptions", func(t *testing.T) { 653 assert.ElementsMatch(t, discoverPointerFields(reflect.TypeOf(openrtb2.EID{})), 654 []string{ 655 "UIDs", 656 "Ext", 657 }) 658 }) 659 } 660 661 func TestCloneUIDSlice(t *testing.T) { 662 t.Run("nil", func(t *testing.T) { 663 result := CloneUIDSlice(nil) 664 assert.Nil(t, result) 665 }) 666 667 t.Run("empty", func(t *testing.T) { 668 given := []openrtb2.UID{} 669 result := CloneUIDSlice(given) 670 assert.Empty(t, result) 671 assert.NotSame(t, given, result) 672 }) 673 674 t.Run("one", func(t *testing.T) { 675 given := []openrtb2.UID{ 676 {ID: "1", Ext: json.RawMessage(`{"anyField":1}`)}, 677 } 678 result := CloneUIDSlice(given) 679 assert.Equal(t, given, result, "equality") 680 assert.NotSame(t, given[0], result[0], "item-pointer") 681 assert.NotSame(t, given[0].Ext, result[0].Ext, "item-pointer-ext") 682 }) 683 684 t.Run("many", func(t *testing.T) { 685 given := []openrtb2.UID{ 686 {ID: "1", Ext: json.RawMessage(`{"anyField":1}`)}, 687 {ID: "2", Ext: json.RawMessage(`{"anyField":2}`)}, 688 } 689 result := CloneUIDSlice(given) 690 assert.Equal(t, given, result, "equality") 691 assert.NotSame(t, given[0], result[0], "item0-pointer") 692 assert.NotSame(t, given[0].Ext, result[0].Ext, "item0-pointer-ext") 693 assert.NotSame(t, given[1], result[1], "item1-pointer") 694 assert.NotSame(t, given[1].Ext, result[1].Ext, "item1-pointer-ext") 695 }) 696 } 697 698 func TestCloneUID(t *testing.T) { 699 t.Run("populated", func(t *testing.T) { 700 given := openrtb2.UID{ 701 ID: "anyID", 702 AType: adcom1.AgentTypePerson, 703 Ext: json.RawMessage(`{"anyField":1}`), 704 } 705 result := CloneUID(given) 706 assert.Equal(t, given, result, "equality") 707 assert.NotSame(t, given, result, "pointer") 708 assert.NotSame(t, given.Ext, result.Ext, "ext") 709 }) 710 711 t.Run("assumptions", func(t *testing.T) { 712 assert.ElementsMatch(t, discoverPointerFields(reflect.TypeOf(openrtb2.UID{})), 713 []string{ 714 "Ext", 715 }) 716 }) 717 } 718 719 func TestCloneBidderReq(t *testing.T) { 720 t.Run("nil", func(t *testing.T) { 721 result := CloneBidRequestPartial(nil) 722 assert.Nil(t, result) 723 }) 724 725 t.Run("empty", func(t *testing.T) { 726 given := &openrtb2.BidRequest{} 727 result := CloneBidRequestPartial(given) 728 assert.Equal(t, given, result) 729 assert.NotSame(t, given, result) 730 }) 731 732 t.Run("populated", func(t *testing.T) { 733 given := &openrtb2.BidRequest{ 734 ID: "anyID", 735 User: &openrtb2.User{ID: "testUserId"}, 736 Device: &openrtb2.Device{Carrier: "testCarrier"}, 737 Source: &openrtb2.Source{TID: "testTID"}, 738 } 739 result := CloneBidRequestPartial(given) 740 assert.Equal(t, given, result) 741 assert.NotSame(t, given, result, "pointer") 742 assert.NotSame(t, given.Device, result.Device, "device") 743 assert.NotSame(t, given.User, result.User, "user") 744 assert.NotSame(t, given.Source, result.Source, "source") 745 }) 746 747 // TODO: Implement a full bid request clone and track changes using an 'assumptions' test. 748 } 749 750 // discoverPointerFields returns the names of all fields of an object that are 751 // pointers and would need to be cloned. This method is specific to types which can 752 // appear within an OpenRTB data model object. 753 func discoverPointerFields(t reflect.Type) []string { 754 var fields []string 755 for _, f := range reflect.VisibleFields(t) { 756 if f.Type.Kind() == reflect.Slice || f.Type.Kind() == reflect.Pointer { 757 fields = append(fields, f.Name) 758 } 759 } 760 return fields 761 }