github.com/google/osv-scalibr@v0.4.1/extractor/filesystem/language/dart/pubspec/pubspec_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 pubspec_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/dart/pubspec" 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 inputPath: "", 39 want: false, 40 }, 41 { 42 inputPath: "pubspec.lock", 43 want: true, 44 }, 45 { 46 inputPath: "path/to/my/pubspec.lock", 47 want: true, 48 }, 49 { 50 inputPath: "path/to/my/pubspec.lock/file", 51 want: false, 52 }, 53 { 54 inputPath: "path/to/my/pubspec.lock.file", 55 want: false, 56 }, 57 { 58 inputPath: "path.to.my.pubspec.lock", 59 want: false, 60 }, 61 } 62 for _, tt := range tests { 63 t.Run(tt.inputPath, func(t *testing.T) { 64 e := pubspec.Extractor{} 65 got := e.FileRequired(simplefileapi.New(tt.inputPath, nil)) 66 if got != tt.want { 67 t.Errorf("FileRequired(%s, FileInfo) got = %v, want %v", tt.inputPath, got, tt.want) 68 } 69 }) 70 } 71 } 72 73 func TestExtractor_Extract(t *testing.T) { 74 tests := []extracttest.TestTableEntry{ 75 { 76 Name: "invalid yaml", 77 InputConfig: extracttest.ScanInputMockConfig{ 78 Path: "testdata/not-yaml.txt", 79 }, 80 WantErr: extracttest.ContainsErrStr{Str: "could not extract"}, 81 }, 82 { 83 Name: "empty", 84 InputConfig: extracttest.ScanInputMockConfig{ 85 Path: "testdata/empty.lock", 86 }, 87 WantErr: extracttest.ContainsErrStr{Str: "could not extract"}, 88 }, 89 { 90 Name: "no packages", 91 InputConfig: extracttest.ScanInputMockConfig{ 92 Path: "testdata/no-packages.lock", 93 }, 94 WantPackages: []*extractor.Package{}, 95 }, 96 { 97 Name: "one package", 98 InputConfig: extracttest.ScanInputMockConfig{ 99 Path: "testdata/one-package.lock", 100 }, 101 WantPackages: []*extractor.Package{ 102 { 103 Name: "back_button_interceptor", 104 Version: "6.0.1", 105 PURLType: purl.TypePub, 106 Locations: []string{"testdata/one-package.lock"}, 107 SourceCode: &extractor.SourceCodeIdentifier{ 108 Commit: "", 109 }, 110 Metadata: osv.DepGroupMetadata{}, 111 }, 112 }, 113 }, 114 { 115 Name: "one package dev", 116 InputConfig: extracttest.ScanInputMockConfig{ 117 Path: "testdata/one-package-dev.lock", 118 }, 119 WantPackages: []*extractor.Package{ 120 { 121 Name: "build_runner", 122 Version: "2.2.1", 123 PURLType: purl.TypePub, 124 Locations: []string{"testdata/one-package-dev.lock"}, 125 SourceCode: &extractor.SourceCodeIdentifier{ 126 Commit: "", 127 }, 128 Metadata: osv.DepGroupMetadata{ 129 DepGroupVals: []string{"dev"}, 130 }, 131 }, 132 }, 133 }, 134 { 135 Name: "two packages", 136 InputConfig: extracttest.ScanInputMockConfig{ 137 Path: "testdata/two-packages.lock", 138 }, 139 WantPackages: []*extractor.Package{ 140 { 141 Name: "shelf", 142 Version: "1.3.2", 143 PURLType: purl.TypePub, 144 Locations: []string{"testdata/two-packages.lock"}, 145 SourceCode: &extractor.SourceCodeIdentifier{ 146 Commit: "", 147 }, 148 Metadata: osv.DepGroupMetadata{}, 149 }, 150 { 151 Name: "shelf_web_socket", 152 Version: "1.0.2", 153 PURLType: purl.TypePub, 154 Locations: []string{"testdata/two-packages.lock"}, 155 SourceCode: &extractor.SourceCodeIdentifier{ 156 Commit: "", 157 }, 158 Metadata: osv.DepGroupMetadata{}, 159 }, 160 }, 161 }, 162 { 163 Name: "mixed packages", 164 InputConfig: extracttest.ScanInputMockConfig{ 165 Path: "testdata/mixed-packages.lock", 166 }, 167 WantPackages: []*extractor.Package{ 168 { 169 Name: "back_button_interceptor", 170 Version: "6.0.1", 171 PURLType: purl.TypePub, 172 Locations: []string{"testdata/mixed-packages.lock"}, 173 SourceCode: &extractor.SourceCodeIdentifier{ 174 Commit: "", 175 }, 176 Metadata: osv.DepGroupMetadata{}, 177 }, 178 { 179 Name: "build_runner", 180 Version: "2.2.1", 181 PURLType: purl.TypePub, 182 Locations: []string{"testdata/mixed-packages.lock"}, 183 SourceCode: &extractor.SourceCodeIdentifier{ 184 Commit: "", 185 }, 186 Metadata: osv.DepGroupMetadata{ 187 DepGroupVals: []string{"dev"}, 188 }, 189 }, 190 { 191 Name: "shelf", 192 Version: "1.3.2", 193 PURLType: purl.TypePub, 194 Locations: []string{"testdata/mixed-packages.lock"}, 195 SourceCode: &extractor.SourceCodeIdentifier{ 196 Commit: "", 197 }, 198 Metadata: osv.DepGroupMetadata{}, 199 }, 200 { 201 Name: "shelf_web_socket", 202 Version: "1.0.2", 203 PURLType: purl.TypePub, 204 Locations: []string{"testdata/mixed-packages.lock"}, 205 SourceCode: &extractor.SourceCodeIdentifier{ 206 Commit: "", 207 }, 208 Metadata: osv.DepGroupMetadata{}, 209 }, 210 }, 211 }, 212 { 213 Name: "package with git source", 214 InputConfig: extracttest.ScanInputMockConfig{ 215 Path: "testdata/source-git.lock", 216 }, 217 WantPackages: []*extractor.Package{ 218 { 219 Name: "flutter_rust_bridge", 220 Version: "1.32.0", 221 PURLType: purl.TypePub, 222 Locations: []string{"testdata/source-git.lock"}, 223 SourceCode: &extractor.SourceCodeIdentifier{ 224 Commit: "e5adce55eea0b74d3680e66a2c5252edf17b07e1", 225 }, 226 Metadata: osv.DepGroupMetadata{}, 227 }, 228 { 229 Name: "screen_retriever", 230 Version: "0.1.2", 231 PURLType: purl.TypePub, 232 Locations: []string{"testdata/source-git.lock"}, 233 SourceCode: &extractor.SourceCodeIdentifier{ 234 Commit: "406b9b038b2c1d779f1e7bf609c8c248be247372", 235 }, 236 Metadata: osv.DepGroupMetadata{}, 237 }, 238 { 239 Name: "tray_manager", 240 Version: "0.1.8", 241 PURLType: purl.TypePub, 242 Locations: []string{"testdata/source-git.lock"}, 243 SourceCode: &extractor.SourceCodeIdentifier{ 244 Commit: "3aa37c86e47ea748e7b5507cbe59f2c54ebdb23a", 245 }, 246 Metadata: osv.DepGroupMetadata{}, 247 }, 248 { 249 Name: "window_manager", 250 Version: "0.2.7", 251 PURLType: purl.TypePub, 252 Locations: []string{"testdata/source-git.lock"}, 253 SourceCode: &extractor.SourceCodeIdentifier{ 254 Commit: "88487257cbafc501599ab4f82ec343b46acec020", 255 }, 256 Metadata: osv.DepGroupMetadata{}, 257 }, 258 { 259 Name: "toggle_switch", 260 Version: "1.4.0", 261 PURLType: purl.TypePub, 262 Locations: []string{"testdata/source-git.lock"}, 263 SourceCode: &extractor.SourceCodeIdentifier{ 264 Commit: "", 265 }, 266 Metadata: osv.DepGroupMetadata{}, 267 }, 268 }, 269 }, 270 { 271 Name: "package with sdk source", 272 InputConfig: extracttest.ScanInputMockConfig{ 273 Path: "testdata/source-sdk.lock", 274 }, 275 WantPackages: []*extractor.Package{ 276 { 277 Name: "flutter_web_plugins", 278 Version: "0.0.0", 279 PURLType: purl.TypePub, 280 Locations: []string{"testdata/source-sdk.lock"}, 281 SourceCode: &extractor.SourceCodeIdentifier{ 282 Commit: "", 283 }, 284 Metadata: osv.DepGroupMetadata{}, 285 }, 286 }, 287 }, 288 { 289 Name: "package with path source", 290 InputConfig: extracttest.ScanInputMockConfig{ 291 Path: "testdata/source-path.lock", 292 }, 293 WantPackages: []*extractor.Package{ 294 { 295 Name: "maa_core", 296 Version: "0.0.1", 297 PURLType: purl.TypePub, 298 Locations: []string{"testdata/source-path.lock"}, 299 SourceCode: &extractor.SourceCodeIdentifier{ 300 Commit: "", 301 }, 302 Metadata: osv.DepGroupMetadata{}, 303 }, 304 }, 305 }, 306 } 307 308 for _, tt := range tests { 309 t.Run(tt.Name, func(t *testing.T) { 310 extr := pubspec.Extractor{} 311 312 scanInput := extracttest.GenerateScanInputMock(t, tt.InputConfig) 313 defer extracttest.CloseTestScanInput(t, scanInput) 314 315 got, err := extr.Extract(t.Context(), &scanInput) 316 317 if diff := cmp.Diff(tt.WantErr, err, cmpopts.EquateErrors()); diff != "" { 318 t.Errorf("%s.Extract(%q) error diff (-want +got):\n%s", extr.Name(), tt.InputConfig.Path, diff) 319 return 320 } 321 322 wantInv := inventory.Inventory{Packages: tt.WantPackages} 323 if diff := cmp.Diff(wantInv, got, cmpopts.SortSlices(extracttest.PackageCmpLess)); diff != "" { 324 t.Errorf("%s.Extract(%q) diff (-want +got):\n%s", extr.Name(), tt.InputConfig.Path, diff) 325 } 326 }) 327 } 328 }