1package test
2
3import (
4	"io/ioutil"
5	"os"
6
7	. "gopkg.in/check.v1"
8	. "gopkg.in/src-d/go-billy.v3"
9	"gopkg.in/src-d/go-billy.v3/util"
10)
11
12// SymlinkSuite is a convenient test suite to validate any implementation of
13// billy.Symlink
14type SymlinkSuite struct {
15	FS interface {
16		Basic
17		Symlink
18	}
19}
20
21func (s *SymlinkSuite) TestSymlink(c *C) {
22	err := util.WriteFile(s.FS, "file", nil, 0644)
23	c.Assert(err, IsNil)
24
25	err = s.FS.Symlink("file", "link")
26	c.Assert(err, IsNil)
27
28	fi, err := s.FS.Stat("link")
29	c.Assert(err, IsNil)
30	c.Assert(fi.Name(), Equals, "link")
31}
32
33func (s *SymlinkSuite) TestSymlinkCrossDirs(c *C) {
34	err := util.WriteFile(s.FS, "foo/file", nil, 0644)
35	c.Assert(err, IsNil)
36
37	err = s.FS.Symlink("../foo/file", "bar/link")
38	c.Assert(err, IsNil)
39
40	fi, err := s.FS.Stat("bar/link")
41	c.Assert(err, IsNil)
42	c.Assert(fi.Name(), Equals, "link")
43}
44
45func (s *SymlinkSuite) TestSymlinkNested(c *C) {
46	err := util.WriteFile(s.FS, "file", []byte("hello world!"), 0644)
47	c.Assert(err, IsNil)
48
49	err = s.FS.Symlink("file", "linkA")
50	c.Assert(err, IsNil)
51
52	err = s.FS.Symlink("linkA", "linkB")
53	c.Assert(err, IsNil)
54
55	fi, err := s.FS.Stat("linkB")
56	c.Assert(err, IsNil)
57	c.Assert(fi.Name(), Equals, "linkB")
58	c.Assert(fi.Size(), Equals, int64(12))
59}
60
61func (s *SymlinkSuite) TestSymlinkWithNonExistentdTarget(c *C) {
62	err := s.FS.Symlink("file", "link")
63	c.Assert(err, IsNil)
64
65	_, err = s.FS.Stat("link")
66	c.Assert(os.IsNotExist(err), Equals, true)
67}
68
69func (s *SymlinkSuite) TestSymlinkWithExistingLink(c *C) {
70	err := util.WriteFile(s.FS, "link", nil, 0644)
71	c.Assert(err, IsNil)
72
73	err = s.FS.Symlink("file", "link")
74	c.Assert(err, Not(IsNil))
75}
76
77func (s *SymlinkSuite) TestOpenWithSymlinkToRelativePath(c *C) {
78	err := util.WriteFile(s.FS, "dir/file", []byte("foo"), 0644)
79	c.Assert(err, IsNil)
80
81	err = s.FS.Symlink("file", "dir/link")
82	c.Assert(err, IsNil)
83
84	f, err := s.FS.Open("dir/link")
85	c.Assert(err, IsNil)
86
87	all, err := ioutil.ReadAll(f)
88	c.Assert(err, IsNil)
89	c.Assert(string(all), Equals, "foo")
90	c.Assert(f.Close(), IsNil)
91}
92
93func (s *SymlinkSuite) TestOpenWithSymlinkToAbsolutePath(c *C) {
94	err := util.WriteFile(s.FS, "dir/file", []byte("foo"), 0644)
95	c.Assert(err, IsNil)
96
97	err = s.FS.Symlink("/dir/file", "dir/link")
98	c.Assert(err, IsNil)
99
100	f, err := s.FS.Open("dir/link")
101	c.Assert(err, IsNil)
102
103	all, err := ioutil.ReadAll(f)
104	c.Assert(err, IsNil)
105	c.Assert(string(all), Equals, "foo")
106	c.Assert(f.Close(), IsNil)
107}
108
109func (s *SymlinkSuite) TestReadlink(c *C) {
110	err := util.WriteFile(s.FS, "file", nil, 0644)
111	c.Assert(err, IsNil)
112
113	_, err = s.FS.Readlink("file")
114	c.Assert(err, Not(IsNil))
115}
116
117func (s *SymlinkSuite) TestReadlinkWithRelativePath(c *C) {
118	err := util.WriteFile(s.FS, "dir/file", nil, 0644)
119	c.Assert(err, IsNil)
120
121	err = s.FS.Symlink("file", "dir/link")
122	c.Assert(err, IsNil)
123
124	oldname, err := s.FS.Readlink("dir/link")
125	c.Assert(err, IsNil)
126	c.Assert(oldname, Equals, "file")
127}
128
129func (s *SymlinkSuite) TestReadlinkWithAbsolutePath(c *C) {
130	err := util.WriteFile(s.FS, "dir/file", nil, 0644)
131	c.Assert(err, IsNil)
132
133	err = s.FS.Symlink("/dir/file", "dir/link")
134	c.Assert(err, IsNil)
135
136	oldname, err := s.FS.Readlink("dir/link")
137	c.Assert(err, IsNil)
138	c.Assert(oldname, Equals, expectedSymlinkTarget)
139}
140
141func (s *SymlinkSuite) TestReadlinkWithNonExistentTarget(c *C) {
142	err := s.FS.Symlink("file", "link")
143	c.Assert(err, IsNil)
144
145	oldname, err := s.FS.Readlink("link")
146	c.Assert(err, IsNil)
147	c.Assert(oldname, Equals, "file")
148}
149
150func (s *SymlinkSuite) TestReadlinkWithNonExistentLink(c *C) {
151	_, err := s.FS.Readlink("link")
152	c.Assert(os.IsNotExist(err), Equals, true)
153}
154
155func (s *SymlinkSuite) TestStatLink(c *C) {
156	util.WriteFile(s.FS, "foo/bar", []byte("foo"), customMode)
157	s.FS.Symlink("bar", "foo/qux")
158
159	fi, err := s.FS.Stat("foo/qux")
160	c.Assert(err, IsNil)
161	c.Assert(fi.Name(), Equals, "qux")
162	c.Assert(fi.Size(), Equals, int64(3))
163	c.Assert(fi.Mode(), Equals, customMode)
164	c.Assert(fi.ModTime().IsZero(), Equals, false)
165	c.Assert(fi.IsDir(), Equals, false)
166}
167
168func (s *SymlinkSuite) TestLstat(c *C) {
169	util.WriteFile(s.FS, "foo/bar", []byte("foo"), customMode)
170
171	fi, err := s.FS.Lstat("foo/bar")
172	c.Assert(err, IsNil)
173	c.Assert(fi.Name(), Equals, "bar")
174	c.Assert(fi.Size(), Equals, int64(3))
175	c.Assert(fi.Mode()&os.ModeSymlink != 0, Equals, false)
176	c.Assert(fi.ModTime().IsZero(), Equals, false)
177	c.Assert(fi.IsDir(), Equals, false)
178}
179
180func (s *SymlinkSuite) TestLstatLink(c *C) {
181	util.WriteFile(s.FS, "foo/bar", []byte("fosddddaaao"), customMode)
182	s.FS.Symlink("bar", "foo/qux")
183
184	fi, err := s.FS.Lstat("foo/qux")
185	c.Assert(err, IsNil)
186	c.Assert(fi.Name(), Equals, "qux")
187	c.Assert(fi.Mode()&os.ModeSymlink != 0, Equals, true)
188	c.Assert(fi.ModTime().IsZero(), Equals, false)
189	c.Assert(fi.IsDir(), Equals, false)
190}
191
192func (s *SymlinkSuite) TestRenameWithSymlink(c *C) {
193	err := s.FS.Symlink("file", "link")
194	c.Assert(err, IsNil)
195
196	err = s.FS.Rename("link", "newlink")
197	c.Assert(err, IsNil)
198
199	_, err = s.FS.Readlink("newlink")
200	c.Assert(err, IsNil)
201}
202
203func (s *SymlinkSuite) TestRemoveWithSymlink(c *C) {
204	err := util.WriteFile(s.FS, "file", []byte("foo"), 0644)
205	c.Assert(err, IsNil)
206
207	err = s.FS.Symlink("file", "link")
208	c.Assert(err, IsNil)
209
210	err = s.FS.Remove("link")
211	c.Assert(err, IsNil)
212
213	_, err = s.FS.Readlink("link")
214	c.Assert(os.IsNotExist(err), Equals, true)
215
216	_, err = s.FS.Stat("link")
217	c.Assert(os.IsNotExist(err), Equals, true)
218
219	_, err = s.FS.Stat("file")
220	c.Assert(err, IsNil)
221}
222