1
16
17
18
19
20
21
22
23
24
25 package testfiles
26
27 import (
28 "embed"
29 "errors"
30 "fmt"
31 "io/fs"
32 "os"
33 "path"
34 "path/filepath"
35 "strings"
36 )
37
38 var filesources []FileSource
39
40
41
42
43 func AddFileSource(filesource FileSource) {
44 filesources = append(filesources, filesource)
45 }
46
47
48
49
50 type FileSource interface {
51
52
53
54
55
56
57
58 ReadTestFile(filePath string) ([]byte, error)
59
60
61
62
63
64 DescribeFiles() string
65 }
66
67
68
69 func Read(filePath string) ([]byte, error) {
70 if len(filesources) == 0 {
71 return nil, fmt.Errorf("no file sources registered (yet?), cannot retrieve test file %s", filePath)
72 }
73 for _, filesource := range filesources {
74 data, err := filesource.ReadTestFile(filePath)
75 if err != nil {
76 return nil, fmt.Errorf("fatal error retrieving test file %s: %w", filePath, err)
77 }
78 if data != nil {
79 return data, nil
80 }
81 }
82
83
84 err := fmt.Sprintf("Test file %q was not found.\n", filePath)
85 for _, filesource := range filesources {
86 err += filesource.DescribeFiles()
87 err += "\n"
88 }
89 return nil, errors.New(err)
90 }
91
92
93
94
95 func Exists(filePath string) (bool, error) {
96 for _, filesource := range filesources {
97 data, err := filesource.ReadTestFile(filePath)
98 if err != nil {
99 return false, err
100 }
101 if data != nil {
102 return true, nil
103 }
104 }
105 return false, nil
106 }
107
108
109 type RootFileSource struct {
110 Root string
111 }
112
113
114
115
116
117 func (r RootFileSource) ReadTestFile(filePath string) ([]byte, error) {
118 var fullPath string
119 if path.IsAbs(filePath) {
120 fullPath = filePath
121 } else {
122 fullPath = filepath.Join(r.Root, filePath)
123 }
124 data, err := os.ReadFile(fullPath)
125 if os.IsNotExist(err) {
126
127 return nil, nil
128 }
129 return data, err
130 }
131
132
133
134 func (r RootFileSource) DescribeFiles() string {
135 description := fmt.Sprintf("Test files are expected in %q", r.Root)
136 if !path.IsAbs(r.Root) {
137
138
139
140
141 abs, err := filepath.Abs(r.Root)
142 if err == nil {
143 description += fmt.Sprintf(" = %q", abs)
144 }
145 }
146 description += "."
147 return description
148 }
149
150
151 type EmbeddedFileSource struct {
152 EmbeddedFS embed.FS
153 Root string
154 fileList []string
155 }
156
157
158 func (e EmbeddedFileSource) ReadTestFile(filepath string) ([]byte, error) {
159 relativePath := strings.TrimPrefix(filepath, fmt.Sprintf("%s/", e.Root))
160
161 b, err := e.EmbeddedFS.ReadFile(relativePath)
162 if err != nil {
163 if errors.Is(err, fs.ErrNotExist) {
164 return nil, nil
165 }
166 return nil, err
167 }
168
169 return b, nil
170 }
171
172
173 func (e EmbeddedFileSource) DescribeFiles() string {
174 var lines []string
175 lines = append(lines, "The following files are embedded into the test executable:")
176
177 if len(e.fileList) == 0 {
178 e.populateFileList()
179 }
180 lines = append(lines, e.fileList...)
181
182 return strings.Join(lines, "\n\t")
183 }
184
185 func (e *EmbeddedFileSource) populateFileList() {
186 fs.WalkDir(e.EmbeddedFS, ".", func(path string, d fs.DirEntry, err error) error {
187 if !d.IsDir() {
188 e.fileList = append(e.fileList, filepath.Join(e.Root, path))
189 }
190
191 return nil
192 })
193 }
194
View as plain text