github.com/lineaje-labs/syft@v0.98.1-0.20231227153149-9e393f60ff1b/syft/pkg/cataloger/cataloger_test.go (about) 1 package cataloger 2 3 import ( 4 "testing" 5 6 "github.com/stretchr/testify/assert" 7 8 "github.com/anchore/syft/syft/artifact" 9 "github.com/anchore/syft/syft/file" 10 "github.com/anchore/syft/syft/pkg" 11 ) 12 13 var _ pkg.Cataloger = (*dummy)(nil) 14 15 type dummy struct { 16 name string 17 } 18 19 func (d dummy) Name() string { 20 return d.name 21 } 22 23 func (d dummy) Catalog(_ file.Resolver) ([]pkg.Package, []artifact.Relationship, error) { 24 panic("not implemented") 25 } 26 27 func Test_filterCatalogers(t *testing.T) { 28 largeCatalogerList := []string{ 29 "alpm-db-cataloger", 30 "apkdb-cataloger", 31 "binary-cataloger", 32 "conan-cataloger", 33 "dartlang-lock-cataloger", 34 "dpkg-db-cataloger", 35 "dotnet-deps-cataloger", 36 "elixir-mix-lock-cataloger", 37 "erlang-rebar-lock-cataloger", 38 "go-module-file-cataloger", 39 "go-module-binary-cataloger", 40 "haskell-cataloger", 41 "graalvm-native-image-cataloger", 42 "java-cataloger", 43 "java-pom-cataloger", 44 "javascript-package-cataloger", 45 "javascript-lock-cataloger", 46 "php-composer-installed-cataloger", 47 "php-composer-lock-cataloger", 48 "portage-cataloger", 49 "python-package-cataloger", 50 "python-installed-package-cataloger", 51 "rpm-db-cataloger", 52 "rpm-archive-cataloger", 53 "ruby-gemfile-cataloger", 54 "ruby-installed-gemspec-cataloger", 55 "rust-cargo-lock-cataloger", 56 "cargo-auditable-binary-cataloger", 57 "sbom-cataloger", 58 "cocoapods-cataloger", 59 } 60 tests := []struct { 61 name string 62 patterns []string 63 catalogers []string 64 want []string 65 }{ 66 { 67 name: "no filtering", 68 patterns: nil, 69 catalogers: []string{ 70 "ruby-installed-gemspec-cataloger", 71 "python-installed-package-cataloger", 72 "php-composer-installed-cataloger", 73 "javascript-package-cataloger", 74 "dpkg-db-cataloger", 75 "rpm-db-cataloger", 76 "java-cataloger", 77 "apkdb-cataloger", 78 "go-module-binary-cataloger", 79 }, 80 want: []string{ 81 "ruby-installed-gemspec-cataloger", 82 "python-installed-package-cataloger", 83 "php-composer-installed-cataloger", 84 "javascript-package-cataloger", 85 "dpkg-db-cataloger", 86 "rpm-db-cataloger", 87 "java-cataloger", 88 "apkdb-cataloger", 89 "go-module-binary-cataloger", 90 }, 91 }, 92 { 93 name: "exact name match", 94 patterns: []string{ 95 "rpm-db-cataloger", 96 "javascript-package-cataloger", 97 }, 98 catalogers: []string{ 99 "ruby-installed-gemspec-cataloger", 100 "python-installed-package-cataloger", 101 "php-composer-installed-cataloger", 102 "javascript-package-cataloger", 103 "dpkg-db-cataloger", 104 "rpm-db-cataloger", 105 "java-cataloger", 106 "apkdb-cataloger", 107 "go-module-binary-cataloger", 108 }, 109 want: []string{ 110 "javascript-package-cataloger", 111 "rpm-db-cataloger", 112 }, 113 }, 114 { 115 name: "partial name match", 116 patterns: []string{ 117 "ruby", 118 "installed", 119 }, 120 catalogers: []string{ 121 "ruby-installed-gemspec-cataloger", 122 "ruby-gemfile-cataloger", 123 "python-installed-package-cataloger", 124 "php-composer-installed-cataloger", 125 "javascript-package-cataloger", 126 "dpkg-db-cataloger", 127 "rpm-db-cataloger", 128 "java-cataloger", 129 "apkdb-cataloger", 130 "go-module-binary-cataloger", 131 }, 132 want: []string{ 133 "php-composer-installed-cataloger", 134 "python-installed-package-cataloger", 135 "ruby-installed-gemspec-cataloger", 136 "ruby-gemfile-cataloger", 137 }, 138 }, 139 { 140 name: "ignore 'cataloger' keyword", 141 patterns: []string{ 142 "cataloger", 143 }, 144 catalogers: []string{ 145 "ruby-installed-gemspec-cataloger", 146 "ruby-gemfile-cataloger", 147 "python-installed-package-cataloger", 148 "php-composer-installed-cataloger", 149 "javascript-package-cataloger", 150 "dpkg-db-cataloger", 151 "rpm-db-cataloger", 152 "java-cataloger", 153 "apkdb-cataloger", 154 "go-module-binary-cataloger", 155 }, 156 want: []string{}, 157 }, 158 { 159 name: "only some patterns match", 160 patterns: []string{ 161 "cataloger", 162 "go-module", 163 }, 164 catalogers: []string{ 165 "ruby-installed-gemspec-cataloger", 166 "ruby-gemfile-cataloger", 167 "python-installed-package-cataloger", 168 "php-composer-installed-cataloger", 169 "javascript-package-cataloger", 170 "dpkg-db-cataloger", 171 "rpm-db-cataloger", 172 "java-cataloger", 173 "apkdb-cataloger", 174 "go-module-binary-cataloger", 175 }, 176 want: []string{ 177 "go-module-binary-cataloger", 178 }, 179 }, 180 { 181 name: "don't cross match ecosystems with matching prefix", 182 patterns: []string{ 183 "java-cataloger", 184 }, 185 catalogers: []string{ 186 "javascript-package-cataloger", 187 "java-cataloger", 188 }, 189 want: []string{ 190 "java-cataloger", 191 }, 192 }, 193 { 194 name: "don't cross match ecosystems with short, common name", 195 patterns: []string{ 196 "go", 197 }, 198 catalogers: largeCatalogerList, 199 want: []string{ 200 "go-module-file-cataloger", 201 "go-module-binary-cataloger", 202 //"rust-cargo-lock-cataloger", // with naive "contains" matching 203 //"cargo-auditable-binary-cataloger", // with naive "contains" matching 204 }, 205 }, 206 { 207 name: "ignore partial matches", 208 patterns: []string{ 209 "mod", 210 }, 211 catalogers: largeCatalogerList, 212 want: []string{ 213 // important! these are NOT found 214 //"go-module-file-cataloger", 215 //"go-module-binary-cataloger", 216 }, 217 }, 218 } 219 for _, tt := range tests { 220 t.Run(tt.name, func(t *testing.T) { 221 var catalogers []pkg.Cataloger 222 for _, n := range tt.catalogers { 223 catalogers = append(catalogers, dummy{name: n}) 224 } 225 got := filterCatalogers(catalogers, tt.patterns) 226 var gotNames []string 227 for _, g := range got { 228 gotNames = append(gotNames, g.Name()) 229 } 230 assert.ElementsMatch(t, tt.want, gotNames) 231 }) 232 } 233 } 234 235 func Test_contains(t *testing.T) { 236 tests := []struct { 237 name string 238 enabledCatalogers []string 239 catalogerName string 240 want bool 241 }{ 242 { 243 name: "keep exact match", 244 enabledCatalogers: []string{ 245 "php-composer-installed-cataloger", 246 }, 247 catalogerName: "php-composer-installed-cataloger", 248 want: true, 249 }, 250 { 251 name: "match substring", 252 enabledCatalogers: []string{ 253 "python", 254 }, 255 catalogerName: "python-installed-package-cataloger", 256 want: true, 257 }, 258 { 259 name: "dont match on 'cataloger'", 260 enabledCatalogers: []string{ 261 "cataloger", 262 }, 263 catalogerName: "python-installed-package-cataloger", 264 want: false, 265 }, 266 } 267 for _, tt := range tests { 268 t.Run(tt.name, func(t *testing.T) { 269 assert.Equal(t, tt.want, contains(tt.enabledCatalogers, tt.catalogerName)) 270 }) 271 } 272 } 273 274 func Test_hasFullWord(t *testing.T) { 275 276 tests := []struct { 277 name string 278 targetPhrase string 279 candidate string 280 want bool 281 }{ 282 { 283 name: "exact match", 284 targetPhrase: "php-composer-installed-cataloger", 285 candidate: "php-composer-installed-cataloger", 286 want: true, 287 }, 288 { 289 name: "partial, full word match", 290 targetPhrase: "composer", 291 candidate: "php-composer-installed-cataloger", 292 want: true, 293 }, 294 { 295 name: "partial, full, multi-word match", 296 targetPhrase: "php-composer", 297 candidate: "php-composer-installed-cataloger", 298 want: true, 299 }, 300 { 301 name: "prefix match", 302 targetPhrase: "php", 303 candidate: "php-composer-installed-cataloger", 304 want: true, 305 }, 306 { 307 name: "postfix match with -cataloger suffix", 308 targetPhrase: "installed", 309 candidate: "php-composer-installed-cataloger", 310 want: true, 311 }, 312 { 313 name: "postfix match", 314 targetPhrase: "installed", 315 candidate: "php-composer-installed", 316 want: true, 317 }, 318 { 319 name: "ignore cataloger keyword", 320 targetPhrase: "cataloger", 321 candidate: "php-composer-installed-cataloger", 322 want: false, 323 }, 324 { 325 name: "ignore partial match", 326 targetPhrase: "hp", 327 candidate: "php-composer-installed-cataloger", 328 want: false, 329 }, 330 { 331 name: "ignore empty string", 332 targetPhrase: "", 333 candidate: "php-composer-installed-cataloger", 334 want: false, 335 }, 336 } 337 for _, tt := range tests { 338 t.Run(tt.name, func(t *testing.T) { 339 assert.Equalf(t, tt.want, hasFullWord(tt.targetPhrase, tt.candidate), "hasFullWord(%v, %v)", tt.targetPhrase, tt.candidate) 340 }) 341 } 342 }