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  }