virtualfs_test.go 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153
  1. // Copyright (C) 2017 The Syncthing Authors.
  2. //
  3. // This Source Code Form is subject to the terms of the Mozilla Public
  4. // License, v. 2.0. If a copy of the MPL was not distributed with this file,
  5. // You can obtain one at https://mozilla.org/MPL/2.0/.
  6. package scanner
  7. import (
  8. "errors"
  9. "fmt"
  10. "io"
  11. "path/filepath"
  12. "strings"
  13. "time"
  14. "github.com/syncthing/syncthing/lib/fs"
  15. )
  16. type infiniteFS struct {
  17. fs.Filesystem
  18. width int // number of files and directories per level
  19. depth int // number of tree levels to simulate
  20. filesize int64 // size of each file in bytes
  21. }
  22. var errNotSupp = errors.New("not supported")
  23. func (i infiniteFS) Lstat(name string) (fs.FileInfo, error) {
  24. return fakeInfo{name, i.filesize}, nil
  25. }
  26. func (i infiniteFS) Stat(name string) (fs.FileInfo, error) {
  27. return fakeInfo{name, i.filesize}, nil
  28. }
  29. func (i infiniteFS) DirNames(name string) ([]string, error) {
  30. // Returns a list of fake files and directories. Names are such that
  31. // files appear before directories - this makes it so the scanner will
  32. // actually see a few files without having to reach the max depth.
  33. var names []string
  34. for j := 0; j < i.width; j++ {
  35. names = append(names, fmt.Sprintf("aa-file-%d", j))
  36. }
  37. if len(fs.PathComponents(name)) < i.depth {
  38. for j := 0; j < i.width; j++ {
  39. names = append(names, fmt.Sprintf("zz-dir-%d", j))
  40. }
  41. }
  42. return names, nil
  43. }
  44. func (i infiniteFS) Open(name string) (fs.File, error) {
  45. return &fakeFile{name, i.filesize, 0}, nil
  46. }
  47. type singleFileFS struct {
  48. fs.Filesystem
  49. name string
  50. filesize int64
  51. }
  52. func (s singleFileFS) Lstat(name string) (fs.FileInfo, error) {
  53. switch name {
  54. case ".":
  55. return fakeInfo{".", 0}, nil
  56. case s.name:
  57. return fakeInfo{s.name, s.filesize}, nil
  58. default:
  59. return nil, errors.New("no such file")
  60. }
  61. }
  62. func (s singleFileFS) Stat(name string) (fs.FileInfo, error) {
  63. switch name {
  64. case ".":
  65. return fakeInfo{".", 0}, nil
  66. case s.name:
  67. return fakeInfo{s.name, s.filesize}, nil
  68. default:
  69. return nil, errors.New("no such file")
  70. }
  71. }
  72. func (s singleFileFS) DirNames(name string) ([]string, error) {
  73. if name != "." {
  74. return nil, errors.New("no such file")
  75. }
  76. return []string{s.name}, nil
  77. }
  78. func (s singleFileFS) Open(name string) (fs.File, error) {
  79. if name != s.name {
  80. return nil, errors.New("no such file")
  81. }
  82. return &fakeFile{s.name, s.filesize, 0}, nil
  83. }
  84. func (s singleFileFS) Options() []fs.Option {
  85. return nil
  86. }
  87. type fakeInfo struct {
  88. name string
  89. size int64
  90. }
  91. func (f fakeInfo) Name() string { return f.name }
  92. func (f fakeInfo) Mode() fs.FileMode { return 0755 }
  93. func (f fakeInfo) Size() int64 { return f.size }
  94. func (f fakeInfo) ModTime() time.Time { return time.Unix(1234567890, 0) }
  95. func (f fakeInfo) IsDir() bool {
  96. return strings.Contains(filepath.Base(f.name), "dir") || f.name == "."
  97. }
  98. func (f fakeInfo) IsRegular() bool { return !f.IsDir() }
  99. func (f fakeInfo) IsSymlink() bool { return false }
  100. func (f fakeInfo) Owner() int { return 0 }
  101. func (f fakeInfo) Group() int { return 0 }
  102. type fakeFile struct {
  103. name string
  104. size int64
  105. readOffset int64
  106. }
  107. func (f *fakeFile) Name() string {
  108. return f.name
  109. }
  110. func (f *fakeFile) Read(bs []byte) (int, error) {
  111. remaining := f.size - f.readOffset
  112. if remaining == 0 {
  113. return 0, io.EOF
  114. }
  115. if remaining < int64(len(bs)) {
  116. f.readOffset = f.size
  117. return int(remaining), nil
  118. }
  119. f.readOffset += int64(len(bs))
  120. return len(bs), nil
  121. }
  122. func (f *fakeFile) Stat() (fs.FileInfo, error) {
  123. return fakeInfo{f.name, f.size}, nil
  124. }
  125. func (f *fakeFile) Write([]byte) (int, error) { return 0, errNotSupp }
  126. func (f *fakeFile) WriteAt([]byte, int64) (int, error) { return 0, errNotSupp }
  127. func (f *fakeFile) Close() error { return nil }
  128. func (f *fakeFile) Truncate(size int64) error { return errNotSupp }
  129. func (f *fakeFile) ReadAt([]byte, int64) (int, error) { return 0, errNotSupp }
  130. func (f *fakeFile) Seek(int64, int) (int64, error) { return 0, errNotSupp }
  131. func (f *fakeFile) Sync() error { return nil }