syft/internal/capabilities/generate/cataloger_config_linking_test.go
Alex Goodman 1510db7c4e add info command from generated capabilities
Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com>
2025-10-13 17:14:40 -04:00

243 lines
6.1 KiB
Go

package main
import (
"testing"
"github.com/stretchr/testify/require"
)
func TestLinkCatalogersToConfigs(t *testing.T) {
repoRoot, err := RepoRoot()
require.NoError(t, err)
linkages, err := LinkCatalogersToConfigs(repoRoot)
require.NoError(t, err)
// verify we discovered multiple catalogers
require.NotEmpty(t, linkages, "should discover at least one cataloger linkage")
// test cases for known catalogers with configs
// NOTE: Some catalogers may not be detected if their Name() method is in a different file
// than the constructor function. This is a known limitation.
tests := []struct {
catalogerName string
wantConfig string
optional bool // set to true if detection may not work due to cross-file Name() methods
}{
{
catalogerName: "go-module-binary-cataloger",
wantConfig: "golang.CatalogerConfig",
},
{
catalogerName: "go-module-file-cataloger",
wantConfig: "golang.CatalogerConfig",
},
{
catalogerName: "python-package-cataloger",
wantConfig: "python.CatalogerConfig",
},
{
catalogerName: "java-archive-cataloger",
wantConfig: "java.ArchiveCatalogerConfig",
},
{
catalogerName: "java-pom-cataloger",
wantConfig: "java.ArchiveCatalogerConfig",
optional: true, // Name() method in different file
},
{
catalogerName: "dotnet-deps-binary-cataloger",
wantConfig: "dotnet.CatalogerConfig",
optional: true, // Name() method in different file
},
{
catalogerName: "javascript-lock-cataloger",
wantConfig: "javascript.CatalogerConfig",
},
{
catalogerName: "linux-kernel-cataloger",
wantConfig: "kernel.LinuxKernelCatalogerConfig",
},
{
catalogerName: "nix-cataloger",
wantConfig: "nix.Config",
optional: true, // Name() method in different file
},
}
for _, tt := range tests {
t.Run(tt.catalogerName, func(t *testing.T) {
config, ok := linkages[tt.catalogerName]
if tt.optional && !ok {
t.Skipf("cataloger %s not detected (expected due to cross-file Name() method)", tt.catalogerName)
return
}
require.True(t, ok, "should find linkage for cataloger: %s", tt.catalogerName)
require.Equal(t, tt.wantConfig, config, "config type should match for cataloger: %s", tt.catalogerName)
})
}
// test catalogers without configs (should have empty string)
catalogersWithoutConfig := []string{
"python-installed-package-cataloger",
"java-gradle-lockfile-cataloger",
"java-jvm-cataloger",
"dotnet-packages-lock-cataloger",
"javascript-package-cataloger",
}
for _, catalogerName := range catalogersWithoutConfig {
t.Run(catalogerName+"_no_config", func(t *testing.T) {
config, ok := linkages[catalogerName]
if ok {
require.Empty(t, config, "cataloger %s should have empty config", catalogerName)
}
})
}
// print summary for manual inspection
t.Logf("Discovered %d cataloger-to-config linkages:", len(linkages))
// separate into catalogers with and without configs
withConfig := make(map[string]string)
withoutConfig := make([]string, 0)
for name, config := range linkages {
if config != "" {
withConfig[name] = config
} else {
withoutConfig = append(withoutConfig, name)
}
}
t.Logf("Catalogers with configs (%d):", len(withConfig))
for name, config := range withConfig {
t.Logf(" %s -> %s", name, config)
}
t.Logf("Catalogers without configs (%d):", len(withoutConfig))
for _, name := range withoutConfig {
t.Logf(" %s", name)
}
// ensure we found at least some catalogers with configs
require.GreaterOrEqual(t, len(withConfig), 6, "should find at least 6 catalogers with configs")
}
func TestExtractConfigTypeName(t *testing.T) {
tests := []struct {
name string
catalogerName string
expectedConfig string
expectedNoConfig bool
}{
{
name: "golang config",
catalogerName: "go-module-binary-cataloger",
expectedConfig: "golang.CatalogerConfig",
},
{
name: "python config",
catalogerName: "python-package-cataloger",
expectedConfig: "python.CatalogerConfig",
},
{
name: "java archive config",
catalogerName: "java-archive-cataloger",
expectedConfig: "java.ArchiveCatalogerConfig",
},
{
name: "kernel config",
catalogerName: "linux-kernel-cataloger",
expectedConfig: "kernel.LinuxKernelCatalogerConfig",
},
{
name: "python installed - no config",
catalogerName: "python-installed-package-cataloger",
expectedNoConfig: true,
},
}
repoRoot, err := RepoRoot()
require.NoError(t, err)
linkages, err := LinkCatalogersToConfigs(repoRoot)
require.NoError(t, err)
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
config, ok := linkages[tt.catalogerName]
if tt.expectedNoConfig {
if ok {
require.Empty(t, config, "expected no config for %s", tt.catalogerName)
}
} else {
require.True(t, ok, "should find cataloger %s", tt.catalogerName)
require.Equal(t, tt.expectedConfig, config)
}
})
}
}
func TestLooksLikeConfigType(t *testing.T) {
tests := []struct {
name string
typeName string
want bool
}{
{
name: "golang config",
typeName: "golang.CatalogerConfig",
want: true,
},
{
name: "python config",
typeName: "python.CatalogerConfig",
want: true,
},
{
name: "java archive config",
typeName: "java.ArchiveCatalogerConfig",
want: true,
},
{
name: "kernel config",
typeName: "kernel.LinuxKernelCatalogerConfig",
want: true,
},
{
name: "nix config",
typeName: "nix.Config",
want: true,
},
{
name: "config prefix",
typeName: "package.ConfigOptions",
want: true,
},
{
name: "not a config type",
typeName: "package.Parser",
want: false,
},
{
name: "not a config type - resolver",
typeName: "file.Resolver",
want: false,
},
{
name: "no package prefix",
typeName: "CatalogerConfig",
want: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got := looksLikeConfigType(tt.typeName)
require.Equal(t, tt.want, got)
})
}
}