github.com/google/osv-scalibr@v0.4.1/extractor/filesystem/language/javascript/pnpmlock/pnpmlock-v9_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 pnpmlock_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/pnpmlock"
    24  	"github.com/google/osv-scalibr/extractor/filesystem/osv"
    25  	"github.com/google/osv-scalibr/inventory"
    26  	"github.com/google/osv-scalibr/purl"
    27  	"github.com/google/osv-scalibr/testing/extracttest"
    28  )
    29  
    30  func TestExtractor_Extract_v9(t *testing.T) {
    31  	tests := []extracttest.TestTableEntry{
    32  		{
    33  			Name: "no packages",
    34  			InputConfig: extracttest.ScanInputMockConfig{
    35  				Path: "testdata/no-packages.v9.yaml",
    36  			},
    37  			WantPackages: []*extractor.Package{},
    38  		},
    39  		{
    40  			Name: "one package",
    41  			InputConfig: extracttest.ScanInputMockConfig{
    42  				Path: "testdata/one-package.v9.yaml",
    43  			},
    44  			WantPackages: []*extractor.Package{
    45  				{
    46  					Name:       "acorn",
    47  					Version:    "8.11.3",
    48  					PURLType:   purl.TypeNPM,
    49  					Locations:  []string{"testdata/one-package.v9.yaml"},
    50  					SourceCode: &extractor.SourceCodeIdentifier{},
    51  					Metadata: osv.DepGroupMetadata{
    52  						DepGroupVals: []string{},
    53  					},
    54  				},
    55  			},
    56  		},
    57  		{
    58  			Name: "one package dev",
    59  			InputConfig: extracttest.ScanInputMockConfig{
    60  				Path: "testdata/one-package-dev.v9.yaml",
    61  			},
    62  			WantPackages: []*extractor.Package{
    63  				{
    64  					Name:       "acorn",
    65  					Version:    "8.11.3",
    66  					PURLType:   purl.TypeNPM,
    67  					Locations:  []string{"testdata/one-package-dev.v9.yaml"},
    68  					SourceCode: &extractor.SourceCodeIdentifier{},
    69  					Metadata: osv.DepGroupMetadata{
    70  						DepGroupVals: []string{},
    71  					},
    72  				},
    73  			},
    74  		},
    75  		{
    76  			Name: "scoped packages",
    77  			InputConfig: extracttest.ScanInputMockConfig{
    78  				Path: "testdata/scoped-packages.v9.yaml",
    79  			},
    80  			WantPackages: []*extractor.Package{
    81  				{
    82  					Name:       "@typescript-eslint/types",
    83  					Version:    "5.62.0",
    84  					PURLType:   purl.TypeNPM,
    85  					Locations:  []string{"testdata/scoped-packages.v9.yaml"},
    86  					SourceCode: &extractor.SourceCodeIdentifier{},
    87  					Metadata: osv.DepGroupMetadata{
    88  						DepGroupVals: []string{},
    89  					},
    90  				},
    91  			},
    92  		},
    93  		{
    94  			Name: "peer dependencies",
    95  			InputConfig: extracttest.ScanInputMockConfig{
    96  				Path: "testdata/peer-dependencies.v9.yaml",
    97  			},
    98  			WantPackages: []*extractor.Package{
    99  				{
   100  					Name:       "acorn-jsx",
   101  					Version:    "5.3.2",
   102  					PURLType:   purl.TypeNPM,
   103  					Locations:  []string{"testdata/peer-dependencies.v9.yaml"},
   104  					SourceCode: &extractor.SourceCodeIdentifier{},
   105  					Metadata: osv.DepGroupMetadata{
   106  						DepGroupVals: []string{},
   107  					},
   108  				},
   109  				{
   110  					Name:       "acorn",
   111  					Version:    "8.11.3",
   112  					PURLType:   purl.TypeNPM,
   113  					Locations:  []string{"testdata/peer-dependencies.v9.yaml"},
   114  					SourceCode: &extractor.SourceCodeIdentifier{},
   115  					Metadata: osv.DepGroupMetadata{
   116  						DepGroupVals: []string{},
   117  					},
   118  				},
   119  			},
   120  		},
   121  		{
   122  			Name: "peer dependencies advanced",
   123  			InputConfig: extracttest.ScanInputMockConfig{
   124  				Path: "testdata/peer-dependencies-advanced.v9.yaml",
   125  			},
   126  			WantPackages: []*extractor.Package{
   127  				{
   128  					Name:       "@eslint-community/eslint-utils",
   129  					Version:    "4.4.0",
   130  					PURLType:   purl.TypeNPM,
   131  					Locations:  []string{"testdata/peer-dependencies-advanced.v9.yaml"},
   132  					SourceCode: &extractor.SourceCodeIdentifier{},
   133  					Metadata: osv.DepGroupMetadata{
   134  						DepGroupVals: []string{},
   135  					},
   136  				},
   137  				{
   138  					Name:       "@eslint/eslintrc",
   139  					Version:    "2.1.4",
   140  					PURLType:   purl.TypeNPM,
   141  					Locations:  []string{"testdata/peer-dependencies-advanced.v9.yaml"},
   142  					SourceCode: &extractor.SourceCodeIdentifier{},
   143  					Metadata: osv.DepGroupMetadata{
   144  						DepGroupVals: []string{},
   145  					},
   146  				},
   147  				{
   148  					Name:       "@typescript-eslint/eslint-plugin",
   149  					Version:    "5.62.0",
   150  					PURLType:   purl.TypeNPM,
   151  					Locations:  []string{"testdata/peer-dependencies-advanced.v9.yaml"},
   152  					SourceCode: &extractor.SourceCodeIdentifier{},
   153  					Metadata: osv.DepGroupMetadata{
   154  						DepGroupVals: []string{},
   155  					},
   156  				},
   157  				{
   158  					Name:       "@typescript-eslint/parser",
   159  					Version:    "5.62.0",
   160  					PURLType:   purl.TypeNPM,
   161  					Locations:  []string{"testdata/peer-dependencies-advanced.v9.yaml"},
   162  					SourceCode: &extractor.SourceCodeIdentifier{},
   163  					Metadata: osv.DepGroupMetadata{
   164  						DepGroupVals: []string{},
   165  					},
   166  				},
   167  				{
   168  					Name:       "@typescript-eslint/type-utils",
   169  					Version:    "5.62.0",
   170  					PURLType:   purl.TypeNPM,
   171  					Locations:  []string{"testdata/peer-dependencies-advanced.v9.yaml"},
   172  					SourceCode: &extractor.SourceCodeIdentifier{},
   173  					Metadata: osv.DepGroupMetadata{
   174  						DepGroupVals: []string{},
   175  					},
   176  				},
   177  				{
   178  					Name:       "@typescript-eslint/typescript-estree",
   179  					Version:    "5.62.0",
   180  					PURLType:   purl.TypeNPM,
   181  					Locations:  []string{"testdata/peer-dependencies-advanced.v9.yaml"},
   182  					SourceCode: &extractor.SourceCodeIdentifier{},
   183  					Metadata: osv.DepGroupMetadata{
   184  						DepGroupVals: []string{},
   185  					},
   186  				},
   187  				{
   188  					Name:       "@typescript-eslint/utils",
   189  					Version:    "5.62.0",
   190  					PURLType:   purl.TypeNPM,
   191  					Locations:  []string{"testdata/peer-dependencies-advanced.v9.yaml"},
   192  					SourceCode: &extractor.SourceCodeIdentifier{},
   193  					Metadata: osv.DepGroupMetadata{
   194  						DepGroupVals: []string{},
   195  					},
   196  				},
   197  				{
   198  					Name:       "debug",
   199  					Version:    "4.3.4",
   200  					PURLType:   purl.TypeNPM,
   201  					Locations:  []string{"testdata/peer-dependencies-advanced.v9.yaml"},
   202  					SourceCode: &extractor.SourceCodeIdentifier{},
   203  					Metadata: osv.DepGroupMetadata{
   204  						DepGroupVals: []string{},
   205  					},
   206  				},
   207  				{
   208  					Name:       "eslint",
   209  					Version:    "8.57.0",
   210  					PURLType:   purl.TypeNPM,
   211  					Locations:  []string{"testdata/peer-dependencies-advanced.v9.yaml"},
   212  					SourceCode: &extractor.SourceCodeIdentifier{},
   213  					Metadata: osv.DepGroupMetadata{
   214  						DepGroupVals: []string{},
   215  					},
   216  				},
   217  				{
   218  					Name:       "has-flag",
   219  					Version:    "4.0.0",
   220  					PURLType:   purl.TypeNPM,
   221  					Locations:  []string{"testdata/peer-dependencies-advanced.v9.yaml"},
   222  					SourceCode: &extractor.SourceCodeIdentifier{},
   223  					Metadata: osv.DepGroupMetadata{
   224  						DepGroupVals: []string{},
   225  					},
   226  				},
   227  				{
   228  					Name:       "supports-color",
   229  					Version:    "7.2.0",
   230  					PURLType:   purl.TypeNPM,
   231  					Locations:  []string{"testdata/peer-dependencies-advanced.v9.yaml"},
   232  					SourceCode: &extractor.SourceCodeIdentifier{},
   233  					Metadata: osv.DepGroupMetadata{
   234  						DepGroupVals: []string{},
   235  					},
   236  				},
   237  				{
   238  					Name:       "tsutils",
   239  					Version:    "3.21.0",
   240  					PURLType:   purl.TypeNPM,
   241  					Locations:  []string{"testdata/peer-dependencies-advanced.v9.yaml"},
   242  					SourceCode: &extractor.SourceCodeIdentifier{},
   243  					Metadata: osv.DepGroupMetadata{
   244  						DepGroupVals: []string{},
   245  					},
   246  				},
   247  				{
   248  					Name:       "typescript",
   249  					Version:    "4.9.5",
   250  					PURLType:   purl.TypeNPM,
   251  					Locations:  []string{"testdata/peer-dependencies-advanced.v9.yaml"},
   252  					SourceCode: &extractor.SourceCodeIdentifier{},
   253  					Metadata: osv.DepGroupMetadata{
   254  						DepGroupVals: []string{},
   255  					},
   256  				},
   257  			},
   258  		},
   259  		{
   260  			Name: "multiple versions",
   261  			InputConfig: extracttest.ScanInputMockConfig{
   262  				Path: "testdata/multiple-versions.v9.yaml",
   263  			},
   264  			WantPackages: []*extractor.Package{
   265  				{
   266  					Name:       "uuid",
   267  					Version:    "8.0.0",
   268  					PURLType:   purl.TypeNPM,
   269  					Locations:  []string{"testdata/multiple-versions.v9.yaml"},
   270  					SourceCode: &extractor.SourceCodeIdentifier{},
   271  					Metadata: osv.DepGroupMetadata{
   272  						DepGroupVals: []string{},
   273  					},
   274  				},
   275  				{
   276  					Name:       "uuid",
   277  					Version:    "8.3.2",
   278  					PURLType:   purl.TypeNPM,
   279  					Locations:  []string{"testdata/multiple-versions.v9.yaml"},
   280  					SourceCode: &extractor.SourceCodeIdentifier{},
   281  					Metadata: osv.DepGroupMetadata{
   282  						DepGroupVals: []string{},
   283  					},
   284  				},
   285  				{
   286  					Name:       "xmlbuilder",
   287  					Version:    "11.0.1",
   288  					PURLType:   purl.TypeNPM,
   289  					Locations:  []string{"testdata/multiple-versions.v9.yaml"},
   290  					SourceCode: &extractor.SourceCodeIdentifier{},
   291  					Metadata: osv.DepGroupMetadata{
   292  						DepGroupVals: []string{},
   293  					},
   294  				},
   295  			},
   296  		},
   297  		{
   298  			Name: "commits",
   299  			InputConfig: extracttest.ScanInputMockConfig{
   300  				Path: "testdata/commits.v9.yaml",
   301  			},
   302  			WantPackages: []*extractor.Package{
   303  				{
   304  					Name:      "ansi-regex",
   305  					Version:   "6.0.1",
   306  					PURLType:  purl.TypeNPM,
   307  					Locations: []string{"testdata/commits.v9.yaml"},
   308  					SourceCode: &extractor.SourceCodeIdentifier{
   309  						Commit: "02fa893d619d3da85411acc8fd4e2eea0e95a9d9",
   310  					},
   311  					Metadata: osv.DepGroupMetadata{
   312  						DepGroupVals: []string{},
   313  					},
   314  				},
   315  				{
   316  					Name:      "is-number",
   317  					Version:   "7.0.0",
   318  					PURLType:  purl.TypeNPM,
   319  					Locations: []string{"testdata/commits.v9.yaml"},
   320  					SourceCode: &extractor.SourceCodeIdentifier{
   321  						Commit: "98e8ff1da1a89f93d1397a24d7413ed15421c139",
   322  					},
   323  					Metadata: osv.DepGroupMetadata{
   324  						DepGroupVals: []string{},
   325  					},
   326  				},
   327  			},
   328  		},
   329  		{
   330  			Name: "mixed groups",
   331  			InputConfig: extracttest.ScanInputMockConfig{
   332  				Path: "testdata/mixed-groups.v9.yaml",
   333  			},
   334  			WantPackages: []*extractor.Package{
   335  				{
   336  					Name:       "ansi-regex",
   337  					Version:    "5.0.1",
   338  					PURLType:   purl.TypeNPM,
   339  					Locations:  []string{"testdata/mixed-groups.v9.yaml"},
   340  					SourceCode: &extractor.SourceCodeIdentifier{},
   341  					Metadata: osv.DepGroupMetadata{
   342  						DepGroupVals: []string{},
   343  					},
   344  				},
   345  				{
   346  					Name:       "uuid",
   347  					Version:    "8.3.2",
   348  					PURLType:   purl.TypeNPM,
   349  					Locations:  []string{"testdata/mixed-groups.v9.yaml"},
   350  					SourceCode: &extractor.SourceCodeIdentifier{},
   351  					Metadata: osv.DepGroupMetadata{
   352  						DepGroupVals: []string{},
   353  					},
   354  				},
   355  				{
   356  					Name:       "is-number",
   357  					Version:    "7.0.0",
   358  					PURLType:   purl.TypeNPM,
   359  					Locations:  []string{"testdata/mixed-groups.v9.yaml"},
   360  					SourceCode: &extractor.SourceCodeIdentifier{},
   361  					Metadata: osv.DepGroupMetadata{
   362  						DepGroupVals: []string{},
   363  					},
   364  				},
   365  			},
   366  		},
   367  	}
   368  
   369  	for _, tt := range tests {
   370  		t.Run(tt.Name, func(t *testing.T) {
   371  			extr := pnpmlock.Extractor{}
   372  
   373  			scanInput := extracttest.GenerateScanInputMock(t, tt.InputConfig)
   374  			defer extracttest.CloseTestScanInput(t, scanInput)
   375  
   376  			got, err := extr.Extract(t.Context(), &scanInput)
   377  
   378  			if diff := cmp.Diff(tt.WantErr, err, cmpopts.EquateErrors()); diff != "" {
   379  				t.Errorf("%s.Extract(%q) error diff (-want +got):\n%s", extr.Name(), tt.InputConfig.Path, diff)
   380  				return
   381  			}
   382  
   383  			wantInv := inventory.Inventory{Packages: tt.WantPackages}
   384  			if diff := cmp.Diff(wantInv, got, cmpopts.SortSlices(extracttest.PackageCmpLess)); diff != "" {
   385  				t.Errorf("%s.Extract(%q) diff (-want +got):\n%s", extr.Name(), tt.InputConfig.Path, diff)
   386  			}
   387  		})
   388  	}
   389  }