github.com/google/osv-scalibr@v0.4.1/extractor/filesystem/language/javascript/yarnlock/yarnlock-v1_test.go (about) 1 // Copyright 2025 Google LLC 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package yarnlock_test 16 17 import ( 18 "testing" 19 20 "github.com/google/go-cmp/cmp" 21 "github.com/google/go-cmp/cmp/cmpopts" 22 "github.com/google/osv-scalibr/extractor" 23 "github.com/google/osv-scalibr/extractor/filesystem/language/javascript/yarnlock" 24 "github.com/google/osv-scalibr/inventory" 25 "github.com/google/osv-scalibr/purl" 26 "github.com/google/osv-scalibr/testing/extracttest" 27 ) 28 29 func TestExtractor_Extract_v1(t *testing.T) { 30 tests := []extracttest.TestTableEntry{ 31 { 32 Name: "no packages", 33 InputConfig: extracttest.ScanInputMockConfig{ 34 Path: "testdata/empty.v1.lock", 35 }, 36 WantPackages: []*extractor.Package{}, 37 }, 38 { 39 Name: "one package", 40 InputConfig: extracttest.ScanInputMockConfig{ 41 Path: "testdata/one-package.v1.lock", 42 }, 43 WantPackages: []*extractor.Package{ 44 { 45 Name: "balanced-match", 46 Version: "1.0.2", 47 PURLType: purl.TypeNPM, 48 Locations: []string{"testdata/one-package.v1.lock"}, 49 SourceCode: &extractor.SourceCodeIdentifier{ 50 Commit: "", 51 }, 52 }, 53 }, 54 }, 55 { 56 Name: "package with no version in header", 57 InputConfig: extracttest.ScanInputMockConfig{ 58 Path: "testdata/no-version.v1.lock", 59 }, 60 WantPackages: []*extractor.Package{ 61 { 62 Name: "balanced-match", 63 Version: "1.0.2", 64 PURLType: purl.TypeNPM, 65 Locations: []string{"testdata/no-version.v1.lock"}, 66 SourceCode: &extractor.SourceCodeIdentifier{ 67 Commit: "", 68 }, 69 }, 70 }, 71 }, 72 { 73 Name: "two packages", 74 InputConfig: extracttest.ScanInputMockConfig{ 75 Path: "testdata/two-packages.v1.lock", 76 }, 77 WantPackages: []*extractor.Package{ 78 { 79 Name: "concat-stream", 80 Version: "1.6.2", 81 PURLType: purl.TypeNPM, 82 Locations: []string{"testdata/two-packages.v1.lock"}, 83 SourceCode: &extractor.SourceCodeIdentifier{ 84 Commit: "", 85 }, 86 }, 87 { 88 Name: "concat-map", 89 Version: "0.0.1", 90 PURLType: purl.TypeNPM, 91 Locations: []string{"testdata/two-packages.v1.lock"}, 92 SourceCode: &extractor.SourceCodeIdentifier{ 93 Commit: "", 94 }, 95 }, 96 }, 97 }, 98 { 99 Name: "with quotes", 100 InputConfig: extracttest.ScanInputMockConfig{ 101 Path: "testdata/with-quotes.v1.lock", 102 }, 103 WantPackages: []*extractor.Package{ 104 { 105 Name: "concat-stream", 106 Version: "1.6.2", 107 PURLType: purl.TypeNPM, 108 Locations: []string{"testdata/with-quotes.v1.lock"}, 109 SourceCode: &extractor.SourceCodeIdentifier{ 110 Commit: "", 111 }, 112 }, 113 { 114 Name: "concat-map", 115 Version: "0.0.1", 116 PURLType: purl.TypeNPM, 117 Locations: []string{"testdata/with-quotes.v1.lock"}, 118 SourceCode: &extractor.SourceCodeIdentifier{ 119 Commit: "", 120 }, 121 }, 122 }, 123 }, 124 { 125 Name: "multiple versions", 126 InputConfig: extracttest.ScanInputMockConfig{ 127 Path: "testdata/multiple-versions.v1.lock", 128 }, 129 WantPackages: []*extractor.Package{ 130 { 131 Name: "define-properties", 132 Version: "1.1.3", 133 PURLType: purl.TypeNPM, 134 Locations: []string{"testdata/multiple-versions.v1.lock"}, 135 SourceCode: &extractor.SourceCodeIdentifier{ 136 Commit: "", 137 }, 138 }, 139 { 140 Name: "define-property", 141 Version: "0.2.5", 142 PURLType: purl.TypeNPM, 143 Locations: []string{"testdata/multiple-versions.v1.lock"}, 144 SourceCode: &extractor.SourceCodeIdentifier{ 145 Commit: "", 146 }, 147 }, 148 { 149 Name: "define-property", 150 Version: "1.0.0", 151 PURLType: purl.TypeNPM, 152 Locations: []string{"testdata/multiple-versions.v1.lock"}, 153 SourceCode: &extractor.SourceCodeIdentifier{ 154 Commit: "", 155 }, 156 }, 157 { 158 Name: "define-property", 159 Version: "2.0.2", 160 PURLType: purl.TypeNPM, 161 Locations: []string{"testdata/multiple-versions.v1.lock"}, 162 SourceCode: &extractor.SourceCodeIdentifier{ 163 Commit: "", 164 }, 165 }, 166 }, 167 }, 168 { 169 Name: "multiple constraints", 170 InputConfig: extracttest.ScanInputMockConfig{ 171 Path: "testdata/multiple-constraints.v1.lock", 172 }, 173 WantPackages: []*extractor.Package{ 174 { 175 Name: "@babel/code-frame", 176 Version: "7.12.13", 177 PURLType: purl.TypeNPM, 178 Locations: []string{"testdata/multiple-constraints.v1.lock"}, 179 SourceCode: &extractor.SourceCodeIdentifier{ 180 Commit: "", 181 }, 182 }, 183 { 184 Name: "domelementtype", 185 Version: "1.3.1", 186 PURLType: purl.TypeNPM, 187 Locations: []string{"testdata/multiple-constraints.v1.lock"}, 188 SourceCode: &extractor.SourceCodeIdentifier{ 189 Commit: "", 190 }, 191 }, 192 }, 193 }, 194 { 195 Name: "scoped packages", 196 InputConfig: extracttest.ScanInputMockConfig{ 197 Path: "testdata/scoped-packages.v1.lock", 198 }, 199 WantPackages: []*extractor.Package{ 200 { 201 Name: "@babel/code-frame", 202 Version: "7.12.11", 203 PURLType: purl.TypeNPM, 204 Locations: []string{"testdata/scoped-packages.v1.lock"}, 205 SourceCode: &extractor.SourceCodeIdentifier{ 206 Commit: "", 207 }, 208 }, 209 { 210 Name: "@babel/compat-data", 211 Version: "7.14.0", 212 PURLType: purl.TypeNPM, 213 Locations: []string{"testdata/scoped-packages.v1.lock"}, 214 SourceCode: &extractor.SourceCodeIdentifier{ 215 Commit: "", 216 }, 217 }, 218 }, 219 }, 220 { 221 Name: "with prerelease", 222 InputConfig: extracttest.ScanInputMockConfig{ 223 Path: "testdata/with-prerelease.v1.lock", 224 }, 225 WantPackages: []*extractor.Package{ 226 { 227 Name: "css-tree", 228 Version: "1.0.0-alpha.37", 229 PURLType: purl.TypeNPM, 230 Locations: []string{"testdata/with-prerelease.v1.lock"}, 231 SourceCode: &extractor.SourceCodeIdentifier{ 232 Commit: "", 233 }, 234 }, 235 { 236 Name: "gensync", 237 Version: "1.0.0-beta.2", 238 PURLType: purl.TypeNPM, 239 Locations: []string{"testdata/with-prerelease.v1.lock"}, 240 SourceCode: &extractor.SourceCodeIdentifier{ 241 Commit: "", 242 }, 243 }, 244 { 245 Name: "node-fetch", 246 Version: "3.0.0-beta.9", 247 PURLType: purl.TypeNPM, 248 Locations: []string{"testdata/with-prerelease.v1.lock"}, 249 SourceCode: &extractor.SourceCodeIdentifier{ 250 Commit: "", 251 }, 252 }, 253 { 254 Name: "resolve", 255 Version: "1.20.0", 256 PURLType: purl.TypeNPM, 257 Locations: []string{"testdata/with-prerelease.v1.lock"}, 258 SourceCode: &extractor.SourceCodeIdentifier{ 259 Commit: "", 260 }, 261 }, 262 { 263 Name: "resolve", 264 Version: "2.0.0-next.3", 265 PURLType: purl.TypeNPM, 266 Locations: []string{"testdata/with-prerelease.v1.lock"}, 267 SourceCode: &extractor.SourceCodeIdentifier{ 268 Commit: "", 269 }, 270 }, 271 }, 272 }, 273 { 274 Name: "with build string", 275 InputConfig: extracttest.ScanInputMockConfig{ 276 Path: "testdata/with-build-string.v1.lock", 277 }, 278 WantPackages: []*extractor.Package{ 279 { 280 Name: "domino", 281 Version: "2.1.6+git", 282 PURLType: purl.TypeNPM, 283 Locations: []string{"testdata/with-build-string.v1.lock"}, 284 SourceCode: &extractor.SourceCodeIdentifier{ 285 Commit: "", 286 }, 287 }, 288 { 289 Name: "tslib", 290 Version: "2.6.2", 291 PURLType: purl.TypeNPM, 292 Locations: []string{"testdata/with-build-string.v1.lock"}, 293 SourceCode: &extractor.SourceCodeIdentifier{ 294 Commit: "", 295 }, 296 }, 297 }, 298 }, 299 { 300 Name: "commits", 301 InputConfig: extracttest.ScanInputMockConfig{ 302 Path: "testdata/commits.v1.lock", 303 }, 304 WantPackages: []*extractor.Package{ 305 { 306 Name: "mine1", 307 Version: "1.0.0-alpha.37", 308 PURLType: purl.TypeNPM, 309 Locations: []string{"testdata/commits.v1.lock"}, 310 SourceCode: &extractor.SourceCodeIdentifier{ 311 Commit: "0a2d2506c1fe299691fc5db53a2097db3bd615bc", 312 }, 313 }, 314 { 315 Name: "mine2", 316 Version: "0.0.1", 317 PURLType: purl.TypeNPM, 318 Locations: []string{"testdata/commits.v1.lock"}, 319 SourceCode: &extractor.SourceCodeIdentifier{ 320 Commit: "0a2d2506c1fe299691fc5db53a2097db3bd615bc", 321 }, 322 }, 323 { 324 Name: "mine3", 325 Version: "1.2.3", 326 PURLType: purl.TypeNPM, 327 Locations: []string{"testdata/commits.v1.lock"}, 328 SourceCode: &extractor.SourceCodeIdentifier{ 329 Commit: "094e581aaf927d010e4b61d706ba584551dac502", 330 }, 331 }, 332 { 333 Name: "mine4", 334 Version: "0.0.2", 335 PURLType: purl.TypeNPM, 336 Locations: []string{"testdata/commits.v1.lock"}, 337 SourceCode: &extractor.SourceCodeIdentifier{ 338 Commit: "aa3bdfcb1d845c79f14abb66f60d35b8a3ee5998", 339 }, 340 }, 341 { 342 Name: "mine4", 343 Version: "0.0.4", 344 PURLType: purl.TypeNPM, 345 Locations: []string{"testdata/commits.v1.lock"}, 346 SourceCode: &extractor.SourceCodeIdentifier{ 347 Commit: "aa3bdfcb1d845c79f14abb66f60d35b8a3ee5998", 348 }, 349 }, 350 { 351 Name: "my-package", 352 Version: "1.8.3", 353 PURLType: purl.TypeNPM, 354 Locations: []string{"testdata/commits.v1.lock"}, 355 SourceCode: &extractor.SourceCodeIdentifier{ 356 Commit: "b3bd3f1b3dad036e671251f5258beaae398f983a", 357 }, 358 }, 359 { 360 Name: "@bower_components/angular-animate", 361 Version: "1.4.14", 362 PURLType: purl.TypeNPM, 363 Locations: []string{"testdata/commits.v1.lock"}, 364 SourceCode: &extractor.SourceCodeIdentifier{ 365 Commit: "e7f778fc054a086ba3326d898a00fa1bc78650a8", 366 }, 367 }, 368 { 369 Name: "@bower_components/alertify", 370 Version: "0.0.0", 371 PURLType: purl.TypeNPM, 372 Locations: []string{"testdata/commits.v1.lock"}, 373 SourceCode: &extractor.SourceCodeIdentifier{ 374 Commit: "e7b6c46d76604d297c389d830817b611c9a8f17c", 375 }, 376 }, 377 { 378 Name: "minimist", 379 Version: "0.0.8", 380 PURLType: purl.TypeNPM, 381 Locations: []string{"testdata/commits.v1.lock"}, 382 SourceCode: &extractor.SourceCodeIdentifier{ 383 Commit: "3754568bfd43a841d2d72d7fb54598635aea8fa4", 384 }, 385 }, 386 { 387 Name: "bats-assert", 388 Version: "2.0.0", 389 PURLType: purl.TypeNPM, 390 Locations: []string{"testdata/commits.v1.lock"}, 391 SourceCode: &extractor.SourceCodeIdentifier{ 392 Commit: "4bdd58d3fbcdce3209033d44d884e87add1d8405", 393 }, 394 }, 395 { 396 Name: "bats-support", 397 Version: "0.3.0", 398 PURLType: purl.TypeNPM, 399 Locations: []string{"testdata/commits.v1.lock"}, 400 SourceCode: &extractor.SourceCodeIdentifier{ 401 Commit: "d140a65044b2d6810381935ae7f0c94c7023c8c3", 402 }, 403 }, 404 { 405 Name: "bats", 406 Version: "1.5.0", 407 PURLType: purl.TypeNPM, 408 Locations: []string{"testdata/commits.v1.lock"}, 409 SourceCode: &extractor.SourceCodeIdentifier{ 410 Commit: "172580d2ce19ee33780b5f1df817bbddced43789", 411 }, 412 }, 413 { 414 Name: "vue", 415 Version: "2.6.12", 416 PURLType: purl.TypeNPM, 417 Locations: []string{"testdata/commits.v1.lock"}, 418 SourceCode: &extractor.SourceCodeIdentifier{ 419 Commit: "bb253db0b3e17124b6d1fe93fbf2db35470a1347", 420 }, 421 }, 422 { 423 Name: "kit", 424 Version: "1.0.0", 425 PURLType: purl.TypeNPM, 426 Locations: []string{"testdata/commits.v1.lock"}, 427 SourceCode: &extractor.SourceCodeIdentifier{ 428 Commit: "5b6830c0252eb73c6024d40a8ff5106d3023a2a6", 429 }, 430 }, 431 { 432 Name: "casadistance", 433 Version: "1.0.0", 434 PURLType: purl.TypeNPM, 435 Locations: []string{"testdata/commits.v1.lock"}, 436 SourceCode: &extractor.SourceCodeIdentifier{ 437 Commit: "f0308391f0c50104182bfb2332a53e4e523a4603", 438 }, 439 }, 440 { 441 Name: "babel-preset-php", 442 Version: "1.1.1", 443 PURLType: purl.TypeNPM, 444 Locations: []string{"testdata/commits.v1.lock"}, 445 SourceCode: &extractor.SourceCodeIdentifier{ 446 Commit: "c5a7ba5e0ad98b8db1cb8ce105403dd4b768cced", 447 }, 448 }, 449 { 450 Name: "is-number", 451 Version: "2.0.0", 452 PURLType: purl.TypeNPM, 453 Locations: []string{"testdata/commits.v1.lock"}, 454 SourceCode: &extractor.SourceCodeIdentifier{ 455 Commit: "d5ac0584ee9ae7bd9288220a39780f155b9ad4c8", 456 }, 457 }, 458 { 459 Name: "is-number", 460 Version: "5.0.0", 461 PURLType: purl.TypeNPM, 462 Locations: []string{"testdata/commits.v1.lock"}, 463 SourceCode: &extractor.SourceCodeIdentifier{ 464 Commit: "af885e2e890b9ef0875edd2b117305119ee5bdc5", 465 }, 466 }, 467 }, 468 }, 469 { 470 Name: "files", 471 InputConfig: extracttest.ScanInputMockConfig{ 472 Path: "testdata/files.v1.lock", 473 }, 474 WantPackages: []*extractor.Package{ 475 { 476 Name: "etag", 477 Version: "1.8.1", 478 PURLType: purl.TypeNPM, 479 Locations: []string{"testdata/files.v1.lock"}, 480 SourceCode: &extractor.SourceCodeIdentifier{ 481 Commit: "", 482 }, 483 }, 484 { 485 Name: "filedep", 486 Version: "1.2.0", 487 PURLType: purl.TypeNPM, 488 Locations: []string{"testdata/files.v1.lock"}, 489 SourceCode: &extractor.SourceCodeIdentifier{ 490 Commit: "", 491 }, 492 }, 493 { 494 Name: "lodash", 495 Version: "1.3.1", 496 PURLType: purl.TypeNPM, 497 Locations: []string{"testdata/files.v1.lock"}, 498 SourceCode: &extractor.SourceCodeIdentifier{ 499 Commit: "", 500 }, 501 }, 502 { 503 Name: "other_package", 504 Version: "0.0.2", 505 PURLType: purl.TypeNPM, 506 Locations: []string{"testdata/files.v1.lock"}, 507 SourceCode: &extractor.SourceCodeIdentifier{ 508 Commit: "", 509 }, 510 }, 511 { 512 Name: "sprintf-js", 513 Version: "0.0.0", 514 PURLType: purl.TypeNPM, 515 Locations: []string{"testdata/files.v1.lock"}, 516 SourceCode: &extractor.SourceCodeIdentifier{ 517 Commit: "", 518 }, 519 }, 520 { 521 Name: "etag", 522 Version: "1.8.0", 523 PURLType: purl.TypeNPM, 524 Locations: []string{"testdata/files.v1.lock"}, 525 SourceCode: &extractor.SourceCodeIdentifier{ 526 Commit: "", 527 }, 528 }, 529 }, 530 }, 531 { 532 Name: "with aliases", 533 InputConfig: extracttest.ScanInputMockConfig{ 534 Path: "testdata/with-aliases.v1.lock", 535 }, 536 WantPackages: []*extractor.Package{ 537 { 538 Name: "@babel/helper-validator-identifier", 539 Version: "7.22.20", 540 PURLType: purl.TypeNPM, 541 Locations: []string{"testdata/with-aliases.v1.lock"}, 542 SourceCode: &extractor.SourceCodeIdentifier{ 543 Commit: "", 544 }, 545 }, 546 { 547 Name: "ansi-regex", 548 Version: "6.0.1", 549 PURLType: purl.TypeNPM, 550 Locations: []string{"testdata/with-aliases.v1.lock"}, 551 SourceCode: &extractor.SourceCodeIdentifier{ 552 Commit: "", 553 }, 554 }, 555 { 556 Name: "ansi-regex", 557 Version: "5.0.1", 558 PURLType: purl.TypeNPM, 559 Locations: []string{"testdata/with-aliases.v1.lock"}, 560 SourceCode: &extractor.SourceCodeIdentifier{ 561 Commit: "", 562 }, 563 }, 564 }, 565 }, 566 } 567 568 for _, tt := range tests { 569 t.Run(tt.Name, func(t *testing.T) { 570 extr := yarnlock.Extractor{} 571 572 scanInput := extracttest.GenerateScanInputMock(t, tt.InputConfig) 573 defer extracttest.CloseTestScanInput(t, scanInput) 574 575 got, err := extr.Extract(t.Context(), &scanInput) 576 577 if diff := cmp.Diff(tt.WantErr, err, cmpopts.EquateErrors()); diff != "" { 578 t.Errorf("%s.Extract(%q) error diff (-want +got):\n%s", extr.Name(), tt.InputConfig.Path, diff) 579 return 580 } 581 582 wantInv := inventory.Inventory{Packages: tt.WantPackages} 583 if diff := cmp.Diff(wantInv, got, cmpopts.SortSlices(extracttest.PackageCmpLess)); diff != "" { 584 t.Errorf("%s.Extract(%q) diff (-want +got):\n%s", extr.Name(), tt.InputConfig.Path, diff) 585 } 586 }) 587 } 588 }