github.com/google/osv-scalibr@v0.4.1/extractor/filesystem/language/java/gradleverificationmetadataxml/gradleverificationmetadataxml_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 gradleverificationmetadataxml_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/java/gradleverificationmetadataxml" 24 "github.com/google/osv-scalibr/extractor/filesystem/language/java/javalockfile" 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: "Empty string", 39 inputPath: "", 40 want: false, 41 }, 42 { 43 name: "file name by itself", 44 inputPath: "verification-metadata.xml", 45 want: false, 46 }, 47 { 48 name: "file under gradle directory", 49 inputPath: "gradle/verification-metadata.xml", 50 want: true, 51 }, 52 { 53 name: "file not under gradle directory", 54 inputPath: "path/to/my/verification-metadata.xml", 55 want: false, 56 }, 57 { 58 name: "more path after file name, not in gradle directory", 59 inputPath: "path/to/my/verification-metadata.xml/file", 60 want: false, 61 }, 62 { 63 name: "wrong extension, not in gradle directory", 64 inputPath: "path/to/my/verification-metadata.xml.file", 65 want: false, 66 }, 67 { 68 name: "file name as suffix, not in gradle directory", 69 inputPath: "path.to.my.verification-metadata.xml", 70 want: false, 71 }, 72 { 73 name: "nested file in gradle directory", 74 inputPath: "path/to/my/gradle/verification-metadata.xml", 75 want: true, 76 }, 77 { 78 name: "more path after file name, in gradle directory", 79 inputPath: "path/to/my/gradle/verification-metadata.xml/file", 80 want: false, 81 }, 82 { 83 name: "wrong extension, in gradle directory", 84 inputPath: "path/to/my/gradle/verification-metadata.xml.file", 85 want: false, 86 }, 87 { 88 name: "gradle in file name instead of as parent directory", 89 inputPath: "path.to.my.gradle.verification-metadata.xml", 90 want: false, 91 }, 92 } 93 for _, tt := range tests { 94 t.Run(tt.name, func(t *testing.T) { 95 e := gradleverificationmetadataxml.Extractor{} 96 got := e.FileRequired(simplefileapi.New(tt.inputPath, nil)) 97 if got != tt.want { 98 t.Errorf("FileRequired(%s, FileInfo) got = %v, want %v", tt.inputPath, got, tt.want) 99 } 100 }) 101 } 102 } 103 104 func TestExtractor_Extract(t *testing.T) { 105 tests := []extracttest.TestTableEntry{ 106 { 107 Name: "invalid xml", 108 InputConfig: extracttest.ScanInputMockConfig{ 109 Path: "testdata/not-xml.txt", 110 }, 111 WantPackages: nil, 112 WantErr: extracttest.ContainsErrStr{Str: "could not extract"}, 113 }, 114 { 115 Name: "no packages", 116 InputConfig: extracttest.ScanInputMockConfig{ 117 Path: "testdata/empty.xml", 118 }, 119 WantPackages: []*extractor.Package{}, 120 }, 121 { 122 Name: "one package", 123 InputConfig: extracttest.ScanInputMockConfig{ 124 Path: "testdata/one-package.xml", 125 }, 126 WantPackages: []*extractor.Package{ 127 { 128 Name: "org.apache.pdfbox:pdfbox", 129 Version: "2.0.17", 130 PURLType: purl.TypeMaven, 131 Locations: []string{"testdata/one-package.xml"}, 132 Metadata: &javalockfile.Metadata{ArtifactID: "pdfbox", GroupID: "org.apache.pdfbox"}, 133 }, 134 }, 135 }, 136 { 137 Name: "two packages", 138 InputConfig: extracttest.ScanInputMockConfig{ 139 Path: "testdata/two-packages.xml", 140 }, 141 WantPackages: []*extractor.Package{ 142 { 143 Name: "org.apache.pdfbox:pdfbox", 144 Version: "2.0.17", 145 PURLType: purl.TypeMaven, 146 Locations: []string{"testdata/two-packages.xml"}, 147 Metadata: &javalockfile.Metadata{ArtifactID: "pdfbox", GroupID: "org.apache.pdfbox"}, 148 }, 149 { 150 Name: "com.github.javaparser:javaparser-core", 151 Version: "3.6.11", 152 PURLType: purl.TypeMaven, 153 Locations: []string{"testdata/two-packages.xml"}, 154 Metadata: &javalockfile.Metadata{ArtifactID: "javaparser-core", GroupID: "com.github.javaparser"}, 155 }, 156 }, 157 }, 158 { 159 Name: "multiple versions", 160 InputConfig: extracttest.ScanInputMockConfig{ 161 Path: "testdata/multiple-versions.xml", 162 }, 163 WantPackages: []*extractor.Package{ 164 { 165 Name: "androidx.activity:activity", 166 Version: "1.2.1", 167 PURLType: purl.TypeMaven, 168 Locations: []string{"testdata/multiple-versions.xml"}, 169 Metadata: &javalockfile.Metadata{ArtifactID: "activity", GroupID: "androidx.activity"}, 170 }, 171 { 172 Name: "androidx.activity:activity", 173 Version: "1.2.3", 174 PURLType: purl.TypeMaven, 175 Locations: []string{"testdata/multiple-versions.xml"}, 176 Metadata: &javalockfile.Metadata{ArtifactID: "activity", GroupID: "androidx.activity"}, 177 }, 178 { 179 Name: "androidx.activity:activity", 180 Version: "1.5.1", 181 PURLType: purl.TypeMaven, 182 Locations: []string{"testdata/multiple-versions.xml"}, 183 Metadata: &javalockfile.Metadata{ArtifactID: "activity", GroupID: "androidx.activity"}, 184 }, 185 { 186 Name: "androidx.activity:activity", 187 Version: "1.6.0", 188 PURLType: purl.TypeMaven, 189 Locations: []string{"testdata/multiple-versions.xml"}, 190 Metadata: &javalockfile.Metadata{ArtifactID: "activity", GroupID: "androidx.activity"}, 191 }, 192 { 193 Name: "androidx.activity:activity", 194 Version: "1.7.0", 195 PURLType: purl.TypeMaven, 196 Locations: []string{"testdata/multiple-versions.xml"}, 197 Metadata: &javalockfile.Metadata{ArtifactID: "activity", GroupID: "androidx.activity"}, 198 }, 199 { 200 Name: "androidx.activity:activity", 201 Version: "1.7.2", 202 PURLType: purl.TypeMaven, 203 Locations: []string{"testdata/multiple-versions.xml"}, 204 Metadata: &javalockfile.Metadata{ArtifactID: "activity", GroupID: "androidx.activity"}, 205 }, 206 { 207 Name: "androidx.activity:activity-compose", 208 Version: "1.5.0", 209 PURLType: purl.TypeMaven, 210 Locations: []string{"testdata/multiple-versions.xml"}, 211 Metadata: &javalockfile.Metadata{ArtifactID: "activity-compose", GroupID: "androidx.activity"}, 212 }, 213 { 214 Name: "androidx.activity:activity-compose", 215 Version: "1.7.0", 216 PURLType: purl.TypeMaven, 217 Locations: []string{"testdata/multiple-versions.xml"}, 218 Metadata: &javalockfile.Metadata{ArtifactID: "activity-compose", GroupID: "androidx.activity"}, 219 }, 220 { 221 Name: "androidx.activity:activity-compose", 222 Version: "1.7.2", 223 PURLType: purl.TypeMaven, 224 Locations: []string{"testdata/multiple-versions.xml"}, 225 Metadata: &javalockfile.Metadata{ArtifactID: "activity-compose", GroupID: "androidx.activity"}, 226 }, 227 { 228 Name: "androidx.activity:activity-ktx", 229 Version: "1.5.1", 230 PURLType: purl.TypeMaven, 231 Locations: []string{"testdata/multiple-versions.xml"}, 232 Metadata: &javalockfile.Metadata{ArtifactID: "activity-ktx", GroupID: "androidx.activity"}, 233 }, 234 { 235 Name: "androidx.activity:activity-ktx", 236 Version: "1.7.0", 237 PURLType: purl.TypeMaven, 238 Locations: []string{"testdata/multiple-versions.xml"}, 239 Metadata: &javalockfile.Metadata{ArtifactID: "activity-ktx", GroupID: "androidx.activity"}, 240 }, 241 { 242 Name: "androidx.activity:activity-ktx", 243 Version: "1.7.2", 244 PURLType: purl.TypeMaven, 245 Locations: []string{"testdata/multiple-versions.xml"}, 246 Metadata: &javalockfile.Metadata{ArtifactID: "activity-ktx", GroupID: "androidx.activity"}, 247 }, 248 { 249 Name: "io.ktor:ktor-serialization-jvm", 250 Version: "2.0.0", 251 PURLType: purl.TypeMaven, 252 Locations: []string{"testdata/multiple-versions.xml"}, 253 Metadata: &javalockfile.Metadata{ArtifactID: "ktor-serialization-jvm", GroupID: "io.ktor"}, 254 }, 255 { 256 Name: "io.ktor:ktor-serialization-jvm", 257 Version: "2.0.0-beta-1", 258 PURLType: purl.TypeMaven, 259 Locations: []string{"testdata/multiple-versions.xml"}, 260 Metadata: &javalockfile.Metadata{ArtifactID: "ktor-serialization-jvm", GroupID: "io.ktor"}, 261 }, 262 { 263 Name: "io.ktor:ktor-serialization-jvm", 264 Version: "2.0.3", 265 PURLType: purl.TypeMaven, 266 Locations: []string{"testdata/multiple-versions.xml"}, 267 Metadata: &javalockfile.Metadata{ArtifactID: "ktor-serialization-jvm", GroupID: "io.ktor"}, 268 }, 269 { 270 Name: "com.google.auto.service:auto-service", 271 Version: "1.0-rc4", 272 PURLType: purl.TypeMaven, 273 Locations: []string{"testdata/multiple-versions.xml"}, 274 Metadata: &javalockfile.Metadata{ArtifactID: "auto-service", GroupID: "com.google.auto.service"}, 275 }, 276 { 277 Name: "com.google.auto.service:auto-service", 278 Version: "1.0.1", 279 PURLType: purl.TypeMaven, 280 Locations: []string{"testdata/multiple-versions.xml"}, 281 Metadata: &javalockfile.Metadata{ArtifactID: "auto-service", GroupID: "com.google.auto.service"}, 282 }, 283 { 284 Name: "com.google.auto.service:auto-service", 285 Version: "1.1.1", 286 PURLType: purl.TypeMaven, 287 Locations: []string{"testdata/multiple-versions.xml"}, 288 Metadata: &javalockfile.Metadata{ArtifactID: "auto-service", GroupID: "com.google.auto.service"}, 289 }, 290 }, 291 }, 292 { 293 Name: "odd versions", 294 InputConfig: extracttest.ScanInputMockConfig{ 295 Path: "testdata/odd-versions.xml", 296 }, 297 WantPackages: []*extractor.Package{ 298 { 299 Name: "com.google:google", 300 Version: "1", 301 PURLType: purl.TypeMaven, 302 Locations: []string{"testdata/odd-versions.xml"}, 303 Metadata: &javalockfile.Metadata{ArtifactID: "google", GroupID: "com.google"}, 304 }, 305 { 306 Name: "com.almworks.sqlite4java:sqlite4java", 307 Version: "0.282", 308 PURLType: purl.TypeMaven, 309 Locations: []string{"testdata/odd-versions.xml"}, 310 Metadata: &javalockfile.Metadata{ArtifactID: "sqlite4java", GroupID: "com.almworks.sqlite4java"}, 311 }, 312 { 313 Name: "com.google.errorprone:javac", 314 Version: "9+181-r4173-1", 315 PURLType: purl.TypeMaven, 316 Locations: []string{"testdata/odd-versions.xml"}, 317 Metadata: &javalockfile.Metadata{ArtifactID: "javac", GroupID: "com.google.errorprone"}, 318 }, 319 { 320 Name: "com.android.tools.build:aapt2", 321 Version: "8.3.0-10880808", 322 PURLType: purl.TypeMaven, 323 Locations: []string{"testdata/odd-versions.xml"}, 324 Metadata: &javalockfile.Metadata{ArtifactID: "aapt2", GroupID: "com.android.tools.build"}, 325 }, 326 { 327 Name: "com.android.tools.build:aapt2-proto", 328 Version: "8.3.0-10880808", 329 PURLType: purl.TypeMaven, 330 Locations: []string{"testdata/odd-versions.xml"}, 331 Metadata: &javalockfile.Metadata{ArtifactID: "aapt2-proto", GroupID: "com.android.tools.build"}, 332 }, 333 { 334 Name: "com.android.tools.build:transform-api", 335 Version: "2.0.0-deprecated-use-gradle-api", 336 PURLType: purl.TypeMaven, 337 Locations: []string{"testdata/odd-versions.xml"}, 338 Metadata: &javalockfile.Metadata{ArtifactID: "transform-api", GroupID: "com.android.tools.build"}, 339 }, 340 { 341 Name: "com.android.tools.build.jetifier:jetifier-core", 342 Version: "1.0.0-beta10", 343 PURLType: purl.TypeMaven, 344 Locations: []string{"testdata/odd-versions.xml"}, 345 Metadata: &javalockfile.Metadata{ArtifactID: "jetifier-core", GroupID: "com.android.tools.build.jetifier"}, 346 }, 347 { 348 Name: "com.google.apis:google-api-services-androidpublisher", 349 Version: "v3-rev20231115-2.0.0", 350 PURLType: purl.TypeMaven, 351 Locations: []string{"testdata/odd-versions.xml"}, 352 Metadata: &javalockfile.Metadata{ArtifactID: "google-api-services-androidpublisher", GroupID: "com.google.apis"}, 353 }, 354 { 355 Name: "com.google.devtools.ksp:symbol-processing", 356 Version: "1.9.22-1.0.17", 357 PURLType: purl.TypeMaven, 358 Locations: []string{"testdata/odd-versions.xml"}, 359 Metadata: &javalockfile.Metadata{ArtifactID: "symbol-processing", GroupID: "com.google.devtools.ksp"}, 360 }, 361 { 362 Name: "com.google.devtools.ksp:symbol-processing-api", 363 Version: "1.9.22-1.0.17", 364 PURLType: purl.TypeMaven, 365 Locations: []string{"testdata/odd-versions.xml"}, 366 Metadata: &javalockfile.Metadata{ArtifactID: "symbol-processing-api", GroupID: "com.google.devtools.ksp"}, 367 }, 368 { 369 Name: "com.google.devtools.ksp:symbol-processing-gradle-plugin", 370 Version: "1.9.22-1.0.17", 371 PURLType: purl.TypeMaven, 372 Locations: []string{"testdata/odd-versions.xml"}, 373 Metadata: &javalockfile.Metadata{ 374 ArtifactID: "symbol-processing-gradle-plugin", 375 GroupID: "com.google.devtools.ksp", 376 }, 377 }, 378 { 379 Name: "com.google.guava:guava", 380 Version: "32.0.0-jre", 381 PURLType: purl.TypeMaven, 382 Locations: []string{"testdata/odd-versions.xml"}, 383 Metadata: &javalockfile.Metadata{ArtifactID: "guava", GroupID: "com.google.guava"}, 384 }, 385 { 386 Name: "com.google.guava:guava", 387 Version: "32.1.3-jre", 388 PURLType: purl.TypeMaven, 389 Locations: []string{"testdata/odd-versions.xml"}, 390 Metadata: &javalockfile.Metadata{ArtifactID: "guava", GroupID: "com.google.guava"}, 391 }, 392 { 393 Name: "com.google.guava:listenablefuture", 394 Version: "9999.0-empty-to-avoid-conflict-with-guava", 395 PURLType: purl.TypeMaven, 396 Locations: []string{"testdata/odd-versions.xml"}, 397 Metadata: &javalockfile.Metadata{ArtifactID: "listenablefuture", GroupID: "com.google.guava"}, 398 }, 399 { 400 Name: "com.google.testing.platform:core", 401 Version: "0.0.9-alpha02", 402 PURLType: purl.TypeMaven, 403 Locations: []string{"testdata/odd-versions.xml"}, 404 Metadata: &javalockfile.Metadata{ArtifactID: "core", GroupID: "com.google.testing.platform"}, 405 }, 406 { 407 Name: "com.jakewharton.android.repackaged:dalvik-dx", 408 Version: "9.0.0_r3", 409 PURLType: purl.TypeMaven, 410 Locations: []string{"testdata/odd-versions.xml"}, 411 Metadata: &javalockfile.Metadata{ArtifactID: "dalvik-dx", GroupID: "com.jakewharton.android.repackaged"}, 412 }, 413 { 414 Name: "com.vaadin.external.google:android-json", 415 Version: "0.0.20131108.vaadin1", 416 PURLType: purl.TypeMaven, 417 Locations: []string{"testdata/odd-versions.xml"}, 418 Metadata: &javalockfile.Metadata{ArtifactID: "android-json", GroupID: "com.vaadin.external.google"}, 419 }, 420 { 421 Name: "de.mannodermaus.gradle.plugins:android-junit5", 422 Version: "1.10.0.0", 423 PURLType: purl.TypeMaven, 424 Locations: []string{"testdata/odd-versions.xml"}, 425 Metadata: &javalockfile.Metadata{ArtifactID: "android-junit5", GroupID: "de.mannodermaus.gradle.plugins"}, 426 }, 427 { 428 Name: "io.netty:netty-codec-http", 429 Version: "4.1.93.Final", 430 PURLType: purl.TypeMaven, 431 Locations: []string{"testdata/odd-versions.xml"}, 432 Metadata: &javalockfile.Metadata{ArtifactID: "netty-codec-http", GroupID: "io.netty"}, 433 }, 434 { 435 Name: "io.netty:netty-codec-http2", 436 Version: "4.1.93.Final", 437 PURLType: purl.TypeMaven, 438 Locations: []string{"testdata/odd-versions.xml"}, 439 Metadata: &javalockfile.Metadata{ArtifactID: "netty-codec-http2", GroupID: "io.netty"}, 440 }, 441 { 442 Name: "javax.inject:javax.inject", 443 Version: "1", 444 PURLType: purl.TypeMaven, 445 Locations: []string{"testdata/odd-versions.xml"}, 446 Metadata: &javalockfile.Metadata{ArtifactID: "javax.inject", GroupID: "javax.inject"}, 447 }, 448 { 449 Name: "junit:junit", 450 Version: "4.13.2", 451 PURLType: purl.TypeMaven, 452 Locations: []string{"testdata/odd-versions.xml"}, 453 Metadata: &javalockfile.Metadata{ArtifactID: "junit", GroupID: "junit"}, 454 }, 455 { 456 Name: "org.apache:apache", 457 Version: "13", 458 PURLType: purl.TypeMaven, 459 Locations: []string{"testdata/odd-versions.xml"}, 460 Metadata: &javalockfile.Metadata{ArtifactID: "apache", GroupID: "org.apache"}, 461 }, 462 { 463 Name: "org.jetbrains.intellij.deps:trove4j", 464 Version: "1.0.20200330", 465 PURLType: purl.TypeMaven, 466 Locations: []string{"testdata/odd-versions.xml"}, 467 Metadata: &javalockfile.Metadata{ArtifactID: "trove4j", GroupID: "org.jetbrains.intellij.deps"}, 468 }, 469 { 470 Name: "org.json:json", 471 Version: "20180813", 472 PURLType: purl.TypeMaven, 473 Locations: []string{"testdata/odd-versions.xml"}, 474 Metadata: &javalockfile.Metadata{ArtifactID: "json", GroupID: "org.json"}, 475 }, 476 { 477 Name: "org.tensorflow:tensorflow-lite-metadata", 478 Version: "0.1.0-rc2", 479 PURLType: purl.TypeMaven, 480 Locations: []string{"testdata/odd-versions.xml"}, 481 Metadata: &javalockfile.Metadata{ArtifactID: "tensorflow-lite-metadata", GroupID: "org.tensorflow"}, 482 }, 483 { 484 Name: "org.tukaani:xz", 485 Version: "1.9", 486 PURLType: purl.TypeMaven, 487 Locations: []string{"testdata/odd-versions.xml"}, 488 Metadata: &javalockfile.Metadata{ArtifactID: "xz", GroupID: "org.tukaani"}, 489 }, 490 { 491 Name: "org.whitesource:pecoff4j", 492 Version: "0.0.2.1", 493 PURLType: purl.TypeMaven, 494 Locations: []string{"testdata/odd-versions.xml"}, 495 Metadata: &javalockfile.Metadata{ArtifactID: "pecoff4j", GroupID: "org.whitesource"}, 496 }, 497 }, 498 }, 499 } 500 501 for _, tt := range tests { 502 t.Run(tt.Name, func(t *testing.T) { 503 extr := gradleverificationmetadataxml.Extractor{} 504 505 scanInput := extracttest.GenerateScanInputMock(t, tt.InputConfig) 506 defer extracttest.CloseTestScanInput(t, scanInput) 507 508 got, err := extr.Extract(t.Context(), &scanInput) 509 510 if diff := cmp.Diff(tt.WantErr, err, cmpopts.EquateErrors()); diff != "" { 511 t.Errorf("%s.Extract(%q) error diff (-want +got):\n%s", extr.Name(), tt.InputConfig.Path, diff) 512 return 513 } 514 515 wantInv := inventory.Inventory{Packages: tt.WantPackages} 516 if diff := cmp.Diff(wantInv, got, cmpopts.SortSlices(extracttest.PackageCmpLess)); diff != "" { 517 t.Errorf("%s.Extract(%q) diff (-want +got):\n%s", extr.Name(), tt.InputConfig.Path, diff) 518 } 519 }) 520 } 521 }