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