package utils import ( "os" "path/filepath" "runtime" "strings" "testing" ) func TestSafeJoin(t *testing.T) { tests := []struct { name string base string elements []string want string }{ { name: "basic join", base: "data", elements: []string{"events", "test-event"}, want: filepath.Join("data", "events", "test-event"), }, { name: "empty elements", base: "data", elements: []string{}, want: "data", }, { name: "with path separators", base: "data/events", elements: []string{"test-event", "1080p"}, want: filepath.Join("data", "events", "test-event", "1080p"), }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { got := SafeJoin(tt.base, tt.elements...) if got != tt.want { t.Errorf("SafeJoin() = %v, want %v", got, tt.want) } }) } } func TestEnsureDir(t *testing.T) { tempDir, err := os.MkdirTemp("", "utils_test_*") if err != nil { t.Fatalf("Failed to create temp dir: %v", err) } defer os.RemoveAll(tempDir) testPath := filepath.Join(tempDir, "test", "nested", "directory") // Test creating nested directories err = EnsureDir(testPath) if err != nil { t.Errorf("EnsureDir() failed: %v", err) } // Verify directory was created if _, err := os.Stat(testPath); os.IsNotExist(err) { t.Errorf("Directory was not created: %s", testPath) } // Test with existing directory (should not fail) err = EnsureDir(testPath) if err != nil { t.Errorf("EnsureDir() failed on existing directory: %v", err) } } func TestPathExists(t *testing.T) { tempDir, err := os.MkdirTemp("", "utils_test_*") if err != nil { t.Fatalf("Failed to create temp dir: %v", err) } defer os.RemoveAll(tempDir) // Test existing path if !PathExists(tempDir) { t.Errorf("PathExists() should return true for existing path: %s", tempDir) } // Test non-existing path nonExistentPath := filepath.Join(tempDir, "does-not-exist") if PathExists(nonExistentPath) { t.Errorf("PathExists() should return false for non-existent path: %s", nonExistentPath) } // Test with file testFile := filepath.Join(tempDir, "test.txt") f, err := os.Create(testFile) if err != nil { t.Fatalf("Failed to create test file: %v", err) } f.Close() if !PathExists(testFile) { t.Errorf("PathExists() should return true for existing file: %s", testFile) } } func TestIsValidPath(t *testing.T) { tests := []struct { name string path string want bool }{ {"empty path", "", false}, {"valid path", "data/events/test", true}, {"path with colon", "data:events", false}, {"path with pipe", "data|events", false}, {"path with question mark", "data?events", false}, {"path with asterisk", "data*events", false}, {"path with quotes", "data\"events", false}, {"path with angle brackets", "data", false}, {"normal windows path", "C:\\data\\events", true}, // Windows path separators are actually OK {"unix path", "/home/user/data", true}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { got := IsValidPath(tt.path) if got != tt.want { t.Errorf("IsValidPath(%q) = %v, want %v", tt.path, got, tt.want) } }) } } func TestNormalizePath(t *testing.T) { tests := []struct { name string path string want string }{ { name: "windows backslashes", path: "data\\events\\test", want: filepath.Join("data", "events", "test"), }, { name: "unix forward slashes", path: "data/events/test", want: filepath.Join("data", "events", "test"), }, { name: "mixed slashes", path: "data\\events/test\\file", want: filepath.Join("data", "events", "test", "file"), }, { name: "redundant separators", path: "data//events\\\\test", want: filepath.Join("data", "events", "test"), }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { got := NormalizePath(tt.path) if got != tt.want { t.Errorf("NormalizePath(%q) = %q, want %q", tt.path, got, tt.want) } }) } } func TestGetRelativePath(t *testing.T) { tempDir, err := os.MkdirTemp("", "utils_test_*") if err != nil { t.Fatalf("Failed to create temp dir: %v", err) } defer os.RemoveAll(tempDir) basePath := tempDir targetPath := filepath.Join(tempDir, "subdir", "file.txt") rel, err := GetRelativePath(basePath, targetPath) if err != nil { t.Errorf("GetRelativePath() failed: %v", err) } expected := filepath.Join("subdir", "file.txt") if rel != expected { t.Errorf("GetRelativePath() = %q, want %q", rel, expected) } // Test with invalid paths _, err = GetRelativePath("", "") if err == nil { t.Error("GetRelativePath() should fail with empty paths") } } func TestValidateWritablePath(t *testing.T) { tempDir, err := os.MkdirTemp("", "utils_test_*") if err != nil { t.Fatalf("Failed to create temp dir: %v", err) } defer os.RemoveAll(tempDir) // Test writable path writablePath := filepath.Join(tempDir, "test", "file.txt") err = ValidateWritablePath(writablePath) if err != nil { t.Errorf("ValidateWritablePath() failed for writable path: %v", err) } // Verify directory was created dir := filepath.Dir(writablePath) if _, err := os.Stat(dir); os.IsNotExist(err) { t.Errorf("Directory should have been created: %s", dir) } // Test with read-only directory (if supported by OS) if runtime.GOOS != "windows" { // Skip on Windows as it's more complex readOnlyDir := filepath.Join(tempDir, "readonly") os.MkdirAll(readOnlyDir, 0755) os.Chmod(readOnlyDir, 0444) // Read-only defer os.Chmod(readOnlyDir, 0755) // Restore permissions for cleanup readOnlyPath := filepath.Join(readOnlyDir, "file.txt") err = ValidateWritablePath(readOnlyPath) if err == nil { t.Error("ValidateWritablePath() should fail for read-only directory") } if !strings.Contains(err.Error(), "not writable") { t.Errorf("Expected 'not writable' error, got: %v", err) } } }