github.com/mferrell/afero@v1.8.3-0.20220319163648-1d8d1d1d8040/iofs_test.go (about)

     1  // +build go1.16
     2  
     3  package afero
     4  
     5  import (
     6  	"bytes"
     7  	"errors"
     8  	"io"
     9  	"io/fs"
    10  	"os"
    11  	"testing"
    12  	"testing/fstest"
    13  	"time"
    14  )
    15  
    16  func TestIOFS(t *testing.T) {
    17  	t.Parallel()
    18  
    19  	t.Run("use MemMapFs", func(t *testing.T) {
    20  		mmfs := NewMemMapFs()
    21  
    22  		err := mmfs.MkdirAll("dir1/dir2", os.ModePerm)
    23  		if err != nil {
    24  			t.Fatal("MkdirAll failed:", err)
    25  		}
    26  
    27  		f, err := mmfs.OpenFile("dir1/dir2/test.txt", os.O_RDWR|os.O_CREATE, os.ModePerm)
    28  		if err != nil {
    29  			t.Fatal("OpenFile (O_CREATE) failed:", err)
    30  		}
    31  
    32  		f.Close()
    33  
    34  		if err := fstest.TestFS(NewIOFS(mmfs), "dir1/dir2/test.txt"); err != nil {
    35  			t.Error(err)
    36  		}
    37  	})
    38  
    39  	t.Run("use OsFs", func(t *testing.T) {
    40  		osfs := NewBasePathFs(NewOsFs(), t.TempDir())
    41  
    42  		err := osfs.MkdirAll("dir1/dir2", os.ModePerm)
    43  		if err != nil {
    44  			t.Fatal("MkdirAll failed:", err)
    45  		}
    46  
    47  		f, err := osfs.OpenFile("dir1/dir2/test.txt", os.O_RDWR|os.O_CREATE, os.ModePerm)
    48  		if err != nil {
    49  			t.Fatal("OpenFile (O_CREATE) failed:", err)
    50  		}
    51  
    52  		f.Close()
    53  
    54  		if err := fstest.TestFS(NewIOFS(osfs), "dir1/dir2/test.txt"); err != nil {
    55  			t.Error(err)
    56  		}
    57  	})
    58  }
    59  
    60  func TestFromIOFS(t *testing.T) {
    61  	t.Parallel()
    62  
    63  	fsys := fstest.MapFS{
    64  		"test.txt": {
    65  			Data:    []byte("File in root"),
    66  			Mode:    fs.ModePerm,
    67  			ModTime: time.Now(),
    68  		},
    69  		"dir1": {
    70  			Mode:    fs.ModeDir | fs.ModePerm,
    71  			ModTime: time.Now(),
    72  		},
    73  		"dir1/dir2": {
    74  			Mode:    fs.ModeDir | fs.ModePerm,
    75  			ModTime: time.Now(),
    76  		},
    77  		"dir1/dir2/hello.txt": {
    78  			Data:    []byte("Hello world"),
    79  			Mode:    fs.ModePerm,
    80  			ModTime: time.Now(),
    81  		},
    82  	}
    83  
    84  	fromIOFS := FromIOFS{fsys}
    85  
    86  	t.Run("Create", func(t *testing.T) {
    87  		_, err := fromIOFS.Create("test")
    88  		assertPermissionError(t, err)
    89  	})
    90  
    91  	t.Run("Mkdir", func(t *testing.T) {
    92  		err := fromIOFS.Mkdir("test", 0)
    93  		assertPermissionError(t, err)
    94  	})
    95  
    96  	t.Run("MkdirAll", func(t *testing.T) {
    97  		err := fromIOFS.Mkdir("test", 0)
    98  		assertPermissionError(t, err)
    99  	})
   100  
   101  	t.Run("Open", func(t *testing.T) {
   102  		t.Run("non existing file", func(t *testing.T) {
   103  			_, err := fromIOFS.Open("nonexisting")
   104  			if !errors.Is(err, fs.ErrNotExist) {
   105  				t.Errorf("Expected error to be fs.ErrNotExist, got %[1]T (%[1]v)", err)
   106  			}
   107  		})
   108  
   109  		t.Run("directory", func(t *testing.T) {
   110  			dirFile, err := fromIOFS.Open("dir1")
   111  			if err != nil {
   112  				t.Errorf("dir1 open failed: %v", err)
   113  				return
   114  			}
   115  
   116  			defer dirFile.Close()
   117  
   118  			dirStat, err := dirFile.Stat()
   119  			if err != nil {
   120  				t.Errorf("dir1 stat failed: %v", err)
   121  				return
   122  			}
   123  
   124  			if !dirStat.IsDir() {
   125  				t.Errorf("dir1 stat told that it is not a directory")
   126  				return
   127  			}
   128  		})
   129  
   130  		t.Run("simple file", func(t *testing.T) {
   131  			file, err := fromIOFS.Open("test.txt")
   132  			if err != nil {
   133  				t.Errorf("test.txt open failed: %v", err)
   134  				return
   135  			}
   136  
   137  			defer file.Close()
   138  
   139  			fileStat, err := file.Stat()
   140  			if err != nil {
   141  				t.Errorf("test.txt stat failed: %v", err)
   142  				return
   143  			}
   144  
   145  			if fileStat.IsDir() {
   146  				t.Errorf("test.txt stat told that it is a directory")
   147  				return
   148  			}
   149  		})
   150  	})
   151  
   152  	t.Run("Remove", func(t *testing.T) {
   153  		err := fromIOFS.Remove("test")
   154  		assertPermissionError(t, err)
   155  	})
   156  
   157  	t.Run("Rename", func(t *testing.T) {
   158  		err := fromIOFS.Rename("test", "test2")
   159  		assertPermissionError(t, err)
   160  	})
   161  
   162  	t.Run("Stat", func(t *testing.T) {
   163  		t.Run("non existing file", func(t *testing.T) {
   164  			_, err := fromIOFS.Stat("nonexisting")
   165  			if !errors.Is(err, fs.ErrNotExist) {
   166  				t.Errorf("Expected error to be fs.ErrNotExist, got %[1]T (%[1]v)", err)
   167  			}
   168  		})
   169  
   170  		t.Run("directory", func(t *testing.T) {
   171  			stat, err := fromIOFS.Stat("dir1/dir2")
   172  			if err != nil {
   173  				t.Errorf("dir1/dir2 stat failed: %v", err)
   174  				return
   175  			}
   176  
   177  			if !stat.IsDir() {
   178  				t.Errorf("dir1/dir2 stat told that it is not a directory")
   179  				return
   180  			}
   181  		})
   182  
   183  		t.Run("file", func(t *testing.T) {
   184  			stat, err := fromIOFS.Stat("dir1/dir2/hello.txt")
   185  			if err != nil {
   186  				t.Errorf("dir1/dir2 stat failed: %v", err)
   187  				return
   188  			}
   189  
   190  			if stat.IsDir() {
   191  				t.Errorf("dir1/dir2/hello.txt stat told that it is a directory")
   192  				return
   193  			}
   194  
   195  			if lenFile := len(fsys["dir1/dir2/hello.txt"].Data); int64(lenFile) != stat.Size() {
   196  				t.Errorf("dir1/dir2/hello.txt stat told invalid size: expected %d, got %d", lenFile, stat.Size())
   197  				return
   198  			}
   199  		})
   200  	})
   201  
   202  	t.Run("Chmod", func(t *testing.T) {
   203  		err := fromIOFS.Chmod("test", os.ModePerm)
   204  		assertPermissionError(t, err)
   205  	})
   206  
   207  	t.Run("Chown", func(t *testing.T) {
   208  		err := fromIOFS.Chown("test", 0, 0)
   209  		assertPermissionError(t, err)
   210  	})
   211  
   212  	t.Run("Chtimes", func(t *testing.T) {
   213  		err := fromIOFS.Chtimes("test", time.Now(), time.Now())
   214  		assertPermissionError(t, err)
   215  	})
   216  }
   217  
   218  func TestFromIOFS_File(t *testing.T) {
   219  	t.Parallel()
   220  
   221  	fsys := fstest.MapFS{
   222  		"test.txt": {
   223  			Data:    []byte("File in root"),
   224  			Mode:    fs.ModePerm,
   225  			ModTime: time.Now(),
   226  		},
   227  		"dir1": {
   228  			Mode:    fs.ModeDir | fs.ModePerm,
   229  			ModTime: time.Now(),
   230  		},
   231  		"dir2": {
   232  			Mode:    fs.ModeDir | fs.ModePerm,
   233  			ModTime: time.Now(),
   234  		},
   235  	}
   236  
   237  	fromIOFS := FromIOFS{fsys}
   238  
   239  	file, err := fromIOFS.Open("test.txt")
   240  	if err != nil {
   241  		t.Errorf("test.txt open failed: %v", err)
   242  		return
   243  	}
   244  
   245  	defer file.Close()
   246  
   247  	fileStat, err := file.Stat()
   248  	if err != nil {
   249  		t.Errorf("test.txt stat failed: %v", err)
   250  		return
   251  	}
   252  
   253  	if fileStat.IsDir() {
   254  		t.Errorf("test.txt stat told that it is a directory")
   255  		return
   256  	}
   257  
   258  	t.Run("ReadAt", func(t *testing.T) {
   259  		// MapFS files implements io.ReaderAt
   260  		b := make([]byte, 2)
   261  		_, err := file.ReadAt(b, 2)
   262  
   263  		if err != nil {
   264  			t.Errorf("ReadAt failed: %v", err)
   265  			return
   266  		}
   267  
   268  		if expectedData := fsys["test.txt"].Data[2:4]; !bytes.Equal(b, expectedData) {
   269  			t.Errorf("Unexpected content read: %s, expected %s", b, expectedData)
   270  		}
   271  	})
   272  
   273  	t.Run("Seek", func(t *testing.T) {
   274  		n, err := file.Seek(2, io.SeekStart)
   275  		if err != nil {
   276  			t.Errorf("Seek failed: %v", err)
   277  			return
   278  		}
   279  
   280  		if n != 2 {
   281  			t.Errorf("Seek returned unexpected value: %d, expected 2", n)
   282  		}
   283  	})
   284  
   285  	t.Run("Write", func(t *testing.T) {
   286  		_, err := file.Write(nil)
   287  		assertPermissionError(t, err)
   288  	})
   289  
   290  	t.Run("WriteAt", func(t *testing.T) {
   291  		_, err := file.WriteAt(nil, 0)
   292  		assertPermissionError(t, err)
   293  	})
   294  
   295  	t.Run("Name", func(t *testing.T) {
   296  		if name := file.Name(); name != "test.txt" {
   297  			t.Errorf("expected file.Name() == test.txt, got %s", name)
   298  		}
   299  	})
   300  
   301  	t.Run("Readdir", func(t *testing.T) {
   302  		t.Run("not directory", func(t *testing.T) {
   303  			_, err := file.Readdir(-1)
   304  			assertPermissionError(t, err)
   305  		})
   306  
   307  		t.Run("root directory", func(t *testing.T) {
   308  			root, err := fromIOFS.Open(".")
   309  			if err != nil {
   310  				t.Errorf("root open failed: %v", err)
   311  				return
   312  			}
   313  
   314  			defer root.Close()
   315  
   316  			items, err := root.Readdir(-1)
   317  			if err != nil {
   318  				t.Errorf("Readdir error: %v", err)
   319  				return
   320  			}
   321  
   322  			var expectedItems = []struct {
   323  				Name  string
   324  				IsDir bool
   325  				Size  int64
   326  			}{
   327  				{Name: "dir1", IsDir: true, Size: 0},
   328  				{Name: "dir2", IsDir: true, Size: 0},
   329  				{Name: "test.txt", IsDir: false, Size: int64(len(fsys["test.txt"].Data))},
   330  			}
   331  
   332  			if len(expectedItems) != len(items) {
   333  				t.Errorf("Items count mismatch, expected %d, got %d", len(expectedItems), len(items))
   334  				return
   335  			}
   336  
   337  			for i, item := range items {
   338  				if item.Name() != expectedItems[i].Name {
   339  					t.Errorf("Item %d: expected name %s, got %s", i, expectedItems[i].Name, item.Name())
   340  				}
   341  
   342  				if item.IsDir() != expectedItems[i].IsDir {
   343  					t.Errorf("Item %d: expected IsDir %t, got %t", i, expectedItems[i].IsDir, item.IsDir())
   344  				}
   345  
   346  				if item.Size() != expectedItems[i].Size {
   347  					t.Errorf("Item %d: expected IsDir %d, got %d", i, expectedItems[i].Size, item.Size())
   348  				}
   349  			}
   350  		})
   351  	})
   352  
   353  	t.Run("Readdirnames", func(t *testing.T) {
   354  		t.Run("not directory", func(t *testing.T) {
   355  			_, err := file.Readdirnames(-1)
   356  			assertPermissionError(t, err)
   357  		})
   358  
   359  		t.Run("root directory", func(t *testing.T) {
   360  			root, err := fromIOFS.Open(".")
   361  			if err != nil {
   362  				t.Errorf("root open failed: %v", err)
   363  				return
   364  			}
   365  
   366  			defer root.Close()
   367  
   368  			items, err := root.Readdirnames(-1)
   369  			if err != nil {
   370  				t.Errorf("Readdirnames error: %v", err)
   371  				return
   372  			}
   373  
   374  			var expectedItems = []string{"dir1", "dir2", "test.txt"}
   375  
   376  			if len(expectedItems) != len(items) {
   377  				t.Errorf("Items count mismatch, expected %d, got %d", len(expectedItems), len(items))
   378  				return
   379  			}
   380  
   381  			for i, item := range items {
   382  				if item != expectedItems[i] {
   383  					t.Errorf("Item %d: expected name %s, got %s", i, expectedItems[i], item)
   384  				}
   385  			}
   386  		})
   387  	})
   388  
   389  	t.Run("Truncate", func(t *testing.T) {
   390  		err := file.Truncate(1)
   391  		assertPermissionError(t, err)
   392  	})
   393  
   394  	t.Run("WriteString", func(t *testing.T) {
   395  		_, err := file.WriteString("a")
   396  		assertPermissionError(t, err)
   397  	})
   398  }
   399  
   400  func assertPermissionError(t *testing.T, err error) {
   401  	t.Helper()
   402  
   403  	var perr *fs.PathError
   404  	if !errors.As(err, &perr) {
   405  		t.Errorf("Expected *fs.PathError, got %[1]T (%[1]v)", err)
   406  		return
   407  	}
   408  
   409  	if perr.Err != fs.ErrPermission {
   410  		t.Errorf("Expected (*fs.PathError).Err == fs.ErrPermisson, got %[1]T (%[1]v)", err)
   411  	}
   412  }