1 /*
2 * Copyright (c) 2020 Nordic Semiconductor ASA
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 /*
8 * @filesystem
9 * @brief test_filesystem
10 * Tests the fs_open flags
11 */
12
13 #include <zephyr.h>
14 #include <ztest.h>
15 #include <fs/fs.h>
16 #include <string.h>
17
18 /* Path for testr file should be provided by test runner and should start
19 * with mount point.
20 */
21 extern char *test_fs_open_flags_file_path;
22
23 static const char something[] = "Something";
24 static char buffer[sizeof(something)];
25 #define RDWR_SIZE sizeof(something)
26
27 struct test_state {
28 /* Path to file */
29 char *file_path;
30 struct fs_file_t file;
31 /* Read write buffer info */
32 const char *write;
33 int write_size;
34 char *read;
35 int read_size;
36 };
37
38 /* ZEQ decides whether test completed successfully and prints appropriate
39 * information.
40 */
ZEQ(int ret,int expected)41 static void ZEQ(int ret, int expected)
42 {
43 zassert_equal(ret, expected,
44 "FAILED: expected = %d, ret = %d, errno = %d\n",
45 expected, ret, errno);
46 TC_PRINT("SUCCESS\n");
47 }
48
49 /* NOTE: Below functions have C preprocessor redefinitions that automatically
50 * fill in the line parameter, so when invoking, do not provide the line
51 * parameter.
52 */
53
54 /* Test fs_open, expected is the return value expected from fs_open */
ZOPEN(struct test_state * ts,int flags,int expected,int line)55 static void ZOPEN(struct test_state *ts, int flags, int expected, int line)
56 {
57 TC_PRINT("# %d: OPEN %s with flags %x\n", line, ts->file_path, flags);
58 ZEQ(fs_open(&ts->file, ts->file_path, flags), expected);
59 }
60
61 /* Close file. Will automatically fail test case if unsuccessful. */
ZCLOSE(struct test_state * ts,int line)62 static void ZCLOSE(struct test_state *ts, int line)
63 {
64 TC_PRINT("# %d: CLOSE %s\n", line, ts->file_path);
65 ZEQ(fs_close(&ts->file), 0);
66 }
67
68 /* Attempt to write to file; expected is what fs_write is supposed to return */
ZWRITE(struct test_state * ts,int expected,int line)69 static void ZWRITE(struct test_state *ts, int expected, int line)
70 {
71 TC_PRINT("# %d: WRITE %s\n", line, ts->file_path);
72 ZEQ(fs_write(&ts->file, ts->write, ts->write_size), expected);
73 }
74
75 /* Attempt to read from file; expected is what fs_read is supposed to return */
ZREAD(struct test_state * ts,int expected,int line)76 static void ZREAD(struct test_state *ts, int expected, int line)
77 {
78 TC_PRINT("# %d: READ %s\n", line, ts->file_path);
79 ZEQ(fs_read(&ts->file, ts->read, ts->read_size), expected);
80 }
81
82 /* Unlink/delete file. Will automatically fail test case if unsuccessful. */
ZUNLINK(struct test_state * ts,int line)83 static void ZUNLINK(struct test_state *ts, int line)
84 {
85 int ret;
86
87 TC_PRINT("# %d: UNLINK %s\n", line, ts->file_path);
88 ret = fs_unlink(ts->file_path);
89 zassert((ret == 0 || ret == -ENOENT), "Done", "Failed");
90 TC_PRINT("SUCCESS\n");
91 }
92
93 /* Check file position; expected is a position file should be at. */
ZCHKPOS(struct test_state * ts,off_t expected,int line)94 static void ZCHKPOS(struct test_state *ts, off_t expected, int line)
95 {
96 TC_PRINT("# %d: CHKPOS\n", line);
97 ZEQ(fs_tell(&ts->file), expected);
98 }
99
100 /* Rewind file. */
ZREWIND(struct test_state * ts,int line)101 static void ZREWIND(struct test_state *ts, int line)
102 {
103 TC_PRINT("# %d: REWIND\n", line);
104 ZEQ(fs_seek(&ts->file, 0, FS_SEEK_SET), 0);
105 }
106
107 /* Banner definitions, print BEGIN/END banner with block number.
108 * Require definition of block variable with vale that will represent first
109 * test block number; the variable is automatically incremented by END.
110 */
111 #define ZBEGIN(info) \
112 TC_PRINT("\n## BEGIN %d: %s (line %d)\n", block, info, __LINE__)
113 #define ZEND() TC_PRINT("## END %d\n", block++)
114
115 /* C preprocessor redefinitions that automatically fill in line parameter */
116 #define ZOPEN(ts, flags, expected) ZOPEN(ts, flags, expected, __LINE__)
117 #define ZCLOSE(ts) ZCLOSE(ts, __LINE__)
118 #define ZWRITE(ts, expected) ZWRITE(ts, expected, __LINE__)
119 #define ZREAD(ts, expected) ZREAD(ts, expected, __LINE__)
120 #define ZUNLINK(ts) ZUNLINK(ts, __LINE__)
121 #define ZCHKPOS(ts, expected) ZCHKPOS(ts, expected, __LINE__)
122 #define ZREWIND(ts) ZREWIND(ts, __LINE__)
123
124 /* Create empty file */
125 #define ZMKEMPTY(ts) \
126 do { \
127 ZUNLINK(ts); \
128 ZOPEN(ts, FS_O_CREATE, 0); \
129 ZCLOSE(ts); \
130 } while (0)
131
test_fs_open_flags(void)132 void test_fs_open_flags(void)
133 {
134 struct test_state ts = {
135 *&test_fs_open_flags_file_path,
136 { 0 },
137 something,
138 RDWR_SIZE,
139 buffer,
140 RDWR_SIZE,
141 };
142 int block = 1;
143
144 fs_file_t_init(&ts.file);
145
146 ZBEGIN("Attempt open non-existent");
147 ZOPEN(&ts, 0, -ENOENT);
148 ZOPEN(&ts, FS_O_WRITE, -ENOENT);
149 ZOPEN(&ts, FS_O_READ, -ENOENT);
150 ZOPEN(&ts, FS_O_RDWR, -ENOENT);
151 ZOPEN(&ts, FS_O_APPEND, -ENOENT);
152 ZOPEN(&ts, FS_O_APPEND | FS_O_READ, -ENOENT);
153 ZOPEN(&ts, FS_O_APPEND | FS_O_WRITE, -ENOENT);
154 ZOPEN(&ts, FS_O_APPEND | FS_O_RDWR, -ENOENT);
155 ZEND();
156
157
158 /* Attempt create new file with no read/write access and check
159 * operations on it.
160 */
161 ZBEGIN("Attempt create new with no R/W access");
162 #ifndef BYPASS_FS_OPEN_FLAGS_LFS_ASSERT_CRASH
163 ZOPEN(&ts, FS_O_CREATE | 0, 0);
164 ZWRITE(&ts, -EACCES);
165 ZREAD(&ts, -EACCES);
166 ZCLOSE(&ts);
167 ZUNLINK(&ts);
168 #else
169 TC_PRINT("Bypassed test\n");
170 #endif
171 ZEND();
172
173
174 ZBEGIN("Attempt create new with READ access");
175 ZOPEN(&ts, FS_O_CREATE | FS_O_READ, 0);
176 #ifndef BYPASS_FS_OPEN_FLAGS_LFS_ASSERT_CRASH
177 ZWRITE(&ts, -EACCES);
178 #else
179 TC_PRINT("Write bypassed\n");
180 #endif
181 ZREAD(&ts, 0);
182 ZCLOSE(&ts);
183 ZUNLINK(&ts);
184 ZEND();
185
186
187 ZBEGIN("Attempt create new with WRITE access");
188 ZOPEN(&ts, FS_O_CREATE | FS_O_WRITE, 0);
189 ZWRITE(&ts, ts.write_size);
190 #ifndef BYPASS_FS_OPEN_FLAGS_LFS_ASSERT_CRASH
191 ZREAD(&ts, -EACCES);
192 #else
193 TC_PRINT("Read bypassed\n");
194 #endif
195 ZCLOSE(&ts);
196 ZUNLINK(&ts);
197 ZEND();
198
199
200 ZBEGIN("Attempt create new with R/W access");
201 ZOPEN(&ts, FS_O_CREATE | FS_O_RDWR, 0);
202 ZWRITE(&ts, ts.write_size);
203 /* Read is done at the end of file, so 0 bytes will be read */
204 ZREAD(&ts, 0);
205 ZCLOSE(&ts);
206 ZUNLINK(&ts);
207 ZEND();
208
209
210 ZBEGIN("Attempt open existing with no R/W access");
211 ZMKEMPTY(&ts);
212 #ifndef BYPASS_FS_OPEN_FLAGS_LFS_RW_IS_DEFAULT
213 ZOPEN(&ts, 0, 0);
214 ZWRITE(&ts, -EACCES);
215 ZREAD(&ts, -EACCES);
216 ZCLOSE(&ts);
217 #else
218 TC_PRINT("Bypassed test\n");
219 #endif
220 ZUNLINK(&ts);
221 ZEND();
222
223
224 ZBEGIN("Attempt open existing with READ access");
225 ZMKEMPTY(&ts);
226 ZOPEN(&ts, FS_O_READ, 0);
227 #ifndef BYPASS_FS_OPEN_FLAGS_LFS_ASSERT_CRASH
228 ZWRITE(&ts, -EACCES);
229 #else
230 TC_PRINT("Write bypassed\n");
231 #endif
232 /* File is empty */
233 ZREAD(&ts, 0);
234 ZCLOSE(&ts);
235 ZUNLINK(&ts);
236 ZEND();
237
238
239 ZBEGIN("Attempt open existing with WRITE access");
240 ZMKEMPTY(&ts);
241 ZOPEN(&ts, FS_O_WRITE, 0);
242 ZCHKPOS(&ts, 0);
243 ZWRITE(&ts, ts.write_size);
244 #ifndef BYPASS_FS_OPEN_FLAGS_LFS_ASSERT_CRASH
245 ZREAD(&ts, -EACCES);
246 #else
247 TC_PRINT("Read bypassed\n");
248 #endif
249 ZCLOSE(&ts);
250 ZUNLINK(&ts);
251 ZEND();
252
253
254 ZBEGIN("Attempt open existing with R/W access");
255 ZMKEMPTY(&ts);
256 ZOPEN(&ts, FS_O_RDWR, 0);
257 ZWRITE(&ts, ts.write_size);
258 /* Read is done at the end of file, so 0 bytes will be read */
259 ZREAD(&ts, 0);
260 ZCLOSE(&ts);
261 ZUNLINK(&ts);
262 ZEND();
263
264
265 ZBEGIN("Attempt append existing with no R/W access");
266 ZMKEMPTY(&ts);
267 #ifndef BYPASS_FS_OPEN_FLAGS_LFS_RW_IS_DEFAULT
268 ZOPEN(&ts, FS_O_APPEND, 0);
269 ZCHKPOS(&ts, 0);
270 ZWRITE(&ts, -EACCES);
271 ZREAD(&ts, -EACCES);
272 ZCLOSE(&ts);
273 #else
274 TC_PRINT("Test bypassed\n");
275 #endif
276 ZUNLINK(&ts);
277 ZEND();
278
279
280 ZBEGIN("Attempt append existing with READ access");
281 ZMKEMPTY(&ts);
282 ZOPEN(&ts, FS_O_APPEND | FS_O_READ, 0);
283 ZCHKPOS(&ts, 0);
284 #ifndef BYPASS_FS_OPEN_FLAGS_LFS_ASSERT_CRASH
285 ZWRITE(&ts, -EACCES);
286 #else
287 TC_PRINT("Write bypassed\n");
288 #endif
289 /* File is empty */
290 ZREAD(&ts, 0);
291 ZCLOSE(&ts);
292 ZUNLINK(&ts);
293 ZEND();
294
295
296 ZBEGIN("Attempt append existing with WRITE access");
297 ZMKEMPTY(&ts);
298 ZOPEN(&ts, FS_O_APPEND | FS_O_WRITE, 0);
299 ZCHKPOS(&ts, 0);
300 ZWRITE(&ts, ts.write_size);
301 #ifndef BYPASS_FS_OPEN_FLAGS_LFS_ASSERT_CRASH
302 ZREAD(&ts, -EACCES);
303 #else
304 TC_PRINT("Read bypassed\n");
305 #endif
306 ZCLOSE(&ts);
307 ZUNLINK(&ts);
308 ZEND();
309
310
311 ZBEGIN("Attempt append existing with R/W access");
312 ZMKEMPTY(&ts);
313 ZOPEN(&ts, FS_O_APPEND | FS_O_RDWR, 0);
314 ZCHKPOS(&ts, 0);
315 ZWRITE(&ts, ts.write_size);
316 /* Read is done at the end of file, so 0 bytes will be read */
317 ZREAD(&ts, 0);
318 ZCLOSE(&ts);
319 ZUNLINK(&ts);
320 ZEND();
321
322
323 /* This is simple check by file position, not contents. Since writing
324 * same pattern twice, the position of file should be twice the
325 * ts.write_size.
326 */
327 ZBEGIN("Check if append adds data to file");
328 /* Prepare file */
329 ZUNLINK(&ts);
330 ZOPEN(&ts, FS_O_CREATE | FS_O_WRITE, 0);
331 ZWRITE(&ts, ts.write_size);
332 ZCLOSE(&ts);
333
334 ZOPEN(&ts, FS_O_APPEND | FS_O_WRITE, 0);
335 ZCHKPOS(&ts, 0);
336 ZWRITE(&ts, ts.write_size);
337 ZCHKPOS(&ts, ts.write_size * 2);
338 ZCLOSE(&ts);
339 ZUNLINK(&ts);
340 ZEND();
341
342
343 ZBEGIN("Check if appended forwards file before write");
344 /* Prepare file */
345 ZUNLINK(&ts);
346 ZOPEN(&ts, FS_O_CREATE | FS_O_WRITE, 0);
347 ZWRITE(&ts, ts.write_size);
348 ZCLOSE(&ts);
349
350 ZOPEN(&ts, FS_O_APPEND | FS_O_WRITE, 0);
351 ZCHKPOS(&ts, 0);
352 ZREWIND(&ts);
353 ZWRITE(&ts, ts.write_size);
354 ZCHKPOS(&ts, ts.write_size * 2);
355 ZCLOSE(&ts);
356 ZUNLINK(&ts);
357 ZEND();
358 }
359