mirror of
https://github.com/anchore/grype
synced 2024-11-14 00:07:08 +00:00
602 lines
18 KiB
Go
602 lines
18 KiB
Go
package integration
|
|
|
|
import (
|
|
"testing"
|
|
|
|
"github.com/sergi/go-diff/diffmatchpatch"
|
|
"github.com/stretchr/testify/require"
|
|
|
|
"github.com/anchore/grype/grype"
|
|
"github.com/anchore/grype/grype/db"
|
|
"github.com/anchore/grype/grype/match"
|
|
"github.com/anchore/grype/grype/matcher"
|
|
"github.com/anchore/grype/grype/pkg"
|
|
"github.com/anchore/grype/grype/store"
|
|
"github.com/anchore/grype/grype/vulnerability"
|
|
"github.com/anchore/grype/internal"
|
|
"github.com/anchore/stereoscope/pkg/imagetest"
|
|
"github.com/anchore/syft/syft"
|
|
syftPkg "github.com/anchore/syft/syft/pkg"
|
|
"github.com/anchore/syft/syft/pkg/cataloger"
|
|
"github.com/anchore/syft/syft/source"
|
|
)
|
|
|
|
func addAlpineMatches(t *testing.T, theSource source.Source, catalog *syftPkg.Catalog, theStore *mockStore, theResult *match.Matches) {
|
|
packages := catalog.PackagesByPath("/lib/apk/db/installed")
|
|
if len(packages) != 1 {
|
|
t.Logf("Alpine Packages: %+v", packages)
|
|
t.Fatalf("problem with upstream syft cataloger (alpine)")
|
|
}
|
|
thePkg := pkg.New(packages[0])
|
|
theVuln := theStore.backend["alpine:distro:alpine:3.12"][thePkg.Name][0]
|
|
vulnObj, err := vulnerability.NewVulnerability(theVuln)
|
|
if err != nil {
|
|
t.Fatalf("failed to create vuln obj: %+v", err)
|
|
}
|
|
theResult.Add(match.Match{
|
|
// note: we are matching on the secdb record, not NVD primarily
|
|
|
|
Vulnerability: *vulnObj,
|
|
Package: thePkg,
|
|
Details: []match.Detail{
|
|
{
|
|
Type: match.ExactDirectMatch,
|
|
Confidence: 1.0,
|
|
SearchedBy: map[string]interface{}{
|
|
"cpe": "cpe:2.3:*:*:libvncserver:0.9.9:*:*:*:*:*:*:*",
|
|
},
|
|
Found: map[string]interface{}{
|
|
"cpes": []string{"cpe:2.3:*:*:libvncserver:0.9.9:*:*:*:*:*:*:*"},
|
|
"constraint": "< 0.9.10 (unknown)",
|
|
},
|
|
Matcher: match.ApkMatcher,
|
|
},
|
|
},
|
|
})
|
|
}
|
|
|
|
func addJavascriptMatches(t *testing.T, theSource source.Source, catalog *syftPkg.Catalog, theStore *mockStore, theResult *match.Matches) {
|
|
packages := catalog.PackagesByPath("/javascript/pkg-json/package.json")
|
|
if len(packages) != 1 {
|
|
t.Logf("Javascript Packages: %+v", packages)
|
|
t.Fatalf("problem with upstream syft cataloger (javascript)")
|
|
}
|
|
thePkg := pkg.New(packages[0])
|
|
theVuln := theStore.backend["github:language:javascript"][thePkg.Name][0]
|
|
vulnObj, err := vulnerability.NewVulnerability(theVuln)
|
|
if err != nil {
|
|
t.Fatalf("failed to create vuln obj: %+v", err)
|
|
}
|
|
theResult.Add(match.Match{
|
|
Vulnerability: *vulnObj,
|
|
Package: thePkg,
|
|
Details: []match.Detail{
|
|
{
|
|
Type: match.ExactDirectMatch,
|
|
Confidence: 1.0,
|
|
SearchedBy: map[string]interface{}{
|
|
"language": "javascript",
|
|
},
|
|
Found: map[string]interface{}{
|
|
"constraint": "< 3.2.1 (unknown)",
|
|
},
|
|
Matcher: match.JavascriptMatcher,
|
|
},
|
|
},
|
|
})
|
|
}
|
|
|
|
func addPythonMatches(t *testing.T, theSource source.Source, catalog *syftPkg.Catalog, theStore *mockStore, theResult *match.Matches) {
|
|
packages := catalog.PackagesByPath("/python/dist-info/METADATA")
|
|
if len(packages) != 1 {
|
|
for _, p := range packages {
|
|
t.Logf("Python Package: %s %+v", p.ID(), p)
|
|
}
|
|
|
|
t.Fatalf("problem with upstream syft cataloger (python)")
|
|
}
|
|
thePkg := pkg.New(packages[0])
|
|
normalizedName := theStore.normalizedPackageNames["github:language:python"][thePkg.Name]
|
|
theVuln := theStore.backend["github:language:python"][normalizedName][0]
|
|
vulnObj, err := vulnerability.NewVulnerability(theVuln)
|
|
if err != nil {
|
|
t.Fatalf("failed to create vuln obj: %+v", err)
|
|
}
|
|
theResult.Add(match.Match{
|
|
|
|
Vulnerability: *vulnObj,
|
|
Package: thePkg,
|
|
Details: []match.Detail{
|
|
{
|
|
Type: match.ExactDirectMatch,
|
|
Confidence: 1.0,
|
|
SearchedBy: map[string]interface{}{
|
|
"language": "python",
|
|
},
|
|
Found: map[string]interface{}{
|
|
"constraint": "< 2.6.2 (python)",
|
|
},
|
|
Matcher: match.PythonMatcher,
|
|
},
|
|
},
|
|
})
|
|
}
|
|
|
|
func addDotnetMatches(t *testing.T, theSource source.Source, catalog *syftPkg.Catalog, theStore *mockStore, theResult *match.Matches) {
|
|
packages := catalog.PackagesByPath("/dotnet/TestLibrary.deps.json")
|
|
if len(packages) != 1 {
|
|
for _, p := range packages {
|
|
t.Logf("Dotnet Package: %s %+v", p.ID(), p)
|
|
}
|
|
|
|
t.Fatalf("problem with upstream syft cataloger (dotnet)")
|
|
}
|
|
thePkg := pkg.New(packages[0])
|
|
normalizedName := theStore.normalizedPackageNames["github:language:dotnet"][thePkg.Name]
|
|
theVuln := theStore.backend["github:language:dotnet"][normalizedName][0]
|
|
vulnObj, err := vulnerability.NewVulnerability(theVuln)
|
|
if err != nil {
|
|
t.Fatalf("failed to create vuln obj: %+v", err)
|
|
}
|
|
theResult.Add(match.Match{
|
|
|
|
Vulnerability: *vulnObj,
|
|
Package: thePkg,
|
|
Details: []match.Detail{
|
|
{
|
|
Type: match.ExactDirectMatch,
|
|
Confidence: 1.0,
|
|
SearchedBy: map[string]interface{}{
|
|
"language": "dotnet",
|
|
},
|
|
Found: map[string]interface{}{
|
|
"constraint": ">= 3.7.0.0, < 3.7.12.0 (dotnet)",
|
|
},
|
|
Matcher: match.DotnetMatcher,
|
|
},
|
|
},
|
|
})
|
|
}
|
|
|
|
func addRubyMatches(t *testing.T, theSource source.Source, catalog *syftPkg.Catalog, theStore *mockStore, theResult *match.Matches) {
|
|
packages := catalog.PackagesByPath("/ruby/specifications/bundler.gemspec")
|
|
if len(packages) != 1 {
|
|
t.Logf("Ruby Packages: %+v", packages)
|
|
t.Fatalf("problem with upstream syft cataloger (ruby)")
|
|
}
|
|
thePkg := pkg.New(packages[0])
|
|
theVuln := theStore.backend["github:language:ruby"][thePkg.Name][0]
|
|
vulnObj, err := vulnerability.NewVulnerability(theVuln)
|
|
if err != nil {
|
|
t.Fatalf("failed to create vuln obj: %+v", err)
|
|
}
|
|
theResult.Add(match.Match{
|
|
|
|
Vulnerability: *vulnObj,
|
|
Package: thePkg,
|
|
Details: []match.Detail{
|
|
{
|
|
Type: match.ExactDirectMatch,
|
|
Confidence: 1.0,
|
|
SearchedBy: map[string]interface{}{
|
|
"language": "ruby",
|
|
},
|
|
Found: map[string]interface{}{
|
|
"constraint": "> 4.0.0, <= 4.1.1 (gemfile)",
|
|
},
|
|
Matcher: match.RubyGemMatcher,
|
|
},
|
|
},
|
|
})
|
|
}
|
|
|
|
func addGolangMatches(t *testing.T, theSource source.Source, catalog *syftPkg.Catalog, theStore *mockStore, theResult *match.Matches) {
|
|
packages := catalog.PackagesByPath("/go-app")
|
|
if len(packages) != 2 {
|
|
t.Logf("Golang Packages: %+v", packages)
|
|
t.Fatalf("problem with upstream syft cataloger (golang)")
|
|
}
|
|
|
|
for _, p := range packages {
|
|
thePkg := pkg.New(p)
|
|
theVuln := theStore.backend["github:language:go"][p.Name][0]
|
|
vulnObj, err := vulnerability.NewVulnerability(theVuln)
|
|
if err != nil {
|
|
t.Fatalf("failed to create vuln obj: %+v", err)
|
|
}
|
|
|
|
// no vuln match supported for main module
|
|
if p.Name != "github.com/anchore/coverage" {
|
|
theResult.Add(match.Match{
|
|
Vulnerability: *vulnObj,
|
|
Package: thePkg,
|
|
Details: []match.Detail{
|
|
{
|
|
Type: match.ExactDirectMatch,
|
|
Confidence: 1.0,
|
|
SearchedBy: map[string]interface{}{
|
|
"langauge": "go",
|
|
},
|
|
Found: map[string]interface{}{
|
|
"constraint": " < 1.4.0 (golang)",
|
|
},
|
|
Matcher: match.GoModuleMatcher,
|
|
},
|
|
},
|
|
})
|
|
}
|
|
}
|
|
}
|
|
|
|
func addJavaMatches(t *testing.T, theSource source.Source, catalog *syftPkg.Catalog, theStore *mockStore, theResult *match.Matches) {
|
|
packages := make([]syftPkg.Package, 0)
|
|
for p := range catalog.Enumerate(syftPkg.JavaPkg) {
|
|
packages = append(packages, p)
|
|
}
|
|
if len(packages) != 2 { // 2, because there's a nested JAR inside the test fixture JAR
|
|
t.Logf("Java Packages: %+v", packages)
|
|
t.Fatalf("problem with upstream syft cataloger (java)")
|
|
}
|
|
theSyftPkg := packages[0]
|
|
|
|
groupId := theSyftPkg.Metadata.(syftPkg.JavaMetadata).PomProperties.GroupID
|
|
lookup := groupId + ":" + theSyftPkg.Name
|
|
|
|
thePkg := pkg.New(theSyftPkg)
|
|
|
|
theVuln := theStore.backend["github:language:java"][lookup][0]
|
|
vulnObj, err := vulnerability.NewVulnerability(theVuln)
|
|
if err != nil {
|
|
t.Fatalf("failed to create vuln obj: %+v", err)
|
|
}
|
|
theResult.Add(match.Match{
|
|
Vulnerability: *vulnObj,
|
|
Package: thePkg,
|
|
Details: []match.Detail{
|
|
{
|
|
Type: match.ExactDirectMatch,
|
|
Confidence: 1.0,
|
|
SearchedBy: map[string]interface{}{
|
|
"language": "java",
|
|
},
|
|
Found: map[string]interface{}{
|
|
"constraint": ">= 0.0.1, < 1.2.0 (unknown)",
|
|
},
|
|
Matcher: match.JavaMatcher,
|
|
},
|
|
},
|
|
})
|
|
}
|
|
|
|
func addDpkgMatches(t *testing.T, theSource source.Source, catalog *syftPkg.Catalog, theStore *mockStore, theResult *match.Matches) {
|
|
packages := catalog.PackagesByPath("/var/lib/dpkg/status")
|
|
if len(packages) != 1 {
|
|
t.Logf("Dpkg Packages: %+v", packages)
|
|
t.Fatalf("problem with upstream syft cataloger (dpkg)")
|
|
}
|
|
thePkg := pkg.New(packages[0])
|
|
// NOTE: this is an indirect match, in typical debian style
|
|
theVuln := theStore.backend["debian:distro:debian:8"][thePkg.Name+"-dev"][0]
|
|
vulnObj, err := vulnerability.NewVulnerability(theVuln)
|
|
if err != nil {
|
|
t.Fatalf("failed to create vuln obj: %+v", err)
|
|
}
|
|
theResult.Add(match.Match{
|
|
|
|
Vulnerability: *vulnObj,
|
|
Package: thePkg,
|
|
Details: []match.Detail{
|
|
{
|
|
Type: match.ExactIndirectMatch,
|
|
Confidence: 1.0,
|
|
SearchedBy: map[string]interface{}{
|
|
"distro": map[string]string{
|
|
"type": "debian",
|
|
"version": "8",
|
|
},
|
|
},
|
|
Found: map[string]interface{}{
|
|
"constraint": "<= 1.8.2 (deb)",
|
|
},
|
|
Matcher: match.DpkgMatcher,
|
|
},
|
|
},
|
|
})
|
|
}
|
|
|
|
func addPortageMatches(t *testing.T, theSource source.Source, catalog *syftPkg.Catalog, theStore *mockStore, theResult *match.Matches) {
|
|
packages := catalog.PackagesByPath("/var/db/pkg/app-containers/skopeo-1.5.1/CONTENTS")
|
|
if len(packages) != 1 {
|
|
t.Logf("Portage Packages: %+v", packages)
|
|
t.Fatalf("problem with upstream syft cataloger (portage)")
|
|
}
|
|
thePkg := pkg.New(packages[0])
|
|
theVuln := theStore.backend["gentoo:distro:gentoo:2.8"][thePkg.Name][0]
|
|
vulnObj, err := vulnerability.NewVulnerability(theVuln)
|
|
if err != nil {
|
|
t.Fatalf("failed to create vuln obj: %+v", err)
|
|
}
|
|
theResult.Add(match.Match{
|
|
Vulnerability: *vulnObj,
|
|
Package: thePkg,
|
|
Details: []match.Detail{
|
|
{
|
|
Type: match.ExactDirectMatch,
|
|
Confidence: 1.0,
|
|
SearchedBy: map[string]interface{}{
|
|
"distro": map[string]string{
|
|
"type": "gentoo",
|
|
"version": "portage",
|
|
},
|
|
},
|
|
Found: map[string]interface{}{
|
|
"constraint": "<= 1.6.0 (gentoo)",
|
|
},
|
|
Matcher: match.PortageMatcher,
|
|
},
|
|
},
|
|
})
|
|
}
|
|
|
|
func addRhelMatches(t *testing.T, theSource source.Source, catalog *syftPkg.Catalog, theStore *mockStore, theResult *match.Matches) {
|
|
packages := catalog.PackagesByPath("/var/lib/rpm/Packages")
|
|
if len(packages) != 1 {
|
|
t.Logf("RPMDB Packages: %+v", packages)
|
|
t.Fatalf("problem with upstream syft cataloger (RPMDB)")
|
|
}
|
|
thePkg := pkg.New(packages[0])
|
|
theVuln := theStore.backend["redhat:distro:redhat:8"][thePkg.Name][0]
|
|
vulnObj, err := vulnerability.NewVulnerability(theVuln)
|
|
if err != nil {
|
|
t.Fatalf("failed to create vuln obj: %+v", err)
|
|
}
|
|
theResult.Add(match.Match{
|
|
|
|
Vulnerability: *vulnObj,
|
|
Package: thePkg,
|
|
Details: []match.Detail{
|
|
{
|
|
Type: match.ExactDirectMatch,
|
|
Confidence: 1.0,
|
|
SearchedBy: map[string]interface{}{
|
|
"distro": map[string]string{
|
|
"type": "centos",
|
|
"version": "8",
|
|
},
|
|
},
|
|
Found: map[string]interface{}{
|
|
"constraint": "<= 1.0.42 (rpm)",
|
|
},
|
|
Matcher: match.RpmDBMatcher,
|
|
},
|
|
},
|
|
})
|
|
}
|
|
|
|
func addSlesMatches(t *testing.T, theSource source.Source, catalog *syftPkg.Catalog, theStore *mockStore, theResult *match.Matches) {
|
|
packages := catalog.PackagesByPath("/var/lib/rpm/Packages")
|
|
if len(packages) != 1 {
|
|
t.Logf("Sles Packages: %+v", packages)
|
|
t.Fatalf("problem with upstream syft cataloger (RPMDB)")
|
|
}
|
|
thePkg := pkg.New(packages[0])
|
|
theVuln := theStore.backend["redhat:distro:redhat:8"][thePkg.Name][0]
|
|
vulnObj, err := vulnerability.NewVulnerability(theVuln)
|
|
if err != nil {
|
|
t.Fatalf("failed to create vuln obj: %+v", err)
|
|
}
|
|
theResult.Add(match.Match{
|
|
Vulnerability: *vulnObj,
|
|
Package: thePkg,
|
|
Details: []match.Detail{
|
|
{
|
|
Type: match.ExactDirectMatch,
|
|
Confidence: 1.0,
|
|
SearchedBy: map[string]interface{}{
|
|
"distro": map[string]string{
|
|
"type": "sles",
|
|
"version": "12.5",
|
|
},
|
|
},
|
|
Found: map[string]interface{}{
|
|
"constraint": "<= 1.0.42 (rpm)",
|
|
},
|
|
Matcher: match.RpmDBMatcher,
|
|
},
|
|
},
|
|
})
|
|
}
|
|
|
|
func addHaskellMatches(t *testing.T, theSource source.Source, catalog *syftPkg.Catalog, theStore *mockStore, theResult *match.Matches) {
|
|
packages := catalog.PackagesByPath("/haskell/stack.yaml")
|
|
if len(packages) < 1 {
|
|
t.Logf("Haskel Packages: %+v", packages)
|
|
t.Fatalf("problem with upstream syft cataloger (haskell)")
|
|
}
|
|
thePkg := pkg.New(packages[0])
|
|
theVuln := theStore.backend["github:language:haskell"][thePkg.Name][0]
|
|
vulnObj, err := vulnerability.NewVulnerability(theVuln)
|
|
if err != nil {
|
|
t.Fatalf("failed to create vuln obj: %+v", err)
|
|
}
|
|
theResult.Add(match.Match{
|
|
Vulnerability: *vulnObj,
|
|
Package: thePkg,
|
|
Details: []match.Detail{
|
|
{
|
|
Type: match.ExactDirectMatch,
|
|
Confidence: 1.0,
|
|
SearchedBy: map[string]interface{}{
|
|
"language": map[string]string{
|
|
"type": "haskell",
|
|
"version": "",
|
|
},
|
|
},
|
|
Found: map[string]interface{}{
|
|
"constraint": "< 0.9.0 (haskell)",
|
|
},
|
|
Matcher: match.UnknownMatcherType,
|
|
},
|
|
},
|
|
})
|
|
}
|
|
|
|
func TestMatchByImage(t *testing.T) {
|
|
observedMatchers := internal.NewStringSet()
|
|
definedMatchers := internal.NewStringSet()
|
|
for _, l := range match.AllMatcherTypes {
|
|
definedMatchers.Add(string(l))
|
|
}
|
|
|
|
tests := []struct {
|
|
fixtureImage string
|
|
expectedFn func(source.Source, *syftPkg.Catalog, *mockStore) match.Matches
|
|
}{
|
|
{
|
|
fixtureImage: "image-debian-match-coverage",
|
|
expectedFn: func(theSource source.Source, catalog *syftPkg.Catalog, theStore *mockStore) match.Matches {
|
|
expectedMatches := match.NewMatches()
|
|
addPythonMatches(t, theSource, catalog, theStore, &expectedMatches)
|
|
addRubyMatches(t, theSource, catalog, theStore, &expectedMatches)
|
|
addJavaMatches(t, theSource, catalog, theStore, &expectedMatches)
|
|
addDpkgMatches(t, theSource, catalog, theStore, &expectedMatches)
|
|
addJavascriptMatches(t, theSource, catalog, theStore, &expectedMatches)
|
|
addDotnetMatches(t, theSource, catalog, theStore, &expectedMatches)
|
|
addGolangMatches(t, theSource, catalog, theStore, &expectedMatches)
|
|
addHaskellMatches(t, theSource, catalog, theStore, &expectedMatches)
|
|
return expectedMatches
|
|
},
|
|
},
|
|
{
|
|
fixtureImage: "image-centos-match-coverage",
|
|
expectedFn: func(theSource source.Source, catalog *syftPkg.Catalog, theStore *mockStore) match.Matches {
|
|
expectedMatches := match.NewMatches()
|
|
addRhelMatches(t, theSource, catalog, theStore, &expectedMatches)
|
|
return expectedMatches
|
|
},
|
|
},
|
|
{
|
|
fixtureImage: "image-alpine-match-coverage",
|
|
expectedFn: func(theSource source.Source, catalog *syftPkg.Catalog, theStore *mockStore) match.Matches {
|
|
expectedMatches := match.NewMatches()
|
|
addAlpineMatches(t, theSource, catalog, theStore, &expectedMatches)
|
|
return expectedMatches
|
|
},
|
|
},
|
|
{
|
|
fixtureImage: "image-sles-match-coverage",
|
|
expectedFn: func(theSource source.Source, catalog *syftPkg.Catalog, theStore *mockStore) match.Matches {
|
|
expectedMatches := match.NewMatches()
|
|
addSlesMatches(t, theSource, catalog, theStore, &expectedMatches)
|
|
return expectedMatches
|
|
},
|
|
},
|
|
{
|
|
fixtureImage: "image-portage-match-coverage",
|
|
expectedFn: func(theSource source.Source, catalog *syftPkg.Catalog, theStore *mockStore) match.Matches {
|
|
expectedMatches := match.NewMatches()
|
|
addPortageMatches(t, theSource, catalog, theStore, &expectedMatches)
|
|
return expectedMatches
|
|
},
|
|
},
|
|
}
|
|
|
|
for _, test := range tests {
|
|
t.Run(test.fixtureImage, func(t *testing.T) {
|
|
theStore := newMockDbStore()
|
|
|
|
imagetest.GetFixtureImage(t, "docker-archive", test.fixtureImage)
|
|
tarPath := imagetest.GetFixtureImageTarPath(t, test.fixtureImage)
|
|
|
|
userImage := "docker-archive:" + tarPath
|
|
|
|
sourceInput, err := source.ParseInput(userImage, "", true)
|
|
if err != nil {
|
|
t.Fatalf("unable to parse user input %+v", err)
|
|
}
|
|
|
|
// this is purely done to help setup mocks
|
|
theSource, cleanup, err := source.New(*sourceInput, nil, nil)
|
|
if err != nil {
|
|
t.Fatalf("failed to determine image source: %+v", err)
|
|
}
|
|
defer cleanup()
|
|
|
|
// TODO: relationships are not verified at this time
|
|
config := cataloger.DefaultConfig()
|
|
config.Search.Scope = source.SquashedScope
|
|
|
|
// enable all catalogers to cover non default cases
|
|
config.Catalogers = []string{"all"}
|
|
|
|
theCatalog, _, theDistro, err := syft.CatalogPackages(theSource, config)
|
|
if err != nil {
|
|
t.Fatalf("could not get the source obj: %+v", err)
|
|
}
|
|
|
|
matchers := matcher.NewDefaultMatchers(matcher.Config{})
|
|
|
|
vp, err := db.NewVulnerabilityProvider(theStore)
|
|
require.NoError(t, err)
|
|
ep := db.NewMatchExclusionProvider(theStore)
|
|
store := store.Store{
|
|
Provider: vp,
|
|
MetadataProvider: nil,
|
|
ExclusionProvider: ep,
|
|
}
|
|
|
|
actualResults := grype.FindVulnerabilitiesForPackage(store, theDistro, matchers, pkg.FromCatalog(theCatalog, pkg.ProviderConfig{}))
|
|
|
|
// build expected matches from what's discovered from the catalog
|
|
expectedMatches := test.expectedFn(*theSource, theCatalog, theStore)
|
|
|
|
// build expected match set...
|
|
expectedMatchSet := map[string]string{}
|
|
for eMatch := range expectedMatches.Enumerate() {
|
|
// NOTE: this does not include all fields...
|
|
expectedMatchSet[eMatch.Package.Name] = eMatch.String()
|
|
}
|
|
|
|
expectedCount := len(expectedMatchSet)
|
|
|
|
// ensure that all matches are covered
|
|
actualCount := 0
|
|
for aMatch := range actualResults.Enumerate() {
|
|
actualCount++
|
|
for _, details := range aMatch.Details {
|
|
observedMatchers.Add(string(details.Matcher))
|
|
}
|
|
value, ok := expectedMatchSet[aMatch.Package.Name]
|
|
if !ok {
|
|
t.Errorf("Package: %s was expected but not found", aMatch.Package.Name)
|
|
}
|
|
|
|
if value != aMatch.String() {
|
|
dmp := diffmatchpatch.New()
|
|
diffs := dmp.DiffMain(value, aMatch.String(), true)
|
|
t.Errorf("mismatched output:\n%s", dmp.DiffPrettyText(diffs))
|
|
}
|
|
}
|
|
|
|
if expectedCount != actualCount {
|
|
t.Errorf("expected %d matches but got %d matches", expectedCount, actualCount)
|
|
}
|
|
})
|
|
}
|
|
|
|
// ensure that integration test cases stay in sync with the implemented matchers
|
|
observedMatchers.Remove(string(match.UnknownMatcherType))
|
|
definedMatchers.Remove(string(match.UnknownMatcherType))
|
|
definedMatchers.Remove(string(match.MsrcMatcher))
|
|
|
|
if len(observedMatchers) != len(definedMatchers) {
|
|
t.Errorf("matcher coverage incomplete (matchers=%d, coverage=%d)", len(definedMatchers), len(observedMatchers))
|
|
for _, m := range definedMatchers.ToSlice() {
|
|
t.Logf(" defined: %+v\n", m)
|
|
}
|
|
for _, m := range observedMatchers.ToSlice() {
|
|
t.Logf(" found: %+v\n", m)
|
|
}
|
|
}
|
|
|
|
}
|