github.com/gozelle/afero@v0.0.0-20230510083704-09e2ff18f19e/memmap_test.go (about)

     1  package afero
     2  
     3  import (
     4  	"fmt"
     5  	"io"
     6  	"io/fs"
     7  	"os"
     8  	"path/filepath"
     9  	"runtime"
    10  	"strings"
    11  	"sync"
    12  	"testing"
    13  	"time"
    14  )
    15  
    16  func TestNormalizePath(t *testing.T) {
    17  	type test struct {
    18  		input    string
    19  		expected string
    20  	}
    21  
    22  	data := []test{
    23  		{".", FilePathSeparator},
    24  		{"./", FilePathSeparator},
    25  		{"..", FilePathSeparator},
    26  		{"../", FilePathSeparator},
    27  		{"./..", FilePathSeparator},
    28  		{"./../", FilePathSeparator},
    29  	}
    30  
    31  	for i, d := range data {
    32  		cpath := normalizePath(d.input)
    33  		if d.expected != cpath {
    34  			t.Errorf("Test %d failed. Expected %q got %q", i, d.expected, cpath)
    35  		}
    36  	}
    37  }
    38  
    39  func TestPathErrors(t *testing.T) {
    40  	path := filepath.Join(".", "some", "path")
    41  	path2 := filepath.Join(".", "different", "path")
    42  	fs := NewMemMapFs()
    43  	perm := os.FileMode(0o755)
    44  	uid := 1000
    45  	gid := 1000
    46  
    47  	// relevant functions:
    48  	// func (m *MemMapFs) Chmod(name string, mode os.FileMode) error
    49  	// func (m *MemMapFs) Chtimes(name string, atime time.Time, mtime time.Time) error
    50  	// func (m *MemMapFs) Create(name string) (File, error)
    51  	// func (m *MemMapFs) Mkdir(name string, perm os.FileMode) error
    52  	// func (m *MemMapFs) MkdirAll(path string, perm os.FileMode) error
    53  	// func (m *MemMapFs) Open(name string) (File, error)
    54  	// func (m *MemMapFs) OpenFile(name string, flag int, perm os.FileMode) (File, error)
    55  	// func (m *MemMapFs) Remove(name string) error
    56  	// func (m *MemMapFs) Rename(oldname, newname string) error
    57  	// func (m *MemMapFs) Stat(name string) (os.FileInfo, error)
    58  
    59  	err := fs.Chmod(path, perm)
    60  	checkPathError(t, err, "Chmod")
    61  
    62  	err = fs.Chown(path, uid, gid)
    63  	checkPathError(t, err, "Chown")
    64  
    65  	err = fs.Chtimes(path, time.Now(), time.Now())
    66  	checkPathError(t, err, "Chtimes")
    67  
    68  	// fs.Create doesn't return an error
    69  
    70  	err = fs.Mkdir(path2, perm)
    71  	if err != nil {
    72  		t.Error(err)
    73  	}
    74  	err = fs.Mkdir(path2, perm)
    75  	checkPathError(t, err, "Mkdir")
    76  
    77  	err = fs.MkdirAll(path2, perm)
    78  	if err != nil {
    79  		t.Error("MkdirAll:", err)
    80  	}
    81  
    82  	_, err = fs.Open(path)
    83  	checkPathError(t, err, "Open")
    84  
    85  	_, err = fs.OpenFile(path, os.O_RDWR, perm)
    86  	checkPathError(t, err, "OpenFile")
    87  
    88  	err = fs.Remove(path)
    89  	checkPathError(t, err, "Remove")
    90  
    91  	err = fs.RemoveAll(path)
    92  	if err != nil {
    93  		t.Error("RemoveAll:", err)
    94  	}
    95  
    96  	err = fs.Rename(path, path2)
    97  	checkPathError(t, err, "Rename")
    98  
    99  	_, err = fs.Stat(path)
   100  	checkPathError(t, err, "Stat")
   101  }
   102  
   103  func checkPathError(t *testing.T, err error, op string) {
   104  	pathErr, ok := err.(*os.PathError)
   105  	if !ok {
   106  		t.Error(op+":", err, "is not a os.PathError")
   107  		return
   108  	}
   109  	_, ok = pathErr.Err.(*os.PathError)
   110  	if ok {
   111  		t.Error(op+":", err, "contains another os.PathError")
   112  	}
   113  }
   114  
   115  // Ensure os.O_EXCL is correctly handled.
   116  func TestOpenFileExcl(t *testing.T) {
   117  	const fileName = "/myFileTest"
   118  	const fileMode = os.FileMode(0o765)
   119  
   120  	fs := NewMemMapFs()
   121  
   122  	// First creation should succeed.
   123  	f, err := fs.OpenFile(fileName, os.O_CREATE|os.O_EXCL, fileMode)
   124  	if err != nil {
   125  		t.Errorf("OpenFile Create Excl failed: %s", err)
   126  		return
   127  	}
   128  	f.Close()
   129  
   130  	// Second creation should fail.
   131  	_, err = fs.OpenFile(fileName, os.O_CREATE|os.O_EXCL, fileMode)
   132  	if err == nil {
   133  		t.Errorf("OpenFile Create Excl should have failed, but it didn't")
   134  	}
   135  	checkPathError(t, err, "Open")
   136  }
   137  
   138  // Ensure Permissions are set on OpenFile/Mkdir/MkdirAll
   139  func TestPermSet(t *testing.T) {
   140  	const fileName = "/myFileTest"
   141  	const dirPath = "/myDirTest"
   142  	const dirPathAll = "/my/path/to/dir"
   143  
   144  	const fileMode = os.FileMode(0o765)
   145  	// directories will also have the directory bit set
   146  	const dirMode = fileMode | os.ModeDir
   147  
   148  	fs := NewMemMapFs()
   149  
   150  	// Test Openfile
   151  	f, err := fs.OpenFile(fileName, os.O_CREATE, fileMode)
   152  	if err != nil {
   153  		t.Errorf("OpenFile Create failed: %s", err)
   154  		return
   155  	}
   156  	f.Close()
   157  
   158  	s, err := fs.Stat(fileName)
   159  	if err != nil {
   160  		t.Errorf("Stat failed: %s", err)
   161  		return
   162  	}
   163  	if s.Mode().String() != fileMode.String() {
   164  		t.Errorf("Permissions Incorrect: %s != %s", s.Mode().String(), fileMode.String())
   165  		return
   166  	}
   167  
   168  	// Test Mkdir
   169  	err = fs.Mkdir(dirPath, dirMode)
   170  	if err != nil {
   171  		t.Errorf("MkDir Create failed: %s", err)
   172  		return
   173  	}
   174  	s, err = fs.Stat(dirPath)
   175  	if err != nil {
   176  		t.Errorf("Stat failed: %s", err)
   177  		return
   178  	}
   179  	// sets File
   180  	if s.Mode().String() != dirMode.String() {
   181  		t.Errorf("Permissions Incorrect: %s != %s", s.Mode().String(), dirMode.String())
   182  		return
   183  	}
   184  
   185  	// Test MkdirAll
   186  	err = fs.MkdirAll(dirPathAll, dirMode)
   187  	if err != nil {
   188  		t.Errorf("MkDir Create failed: %s", err)
   189  		return
   190  	}
   191  	s, err = fs.Stat(dirPathAll)
   192  	if err != nil {
   193  		t.Errorf("Stat failed: %s", err)
   194  		return
   195  	}
   196  	if s.Mode().String() != dirMode.String() {
   197  		t.Errorf("Permissions Incorrect: %s != %s", s.Mode().String(), dirMode.String())
   198  		return
   199  	}
   200  }
   201  
   202  // Fails if multiple file objects use the same file.at counter in MemMapFs
   203  func TestMultipleOpenFiles(t *testing.T) {
   204  	defer removeAllTestFiles(t)
   205  	const fileName = "afero-demo2.txt"
   206  
   207  	data := make([][]byte, len(Fss))
   208  
   209  	for i, fs := range Fss {
   210  		dir := testDir(fs)
   211  		path := filepath.Join(dir, fileName)
   212  		fh1, err := fs.Create(path)
   213  		if err != nil {
   214  			t.Error("fs.Create failed: " + err.Error())
   215  		}
   216  		_, err = fh1.Write([]byte("test"))
   217  		if err != nil {
   218  			t.Error("fh.Write failed: " + err.Error())
   219  		}
   220  		_, err = fh1.Seek(0, io.SeekStart)
   221  		if err != nil {
   222  			t.Error(err)
   223  		}
   224  
   225  		fh2, err := fs.OpenFile(path, os.O_RDWR, 0o777)
   226  		if err != nil {
   227  			t.Error("fs.OpenFile failed: " + err.Error())
   228  		}
   229  		_, err = fh2.Seek(0, io.SeekEnd)
   230  		if err != nil {
   231  			t.Error(err)
   232  		}
   233  		_, err = fh2.Write([]byte("data"))
   234  		if err != nil {
   235  			t.Error(err)
   236  		}
   237  		err = fh2.Close()
   238  		if err != nil {
   239  			t.Error(err)
   240  		}
   241  
   242  		_, err = fh1.Write([]byte("data"))
   243  		if err != nil {
   244  			t.Error(err)
   245  		}
   246  		err = fh1.Close()
   247  		if err != nil {
   248  			t.Error(err)
   249  		}
   250  		// the file now should contain "datadata"
   251  		data[i], err = ReadFile(fs, path)
   252  		if err != nil {
   253  			t.Error(err)
   254  		}
   255  	}
   256  
   257  	for i, fs := range Fss {
   258  		if i == 0 {
   259  			continue
   260  		}
   261  		if string(data[0]) != string(data[i]) {
   262  			t.Errorf("%s and %s don't behave the same\n"+
   263  				"%s: \"%s\"\n%s: \"%s\"\n",
   264  				Fss[0].Name(), fs.Name(), Fss[0].Name(), data[0], fs.Name(), data[i])
   265  		}
   266  	}
   267  }
   268  
   269  // Test if file.Write() fails when opened as read only
   270  func TestReadOnly(t *testing.T) {
   271  	defer removeAllTestFiles(t)
   272  	const fileName = "afero-demo.txt"
   273  
   274  	for _, fs := range Fss {
   275  		dir := testDir(fs)
   276  		path := filepath.Join(dir, fileName)
   277  
   278  		f, err := fs.Create(path)
   279  		if err != nil {
   280  			t.Error(fs.Name()+":", "fs.Create failed: "+err.Error())
   281  		}
   282  		_, err = f.Write([]byte("test"))
   283  		if err != nil {
   284  			t.Error(fs.Name()+":", "Write failed: "+err.Error())
   285  		}
   286  		f.Close()
   287  
   288  		f, err = fs.Open(path)
   289  		if err != nil {
   290  			t.Error("fs.Open failed: " + err.Error())
   291  		}
   292  		_, err = f.Write([]byte("data"))
   293  		if err == nil {
   294  			t.Error(fs.Name()+":", "No write error")
   295  		}
   296  		f.Close()
   297  
   298  		f, err = fs.OpenFile(path, os.O_RDONLY, 0o644)
   299  		if err != nil {
   300  			t.Error("fs.Open failed: " + err.Error())
   301  		}
   302  		_, err = f.Write([]byte("data"))
   303  		if err == nil {
   304  			t.Error(fs.Name()+":", "No write error")
   305  		}
   306  		f.Close()
   307  	}
   308  }
   309  
   310  func TestWriteCloseTime(t *testing.T) {
   311  	defer removeAllTestFiles(t)
   312  	const fileName = "afero-demo.txt"
   313  
   314  	for _, fs := range Fss {
   315  		dir := testDir(fs)
   316  		path := filepath.Join(dir, fileName)
   317  
   318  		f, err := fs.Create(path)
   319  		if err != nil {
   320  			t.Error(fs.Name()+":", "fs.Create failed: "+err.Error())
   321  		}
   322  		f.Close()
   323  
   324  		f, err = fs.Create(path)
   325  		if err != nil {
   326  			t.Error(fs.Name()+":", "fs.Create failed: "+err.Error())
   327  		}
   328  		fi, err := f.Stat()
   329  		if err != nil {
   330  			t.Error(fs.Name()+":", "Stat failed: "+err.Error())
   331  		}
   332  		timeBefore := fi.ModTime()
   333  
   334  		// sorry for the delay, but we have to make sure time advances,
   335  		// also on non Un*x systems...
   336  		switch runtime.GOOS {
   337  		case "windows":
   338  			time.Sleep(2 * time.Second)
   339  		case "darwin":
   340  			time.Sleep(1 * time.Second)
   341  		default: // depending on the FS, this may work with < 1 second, on my old ext3 it does not
   342  			time.Sleep(1 * time.Second)
   343  		}
   344  
   345  		_, err = f.Write([]byte("test"))
   346  		if err != nil {
   347  			t.Error(fs.Name()+":", "Write failed: "+err.Error())
   348  		}
   349  		f.Close()
   350  		fi, err = fs.Stat(path)
   351  		if err != nil {
   352  			t.Error(fs.Name()+":", "fs.Stat failed: "+err.Error())
   353  		}
   354  		if fi.ModTime().Equal(timeBefore) {
   355  			t.Error(fs.Name()+":", "ModTime was not set on Close()")
   356  		}
   357  	}
   358  }
   359  
   360  // This test should be run with the race detector on:
   361  // go test -race -v -timeout 10s -run TestRacingDeleteAndClose
   362  func TestRacingDeleteAndClose(t *testing.T) {
   363  	fs := NewMemMapFs()
   364  	pathname := "testfile"
   365  	f, err := fs.Create(pathname)
   366  	if err != nil {
   367  		t.Fatal(err)
   368  	}
   369  
   370  	in := make(chan bool)
   371  
   372  	go func() {
   373  		<-in
   374  		f.Close()
   375  	}()
   376  	go func() {
   377  		<-in
   378  		fs.Remove(pathname)
   379  	}()
   380  	close(in)
   381  }
   382  
   383  // This test should be run with the race detector on:
   384  // go test -run TestMemFsDataRace -race
   385  func TestMemFsDataRace(t *testing.T) {
   386  	const dir = "test_dir"
   387  	fs := NewMemMapFs()
   388  
   389  	if err := fs.MkdirAll(dir, 0o777); err != nil {
   390  		t.Fatal(err)
   391  	}
   392  
   393  	const n = 1000
   394  	done := make(chan struct{})
   395  
   396  	go func() {
   397  		defer close(done)
   398  		for i := 0; i < n; i++ {
   399  			fname := filepath.Join(dir, fmt.Sprintf("%d.txt", i))
   400  			if err := WriteFile(fs, fname, []byte(""), 0o777); err != nil {
   401  				panic(err)
   402  			}
   403  			if err := fs.Remove(fname); err != nil {
   404  				panic(err)
   405  			}
   406  		}
   407  	}()
   408  
   409  loop:
   410  	for {
   411  		select {
   412  		case <-done:
   413  			break loop
   414  		default:
   415  			_, err := ReadDir(fs, dir)
   416  			if err != nil {
   417  				t.Fatal(err)
   418  			}
   419  		}
   420  	}
   421  }
   422  
   423  // root is a directory
   424  func TestMemFsRootDirMode(t *testing.T) {
   425  	t.Parallel()
   426  
   427  	fs := NewMemMapFs()
   428  	info, err := fs.Stat("/")
   429  	if err != nil {
   430  		t.Fatal(err)
   431  	}
   432  	if !info.IsDir() {
   433  		t.Error("should be a directory")
   434  	}
   435  	if !info.Mode().IsDir() {
   436  		t.Errorf("FileMode is not directory, is %s", info.Mode().String())
   437  	}
   438  }
   439  
   440  // MkdirAll creates intermediate directories with correct mode
   441  func TestMemFsMkdirAllMode(t *testing.T) {
   442  	t.Parallel()
   443  
   444  	fs := NewMemMapFs()
   445  	err := fs.MkdirAll("/a/b/c", 0o755)
   446  	if err != nil {
   447  		t.Fatal(err)
   448  	}
   449  	info, err := fs.Stat("/a")
   450  	if err != nil {
   451  		t.Fatal(err)
   452  	}
   453  	if !info.Mode().IsDir() {
   454  		t.Error("/a: mode is not directory")
   455  	}
   456  	if !info.ModTime().After(time.Now().Add(-1 * time.Hour)) {
   457  		t.Errorf("/a: mod time not set, got %s", info.ModTime())
   458  	}
   459  	if info.Mode() != os.FileMode(os.ModeDir|0o755) {
   460  		t.Errorf("/a: wrong permissions, expected drwxr-xr-x, got %s", info.Mode())
   461  	}
   462  	info, err = fs.Stat("/a/b")
   463  	if err != nil {
   464  		t.Fatal(err)
   465  	}
   466  	if !info.Mode().IsDir() {
   467  		t.Error("/a/b: mode is not directory")
   468  	}
   469  	if info.Mode() != os.FileMode(os.ModeDir|0o755) {
   470  		t.Errorf("/a/b: wrong permissions, expected drwxr-xr-x, got %s", info.Mode())
   471  	}
   472  	if !info.ModTime().After(time.Now().Add(-1 * time.Hour)) {
   473  		t.Errorf("/a/b: mod time not set, got %s", info.ModTime())
   474  	}
   475  	info, err = fs.Stat("/a/b/c")
   476  	if err != nil {
   477  		t.Fatal(err)
   478  	}
   479  	if !info.Mode().IsDir() {
   480  		t.Error("/a/b/c: mode is not directory")
   481  	}
   482  	if info.Mode() != os.FileMode(os.ModeDir|0o755) {
   483  		t.Errorf("/a/b/c: wrong permissions, expected drwxr-xr-x, got %s", info.Mode())
   484  	}
   485  	if !info.ModTime().After(time.Now().Add(-1 * time.Hour)) {
   486  		t.Errorf("/a/b/c: mod time not set, got %s", info.ModTime())
   487  	}
   488  }
   489  
   490  // MkdirAll does not change permissions of already-existing directories
   491  func TestMemFsMkdirAllNoClobber(t *testing.T) {
   492  	t.Parallel()
   493  
   494  	fs := NewMemMapFs()
   495  	err := fs.MkdirAll("/a/b/c", 0o755)
   496  	if err != nil {
   497  		t.Fatal(err)
   498  	}
   499  	info, err := fs.Stat("/a/b")
   500  	if err != nil {
   501  		t.Fatal(err)
   502  	}
   503  	if info.Mode() != os.FileMode(os.ModeDir|0o755) {
   504  		t.Errorf("/a/b: wrong permissions, expected drwxr-xr-x, got %s", info.Mode())
   505  	}
   506  	err = fs.MkdirAll("/a/b/c/d/e/f", 0o710)
   507  	// '/a/b' is unchanged
   508  	if err != nil {
   509  		t.Fatal(err)
   510  	}
   511  	info, err = fs.Stat("/a/b")
   512  	if err != nil {
   513  		t.Fatal(err)
   514  	}
   515  	if info.Mode() != os.FileMode(os.ModeDir|0o755) {
   516  		t.Errorf("/a/b: wrong permissions, expected drwxr-xr-x, got %s", info.Mode())
   517  	}
   518  	// new directories created with proper permissions
   519  	info, err = fs.Stat("/a/b/c/d")
   520  	if err != nil {
   521  		t.Fatal(err)
   522  	}
   523  	if info.Mode() != os.FileMode(os.ModeDir|0o710) {
   524  		t.Errorf("/a/b/c/d: wrong permissions, expected drwx--x---, got %s", info.Mode())
   525  	}
   526  	info, err = fs.Stat("/a/b/c/d/e")
   527  	if err != nil {
   528  		t.Fatal(err)
   529  	}
   530  	if info.Mode() != os.FileMode(os.ModeDir|0o710) {
   531  		t.Errorf("/a/b/c/d/e: wrong permissions, expected drwx--x---, got %s", info.Mode())
   532  	}
   533  	info, err = fs.Stat("/a/b/c/d/e/f")
   534  	if err != nil {
   535  		t.Fatal(err)
   536  	}
   537  	if info.Mode() != os.FileMode(os.ModeDir|0o710) {
   538  		t.Errorf("/a/b/c/d/e/f: wrong permissions, expected drwx--x---, got %s", info.Mode())
   539  	}
   540  }
   541  
   542  func TestMemFsDirMode(t *testing.T) {
   543  	fs := NewMemMapFs()
   544  	err := fs.Mkdir("/testDir1", 0o644)
   545  	if err != nil {
   546  		t.Error(err)
   547  	}
   548  	err = fs.MkdirAll("/sub/testDir2", 0o644)
   549  	if err != nil {
   550  		t.Error(err)
   551  	}
   552  	info, err := fs.Stat("/testDir1")
   553  	if err != nil {
   554  		t.Error(err)
   555  	}
   556  	if !info.IsDir() {
   557  		t.Error("should be a directory")
   558  	}
   559  	if !info.Mode().IsDir() {
   560  		t.Error("FileMode is not directory")
   561  	}
   562  	info, err = fs.Stat("/sub/testDir2")
   563  	if err != nil {
   564  		t.Error(err)
   565  	}
   566  	if !info.IsDir() {
   567  		t.Error("should be a directory")
   568  	}
   569  	if !info.Mode().IsDir() {
   570  		t.Error("FileMode is not directory")
   571  	}
   572  }
   573  
   574  func TestMemFsUnexpectedEOF(t *testing.T) {
   575  	t.Parallel()
   576  
   577  	fs := NewMemMapFs()
   578  
   579  	if err := WriteFile(fs, "file.txt", []byte("abc"), 0o777); err != nil {
   580  		t.Fatal(err)
   581  	}
   582  
   583  	f, err := fs.Open("file.txt")
   584  	if err != nil {
   585  		t.Fatal(err)
   586  	}
   587  	defer f.Close()
   588  
   589  	// Seek beyond the end.
   590  	_, err = f.Seek(512, 0)
   591  	if err != nil {
   592  		t.Fatal(err)
   593  	}
   594  
   595  	buff := make([]byte, 256)
   596  	_, err = io.ReadAtLeast(f, buff, 256)
   597  
   598  	if err != io.ErrUnexpectedEOF {
   599  		t.Fatal("Expected ErrUnexpectedEOF")
   600  	}
   601  }
   602  
   603  func TestMemFsChmod(t *testing.T) {
   604  	t.Parallel()
   605  
   606  	fs := NewMemMapFs()
   607  	const file = "hello"
   608  	if err := fs.Mkdir(file, 0o700); err != nil {
   609  		t.Fatal(err)
   610  	}
   611  
   612  	info, err := fs.Stat(file)
   613  	if err != nil {
   614  		t.Fatal(err)
   615  	}
   616  	if info.Mode().String() != "drwx------" {
   617  		t.Fatal("mkdir failed to create a directory: mode =", info.Mode())
   618  	}
   619  
   620  	err = fs.Chmod(file, 0)
   621  	if err != nil {
   622  		t.Error("Failed to run chmod:", err)
   623  	}
   624  
   625  	info, err = fs.Stat(file)
   626  	if err != nil {
   627  		t.Fatal(err)
   628  	}
   629  	if info.Mode().String() != "d---------" {
   630  		t.Error("chmod should not change file type. New mode =", info.Mode())
   631  	}
   632  }
   633  
   634  // can't use Mkdir to get around which permissions we're allowed to set
   635  func TestMemFsMkdirModeIllegal(t *testing.T) {
   636  	t.Parallel()
   637  
   638  	fs := NewMemMapFs()
   639  	err := fs.Mkdir("/a", os.ModeSocket|0o755)
   640  	if err != nil {
   641  		t.Fatal(err)
   642  	}
   643  	info, err := fs.Stat("/a")
   644  	if err != nil {
   645  		t.Fatal(err)
   646  	}
   647  	if info.Mode() != os.FileMode(os.ModeDir|0o755) {
   648  		t.Fatalf("should not be able to use Mkdir to set illegal mode: %s", info.Mode().String())
   649  	}
   650  }
   651  
   652  // can't use OpenFile to get around which permissions we're allowed to set
   653  func TestMemFsOpenFileModeIllegal(t *testing.T) {
   654  	t.Parallel()
   655  
   656  	fs := NewMemMapFs()
   657  	file, err := fs.OpenFile("/a", os.O_CREATE, os.ModeSymlink|0o644)
   658  	if err != nil {
   659  		t.Fatal(err)
   660  	}
   661  	defer file.Close()
   662  	info, err := fs.Stat("/a")
   663  	if err != nil {
   664  		t.Fatal(err)
   665  	}
   666  	if info.Mode() != os.FileMode(0o644) {
   667  		t.Fatalf("should not be able to use OpenFile to set illegal mode: %s", info.Mode().String())
   668  	}
   669  }
   670  
   671  // LstatIfPossible should always return false, since MemMapFs does not
   672  // support symlinks.
   673  func TestMemFsLstatIfPossible(t *testing.T) {
   674  	t.Parallel()
   675  
   676  	fs := NewMemMapFs()
   677  
   678  	// We assert that fs implements Lstater
   679  	fsAsserted, ok := fs.(Lstater)
   680  	if !ok {
   681  		t.Fatalf("The filesytem does not implement Lstater")
   682  	}
   683  
   684  	file, err := fs.OpenFile("/a.txt", os.O_CREATE, 0o644)
   685  	if err != nil {
   686  		t.Fatalf("Error when opening file: %v", err)
   687  	}
   688  	defer file.Close()
   689  
   690  	_, lstatCalled, err := fsAsserted.LstatIfPossible("/a.txt")
   691  	if err != nil {
   692  		t.Fatalf("Function returned err: %v", err)
   693  	}
   694  	if lstatCalled {
   695  		t.Fatalf("Function indicated lstat was called. This should never be true.")
   696  	}
   697  }
   698  
   699  func TestMemMapFsConfurrentMkdir(t *testing.T) {
   700  	const dir = "test_dir"
   701  	const n = 1000
   702  	mfs := NewMemMapFs().(*MemMapFs)
   703  
   704  	allFilePaths := make([]string, 0, n)
   705  
   706  	// run concurrency test
   707  	var wg sync.WaitGroup
   708  	for i := 0; i < n; i++ {
   709  		fp := filepath.Join(
   710  			dir,
   711  			fmt.Sprintf("%02d", n%10),
   712  			fmt.Sprintf("%d.txt", i),
   713  		)
   714  		allFilePaths = append(allFilePaths, fp)
   715  
   716  		wg.Add(1)
   717  		go func() {
   718  			defer wg.Done()
   719  
   720  			if err := mfs.MkdirAll(filepath.Dir(fp), 0o755); err != nil {
   721  				t.Error(err)
   722  			}
   723  
   724  			wt, err := mfs.Create(fp)
   725  			if err != nil {
   726  				t.Error(err)
   727  			}
   728  			defer func() {
   729  				if err := wt.Close(); err != nil {
   730  					t.Error(err)
   731  				}
   732  			}()
   733  
   734  			// write 30 bytes
   735  			for j := 0; j < 10; j++ {
   736  				_, err := wt.Write([]byte("000"))
   737  				if err != nil {
   738  					t.Error(err)
   739  				}
   740  			}
   741  		}()
   742  	}
   743  	wg.Wait()
   744  
   745  	// Test1: find all files by full path access
   746  	for _, fp := range allFilePaths {
   747  		info, err := mfs.Stat(fp)
   748  		if err != nil {
   749  			t.Error(err)
   750  		}
   751  
   752  		if info.Size() != 30 {
   753  			t.Errorf("file size should be 30, but got %d", info.Size())
   754  		}
   755  
   756  	}
   757  
   758  	// Test2: find all files by walk
   759  	foundFiles := make([]string, 0, n)
   760  	wErr := Walk(mfs, dir, func(path string, info fs.FileInfo, err error) error {
   761  		if err != nil {
   762  			t.Error(err)
   763  		}
   764  		if info.IsDir() {
   765  			return nil // skip dir
   766  		}
   767  		if strings.HasSuffix(info.Name(), ".txt") {
   768  			foundFiles = append(foundFiles, path)
   769  		}
   770  		return nil
   771  	})
   772  	if wErr != nil {
   773  		t.Error(wErr)
   774  	}
   775  	if len(foundFiles) != n {
   776  		t.Errorf("found %d files, but expect %d", len(foundFiles), n)
   777  	}
   778  }
   779  
   780  func TestMemFsRenameDir(t *testing.T) {
   781  	const srcPath = "/src"
   782  	const dstPath = "/dst"
   783  	const subDir = "dir"
   784  	const subFile = "file.txt"
   785  
   786  	fs := NewMemMapFs()
   787  
   788  	err := fs.MkdirAll(srcPath+FilePathSeparator+subDir, 0o777)
   789  	if err != nil {
   790  		t.Fatalf("MkDirAll failed: %s", err)
   791  	}
   792  
   793  	f, err := fs.Create(srcPath + FilePathSeparator + subFile)
   794  	if err != nil {
   795  		t.Fatalf("Create failed: %s", err)
   796  	}
   797  	if err = f.Close(); err != nil {
   798  		t.Fatalf("Close failed: %s", err)
   799  	}
   800  
   801  	err = fs.Rename(srcPath, dstPath)
   802  	if err != nil {
   803  		t.Fatalf("Rename failed: %s", err)
   804  	}
   805  
   806  	_, err = fs.Stat(srcPath + FilePathSeparator + subDir)
   807  	if err == nil {
   808  		t.Fatalf("SubDir still exists in the source dir")
   809  	}
   810  
   811  	_, err = fs.Stat(srcPath + FilePathSeparator + subFile)
   812  	if err == nil {
   813  		t.Fatalf("SubFile still exists in the source dir")
   814  	}
   815  
   816  	_, err = fs.Stat(dstPath + FilePathSeparator + subDir)
   817  	if err != nil {
   818  		t.Fatalf("SubDir stat in the destination dir: %s", err)
   819  	}
   820  
   821  	_, err = fs.Stat(dstPath + FilePathSeparator + subFile)
   822  	if err != nil {
   823  		t.Fatalf("SubFile stat in the destination dir: %s", err)
   824  	}
   825  
   826  	err = fs.Mkdir(srcPath, 0o777)
   827  	if err != nil {
   828  		t.Fatalf("Cannot recreate the source dir: %s", err)
   829  	}
   830  
   831  	err = fs.Mkdir(srcPath+FilePathSeparator+subDir, 0o777)
   832  	if err != nil {
   833  		t.Errorf("Cannot recreate the subdir in the source dir: %s", err)
   834  	}
   835  }