mirror of
https://github.com/Dvorinka/Devour.git
synced 2026-06-04 12:33:04 +00:00
343 lines
9.3 KiB
Go
343 lines
9.3 KiB
Go
package quality
|
|
|
|
import (
|
|
"context"
|
|
"testing"
|
|
)
|
|
|
|
// DetectorMock implements the Detector interface for testing
|
|
type DetectorMock struct {
|
|
name string
|
|
severity Severity
|
|
}
|
|
|
|
func (m *DetectorMock) Name() string {
|
|
return m.name
|
|
}
|
|
|
|
func (m *DetectorMock) Detect(ctx context.Context, path string, config *Config) ([]Finding, error) {
|
|
return []Finding{
|
|
{
|
|
Type: "mock_finding",
|
|
Severity: m.severity,
|
|
Status: StatusOpen,
|
|
Score: 5,
|
|
},
|
|
}, nil
|
|
}
|
|
|
|
func (m *DetectorMock) Severity() Severity {
|
|
return m.severity
|
|
}
|
|
|
|
// LanguageDetectorMock implements both Detector and LanguageDetector interfaces
|
|
type LanguageDetectorMock struct {
|
|
*DetectorMock
|
|
supportedLanguages []string
|
|
}
|
|
|
|
func (m *LanguageDetectorMock) SupportedLanguages() []string {
|
|
return m.supportedLanguages
|
|
}
|
|
|
|
func (m *LanguageDetectorMock) ExtractFunctions(ctx context.Context, files []string) ([]FunctionInfo, error) {
|
|
var functions []FunctionInfo
|
|
for _, file := range files {
|
|
functions = append(functions, FunctionInfo{
|
|
Name: "test_func",
|
|
File: file,
|
|
})
|
|
}
|
|
return functions, nil
|
|
}
|
|
|
|
func (m *LanguageDetectorMock) ExtractClasses(ctx context.Context, files []string) ([]ClassInfo, error) {
|
|
var classes []ClassInfo
|
|
for _, file := range files {
|
|
classes = append(classes, ClassInfo{
|
|
Name: "TestClass",
|
|
File: file,
|
|
})
|
|
}
|
|
return classes, nil
|
|
}
|
|
|
|
// FileFinderMock implements the FileFinder interface for testing
|
|
type FileFinderMock struct {
|
|
files []string
|
|
}
|
|
|
|
func (m *FileFinderMock) FindFiles(path string, language string) ([]string, error) {
|
|
return m.files, nil
|
|
}
|
|
|
|
func (m *FileFinderMock) IsSourceFile(path string, language string) bool {
|
|
return true
|
|
}
|
|
|
|
func TestNewBaseDetector(t *testing.T) {
|
|
finder := &FileFinderMock{files: []string{"test.go"}}
|
|
detector := NewBaseDetector("test-detector", SeverityT2, finder)
|
|
|
|
if detector == nil {
|
|
t.Error("NewBaseDetector() should not return nil")
|
|
}
|
|
|
|
if detector.name != "test-detector" {
|
|
t.Errorf("NewBaseDetector() name = %v, want test-detector", detector.name)
|
|
}
|
|
|
|
if detector.severity != SeverityT2 {
|
|
t.Errorf("NewBaseDetector() severity = %v, want T2", detector.severity)
|
|
}
|
|
|
|
if detector.finder != finder {
|
|
t.Error("NewBaseDetector() finder not set correctly")
|
|
}
|
|
}
|
|
|
|
func TestBaseDetector_Name(t *testing.T) {
|
|
detector := NewBaseDetector("test-name", SeverityT1, nil)
|
|
|
|
if detector.Name() != "test-name" {
|
|
t.Errorf("Name() = %v, want test-name", detector.Name())
|
|
}
|
|
}
|
|
|
|
func TestBaseDetector_Severity(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
severity Severity
|
|
}{
|
|
{"T1 severity", SeverityT1},
|
|
{"T2 severity", SeverityT2},
|
|
{"T3 severity", SeverityT3},
|
|
{"T4 severity", SeverityT4},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
detector := NewBaseDetector("test", tt.severity, nil)
|
|
if detector.Severity() != tt.severity {
|
|
t.Errorf("Severity() = %v, want %v", detector.Severity(), tt.severity)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestBaseDetector_FindFiles(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
finder FileFinder
|
|
expected []string
|
|
}{
|
|
{
|
|
name: "with finder",
|
|
finder: &FileFinderMock{files: []string{"file1.go", "file2.go"}},
|
|
expected: []string{"file1.go", "file2.go"},
|
|
},
|
|
{
|
|
name: "without finder",
|
|
finder: nil,
|
|
expected: nil,
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
detector := NewBaseDetector("test", SeverityT1, tt.finder)
|
|
files, err := detector.FindFiles("/test/path", "go")
|
|
|
|
if err != nil {
|
|
t.Errorf("FindFiles() unexpected error: %v", err)
|
|
}
|
|
|
|
if len(files) != len(tt.expected) {
|
|
t.Errorf("FindFiles() expected %d files, got %d", len(tt.expected), len(files))
|
|
}
|
|
|
|
for i, file := range files {
|
|
if i < len(tt.expected) && file != tt.expected[i] {
|
|
t.Errorf("FindFiles() file %d = %v, want %v", i, file, tt.expected[i])
|
|
}
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestShouldExclude(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
path string
|
|
excludes []string
|
|
expected bool
|
|
}{
|
|
{"no excludes", "test.go", []string{}, false},
|
|
{"empty excludes", "test.go", []string{""}, false},
|
|
{"exact match", "test.go", []string{"test.go"}, true},
|
|
{"pattern match", "test_*.go", []string{"test_*.go"}, true},
|
|
{"no match", "other.go", []string{"test.go"}, false},
|
|
{
|
|
name: "directory match",
|
|
path: "vendor/lib.go",
|
|
excludes: []string{"vendor"},
|
|
expected: false,
|
|
}, // filepath.Match doesn't match directories this way
|
|
{"base directory match", "lib.go", []string{"lib.go"}, true},
|
|
{"multiple patterns", "test.go", []string{"*.py", "test.go"}, true},
|
|
{"invalid pattern", "test.go", []string{"[invalid"}, false},
|
|
{"complex pattern", "internal/test/file.go", []string{"internal/*/file.go"}, true},
|
|
{"case sensitive", "Test.go", []string{"test.go"}, false},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
result := ShouldExclude(tt.path, tt.excludes)
|
|
if result != tt.expected {
|
|
t.Errorf("ShouldExclude(%s, %v) = %v, want %v", tt.path, tt.excludes, result, tt.expected)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestShouldExclude_EdgeCases(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
path string
|
|
excludes []string
|
|
expected bool
|
|
}{
|
|
{"empty path", "", []string{"*"}, true},
|
|
{"empty pattern", "test.go", []string{""}, false},
|
|
{"star pattern", "any_file.go", []string{"*"}, true}, {
|
|
name: "question mark",
|
|
path: "file.go",
|
|
excludes: []string{"file.?"},
|
|
expected: false}, // filepath.Match doesn't support ? this way
|
|
{
|
|
name: "character class",
|
|
path: "file.go",
|
|
excludes: []string{"file.[go]"},
|
|
expected: false}, // filepath.Match doesn't support character classes
|
|
{"nested pattern", "a/b/c/file.go", []string{"a/*/c/file.go"}, true},
|
|
{"absolute path", "/absolute/path/file.go", []string{"*.go"}, true},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
result := ShouldExclude(tt.path, tt.excludes)
|
|
if result != tt.expected {
|
|
t.Errorf("ShouldExclude(%s, %v) = %v, want %v", tt.path, tt.excludes, result, tt.expected)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestMockDetector_Interface(t *testing.T) {
|
|
// Verify that DetectorMock implements Detector interface
|
|
var _ Detector = &DetectorMock{name: "test", severity: SeverityT1}
|
|
|
|
detector := &DetectorMock{name: "test-detector", severity: SeverityT2}
|
|
|
|
ctx := context.Background()
|
|
findings, err := detector.Detect(ctx, "/test/path", &Config{})
|
|
|
|
if err != nil {
|
|
t.Errorf("MockDetector.Detect() unexpected error: %v", err)
|
|
}
|
|
|
|
if len(findings) != 1 {
|
|
t.Errorf("DetectorMock.Detect() expected 1 finding, got %d", len(findings))
|
|
}
|
|
|
|
if findings[0].Type != "mock_finding" {
|
|
t.Errorf("DetectorMock.Detect() finding type = %v, want mock_finding", findings[0].Type)
|
|
}
|
|
|
|
if findings[0].Severity != SeverityT2 {
|
|
t.Errorf("DetectorMock.Detect() finding severity = %v, want T2", findings[0].Severity)
|
|
}
|
|
}
|
|
|
|
func TestLanguageDetectorMock_Interface(t *testing.T) {
|
|
// Verify that LanguageDetectorMock implements LanguageDetector interface
|
|
var _ LanguageDetector = &LanguageDetectorMock{
|
|
DetectorMock: &DetectorMock{name: "test", severity: SeverityT1},
|
|
supportedLanguages: []string{"go", "python"},
|
|
}
|
|
|
|
detector := &LanguageDetectorMock{
|
|
DetectorMock: &DetectorMock{name: "test-lang", severity: SeverityT3},
|
|
supportedLanguages: []string{"go", "python", "javascript"},
|
|
}
|
|
|
|
if len(detector.SupportedLanguages()) != 3 {
|
|
t.Errorf("LanguageDetectorMock.SupportedLanguages() expected 3 languages, got %d", len(detector.SupportedLanguages()))
|
|
}
|
|
|
|
ctx := context.Background()
|
|
files := []string{"file1.go", "file2.py"}
|
|
|
|
functions, err := detector.ExtractFunctions(ctx, files)
|
|
if err != nil {
|
|
t.Errorf("LanguageDetectorMock.ExtractFunctions() unexpected error: %v", err)
|
|
}
|
|
|
|
if len(functions) != 2 {
|
|
t.Errorf("LanguageDetectorMock.ExtractFunctions() expected 2 functions, got %d", len(functions))
|
|
}
|
|
|
|
classes, err := detector.ExtractClasses(ctx, files)
|
|
if err != nil {
|
|
t.Errorf("LanguageDetectorMock.ExtractClasses() unexpected error: %v", err)
|
|
}
|
|
|
|
if len(classes) != 2 {
|
|
t.Errorf("LanguageDetectorMock.ExtractClasses() expected 2 classes, got %d", len(classes))
|
|
}
|
|
}
|
|
|
|
func TestMockFileFinder_Interface(t *testing.T) {
|
|
// Verify that FileFinderMock implements FileFinder interface
|
|
var _ FileFinder = &FileFinderMock{files: []string{"test.go"}}
|
|
|
|
finder := &FileFinderMock{files: []string{"file1.go", "file2.go"}}
|
|
|
|
files, err := finder.FindFiles("/test/path", "go")
|
|
if err != nil {
|
|
t.Errorf("FileFinderMock.FindFiles() unexpected error: %v", err)
|
|
}
|
|
|
|
if len(files) != 2 {
|
|
t.Errorf("FileFinderMock.FindFiles() expected 2 files, got %d", len(files))
|
|
}
|
|
|
|
if !finder.IsSourceFile("test.go", "go") {
|
|
t.Error("FileFinderMock.IsSourceFile() should return true")
|
|
}
|
|
}
|
|
|
|
func TestBaseDetector_Integration(t *testing.T) {
|
|
// Test BaseDetector with real mock implementations
|
|
finder := &FileFinderMock{files: []string{"main.go", "utils.go"}}
|
|
detector := NewBaseDetector("integration-test", SeverityT2, finder)
|
|
|
|
// Test all methods
|
|
if detector.Name() != "integration-test" {
|
|
t.Errorf("Integration test: Name() = %v, want integration-test", detector.Name())
|
|
}
|
|
|
|
if detector.Severity() != SeverityT2 {
|
|
t.Errorf("Integration test: Severity() = %v, want T2", detector.Severity())
|
|
}
|
|
|
|
files, err := detector.FindFiles("/project", "go")
|
|
if err != nil {
|
|
t.Errorf("Integration test: FindFiles() unexpected error: %v", err)
|
|
}
|
|
|
|
if len(files) != 2 {
|
|
t.Errorf("Integration test: FindFiles() expected 2 files, got %d", len(files))
|
|
}
|
|
}
|