github.com/IBM/fsgo@v0.0.0-20220920202152-e16fd2119d49/memmap_test.go (about)

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