github.com/google/osv-scalibr@v0.4.1/extractor/filesystem/language/javascript/yarnlock/yarnlock-v2_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_v2(t *testing.T) { 30 tests := []extracttest.TestTableEntry{ 31 { 32 Name: "no packages", 33 InputConfig: extracttest.ScanInputMockConfig{ 34 Path: "testdata/empty.v2.lock", 35 }, 36 WantPackages: []*extractor.Package{}, 37 }, 38 { 39 Name: "one package", 40 InputConfig: extracttest.ScanInputMockConfig{ 41 Path: "testdata/one-package.v2.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.v2.lock"}, 49 SourceCode: &extractor.SourceCodeIdentifier{ 50 Commit: "", 51 }, 52 }, 53 }, 54 }, 55 { 56 Name: "two packages", 57 InputConfig: extracttest.ScanInputMockConfig{ 58 Path: "testdata/two-packages.v2.lock", 59 }, 60 WantPackages: []*extractor.Package{ 61 { 62 Name: "compare-func", 63 Version: "2.0.0", 64 PURLType: purl.TypeNPM, 65 Locations: []string{"testdata/two-packages.v2.lock"}, 66 SourceCode: &extractor.SourceCodeIdentifier{ 67 Commit: "", 68 }, 69 }, 70 { 71 Name: "concat-map", 72 Version: "0.0.1", 73 PURLType: purl.TypeNPM, 74 Locations: []string{"testdata/two-packages.v2.lock"}, 75 SourceCode: &extractor.SourceCodeIdentifier{ 76 Commit: "", 77 }, 78 }, 79 }, 80 }, 81 { 82 Name: "with quotes", 83 InputConfig: extracttest.ScanInputMockConfig{ 84 Path: "testdata/with-quotes.v2.lock", 85 }, 86 WantPackages: []*extractor.Package{ 87 { 88 Name: "compare-func", 89 Version: "2.0.0", 90 PURLType: purl.TypeNPM, 91 Locations: []string{"testdata/with-quotes.v2.lock"}, 92 SourceCode: &extractor.SourceCodeIdentifier{ 93 Commit: "", 94 }, 95 }, 96 { 97 Name: "concat-map", 98 Version: "0.0.1", 99 PURLType: purl.TypeNPM, 100 Locations: []string{"testdata/with-quotes.v2.lock"}, 101 SourceCode: &extractor.SourceCodeIdentifier{ 102 Commit: "", 103 }, 104 }, 105 }, 106 }, 107 { 108 Name: "multiple versions", 109 InputConfig: extracttest.ScanInputMockConfig{ 110 Path: "testdata/multiple-versions.v2.lock", 111 }, 112 WantPackages: []*extractor.Package{ 113 { 114 Name: "debug", 115 Version: "4.3.3", 116 PURLType: purl.TypeNPM, 117 Locations: []string{"testdata/multiple-versions.v2.lock"}, 118 SourceCode: &extractor.SourceCodeIdentifier{ 119 Commit: "", 120 }, 121 }, 122 { 123 Name: "debug", 124 Version: "2.6.9", 125 PURLType: purl.TypeNPM, 126 Locations: []string{"testdata/multiple-versions.v2.lock"}, 127 SourceCode: &extractor.SourceCodeIdentifier{ 128 Commit: "", 129 }, 130 }, 131 { 132 Name: "debug", 133 Version: "3.2.7", 134 PURLType: purl.TypeNPM, 135 Locations: []string{"testdata/multiple-versions.v2.lock"}, 136 SourceCode: &extractor.SourceCodeIdentifier{ 137 Commit: "", 138 }, 139 }, 140 }, 141 }, 142 { 143 Name: "scoped packages", 144 InputConfig: extracttest.ScanInputMockConfig{ 145 Path: "testdata/scoped-packages.v2.lock", 146 }, 147 WantPackages: []*extractor.Package{ 148 { 149 Name: "@babel/cli", 150 Version: "7.16.8", 151 PURLType: purl.TypeNPM, 152 Locations: []string{"testdata/scoped-packages.v2.lock"}, 153 SourceCode: &extractor.SourceCodeIdentifier{ 154 Commit: "", 155 }, 156 }, 157 { 158 Name: "@babel/code-frame", 159 Version: "7.16.7", 160 PURLType: purl.TypeNPM, 161 Locations: []string{"testdata/scoped-packages.v2.lock"}, 162 SourceCode: &extractor.SourceCodeIdentifier{ 163 Commit: "", 164 }, 165 }, 166 { 167 Name: "@babel/compat-data", 168 Version: "7.16.8", 169 PURLType: purl.TypeNPM, 170 Locations: []string{"testdata/scoped-packages.v2.lock"}, 171 SourceCode: &extractor.SourceCodeIdentifier{ 172 Commit: "", 173 }, 174 }, 175 }, 176 }, 177 { 178 Name: "with prerelease", 179 InputConfig: extracttest.ScanInputMockConfig{ 180 Path: "testdata/with-prerelease.v2.lock", 181 }, 182 WantPackages: []*extractor.Package{ 183 { 184 Name: "@nicolo-ribaudo/chokidar-2", 185 Version: "2.1.8-no-fsevents.3", 186 PURLType: purl.TypeNPM, 187 Locations: []string{"testdata/with-prerelease.v2.lock"}, 188 SourceCode: &extractor.SourceCodeIdentifier{ 189 Commit: "", 190 }, 191 }, 192 { 193 Name: "gensync", 194 Version: "1.0.0-beta.2", 195 PURLType: purl.TypeNPM, 196 Locations: []string{"testdata/with-prerelease.v2.lock"}, 197 SourceCode: &extractor.SourceCodeIdentifier{ 198 Commit: "", 199 }, 200 }, 201 }, 202 }, 203 { 204 Name: "with build string", 205 InputConfig: extracttest.ScanInputMockConfig{ 206 Path: "testdata/with-build-string.v2.lock", 207 }, 208 WantPackages: []*extractor.Package{ 209 { 210 Name: "domino", 211 Version: "2.1.6+git", 212 PURLType: purl.TypeNPM, 213 Locations: []string{"testdata/with-build-string.v2.lock"}, 214 SourceCode: &extractor.SourceCodeIdentifier{ 215 Commit: "f2435fe1f9f7c91ade0bd472c4723e5eacd7d19a", 216 }, 217 }, 218 { 219 Name: "tslib", 220 Version: "2.6.2", 221 PURLType: purl.TypeNPM, 222 Locations: []string{"testdata/with-build-string.v2.lock"}, 223 SourceCode: &extractor.SourceCodeIdentifier{ 224 Commit: "", 225 }, 226 }, 227 }, 228 }, 229 { 230 Name: "commits", 231 InputConfig: extracttest.ScanInputMockConfig{ 232 Path: "testdata/commits.v2.lock", 233 }, 234 WantPackages: []*extractor.Package{ 235 { 236 Name: "@my-scope/my-first-package", 237 Version: "0.0.6", 238 PURLType: purl.TypeNPM, 239 Locations: []string{"testdata/commits.v2.lock"}, 240 SourceCode: &extractor.SourceCodeIdentifier{ 241 Commit: "0b824c650d3a03444dbcf2b27a5f3566f6e41358", 242 }, 243 }, 244 { 245 Name: "my-second-package", 246 Version: "0.2.2", 247 PURLType: purl.TypeNPM, 248 Locations: []string{"testdata/commits.v2.lock"}, 249 SourceCode: &extractor.SourceCodeIdentifier{ 250 Commit: "59e2127b9f9d4fda5f928c4204213b3502cd5bb0", 251 }, 252 }, 253 { 254 Name: "@typegoose/typegoose", 255 Version: "7.2.0", 256 PURLType: purl.TypeNPM, 257 Locations: []string{"testdata/commits.v2.lock"}, 258 SourceCode: &extractor.SourceCodeIdentifier{ 259 Commit: "3ed06e5097ab929f69755676fee419318aaec73a", 260 }, 261 }, 262 { 263 Name: "vuejs", 264 Version: "2.5.0", 265 PURLType: purl.TypeNPM, 266 Locations: []string{"testdata/commits.v2.lock"}, 267 SourceCode: &extractor.SourceCodeIdentifier{ 268 Commit: "0948d999f2fddf9f90991956493f976273c5da1f", 269 }, 270 }, 271 { 272 Name: "my-third-package", 273 Version: "0.16.1-dev", 274 PURLType: purl.TypeNPM, 275 Locations: []string{"testdata/commits.v2.lock"}, 276 SourceCode: &extractor.SourceCodeIdentifier{ 277 Commit: "5675a0aed98e067ff6ecccc5ac674fe8995960e0", 278 }, 279 }, 280 { 281 Name: "my-node-sdk", 282 Version: "1.1.0", 283 PURLType: purl.TypeNPM, 284 Locations: []string{"testdata/commits.v2.lock"}, 285 SourceCode: &extractor.SourceCodeIdentifier{ 286 Commit: "053dea9e0b8af442d8f867c8e690d2fb0ceb1bf5", 287 }, 288 }, 289 { 290 Name: "is-really-great", 291 Version: "1.0.0", 292 PURLType: purl.TypeNPM, 293 Locations: []string{"testdata/commits.v2.lock"}, 294 SourceCode: &extractor.SourceCodeIdentifier{ 295 Commit: "191eeef50c584714e1fb8927d17ee72b3b8c97c4", 296 }, 297 }, 298 }, 299 }, 300 { 301 Name: "files", 302 InputConfig: extracttest.ScanInputMockConfig{ 303 Path: "testdata/files.v2.lock", 304 }, 305 WantPackages: []*extractor.Package{ 306 { 307 Name: "my-package", 308 Version: "0.0.2", 309 PURLType: purl.TypeNPM, 310 Locations: []string{"testdata/files.v2.lock"}, 311 SourceCode: &extractor.SourceCodeIdentifier{ 312 Commit: "", 313 }, 314 }, 315 }, 316 }, 317 { 318 Name: "with aliases", 319 InputConfig: extracttest.ScanInputMockConfig{ 320 Path: "testdata/with-aliases.v2.lock", 321 }, 322 WantPackages: []*extractor.Package{ 323 { 324 Name: "@babel/helper-validator-identifier", 325 Version: "7.22.20", 326 PURLType: purl.TypeNPM, 327 Locations: []string{"testdata/with-aliases.v2.lock"}, 328 SourceCode: &extractor.SourceCodeIdentifier{ 329 Commit: "", 330 }, 331 }, 332 { 333 Name: "ansi-regex", 334 Version: "6.0.1", 335 PURLType: purl.TypeNPM, 336 Locations: []string{"testdata/with-aliases.v2.lock"}, 337 SourceCode: &extractor.SourceCodeIdentifier{ 338 Commit: "", 339 }, 340 }, 341 { 342 Name: "ansi-regex", 343 Version: "5.0.1", 344 PURLType: purl.TypeNPM, 345 Locations: []string{"testdata/with-aliases.v2.lock"}, 346 SourceCode: &extractor.SourceCodeIdentifier{ 347 Commit: "", 348 }, 349 }, 350 }, 351 }, 352 { 353 Name: "exclude root", 354 InputConfig: extracttest.ScanInputMockConfig{ 355 Path: "testdata/exclude-root.v2.lock", 356 }, 357 WantPackages: []*extractor.Package{ 358 { 359 Name: "@ws/ansi-regex", 360 Version: "0.0.0-use.local", 361 PURLType: purl.TypeNPM, 362 Locations: []string{"testdata/exclude-root.v2.lock"}, 363 SourceCode: &extractor.SourceCodeIdentifier{ 364 Commit: "", 365 }, 366 }, 367 { 368 Name: "ansi-regex", 369 Version: "6.1.0", 370 PURLType: purl.TypeNPM, 371 Locations: []string{"testdata/exclude-root.v2.lock"}, 372 SourceCode: &extractor.SourceCodeIdentifier{ 373 Commit: "", 374 }, 375 }, 376 }, 377 }, 378 } 379 380 for _, tt := range tests { 381 t.Run(tt.Name, func(t *testing.T) { 382 extr := yarnlock.Extractor{} 383 384 scanInput := extracttest.GenerateScanInputMock(t, tt.InputConfig) 385 defer extracttest.CloseTestScanInput(t, scanInput) 386 387 got, err := extr.Extract(t.Context(), &scanInput) 388 389 if diff := cmp.Diff(tt.WantErr, err, cmpopts.EquateErrors()); diff != "" { 390 t.Errorf("%s.Extract(%q) error diff (-want +got):\n%s", extr.Name(), tt.InputConfig.Path, diff) 391 return 392 } 393 394 wantInv := inventory.Inventory{Packages: tt.WantPackages} 395 if diff := cmp.Diff(wantInv, got, cmpopts.SortSlices(extracttest.PackageCmpLess)); diff != "" { 396 t.Errorf("%s.Extract(%q) diff (-want +got):\n%s", extr.Name(), tt.InputConfig.Path, diff) 397 } 398 }) 399 } 400 }