github.com/anchore/syft@v1.4.2-0.20240516191711-1bec1fc5d397/syft/format/syftjson/model/package_test.go (about) 1 package model 2 3 import ( 4 "encoding/json" 5 "reflect" 6 "testing" 7 8 "github.com/stretchr/testify/assert" 9 "github.com/stretchr/testify/require" 10 11 "github.com/anchore/syft/syft/license" 12 "github.com/anchore/syft/syft/pkg" 13 ) 14 15 func Test_UnmarshalJSON(t *testing.T) { 16 tests := []struct { 17 name string 18 packageData []byte 19 assert func(*Package) 20 }{ 21 { 22 name: "unmarshal package metadata", 23 packageData: []byte(`{ 24 "id": "8b594519bc23da50", 25 "name": "gopkg.in/square/go-jose.v2", 26 "version": "v2.6.0", 27 "type": "go-module", 28 "foundBy": "go-module-binary-cataloger", 29 "locations": [ 30 { 31 "path": "/Users/hal/go/bin/syft" 32 } 33 ], 34 "licenses": [ 35 { 36 "value": "MIT", 37 "spdxExpression": "MIT", 38 "type": "declared", 39 "url": [] 40 } 41 ], 42 "language": "go", 43 "cpes": [], 44 "purl": "pkg:golang/gopkg.in/square/go-jose.v2@v2.6.0", 45 "metadataType": "GolangBinMetadata", 46 "metadata": { 47 "goCompiledVersion": "go1.18", 48 "architecture": "amd64", 49 "h1Digest": "h1:NGk74WTnPKBNUhNzQX7PYcTLUjoq7mzKk2OKbvwk2iI=" 50 } 51 }`), 52 assert: func(p *Package) { 53 require.NotNil(t, p.Metadata) 54 golangMetadata := p.Metadata.(pkg.GolangBinaryBuildinfoEntry) 55 require.NotEmpty(t, golangMetadata) 56 assert.Equal(t, "go1.18", golangMetadata.GoCompiledVersion) 57 }, 58 }, 59 { 60 name: "can handle package without metadata", 61 packageData: []byte(`{ 62 "id": "8b594519bc23da50", 63 "name": "gopkg.in/square/go-jose.v2", 64 "version": "v2.6.0", 65 "type": "go-module", 66 "foundBy": "go-mod-cataloger", 67 "locations": [ 68 { 69 "path": "/Users/hal/go/bin/syft" 70 } 71 ], 72 "licenses": [ 73 { 74 "value": "MIT", 75 "spdxExpression": "MIT", 76 "type": "declared", 77 "url": ["https://www.github.com"] 78 }, 79 { 80 "value": "MIT", 81 "spdxExpression": "MIT", 82 "type": "declared", 83 "locations": [{"path": "/Users/hal/go/bin/syft"}] 84 } 85 ], 86 "language": "go", 87 "cpes": [], 88 "purl": "pkg:golang/gopkg.in/square/go-jose.v2@v2.6.0" 89 }`), 90 assert: func(p *Package) { 91 assert.Empty(t, p.MetadataType) 92 assert.Empty(t, p.Metadata) 93 }, 94 }, 95 { 96 name: "can handle package with []string licenses", 97 packageData: []byte(`{ 98 "id": "8b594519bc23da50", 99 "name": "gopkg.in/square/go-jose.v2", 100 "version": "v2.6.0", 101 "type": "go-module", 102 "foundBy": "go-mod-cataloger", 103 "locations": [ 104 { 105 "path": "/Users/hal/go/bin/syft" 106 } 107 ], 108 "licenses": ["MIT", "Apache-2.0"], 109 "language": "go", 110 "cpes": [], 111 "purl": "pkg:golang/gopkg.in/square/go-jose.v2@v2.6.0" 112 }`), 113 assert: func(p *Package) { 114 assert.Equal(t, licenses{ 115 { 116 Value: "MIT", 117 SPDXExpression: "MIT", 118 Type: license.Declared, 119 }, 120 { 121 Value: "Apache-2.0", 122 SPDXExpression: "Apache-2.0", 123 Type: license.Declared, 124 }, 125 }, p.Licenses) 126 }, 127 }, 128 { 129 name: "can handle package with []pkg.License licenses", 130 packageData: []byte(`{ 131 "id": "8b594519bc23da50", 132 "name": "gopkg.in/square/go-jose.v2", 133 "version": "v2.6.0", 134 "type": "go-module", 135 "foundBy": "go-mod-cataloger", 136 "locations": [ 137 { 138 "path": "/Users/hal/go/bin/syft" 139 } 140 ], 141 "licenses": [ 142 { 143 "value": "MIT", 144 "spdxExpression": "MIT", 145 "type": "declared" 146 }, 147 { 148 "value": "Apache-2.0", 149 "spdxExpression": "Apache-2.0", 150 "type": "declared" 151 } 152 ], 153 "language": "go", 154 "cpes": [], 155 "purl": "pkg:golang/gopkg.in/square/go-jose.v2@v2.6.0" 156 }`), 157 assert: func(p *Package) { 158 assert.Equal(t, licenses{ 159 { 160 Value: "MIT", 161 SPDXExpression: "MIT", 162 Type: license.Declared, 163 }, 164 { 165 Value: "Apache-2.0", 166 SPDXExpression: "Apache-2.0", 167 Type: license.Declared, 168 }, 169 }, p.Licenses) 170 }, 171 }, 172 { 173 name: "breaking v11-v12 schema change: rpm db vs archive (select db)", 174 packageData: []byte(`{ 175 "id": "739158935bfffc4d", 176 "name": "dbus", 177 "version": "1:1.12.8-12.el8", 178 "type": "rpm", 179 "foundBy": "rpm-db-cataloger", 180 "locations": [ 181 { 182 "path": "/var/lib/rpm/Packages", 183 "layerID": "sha256:d871dadfb37b53ef1ca45be04fc527562b91989991a8f545345ae3be0b93f92a", 184 "annotations": { 185 "evidence": "primary" 186 } 187 } 188 ], 189 "licenses": [], 190 "language": "", 191 "cpes": [], 192 "purl": "pkg:rpm/centos/dbus@1.12.8-12.el8?arch=aarch64&epoch=1&upstream=dbus-1.12.8-12.el8.src.rpm&distro=centos-8", 193 "metadataType": "RpmMetadata", 194 "metadata": { 195 "name": "dbus", 196 "version": "1.12.8", 197 "epoch": 1, 198 "architecture": "aarch64", 199 "release": "12.el8", 200 "sourceRpm": "dbus-1.12.8-12.el8.src.rpm", 201 "size": 0, 202 "vendor": "CentOS", 203 "modularityLabel": "", 204 "files": [] 205 } 206 } 207 `), 208 assert: func(p *Package) { 209 assert.Equal(t, pkg.RpmPkg, p.Type) 210 assert.Equal(t, reflect.TypeOf(pkg.RpmDBEntry{}).Name(), reflect.TypeOf(p.Metadata).Name()) 211 }, 212 }, 213 { 214 name: "breaking v11-v12 schema change: rpm db vs archive (select archive)", 215 packageData: []byte(`{ 216 "id": "739158935bfffc4d", 217 "name": "dbus", 218 "version": "1:1.12.8-12.el8", 219 "type": "rpm", 220 "foundBy": "rpm-db-cataloger", 221 "locations": [ 222 { 223 "path": "/var/cache/dbus-1.12.8-12.el8.rpm", 224 "layerID": "sha256:d871dadfb37b53ef1ca45be04fc527562b91989991a8f545345ae3be0b93f92a", 225 "annotations": { 226 "evidence": "primary" 227 } 228 } 229 ], 230 "licenses": [], 231 "language": "", 232 "cpes": [], 233 "purl": "pkg:rpm/centos/dbus@1.12.8-12.el8?arch=aarch64&epoch=1&upstream=dbus-1.12.8-12.el8.src.rpm&distro=centos-8", 234 "metadataType": "RpmMetadata", 235 "metadata": { 236 "name": "dbus", 237 "version": "1.12.8", 238 "epoch": 1, 239 "architecture": "aarch64", 240 "release": "12.el8", 241 "sourceRpm": "dbus-1.12.8-12.el8.src.rpm", 242 "size": 0, 243 "vendor": "CentOS", 244 "modularityLabel": "", 245 "files": [] 246 } 247 } 248 `), 249 assert: func(p *Package) { 250 assert.Equal(t, pkg.RpmPkg, p.Type) 251 assert.Equal(t, reflect.TypeOf(pkg.RpmArchive{}).Name(), reflect.TypeOf(p.Metadata).Name()) 252 }, 253 }, 254 { 255 name: "breaking v11-v12 schema change: stack.yaml vs stack.yaml.lock (select stack.yaml)", 256 packageData: []byte(`{ 257 "id": "46ff1a71f7715f38", 258 "name": "hspec-discover", 259 "version": "2.9.4", 260 "type": "hackage", 261 "foundBy": "haskell-cataloger", 262 "locations": [ 263 { 264 "path": "/stack.yaml", 265 "annotations": { 266 "evidence": "primary" 267 } 268 } 269 ], 270 "licenses": [], 271 "language": "haskell", 272 "cpes": [ 273 "cpe:2.3:a:hspec-discover:hspec-discover:2.9.4:*:*:*:*:*:*:*", 274 "cpe:2.3:a:hspec-discover:hspec_discover:2.9.4:*:*:*:*:*:*:*", 275 "cpe:2.3:a:hspec_discover:hspec-discover:2.9.4:*:*:*:*:*:*:*", 276 "cpe:2.3:a:hspec_discover:hspec_discover:2.9.4:*:*:*:*:*:*:*", 277 "cpe:2.3:a:hspec:hspec-discover:2.9.4:*:*:*:*:*:*:*", 278 "cpe:2.3:a:hspec:hspec_discover:2.9.4:*:*:*:*:*:*:*" 279 ], 280 "purl": "pkg:hackage/hspec-discover@2.9.4", 281 "metadataType": "HackageMetadataType", 282 "metadata": { 283 "name": "", 284 "version": "", 285 "pkgHash": "fbcf49ecfc3d4da53e797fd0275264cba776ffa324ee223e2a3f4ec2d2c9c4a6" 286 } 287 }`), 288 assert: func(p *Package) { 289 assert.Equal(t, pkg.HackagePkg, p.Type) 290 assert.Equal(t, reflect.TypeOf(pkg.HackageStackYamlEntry{}).Name(), reflect.TypeOf(p.Metadata).Name()) 291 }, 292 }, 293 { 294 name: "breaking v11-v12 schema change: stack.yaml vs stack.yaml.lock (select stack.yaml.lock)", 295 packageData: []byte(`{ 296 "id": "87939e95124ceb92", 297 "name": "optparse-applicative", 298 "version": "0.16.1.0", 299 "type": "hackage", 300 "foundBy": "haskell-cataloger", 301 "locations": [ 302 { 303 "path": "/stack.yaml.lock", 304 "annotations": { 305 "evidence": "primary" 306 } 307 } 308 ], 309 "licenses": [], 310 "language": "haskell", 311 "cpes": [ 312 "cpe:2.3:a:optparse-applicative:optparse-applicative:0.16.1.0:*:*:*:*:*:*:*", 313 "cpe:2.3:a:optparse-applicative:optparse_applicative:0.16.1.0:*:*:*:*:*:*:*", 314 "cpe:2.3:a:optparse_applicative:optparse-applicative:0.16.1.0:*:*:*:*:*:*:*", 315 "cpe:2.3:a:optparse_applicative:optparse_applicative:0.16.1.0:*:*:*:*:*:*:*", 316 "cpe:2.3:a:optparse:optparse-applicative:0.16.1.0:*:*:*:*:*:*:*", 317 "cpe:2.3:a:optparse:optparse_applicative:0.16.1.0:*:*:*:*:*:*:*" 318 ], 319 "purl": "pkg:hackage/optparse-applicative@0.16.1.0", 320 "metadataType": "HackageMetadataType", 321 "metadata": { 322 "name": "", 323 "version": "", 324 "pkgHash": "418c22ed6a19124d457d96bc66bd22c93ac22fad0c7100fe4972bbb4ac989731", 325 "snapshotURL": "https://raw.githubusercontent.com/commercialhaskell/stackage-snapshots/master/lts/19/14.yaml" 326 } 327 }`), 328 assert: func(p *Package) { 329 assert.Equal(t, pkg.HackagePkg, p.Type) 330 assert.Equal(t, reflect.TypeOf(pkg.HackageStackYamlLockEntry{}).Name(), reflect.TypeOf(p.Metadata).Name()) 331 }, 332 }, 333 { 334 name: "breaking v11-v12 schema change: rust cargo.lock vs audit (select cargo.lock)", 335 packageData: []byte(`{ 336 "id": "95124ceb9287939e", 337 "name": "optpkg", 338 "version": "1.16.1", 339 "type": "hackage", 340 "foundBy": "rust-cataloger", 341 "locations": [ 342 { 343 "path": "/cargo.lock", 344 "annotations": { 345 "evidence": "primary" 346 } 347 } 348 ], 349 "licenses": [], 350 "language": "rust", 351 "cpes": [], 352 "purl": "pkg:cargo/optpkg@1.16.1", 353 "metadataType": "RustCargoPackageMetadata", 354 "metadata": {} 355 }`), 356 assert: func(p *Package) { 357 assert.Equal(t, pkg.HackagePkg, p.Type) 358 assert.Equal(t, reflect.TypeOf(pkg.RustCargoLockEntry{}).Name(), reflect.TypeOf(p.Metadata).Name()) 359 }, 360 }, 361 { 362 name: "breaking v11-v12 schema change: rust cargo.lock vs audit (select audit binary)", 363 packageData: []byte(`{ 364 "id": "95124ceb9287939e", 365 "name": "optpkg", 366 "version": "1.16.1", 367 "type": "hackage", 368 "foundBy": "rust-cataloger", 369 "locations": [ 370 { 371 "path": "/my-binary", 372 "annotations": { 373 "evidence": "primary" 374 } 375 } 376 ], 377 "licenses": [], 378 "language": "rust", 379 "cpes": [], 380 "purl": "pkg:cargo/optpkg@1.16.1", 381 "metadataType": "RustCargoPackageMetadata", 382 "metadata": {} 383 }`), 384 assert: func(p *Package) { 385 assert.Equal(t, pkg.HackagePkg, p.Type) 386 assert.Equal(t, reflect.TypeOf(pkg.RustBinaryAuditEntry{}).Name(), reflect.TypeOf(p.Metadata).Name()) 387 }, 388 }, 389 { 390 name: "map-based java metadata", 391 packageData: []byte(`{ 392 "id": "e6f845bdaa69ddb2", 393 "name": "SparseBitSet", 394 "version": "1.2", 395 "type": "java-archive", 396 "foundBy": "java-archive-cataloger", 397 "locations": [], 398 "licenses": [], 399 "language": "java", 400 "cpes": [], 401 "purl": "pkg:maven/com.zaxxer/SparseBitSet@1.2", 402 "metadataType": "java-archive", 403 "metadata": { 404 "virtualPath": "/opt/solr-9.4.1/modules/extraction/lib/SparseBitSet-1.2.jar", 405 "manifest": { 406 "main": { 407 "Archiver-Version": "Plexus Archiver", 408 "Build-Jdk": "1.8.0_73", 409 "Built-By": "lbayer", 410 "Created-By": "Apache Maven 3.5.0", 411 "Manifest-Version": "1.0" 412 }, 413 "namedSections": { 414 "META-INF/mailcap": { 415 "SHA-256-Digest": "kXN4VupOQOJhduMGwxumj4ijmD/YAlz97a9Mp7CVXtk=" 416 }, 417 "META-INF/versions/9/module-info.class": { 418 "SHA-256-Digest": "cMeIRa5l8DWPgrVWavr/6TKVBUGixVKGcu6yOTZMlKk=" 419 } 420 } 421 } 422 } 423 }`), 424 assert: func(p *Package) { 425 meta := p.Metadata.(pkg.JavaArchive) 426 manifest := meta.Manifest 427 assert.Equal(t, "1.8.0_73", manifest.Main.MustGet("Build-Jdk")) 428 require.Equal(t, 2, len(manifest.Sections)) 429 assert.Equal(t, "META-INF/mailcap", manifest.Sections[0].MustGet("Name")) 430 assert.Equal(t, "kXN4VupOQOJhduMGwxumj4ijmD/YAlz97a9Mp7CVXtk=", manifest.Sections[0].MustGet("SHA-256-Digest")) 431 assert.Equal(t, "META-INF/versions/9/module-info.class", manifest.Sections[1].MustGet("Name")) 432 assert.Equal(t, "cMeIRa5l8DWPgrVWavr/6TKVBUGixVKGcu6yOTZMlKk=", manifest.Sections[1].MustGet("SHA-256-Digest")) 433 }, 434 }, 435 { 436 name: "pre key-value golang metadata", 437 packageData: []byte(`{ 438 "id": "e348ed25484a94c9", 439 "name": "github.com/anchore/syft", 440 "version": "v0.101.1-SNAPSHOT-4c777834", 441 "type": "go-module", 442 "foundBy": "go-module-binary-cataloger", 443 "locations": [ 444 { 445 "path": "/syft", 446 "layerID": "sha256:2274947a5f3527e48d8725a96646aefdcce3d99340c1eefb1e7c894043863c92", 447 "accessPath": "/syft", 448 "annotations": { 449 "evidence": "primary" 450 } 451 } 452 ], 453 "licenses": [], 454 "language": "go", 455 "cpes": [ 456 "cpe:2.3:a:anchore:syft:v0.101.1-SNAPSHOT-4c777834:*:*:*:*:*:*:*" 457 ], 458 "purl": "pkg:golang/github.com/anchore/syft@v0.101.1-SNAPSHOT-4c777834", 459 "metadataType": "go-module-buildinfo-entry", 460 "metadata": { 461 "goBuildSettings": { 462 "-buildmode": "exe", 463 "-compiler": "gc", 464 "-ldflags": "-w -s -extldflags '-static' -X main.version=0.101.1-SNAPSHOT-4c777834 -X main.gitCommit=4c777834618b2ad8ad94cd200a45d6670bc1c013 -X main.buildDate=2024-01-22T16:43:49Z -X main.gitDescription=v0.101.1-4-g4c777834 ", 465 "CGO_ENABLED": "0", 466 "GOAMD64": "v1", 467 "GOARCH": "amd64", 468 "GOOS": "linux", 469 "vcs": "git", 470 "vcs.modified": "false", 471 "vcs.revision": "4c777834618b2ad8ad94cd200a45d6670bc1c013", 472 "vcs.time": "2024-01-22T16:31:41Z" 473 }, 474 "goCompiledVersion": "go1.21.2", 475 "architecture": "amd64", 476 "mainModule": "github.com/anchore/syft" 477 } 478 } 479 `), 480 assert: func(p *Package) { 481 buildInfo := p.Metadata.(pkg.GolangBinaryBuildinfoEntry) 482 assert.Equal(t, "exe", buildInfo.BuildSettings.MustGet("-buildmode")) 483 }, 484 }, 485 { 486 name: "conan lock with legacy options", 487 packageData: []byte(`{ 488 "id": "75eb35307226c921", 489 "name": "boost", 490 "version": "1.75.0", 491 "type": "conan", 492 "foundBy": "conan-cataloger", 493 "locations": [ 494 { 495 "path": "/conan.lock", 496 "accessPath": "/conan.lock", 497 "annotations": { 498 "evidence": "primary" 499 } 500 } 501 ], 502 "licenses": [], 503 "language": "c++", 504 "cpes": [ 505 "cpe:2.3:a:boost:boost:1.75.0:*:*:*:*:*:*:*" 506 ], 507 "purl": "pkg:conan/boost@1.75.0", 508 "metadataType": "c-conan-lock-entry", 509 "metadata": { 510 "ref": "boost/1.75.0#a9c318f067216f900900e044e7af4ab1", 511 "package_id": "dc8aedd23a0f0a773a5fcdcfe1ae3e89c4205978", 512 "prev": "b9d7912e6131dfa453c725593b36c808", 513 "options": { 514 "addr2line_location": "/usr/bin/addr2line", 515 "asio_no_deprecated": "False", 516 "zstd": "False" 517 }, 518 "context": "host" 519 } 520 }`), 521 assert: func(p *Package) { 522 metadata := p.Metadata.(pkg.ConanV1LockEntry) 523 assert.Equal(t, "False", metadata.Options.MustGet("asio_no_deprecated")) 524 }, 525 }, 526 } 527 528 for _, test := range tests { 529 t.Run(test.name, func(t *testing.T) { 530 p := &Package{} 531 err := p.UnmarshalJSON(test.packageData) 532 require.NoError(t, err) 533 test.assert(p) 534 }) 535 } 536 } 537 538 func Test_unpackMetadata(t *testing.T) { 539 tests := []struct { 540 name string 541 packageData []byte 542 wantMetadata any 543 wantErr require.ErrorAssertionFunc 544 }{ 545 { 546 name: "unmarshal package metadata", 547 wantMetadata: pkg.GolangBinaryBuildinfoEntry{}, 548 packageData: []byte(`{ 549 "id": "8b594519bc23da50", 550 "name": "gopkg.in/square/go-jose.v2", 551 "version": "v2.6.0", 552 "type": "go-module", 553 "foundBy": "go-module-binary-cataloger", 554 "locations": [ 555 { 556 "path": "/Users/hal/go/bin/syft" 557 } 558 ], 559 "licenses": [], 560 "language": "go", 561 "cpes": [], 562 "purl": "pkg:golang/gopkg.in/square/go-jose.v2@v2.6.0", 563 "metadataType": "GolangBinMetadata", 564 "metadata": { 565 "goCompiledVersion": "go1.18", 566 "architecture": "amd64", 567 "h1Digest": "h1:NGk74WTnPKBNUhNzQX7PYcTLUjoq7mzKk2OKbvwk2iI=" 568 } 569 }`), 570 }, 571 { 572 name: "can handle package without metadata", 573 wantMetadata: nil, 574 packageData: []byte(`{ 575 "id": "8b594519bc23da50", 576 "name": "gopkg.in/square/go-jose.v2", 577 "version": "v2.6.0", 578 "type": "go-module", 579 "foundBy": "go-mod-cataloger", 580 "locations": [ 581 { 582 "path": "/Users/hal/go/bin/syft" 583 } 584 ], 585 "licenses": [], 586 "language": "go", 587 "cpes": [], 588 "purl": "pkg:golang/gopkg.in/square/go-jose.v2@v2.6.0" 589 }`), 590 }, 591 { 592 name: "can handle RpmdbMetadata", 593 wantMetadata: pkg.RpmDBEntry{}, 594 packageData: []byte(`{ 595 "id": "4ac699c3b8fe1835", 596 "name": "acl", 597 "version": "2.2.53-1.el8", 598 "type": "rpm", 599 "foundBy": "rpm-db-cataloger", 600 "locations": [ 601 { 602 "path": "/var/lib/rpm/Packages", 603 "layerID": "sha256:74ddd0ec08fa43d09f32636ba91a0a3053b02cb4627c35051aff89f853606b59" 604 } 605 ], 606 "language": "", 607 "cpes": [ 608 "cpe:2.3:a:centos:acl:2.2.53-1.el8:*:*:*:*:*:*:*", 609 "cpe:2.3:a:acl:acl:2.2.53-1.el8:*:*:*:*:*:*:*" 610 ], 611 "purl": "pkg:rpm/centos/acl@2.2.53-1.el8?arch=x86_64&upstream=acl-2.2.53-1.el8.src.rpm&distro=centos-8", 612 "metadataType": "RpmdbMetadata", 613 "metadata": { 614 "name": "acl", 615 "version": "2.2.53", 616 "epoch": null, 617 "architecture": "x86_64", 618 "release": "1.el8", 619 "sourceRpm": "acl-2.2.53-1.el8.src.rpm", 620 "size": 205740, 621 "license": "GPLv2+", 622 "vendor": "CentOS", 623 "modularityLabel": "" 624 } 625 }`), 626 }, 627 { 628 name: "bad metadata type is an error", 629 wantErr: require.Error, 630 packageData: []byte(`{ 631 "id": "8b594519bc23da50", 632 "name": "gopkg.in/square/go-jose.v2", 633 "version": "v2.6.0", 634 "type": "go-module", 635 "foundBy": "go-mod-cataloger", 636 "locations": [ 637 { 638 "path": "/Users/hal/go/bin/syft" 639 } 640 ], 641 "licenses": [], 642 "language": "go", 643 "cpes": [], 644 "purl": "pkg:golang/gopkg.in/square/go-jose.v2@v2.6.0", 645 "metadataType": "BOGOSITY" 646 }`), 647 }, 648 { 649 name: "unknown metadata type", 650 packageData: []byte(`{ 651 "metadataType": "NewMetadataType", 652 "metadata": { 653 "thing": "thing-1" 654 } 655 }`), 656 wantErr: require.Error, 657 wantMetadata: map[string]interface{}{ 658 "thing": "thing-1", 659 }, 660 }, 661 { 662 name: "can handle package with metadata type but missing metadata", 663 packageData: []byte(`{ 664 "metadataType": "GolangBinMetadata" 665 }`), 666 wantMetadata: pkg.GolangBinaryBuildinfoEntry{}, 667 }, 668 { 669 name: "can handle package with golang bin metadata type", 670 packageData: []byte(`{ 671 "metadataType": "GolangBinMetadata" 672 }`), 673 wantMetadata: pkg.GolangBinaryBuildinfoEntry{}, 674 }, 675 { 676 name: "can handle package with unknown metadata type and missing metadata", 677 packageData: []byte(`{ 678 "metadataType": "BadMetadata" 679 }`), 680 wantErr: require.Error, 681 }, 682 { 683 name: "can handle package with unknown metadata type and metadata", 684 packageData: []byte(`{ 685 "metadataType": "BadMetadata", 686 "metadata": { 687 "random": "thing" 688 } 689 }`), 690 wantErr: require.Error, 691 }, 692 } 693 694 for _, test := range tests { 695 t.Run(test.name, func(t *testing.T) { 696 if test.wantErr == nil { 697 test.wantErr = require.NoError 698 } 699 p := &Package{} 700 701 var unpacker packageMetadataUnpacker 702 require.NoError(t, json.Unmarshal(test.packageData, &unpacker)) 703 704 err := unpackPkgMetadata(p, unpacker) 705 test.wantErr(t, err) 706 707 if test.wantMetadata != nil { 708 if p.Metadata == nil { 709 t.Fatalf("expected metadata to be populated") 710 return 711 } 712 assert.Equal(t, reflect.TypeOf(test.wantMetadata).Name(), reflect.TypeOf(p.Metadata).Name()) 713 } 714 }) 715 } 716 }