package security import ( "path/filepath" "runtime" "testing" ) func TestPathValidator_ValidatePath(t *testing.T) { t.Parallel() cases := []struct { name string path string strict bool wantError bool }{ { name: "valid relative path", path: "usr/bin/test", strict: true, wantError: false, }, { name: "path traversal attempt", path: "../../../etc/passwd", strict: true, wantError: true, }, { name: "absolute path in strict mode", path: "/usr/bin/test", strict: true, wantError: true, }, { name: "absolute path in non-strict mode", path: "/usr/bin/test", strict: false, wantError: false, }, { name: "suspicious characters", path: "test$HOME", strict: true, wantError: true, }, { name: "hidden file with dots only", path: "...", strict: true, wantError: true, }, { name: "valid hidden file", path: ".config", strict: true, wantError: false, }, } for _, tc := range cases { t.Run(tc.name, func(t *testing.T) { validator := NewPathValidator(nil, tc.strict) err := validator.ValidatePath(tc.path) gotError := err != nil if gotError != tc.wantError { t.Errorf("ValidatePath(%q) error = %v, wantError %v", tc.path, err, tc.wantError) } }) } } func TestPathValidator_SanitizePath(t *testing.T) { t.Parallel() cases := []struct { name string input string expected string }{ { name: "normal path", input: "usr/bin/test", expected: "usr/bin/test", }, { name: "path with null bytes", input: "test\x00file", expected: "testfile", }, { name: "path with forward slashes", input: "usr/bin/test", expected: joinOSPath("usr", "bin", "test"), }, { name: "path with consecutive separators", input: "usr//bin///test", expected: joinOSPath("usr", "bin", "test"), }, { name: "path with . and ..", input: "usr/./bin/../test", expected: joinOSPath("usr", "test"), }, } for _, tc := range cases { t.Run(tc.name, func(t *testing.T) { validator := NewPathValidator(nil, true) result := validator.SanitizePath(tc.input) if result != tc.expected { t.Errorf("SanitizePath(%q) = %q, expected %q", tc.input, result, tc.expected) } }) } } func TestPathValidator_ValidateFileName(t *testing.T) { t.Parallel() cases := []struct { name string filename string wantError bool }{ { name: "valid filename", filename: "test.txt", wantError: false, }, { name: "empty filename", filename: "", wantError: true, }, { name: "filename too long", filename: string(make([]byte, 256)), wantError: true, }, { name: "filename with trailing whitespace", filename: "test ", wantError: true, }, } // Add platform-specific tests if runtime.GOOS == "windows" { cases = append(cases, []struct { name string filename string wantError bool }{ { name: "windows reserved name", filename: "CON", wantError: true, }, { name: "windows invalid characters", filename: "test