1package test 2 3import ( 4 "os" 5 "runtime" 6 7 . "gopkg.in/check.v1" 8 . "github.com/go-git/go-billy/v5" 9 "github.com/go-git/go-billy/v5/util" 10) 11 12// FilesystemSuite is a convenient test suite to validate any implementation of 13// billy.Filesystem 14type FilesystemSuite struct { 15 FS Filesystem 16 17 BasicSuite 18 DirSuite 19 SymlinkSuite 20 TempFileSuite 21 ChrootSuite 22} 23 24// NewFilesystemSuite returns a new FilesystemSuite based on the given fs. 25func NewFilesystemSuite(fs Filesystem) FilesystemSuite { 26 s := FilesystemSuite{FS: fs} 27 s.BasicSuite.FS = s.FS 28 s.DirSuite.FS = s.FS 29 s.SymlinkSuite.FS = s.FS 30 s.TempFileSuite.FS = s.FS 31 s.ChrootSuite.FS = s.FS 32 33 return s 34} 35 36func (s *FilesystemSuite) TestSymlinkToDir(c *C) { 37 if runtime.GOOS == "plan9" { 38 c.Skip("skipping on Plan 9; symlinks are not supported") 39 } 40 err := s.FS.MkdirAll("dir", 0755) 41 c.Assert(err, IsNil) 42 43 err = s.FS.Symlink("dir", "link") 44 c.Assert(err, IsNil) 45 46 fi, err := s.FS.Stat("link") 47 c.Assert(err, IsNil) 48 c.Assert(fi.Name(), Equals, "link") 49 c.Assert(fi.IsDir(), Equals, true) 50} 51 52func (s *FilesystemSuite) TestSymlinkReadDir(c *C) { 53 if runtime.GOOS == "plan9" { 54 c.Skip("skipping on Plan 9; symlinks are not supported") 55 } 56 err := util.WriteFile(s.FS, "dir/file", []byte("foo"), 0644) 57 c.Assert(err, IsNil) 58 59 err = s.FS.Symlink("dir", "link") 60 c.Assert(err, IsNil) 61 62 info, err := s.FS.ReadDir("link") 63 c.Assert(err, IsNil) 64 c.Assert(info, HasLen, 1) 65 66 c.Assert(info[0].Size(), Equals, int64(3)) 67 c.Assert(info[0].IsDir(), Equals, false) 68 c.Assert(info[0].Name(), Equals, "file") 69} 70 71func (s *FilesystemSuite) TestCreateWithExistantDir(c *C) { 72 err := s.FS.MkdirAll("foo", 0644) 73 c.Assert(err, IsNil) 74 75 f, err := s.FS.Create("foo") 76 c.Assert(err, NotNil) 77 c.Assert(f, IsNil) 78} 79 80func (s *ChrootSuite) TestReadDirWithChroot(c *C) { 81 files := []string{"foo", "bar", "qux/baz", "qux/qux"} 82 for _, name := range files { 83 err := util.WriteFile(s.FS, name, nil, 0644) 84 c.Assert(err, IsNil) 85 } 86 87 qux, _ := s.FS.Chroot("/qux") 88 89 info, err := qux.(Filesystem).ReadDir("/") 90 c.Assert(err, IsNil) 91 c.Assert(info, HasLen, 2) 92} 93 94func (s *FilesystemSuite) TestSymlinkWithChrootBasic(c *C) { 95 if runtime.GOOS == "plan9" { 96 c.Skip("skipping on Plan 9; symlinks are not supported") 97 } 98 qux, _ := s.FS.Chroot("/qux") 99 100 err := util.WriteFile(qux, "file", nil, 0644) 101 c.Assert(err, IsNil) 102 103 err = qux.(Filesystem).Symlink("file", "link") 104 c.Assert(err, IsNil) 105 106 fi, err := qux.Stat("link") 107 c.Assert(err, IsNil) 108 c.Assert(fi.Name(), Equals, "link") 109 110 fi, err = s.FS.Stat("qux/link") 111 c.Assert(err, IsNil) 112 c.Assert(fi.Name(), Equals, "link") 113} 114 115func (s *FilesystemSuite) TestSymlinkWithChrootCrossBounders(c *C) { 116 if runtime.GOOS == "plan9" { 117 c.Skip("skipping on Plan 9; symlinks are not supported") 118 } 119 qux, _ := s.FS.Chroot("/qux") 120 util.WriteFile(s.FS, "file", []byte("foo"), customMode) 121 122 err := qux.Symlink("../../file", "qux/link") 123 c.Assert(err, Equals, nil) 124 125 fi, err := qux.Stat("qux/link") 126 c.Assert(fi, NotNil) 127 c.Assert(err, Equals, nil) 128} 129 130func (s *FilesystemSuite) TestReadDirWithLink(c *C) { 131 if runtime.GOOS == "plan9" { 132 c.Skip("skipping on Plan 9; symlinks are not supported") 133 } 134 util.WriteFile(s.FS, "foo/bar", []byte("foo"), customMode) 135 s.FS.Symlink("bar", "foo/qux") 136 137 info, err := s.FS.ReadDir("/foo") 138 c.Assert(err, IsNil) 139 c.Assert(info, HasLen, 2) 140} 141 142func (s *FilesystemSuite) TestRemoveAllNonExistent(c *C) { 143 c.Assert(util.RemoveAll(s.FS, "non-existent"), IsNil) 144} 145 146func (s *FilesystemSuite) TestRemoveAllEmptyDir(c *C) { 147 c.Assert(s.FS.MkdirAll("empty", os.FileMode(0755)), IsNil) 148 c.Assert(util.RemoveAll(s.FS, "empty"), IsNil) 149 _, err := s.FS.Stat("empty") 150 c.Assert(err, NotNil) 151 c.Assert(os.IsNotExist(err), Equals, true) 152} 153 154func (s *FilesystemSuite) TestRemoveAll(c *C) { 155 fnames := []string{ 156 "foo/1", 157 "foo/2", 158 "foo/bar/1", 159 "foo/bar/2", 160 "foo/bar/baz/1", 161 "foo/bar/baz/qux/1", 162 "foo/bar/baz/qux/2", 163 "foo/bar/baz/qux/3", 164 } 165 166 for _, fname := range fnames { 167 err := util.WriteFile(s.FS, fname, nil, 0644) 168 c.Assert(err, IsNil) 169 } 170 171 c.Assert(util.RemoveAll(s.FS, "foo"), IsNil) 172 173 for _, fname := range fnames { 174 _, err := s.FS.Stat(fname) 175 comment := Commentf("not removed: %s %s", fname, err) 176 c.Assert(os.IsNotExist(err), Equals, true, comment) 177 } 178} 179 180func (s *FilesystemSuite) TestRemoveAllRelative(c *C) { 181 fnames := []string{ 182 "foo/1", 183 "foo/2", 184 "foo/bar/1", 185 "foo/bar/2", 186 "foo/bar/baz/1", 187 "foo/bar/baz/qux/1", 188 "foo/bar/baz/qux/2", 189 "foo/bar/baz/qux/3", 190 } 191 192 for _, fname := range fnames { 193 err := util.WriteFile(s.FS, fname, nil, 0644) 194 c.Assert(err, IsNil) 195 } 196 197 c.Assert(util.RemoveAll(s.FS, "foo/bar/.."), IsNil) 198 199 for _, fname := range fnames { 200 _, err := s.FS.Stat(fname) 201 comment := Commentf("not removed: %s %s", fname, err) 202 c.Assert(os.IsNotExist(err), Equals, true, comment) 203 } 204} 205 206func (s *FilesystemSuite) TestReadDir(c *C) { 207 err := s.FS.MkdirAll("qux", 0755) 208 c.Assert(err, IsNil) 209 210 files := []string{"foo", "bar", "qux/baz", "qux/qux"} 211 for _, name := range files { 212 err := util.WriteFile(s.FS, name, nil, 0644) 213 c.Assert(err, IsNil) 214 } 215 216 info, err := s.FS.ReadDir("/") 217 c.Assert(err, IsNil) 218 c.Assert(info, HasLen, 3) 219 220 info, err = s.FS.ReadDir("/qux") 221 c.Assert(err, IsNil) 222 c.Assert(info, HasLen, 2) 223} 224