github.com/google/osv-scalibr@v0.4.1/extractor/filesystem/language/python/pipfilelock/pipfilelock_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 pipfilelock_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/python/pipfilelock" 24 "github.com/google/osv-scalibr/extractor/filesystem/osv" 25 "github.com/google/osv-scalibr/extractor/filesystem/simplefileapi" 26 "github.com/google/osv-scalibr/inventory" 27 "github.com/google/osv-scalibr/purl" 28 "github.com/google/osv-scalibr/testing/extracttest" 29 ) 30 31 func TestExtractor_FileRequired(t *testing.T) { 32 tests := []struct { 33 name string 34 inputPath string 35 want bool 36 }{ 37 { 38 name: "", 39 inputPath: "", 40 want: false, 41 }, 42 { 43 name: "", 44 inputPath: "Pipfile.lock", 45 want: true, 46 }, 47 { 48 name: "", 49 inputPath: "path/to/my/Pipfile.lock", 50 want: true, 51 }, 52 { 53 name: "", 54 inputPath: "path/to/my/Pipfile.lock/file", 55 want: false, 56 }, 57 { 58 name: "", 59 inputPath: "path/to/my/Pipfile.lock.file", 60 want: false, 61 }, 62 { 63 name: "", 64 inputPath: "path.to.my.Pipfile.lock", 65 want: false, 66 }, 67 } 68 for _, tt := range tests { 69 t.Run(tt.name, func(t *testing.T) { 70 e := pipfilelock.Extractor{} 71 got := e.FileRequired(simplefileapi.New(tt.inputPath, nil)) 72 if got != tt.want { 73 t.Errorf("FileRequired(%q, FileInfo) got = %v, want %v", tt.inputPath, got, tt.want) 74 } 75 }) 76 } 77 } 78 79 func TestExtractor_Extract(t *testing.T) { 80 tests := []extracttest.TestTableEntry{ 81 { 82 Name: "invalid json", 83 InputConfig: extracttest.ScanInputMockConfig{ 84 Path: "testdata/not-json.txt", 85 }, 86 WantErr: extracttest.ContainsErrStr{Str: "could not extract"}, 87 WantPackages: nil, 88 }, 89 { 90 Name: "no packages", 91 InputConfig: extracttest.ScanInputMockConfig{ 92 Path: "testdata/empty.json", 93 }, 94 WantPackages: nil, 95 }, 96 { 97 Name: "one package", 98 InputConfig: extracttest.ScanInputMockConfig{ 99 Path: "testdata/one-package.json", 100 }, 101 WantPackages: []*extractor.Package{ 102 { 103 Name: "markupsafe", 104 Version: "2.1.1", 105 PURLType: purl.TypePyPi, 106 Locations: []string{"testdata/one-package.json"}, 107 Metadata: osv.DepGroupMetadata{ 108 DepGroupVals: []string{}, 109 }, 110 }, 111 }, 112 }, 113 { 114 Name: "one package dev", 115 InputConfig: extracttest.ScanInputMockConfig{ 116 Path: "testdata/one-package-dev.json", 117 }, 118 WantPackages: []*extractor.Package{ 119 { 120 Name: "markupsafe", 121 Version: "2.1.1", 122 PURLType: purl.TypePyPi, 123 Locations: []string{"testdata/one-package-dev.json"}, 124 Metadata: osv.DepGroupMetadata{ 125 DepGroupVals: []string{"dev"}, 126 }, 127 }, 128 }, 129 }, 130 { 131 Name: "two packages", 132 InputConfig: extracttest.ScanInputMockConfig{ 133 Path: "testdata/two-packages.json", 134 }, 135 WantPackages: []*extractor.Package{ 136 { 137 Name: "itsdangerous", 138 Version: "2.1.2", 139 PURLType: purl.TypePyPi, 140 Locations: []string{"testdata/two-packages.json"}, 141 Metadata: osv.DepGroupMetadata{ 142 DepGroupVals: []string{}, 143 }, 144 }, 145 { 146 Name: "markupsafe", 147 Version: "2.1.1", 148 PURLType: purl.TypePyPi, 149 Locations: []string{"testdata/two-packages.json"}, 150 Metadata: osv.DepGroupMetadata{ 151 DepGroupVals: []string{"dev"}, 152 }, 153 }, 154 }, 155 }, 156 { 157 Name: "two packages alt", 158 InputConfig: extracttest.ScanInputMockConfig{ 159 Path: "testdata/two-packages-alt.json", 160 }, 161 WantPackages: []*extractor.Package{ 162 { 163 Name: "itsdangerous", 164 Version: "2.1.2", 165 PURLType: purl.TypePyPi, 166 Locations: []string{"testdata/two-packages-alt.json"}, 167 Metadata: osv.DepGroupMetadata{ 168 DepGroupVals: []string{}, 169 }, 170 }, 171 { 172 Name: "markupsafe", 173 Version: "2.1.1", 174 PURLType: purl.TypePyPi, 175 Locations: []string{"testdata/two-packages-alt.json"}, 176 Metadata: osv.DepGroupMetadata{ 177 DepGroupVals: []string{}, 178 }, 179 }, 180 }, 181 }, 182 { 183 Name: "multiple packages", 184 InputConfig: extracttest.ScanInputMockConfig{ 185 Path: "testdata/multiple-packages.json", 186 }, 187 WantPackages: []*extractor.Package{ 188 { 189 Name: "itsdangerous", 190 Version: "2.1.2", 191 PURLType: purl.TypePyPi, 192 Locations: []string{"testdata/multiple-packages.json"}, 193 Metadata: osv.DepGroupMetadata{ 194 DepGroupVals: []string{}, 195 }, 196 }, 197 { 198 Name: "pluggy", 199 Version: "1.0.1", 200 PURLType: purl.TypePyPi, 201 Locations: []string{"testdata/multiple-packages.json"}, 202 Metadata: osv.DepGroupMetadata{ 203 DepGroupVals: []string{}, 204 }, 205 }, 206 { 207 Name: "pluggy", 208 Version: "1.0.0", 209 PURLType: purl.TypePyPi, 210 Locations: []string{"testdata/multiple-packages.json"}, 211 Metadata: osv.DepGroupMetadata{ 212 DepGroupVals: []string{"dev"}, 213 }, 214 }, 215 { 216 Name: "markupsafe", 217 Version: "2.1.1", 218 PURLType: purl.TypePyPi, 219 Locations: []string{"testdata/multiple-packages.json"}, 220 Metadata: osv.DepGroupMetadata{ 221 DepGroupVals: []string{}, 222 }, 223 }, 224 }, 225 }, 226 { 227 Name: "package without version", 228 InputConfig: extracttest.ScanInputMockConfig{ 229 Path: "testdata/no-version.json", 230 }, 231 WantPackages: nil, 232 }, 233 } 234 235 for _, tt := range tests { 236 t.Run(tt.Name, func(t *testing.T) { 237 extr := pipfilelock.Extractor{} 238 239 scanInput := extracttest.GenerateScanInputMock(t, tt.InputConfig) 240 defer extracttest.CloseTestScanInput(t, scanInput) 241 242 got, err := extr.Extract(t.Context(), &scanInput) 243 244 if diff := cmp.Diff(tt.WantErr, err, cmpopts.EquateErrors()); diff != "" { 245 t.Errorf("%s.Extract(%q) error diff (-want +got):\n%s", extr.Name(), tt.InputConfig.Path, diff) 246 return 247 } 248 249 wantInv := inventory.Inventory{Packages: tt.WantPackages} 250 if diff := cmp.Diff(wantInv, got, cmpopts.SortSlices(extracttest.PackageCmpLess)); diff != "" { 251 t.Errorf("%s.Extract(%q) diff (-want +got):\n%s", extr.Name(), tt.InputConfig.Path, diff) 252 } 253 }) 254 } 255 }