Files
Devour/internal/quality/languages_test.go
T
Tomas Dvorak 898a3c303f update
2026-02-24 10:33:59 +01:00

457 lines
12 KiB
Go

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("<project></project>"), 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("<Project></Project>"), 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)
}
}
}
}