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  }