github.com/treeverse/lakefs@v1.24.1-0.20240520134607-95648127bfb0/pkg/fileutil/fs_case_test.go (about) 1 package fileutil_test 2 3 import ( 4 "errors" 5 "os" 6 "strings" 7 "testing" 8 9 "github.com/treeverse/lakefs/pkg/fileutil" 10 ) 11 12 func fatal(t testing.TB) func(string) { 13 return func(message string) { 14 t.Fatal(message) 15 } 16 } 17 18 type nothing struct{} 19 20 type PathSet map[string]nothing 21 22 // PathMapFS fakes a fileutil.FS that maps all pathnames through a mapping. 23 type PathMapFS struct { 24 PathMapper func(string) string 25 Paths PathSet 26 27 // If non-nil, return this error for any operation on a path that 28 // starts with ErrorPathPrefix. 29 Err error 30 // Prefix to use for reporting Err. 31 ErrorPathPrefix string 32 } 33 34 func (f *PathMapFS) Touch(path string) error { 35 path = f.PathMapper(path) 36 if f.Err != nil && strings.HasPrefix(path, f.ErrorPathPrefix) { 37 return f.Err 38 } 39 40 if _, ok := f.Paths[path]; ok { 41 return os.ErrExist 42 } 43 f.Paths[path] = nothing{} 44 return nil 45 } 46 47 func (f *PathMapFS) Exists(path string) (bool, error) { 48 path = f.PathMapper(path) 49 if f.Err != nil && strings.HasPrefix(path, f.ErrorPathPrefix) { 50 return false, f.Err 51 } 52 53 _, ok := f.Paths[path] 54 return ok, nil 55 } 56 57 func (f *PathMapFS) Remove(path string) error { 58 path = f.PathMapper(path) 59 if f.Err != nil && strings.HasPrefix(path, f.ErrorPathPrefix) { 60 return f.Err 61 } 62 63 if _, ok := f.Paths[path]; ok { 64 delete(f.Paths, path) 65 return nil 66 } 67 return os.ErrNotExist 68 } 69 70 // CaseSensitiveFS fakes a case-sensitive fileutil.FS, that returns errors 71 // for some paths. 72 func CaseSensitiveFS() *PathMapFS { 73 return &PathMapFS{ 74 PathMapper: func(p string) string { return p }, 75 Paths: make(PathSet), 76 } 77 } 78 79 // CaseInsensitiveFS fakes a case-sensitive fileutil.FS. 80 func CaseInsensitiveFS() *PathMapFS { 81 return &PathMapFS{ 82 PathMapper: func(p string) string { return strings.ToLower(p) }, 83 Paths: make(PathSet), 84 } 85 } 86 87 func TestIsCaseInsensitiveLocationFalse(t *testing.T) { 88 fs := CaseSensitiveFS() 89 90 insensitive, err := fileutil.IsCaseInsensitiveLocation(fs, "/home/me/dir", fatal(t)) 91 if insensitive { 92 t.Error("Expected case-sensitive FS to be reported as such") 93 } 94 if err != nil { 95 t.Errorf("Failed to test case-sensitive FS: %s", err) 96 } 97 } 98 99 func TestIsCaseInsensitiveLocationTrue(t *testing.T) { 100 fs := CaseInsensitiveFS() 101 102 insensitive, err := fileutil.IsCaseInsensitiveLocation(fs, "/home/me/dir", fatal(t)) 103 if !insensitive { 104 t.Error("Expected case-insensitive FS to be reported as such") 105 } 106 if err != nil { 107 t.Errorf("Failed to test case-sensitive FS: %s", err) 108 } 109 } 110 111 func TestIsCaseInsensitiveLocationError(t *testing.T) { 112 testingErr := errors.New("for testing") 113 114 fs := CaseSensitiveFS() 115 fs.Err = testingErr 116 fs.ErrorPathPrefix = "/home/me/err/" 117 118 _, err := fileutil.IsCaseInsensitiveLocation(fs, "/home/me/err/", fatal(t)) 119 if !errors.Is(err, testingErr) { 120 t.Errorf("Got error %s when expecting %s", err, testingErr) 121 } 122 } 123 124 // TestOSIsCaseInsensitiveLocation tests that IsCaseInsensitiveLocation 125 // works on the OS. It cannot test the result, as it does not know what to 126 // expect. 127 func TestOSIsCaseInsensitiveLocation(t *testing.T) { 128 fs := fileutil.NewOSFS() 129 tempDir := t.TempDir() 130 isCaseInsensitive, err := fileutil.IsCaseInsensitiveLocation(fs, tempDir, fatal(t)) 131 132 if err != nil { 133 t.Errorf("IsCaseInsensitiveLocation failed: %s", err) 134 } 135 136 if isCaseInsensitive { 137 t.Logf("Case-insensitive directory: %s", tempDir) 138 } else { 139 t.Logf("Case-sensitive directory: %s", tempDir) 140 } 141 }