1
2[[case]] # simple file test
3code = '''
4    lfs_format(&lfs, &cfg) => 0;
5    lfs_mount(&lfs, &cfg) => 0;
6    lfs_file_open(&lfs, &file, "hello",
7            LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0;
8    size = strlen("Hello World!")+1;
9    strcpy((char*)buffer, "Hello World!");
10    lfs_file_write(&lfs, &file, buffer, size) => size;
11    lfs_file_close(&lfs, &file) => 0;
12    lfs_unmount(&lfs) => 0;
13
14    lfs_mount(&lfs, &cfg) => 0;
15    lfs_file_open(&lfs, &file, "hello", LFS_O_RDONLY) => 0;
16    lfs_file_read(&lfs, &file, buffer, size) => size;
17    assert(strcmp((char*)buffer, "Hello World!") == 0);
18    lfs_file_close(&lfs, &file) => 0;
19    lfs_unmount(&lfs) => 0;
20'''
21
22[[case]] # larger files
23define.SIZE = [32, 8192, 262144, 0, 7, 8193]
24define.CHUNKSIZE = [31, 16, 33, 1, 1023]
25code = '''
26    lfs_format(&lfs, &cfg) => 0;
27
28    // write
29    lfs_mount(&lfs, &cfg) => 0;
30    lfs_file_open(&lfs, &file, "avacado",
31            LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0;
32    srand(1);
33    for (lfs_size_t i = 0; i < SIZE; i += CHUNKSIZE) {
34        lfs_size_t chunk = lfs_min(CHUNKSIZE, SIZE-i);
35        for (lfs_size_t b = 0; b < chunk; b++) {
36            buffer[b] = rand() & 0xff;
37        }
38        lfs_file_write(&lfs, &file, buffer, chunk) => chunk;
39    }
40    lfs_file_close(&lfs, &file) => 0;
41    lfs_unmount(&lfs) => 0;
42
43    // read
44    lfs_mount(&lfs, &cfg) => 0;
45    lfs_file_open(&lfs, &file, "avacado", LFS_O_RDONLY) => 0;
46    lfs_file_size(&lfs, &file) => SIZE;
47    srand(1);
48    for (lfs_size_t i = 0; i < SIZE; i += CHUNKSIZE) {
49        lfs_size_t chunk = lfs_min(CHUNKSIZE, SIZE-i);
50        lfs_file_read(&lfs, &file, buffer, chunk) => chunk;
51        for (lfs_size_t b = 0; b < chunk; b++) {
52            assert(buffer[b] == (rand() & 0xff));
53        }
54    }
55    lfs_file_read(&lfs, &file, buffer, CHUNKSIZE) => 0;
56    lfs_file_close(&lfs, &file) => 0;
57    lfs_unmount(&lfs) => 0;
58'''
59
60[[case]] # rewriting files
61define.SIZE1 = [32, 8192, 131072, 0, 7, 8193]
62define.SIZE2 = [32, 8192, 131072, 0, 7, 8193]
63define.CHUNKSIZE = [31, 16, 1]
64code = '''
65    lfs_format(&lfs, &cfg) => 0;
66
67    // write
68    lfs_mount(&lfs, &cfg) => 0;
69    lfs_file_open(&lfs, &file, "avacado",
70            LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0;
71    srand(1);
72    for (lfs_size_t i = 0; i < SIZE1; i += CHUNKSIZE) {
73        lfs_size_t chunk = lfs_min(CHUNKSIZE, SIZE1-i);
74        for (lfs_size_t b = 0; b < chunk; b++) {
75            buffer[b] = rand() & 0xff;
76        }
77        lfs_file_write(&lfs, &file, buffer, chunk) => chunk;
78    }
79    lfs_file_close(&lfs, &file) => 0;
80    lfs_unmount(&lfs) => 0;
81
82    // read
83    lfs_mount(&lfs, &cfg) => 0;
84    lfs_file_open(&lfs, &file, "avacado", LFS_O_RDONLY) => 0;
85    lfs_file_size(&lfs, &file) => SIZE1;
86    srand(1);
87    for (lfs_size_t i = 0; i < SIZE1; i += CHUNKSIZE) {
88        lfs_size_t chunk = lfs_min(CHUNKSIZE, SIZE1-i);
89        lfs_file_read(&lfs, &file, buffer, chunk) => chunk;
90        for (lfs_size_t b = 0; b < chunk; b++) {
91            assert(buffer[b] == (rand() & 0xff));
92        }
93    }
94    lfs_file_read(&lfs, &file, buffer, CHUNKSIZE) => 0;
95    lfs_file_close(&lfs, &file) => 0;
96    lfs_unmount(&lfs) => 0;
97
98    // rewrite
99    lfs_mount(&lfs, &cfg) => 0;
100    lfs_file_open(&lfs, &file, "avacado", LFS_O_WRONLY) => 0;
101    srand(2);
102    for (lfs_size_t i = 0; i < SIZE2; i += CHUNKSIZE) {
103        lfs_size_t chunk = lfs_min(CHUNKSIZE, SIZE2-i);
104        for (lfs_size_t b = 0; b < chunk; b++) {
105            buffer[b] = rand() & 0xff;
106        }
107        lfs_file_write(&lfs, &file, buffer, chunk) => chunk;
108    }
109    lfs_file_close(&lfs, &file) => 0;
110    lfs_unmount(&lfs) => 0;
111
112    // read
113    lfs_mount(&lfs, &cfg) => 0;
114    lfs_file_open(&lfs, &file, "avacado", LFS_O_RDONLY) => 0;
115    lfs_file_size(&lfs, &file) => lfs_max(SIZE1, SIZE2);
116    srand(2);
117    for (lfs_size_t i = 0; i < SIZE2; i += CHUNKSIZE) {
118        lfs_size_t chunk = lfs_min(CHUNKSIZE, SIZE2-i);
119        lfs_file_read(&lfs, &file, buffer, chunk) => chunk;
120        for (lfs_size_t b = 0; b < chunk; b++) {
121            assert(buffer[b] == (rand() & 0xff));
122        }
123    }
124    if (SIZE1 > SIZE2) {
125        srand(1);
126        for (lfs_size_t b = 0; b < SIZE2; b++) {
127            rand();
128        }
129        for (lfs_size_t i = SIZE2; i < SIZE1; i += CHUNKSIZE) {
130            lfs_size_t chunk = lfs_min(CHUNKSIZE, SIZE1-i);
131            lfs_file_read(&lfs, &file, buffer, chunk) => chunk;
132            for (lfs_size_t b = 0; b < chunk; b++) {
133                assert(buffer[b] == (rand() & 0xff));
134            }
135        }
136    }
137    lfs_file_read(&lfs, &file, buffer, CHUNKSIZE) => 0;
138    lfs_file_close(&lfs, &file) => 0;
139    lfs_unmount(&lfs) => 0;
140'''
141
142[[case]] # appending files
143define.SIZE1 = [32, 8192, 131072, 0, 7, 8193]
144define.SIZE2 = [32, 8192, 131072, 0, 7, 8193]
145define.CHUNKSIZE = [31, 16, 1]
146code = '''
147    lfs_format(&lfs, &cfg) => 0;
148
149    // write
150    lfs_mount(&lfs, &cfg) => 0;
151    lfs_file_open(&lfs, &file, "avacado",
152            LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0;
153    srand(1);
154    for (lfs_size_t i = 0; i < SIZE1; i += CHUNKSIZE) {
155        lfs_size_t chunk = lfs_min(CHUNKSIZE, SIZE1-i);
156        for (lfs_size_t b = 0; b < chunk; b++) {
157            buffer[b] = rand() & 0xff;
158        }
159        lfs_file_write(&lfs, &file, buffer, chunk) => chunk;
160    }
161    lfs_file_close(&lfs, &file) => 0;
162    lfs_unmount(&lfs) => 0;
163
164    // read
165    lfs_mount(&lfs, &cfg) => 0;
166    lfs_file_open(&lfs, &file, "avacado", LFS_O_RDONLY) => 0;
167    lfs_file_size(&lfs, &file) => SIZE1;
168    srand(1);
169    for (lfs_size_t i = 0; i < SIZE1; i += CHUNKSIZE) {
170        lfs_size_t chunk = lfs_min(CHUNKSIZE, SIZE1-i);
171        lfs_file_read(&lfs, &file, buffer, chunk) => chunk;
172        for (lfs_size_t b = 0; b < chunk; b++) {
173            assert(buffer[b] == (rand() & 0xff));
174        }
175    }
176    lfs_file_read(&lfs, &file, buffer, CHUNKSIZE) => 0;
177    lfs_file_close(&lfs, &file) => 0;
178    lfs_unmount(&lfs) => 0;
179
180    // append
181    lfs_mount(&lfs, &cfg) => 0;
182    lfs_file_open(&lfs, &file, "avacado", LFS_O_WRONLY | LFS_O_APPEND) => 0;
183    srand(2);
184    for (lfs_size_t i = 0; i < SIZE2; i += CHUNKSIZE) {
185        lfs_size_t chunk = lfs_min(CHUNKSIZE, SIZE2-i);
186        for (lfs_size_t b = 0; b < chunk; b++) {
187            buffer[b] = rand() & 0xff;
188        }
189        lfs_file_write(&lfs, &file, buffer, chunk) => chunk;
190    }
191    lfs_file_close(&lfs, &file) => 0;
192    lfs_unmount(&lfs) => 0;
193
194    // read
195    lfs_mount(&lfs, &cfg) => 0;
196    lfs_file_open(&lfs, &file, "avacado", LFS_O_RDONLY) => 0;
197    lfs_file_size(&lfs, &file) => SIZE1 + SIZE2;
198    srand(1);
199    for (lfs_size_t i = 0; i < SIZE1; i += CHUNKSIZE) {
200        lfs_size_t chunk = lfs_min(CHUNKSIZE, SIZE1-i);
201        lfs_file_read(&lfs, &file, buffer, chunk) => chunk;
202        for (lfs_size_t b = 0; b < chunk; b++) {
203            assert(buffer[b] == (rand() & 0xff));
204        }
205    }
206    srand(2);
207    for (lfs_size_t i = 0; i < SIZE2; i += CHUNKSIZE) {
208        lfs_size_t chunk = lfs_min(CHUNKSIZE, SIZE2-i);
209        lfs_file_read(&lfs, &file, buffer, chunk) => chunk;
210        for (lfs_size_t b = 0; b < chunk; b++) {
211            assert(buffer[b] == (rand() & 0xff));
212        }
213    }
214    lfs_file_read(&lfs, &file, buffer, CHUNKSIZE) => 0;
215    lfs_file_close(&lfs, &file) => 0;
216    lfs_unmount(&lfs) => 0;
217'''
218
219[[case]] # truncating files
220define.SIZE1 = [32, 8192, 131072, 0, 7, 8193]
221define.SIZE2 = [32, 8192, 131072, 0, 7, 8193]
222define.CHUNKSIZE = [31, 16, 1]
223code = '''
224    lfs_format(&lfs, &cfg) => 0;
225
226    // write
227    lfs_mount(&lfs, &cfg) => 0;
228    lfs_file_open(&lfs, &file, "avacado",
229            LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0;
230    srand(1);
231    for (lfs_size_t i = 0; i < SIZE1; i += CHUNKSIZE) {
232        lfs_size_t chunk = lfs_min(CHUNKSIZE, SIZE1-i);
233        for (lfs_size_t b = 0; b < chunk; b++) {
234            buffer[b] = rand() & 0xff;
235        }
236        lfs_file_write(&lfs, &file, buffer, chunk) => chunk;
237    }
238    lfs_file_close(&lfs, &file) => 0;
239    lfs_unmount(&lfs) => 0;
240
241    // read
242    lfs_mount(&lfs, &cfg) => 0;
243    lfs_file_open(&lfs, &file, "avacado", LFS_O_RDONLY) => 0;
244    lfs_file_size(&lfs, &file) => SIZE1;
245    srand(1);
246    for (lfs_size_t i = 0; i < SIZE1; i += CHUNKSIZE) {
247        lfs_size_t chunk = lfs_min(CHUNKSIZE, SIZE1-i);
248        lfs_file_read(&lfs, &file, buffer, chunk) => chunk;
249        for (lfs_size_t b = 0; b < chunk; b++) {
250            assert(buffer[b] == (rand() & 0xff));
251        }
252    }
253    lfs_file_read(&lfs, &file, buffer, CHUNKSIZE) => 0;
254    lfs_file_close(&lfs, &file) => 0;
255    lfs_unmount(&lfs) => 0;
256
257    // truncate
258    lfs_mount(&lfs, &cfg) => 0;
259    lfs_file_open(&lfs, &file, "avacado", LFS_O_WRONLY | LFS_O_TRUNC) => 0;
260    srand(2);
261    for (lfs_size_t i = 0; i < SIZE2; i += CHUNKSIZE) {
262        lfs_size_t chunk = lfs_min(CHUNKSIZE, SIZE2-i);
263        for (lfs_size_t b = 0; b < chunk; b++) {
264            buffer[b] = rand() & 0xff;
265        }
266        lfs_file_write(&lfs, &file, buffer, chunk) => chunk;
267    }
268    lfs_file_close(&lfs, &file) => 0;
269    lfs_unmount(&lfs) => 0;
270
271    // read
272    lfs_mount(&lfs, &cfg) => 0;
273    lfs_file_open(&lfs, &file, "avacado", LFS_O_RDONLY) => 0;
274    lfs_file_size(&lfs, &file) => SIZE2;
275    srand(2);
276    for (lfs_size_t i = 0; i < SIZE2; i += CHUNKSIZE) {
277        lfs_size_t chunk = lfs_min(CHUNKSIZE, SIZE2-i);
278        lfs_file_read(&lfs, &file, buffer, chunk) => chunk;
279        for (lfs_size_t b = 0; b < chunk; b++) {
280            assert(buffer[b] == (rand() & 0xff));
281        }
282    }
283    lfs_file_read(&lfs, &file, buffer, CHUNKSIZE) => 0;
284    lfs_file_close(&lfs, &file) => 0;
285    lfs_unmount(&lfs) => 0;
286'''
287
288[[case]] # reentrant file writing
289define.SIZE = [32, 0, 7, 2049]
290define.CHUNKSIZE = [31, 16, 65]
291reentrant = true
292code = '''
293    err = lfs_mount(&lfs, &cfg);
294    if (err) {
295        lfs_format(&lfs, &cfg) => 0;
296        lfs_mount(&lfs, &cfg) => 0;
297    }
298
299    err = lfs_file_open(&lfs, &file, "avacado", LFS_O_RDONLY);
300    assert(err == LFS_ERR_NOENT || err == 0);
301    if (err == 0) {
302        // can only be 0 (new file) or full size
303        size = lfs_file_size(&lfs, &file);
304        assert(size == 0 || size == SIZE);
305        lfs_file_close(&lfs, &file) => 0;
306    }
307
308    // write
309    lfs_file_open(&lfs, &file, "avacado", LFS_O_WRONLY | LFS_O_CREAT) => 0;
310    srand(1);
311    for (lfs_size_t i = 0; i < SIZE; i += CHUNKSIZE) {
312        lfs_size_t chunk = lfs_min(CHUNKSIZE, SIZE-i);
313        for (lfs_size_t b = 0; b < chunk; b++) {
314            buffer[b] = rand() & 0xff;
315        }
316        lfs_file_write(&lfs, &file, buffer, chunk) => chunk;
317    }
318    lfs_file_close(&lfs, &file) => 0;
319
320    // read
321    lfs_file_open(&lfs, &file, "avacado", LFS_O_RDONLY) => 0;
322    lfs_file_size(&lfs, &file) => SIZE;
323    srand(1);
324    for (lfs_size_t i = 0; i < SIZE; i += CHUNKSIZE) {
325        lfs_size_t chunk = lfs_min(CHUNKSIZE, SIZE-i);
326        lfs_file_read(&lfs, &file, buffer, chunk) => chunk;
327        for (lfs_size_t b = 0; b < chunk; b++) {
328            assert(buffer[b] == (rand() & 0xff));
329        }
330    }
331    lfs_file_read(&lfs, &file, buffer, CHUNKSIZE) => 0;
332    lfs_file_close(&lfs, &file) => 0;
333    lfs_unmount(&lfs) => 0;
334'''
335
336[[case]] # reentrant file writing with syncs
337define = [
338    # append (O(n))
339    {MODE='LFS_O_APPEND',   SIZE=[32, 0, 7, 2049],  CHUNKSIZE=[31, 16, 65]},
340    # truncate (O(n^2))
341    {MODE='LFS_O_TRUNC',    SIZE=[32, 0, 7, 200],   CHUNKSIZE=[31, 16, 65]},
342    # rewrite (O(n^2))
343    {MODE=0,                SIZE=[32, 0, 7, 200],   CHUNKSIZE=[31, 16, 65]},
344]
345reentrant = true
346code = '''
347    err = lfs_mount(&lfs, &cfg);
348    if (err) {
349        lfs_format(&lfs, &cfg) => 0;
350        lfs_mount(&lfs, &cfg) => 0;
351    }
352
353    err = lfs_file_open(&lfs, &file, "avacado", LFS_O_RDONLY);
354    assert(err == LFS_ERR_NOENT || err == 0);
355    if (err == 0) {
356        // with syncs we could be any size, but it at least must be valid data
357        size = lfs_file_size(&lfs, &file);
358        assert(size <= SIZE);
359        srand(1);
360        for (lfs_size_t i = 0; i < size; i += CHUNKSIZE) {
361            lfs_size_t chunk = lfs_min(CHUNKSIZE, size-i);
362            lfs_file_read(&lfs, &file, buffer, chunk) => chunk;
363            for (lfs_size_t b = 0; b < chunk; b++) {
364                assert(buffer[b] == (rand() & 0xff));
365            }
366        }
367        lfs_file_close(&lfs, &file) => 0;
368    }
369
370    // write
371    lfs_file_open(&lfs, &file, "avacado",
372        LFS_O_WRONLY | LFS_O_CREAT | MODE) => 0;
373    size = lfs_file_size(&lfs, &file);
374    assert(size <= SIZE);
375    srand(1);
376    lfs_size_t skip = (MODE == LFS_O_APPEND) ? size : 0;
377    for (lfs_size_t b = 0; b < skip; b++) {
378        rand();
379    }
380    for (lfs_size_t i = skip; i < SIZE; i += CHUNKSIZE) {
381        lfs_size_t chunk = lfs_min(CHUNKSIZE, SIZE-i);
382        for (lfs_size_t b = 0; b < chunk; b++) {
383            buffer[b] = rand() & 0xff;
384        }
385        lfs_file_write(&lfs, &file, buffer, chunk) => chunk;
386        lfs_file_sync(&lfs, &file) => 0;
387    }
388    lfs_file_close(&lfs, &file) => 0;
389
390    // read
391    lfs_file_open(&lfs, &file, "avacado", LFS_O_RDONLY) => 0;
392    lfs_file_size(&lfs, &file) => SIZE;
393    srand(1);
394    for (lfs_size_t i = 0; i < SIZE; i += CHUNKSIZE) {
395        lfs_size_t chunk = lfs_min(CHUNKSIZE, SIZE-i);
396        lfs_file_read(&lfs, &file, buffer, chunk) => chunk;
397        for (lfs_size_t b = 0; b < chunk; b++) {
398            assert(buffer[b] == (rand() & 0xff));
399        }
400    }
401    lfs_file_read(&lfs, &file, buffer, CHUNKSIZE) => 0;
402    lfs_file_close(&lfs, &file) => 0;
403    lfs_unmount(&lfs) => 0;
404'''
405
406[[case]] # many files
407define.N = 300
408code = '''
409    lfs_format(&lfs, &cfg) => 0;
410    // create N files of 7 bytes
411    lfs_mount(&lfs, &cfg) => 0;
412    for (int i = 0; i < N; i++) {
413        sprintf(path, "file_%03d", i);
414        lfs_file_open(&lfs, &file, path,
415                LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0;
416        char wbuffer[1024];
417        size = 7;
418        snprintf(wbuffer, size, "Hi %03d", i);
419        lfs_file_write(&lfs, &file, wbuffer, size) => size;
420        lfs_file_close(&lfs, &file) => 0;
421
422        char rbuffer[1024];
423        lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0;
424        lfs_file_read(&lfs, &file, rbuffer, size) => size;
425        assert(strcmp(rbuffer, wbuffer) == 0);
426        lfs_file_close(&lfs, &file) => 0;
427    }
428    lfs_unmount(&lfs) => 0;
429'''
430
431[[case]] # many files with power cycle
432define.N = 300
433code = '''
434    lfs_format(&lfs, &cfg) => 0;
435    // create N files of 7 bytes
436    lfs_mount(&lfs, &cfg) => 0;
437    for (int i = 0; i < N; i++) {
438        sprintf(path, "file_%03d", i);
439        lfs_file_open(&lfs, &file, path,
440                LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0;
441        char wbuffer[1024];
442        size = 7;
443        snprintf(wbuffer, size, "Hi %03d", i);
444        lfs_file_write(&lfs, &file, wbuffer, size) => size;
445        lfs_file_close(&lfs, &file) => 0;
446        lfs_unmount(&lfs) => 0;
447
448        char rbuffer[1024];
449        lfs_mount(&lfs, &cfg) => 0;
450        lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0;
451        lfs_file_read(&lfs, &file, rbuffer, size) => size;
452        assert(strcmp(rbuffer, wbuffer) == 0);
453        lfs_file_close(&lfs, &file) => 0;
454    }
455    lfs_unmount(&lfs) => 0;
456'''
457
458[[case]] # many files with power loss
459define.N = 300
460reentrant = true
461code = '''
462    err = lfs_mount(&lfs, &cfg);
463    if (err) {
464        lfs_format(&lfs, &cfg) => 0;
465        lfs_mount(&lfs, &cfg) => 0;
466    }
467    // create N files of 7 bytes
468    for (int i = 0; i < N; i++) {
469        sprintf(path, "file_%03d", i);
470        err = lfs_file_open(&lfs, &file, path, LFS_O_WRONLY | LFS_O_CREAT);
471        char wbuffer[1024];
472        size = 7;
473        snprintf(wbuffer, size, "Hi %03d", i);
474        if ((lfs_size_t)lfs_file_size(&lfs, &file) != size) {
475            lfs_file_write(&lfs, &file, wbuffer, size) => size;
476        }
477        lfs_file_close(&lfs, &file) => 0;
478
479        char rbuffer[1024];
480        lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0;
481        lfs_file_read(&lfs, &file, rbuffer, size) => size;
482        assert(strcmp(rbuffer, wbuffer) == 0);
483        lfs_file_close(&lfs, &file) => 0;
484    }
485    lfs_unmount(&lfs) => 0;
486'''
487