1
2 package tarfs
3
4 import (
5 "archive/tar"
6 "errors"
7 "fmt"
8 "io"
9 "os"
10 "path/filepath"
11 "reflect"
12 "strings"
13 "syscall"
14 "testing"
15
16 "github.com/spf13/afero"
17 )
18
19 var files = []struct {
20 name string
21 exists bool
22 isdir bool
23 size int64
24 content string
25 contentAt4k string
26 }{
27 {"/", true, true, 0, "", ""},
28 {"/sub", true, true, 0, "", ""},
29 {"/sub/testDir2", true, true, 0, "", ""},
30 {"/sub/testDir2/testFile", true, false, 8192, "cccccccc", "ccccdddd"},
31 {"/testFile", true, false, 8192, "aaaaaaaa", "aaaabbbb"},
32 {"/testDir1/testFile", true, false, 8192, "bbbbbbbb", "bbbbcccc"},
33
34 {"/nonExisting", false, false, 0, "", ""},
35 }
36
37 var dirs = []struct {
38 name string
39 children []string
40 }{
41 {"/", []string{"sub", "testDir1", "testFile"}},
42 {"/sub", []string{"testDir2"}},
43 {"/sub/testDir2", []string{"testFile"}},
44 {"/testDir1", []string{"testFile"}},
45 }
46
47 var afs *afero.Afero
48
49 func TestMain(m *testing.M) {
50 tf, err := os.Open("testdata/t.tar")
51 if err != nil {
52 fmt.Print(err)
53 os.Exit(1)
54 }
55
56 tfs := New(tar.NewReader(tf))
57 afs = &afero.Afero{Fs: tfs}
58
59
60 _ = New(tar.NewReader(strings.NewReader("")))
61 os.Exit(m.Run())
62 }
63
64 func TestFsOpen(t *testing.T) {
65 for _, f := range files {
66 file, err := afs.Open(f.name)
67 if (err == nil) != f.exists {
68 t.Errorf("%v exists = %v, but got err = %v", f.name, f.exists, err)
69 }
70
71 if !f.exists {
72 continue
73 }
74 if err != nil {
75 t.Fatalf("%v: %v", f.name, err)
76 }
77
78 if file.Name() != filepath.FromSlash(f.name) {
79 t.Errorf("Name(), got %v, expected %v", file.Name(), filepath.FromSlash(f.name))
80 }
81
82 s, err := file.Stat()
83 if err != nil {
84 t.Fatalf("stat %v: got error '%v'", file.Name(), err)
85 }
86
87 if isdir := s.IsDir(); isdir != f.isdir {
88 t.Errorf("%v directory, got: %v, expected: %v", file.Name(), isdir, f.isdir)
89 }
90
91 if size := s.Size(); size != f.size {
92 t.Errorf("%v size, got: %v, expected: %v", file.Name(), size, f.size)
93 }
94 }
95 }
96
97 func TestRead(t *testing.T) {
98 for _, f := range files {
99 if !f.exists {
100 continue
101 }
102
103 file, err := afs.Open(f.name)
104 if err != nil {
105 t.Fatalf("opening %v: %v", f.name, err)
106 }
107
108 buf := make([]byte, 8)
109 n, err := file.Read(buf)
110 if err != nil {
111 if f.isdir && (err != syscall.EISDIR) {
112 t.Errorf("%v got error %v, expected EISDIR", f.name, err)
113 } else if !f.isdir {
114 t.Errorf("%v: %v", f.name, err)
115 }
116 } else if n != 8 {
117 t.Errorf("%v: got %d read bytes, expected 8", f.name, n)
118 } else if string(buf) != f.content {
119 t.Errorf("%v: got <%s>, expected <%s>", f.name, f.content, string(buf))
120 }
121
122 }
123 }
124
125 func TestReadAt(t *testing.T) {
126 for _, f := range files {
127 if !f.exists {
128 continue
129 }
130
131 file, err := afs.Open(f.name)
132 if err != nil {
133 t.Fatalf("opening %v: %v", f.name, err)
134 }
135
136 buf := make([]byte, 8)
137 n, err := file.ReadAt(buf, 4092)
138 if err != nil {
139 if f.isdir && (err != syscall.EISDIR) {
140 t.Errorf("%v got error %v, expected EISDIR", f.name, err)
141 } else if !f.isdir {
142 t.Errorf("%v: %v", f.name, err)
143 }
144 } else if n != 8 {
145 t.Errorf("%v: got %d read bytes, expected 8", f.name, n)
146 } else if string(buf) != f.contentAt4k {
147 t.Errorf("%v: got <%s>, expected <%s>", f.name, f.contentAt4k, string(buf))
148 }
149
150 }
151 }
152
153 func TestSeek(t *testing.T) {
154 for _, f := range files {
155 if !f.exists {
156 continue
157 }
158
159 file, err := afs.Open(f.name)
160 if err != nil {
161 t.Fatalf("opening %v: %v", f.name, err)
162 }
163
164 tests := []struct {
165 offin int64
166 whence int
167 offout int64
168 }{
169 {0, io.SeekStart, 0},
170 {10, io.SeekStart, 10},
171 {1, io.SeekCurrent, 11},
172 {10, io.SeekCurrent, 21},
173 {0, io.SeekEnd, f.size},
174 {-1, io.SeekEnd, f.size - 1},
175 }
176
177 for _, s := range tests {
178 n, err := file.Seek(s.offin, s.whence)
179 if err != nil {
180 if f.isdir && err == syscall.EISDIR {
181 continue
182 }
183
184 t.Errorf("%v: %v", f.name, err)
185 }
186
187 if n != s.offout {
188 t.Errorf("%v: (off: %v, whence: %v): got %v, expected %v", f.name, s.offin, s.whence, n, s.offout)
189 }
190 }
191
192 }
193 }
194
195 func TestName(t *testing.T) {
196 for _, f := range files {
197 if !f.exists {
198 continue
199 }
200
201 file, err := afs.Open(f.name)
202 if err != nil {
203 t.Fatalf("opening %v: %v", f.name, err)
204 }
205
206 n := file.Name()
207 if n != filepath.FromSlash(f.name) {
208 t.Errorf("got: %v, expected: %v", n, filepath.FromSlash(f.name))
209 }
210
211 }
212 }
213
214 func TestClose(t *testing.T) {
215 for _, f := range files {
216 if !f.exists {
217 continue
218 }
219
220 file, err := afs.Open(f.name)
221 if err != nil {
222 t.Fatalf("opening %v: %v", f.name, err)
223 }
224
225 err = file.Close()
226 if err != nil {
227 t.Errorf("%v: %v", f.name, err)
228 }
229
230 err = file.Close()
231 if err == nil {
232 t.Errorf("%v: closing twice should return an error", f.name)
233 }
234
235 buf := make([]byte, 8)
236 n, err := file.Read(buf)
237 if n != 0 || err == nil {
238 t.Errorf("%v: could read from a closed file", f.name)
239 }
240
241 n, err = file.ReadAt(buf, 256)
242 if n != 0 || err == nil {
243 t.Errorf("%v: could readAt from a closed file", f.name)
244 }
245
246 off, err := file.Seek(0, io.SeekStart)
247 if off != 0 || err == nil {
248 t.Errorf("%v: could seek from a closed file", f.name)
249 }
250 }
251 }
252
253 func TestOpenFile(t *testing.T) {
254 for _, f := range files {
255 file, err := afs.OpenFile(f.name, os.O_RDONLY, 0o400)
256 if !f.exists {
257 if !errors.Is(err, syscall.ENOENT) {
258 t.Errorf("%v: got %v, expected%v", f.name, err, syscall.ENOENT)
259 }
260
261 continue
262 }
263
264 if err != nil {
265 t.Fatalf("%v: %v", f.name, err)
266 }
267 file.Close()
268
269 _, err = afs.OpenFile(f.name, os.O_CREATE, 0o600)
270 if !errors.Is(err, syscall.EPERM) {
271 t.Errorf("%v: open for write: got %v, expected %v", f.name, err, syscall.EPERM)
272 }
273
274 }
275 }
276
277 func TestFsStat(t *testing.T) {
278 for _, f := range files {
279 fi, err := afs.Stat(f.name)
280 if !f.exists {
281 if !errors.Is(err, syscall.ENOENT) {
282 t.Errorf("%v: got %v, expected%v", f.name, err, syscall.ENOENT)
283 }
284
285 continue
286 }
287
288 if err != nil {
289 t.Fatalf("stat %v: got error '%v'", f.name, err)
290 }
291
292 if isdir := fi.IsDir(); isdir != f.isdir {
293 t.Errorf("%v directory, got: %v, expected: %v", f.name, isdir, f.isdir)
294 }
295
296 if size := fi.Size(); size != f.size {
297 t.Errorf("%v size, got: %v, expected: %v", f.name, size, f.size)
298 }
299 }
300 }
301
302 func TestReaddir(t *testing.T) {
303 for _, d := range dirs {
304 dir, err := afs.Open(d.name)
305 if err != nil {
306 t.Fatal(err)
307 }
308
309 fi, err := dir.Readdir(0)
310 if err != nil {
311 t.Fatal(err)
312 }
313 var names []string
314 for _, f := range fi {
315 names = append(names, f.Name())
316 }
317
318 if !reflect.DeepEqual(names, d.children) {
319 t.Errorf("%v: children, got '%v', expected '%v'", d.name, names, d.children)
320 }
321
322 fi, err = dir.Readdir(1)
323 if err != nil {
324 t.Fatal(err)
325 }
326
327 names = []string{}
328 for _, f := range fi {
329 names = append(names, f.Name())
330 }
331
332 if !reflect.DeepEqual(names, d.children[0:1]) {
333 t.Errorf("%v: children, got '%v', expected '%v'", d.name, names, d.children[0:1])
334 }
335 }
336
337 dir, err := afs.Open("/testFile")
338 if err != nil {
339 t.Fatal(err)
340 }
341
342 _, err = dir.Readdir(-1)
343 if err != syscall.ENOTDIR {
344 t.Fatal("Expected error")
345 }
346 }
347
348 func TestReaddirnames(t *testing.T) {
349 for _, d := range dirs {
350 dir, err := afs.Open(d.name)
351 if err != nil {
352 t.Fatal(err)
353 }
354
355 names, err := dir.Readdirnames(0)
356 if err != nil {
357 t.Fatal(err)
358 }
359
360 if !reflect.DeepEqual(names, d.children) {
361 t.Errorf("%v: children, got '%v', expected '%v'", d.name, names, d.children)
362 }
363
364 names, err = dir.Readdirnames(1)
365 if err != nil {
366 t.Fatal(err)
367 }
368
369 if !reflect.DeepEqual(names, d.children[0:1]) {
370 t.Errorf("%v: children, got '%v', expected '%v'", d.name, names, d.children[0:1])
371 }
372 }
373
374 dir, err := afs.Open("/testFile")
375 if err != nil {
376 t.Fatal(err)
377 }
378
379 _, err = dir.Readdir(-1)
380 if err != syscall.ENOTDIR {
381 t.Fatal("Expected error")
382 }
383 }
384
385 func TestGlob(t *testing.T) {
386 for _, s := range []struct {
387 glob string
388 entries []string
389 }{
390 {filepath.FromSlash("/*"), []string{filepath.FromSlash("/sub"), filepath.FromSlash("/testDir1"), filepath.FromSlash("/testFile")}},
391 {filepath.FromSlash("*"), []string{filepath.FromSlash("sub"), filepath.FromSlash("testDir1"), filepath.FromSlash("testFile")}},
392 {filepath.FromSlash("sub/*"), []string{filepath.FromSlash("sub/testDir2")}},
393 {filepath.FromSlash("sub/testDir2/*"), []string{filepath.FromSlash("sub/testDir2/testFile")}},
394 {filepath.FromSlash("testDir1/*"), []string{filepath.FromSlash("testDir1/testFile")}},
395 } {
396 entries, err := afero.Glob(afs.Fs, s.glob)
397 if err != nil {
398 t.Error(err)
399 }
400 if reflect.DeepEqual(entries, s.entries) {
401 t.Logf("glob: %s: glob ok", s.glob)
402 } else {
403 t.Errorf("glob: %s: got %#v, expected %#v", s.glob, entries, s.entries)
404 }
405 }
406 }
407
View as plain text