package quality import ( "os" "path/filepath" "strings" "testing" ) func TestGetSupportedLanguages(t *testing.T) { languages := GetSupportedLanguages() if len(languages) == 0 { t.Error("GetSupportedLanguages() should return at least one language") } expectedLanguages := []string{ "go", "typescript", "python", "java", "rust", "javascript", "csharp", "dart", } if len(languages) != len(expectedLanguages) { t.Errorf("GetSupportedLanguages() expected %d languages, got %d", len(expectedLanguages), len(languages)) } // Check that all expected languages are present languageMap := make(map[string]bool) for _, lang := range languages { languageMap[lang.Name] = true } for _, expected := range expectedLanguages { if !languageMap[expected] { t.Errorf("GetSupportedLanguages() missing expected language: %s", expected) } } // Verify Go language configuration var goConfig *LanguageConfig for _, lang := range languages { if lang.Name == "go" { goConfig = &lang break } } if goConfig == nil { t.Error("GetSupportedLanguages() should include Go language") return } expectedGoExtensions := []string{".go"} if len(goConfig.Extensions) != len(expectedGoExtensions) { t.Errorf("Go expected %d extensions, got %d", len(expectedGoExtensions), len(goConfig.Extensions)) } for i, ext := range goConfig.Extensions { if ext != expectedGoExtensions[i] { t.Errorf("Go extension %d expected %s, got %s", i, expectedGoExtensions[i], ext) } } expectedGoMarkers := []string{"go.mod", "go.sum"} if len(goConfig.MarkerFiles) != len(expectedGoMarkers) { t.Errorf("Go expected %d marker files, got %d", len(expectedGoMarkers), len(goConfig.MarkerFiles)) } if goConfig.DefaultSrc != "." { t.Errorf("Go expected default src '.', got %s", goConfig.DefaultSrc) } } func TestNewDefaultFileFinder(t *testing.T) { finder := NewDefaultFileFinder() if finder == nil { t.Error("NewDefaultFileFinder() should not return nil") } // Test that it implements the interface var _ FileFinder = finder } func TestDefaultFileFinder_FindFiles(t *testing.T) { // Create temporary directory for testing tmpDir, err := os.MkdirTemp("", "filefinder_test") if err != nil { t.Fatalf("Failed to create temp dir: %v", err) } defer os.RemoveAll(tmpDir) finder := NewDefaultFileFinder() // Create test files testFiles := map[string]string{ "main.go": "package main", "utils.go": "package utils", "test.ts": "export function test() {}", "app.py": "print('hello')", "Main.java": "public class Main {}", "lib.rs": "fn main() {}", "script.js": "console.log('hello')", "Program.cs": "using System;", "main.dart": "void main() {}", "readme.md": "# README", "config.json": "{}", } for file, content := range testFiles { fullPath := filepath.Join(tmpDir, file) err := os.WriteFile(fullPath, []byte(content), 0644) if err != nil { t.Fatalf("Failed to create test file %s: %v", file, err) } } // Create subdirectory with hidden folder os.MkdirAll(filepath.Join(tmpDir, ".hidden"), 0755) os.WriteFile(filepath.Join(tmpDir, ".hidden", "hidden.go"), []byte("package hidden"), 0644) // Create node_modules directory (should be skipped) os.MkdirAll(filepath.Join(tmpDir, "node_modules"), 0755) os.WriteFile(filepath.Join(tmpDir, "node_modules", "index.js"), []byte("module code"), 0644) tests := []struct { name string language string expected int }{ {"go files", "go", 2}, {"typescript files", "typescript", 1}, {"python files", "python", 1}, {"java files", "java", 1}, {"rust files", "rust", 1}, {"javascript files", "javascript", 1}, {"csharp files", "csharp", 1}, {"dart files", "dart", 1}, {"unknown language defaults to go", "unknown", 2}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { files, err := finder.FindFiles(tmpDir, tt.language) if err != nil { t.Errorf("FindFiles() failed: %v", err) } if len(files) != tt.expected { t.Errorf("FindFiles() expected %d files, got %d", tt.expected, len(files)) } }) } } func TestDefaultFileFinder_FindFiles_EmptyDirectory(t *testing.T) { tmpDir, err := os.MkdirTemp("", "filefinder_empty_test") if err != nil { t.Fatalf("Failed to create temp dir: %v", err) } defer os.RemoveAll(tmpDir) finder := NewDefaultFileFinder() files, err := finder.FindFiles(tmpDir, "go") if err != nil { t.Errorf("FindFiles() failed: %v", err) } if len(files) != 0 { t.Errorf("FindFiles() expected 0 files, got %d", len(files)) } } func TestDefaultFileFinder_FindFiles_DotPathRootNotSkipped(t *testing.T) { tmpDir, err := os.MkdirTemp("", "filefinder_dot_root_test") if err != nil { t.Fatalf("Failed to create temp dir: %v", err) } defer os.RemoveAll(tmpDir) if err := os.WriteFile(filepath.Join(tmpDir, "main.go"), []byte("package main"), 0644); err != nil { t.Fatalf("Failed to write go file: %v", err) } cwd, err := os.Getwd() if err != nil { t.Fatalf("Failed to get cwd: %v", err) } defer func() { _ = os.Chdir(cwd) }() if err := os.Chdir(tmpDir); err != nil { t.Fatalf("Failed to chdir: %v", err) } finder := NewDefaultFileFinder() files, err := finder.FindFiles(".", "go") if err != nil { t.Fatalf("FindFiles() failed: %v", err) } if len(files) != 1 { t.Fatalf("FindFiles('.') expected 1 file, got %d", len(files)) } } func TestDefaultFileFinder_FindFiles_NonExistentPath(t *testing.T) { finder := NewDefaultFileFinder() files, err := finder.FindFiles("/non/existent/path", "go") if err == nil { t.Error("FindFiles() should fail for non-existent path") } if len(files) != 0 { t.Errorf("FindFiles() expected 0 files for error case, got %d", len(files)) } } func TestDefaultFileFinder_IsSourceFile(t *testing.T) { finder := NewDefaultFileFinder() tests := []struct { name string path string language string expected bool }{ {"go file", "main.go", "go", true}, {"typescript file", "app.ts", "typescript", true}, {"tsx file", "component.tsx", "typescript", true}, {"python file", "script.py", "python", true}, {"java file", "Main.java", "java", true}, {"rust file", "lib.rs", "rust", true}, {"javascript file", "app.js", "javascript", true}, {"jsx file", "component.jsx", "javascript", true}, {"csharp file", "Program.cs", "csharp", true}, {"dart file", "main.dart", "dart", true}, {"markdown file", "readme.md", "go", false}, {"json file", "config.json", "go", false}, {"text file", "notes.txt", "go", false}, {"unknown language defaults to go", "script.rb", "ruby", false}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { result := finder.IsSourceFile(tt.path, tt.language) if result != tt.expected { t.Errorf("IsSourceFile(%s, %s) = %v, want %v", tt.path, tt.language, result, tt.expected) } }) } } func TestDetectLanguage(t *testing.T) { // Create temporary directory for testing tmpDir, err := os.MkdirTemp("", "detect_language_test") if err != nil { t.Fatalf("Failed to create temp dir: %v", err) } defer os.RemoveAll(tmpDir) tests := []struct { name string setup func() string expected string }{ { name: "go project with go.mod", setup: func() string { dir, _ := os.MkdirTemp("", "go_test") os.WriteFile(filepath.Join(dir, "go.mod"), []byte("module test"), 0644) return dir }, expected: "go", }, { name: "typescript project with package.json", setup: func() string { dir, _ := os.MkdirTemp("", "ts_test") os.WriteFile(filepath.Join(dir, "package.json"), []byte("{}"), 0644) return dir }, expected: "typescript", }, { name: "typescript project with tsconfig.json", setup: func() string { dir, _ := os.MkdirTemp("", "tsconfig_test") os.WriteFile(filepath.Join(dir, "tsconfig.json"), []byte("{}"), 0644) return dir }, expected: "typescript", }, { name: "python project with requirements.txt", setup: func() string { dir, _ := os.MkdirTemp("", "py_test") os.WriteFile(filepath.Join(dir, "requirements.txt"), []byte("flask"), 0644) return dir }, expected: "python", }, { name: "python project with setup.py", setup: func() string { dir, _ := os.MkdirTemp("", "setup_test") os.WriteFile(filepath.Join(dir, "setup.py"), []byte("from setuptools import setup"), 0644) return dir }, expected: "python", }, { name: "python project with pyproject.toml", setup: func() string { dir, _ := os.MkdirTemp("", "pyproject_test") os.WriteFile(filepath.Join(dir, "pyproject.toml"), []byte("[build-system]"), 0644) return dir }, expected: "python", }, { name: "java project with pom.xml", setup: func() string { dir, _ := os.MkdirTemp("", "java_test") os.WriteFile(filepath.Join(dir, "pom.xml"), []byte(""), 0644) return dir }, expected: "java", }, { name: "java project with build.gradle", setup: func() string { dir, _ := os.MkdirTemp("", "gradle_test") os.WriteFile(filepath.Join(dir, "build.gradle"), []byte("plugins {}"), 0644) return dir }, expected: "java", }, { name: "rust project with Cargo.toml", setup: func() string { dir, _ := os.MkdirTemp("", "rust_test") os.WriteFile(filepath.Join(dir, "Cargo.toml"), []byte("[package]"), 0644) return dir }, expected: "rust", }, { name: "javascript project with package.json", setup: func() string { dir, _ := os.MkdirTemp("", "js_test") os.WriteFile(filepath.Join(dir, "package.json"), []byte("{}"), 0644) return dir }, expected: "typescript", // TypeScript comes before JavaScript in the list }, { name: "csharp project with .csproj file", setup: func() string { dir, _ := os.MkdirTemp("", "cs_test") os.WriteFile(filepath.Join(dir, "Project.csproj"), []byte(""), 0644) return dir }, expected: "csharp", }, { name: "csharp project with .sln file", setup: func() string { dir, _ := os.MkdirTemp("", "sln_test") os.WriteFile(filepath.Join(dir, "Solution.sln"), []byte("Microsoft Visual Studio Solution File"), 0644) return dir }, expected: "csharp", }, { name: "dart project with pubspec.yaml", setup: func() string { dir, _ := os.MkdirTemp("", "dart_test") os.WriteFile(filepath.Join(dir, "pubspec.yaml"), []byte("name: test"), 0644) return dir }, expected: "dart", }, { name: "no markers defaults to go", setup: func() string { dir, _ := os.MkdirTemp("", "empty_test") return dir }, expected: "go", }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { dir := tt.setup() defer os.RemoveAll(dir) detected := DetectLanguage(dir) if detected != tt.expected { t.Errorf("DetectLanguage() = %v, want %v", detected, tt.expected) } }) } } func TestDetectLanguage_NonExistentPath(t *testing.T) { result := DetectLanguage("/non/existent/path") if result != "go" { t.Errorf("DetectLanguage() should default to 'go' for non-existent path, got %s", result) } } func TestDetectLanguage_MultipleMarkers(t *testing.T) { tmpDir, err := os.MkdirTemp("", "multiple_markers_test") if err != nil { t.Fatalf("Failed to create temp dir: %v", err) } defer os.RemoveAll(tmpDir) // Create multiple marker files - should detect the first one in order os.WriteFile(filepath.Join(tmpDir, "go.mod"), []byte("module test"), 0644) os.WriteFile(filepath.Join(tmpDir, "package.json"), []byte("{}"), 0644) detected := DetectLanguage(tmpDir) if detected != "go" { t.Errorf("DetectLanguage() should detect 'go' (first in order), got %s", detected) } } func TestLanguageConfig_Structure(t *testing.T) { languages := GetSupportedLanguages() for _, lang := range languages { if lang.Name == "" { t.Error("LanguageConfig.Name should not be empty") } if len(lang.Extensions) == 0 { t.Errorf("LanguageConfig %s should have at least one extension", lang.Name) } if len(lang.MarkerFiles) == 0 { t.Errorf("LanguageConfig %s should have at least one marker file", lang.Name) } if lang.DefaultSrc == "" { t.Errorf("LanguageConfig %s should have a default source directory", lang.Name) } // Verify extensions start with dot for _, ext := range lang.Extensions { if !strings.HasPrefix(ext, ".") { t.Errorf("LanguageConfig %s extension %s should start with '.'", lang.Name, ext) } } } }