tractor.dev/toolkit-go@v0.0.0-20241010005851-214d91207d07/engine/fs/memfs/fs_test.go (about)

     1  // Copyright © 2014 Steve Francia <spf@spf13.com>.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  // http://www.apache.org/licenses/LICENSE-2.0
     7  //
     8  // Unless required by applicable law or agreed to in writing, software
     9  // distributed under the License is distributed on an "AS IS" BASIS,
    10  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    11  // See the License for the specific language governing permissions and
    12  // limitations under the License.
    13  
    14  package memfs
    15  
    16  import (
    17  	"fmt"
    18  	"io"
    19  	"io/fs"
    20  	"os"
    21  	"path/filepath"
    22  	"reflect"
    23  	"runtime"
    24  	"testing"
    25  	"time"
    26  
    27  	"tractor.dev/toolkit-go/engine/fs/fsutil"
    28  )
    29  
    30  var Fss = []*FS{{}}
    31  
    32  var testRegistry map[*FS][]string = make(map[*FS][]string)
    33  
    34  func removeAllTestFiles(t *testing.T) {
    35  	for fs, list := range testRegistry {
    36  		for _, path := range list {
    37  			if err := fs.RemoveAll(path); err != nil {
    38  				t.Error(err)
    39  			}
    40  		}
    41  	}
    42  	testRegistry = make(map[*FS][]string)
    43  }
    44  
    45  func testDir(fsys *FS) string {
    46  	name, err := fsutil.TempDir(fsys, "", "vfs")
    47  	if err != nil {
    48  		panic(fmt.Sprint("unable to work with test dir", err))
    49  	}
    50  	testRegistry[fsys] = append(testRegistry[fsys], name)
    51  
    52  	return name
    53  }
    54  
    55  func fsName(fs *FS) string {
    56  	return filepath.Base(reflect.TypeOf(fs).Elem().PkgPath()) + ".FS"
    57  }
    58  
    59  func TestNormalizePath(t *testing.T) {
    60  	type test struct {
    61  		input    string
    62  		expected string
    63  	}
    64  
    65  	data := []test{
    66  		{".", filePathSeparator},
    67  		{"./", filePathSeparator},
    68  		{"..", filePathSeparator},
    69  		{"../", filePathSeparator},
    70  		{"./..", filePathSeparator},
    71  		{"./../", filePathSeparator},
    72  	}
    73  
    74  	for i, d := range data {
    75  		cpath := normalizePath(d.input)
    76  		if d.expected != cpath {
    77  			t.Errorf("Test %d failed. Expected %q got %q", i, d.expected, cpath)
    78  		}
    79  	}
    80  }
    81  
    82  func TestPathErrors(t *testing.T) {
    83  	path := filepath.Join(".", "some", "path")
    84  	path2 := filepath.Join(".", "different", "path")
    85  	fs := New()
    86  	perm := os.FileMode(0755)
    87  	uid := 1000
    88  	gid := 1000
    89  
    90  	// relevant functions:
    91  	// func (m *MemMapFs) Chmod(name string, mode os.FileMode) error
    92  	// func (m *MemMapFs) Chtimes(name string, atime time.Time, mtime time.Time) error
    93  	// func (m *MemMapFs) Create(name string) (File, error)
    94  	// func (m *MemMapFs) Mkdir(name string, perm os.FileMode) error
    95  	// func (m *MemMapFs) MkdirAll(path string, perm os.FileMode) error
    96  	// func (m *MemMapFs) Open(name string) (File, error)
    97  	// func (m *MemMapFs) OpenFile(name string, flag int, perm os.FileMode) (File, error)
    98  	// func (m *MemMapFs) Remove(name string) error
    99  	// func (m *MemMapFs) Rename(oldname, newname string) error
   100  	// func (m *MemMapFs) Stat(name string) (os.FileInfo, error)
   101  
   102  	err := fs.Chmod(path, perm)
   103  	checkPathError(t, err, "Chmod")
   104  
   105  	err = fs.Chown(path, uid, gid)
   106  	checkPathError(t, err, "Chown")
   107  
   108  	err = fs.Chtimes(path, time.Now(), time.Now())
   109  	checkPathError(t, err, "Chtimes")
   110  
   111  	// fs.Create doesn't return an error
   112  
   113  	err = fs.Mkdir(path2, perm)
   114  	if err != nil {
   115  		t.Error(err)
   116  	}
   117  	err = fs.Mkdir(path2, perm)
   118  	checkPathError(t, err, "Mkdir")
   119  
   120  	err = fs.MkdirAll(path2, perm)
   121  	if err != nil {
   122  		t.Error("MkdirAll:", err)
   123  	}
   124  
   125  	_, err = fs.Open(path)
   126  	checkPathError(t, err, "Open")
   127  
   128  	_, err = fs.OpenFile(path, os.O_RDWR, perm)
   129  	checkPathError(t, err, "OpenFile")
   130  
   131  	err = fs.Remove(path)
   132  	checkPathError(t, err, "Remove")
   133  
   134  	err = fs.RemoveAll(path)
   135  	if err != nil {
   136  		t.Error("RemoveAll:", err)
   137  	}
   138  
   139  	err = fs.Rename(path, path2)
   140  	checkPathError(t, err, "Rename")
   141  
   142  	_, err = fs.Stat(path)
   143  	checkPathError(t, err, "Stat")
   144  }
   145  
   146  func checkPathError(t *testing.T, err error, op string) {
   147  	pathErr, ok := err.(*os.PathError)
   148  	if !ok {
   149  		t.Error(op+":", err, "is not a os.PathError")
   150  		return
   151  	}
   152  	_, ok = pathErr.Err.(*os.PathError)
   153  	if ok {
   154  		t.Error(op+":", err, "contains another os.PathError")
   155  	}
   156  }
   157  
   158  // Ensure os.O_EXCL is correctly handled.
   159  func TestOpenFileExcl(t *testing.T) {
   160  	const fileName = "/myFileTest"
   161  	const fileMode = os.FileMode(0765)
   162  
   163  	fs := New()
   164  
   165  	// First creation should succeed.
   166  	f, err := fs.OpenFile(fileName, os.O_CREATE|os.O_EXCL, fileMode)
   167  	if err != nil {
   168  		t.Errorf("OpenFile Create Excl failed: %s", err)
   169  		return
   170  	}
   171  	f.Close()
   172  
   173  	// Second creation should fail.
   174  	_, err = fs.OpenFile(fileName, os.O_CREATE|os.O_EXCL, fileMode)
   175  	if err == nil {
   176  		t.Errorf("OpenFile Create Excl should have failed, but it didn't")
   177  	}
   178  	checkPathError(t, err, "Open")
   179  }
   180  
   181  // Ensure Permissions are set on OpenFile/Mkdir/MkdirAll
   182  func TestPermSet(t *testing.T) {
   183  	const fileName = "/myFileTest"
   184  	const dirPath = "/myDirTest"
   185  	const dirPathAll = "/my/path/to/dir"
   186  
   187  	const fileMode = os.FileMode(0765)
   188  	// directories will also have the directory bit set
   189  	const dirMode = fileMode | os.ModeDir
   190  
   191  	fs := New()
   192  
   193  	// Test Openfile
   194  	f, err := fs.OpenFile(fileName, os.O_CREATE, fileMode)
   195  	if err != nil {
   196  		t.Errorf("OpenFile Create failed: %s", err)
   197  		return
   198  	}
   199  	f.Close()
   200  
   201  	s, err := fs.Stat(fileName)
   202  	if err != nil {
   203  		t.Errorf("Stat failed: %s", err)
   204  		return
   205  	}
   206  	if s.Mode().String() != fileMode.String() {
   207  		t.Errorf("Permissions Incorrect: %s != %s", s.Mode().String(), fileMode.String())
   208  		return
   209  	}
   210  
   211  	// Test Mkdir
   212  	err = fs.Mkdir(dirPath, dirMode)
   213  	if err != nil {
   214  		t.Errorf("MkDir Create failed: %s", err)
   215  		return
   216  	}
   217  	s, err = fs.Stat(dirPath)
   218  	if err != nil {
   219  		t.Errorf("Stat failed: %s", err)
   220  		return
   221  	}
   222  	// sets File
   223  	if s.Mode().String() != dirMode.String() {
   224  		t.Errorf("Permissions Incorrect: %s != %s", s.Mode().String(), dirMode.String())
   225  		return
   226  	}
   227  
   228  	// Test MkdirAll
   229  	err = fs.MkdirAll(dirPathAll, dirMode)
   230  	if err != nil {
   231  		t.Errorf("MkDir Create failed: %s", err)
   232  		return
   233  	}
   234  	s, err = fs.Stat(dirPathAll)
   235  	if err != nil {
   236  		t.Errorf("Stat failed: %s", err)
   237  		return
   238  	}
   239  	if s.Mode().String() != dirMode.String() {
   240  		t.Errorf("Permissions Incorrect: %s != %s", s.Mode().String(), dirMode.String())
   241  		return
   242  	}
   243  }
   244  
   245  // Fails if multiple file objects use the same file.at counter in MemMapFs
   246  func TestMultipleOpenFiles(t *testing.T) {
   247  	defer removeAllTestFiles(t)
   248  	const fileName = "afero-demo2.txt"
   249  
   250  	var data = make([][]byte, len(Fss))
   251  
   252  	for i, fsys := range Fss {
   253  		dir := testDir(fsys)
   254  		path := filepath.Join(dir, fileName)
   255  		fh1, err := fsys.Create(path)
   256  		if err != nil {
   257  			t.Error("fs.Create failed: " + err.Error())
   258  		}
   259  		fw1, ok := fh1.(io.Writer)
   260  		if !ok {
   261  			t.Fatal("file not a io.Writer")
   262  		}
   263  		_, err = fw1.Write([]byte("test"))
   264  		if err != nil {
   265  			t.Error("fh.Write failed: " + err.Error())
   266  		}
   267  		fs1, ok := fh1.(io.Seeker)
   268  		if !ok {
   269  			t.Fatal("file not a io.Seeker")
   270  		}
   271  		_, err = fs1.Seek(0, os.SEEK_SET)
   272  		if err != nil {
   273  			t.Error(err)
   274  		}
   275  
   276  		fh2, err := fsys.OpenFile(path, os.O_RDWR, 0777)
   277  		if err != nil {
   278  			t.Error("fs.OpenFile failed: " + err.Error())
   279  		}
   280  		fs2, ok := fh2.(io.Seeker)
   281  		if !ok {
   282  			t.Fatal("file not a io.Seeker")
   283  		}
   284  		_, err = fs2.Seek(0, os.SEEK_END)
   285  		if err != nil {
   286  			t.Error(err)
   287  		}
   288  		fw2, ok := fh2.(io.Writer)
   289  		if !ok {
   290  			t.Fatal("file not a io.Writer")
   291  		}
   292  		_, err = fw2.Write([]byte("data"))
   293  		if err != nil {
   294  			t.Error(err)
   295  		}
   296  		err = fh2.Close()
   297  		if err != nil {
   298  			t.Error(err)
   299  		}
   300  
   301  		_, err = fw1.Write([]byte("data"))
   302  		if err != nil {
   303  			t.Error(err)
   304  		}
   305  		err = fh1.Close()
   306  		if err != nil {
   307  			t.Error(err)
   308  		}
   309  		// the file now should contain "datadata"
   310  		data[i], err = fs.ReadFile(fsys, path)
   311  		if err != nil {
   312  			t.Error(err)
   313  		}
   314  	}
   315  
   316  	for i, fs := range Fss {
   317  		if i == 0 {
   318  			continue
   319  		}
   320  		if string(data[0]) != string(data[i]) {
   321  			t.Errorf("%s and %s don't behave the same\n"+
   322  				"%s: \"%s\"\n%s: \"%s\"\n",
   323  				fsName(Fss[0]), fsName(fs), fsName(Fss[0]), data[0], fsName(fs), data[i])
   324  		}
   325  	}
   326  }
   327  
   328  // Test if file.Write() fails when opened as read only
   329  func TestReadOnly(t *testing.T) {
   330  	defer removeAllTestFiles(t)
   331  	const fileName = "afero-demo.txt"
   332  
   333  	for _, fs := range Fss {
   334  		dir := testDir(fs)
   335  		path := filepath.Join(dir, fileName)
   336  
   337  		f, err := fs.Create(path)
   338  		if err != nil {
   339  			t.Error(fsName(fs)+":", "fs.Create failed: "+err.Error())
   340  		}
   341  		fw, ok := f.(io.Writer)
   342  		if !ok {
   343  			t.Fatal("file not a io.Writer")
   344  		}
   345  		_, err = fw.Write([]byte("test"))
   346  		if err != nil {
   347  			t.Error(fsName(fs)+":", "Write failed: "+err.Error())
   348  		}
   349  		f.Close()
   350  
   351  		f, err = fs.Open(path)
   352  		if err != nil {
   353  			t.Error("fs.Open failed: " + err.Error())
   354  		}
   355  		fw, ok = f.(io.Writer)
   356  		if !ok {
   357  			t.Fatal("file not a io.Writer")
   358  		}
   359  		_, err = fw.Write([]byte("data"))
   360  		if err == nil {
   361  			t.Error(fsName(fs)+":", "No write error")
   362  		}
   363  		f.Close()
   364  
   365  		f, err = fs.OpenFile(path, os.O_RDONLY, 0644)
   366  		if err != nil {
   367  			t.Error("fs.Open failed: " + err.Error())
   368  		}
   369  		fw, ok = f.(io.Writer)
   370  		if !ok {
   371  			t.Fatal("file not a io.Writer")
   372  		}
   373  		_, err = fw.Write([]byte("data"))
   374  		if err == nil {
   375  			t.Error(fsName(fs)+":", "No write error")
   376  		}
   377  		f.Close()
   378  	}
   379  }
   380  
   381  func TestWriteCloseTime(t *testing.T) {
   382  	defer removeAllTestFiles(t)
   383  	const fileName = "afero-demo.txt"
   384  
   385  	for _, fs := range Fss {
   386  		dir := testDir(fs)
   387  		path := filepath.Join(dir, fileName)
   388  
   389  		f, err := fs.Create(path)
   390  		if err != nil {
   391  			t.Error(fsName(fs)+":", "fs.Create failed: "+err.Error())
   392  		}
   393  		f.Close()
   394  
   395  		f, err = fs.Create(path)
   396  		if err != nil {
   397  			t.Error(fsName(fs)+":", "fs.Create failed: "+err.Error())
   398  		}
   399  		fi, err := f.Stat()
   400  		if err != nil {
   401  			t.Error(fsName(fs)+":", "Stat failed: "+err.Error())
   402  		}
   403  		timeBefore := fi.ModTime()
   404  
   405  		// sorry for the delay, but we have to make sure time advances,
   406  		// also on non Un*x systems...
   407  		switch runtime.GOOS {
   408  		case "windows":
   409  			time.Sleep(2 * time.Second)
   410  		case "darwin":
   411  			time.Sleep(1 * time.Second)
   412  		default: // depending on the FS, this may work with < 1 second, on my old ext3 it does not
   413  			time.Sleep(1 * time.Second)
   414  		}
   415  
   416  		fw, ok := f.(io.Writer)
   417  		if !ok {
   418  			t.Fatal("file not a io.Writer")
   419  		}
   420  		_, err = fw.Write([]byte("test"))
   421  		if err != nil {
   422  			t.Error(fsName(fs)+":", "Write failed: "+err.Error())
   423  		}
   424  		f.Close()
   425  		fi, err = fs.Stat(path)
   426  		if err != nil {
   427  			t.Error(fsName(fs)+":", "fs.Stat failed: "+err.Error())
   428  		}
   429  		if fi.ModTime().Equal(timeBefore) {
   430  			t.Error(fsName(fs)+":", "ModTime was not set on Close()")
   431  		}
   432  	}
   433  }
   434  
   435  // This test should be run with the race detector on:
   436  // go test -race -v -timeout 10s -run TestRacingDeleteAndClose
   437  func TestRacingDeleteAndClose(t *testing.T) {
   438  	fs := New()
   439  	pathname := "testfile"
   440  	f, err := fs.Create(pathname)
   441  	if err != nil {
   442  		t.Fatal(err)
   443  	}
   444  
   445  	in := make(chan bool)
   446  
   447  	go func() {
   448  		<-in
   449  		f.Close()
   450  	}()
   451  	go func() {
   452  		<-in
   453  		fs.Remove(pathname)
   454  	}()
   455  	close(in)
   456  }
   457  
   458  // This test should be run with the race detector on:
   459  // go test -run TestMemFsDataRace -race
   460  func TestMemFsDataRace(t *testing.T) {
   461  	const dir = "test_dir"
   462  	fsys := New()
   463  
   464  	if err := fsys.MkdirAll(dir, 0777); err != nil {
   465  		t.Fatal(err)
   466  	}
   467  
   468  	const n = 1000
   469  	done := make(chan struct{})
   470  
   471  	go func() {
   472  		defer close(done)
   473  		for i := 0; i < n; i++ {
   474  			fname := filepath.Join(dir, fmt.Sprintf("%d.txt", i))
   475  			if err := fsutil.WriteFile(fsys, fname, []byte(""), 0777); err != nil {
   476  				panic(err)
   477  			}
   478  			if err := fsys.Remove(fname); err != nil {
   479  				panic(err)
   480  			}
   481  		}
   482  	}()
   483  
   484  loop:
   485  	for {
   486  		select {
   487  		case <-done:
   488  			break loop
   489  		default:
   490  			_, err := fs.ReadDir(fsys, dir)
   491  			if err != nil {
   492  				t.Fatal(err)
   493  			}
   494  		}
   495  	}
   496  }
   497  
   498  // root is a directory
   499  func TestMemFsRootDirMode(t *testing.T) {
   500  	t.Parallel()
   501  
   502  	fs := New()
   503  	info, err := fs.Stat("/")
   504  	if err != nil {
   505  		t.Fatal(err)
   506  	}
   507  	if !info.IsDir() {
   508  		t.Error("should be a directory")
   509  	}
   510  	if !info.Mode().IsDir() {
   511  		t.Errorf("FileMode is not directory, is %s", info.Mode().String())
   512  	}
   513  }
   514  
   515  // MkdirAll creates intermediate directories with correct mode
   516  func TestMemFsMkdirAllMode(t *testing.T) {
   517  	t.Parallel()
   518  
   519  	fs := New()
   520  	err := fs.MkdirAll("/a/b/c", 0755)
   521  	if err != nil {
   522  		t.Fatal(err)
   523  	}
   524  	info, err := fs.Stat("/a")
   525  	if err != nil {
   526  		t.Fatal(err)
   527  	}
   528  	if !info.Mode().IsDir() {
   529  		t.Error("/a: mode is not directory")
   530  	}
   531  	if info.Mode() != os.FileMode(os.ModeDir|0755) {
   532  		t.Errorf("/a: wrong permissions, expected drwxr-xr-x, got %s", info.Mode())
   533  	}
   534  	info, err = fs.Stat("/a/b")
   535  	if err != nil {
   536  		t.Fatal(err)
   537  	}
   538  	if !info.Mode().IsDir() {
   539  		t.Error("/a/b: mode is not directory")
   540  	}
   541  	if info.Mode() != os.FileMode(os.ModeDir|0755) {
   542  		t.Errorf("/a/b: wrong permissions, expected drwxr-xr-x, got %s", info.Mode())
   543  	}
   544  	info, err = fs.Stat("/a/b/c")
   545  	if err != nil {
   546  		t.Fatal(err)
   547  	}
   548  	if !info.Mode().IsDir() {
   549  		t.Error("/a/b/c: mode is not directory")
   550  	}
   551  	if info.Mode() != os.FileMode(os.ModeDir|0755) {
   552  		t.Errorf("/a/b/c: wrong permissions, expected drwxr-xr-x, got %s", info.Mode())
   553  	}
   554  }
   555  
   556  // MkdirAll does not change permissions of already-existing directories
   557  func TestMemFsMkdirAllNoClobber(t *testing.T) {
   558  	t.Parallel()
   559  
   560  	fs := New()
   561  	err := fs.MkdirAll("/a/b/c", 0755)
   562  	if err != nil {
   563  		t.Fatal(err)
   564  	}
   565  	info, err := fs.Stat("/a/b")
   566  	if err != nil {
   567  		t.Fatal(err)
   568  	}
   569  	if info.Mode() != os.FileMode(os.ModeDir|0755) {
   570  		t.Errorf("/a/b: wrong permissions, expected drwxr-xr-x, got %s", info.Mode())
   571  	}
   572  	err = fs.MkdirAll("/a/b/c/d/e/f", 0710)
   573  	// '/a/b' is unchanged
   574  	if err != nil {
   575  		t.Fatal(err)
   576  	}
   577  	info, err = fs.Stat("/a/b")
   578  	if err != nil {
   579  		t.Fatal(err)
   580  	}
   581  	if info.Mode() != os.FileMode(os.ModeDir|0755) {
   582  		t.Errorf("/a/b: wrong permissions, expected drwxr-xr-x, got %s", info.Mode())
   583  	}
   584  	// new directories created with proper permissions
   585  	info, err = fs.Stat("/a/b/c/d")
   586  	if err != nil {
   587  		t.Fatal(err)
   588  	}
   589  	if info.Mode() != os.FileMode(os.ModeDir|0710) {
   590  		t.Errorf("/a/b/c/d: wrong permissions, expected drwx--x---, got %s", info.Mode())
   591  	}
   592  	info, err = fs.Stat("/a/b/c/d/e")
   593  	if err != nil {
   594  		t.Fatal(err)
   595  	}
   596  	if info.Mode() != os.FileMode(os.ModeDir|0710) {
   597  		t.Errorf("/a/b/c/d/e: wrong permissions, expected drwx--x---, got %s", info.Mode())
   598  	}
   599  	info, err = fs.Stat("/a/b/c/d/e/f")
   600  	if err != nil {
   601  		t.Fatal(err)
   602  	}
   603  	if info.Mode() != os.FileMode(os.ModeDir|0710) {
   604  		t.Errorf("/a/b/c/d/e/f: wrong permissions, expected drwx--x---, got %s", info.Mode())
   605  	}
   606  }
   607  
   608  func TestMemFsDirMode(t *testing.T) {
   609  	fs := New()
   610  	err := fs.Mkdir("/testDir1", 0644)
   611  	if err != nil {
   612  		t.Error(err)
   613  	}
   614  	err = fs.MkdirAll("/sub/testDir2", 0644)
   615  	if err != nil {
   616  		t.Error(err)
   617  	}
   618  	info, err := fs.Stat("/testDir1")
   619  	if err != nil {
   620  		t.Error(err)
   621  	}
   622  	if !info.IsDir() {
   623  		t.Error("should be a directory")
   624  	}
   625  	if !info.Mode().IsDir() {
   626  		t.Error("FileMode is not directory")
   627  	}
   628  	info, err = fs.Stat("/sub/testDir2")
   629  	if err != nil {
   630  		t.Error(err)
   631  	}
   632  	if !info.IsDir() {
   633  		t.Error("should be a directory")
   634  	}
   635  	if !info.Mode().IsDir() {
   636  		t.Error("FileMode is not directory")
   637  	}
   638  }
   639  
   640  func TestMemFsUnexpectedEOF(t *testing.T) {
   641  	t.Parallel()
   642  
   643  	fs := New()
   644  
   645  	if err := fsutil.WriteFile(fs, "file.txt", []byte("abc"), 0777); err != nil {
   646  		t.Fatal(err)
   647  	}
   648  
   649  	f, err := fs.Open("file.txt")
   650  	if err != nil {
   651  		t.Fatal(err)
   652  	}
   653  	defer f.Close()
   654  
   655  	// Seek beyond the end.
   656  	fseek, ok := f.(io.Seeker)
   657  	if !ok {
   658  		t.Fatal("file not a io.Seeker")
   659  	}
   660  	_, err = fseek.Seek(512, 0)
   661  	if err != nil {
   662  		t.Fatal(err)
   663  	}
   664  
   665  	buff := make([]byte, 256)
   666  	_, err = io.ReadAtLeast(f, buff, 256)
   667  
   668  	if err != io.ErrUnexpectedEOF {
   669  		t.Fatal("Expected ErrUnexpectedEOF")
   670  	}
   671  }
   672  
   673  func TestMemFsChmod(t *testing.T) {
   674  	t.Parallel()
   675  
   676  	fs := New()
   677  	const file = "hello"
   678  	if err := fs.Mkdir(file, 0700); err != nil {
   679  		t.Fatal(err)
   680  	}
   681  
   682  	info, err := fs.Stat(file)
   683  	if err != nil {
   684  		t.Fatal(err)
   685  	}
   686  	if info.Mode().String() != "drwx------" {
   687  		t.Fatal("mkdir failed to create a directory: mode =", info.Mode())
   688  	}
   689  
   690  	err = fs.Chmod(file, 0)
   691  	if err != nil {
   692  		t.Error("Failed to run chmod:", err)
   693  	}
   694  
   695  	info, err = fs.Stat(file)
   696  	if err != nil {
   697  		t.Fatal(err)
   698  	}
   699  	if info.Mode().String() != "d---------" {
   700  		t.Error("chmod should not change file type. New mode =", info.Mode())
   701  	}
   702  }
   703  
   704  // can't use Mkdir to get around which permissions we're allowed to set
   705  func TestMemFsMkdirModeIllegal(t *testing.T) {
   706  	t.Parallel()
   707  
   708  	fs := New()
   709  	err := fs.Mkdir("/a", os.ModeSocket|0755)
   710  	if err != nil {
   711  		t.Fatal(err)
   712  	}
   713  	info, err := fs.Stat("/a")
   714  	if err != nil {
   715  		t.Fatal(err)
   716  	}
   717  	if info.Mode() != os.FileMode(os.ModeDir|0755) {
   718  		t.Fatalf("should not be able to use Mkdir to set illegal mode: %s", info.Mode().String())
   719  	}
   720  }
   721  
   722  // can't use OpenFile to get around which permissions we're allowed to set
   723  func TestMemFsOpenFileModeIllegal(t *testing.T) {
   724  	t.Parallel()
   725  
   726  	fs := New()
   727  	file, err := fs.OpenFile("/a", os.O_CREATE, os.ModeSymlink|0644)
   728  	if err != nil {
   729  		t.Fatal(err)
   730  	}
   731  	defer file.Close()
   732  	info, err := fs.Stat("/a")
   733  	if err != nil {
   734  		t.Fatal(err)
   735  	}
   736  	if info.Mode() != os.FileMode(0644) {
   737  		t.Fatalf("should not be able to use OpenFile to set illegal mode: %s", info.Mode().String())
   738  	}
   739  }