github.com/xhghs/rclone@v1.51.1-0.20200430155106-e186a28cced8/vfs/vfs_case_test.go (about)

     1  package vfs
     2  
     3  import (
     4  	"context"
     5  	"os"
     6  	"testing"
     7  
     8  	"github.com/rclone/rclone/fstest"
     9  	"github.com/stretchr/testify/assert"
    10  	"github.com/stretchr/testify/require"
    11  )
    12  
    13  func TestCaseSensitivity(t *testing.T) {
    14  	r := fstest.NewRun(t)
    15  	defer r.Finalise()
    16  
    17  	if r.Fremote.Features().CaseInsensitive {
    18  		t.Skip("Can't test case sensitivity - this remote is officially not case-sensitive")
    19  	}
    20  
    21  	// Create test files
    22  	ctx := context.Background()
    23  	file1 := r.WriteObject(ctx, "FiLeA", "data1", t1)
    24  	file2 := r.WriteObject(ctx, "FiLeB", "data2", t2)
    25  	fstest.CheckItems(t, r.Fremote, file1, file2)
    26  
    27  	// Create file3 with name differing from file2 name only by case.
    28  	// On a case-Sensitive remote this will be a separate file.
    29  	// On a case-INsensitive remote this file will either not exist
    30  	// or overwrite file2 depending on how file system diverges.
    31  	// On a box.com remote this step will even fail.
    32  	file3 := r.WriteObject(ctx, "FilEb", "data3", t3)
    33  
    34  	// Create a case-Sensitive and case-INsensitive VFS
    35  	optCS := DefaultOpt
    36  	optCS.CaseInsensitive = false
    37  	vfsCS := New(r.Fremote, &optCS)
    38  
    39  	optCI := DefaultOpt
    40  	optCI.CaseInsensitive = true
    41  	vfsCI := New(r.Fremote, &optCI)
    42  
    43  	// Run basic checks that must pass on VFS of any type.
    44  	assertFileDataVFS(t, vfsCI, "FiLeA", "data1")
    45  	assertFileDataVFS(t, vfsCS, "FiLeA", "data1")
    46  
    47  	// Detect case sensitivity of the underlying remote.
    48  	remoteIsOK := true
    49  	if !checkFileDataVFS(t, vfsCS, "FiLeA", "data1") {
    50  		remoteIsOK = false
    51  	}
    52  	if !checkFileDataVFS(t, vfsCS, "FiLeB", "data2") {
    53  		remoteIsOK = false
    54  	}
    55  	if !checkFileDataVFS(t, vfsCS, "FilEb", "data3") {
    56  		remoteIsOK = false
    57  	}
    58  
    59  	// The remaining test is only meaningful on a case-Sensitive file system.
    60  	if !remoteIsOK {
    61  		t.Skip("Can't test case sensitivity - this remote doesn't comply as case-sensitive")
    62  	}
    63  
    64  	// Continue with test as the underlying remote is fully case-Sensitive.
    65  	fstest.CheckItems(t, r.Fremote, file1, file2, file3)
    66  
    67  	// See how VFS handles case-INsensitive flag
    68  	assertFileDataVFS(t, vfsCI, "FiLeA", "data1")
    69  	assertFileDataVFS(t, vfsCI, "fileA", "data1")
    70  	assertFileDataVFS(t, vfsCI, "filea", "data1")
    71  	assertFileDataVFS(t, vfsCI, "FILEA", "data1")
    72  
    73  	assertFileDataVFS(t, vfsCI, "FiLeB", "data2")
    74  	assertFileDataVFS(t, vfsCI, "FilEb", "data3")
    75  
    76  	fd, err := vfsCI.OpenFile("fileb", os.O_RDONLY, 0777)
    77  	assert.Nil(t, fd)
    78  	assert.Error(t, err)
    79  	assert.NotEqual(t, err, ENOENT)
    80  
    81  	fd, err = vfsCI.OpenFile("FILEB", os.O_RDONLY, 0777)
    82  	assert.Nil(t, fd)
    83  	assert.Error(t, err)
    84  	assert.NotEqual(t, err, ENOENT)
    85  
    86  	// Run the same set of checks with case-Sensitive VFS, for comparison.
    87  	assertFileDataVFS(t, vfsCS, "FiLeA", "data1")
    88  
    89  	assertFileAbsentVFS(t, vfsCS, "fileA")
    90  	assertFileAbsentVFS(t, vfsCS, "filea")
    91  	assertFileAbsentVFS(t, vfsCS, "FILEA")
    92  
    93  	assertFileDataVFS(t, vfsCS, "FiLeB", "data2")
    94  	assertFileDataVFS(t, vfsCS, "FilEb", "data3")
    95  
    96  	assertFileAbsentVFS(t, vfsCS, "fileb")
    97  	assertFileAbsentVFS(t, vfsCS, "FILEB")
    98  }
    99  
   100  func checkFileDataVFS(t *testing.T, vfs *VFS, name string, expect string) bool {
   101  	fd, err := vfs.OpenFile(name, os.O_RDONLY, 0777)
   102  	if fd == nil || err != nil {
   103  		return false
   104  	}
   105  	defer func() {
   106  		// File must be closed - otherwise Run.cleanUp() will fail on Windows.
   107  		_ = fd.Close()
   108  	}()
   109  
   110  	fh, ok := fd.(*ReadFileHandle)
   111  	if !ok {
   112  		return false
   113  	}
   114  
   115  	size := len(expect)
   116  	buf := make([]byte, size)
   117  	num, err := fh.Read(buf)
   118  	if err != nil || num != size {
   119  		return false
   120  	}
   121  
   122  	return string(buf) == expect
   123  }
   124  
   125  func assertFileDataVFS(t *testing.T, vfs *VFS, name string, expect string) {
   126  	fd, errOpen := vfs.OpenFile(name, os.O_RDONLY, 0777)
   127  	assert.NotNil(t, fd)
   128  	assert.NoError(t, errOpen)
   129  
   130  	defer func() {
   131  		// File must be closed - otherwise Run.cleanUp() will fail on Windows.
   132  		if errOpen == nil && fd != nil {
   133  			_ = fd.Close()
   134  		}
   135  	}()
   136  
   137  	fh, ok := fd.(*ReadFileHandle)
   138  	require.True(t, ok)
   139  
   140  	size := len(expect)
   141  	buf := make([]byte, size)
   142  	numRead, errRead := fh.Read(buf)
   143  	assert.NoError(t, errRead)
   144  	assert.Equal(t, numRead, size)
   145  
   146  	assert.Equal(t, string(buf), expect)
   147  }
   148  
   149  func assertFileAbsentVFS(t *testing.T, vfs *VFS, name string) {
   150  	fd, err := vfs.OpenFile(name, os.O_RDONLY, 0777)
   151  	defer func() {
   152  		// File must be closed - otherwise Run.cleanUp() will fail on Windows.
   153  		if err == nil && fd != nil {
   154  			_ = fd.Close()
   155  		}
   156  	}()
   157  	assert.Nil(t, fd)
   158  	assert.Error(t, err)
   159  	assert.Equal(t, err, ENOENT)
   160  }