package indexgen import ( "bytes" "os" "path/filepath" "regexp" "testing" "time" ) func TestPrettySize(t *testing.T) { tests := []struct { input int64 expected string }{ {0, "0 bytes"}, {1, "1 byte"}, {2, "2 bytes"}, {1023, "1023 bytes"}, {1024, "1 KB"}, {1536, "1 KB"}, {2048, "2 KB"}, {1024 * 1024, "1 MB"}, {1024 * 1024 * 1024, "1 GB"}, {1024 * 1024 * 1024 * 1024, "1 TB"}, {1024 * 1024 * 1024 * 1024 * 1024, "1 PB"}, } for _, tt := range tests { result := PrettySize(tt.input) if result != tt.expected { t.Errorf("PrettySize(%d) = %s, want %s", tt.input, result, tt.expected) } } } func TestGetIconType(t *testing.T) { tests := []struct { filename string expected string }{ {"test.go", "go"}, {"test.py", "py"}, {"test.js", "js"}, {"test.html", "html"}, {"test.css", "css"}, {"test.json", "json"}, {"test.md", "md"}, {"test.pdf", "pdf"}, {"test.jpg", "image"}, {"test.png", "image"}, {"test.mp4", "video"}, {"test.mp3", "audio"}, {"test.zip", "archive"}, {"test.txt", "doc"}, {"README", "license"}, {"LICENSE", "license"}, {"unknown.ext", "generic"}, {"noext", "generic"}, } for _, tt := range tests { result := GetIconType(tt.filename) if result != tt.expected { t.Errorf("GetIconType(%s) = %s, want %s", tt.filename, result, tt.expected) } } } func TestGetIconTypeCaseInsensitive(t *testing.T) { tests := []struct { filename string expected string }{ {"test.GO", "go"}, {"test.Py", "py"}, {"test.JPG", "image"}, {"test.PNG", "image"}, {"test.MP4", "video"}, {"test.MP3", "audio"}, } for _, tt := range tests { result := GetIconType(tt.filename) if result != tt.expected { t.Errorf("GetIconType(%s) = %s, want %s", tt.filename, result, tt.expected) } } } func TestHTMLTemplate(t *testing.T) { tmpl := GetHTMLTemplate() if tmpl == nil { t.Fatal("GetHTMLTemplate() returned nil") } // Test template execution with sample data data := struct { DirName string Entries []FileEntry DirAppend bool OutputFile string IsRoot bool WatermarkURL string }{ DirName: "test-dir", Entries: []FileEntry{}, DirAppend: false, OutputFile: "index.html", IsRoot: false, WatermarkURL: "", } var buf bytes.Buffer err := tmpl.Execute(&buf, data) if err != nil { t.Fatalf("Template execution failed: %v", err) } output := buf.String() if !bytes.Contains([]byte(output), []byte("test-dir")) { t.Error("Template output should contain directory name") } if !bytes.Contains([]byte(output), []byte("")) { t.Error("Template output should contain HTML doctype") } } func TestHTMLTemplateWithEntries(t *testing.T) { tmpl := GetHTMLTemplate() entries := []FileEntry{ { Name: "test.go", Path: "test.go", IsDir: false, IsSymlink: false, Size: 1024, ModTime: time.Now(), IconType: "go", CSSClass: "", SizePretty: "1 KB", ModTimeISO: "2023-01-01T12:00:00Z", ModTimeHuman: "01 Jan 23 12:00 UTC", }, { Name: "subfolder", Path: "subfolder/", IsDir: true, IsSymlink: false, Size: -1, ModTime: time.Now(), IconType: "folder", CSSClass: "folder_filled", SizePretty: "—", ModTimeISO: "2023-01-01T12:00:00Z", ModTimeHuman: "01 Jan 23 12:00 UTC", }, } data := struct { DirName string Entries []FileEntry DirAppend bool OutputFile string IsRoot bool WatermarkURL string }{ DirName: "test-dir", Entries: entries, DirAppend: false, OutputFile: "index.html", IsRoot: false, WatermarkURL: "", } var buf bytes.Buffer err := tmpl.Execute(&buf, data) if err != nil { t.Fatalf("Template execution with entries failed: %v", err) } output := buf.String() if !bytes.Contains([]byte(output), []byte("test.go")) { t.Error("Template output should contain file name") } if !bytes.Contains([]byte(output), []byte("subfolder")) { t.Error("Template output should contain folder name") } if !bytes.Contains([]byte(output), []byte("#go")) { t.Error("Template output should contain Go icon reference") } if !bytes.Contains([]byte(output), []byte("#folder")) { t.Error("Template output should contain folder icon reference") } } func TestHTMLTemplateWithWatermark(t *testing.T) { tmpl := GetHTMLTemplate() if tmpl == nil { t.Fatal("GetHTMLTemplate() returned nil") } // Test template execution with watermark data := struct { DirName string Entries []FileEntry DirAppend bool OutputFile string IsRoot bool WatermarkURL string }{ DirName: "test-dir", Entries: []FileEntry{}, DirAppend: false, OutputFile: "index.html", IsRoot: false, WatermarkURL: "https://example.com/logo.svg", } var buf bytes.Buffer err := tmpl.Execute(&buf, data) if err != nil { t.Fatalf("Template execution with watermark failed: %v", err) } output := buf.String() // Check that watermark image is included if !bytes.Contains([]byte(output), []byte(`src="https://example.com/logo.svg"`)) { t.Error("Template output should contain watermark image URL") } if !bytes.Contains([]byte(output), []byte(`class="watermark"`)) { t.Error("Template output should contain watermark CSS class") } // Test without watermark data.WatermarkURL = "" buf.Reset() err = tmpl.Execute(&buf, data) if err != nil { t.Fatalf("Template execution without watermark failed: %v", err) } outputNoWatermark := buf.String() // Check that watermark image is NOT included when URL is empty if bytes.Contains([]byte(outputNoWatermark), []byte(`class="watermark"`)) { t.Error("Template output should not contain watermark when URL is empty") } } func TestReadDirEntries(t *testing.T) { // Create a temporary directory with test files tempDir := t.TempDir() // Create test files testFiles := []string{"test.go", "test.py", "README.md", ".hidden"} for _, file := range testFiles { f, err := os.Create(filepath.Join(tempDir, file)) if err != nil { t.Fatalf("Failed to create test file %s: %v", file, err) } _, err = f.WriteString("test content") if err != nil { t.Fatalf("Failed to write to file: %v", err) } f.Close() } // Create a subdirectory subDir := filepath.Join(tempDir, "subdir") err := os.Mkdir(subDir, 0755) if err != nil { t.Fatalf("Failed to create subdirectory: %v", err) } opts := &Options{ OutputFile: "index.html", IncludeHidden: false, Verbose: false, } entries, err := ReadDirEntries(tempDir, opts) if err != nil { t.Fatalf("ReadDirEntries failed: %v", err) } // Should have 4 entries (3 visible files + 1 directory), .hidden should be excluded expectedCount := 4 if len(entries) != expectedCount { t.Errorf("Expected %d entries, got %d", expectedCount, len(entries)) } // Check that we have the expected files (ReadDirEntries doesn't sort, ProcessDir does) foundDir := false for _, entry := range entries { if entry.IsDir && entry.Name == "subdir" { foundDir = true break } } if !foundDir { t.Error("Expected to find subdirectory 'subdir'") } // Check that hidden file is excluded for _, entry := range entries { if entry.Name == ".hidden" { t.Error("Hidden file should be excluded when IncludeHidden is false") } } } func TestReadDirEntriesWithHidden(t *testing.T) { tempDir := t.TempDir() // Create test files including hidden testFiles := []string{"test.go", ".hidden"} for _, file := range testFiles { f, err := os.Create(filepath.Join(tempDir, file)) if err != nil { t.Fatalf("Failed to create test file %s: %v", file, err) } f.Close() } opts := &Options{ OutputFile: "index.html", IncludeHidden: true, Verbose: false, } entries, err := ReadDirEntries(tempDir, opts) if err != nil { t.Fatalf("ReadDirEntries failed: %v", err) } // Should include hidden file found := false for _, entry := range entries { if entry.Name == ".hidden" { found = true break } } if !found { t.Error("Hidden file should be included when IncludeHidden is true") } } func TestReadDirEntriesWithRegexExclusion(t *testing.T) { tempDir := t.TempDir() // Create test files testFiles := []string{"test.go", "test.py", "build.log", "node_modules.txt"} for _, file := range testFiles { f, err := os.Create(filepath.Join(tempDir, file)) if err != nil { t.Fatalf("Failed to create test file %s: %v", file, err) } f.Close() } regex := regexp.MustCompile("(build|node_modules)") opts := &Options{ OutputFile: "index.html", IncludeHidden: false, ExcludeRegex: regex, Verbose: false, } entries, err := ReadDirEntries(tempDir, opts) if err != nil { t.Fatalf("ReadDirEntries failed: %v", err) } // Check that excluded files are not present for _, entry := range entries { if entry.Name == "build.log" || entry.Name == "node_modules.txt" { t.Errorf("File %s should be excluded by regex", entry.Name) } } // Should have 2 entries (test.go, test.py) if len(entries) != 2 { t.Errorf("Expected 2 entries after regex exclusion, got %d", len(entries)) } } func TestFileEntryProperties(t *testing.T) { tempDir := t.TempDir() // Create a test file with known content testFile := filepath.Join(tempDir, "test.go") content := "package main\nfunc main() {}\n" err := os.WriteFile(testFile, []byte(content), 0644) if err != nil { t.Fatalf("Failed to create test file: %v", err) } opts := &Options{ OutputFile: "index.html", IncludeHidden: false, Verbose: false, } entries, err := ReadDirEntries(tempDir, opts) if err != nil { t.Fatalf("ReadDirEntries failed: %v", err) } if len(entries) != 1 { t.Fatalf("Expected 1 entry, got %d", len(entries)) } entry := entries[0] // Verify properties if entry.Name != "test.go" { t.Errorf("Expected name 'test.go', got '%s'", entry.Name) } if entry.IsDir { t.Error("Expected file to not be a directory") } if entry.IsSymlink { t.Error("Expected file to not be a symlink") } if entry.IconType != "go" { t.Errorf("Expected icon type 'go', got '%s'", entry.IconType) } if entry.Size != int64(len(content)) { t.Errorf("Expected size %d, got %d", len(content), entry.Size) } if entry.SizePretty != PrettySize(int64(len(content))) { t.Errorf("Size pretty mismatch") } }