diff --git a/go.mod b/go.mod index f2c1b2b9a..14df9a9ae 100644 --- a/go.mod +++ b/go.mod @@ -6,6 +6,7 @@ require ( github.com/adrg/xdg v0.2.1 github.com/anchore/go-testutils v0.0.0-20200624184116-66aa578126db github.com/anchore/stereoscope v0.0.0-20200706164556-7cf39d7f4639 + github.com/bmatcuk/doublestar v1.3.1 github.com/go-test/deep v1.0.6 github.com/google/go-containerregistry v0.1.1 // indirect github.com/gookit/color v1.2.5 diff --git a/go.sum b/go.sum index 31060cc2b..0cc7ff12e 100644 --- a/go.sum +++ b/go.sum @@ -161,6 +161,8 @@ github.com/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod h1:MKsuJm github.com/blakesmith/ar v0.0.0-20190502131153-809d4375e1fb h1:m935MPodAbYS46DG4pJSv7WO+VECIWUQ7OJYSoTrMh4= github.com/blakesmith/ar v0.0.0-20190502131153-809d4375e1fb/go.mod h1:PkYb9DJNAwrSvRx5DYA+gUcOIgTGVMNkfSCbZM8cWpI= github.com/blang/semver v3.5.0+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk= +github.com/bmatcuk/doublestar v1.3.1 h1:rT8rxDPsavp9G+4ZULzqhhUSaI/OPsTZNG88Z3i0xvY= +github.com/bmatcuk/doublestar v1.3.1/go.mod h1:wiQtGV+rzVYxB7WIlirSN++5HPtPlXEo9MEoZQC/PmE= github.com/bombsimon/wsl/v2 v2.0.0/go.mod h1:mf25kr/SqFEPhhcxW1+7pxzGlW+hIl/hYTKY95VwV8U= github.com/bombsimon/wsl/v2 v2.2.0/go.mod h1:Azh8c3XGEJl9LyX0/sFC+CKMc7Ssgua0g+6abzXN4Pg= github.com/bombsimon/wsl/v3 v3.0.0/go.mod h1:st10JtZYLE4D5sC7b8xV4zTKZwAQjCH/Hy2Pm1FNZIc= diff --git a/imgbom/cataloger/bundler/cataloger.go b/imgbom/cataloger/bundler/cataloger.go index 91de47d2f..1c954f599 100644 --- a/imgbom/cataloger/bundler/cataloger.go +++ b/imgbom/cataloger/bundler/cataloger.go @@ -13,7 +13,7 @@ type Cataloger struct { func NewCataloger() *Cataloger { globParsers := map[string]common.ParserFn{ - "*/Gemfile.lock": parseGemfileLockEntries, + "**/Gemfile.lock": parseGemfileLockEntries, } return &Cataloger{ diff --git a/imgbom/cataloger/dpkg/cataloger.go b/imgbom/cataloger/dpkg/cataloger.go index 02a85ef41..f1df32598 100644 --- a/imgbom/cataloger/dpkg/cataloger.go +++ b/imgbom/cataloger/dpkg/cataloger.go @@ -12,12 +12,12 @@ type Cataloger struct { } func NewCataloger() *Cataloger { - pathParsers := map[string]common.ParserFn{ - "/var/lib/dpkg/status": parseDpkgStatus, + globParsers := map[string]common.ParserFn{ + "**/var/lib/dpkg/status": parseDpkgStatus, } return &Cataloger{ - cataloger: common.NewGenericCataloger(pathParsers, nil), + cataloger: common.NewGenericCataloger(nil, globParsers), } } diff --git a/imgbom/cataloger/java/archive_parser.go b/imgbom/cataloger/java/archive_parser.go index df9010184..7047cc449 100644 --- a/imgbom/cataloger/java/archive_parser.go +++ b/imgbom/cataloger/java/archive_parser.go @@ -11,11 +11,11 @@ import ( ) var archiveFormatGlobs = []string{ - "*.jar", - "*.war", - "*.ear", - "*.jpi", - "*.hpi", + "**/*.jar", + "**/*.war", + "**/*.ear", + "**/*.jpi", + "**/*.hpi", } type archiveParser struct { diff --git a/imgbom/cataloger/python/cataloger.go b/imgbom/cataloger/python/cataloger.go index 5bf693223..6b0e6e5cd 100644 --- a/imgbom/cataloger/python/cataloger.go +++ b/imgbom/cataloger/python/cataloger.go @@ -13,8 +13,8 @@ type Cataloger struct { func NewCataloger() *Cataloger { globParsers := map[string]common.ParserFn{ - "*egg-info/PKG-INFO": parseEggMetadata, - "*dist-info/METADATA": parseWheelMetadata, + "**/egg-info/PKG-INFO": parseEggMetadata, + "**/dist-info/METADATA": parseWheelMetadata, } return &Cataloger{ diff --git a/imgbom/cataloger/rpmdb/cataloger.go b/imgbom/cataloger/rpmdb/cataloger.go index b460cc783..0f11d3718 100644 --- a/imgbom/cataloger/rpmdb/cataloger.go +++ b/imgbom/cataloger/rpmdb/cataloger.go @@ -12,12 +12,12 @@ type Cataloger struct { } func NewCataloger() *Cataloger { - pathParsers := map[string]common.ParserFn{ - "/var/lib/rpm/Packages": parseRpmDB, + globParsers := map[string]common.ParserFn{ + "**/var/lib/rpm/Packages": parseRpmDB, } return &Cataloger{ - cataloger: common.NewGenericCataloger(pathParsers, nil), + cataloger: common.NewGenericCataloger(nil, globParsers), } } diff --git a/imgbom/scope/resolvers/directory_resolver.go b/imgbom/scope/resolvers/directory_resolver.go index 32ddfd0bb..7d01f1122 100644 --- a/imgbom/scope/resolvers/directory_resolver.go +++ b/imgbom/scope/resolvers/directory_resolver.go @@ -5,10 +5,10 @@ import ( "io/ioutil" "os" "path" - "path/filepath" "github.com/anchore/imgbom/internal/log" "github.com/anchore/stereoscope/pkg/file" + "github.com/bmatcuk/doublestar" ) type DirectoryResolver struct { @@ -51,7 +51,7 @@ func (s DirectoryResolver) FilesByGlob(patterns ...string) ([]file.Reference, er for _, pattern := range patterns { pathPattern := path.Join(s.Path, pattern) - matches, err := filepath.Glob(pathPattern) + matches, err := doublestar.Glob(pathPattern) if err != nil { return result, err } diff --git a/imgbom/scope/resolvers/directory_resolver_test.go b/imgbom/scope/resolvers/directory_resolver_test.go index 1825e87c6..c70f8a4ff 100644 --- a/imgbom/scope/resolvers/directory_resolver_test.go +++ b/imgbom/scope/resolvers/directory_resolver_test.go @@ -138,6 +138,7 @@ func TestDirectoryResolver_FilesByGlobMultiple(t *testing.T) { t.Run("finds multiple matching files", func(t *testing.T) { resolver := DirectoryResolver{"test-fixtures"} refs, err := resolver.FilesByGlob("image-symlinks/file*") + if err != nil { t.Fatalf("could not use resolver: %+v, %+v", err, refs) } @@ -149,6 +150,22 @@ func TestDirectoryResolver_FilesByGlobMultiple(t *testing.T) { }) } +func TestDirectoryResolver_FilesByGlobRecursive(t *testing.T) { + t.Run("finds multiple matching files", func(t *testing.T) { + resolver := DirectoryResolver{"test-fixtures"} + refs, err := resolver.FilesByGlob("**/*.txt") + + if err != nil { + t.Fatalf("could not use resolver: %+v, %+v", err, refs) + } + + if len(refs) != 4 { + t.Errorf("unexpected number of refs: %d != 4", len(refs)) + } + + }) +} + func TestDirectoryResolver_FilesByGlobSingle(t *testing.T) { t.Run("finds multiple matching files", func(t *testing.T) { resolver := DirectoryResolver{"test-fixtures"} diff --git a/imgbom/scope/resolvers/test-fixtures/image-symlinks/nested/nested/file-3.txt b/imgbom/scope/resolvers/test-fixtures/image-symlinks/nested/nested/file-3.txt new file mode 100644 index 000000000..dc43ed866 --- /dev/null +++ b/imgbom/scope/resolvers/test-fixtures/image-symlinks/nested/nested/file-3.txt @@ -0,0 +1 @@ +file 3 diff --git a/integration/dir_presenters_test.go b/integration/dir_presenters_test.go deleted file mode 100644 index f915d4d13..000000000 --- a/integration/dir_presenters_test.go +++ /dev/null @@ -1,71 +0,0 @@ -// +build integration - -package integration - -import ( - "flag" -) - -var update = flag.Bool("update", false, "update the *.golden files for json presenters") - -// these tests are providing inconsistent results... we can fix in another PR - -//func TestDirTextPresenter(t *testing.T) { -// var buffer bytes.Buffer -// protocol := imgbom.NewProtocol("dir://test-fixtures") -// if protocol.Type != imgbom.DirProtocol { -// t.Errorf("unexpected protocol returned: %v != %v", protocol.Type, imgbom.DirProtocol) -// } -// -// catalog, err := imgbom.CatalogDir(protocol.Value, scope.AllLayersScope) -// if err != nil { -// t.Errorf("could not produce catalog: %w", err) -// } -// presenterOpt := presenter.ParseOption("text") -// dirPresenter := presenter.GetDirPresenter(presenterOpt, protocol.Value, catalog) -// -// dirPresenter.Present(&buffer) -// actual := buffer.Bytes() -// if *update { -// testutils.UpdateGoldenFileContents(t, actual) -// } -// -// var expected = testutils.GetGoldenFileContents(t) -// -// if !bytes.Equal(expected, actual) { -// dmp := diffmatchpatch.New() -// diffs := dmp.DiffMain(string(actual), string(expected), true) -// t.Errorf("mismatched output:\n%s", dmp.DiffPrettyText(diffs)) -// } -// -//} -// -//func TestDirJsonPresenter(t *testing.T) { -// var buffer bytes.Buffer -// protocol := imgbom.NewProtocol("dir://test-fixtures") -// if protocol.Type != imgbom.DirProtocol { -// t.Errorf("unexpected protocol returned: %v != %v", protocol.Type, imgbom.DirProtocol) -// } -// -// catalog, err := imgbom.CatalogDir(protocol.Value, scope.AllLayersScope) -// if err != nil { -// t.Errorf("could not produce catalog: %w", err) -// } -// presenterOpt := presenter.ParseOption("json") -// dirPresenter := presenter.GetDirPresenter(presenterOpt, protocol.Value, catalog) -// -// dirPresenter.Present(&buffer) -// actual := buffer.Bytes() -// if *update { -// testutils.UpdateGoldenFileContents(t, actual) -// } -// -// var expected = testutils.GetGoldenFileContents(t) -// -// if !bytes.Equal(expected, actual) { -// dmp := diffmatchpatch.New() -// diffs := dmp.DiffMain(string(actual), string(expected), true) -// t.Errorf("mismatched output:\n%s", dmp.DiffPrettyText(diffs)) -// } -// -//} diff --git a/integration/fixture_image_pkg_coverage_test.go b/integration/fixture_image_pkg_coverage_test.go deleted file mode 100644 index 2b880e221..000000000 --- a/integration/fixture_image_pkg_coverage_test.go +++ /dev/null @@ -1,204 +0,0 @@ -// +build integration - -package integration - -import ( - "testing" - - "github.com/anchore/imgbom/imgbom" - - "github.com/anchore/imgbom/internal" - - "github.com/anchore/go-testutils" - "github.com/anchore/imgbom/imgbom/pkg" - "github.com/anchore/imgbom/imgbom/scope" -) - -func TestPkgCoverageImage(t *testing.T) { - fixtureImageName := "image-pkg-coverage" - _, cleanup := testutils.GetFixtureImage(t, "docker-archive", fixtureImageName) - tarPath := testutils.GetFixtureImageTarPath(t, fixtureImageName) - defer cleanup() - - catalog, _, _, err := imgbom.Catalog("docker-archive://"+tarPath, scope.AllLayersScope) - if err != nil { - t.Fatalf("failed to catalog image: %+v", err) - } - - cases := []struct { - name string - pkgType pkg.Type - pkgLanguage pkg.Language - pkgInfo map[string]string - }{ - { - name: "find rpmdb packages", - pkgType: pkg.RpmPkg, - pkgInfo: map[string]string{ - "dive": "0.9.2", - }, - }, - { - name: "find dpkg packages", - pkgType: pkg.DebPkg, - pkgInfo: map[string]string{ - "apt": "1.8.2", - }, - }, - { - name: "find java packages", - pkgType: pkg.JavaPkg, - pkgLanguage: pkg.Java, - pkgInfo: map[string]string{ - "example-java-app-maven": "0.1.0", - "example-jenkins-plugin": "1.0-SNAPSHOT", // the jeninks HPI file has a nested JAR of the same name - }, - }, - { - name: "find jenkins plugins", - pkgType: pkg.JenkinsPluginPkg, - pkgLanguage: pkg.Java, - pkgInfo: map[string]string{ - "example-jenkins-plugin": "1.0-SNAPSHOT", - }, - }, - { - name: "find python wheel packages", - pkgType: pkg.WheelPkg, - pkgLanguage: pkg.Python, - pkgInfo: map[string]string{ - "Pygments": "2.6.1", - }, - }, - { - name: "find python egg packages", - pkgType: pkg.EggPkg, - pkgLanguage: pkg.Python, - pkgInfo: map[string]string{ - "requests": "2.22.0", - }, - }, - { - name: "find bundler packages", - pkgType: pkg.BundlerPkg, - pkgLanguage: pkg.Ruby, - pkgInfo: map[string]string{ - "actionmailer": "4.1.1", - "actionpack": "4.1.1", - "actionview": "4.1.1", - "activemodel": "4.1.1", - "activerecord": "4.1.1", - "activesupport": "4.1.1", - "arel": "5.0.1.20140414130214", - "bootstrap-sass": "3.1.1.1", - "builder": "3.2.2", - "coffee-rails": "4.0.1", - "coffee-script": "2.2.0", - "coffee-script-source": "1.7.0", - "erubis": "2.7.0", - "execjs": "2.0.2", - "hike": "1.2.3", - "i18n": "0.6.9", - "jbuilder": "2.0.7", - "jquery-rails": "3.1.0", - "json": "1.8.1", - "kgio": "2.9.2", - "libv8": "3.16.14.3", - "mail": "2.5.4", - "mime-types": "1.25.1", - "minitest": "5.3.4", - "multi_json": "1.10.1", - "mysql2": "0.3.16", - "polyglot": "0.3.4", - "rack": "1.5.2", - "rack-test": "0.6.2", - "rails": "4.1.1", - "railties": "4.1.1", - "raindrops": "0.13.0", - "rake": "10.3.2", - "rdoc": "4.1.1", - "ref": "1.0.5", - "sass": "3.2.19", - "sass-rails": "4.0.3", - "sdoc": "0.4.0", - "spring": "1.1.3", - "sprockets": "2.11.0", - "sprockets-rails": "2.1.3", - "sqlite3": "1.3.9", - "therubyracer": "0.12.1", - "thor": "0.19.1", - "thread_safe": "0.3.3", - "tilt": "1.4.1", - "treetop": "1.4.15", - "turbolinks": "2.2.2", - "tzinfo": "1.2.0", - "uglifier": "2.5.0", - "unicorn": "4.8.3", - }, - }, - } - - observedLanguages := internal.NewStringSet() - definedLanguages := internal.NewStringSet() - for _, l := range pkg.AllLanguages { - definedLanguages.Add(l.String()) - } - - observedPkgs := internal.NewStringSet() - definedPkgs := internal.NewStringSet() - for _, p := range pkg.AllPkgs { - definedPkgs.Add(p.String()) - } - - for _, c := range cases { - t.Run(c.name, func(t *testing.T) { - pkgCount := 0 - - for a := range catalog.Enumerate(c.pkgType) { - - observedLanguages.Add(a.Language.String()) - observedPkgs.Add(a.Type.String()) - - expectedVersion, ok := c.pkgInfo[a.Name] - if !ok { - t.Errorf("unexpected package found: %s", a.Name) - } - - if expectedVersion != a.Version { - t.Errorf("unexpected package version (pkg=%s): %s", a.Name, a.Version) - } - - if a.Language != c.pkgLanguage { - t.Errorf("bad language (pkg=%+v): %+v", a.Name, a.Language) - } - - if a.Type != c.pkgType { - t.Errorf("bad package type (pkg=%+v): %+v", a.Name, a.Type) - } - pkgCount++ - } - - if pkgCount != len(c.pkgInfo) { - for a := range catalog.Enumerate(c.pkgType) { - t.Log(" ", a) - } - t.Fatalf("unexpected package count: %d!=%d", pkgCount, len(c.pkgInfo)) - } - - }) - } - - observedLanguages.Remove(pkg.UnknownLanguage.String()) - definedLanguages.Remove(pkg.UnknownLanguage.String()) - observedPkgs.Remove(pkg.UnknownPkg.String()) - definedPkgs.Remove(pkg.UnknownPkg.String()) - - // ensure that integration test cases stay in sync with the available catalogers - if len(observedLanguages) < len(definedLanguages) { - t.Errorf("language coverage incomplete (languages=%d, coverage=%d)", len(definedLanguages), len(observedLanguages)) - } - - if len(observedPkgs) < len(definedPkgs) { - t.Errorf("package coverage incomplete (packages=%d, coverage=%d)", len(definedPkgs), len(observedPkgs)) - } -} diff --git a/integration/fixture_pkg_coverage_test.go b/integration/fixture_pkg_coverage_test.go new file mode 100644 index 000000000..04a992b81 --- /dev/null +++ b/integration/fixture_pkg_coverage_test.go @@ -0,0 +1,276 @@ +// +build integration + +package integration + +import ( + "testing" + + "github.com/anchore/imgbom/imgbom" + + "github.com/anchore/imgbom/internal" + + "github.com/anchore/go-testutils" + "github.com/anchore/imgbom/imgbom/pkg" + "github.com/anchore/imgbom/imgbom/scope" +) + +var cases = []struct { + name string + pkgType pkg.Type + pkgLanguage pkg.Language + pkgInfo map[string]string +}{ + { + name: "find rpmdb packages", + pkgType: pkg.RpmPkg, + pkgInfo: map[string]string{ + "dive": "0.9.2", + }, + }, + { + name: "find dpkg packages", + pkgType: pkg.DebPkg, + pkgInfo: map[string]string{ + "apt": "1.8.2", + }, + }, + { + name: "find java packages", + pkgType: pkg.JavaPkg, + pkgLanguage: pkg.Java, + pkgInfo: map[string]string{ + "example-java-app-maven": "0.1.0", + "example-jenkins-plugin": "1.0-SNAPSHOT", // the jenkins HPI file has a nested JAR of the same name + }, + }, + { + name: "find jenkins plugins", + pkgType: pkg.JenkinsPluginPkg, + pkgLanguage: pkg.Java, + pkgInfo: map[string]string{ + "example-jenkins-plugin": "1.0-SNAPSHOT", + }, + }, + { + name: "find python wheel packages", + pkgType: pkg.WheelPkg, + pkgLanguage: pkg.Python, + pkgInfo: map[string]string{ + "Pygments": "2.6.1", + }, + }, + { + name: "find python egg packages", + pkgType: pkg.EggPkg, + pkgLanguage: pkg.Python, + pkgInfo: map[string]string{ + "requests": "2.22.0", + }, + }, + { + name: "find bundler packages", + pkgType: pkg.BundlerPkg, + pkgLanguage: pkg.Ruby, + pkgInfo: map[string]string{ + "actionmailer": "4.1.1", + "actionpack": "4.1.1", + "actionview": "4.1.1", + "activemodel": "4.1.1", + "activerecord": "4.1.1", + "activesupport": "4.1.1", + "arel": "5.0.1.20140414130214", + "bootstrap-sass": "3.1.1.1", + "builder": "3.2.2", + "coffee-rails": "4.0.1", + "coffee-script": "2.2.0", + "coffee-script-source": "1.7.0", + "erubis": "2.7.0", + "execjs": "2.0.2", + "hike": "1.2.3", + "i18n": "0.6.9", + "jbuilder": "2.0.7", + "jquery-rails": "3.1.0", + "json": "1.8.1", + "kgio": "2.9.2", + "libv8": "3.16.14.3", + "mail": "2.5.4", + "mime-types": "1.25.1", + "minitest": "5.3.4", + "multi_json": "1.10.1", + "mysql2": "0.3.16", + "polyglot": "0.3.4", + "rack": "1.5.2", + "rack-test": "0.6.2", + "rails": "4.1.1", + "railties": "4.1.1", + "raindrops": "0.13.0", + "rake": "10.3.2", + "rdoc": "4.1.1", + "ref": "1.0.5", + "sass": "3.2.19", + "sass-rails": "4.0.3", + "sdoc": "0.4.0", + "spring": "1.1.3", + "sprockets": "2.11.0", + "sprockets-rails": "2.1.3", + "sqlite3": "1.3.9", + "therubyracer": "0.12.1", + "thor": "0.19.1", + "thread_safe": "0.3.3", + "tilt": "1.4.1", + "treetop": "1.4.15", + "turbolinks": "2.2.2", + "tzinfo": "1.2.0", + "uglifier": "2.5.0", + "unicorn": "4.8.3", + }, + }, +} + +func TestPkgCoverageImage(t *testing.T) { + fixtureImageName := "image-pkg-coverage" + _, cleanup := testutils.GetFixtureImage(t, "docker-archive", fixtureImageName) + tarPath := testutils.GetFixtureImageTarPath(t, fixtureImageName) + defer cleanup() + + catalog, _, _, err := imgbom.Catalog("docker-archive://"+tarPath, scope.AllLayersScope) + if err != nil { + t.Fatalf("failed to catalog image: %+v", err) + } + + observedLanguages := internal.NewStringSet() + definedLanguages := internal.NewStringSet() + for _, l := range pkg.AllLanguages { + definedLanguages.Add(l.String()) + } + + observedPkgs := internal.NewStringSet() + definedPkgs := internal.NewStringSet() + for _, p := range pkg.AllPkgs { + definedPkgs.Add(p.String()) + } + + for _, c := range cases { + t.Run(c.name, func(t *testing.T) { + pkgCount := 0 + + for a := range catalog.Enumerate(c.pkgType) { + + observedLanguages.Add(a.Language.String()) + observedPkgs.Add(a.Type.String()) + + expectedVersion, ok := c.pkgInfo[a.Name] + if !ok { + t.Errorf("unexpected package found: %s", a.Name) + } + + if expectedVersion != a.Version { + t.Errorf("unexpected package version (pkg=%s): %s", a.Name, a.Version) + } + + if a.Language != c.pkgLanguage { + t.Errorf("bad language (pkg=%+v): %+v", a.Name, a.Language) + } + + if a.Type != c.pkgType { + t.Errorf("bad package type (pkg=%+v): %+v", a.Name, a.Type) + } + pkgCount++ + } + + if pkgCount != len(c.pkgInfo) { + for a := range catalog.Enumerate(c.pkgType) { + t.Log(" ", a) + } + t.Fatalf("unexpected package count: %d!=%d", pkgCount, len(c.pkgInfo)) + } + + }) + } + + observedLanguages.Remove(pkg.UnknownLanguage.String()) + definedLanguages.Remove(pkg.UnknownLanguage.String()) + observedPkgs.Remove(pkg.UnknownPkg.String()) + definedPkgs.Remove(pkg.UnknownPkg.String()) + + // ensure that integration test cases stay in sync with the available catalogers + if len(observedLanguages) < len(definedLanguages) { + t.Errorf("language coverage incomplete (languages=%d, coverage=%d)", len(definedLanguages), len(observedLanguages)) + } + + if len(observedPkgs) < len(definedPkgs) { + t.Errorf("package coverage incomplete (packages=%d, coverage=%d)", len(definedPkgs), len(observedPkgs)) + } +} + +func TestPkgCoverageDirectory(t *testing.T) { + catalog, _, _, err := imgbom.Catalog("dir://test-fixtures/image-pkg-coverage", scope.AllLayersScope) + + if err != nil { + t.Errorf("unable to create scope from dir: %+v", err) + } + + observedLanguages := internal.NewStringSet() + definedLanguages := internal.NewStringSet() + for _, l := range pkg.AllLanguages { + definedLanguages.Add(l.String()) + } + + observedPkgs := internal.NewStringSet() + definedPkgs := internal.NewStringSet() + for _, p := range pkg.AllPkgs { + definedPkgs.Add(p.String()) + } + + for _, c := range cases { + t.Run(c.name, func(t *testing.T) { + pkgCount := 0 + + for a := range catalog.Enumerate(c.pkgType) { + + observedLanguages.Add(a.Language.String()) + observedPkgs.Add(a.Type.String()) + + expectedVersion, ok := c.pkgInfo[a.Name] + if !ok { + t.Errorf("unexpected package found: %s", a.Name) + } + + if expectedVersion != a.Version { + t.Errorf("unexpected package version (pkg=%s): %s", a.Name, a.Version) + } + + if a.Language != c.pkgLanguage { + t.Errorf("bad language (pkg=%+v): %+v", a.Name, a.Language) + } + + if a.Type != c.pkgType { + t.Errorf("bad package type (pkg=%+v): %+v", a.Name, a.Type) + } + pkgCount++ + } + + if pkgCount != len(c.pkgInfo) { + for a := range catalog.Enumerate(c.pkgType) { + t.Log(" ", a) + } + t.Fatalf("unexpected package count: %d!=%d", pkgCount, len(c.pkgInfo)) + } + + }) + } + + observedLanguages.Remove(pkg.UnknownLanguage.String()) + definedLanguages.Remove(pkg.UnknownLanguage.String()) + observedPkgs.Remove(pkg.UnknownPkg.String()) + definedPkgs.Remove(pkg.UnknownPkg.String()) + + // ensure that integration test cases stay in sync with the available catalogers + if len(observedLanguages) < len(definedLanguages) { + t.Errorf("language coverage incomplete (languages=%d, coverage=%d)", len(definedLanguages), len(observedLanguages)) + } + + if len(observedPkgs) < len(definedPkgs) { + t.Errorf("package coverage incomplete (packages=%d, coverage=%d)", len(definedPkgs), len(observedPkgs)) + } +} diff --git a/integration/test-fixtures/snapshot/TestDirJsonPresenter.golden b/integration/test-fixtures/snapshot/TestDirJsonPresenter.golden deleted file mode 100644 index 9406dbebc..000000000 --- a/integration/test-fixtures/snapshot/TestDirJsonPresenter.golden +++ /dev/null @@ -1 +0,0 @@ -{"artifacts":[{"name":"actionmailer","version":"4.1.1","type":"bundle","cataloger":"","sources":[{"foundBy":"bundler-cataloger","effects":[]}],"metadata":null},{"name":"actionpack","version":"4.1.1","type":"bundle","cataloger":"","sources":[{"foundBy":"bundler-cataloger","effects":[]}],"metadata":null},{"name":"actionview","version":"4.1.1","type":"bundle","cataloger":"","sources":[{"foundBy":"bundler-cataloger","effects":[]}],"metadata":null},{"name":"activemodel","version":"4.1.1","type":"bundle","cataloger":"","sources":[{"foundBy":"bundler-cataloger","effects":[]}],"metadata":null},{"name":"activerecord","version":"4.1.1","type":"bundle","cataloger":"","sources":[{"foundBy":"bundler-cataloger","effects":[]}],"metadata":null},{"name":"activesupport","version":"4.1.1","type":"bundle","cataloger":"","sources":[{"foundBy":"bundler-cataloger","effects":[]}],"metadata":null},{"name":"arel","version":"5.0.1.20140414130214","type":"bundle","cataloger":"","sources":[{"foundBy":"bundler-cataloger","effects":[]}],"metadata":null},{"name":"bootstrap-sass","version":"3.1.1.1","type":"bundle","cataloger":"","sources":[{"foundBy":"bundler-cataloger","effects":[]}],"metadata":null},{"name":"builder","version":"3.2.2","type":"bundle","cataloger":"","sources":[{"foundBy":"bundler-cataloger","effects":[]}],"metadata":null},{"name":"coffee-rails","version":"4.0.1","type":"bundle","cataloger":"","sources":[{"foundBy":"bundler-cataloger","effects":[]}],"metadata":null},{"name":"coffee-script","version":"2.2.0","type":"bundle","cataloger":"","sources":[{"foundBy":"bundler-cataloger","effects":[]}],"metadata":null},{"name":"coffee-script-source","version":"1.7.0","type":"bundle","cataloger":"","sources":[{"foundBy":"bundler-cataloger","effects":[]}],"metadata":null},{"name":"erubis","version":"2.7.0","type":"bundle","cataloger":"","sources":[{"foundBy":"bundler-cataloger","effects":[]}],"metadata":null},{"name":"execjs","version":"2.0.2","type":"bundle","cataloger":"","sources":[{"foundBy":"bundler-cataloger","effects":[]}],"metadata":null},{"name":"hike","version":"1.2.3","type":"bundle","cataloger":"","sources":[{"foundBy":"bundler-cataloger","effects":[]}],"metadata":null},{"name":"i18n","version":"0.6.9","type":"bundle","cataloger":"","sources":[{"foundBy":"bundler-cataloger","effects":[]}],"metadata":null},{"name":"jbuilder","version":"2.0.7","type":"bundle","cataloger":"","sources":[{"foundBy":"bundler-cataloger","effects":[]}],"metadata":null},{"name":"jquery-rails","version":"3.1.0","type":"bundle","cataloger":"","sources":[{"foundBy":"bundler-cataloger","effects":[]}],"metadata":null},{"name":"json","version":"1.8.1","type":"bundle","cataloger":"","sources":[{"foundBy":"bundler-cataloger","effects":[]}],"metadata":null},{"name":"kgio","version":"2.9.2","type":"bundle","cataloger":"","sources":[{"foundBy":"bundler-cataloger","effects":[]}],"metadata":null},{"name":"libv8","version":"3.16.14.3","type":"bundle","cataloger":"","sources":[{"foundBy":"bundler-cataloger","effects":[]}],"metadata":null},{"name":"mail","version":"2.5.4","type":"bundle","cataloger":"","sources":[{"foundBy":"bundler-cataloger","effects":[]}],"metadata":null},{"name":"mime-types","version":"1.25.1","type":"bundle","cataloger":"","sources":[{"foundBy":"bundler-cataloger","effects":[]}],"metadata":null},{"name":"minitest","version":"5.3.4","type":"bundle","cataloger":"","sources":[{"foundBy":"bundler-cataloger","effects":[]}],"metadata":null},{"name":"multi_json","version":"1.10.1","type":"bundle","cataloger":"","sources":[{"foundBy":"bundler-cataloger","effects":[]}],"metadata":null},{"name":"mysql2","version":"0.3.16","type":"bundle","cataloger":"","sources":[{"foundBy":"bundler-cataloger","effects":[]}],"metadata":null},{"name":"polyglot","version":"0.3.4","type":"bundle","cataloger":"","sources":[{"foundBy":"bundler-cataloger","effects":[]}],"metadata":null},{"name":"rack","version":"1.5.2","type":"bundle","cataloger":"","sources":[{"foundBy":"bundler-cataloger","effects":[]}],"metadata":null},{"name":"rack-test","version":"0.6.2","type":"bundle","cataloger":"","sources":[{"foundBy":"bundler-cataloger","effects":[]}],"metadata":null},{"name":"rails","version":"4.1.1","type":"bundle","cataloger":"","sources":[{"foundBy":"bundler-cataloger","effects":[]}],"metadata":null},{"name":"railties","version":"4.1.1","type":"bundle","cataloger":"","sources":[{"foundBy":"bundler-cataloger","effects":[]}],"metadata":null},{"name":"raindrops","version":"0.13.0","type":"bundle","cataloger":"","sources":[{"foundBy":"bundler-cataloger","effects":[]}],"metadata":null},{"name":"rake","version":"10.3.2","type":"bundle","cataloger":"","sources":[{"foundBy":"bundler-cataloger","effects":[]}],"metadata":null},{"name":"rdoc","version":"4.1.1","type":"bundle","cataloger":"","sources":[{"foundBy":"bundler-cataloger","effects":[]}],"metadata":null},{"name":"ref","version":"1.0.5","type":"bundle","cataloger":"","sources":[{"foundBy":"bundler-cataloger","effects":[]}],"metadata":null},{"name":"sass","version":"3.2.19","type":"bundle","cataloger":"","sources":[{"foundBy":"bundler-cataloger","effects":[]}],"metadata":null},{"name":"sass-rails","version":"4.0.3","type":"bundle","cataloger":"","sources":[{"foundBy":"bundler-cataloger","effects":[]}],"metadata":null},{"name":"sdoc","version":"0.4.0","type":"bundle","cataloger":"","sources":[{"foundBy":"bundler-cataloger","effects":[]}],"metadata":null},{"name":"spring","version":"1.1.3","type":"bundle","cataloger":"","sources":[{"foundBy":"bundler-cataloger","effects":[]}],"metadata":null},{"name":"sprockets","version":"2.11.0","type":"bundle","cataloger":"","sources":[{"foundBy":"bundler-cataloger","effects":[]}],"metadata":null},{"name":"sprockets-rails","version":"2.1.3","type":"bundle","cataloger":"","sources":[{"foundBy":"bundler-cataloger","effects":[]}],"metadata":null},{"name":"sqlite3","version":"1.3.9","type":"bundle","cataloger":"","sources":[{"foundBy":"bundler-cataloger","effects":[]}],"metadata":null},{"name":"therubyracer","version":"0.12.1","type":"bundle","cataloger":"","sources":[{"foundBy":"bundler-cataloger","effects":[]}],"metadata":null},{"name":"thor","version":"0.19.1","type":"bundle","cataloger":"","sources":[{"foundBy":"bundler-cataloger","effects":[]}],"metadata":null},{"name":"thread_safe","version":"0.3.3","type":"bundle","cataloger":"","sources":[{"foundBy":"bundler-cataloger","effects":[]}],"metadata":null},{"name":"tilt","version":"1.4.1","type":"bundle","cataloger":"","sources":[{"foundBy":"bundler-cataloger","effects":[]}],"metadata":null},{"name":"treetop","version":"1.4.15","type":"bundle","cataloger":"","sources":[{"foundBy":"bundler-cataloger","effects":[]}],"metadata":null},{"name":"turbolinks","version":"2.2.2","type":"bundle","cataloger":"","sources":[{"foundBy":"bundler-cataloger","effects":[]}],"metadata":null},{"name":"tzinfo","version":"1.2.0","type":"bundle","cataloger":"","sources":[{"foundBy":"bundler-cataloger","effects":[]}],"metadata":null},{"name":"uglifier","version":"2.5.0","type":"bundle","cataloger":"","sources":[{"foundBy":"bundler-cataloger","effects":[]}],"metadata":null},{"name":"unicorn","version":"4.8.3","type":"bundle","cataloger":"","sources":[{"foundBy":"bundler-cataloger","effects":[]}],"metadata":null}],"Source":"test-fixtures"} \ No newline at end of file diff --git a/integration/test-fixtures/snapshot/TestDirTextPresenter.golden b/integration/test-fixtures/snapshot/TestDirTextPresenter.golden deleted file mode 100644 index de5364a32..000000000 --- a/integration/test-fixtures/snapshot/TestDirTextPresenter.golden +++ /dev/null @@ -1,256 +0,0 @@ -[Path: test-fixtures] -[actionmailer] - Version: 4.1.1 - Type: bundle - Found by: bundler-cataloger - -[actionpack] - Version: 4.1.1 - Type: bundle - Found by: bundler-cataloger - -[actionview] - Version: 4.1.1 - Type: bundle - Found by: bundler-cataloger - -[activemodel] - Version: 4.1.1 - Type: bundle - Found by: bundler-cataloger - -[activerecord] - Version: 4.1.1 - Type: bundle - Found by: bundler-cataloger - -[activesupport] - Version: 4.1.1 - Type: bundle - Found by: bundler-cataloger - -[arel] - Version: 5.0.1.20140414130214 - Type: bundle - Found by: bundler-cataloger - -[bootstrap-sass] - Version: 3.1.1.1 - Type: bundle - Found by: bundler-cataloger - -[builder] - Version: 3.2.2 - Type: bundle - Found by: bundler-cataloger - -[coffee-rails] - Version: 4.0.1 - Type: bundle - Found by: bundler-cataloger - -[coffee-script] - Version: 2.2.0 - Type: bundle - Found by: bundler-cataloger - -[coffee-script-source] - Version: 1.7.0 - Type: bundle - Found by: bundler-cataloger - -[erubis] - Version: 2.7.0 - Type: bundle - Found by: bundler-cataloger - -[execjs] - Version: 2.0.2 - Type: bundle - Found by: bundler-cataloger - -[hike] - Version: 1.2.3 - Type: bundle - Found by: bundler-cataloger - -[i18n] - Version: 0.6.9 - Type: bundle - Found by: bundler-cataloger - -[jbuilder] - Version: 2.0.7 - Type: bundle - Found by: bundler-cataloger - -[jquery-rails] - Version: 3.1.0 - Type: bundle - Found by: bundler-cataloger - -[json] - Version: 1.8.1 - Type: bundle - Found by: bundler-cataloger - -[kgio] - Version: 2.9.2 - Type: bundle - Found by: bundler-cataloger - -[libv8] - Version: 3.16.14.3 - Type: bundle - Found by: bundler-cataloger - -[mail] - Version: 2.5.4 - Type: bundle - Found by: bundler-cataloger - -[mime-types] - Version: 1.25.1 - Type: bundle - Found by: bundler-cataloger - -[minitest] - Version: 5.3.4 - Type: bundle - Found by: bundler-cataloger - -[multi_json] - Version: 1.10.1 - Type: bundle - Found by: bundler-cataloger - -[mysql2] - Version: 0.3.16 - Type: bundle - Found by: bundler-cataloger - -[polyglot] - Version: 0.3.4 - Type: bundle - Found by: bundler-cataloger - -[rack] - Version: 1.5.2 - Type: bundle - Found by: bundler-cataloger - -[rack-test] - Version: 0.6.2 - Type: bundle - Found by: bundler-cataloger - -[rails] - Version: 4.1.1 - Type: bundle - Found by: bundler-cataloger - -[railties] - Version: 4.1.1 - Type: bundle - Found by: bundler-cataloger - -[raindrops] - Version: 0.13.0 - Type: bundle - Found by: bundler-cataloger - -[rake] - Version: 10.3.2 - Type: bundle - Found by: bundler-cataloger - -[rdoc] - Version: 4.1.1 - Type: bundle - Found by: bundler-cataloger - -[ref] - Version: 1.0.5 - Type: bundle - Found by: bundler-cataloger - -[sass] - Version: 3.2.19 - Type: bundle - Found by: bundler-cataloger - -[sass-rails] - Version: 4.0.3 - Type: bundle - Found by: bundler-cataloger - -[sdoc] - Version: 0.4.0 - Type: bundle - Found by: bundler-cataloger - -[spring] - Version: 1.1.3 - Type: bundle - Found by: bundler-cataloger - -[sprockets] - Version: 2.11.0 - Type: bundle - Found by: bundler-cataloger - -[sprockets-rails] - Version: 2.1.3 - Type: bundle - Found by: bundler-cataloger - -[sqlite3] - Version: 1.3.9 - Type: bundle - Found by: bundler-cataloger - -[therubyracer] - Version: 0.12.1 - Type: bundle - Found by: bundler-cataloger - -[thor] - Version: 0.19.1 - Type: bundle - Found by: bundler-cataloger - -[thread_safe] - Version: 0.3.3 - Type: bundle - Found by: bundler-cataloger - -[tilt] - Version: 1.4.1 - Type: bundle - Found by: bundler-cataloger - -[treetop] - Version: 1.4.15 - Type: bundle - Found by: bundler-cataloger - -[turbolinks] - Version: 2.2.2 - Type: bundle - Found by: bundler-cataloger - -[tzinfo] - Version: 1.2.0 - Type: bundle - Found by: bundler-cataloger - -[uglifier] - Version: 2.5.0 - Type: bundle - Found by: bundler-cataloger - -[unicorn] - Version: 4.8.3 - Type: bundle - Found by: bundler-cataloger -