github.com/avfs/avfs@v0.33.1-0.20240303173310-c6ba67c33eb7/test/test_file.go (about)

     1  //
     2  //  Copyright 2021 The AVFS authors
     3  //
     4  //  Licensed under the Apache License, Version 2.0 (the "License");
     5  //  you may not use this file except in compliance with the License.
     6  //  You may obtain a copy of the License at
     7  //
     8  //  	http://www.apache.org/licenses/LICENSE-2.0
     9  //
    10  //  Unless required by applicable law or agreed to in writing, software
    11  //  distributed under the License is distributed on an "AS IS" BASIS,
    12  //  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  //  See the License for the specific language governing permissions and
    14  //  limitations under the License.
    15  //
    16  
    17  package test
    18  
    19  import (
    20  	"bytes"
    21  	"io"
    22  	"io/fs"
    23  	"os"
    24  	"reflect"
    25  	"testing"
    26  	"time"
    27  
    28  	"github.com/avfs/avfs"
    29  )
    30  
    31  func (ts *Suite) TestFile(t *testing.T) {
    32  	ts.RunTests(t, UsrTest,
    33  		ts.TestFileChdir,
    34  		ts.TestFileCloseWrite,
    35  		ts.TestFileCloseRead,
    36  		ts.TestFileFd,
    37  		ts.TestFileName,
    38  		ts.TestFileRead,
    39  		ts.TestFileReadAt,
    40  		ts.TestFileReadDir,
    41  		ts.TestFileReaddirnames,
    42  		ts.TestFileSeek,
    43  		ts.TestFileStat,
    44  		ts.TestFileSync,
    45  		ts.TestFileTruncate,
    46  		ts.TestFileWrite,
    47  		ts.TestFileWriteAt,
    48  		ts.TestFileWriteString,
    49  		ts.TestFileWriteTime)
    50  
    51  	// Tests to be run as root
    52  	adminUser := ts.idm.AdminUser()
    53  	ts.RunTests(t, adminUser.Name(),
    54  		ts.TestFileChmod,
    55  		ts.TestFileChown,
    56  	)
    57  }
    58  
    59  // TestFileChdir tests File.Chdir function.
    60  func (ts *Suite) TestFileChdir(t *testing.T, testDir string) {
    61  	dirs := ts.createSampleDirs(t, testDir)
    62  	vfs := ts.vfsTest
    63  
    64  	t.Run("FileChdir", func(t *testing.T) {
    65  		for _, dir := range dirs {
    66  			f, err := vfs.OpenFile(dir.Path, os.O_RDONLY, 0)
    67  			RequireNoError(t, err, "OpenFile %s", dir.Path)
    68  
    69  			defer f.Close()
    70  
    71  			err = f.Chdir()
    72  			AssertNoError(t, err, "Chdir %s", dir.Path)
    73  
    74  			curDir, err := vfs.Getwd()
    75  			AssertNoError(t, err, "Getwd %s", dir.Path)
    76  
    77  			if curDir != dir.Path {
    78  				t.Errorf("Getwd : want current directory to be %s, got %s", dir.Path, curDir)
    79  			}
    80  		}
    81  	})
    82  
    83  	t.Run("FileChdirOnFile", func(t *testing.T) {
    84  		f, fileName := ts.openedEmptyFile(t, testDir)
    85  
    86  		defer f.Close()
    87  
    88  		err := f.Chdir()
    89  		AssertPathError(t, err).Op("chdir").Path(fileName).
    90  			OSType(avfs.OsLinux).Err(avfs.ErrNotADirectory).Test().
    91  			OSType(avfs.OsWindows).Err(avfs.ErrWinDirNameInvalid).Test()
    92  	})
    93  
    94  	t.Run("FileChdirClosed", func(t *testing.T) {
    95  		f, fileName := ts.closedFile(t, testDir)
    96  
    97  		err := f.Chdir()
    98  		AssertPathError(t, err).Op("chdir").Path(fileName).Err(fs.ErrClosed).Test()
    99  	})
   100  
   101  	t.Run("FileChdirNonExisting", func(t *testing.T) {
   102  		f := ts.openedNonExistingFile(t, testDir)
   103  
   104  		err := f.Chdir()
   105  		AssertInvalid(t, err, "Chdir")
   106  	})
   107  }
   108  
   109  // TestFileChmod tests File.Chmod function.
   110  func (ts *Suite) TestFileChmod(t *testing.T, testDir string) {
   111  	vfs := ts.vfsTest
   112  
   113  	if vfs.HasFeature(avfs.FeatReadOnly) {
   114  		f, fileName := ts.openedEmptyFile(t, testDir)
   115  
   116  		defer f.Close()
   117  
   118  		err := f.Chmod(0)
   119  		AssertPathError(t, err).Op("chmod").Path(fileName).ErrPermDenied().Test()
   120  
   121  		return
   122  	}
   123  
   124  	t.Run("FileChmodClosed", func(t *testing.T) {
   125  		f, fileName := ts.closedFile(t, testDir)
   126  
   127  		err := f.Chmod(avfs.DefaultFilePerm)
   128  		AssertPathError(t, err).Op("chmod").Path(fileName).Err(fs.ErrClosed).Test()
   129  	})
   130  
   131  	t.Run("FileChmodNonExisting", func(t *testing.T) {
   132  		f := ts.openedNonExistingFile(t, testDir)
   133  
   134  		err := f.Chmod(0)
   135  		AssertInvalid(t, err, "Chmod")
   136  	})
   137  }
   138  
   139  // TestFileChown tests File.Chown function.
   140  func (ts *Suite) TestFileChown(t *testing.T, testDir string) {
   141  	vfs := ts.vfsTest
   142  
   143  	if vfs.HasFeature(avfs.FeatReadOnly) {
   144  		f, fileName := ts.openedEmptyFile(t, testDir)
   145  
   146  		defer f.Close()
   147  
   148  		err := f.Chown(0, 0)
   149  		AssertPathError(t, err).Op("chown").Path(fileName).ErrPermDenied().Test()
   150  
   151  		return
   152  	}
   153  
   154  	t.Run("FileChown", func(t *testing.T) {
   155  		f, _ := ts.openedEmptyFile(t, testDir)
   156  
   157  		defer f.Close()
   158  
   159  		u := vfs.User()
   160  		uid, gid := u.Uid(), u.Gid()
   161  
   162  		err := f.Chown(uid, gid)
   163  
   164  		AssertPathError(t, err).Op("chown").
   165  			OSType(avfs.OsLinux).NoError().Test().
   166  			OSType(avfs.OsWindows).Path(f.Name()).Err(avfs.ErrWinNotSupported).Test()
   167  	})
   168  
   169  	t.Run("FileChownClosed", func(t *testing.T) {
   170  		f, fileName := ts.closedFile(t, testDir)
   171  
   172  		err := f.Chown(0, 0)
   173  		AssertPathError(t, err).Op("chown").Path(fileName).Err(fs.ErrClosed).Test()
   174  	})
   175  
   176  	t.Run("FileChownNonExisting", func(t *testing.T) {
   177  		f := ts.openedNonExistingFile(t, testDir)
   178  
   179  		err := f.Chown(0, 0)
   180  		AssertInvalid(t, err, "Chown")
   181  	})
   182  }
   183  
   184  // TestFileCloseRead tests File.Close function for read only files.
   185  func (ts *Suite) TestFileCloseRead(t *testing.T, testDir string) {
   186  	data := []byte("AAABBBCCCDDD")
   187  	path := ts.existingFile(t, testDir, data)
   188  	vfs := ts.vfsTest
   189  
   190  	t.Run("FileCloseReadOnly", func(t *testing.T) {
   191  		openInfo, err := vfs.Stat(path)
   192  		RequireNoError(t, err, "Stat %s", path)
   193  
   194  		f, err := vfs.OpenFile(path, os.O_RDONLY, 0)
   195  		RequireNoError(t, err, "OpenFile %s", path)
   196  
   197  		err = f.Close()
   198  		RequireNoError(t, err, "Close %s", path)
   199  
   200  		closeInfo, err := vfs.Stat(path)
   201  		RequireNoError(t, err, "Stat %s", path)
   202  
   203  		if !reflect.DeepEqual(openInfo, closeInfo) {
   204  			t.Errorf("Stat %s : open info != close info\n%v\n%v", path, openInfo, closeInfo)
   205  		}
   206  
   207  		err = f.Close()
   208  		AssertPathError(t, err).Op("close").Path(path).Err(fs.ErrClosed).Test()
   209  	})
   210  
   211  	t.Run("FileCloseNonExisting", func(t *testing.T) {
   212  		f := ts.openedNonExistingFile(t, testDir)
   213  
   214  		err := f.Close()
   215  		AssertInvalid(t, err, "Close")
   216  	})
   217  }
   218  
   219  // TestFileCloseWrite tests File.Close function for read/write files.
   220  func (ts *Suite) TestFileCloseWrite(t *testing.T, testDir string) {
   221  	vfs := ts.vfsTest
   222  	if vfs.HasFeature(avfs.FeatReadOnly) {
   223  		return
   224  	}
   225  
   226  	data := []byte("AAABBBCCCDDD")
   227  	path := ts.existingFile(t, testDir, data)
   228  
   229  	openInfo, err := vfs.Stat(path)
   230  	RequireNoError(t, err, "Stat %s", path)
   231  
   232  	t.Run("FileCloseWrite", func(t *testing.T) {
   233  		f, err := vfs.OpenFile(path, os.O_APPEND|os.O_WRONLY, avfs.DefaultFilePerm)
   234  		RequireNoError(t, err, "OpenFile %s", path)
   235  
   236  		n, err := f.Write(data)
   237  		RequireNoError(t, err, "Write %s", path)
   238  
   239  		if n != len(data) {
   240  			t.Fatalf("Write : want bytes written to be %d, got %d", len(data), n)
   241  		}
   242  
   243  		err = f.Close()
   244  		RequireNoError(t, err, "Close %s", path)
   245  
   246  		closeInfo, err := vfs.Stat(path)
   247  		RequireNoError(t, err, "Stat %s", path)
   248  
   249  		if reflect.DeepEqual(openInfo, closeInfo) {
   250  			t.Errorf("Stat %s : open info != close info\n%v\n%v", path, openInfo, closeInfo)
   251  		}
   252  
   253  		err = f.Close()
   254  		AssertPathError(t, err).Op("close").Path(path).Err(fs.ErrClosed).Test()
   255  	})
   256  }
   257  
   258  // TestFileFd tests File.Fd function.
   259  func (ts *Suite) TestFileFd(t *testing.T, testDir string) {
   260  	f, fileName := ts.closedFile(t, testDir)
   261  
   262  	fd := f.Fd()
   263  	if fd != ^(uintptr(0)) {
   264  		t.Errorf("Fd %s : want Fd to be %d, got %d", fileName, ^(uintptr(0)), fd)
   265  	}
   266  }
   267  
   268  // TestFileName tests File.Name function.
   269  func (ts *Suite) TestFileName(t *testing.T, testDir string) {
   270  	f, wantName := ts.closedFile(t, testDir)
   271  
   272  	name := f.Name()
   273  	if name != wantName {
   274  		t.Errorf("Name %s : want Name to be %s, got %s", wantName, wantName, name)
   275  	}
   276  }
   277  
   278  // FileNilPtr test calls to File methods when f is a nil File.
   279  func FileNilPtr(t *testing.T, f avfs.File) {
   280  	err := f.Chdir()
   281  	AssertInvalid(t, err, "Chdir")
   282  
   283  	err = f.Chmod(0)
   284  	AssertInvalid(t, err, "Chmod")
   285  
   286  	err = f.Chown(0, 0)
   287  	AssertInvalid(t, err, "Chown")
   288  
   289  	err = f.Close()
   290  	AssertInvalid(t, err, "Close")
   291  
   292  	AssertPanic(t, "f.Name()", func() { _ = f.Name() })
   293  
   294  	fd := f.Fd()
   295  	if fd != ^(uintptr(0)) {
   296  		t.Errorf("Fd : want fd to be %d, got %d", 0, fd)
   297  	}
   298  
   299  	_, err = f.Read([]byte{})
   300  	AssertInvalid(t, err, "Read")
   301  
   302  	_, err = f.ReadAt([]byte{}, 0)
   303  	AssertInvalid(t, err, "ReadAt")
   304  
   305  	_, err = f.ReadDir(0)
   306  	AssertInvalid(t, err, "ReadDir")
   307  
   308  	_, err = f.Readdirnames(0)
   309  	AssertInvalid(t, err, "Readdirnames")
   310  
   311  	_, err = f.Seek(0, io.SeekStart)
   312  	AssertInvalid(t, err, "Seek")
   313  
   314  	_, err = f.Stat()
   315  	AssertInvalid(t, err, "Stat")
   316  
   317  	err = f.Sync()
   318  	AssertInvalid(t, err, "Sync")
   319  
   320  	err = f.Truncate(0)
   321  	AssertInvalid(t, err, "Truncate")
   322  
   323  	_, err = f.Write([]byte{})
   324  	AssertInvalid(t, err, "Write")
   325  
   326  	_, err = f.WriteAt([]byte{}, 0)
   327  	AssertInvalid(t, err, "WriteAt")
   328  
   329  	_, err = f.WriteString("")
   330  	AssertInvalid(t, err, "WriteString")
   331  }
   332  
   333  // TestFileRead tests File.Read function.
   334  func (ts *Suite) TestFileRead(t *testing.T, testDir string) {
   335  	data := []byte("AAABBBCCCDDD")
   336  	path := ts.existingFile(t, testDir, data)
   337  	vfs := ts.vfsTest
   338  
   339  	t.Run("FileRead", func(t *testing.T) {
   340  		const bufSize = 5
   341  
   342  		f, err := vfs.OpenFile(path, os.O_RDONLY, avfs.DefaultFilePerm)
   343  		RequireNoError(t, err, "OpenFile %s", path)
   344  
   345  		defer f.Close()
   346  
   347  		buf := make([]byte, bufSize)
   348  
   349  		for i := 0; ; i += bufSize {
   350  			n, err1 := f.Read(buf)
   351  			if err1 != nil {
   352  				if err1 == io.EOF {
   353  					break
   354  				}
   355  
   356  				t.Errorf("Read : want error to be %v, got %v", io.EOF, err1)
   357  			}
   358  
   359  			if !bytes.Equal(buf[:n], data[i:i+n]) {
   360  				t.Errorf("Read : want content to be %s, got %s", buf[:n], data[i:i+n])
   361  			}
   362  		}
   363  	})
   364  
   365  	t.Run("FileReadNonExisting", func(t *testing.T) {
   366  		f := ts.openedNonExistingFile(t, testDir)
   367  		buf := make([]byte, 0)
   368  
   369  		_, err := f.Read(buf)
   370  		AssertInvalid(t, err, "Read")
   371  	})
   372  
   373  	t.Run("FileReadOnDir", func(t *testing.T) {
   374  		f, err := vfs.OpenFile(testDir, os.O_RDONLY, 0)
   375  		RequireNoError(t, err, "OpenFile %s", testDir)
   376  
   377  		defer f.Close()
   378  
   379  		b := make([]byte, 1)
   380  
   381  		_, err = f.Read(b)
   382  		AssertPathError(t, err).Op("read").Path(testDir).
   383  			OSType(avfs.OsLinux).Err(avfs.ErrIsADirectory).Test().
   384  			OSType(avfs.OsWindows).Err(avfs.ErrWinIncorrectFunc).Test()
   385  	})
   386  
   387  	t.Run("FileReadClosed", func(t *testing.T) {
   388  		f, fileName := ts.closedFile(t, testDir)
   389  
   390  		b := make([]byte, 1)
   391  
   392  		_, err := f.Read(b)
   393  		AssertPathError(t, err).Op("read").Path(fileName).Err(fs.ErrClosed).Test()
   394  	})
   395  }
   396  
   397  // TestFileReadAt tests File.ReadAt function.
   398  func (ts *Suite) TestFileReadAt(t *testing.T, testDir string) {
   399  	data := []byte("AAABBBCCCDDD")
   400  	path := ts.existingFile(t, testDir, data)
   401  	vfs := ts.vfsTest
   402  
   403  	t.Run("FileReadAt", func(t *testing.T) {
   404  		const bufSize = 3
   405  
   406  		f, err := vfs.OpenFile(path, os.O_RDONLY, avfs.DefaultFilePerm)
   407  		RequireNoError(t, err, "OpenFile %s", path)
   408  
   409  		defer f.Close()
   410  
   411  		var n int
   412  
   413  		rb := make([]byte, bufSize)
   414  		for i := len(data); i > 0; i -= bufSize {
   415  			n, err = f.ReadAt(rb, int64(i-bufSize))
   416  			RequireNoError(t, err, "ReadAt %s", path)
   417  
   418  			if n != bufSize {
   419  				t.Errorf("ReadAt : want bytes read to be %d, got %d", bufSize, n)
   420  			}
   421  
   422  			if !bytes.Equal(rb, data[i-bufSize:i]) {
   423  				t.Errorf("ReadAt : want bytes read to be %d, got %d", bufSize, n)
   424  			}
   425  		}
   426  	})
   427  
   428  	t.Run("FileReadAtNonExisting", func(t *testing.T) {
   429  		f := ts.openedNonExistingFile(t, testDir)
   430  		buf := make([]byte, 0)
   431  
   432  		_, err := f.ReadAt(buf, 0)
   433  		AssertInvalid(t, err, "ReadAt")
   434  	})
   435  
   436  	t.Run("FileReadAtAfterEndOfFile", func(t *testing.T) {
   437  		f, err := vfs.OpenFile(path, os.O_RDONLY, 0)
   438  		RequireNoError(t, err, "OpenFile %s", path)
   439  
   440  		defer f.Close()
   441  
   442  		b := make([]byte, 1)
   443  
   444  		off := int64(len(data) * 2)
   445  
   446  		n, err := f.ReadAt(b, off)
   447  		if err != io.EOF {
   448  			t.Errorf("ReadAt : want error to be %v, got %v", io.EOF, err)
   449  		}
   450  
   451  		if n != 0 {
   452  			t.Errorf("ReadAt : want bytes read to be 0, got %d", n)
   453  		}
   454  
   455  		n, err = f.ReadAt(b, -1)
   456  		AssertPathError(t, err).Op("readat").Path(path).Err(avfs.ErrNegativeOffset).Test()
   457  
   458  		if n != 0 {
   459  			t.Errorf("ReadAt : want bytes read to be 0, got %d", n)
   460  		}
   461  	})
   462  
   463  	t.Run("FileReadAtOnDir", func(t *testing.T) {
   464  		f, err := vfs.OpenFile(testDir, os.O_RDONLY, 0)
   465  		RequireNoError(t, err, "OpenFile %s", path)
   466  
   467  		defer f.Close()
   468  
   469  		b := make([]byte, 1)
   470  
   471  		_, err = f.ReadAt(b, 0)
   472  		AssertPathError(t, err).Op("read").Path(testDir).
   473  			OSType(avfs.OsLinux).Err(avfs.ErrIsADirectory).Test().
   474  			OSType(avfs.OsWindows).Err(avfs.ErrWinIncorrectFunc).Test()
   475  	})
   476  
   477  	t.Run("FileReadAtClosed", func(t *testing.T) {
   478  		f, fileName := ts.closedFile(t, testDir)
   479  
   480  		b := make([]byte, 1)
   481  
   482  		_, err := f.ReadAt(b, 0)
   483  		AssertPathError(t, err).Op("read").Path(fileName).Err(fs.ErrClosed).Test()
   484  	})
   485  }
   486  
   487  // TestFileReadDir tests File.ReadDir function.
   488  func (ts *Suite) TestFileReadDir(t *testing.T, testDir string) {
   489  	rndTree := ts.randomDir(t, testDir)
   490  	wantDirs := len(rndTree.Dirs())
   491  	wantFiles := len(rndTree.Files())
   492  	wantSymlinks := len(rndTree.SymLinks())
   493  	vfs := ts.vfsTest
   494  
   495  	const maxRead = 7
   496  
   497  	t.Run("FileReadDirN", func(t *testing.T) {
   498  		f, err := vfs.OpenFile(testDir, os.O_RDONLY, 0)
   499  		RequireNoError(t, err, "OpenFile %s", testDir)
   500  
   501  		defer f.Close()
   502  
   503  		var dirEntries []fs.DirEntry
   504  
   505  		for {
   506  			dirEntriesN, err := f.ReadDir(maxRead)
   507  			if err == io.EOF {
   508  				break
   509  			}
   510  
   511  			RequireNoError(t, err, "ReadDir %s", testDir)
   512  
   513  			dirEntries = append(dirEntries, dirEntriesN...)
   514  		}
   515  
   516  		var gotDirs, gotFiles, gotSymlinks int
   517  
   518  		for _, dirEntry := range dirEntries {
   519  			switch {
   520  			case dirEntry.IsDir():
   521  				gotDirs++
   522  			case dirEntry.Type()&fs.ModeSymlink != 0:
   523  				gotSymlinks++
   524  			default:
   525  				gotFiles++
   526  			}
   527  		}
   528  
   529  		if wantDirs != gotDirs {
   530  			t.Errorf("ReadDirN : want number of dirs to be %d, got %d", wantDirs, gotDirs)
   531  		}
   532  
   533  		if wantFiles != gotFiles {
   534  			t.Errorf("ReadDirN : want number of files to be %d, got %d", wantFiles, gotFiles)
   535  		}
   536  
   537  		if wantSymlinks != gotSymlinks {
   538  			t.Errorf("ReadDirN : want number of symbolic links to be %d, got %d", wantSymlinks, gotSymlinks)
   539  		}
   540  	})
   541  
   542  	t.Run("FileReadDirExistingFile", func(t *testing.T) {
   543  		f, fileName := ts.openedEmptyFile(t, testDir)
   544  
   545  		defer f.Close()
   546  
   547  		_, err := f.ReadDir(-1)
   548  		AssertPathError(t, err).Path(fileName).
   549  			OSType(avfs.OsLinux).Op("readdirent").Err(avfs.ErrNotADirectory).Test().
   550  			OSType(avfs.OsWindows).Op("readdir").Err(avfs.ErrWinPathNotFound).Test()
   551  	})
   552  
   553  	t.Run("FileReadDirClosed", func(t *testing.T) {
   554  		f, fileName := ts.closedFile(t, testDir)
   555  
   556  		_, err := f.ReadDir(-1)
   557  		AssertPathError(t, err).Path(fileName).
   558  			OSType(avfs.OsLinux).Op("readdirent").Err(avfs.ErrFileClosing).Test().
   559  			OSType(avfs.OsWindows).Op("readdir").Err(avfs.ErrWinInvalidHandle).Test()
   560  	})
   561  
   562  	t.Run("FileReadDirNonExisting", func(t *testing.T) {
   563  		f := ts.openedNonExistingFile(t, testDir)
   564  
   565  		_, err := f.ReadDir(-1)
   566  		AssertInvalid(t, err, "ReadDir")
   567  	})
   568  }
   569  
   570  // TestFileReaddirnames tests File.Readdirnames function.
   571  func (ts *Suite) TestFileReaddirnames(t *testing.T, testDir string) {
   572  	rndTree := ts.randomDir(t, testDir)
   573  	wantAll := len(rndTree.Dirs()) + len(rndTree.Files()) + len(rndTree.SymLinks())
   574  
   575  	vfs := ts.vfsTest
   576  	existingFile := vfs.Join(testDir, rndTree.Files()[0].Name)
   577  
   578  	t.Run("FileReaddirnamesAll", func(t *testing.T) {
   579  		f, err := vfs.OpenFile(testDir, os.O_RDONLY, 0)
   580  		RequireNoError(t, err, "OpenFile %s", testDir)
   581  
   582  		defer f.Close()
   583  
   584  		names, err := f.Readdirnames(-1)
   585  		RequireNoError(t, err, "Readdirnames %s", testDir)
   586  
   587  		if wantAll != len(names) {
   588  			t.Errorf("TestFileReaddirnames : want number of elements to be %d, got %d", wantAll, len(names))
   589  		}
   590  	})
   591  
   592  	t.Run("FileReaddirnamesN", func(t *testing.T) {
   593  		f, err := vfs.OpenFile(testDir, os.O_RDONLY, 0)
   594  		RequireNoError(t, err, "OpenFile %s", testDir)
   595  
   596  		defer f.Close()
   597  
   598  		var names []string
   599  
   600  		for {
   601  			namesN, err := f.Readdirnames(11)
   602  			if err == io.EOF {
   603  				break
   604  			}
   605  
   606  			RequireNoError(t, err, "ReadDirNamesN %s", testDir)
   607  
   608  			names = append(names, namesN...)
   609  		}
   610  
   611  		gotAll := len(names)
   612  		if len(names) != wantAll {
   613  			t.Errorf("ReadDirNamesN : want number of elements to be %d, got %d", wantAll, gotAll)
   614  		}
   615  	})
   616  
   617  	t.Run("FileReaddirnamesExistingFile", func(t *testing.T) {
   618  		f, err := vfs.OpenFile(existingFile, os.O_RDONLY, 0)
   619  		RequireNoError(t, err, "OpenFile %s", existingFile)
   620  
   621  		defer f.Close()
   622  
   623  		_, err = f.Readdirnames(-1)
   624  		AssertPathError(t, err).Path(f.Name()).
   625  			OSType(avfs.OsLinux).Op("readdirent").Err(avfs.ErrNotADirectory).Test().
   626  			OSType(avfs.OsWindows).Op("readdir").Err(avfs.ErrWinPathNotFound).Test()
   627  	})
   628  
   629  	t.Run("FileReaddirnamesClosed", func(t *testing.T) {
   630  		f, fileName := ts.closedFile(t, testDir)
   631  
   632  		_, err := f.Readdirnames(-1)
   633  		AssertPathError(t, err).Path(fileName).
   634  			OSType(avfs.OsLinux).Op("readdirent").Err(avfs.ErrFileClosing).Test().
   635  			OSType(avfs.OsWindows).Op("readdir").Err(avfs.ErrWinInvalidHandle).Test()
   636  	})
   637  
   638  	t.Run("FileReaddirnamesNonExisting", func(t *testing.T) {
   639  		f := ts.openedNonExistingFile(t, testDir)
   640  
   641  		_, err := f.Readdirnames(-1)
   642  		AssertInvalid(t, err, "Readdirnames")
   643  	})
   644  }
   645  
   646  // TestFileSeek tests File.Seek function.
   647  func (ts *Suite) TestFileSeek(t *testing.T, testDir string) {
   648  	data := []byte("AAABBBCCCDDD")
   649  	path := ts.existingFile(t, testDir, data)
   650  	vfs := ts.vfsTest
   651  
   652  	f, err := vfs.OpenFile(path, os.O_RDONLY, 0)
   653  	RequireNoError(t, err, "OpenFile %s", path)
   654  
   655  	defer f.Close()
   656  
   657  	pos := int64(0)
   658  	lenData := int64(len(data))
   659  
   660  	t.Run("TestFileSeek", func(t *testing.T) {
   661  		for i := 0; i < len(data); i++ {
   662  			pos, err = f.Seek(int64(i), io.SeekStart)
   663  			RequireNoError(t, err, "Seek %s", path)
   664  
   665  			if int(pos) != i {
   666  				t.Errorf("Seek : want position to be %d, got %d", i, pos)
   667  			}
   668  		}
   669  
   670  		for i := 0; i < len(data); i++ {
   671  			pos, err = f.Seek(-int64(i), io.SeekEnd)
   672  			RequireNoError(t, err, "Seek %s", path)
   673  
   674  			if int(pos) != len(data)-i {
   675  				t.Errorf("Seek : want position to be %d, got %d", i, pos)
   676  			}
   677  		}
   678  
   679  		_, err = f.Seek(0, io.SeekEnd)
   680  		RequireNoError(t, err, "Seek %s", path)
   681  
   682  		for i := len(data) - 1; i >= 0; i-- {
   683  			pos, err = f.Seek(-1, io.SeekCurrent)
   684  			RequireNoError(t, err, "Seek %s", path)
   685  
   686  			if int(pos) != i {
   687  				t.Errorf("Seek : want position to be %d, got %d", i, pos)
   688  			}
   689  		}
   690  	})
   691  
   692  	t.Run("FileSeekInvalidStart", func(t *testing.T) {
   693  		pos, err = f.Seek(-1, io.SeekStart)
   694  		AssertPathError(t, err).Op("seek").Path(f.Name()).
   695  			OSType(avfs.OsLinux).Err(avfs.ErrInvalidArgument).Test().
   696  			OSType(avfs.OsWindows).Err(avfs.ErrWinNegativeSeek).Test()
   697  
   698  		if pos != 0 {
   699  			t.Errorf("Seek : want pos to be %d, got %d", 0, pos)
   700  		}
   701  
   702  		wantPos := lenData * 2
   703  
   704  		pos, err = f.Seek(wantPos, io.SeekStart)
   705  		RequireNoError(t, err, "Seek %s", path)
   706  
   707  		if pos != wantPos {
   708  			t.Errorf("Seek : want pos to be %d, got %d", wantPos, pos)
   709  		}
   710  	})
   711  
   712  	t.Run("FileSeekInvalidEnd", func(t *testing.T) {
   713  		pos, err = f.Seek(1, io.SeekEnd)
   714  		RequireNoError(t, err, "Seek %s", path)
   715  
   716  		wantPos := lenData + 1
   717  		if pos != wantPos {
   718  			t.Errorf("Seek : want pos to be %d, got %d", wantPos, pos)
   719  		}
   720  
   721  		pos, err = f.Seek(-lenData*2, io.SeekEnd)
   722  		AssertPathError(t, err).Op("seek").Path(f.Name()).
   723  			OSType(avfs.OsLinux).Err(avfs.ErrInvalidArgument).Test().
   724  			OSType(avfs.OsWindows).Err(avfs.ErrWinNegativeSeek).Test()
   725  
   726  		if pos != 0 {
   727  			t.Errorf("Seek : want pos to be %d, got %d", 0, pos)
   728  		}
   729  	})
   730  
   731  	t.Run("FileSeekInvalidCur", func(t *testing.T) {
   732  		wantPos := lenData / 2
   733  
   734  		pos, err = f.Seek(wantPos, io.SeekStart)
   735  		if err != nil || pos != wantPos {
   736  			t.Fatalf("Seek : want  pos to be 0 and error to be nil, got %d, %v", pos, err)
   737  		}
   738  
   739  		pos, err = f.Seek(-lenData, io.SeekCurrent)
   740  		AssertPathError(t, err).Op("seek").Path(f.Name()).
   741  			OSType(avfs.OsLinux).Err(avfs.ErrInvalidArgument).Test().
   742  			OSType(avfs.OsWindows).Err(avfs.ErrWinNegativeSeek).Test()
   743  
   744  		if pos != 0 {
   745  			t.Errorf("Seek : want pos to be %d, got %d", 0, pos)
   746  		}
   747  
   748  		pos, err = f.Seek(lenData, io.SeekCurrent)
   749  		RequireNoError(t, err, "Seek %s", path)
   750  
   751  		if pos != lenData/2+lenData {
   752  			t.Errorf("Seek : want pos to be %d, got %d", wantPos, pos)
   753  		}
   754  	})
   755  
   756  	t.Run("FileSeekInvalidWhence", func(t *testing.T) {
   757  		pos, err = f.Seek(0, 10)
   758  
   759  		AssertPathError(t, err).Op("seek").Path(f.Name()).
   760  			OSType(avfs.OsLinux).Err(avfs.ErrInvalidArgument).Test().
   761  			OSType(avfs.OsWindows).NoError().Test()
   762  
   763  		if pos != 0 {
   764  			t.Errorf("Seek : want pos to be %d, got %d", 0, pos)
   765  		}
   766  	})
   767  
   768  	t.Run("FileSeekOnDir", func(t *testing.T) {
   769  		f, err = vfs.OpenFile(testDir, os.O_RDONLY, 0)
   770  		RequireNoError(t, err, "OpenFile %s", testDir)
   771  
   772  		defer f.Close()
   773  
   774  		_, err = f.Seek(0, io.SeekStart)
   775  		RequireNoError(t, err, "Seek %s", testDir)
   776  	})
   777  
   778  	t.Run("FileSeekClosed", func(t *testing.T) {
   779  		f, fileName := ts.closedFile(t, testDir)
   780  
   781  		_, err = f.Seek(0, io.SeekStart)
   782  		AssertPathError(t, err).Op("seek").Path(fileName).Err(fs.ErrClosed).Test()
   783  	})
   784  
   785  	t.Run("FileSeekNonExisting", func(t *testing.T) {
   786  		f := ts.openedNonExistingFile(t, testDir)
   787  
   788  		_, err = f.Seek(0, io.SeekStart)
   789  		AssertInvalid(t, err, "Seek")
   790  	})
   791  }
   792  
   793  // TestFileStat tests File.Stat function.
   794  func (ts *Suite) TestFileStat(t *testing.T, testDir string) {
   795  	dirs := ts.createSampleDirs(t, testDir)
   796  	files := ts.createSampleFiles(t, testDir)
   797  	_ = ts.createSampleSymlinks(t, testDir)
   798  	vfs := ts.vfsTest
   799  
   800  	t.Run("FileStatDir", func(t *testing.T) {
   801  		for _, dir := range dirs {
   802  			f, err := vfs.OpenFile(dir.Path, os.O_RDONLY, 0)
   803  			RequireNoError(t, err, "OpenFile %s", testDir)
   804  
   805  			info, err := f.Stat()
   806  			if !AssertNoError(t, err, "Stat %s", dir.Path) {
   807  				_ = f.Close()
   808  
   809  				continue
   810  			}
   811  
   812  			if vfs.Base(dir.Path) != info.Name() {
   813  				t.Errorf("Stat %s : want name to be %s, got %s", dir.Path, vfs.Base(dir.Path), info.Name())
   814  			}
   815  
   816  			wantMode := (dir.Mode | fs.ModeDir) &^ vfs.UMask()
   817  			if vfs.OSType() == avfs.OsWindows {
   818  				wantMode = fs.ModeDir | fs.ModePerm
   819  			}
   820  
   821  			if wantMode != info.Mode() {
   822  				t.Errorf("Stat %s : want mode to be %s, got %s", dir.Path, wantMode, info.Mode())
   823  			}
   824  
   825  			_ = f.Close()
   826  		}
   827  	})
   828  
   829  	t.Run("FileStatFile", func(t *testing.T) {
   830  		for _, file := range files {
   831  			f, err := vfs.OpenFile(file.Path, os.O_RDONLY, 0)
   832  			RequireNoError(t, err, "OpenFile %s", file.Path)
   833  
   834  			info, err := f.Stat()
   835  			if !AssertNoError(t, err, "Stat %s", file.Path) {
   836  				_ = f.Close()
   837  
   838  				continue
   839  			}
   840  
   841  			if info.Name() != vfs.Base(file.Path) {
   842  				t.Errorf("Stat %s : want name to be %s, got %s", file.Path, vfs.Base(file.Path), info.Name())
   843  			}
   844  
   845  			wantMode := file.Mode &^ vfs.UMask()
   846  			if vfs.OSType() == avfs.OsWindows {
   847  				wantMode = avfs.DefaultFilePerm
   848  			}
   849  
   850  			if wantMode != info.Mode() {
   851  				t.Errorf("Stat %s : want mode to be %s, got %s", file.Path, wantMode, info.Mode())
   852  			}
   853  
   854  			wantSize := int64(len(file.Content))
   855  			if wantSize != info.Size() {
   856  				t.Errorf("Lstat %s : want size to be %d, got %d", file.Path, wantSize, info.Size())
   857  			}
   858  
   859  			_ = f.Close()
   860  		}
   861  	})
   862  
   863  	t.Run("FileStatSymlink", func(t *testing.T) {
   864  		for _, sl := range ts.sampleSymlinksEval(testDir) {
   865  			f, err := vfs.OpenFile(sl.NewPath, os.O_RDONLY, 0)
   866  			RequireNoError(t, err, "OpenFile %s", sl.NewPath)
   867  
   868  			info, err := f.Stat()
   869  			if !AssertNoError(t, err, "Stat %s", sl.NewPath) {
   870  				_ = f.Close()
   871  
   872  				continue
   873  			}
   874  
   875  			wantName := vfs.Base(sl.OldPath)
   876  			if sl.IsSymlink {
   877  				wantName = vfs.Base(sl.NewPath)
   878  			}
   879  
   880  			wantMode := sl.Mode
   881  
   882  			if wantName != info.Name() {
   883  				t.Errorf("Stat %s : want name to be %s, got %s", sl.NewPath, wantName, info.Name())
   884  			}
   885  
   886  			if ts.canTestPerm && wantMode != info.Mode() {
   887  				t.Errorf("Stat %s : want mode to be %s, got %s", sl.NewPath, wantMode, info.Mode())
   888  			}
   889  
   890  			_ = f.Close()
   891  		}
   892  	})
   893  
   894  	t.Run("FileStatNonExistingFile", func(t *testing.T) {
   895  		f := ts.openedNonExistingFile(t, testDir)
   896  
   897  		_, err := f.Stat()
   898  		AssertInvalid(t, err, "Stat")
   899  	})
   900  
   901  	t.Run("FileStatSubDirOnFile", func(t *testing.T) {
   902  		path := vfs.Join(files[0].Path, defaultNonExisting)
   903  
   904  		f, err := vfs.OpenFile(path, os.O_RDONLY, 0)
   905  		AssertPathError(t, err).Op("open").Path(path).
   906  			OSType(avfs.OsLinux).Err(avfs.ErrNotADirectory).Test().
   907  			OSType(avfs.OsWindows).Err(avfs.ErrWinPathNotFound).Test()
   908  
   909  		_, err = f.Stat()
   910  		AssertInvalid(t, err, "Stat")
   911  	})
   912  
   913  	t.Run("FileStatClosed", func(t *testing.T) {
   914  		f, fileName := ts.closedFile(t, testDir)
   915  
   916  		_, err := f.Stat()
   917  		AssertPathError(t, err).Path(fileName).
   918  			OSType(avfs.OsLinux).Op("stat").Err(avfs.ErrFileClosing).Test().
   919  			OSType(avfs.OsWindows).Op("GetFileType").Err(avfs.ErrWinInvalidHandle).Test()
   920  	})
   921  
   922  	t.Run("FileStatNonExisting", func(t *testing.T) {
   923  		f := ts.openedNonExistingFile(t, testDir)
   924  
   925  		_, err := f.Stat()
   926  		AssertInvalid(t, err, "Stat")
   927  	})
   928  }
   929  
   930  // TestFileSync tests File.Sync function.
   931  func (ts *Suite) TestFileSync(t *testing.T, testDir string) {
   932  	vfs := ts.vfsTest
   933  
   934  	if vfs.HasFeature(avfs.FeatReadOnly) {
   935  		f := ts.openedNonExistingFile(t, testDir)
   936  
   937  		err := f.Sync()
   938  		AssertPathError(t, err).Op("sync").Path(avfs.NotImplemented).ErrPermDenied().Test()
   939  
   940  		return
   941  	}
   942  
   943  	t.Run("FileSyncClosed", func(t *testing.T) {
   944  		f, fileName := ts.closedFile(t, testDir)
   945  
   946  		err := f.Sync()
   947  		AssertPathError(t, err).Op("sync").Path(fileName).Err(fs.ErrClosed).Test()
   948  	})
   949  
   950  	t.Run("FileSyncNonExisting", func(t *testing.T) {
   951  		f := ts.openedNonExistingFile(t, testDir)
   952  
   953  		err := f.Sync()
   954  		AssertInvalid(t, err, "Sync")
   955  	})
   956  }
   957  
   958  // TestFileTruncate tests File.Truncate function.
   959  func (ts *Suite) TestFileTruncate(t *testing.T, testDir string) {
   960  	vfs := ts.vfsTest
   961  
   962  	if vfs.HasFeature(avfs.FeatReadOnly) {
   963  		f, fileName := ts.openedEmptyFile(t, testDir)
   964  
   965  		defer f.Close()
   966  
   967  		err := f.Truncate(0)
   968  		AssertPathError(t, err).Op("truncate").Path(fileName).ErrPermDenied().Test()
   969  
   970  		return
   971  	}
   972  
   973  	data := []byte("AAABBBCCCDDD")
   974  
   975  	t.Run("FileTruncate", func(t *testing.T) {
   976  		path := ts.existingFile(t, testDir, data)
   977  
   978  		f, err := vfs.OpenFile(path, os.O_RDWR, avfs.DefaultFilePerm)
   979  		RequireNoError(t, err, "OpenFile %s", path)
   980  
   981  		defer f.Close()
   982  
   983  		b := make([]byte, len(data))
   984  
   985  		for i := len(data) - 1; i >= 0; i-- {
   986  			err = f.Truncate(int64(i))
   987  			RequireNoError(t, err, "Truncate %s", path)
   988  
   989  			_, err = f.ReadAt(b, 0)
   990  			if err != io.EOF {
   991  				t.Errorf("Read : want error to be EOF, got %v", err)
   992  			}
   993  
   994  			if !bytes.Equal(data[:i], b[:i]) {
   995  				t.Errorf("Truncate : want data to be %s, got %s", data[:i], b[:i])
   996  			}
   997  		}
   998  	})
   999  
  1000  	t.Run("FileTruncateOnDir", func(t *testing.T) {
  1001  		f, err := vfs.OpenFile(testDir, os.O_RDONLY, 0)
  1002  		RequireNoError(t, err, "OpenFile %s", testDir)
  1003  
  1004  		defer f.Close()
  1005  
  1006  		err = f.Truncate(0)
  1007  		AssertPathError(t, err).Op("truncate").Path(testDir).
  1008  			OSType(avfs.OsLinux).Err(avfs.ErrInvalidArgument).Test().
  1009  			OSType(avfs.OsWindows).Err(avfs.ErrWinAccessDenied).Test()
  1010  	})
  1011  
  1012  	t.Run("FileTruncateSizeNegative", func(t *testing.T) {
  1013  		path := ts.existingFile(t, testDir, data)
  1014  
  1015  		f, err := vfs.OpenFile(path, os.O_RDWR, avfs.DefaultFilePerm)
  1016  		RequireNoError(t, err, "OpenFile %s", path)
  1017  
  1018  		defer f.Close()
  1019  
  1020  		err = f.Truncate(-1)
  1021  		AssertPathError(t, err).Op("truncate").Path(path).
  1022  			OSType(avfs.OsLinux).Err(avfs.ErrInvalidArgument).Test().
  1023  			OSType(avfs.OsWindows).Err(avfs.ErrWinNegativeSeek).Test()
  1024  	})
  1025  
  1026  	t.Run("FileTruncateSizeBiggerFileSize", func(t *testing.T) {
  1027  		path := ts.existingFile(t, testDir, data)
  1028  
  1029  		f, err := vfs.OpenFile(path, os.O_RDWR, avfs.DefaultFilePerm)
  1030  		RequireNoError(t, err, "OpenFile %s", path)
  1031  
  1032  		newSize := len(data) * 2
  1033  
  1034  		err = f.Truncate(int64(newSize))
  1035  		RequireNoError(t, err, "Truncate %s", path)
  1036  
  1037  		info, err := f.Stat()
  1038  		RequireNoError(t, err, "Stat %s", path)
  1039  
  1040  		if newSize != int(info.Size()) {
  1041  			t.Errorf("Stat : want size to be %d, got %d", newSize, info.Size())
  1042  		}
  1043  
  1044  		f.Close()
  1045  
  1046  		gotContent, err := vfs.ReadFile(path)
  1047  		RequireNoError(t, err, "ReadFile %s", path)
  1048  
  1049  		wantAdded := bytes.Repeat([]byte{0}, len(data))
  1050  		gotAdded := gotContent[len(data):]
  1051  
  1052  		if !bytes.Equal(wantAdded, gotAdded) {
  1053  			t.Errorf("Bytes Added : want %v, got %v", wantAdded, gotAdded)
  1054  		}
  1055  	})
  1056  
  1057  	t.Run("FileTruncateNonExistingFile", func(t *testing.T) {
  1058  		f := ts.openedNonExistingFile(t, testDir)
  1059  
  1060  		err := f.Truncate(0)
  1061  		AssertInvalid(t, err, "Truncate")
  1062  	})
  1063  
  1064  	t.Run("FileTruncateClosed", func(t *testing.T) {
  1065  		f, fileName := ts.closedFile(t, testDir)
  1066  
  1067  		err := f.Truncate(0)
  1068  		AssertPathError(t, err).Op("truncate").Path(fileName).Err(fs.ErrClosed).Test()
  1069  	})
  1070  }
  1071  
  1072  // TestFileWrite tests File.Write function.
  1073  func (ts *Suite) TestFileWrite(t *testing.T, testDir string) {
  1074  	vfs := ts.vfsTest
  1075  
  1076  	if vfs.HasFeature(avfs.FeatReadOnly) {
  1077  		f, fileName := ts.openedEmptyFile(t, testDir)
  1078  
  1079  		defer f.Close()
  1080  
  1081  		_, err := f.Write([]byte{})
  1082  		AssertPathError(t, err).Op("write").Path(fileName).ErrPermDenied().Test()
  1083  
  1084  		return
  1085  	}
  1086  
  1087  	data := []byte("AAABBBCCCDDD")
  1088  
  1089  	t.Run("FileWrite", func(t *testing.T) {
  1090  		path := vfs.Join(testDir, "TestFileWrite.txt")
  1091  
  1092  		f, err := vfs.Create(path)
  1093  		RequireNoError(t, err, "Create %s", path)
  1094  
  1095  		defer f.Close()
  1096  
  1097  		for i := 0; i < len(data); i += 3 {
  1098  			buf3 := data[i : i+3]
  1099  
  1100  			var n int
  1101  
  1102  			n, err = f.Write(buf3)
  1103  			RequireNoError(t, err, "Write %s", path)
  1104  
  1105  			if len(buf3) != n {
  1106  				t.Errorf("Write : want bytes written to be %d, got %d", len(buf3), n)
  1107  			}
  1108  		}
  1109  
  1110  		rb, err := vfs.ReadFile(path)
  1111  		RequireNoError(t, err, "ReadFile %s", path)
  1112  
  1113  		if !bytes.Equal(rb, data) {
  1114  			t.Errorf("ReadFile : want content to be %s, got %s", data, rb)
  1115  		}
  1116  	})
  1117  
  1118  	t.Run("FileWriteNonExisting", func(t *testing.T) {
  1119  		f := ts.openedNonExistingFile(t, testDir)
  1120  		buf := make([]byte, 0)
  1121  
  1122  		_, err := f.Write(buf)
  1123  		AssertInvalid(t, err, "Write")
  1124  	})
  1125  
  1126  	t.Run("FileWriteReadOnly", func(t *testing.T) {
  1127  		path := ts.existingFile(t, testDir, data)
  1128  
  1129  		f, err := vfs.OpenFile(path, os.O_RDONLY, 0)
  1130  		RequireNoError(t, err, "OpenFile %s", path)
  1131  
  1132  		defer f.Close()
  1133  
  1134  		b := make([]byte, len(data)*2)
  1135  		n, err := f.Write(b)
  1136  		AssertPathError(t, err).Op("write").Path(path).
  1137  			OSType(avfs.OsLinux).Err(avfs.ErrBadFileDesc).Test().
  1138  			OSType(avfs.OsWindows).Err(avfs.ErrWinAccessDenied).Test()
  1139  
  1140  		if n != 0 {
  1141  			t.Errorf("Write : want bytes written to be 0, got %d", n)
  1142  		}
  1143  
  1144  		n, err = f.Read(b)
  1145  		RequireNoError(t, err, "Read %s", path)
  1146  
  1147  		if !bytes.Equal(data, b[:n]) {
  1148  			t.Errorf("Read : want data to be %s, got %s", data, b[:n])
  1149  		}
  1150  	})
  1151  
  1152  	t.Run("FileWriteOnDir", func(t *testing.T) {
  1153  		f, err := vfs.OpenFile(testDir, os.O_RDONLY, 0)
  1154  		RequireNoError(t, err, "OpenFile %s", testDir)
  1155  
  1156  		defer f.Close()
  1157  
  1158  		b := make([]byte, 1)
  1159  
  1160  		_, err = f.Write(b)
  1161  		AssertPathError(t, err).Op("write").Path(testDir).
  1162  			OSType(avfs.OsLinux).Err(avfs.ErrBadFileDesc).Test().
  1163  			OSType(avfs.OsWindows).Err(avfs.ErrWinAccessDenied).Test()
  1164  	})
  1165  
  1166  	t.Run("FileWriteClosed", func(t *testing.T) {
  1167  		b := make([]byte, 1)
  1168  
  1169  		f, fileName := ts.closedFile(t, testDir)
  1170  		_, err := f.Write(b)
  1171  		AssertPathError(t, err).Op("write").Path(fileName).Err(fs.ErrClosed).Test()
  1172  	})
  1173  }
  1174  
  1175  // TestFileWriteAt tests File.WriteAt function.
  1176  func (ts *Suite) TestFileWriteAt(t *testing.T, testDir string) {
  1177  	vfs := ts.vfsTest
  1178  
  1179  	if vfs.HasFeature(avfs.FeatReadOnly) {
  1180  		f, fileName := ts.openedEmptyFile(t, testDir)
  1181  
  1182  		_, err := f.WriteAt([]byte{}, 0)
  1183  		AssertPathError(t, err).Op("write").Path(fileName).ErrPermDenied().Test()
  1184  
  1185  		return
  1186  	}
  1187  
  1188  	data := []byte("AAABBBCCCDDD")
  1189  
  1190  	t.Run("FileWriteAt", func(t *testing.T) {
  1191  		path := vfs.Join(testDir, "TestFileWriteAt.txt")
  1192  
  1193  		f, err := vfs.OpenFile(path, os.O_CREATE|os.O_RDWR, avfs.DefaultFilePerm)
  1194  		RequireNoError(t, err, "OpenFile %s", path)
  1195  
  1196  		defer f.Close()
  1197  
  1198  		for i := len(data); i > 0; i -= 3 {
  1199  			var n int
  1200  			n, err = f.WriteAt(data[i-3:i], int64(i-3))
  1201  			RequireNoError(t, err, "WriteAt %s", path)
  1202  
  1203  			if n != 3 {
  1204  				t.Errorf("WriteAt : want bytes written to be %d, got %d", 3, n)
  1205  			}
  1206  		}
  1207  
  1208  		err = f.Close()
  1209  		RequireNoError(t, err, "Close %s", path)
  1210  
  1211  		rb, err := vfs.ReadFile(path)
  1212  		RequireNoError(t, err, "ReadFile %s", path)
  1213  
  1214  		if !bytes.Equal(rb, data) {
  1215  			t.Errorf("ReadFile : want content to be %s, got %s", data, rb)
  1216  		}
  1217  	})
  1218  
  1219  	t.Run("FileWriteAtNonExisting", func(t *testing.T) {
  1220  		f := ts.openedNonExistingFile(t, testDir)
  1221  		buf := make([]byte, 0)
  1222  
  1223  		_, err := f.WriteAt(buf, 0)
  1224  		AssertInvalid(t, err, "WriteAt")
  1225  	})
  1226  
  1227  	t.Run("FileWriteAtNegativeOffset", func(t *testing.T) {
  1228  		path := ts.existingFile(t, testDir, data)
  1229  
  1230  		f, err := vfs.OpenFile(path, os.O_RDWR, avfs.DefaultDirPerm)
  1231  		RequireNoError(t, err, "OpenFile %s", path)
  1232  
  1233  		defer f.Close()
  1234  
  1235  		n, err := f.WriteAt(data, -1)
  1236  		AssertPathError(t, err).Op("writeat").Path(path).Err(avfs.ErrNegativeOffset).Test()
  1237  
  1238  		if n != 0 {
  1239  			t.Errorf("WriteAt : want bytes written to be 0, got %d", n)
  1240  		}
  1241  	})
  1242  
  1243  	t.Run("FileWriteAtAfterEndOfFile", func(t *testing.T) {
  1244  		path := ts.existingFile(t, testDir, data)
  1245  
  1246  		f, err := vfs.OpenFile(path, os.O_RDWR, avfs.DefaultFilePerm)
  1247  		RequireNoError(t, err, "OpenFile %s", path)
  1248  
  1249  		defer f.Close()
  1250  
  1251  		off := int64(len(data) * 3)
  1252  
  1253  		n, err := f.WriteAt(data, off)
  1254  		RequireNoError(t, err, "WriteAt %s", path)
  1255  
  1256  		if n != len(data) {
  1257  			t.Errorf("WriteAt : want bytes written to be %d, got %d", len(data), n)
  1258  		}
  1259  
  1260  		want := make([]byte, int(off)+len(data))
  1261  		_ = copy(want, data)
  1262  		_ = copy(want[off:], data)
  1263  
  1264  		got, err := vfs.ReadFile(path)
  1265  		RequireNoError(t, err, "ReadFile %s", path)
  1266  
  1267  		if !bytes.Equal(want, got) {
  1268  			t.Errorf("want : %s\ngot  : %s", want, got)
  1269  		}
  1270  	})
  1271  
  1272  	t.Run("FileWriteAtReadOnly", func(t *testing.T) {
  1273  		path := ts.existingFile(t, testDir, data)
  1274  
  1275  		f, err := vfs.OpenFile(path, os.O_RDONLY, 0)
  1276  		RequireNoError(t, err, "OpenFile %s", path)
  1277  
  1278  		defer f.Close()
  1279  
  1280  		b := make([]byte, len(data)*2)
  1281  
  1282  		n, err := f.WriteAt(b, 0)
  1283  		AssertPathError(t, err).Op("write").Path(path).
  1284  			OSType(avfs.OsLinux).Err(avfs.ErrBadFileDesc).Test().
  1285  			OSType(avfs.OsWindows).Err(avfs.ErrWinAccessDenied).Test()
  1286  
  1287  		if n != 0 {
  1288  			t.Errorf("WriteAt : want bytes read to be 0, got %d", n)
  1289  		}
  1290  
  1291  		n, err = f.ReadAt(b, 0)
  1292  		if err != io.EOF {
  1293  			t.Errorf("ReadAt : want error to be EOF, got %v", err)
  1294  		}
  1295  
  1296  		if !bytes.Equal(data, b[:n]) {
  1297  			t.Errorf("ReadAt : want data to be %s, got %s", data, b[:n])
  1298  		}
  1299  	})
  1300  
  1301  	t.Run("FileWriteAtOnDir", func(t *testing.T) {
  1302  		f, err := vfs.OpenFile(testDir, os.O_RDONLY, 0)
  1303  		RequireNoError(t, err, "OpenFile %s", testDir)
  1304  
  1305  		defer f.Close()
  1306  
  1307  		b := make([]byte, 1)
  1308  
  1309  		_, err = f.WriteAt(b, 0)
  1310  		AssertPathError(t, err).Op("write").Path(testDir).
  1311  			OSType(avfs.OsLinux).Err(avfs.ErrBadFileDesc).Test().
  1312  			OSType(avfs.OsWindows).Err(avfs.ErrWinAccessDenied).Test()
  1313  	})
  1314  
  1315  	t.Run("FileWriteAtClosed", func(t *testing.T) {
  1316  		b := make([]byte, 1)
  1317  
  1318  		f, fileName := ts.closedFile(t, testDir)
  1319  
  1320  		_, err := f.WriteAt(b, 0)
  1321  		AssertPathError(t, err).Op("write").Path(fileName).Err(fs.ErrClosed).Test()
  1322  	})
  1323  }
  1324  
  1325  // TestFileWriteString tests File.WriteString function.
  1326  func (ts *Suite) TestFileWriteString(t *testing.T, testDir string) {
  1327  	vfs := ts.vfsTest
  1328  
  1329  	if vfs.HasFeature(avfs.FeatReadOnly) {
  1330  		f := ts.openedNonExistingFile(t, testDir)
  1331  
  1332  		_, err := f.WriteString("")
  1333  		AssertPathError(t, err).Op("write").Path(f.Name()).ErrPermDenied().Test()
  1334  
  1335  		return
  1336  	}
  1337  
  1338  	t.Run("FileWriteNonExisting", func(t *testing.T) {
  1339  		f := ts.openedNonExistingFile(t, testDir)
  1340  
  1341  		_, err := f.WriteString("")
  1342  		AssertInvalid(t, err, "WriteString")
  1343  	})
  1344  }
  1345  
  1346  // TestFileWriteTime checks that modification time is updated on write operations.
  1347  func (ts *Suite) TestFileWriteTime(t *testing.T, testDir string) {
  1348  	vfs := ts.vfsTest
  1349  	if vfs.HasFeature(avfs.FeatReadOnly) {
  1350  		return
  1351  	}
  1352  
  1353  	var previous time.Time
  1354  
  1355  	f, fileName := ts.openedEmptyFile(t, testDir)
  1356  
  1357  	// CompareTime tests if the modification time of the file has changed.
  1358  	compareTime := func(mustChange bool) {
  1359  		time.Sleep(10 * time.Millisecond)
  1360  
  1361  		info, err := vfs.Stat(fileName)
  1362  		RequireNoError(t, err, "Stat %s", fileName)
  1363  
  1364  		// Don't compare for the first time.
  1365  		if previous.IsZero() {
  1366  			previous = info.ModTime()
  1367  
  1368  			return
  1369  		}
  1370  
  1371  		current := info.ModTime()
  1372  		if mustChange && !current.After(previous) {
  1373  			t.Errorf("CompareTime : want previous < current time\ngot prev = %v, curr = %v", previous, current)
  1374  		}
  1375  
  1376  		if !mustChange && !current.Equal(previous) {
  1377  			t.Errorf("CompareTime : want previous = current time\ngot prev = %v, curr = %v", previous, current)
  1378  		}
  1379  
  1380  		previous = current
  1381  	}
  1382  
  1383  	compareTime(true)
  1384  
  1385  	data := []byte("AAABBBCCCDDD")
  1386  
  1387  	t.Run("TimeWrite", func(t *testing.T) {
  1388  		_, err := f.Write(data)
  1389  		RequireNoError(t, err, "Write")
  1390  
  1391  		compareTime(true)
  1392  	})
  1393  
  1394  	t.Run("TimeWriteAt", func(t *testing.T) {
  1395  		_, err := f.WriteAt(data, 5)
  1396  		RequireNoError(t, err, "WriteAt")
  1397  
  1398  		compareTime(true)
  1399  	})
  1400  
  1401  	t.Run("TimeTruncate", func(t *testing.T) {
  1402  		err := f.Truncate(5)
  1403  		RequireNoError(t, err, "Truncate")
  1404  
  1405  		compareTime(true)
  1406  	})
  1407  
  1408  	t.Run("TimeClose", func(t *testing.T) {
  1409  		err := f.Close()
  1410  		RequireNoError(t, err, "Close")
  1411  
  1412  		compareTime(false)
  1413  	})
  1414  }