Fix battfs tests.
[bertos.git] / bertos / fs / battfs_test.c
1 /**
2  * \file
3  * <!--
4  * This file is part of BeRTOS.
5  *
6  * Bertos is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
19  *
20  * As a special exception, you may use this file as part of a free software
21  * library without restriction.  Specifically, if other files instantiate
22  * templates or use macros or inline functions from this file, or you compile
23  * this file and link it with other files to produce an executable, this
24  * file does not by itself cause the resulting executable to be covered by
25  * the GNU General Public License.  This exception does not however
26  * invalidate any other reasons why the executable file might be covered by
27  * the GNU General Public License.
28  *
29  * Copyright 2007, 2008 Develer S.r.l. (http://www.develer.com/)
30  * -->
31  *
32  * \brief BattFS Test.
33  *
34  * \version $Id$
35  * \author Francesco Sacchi <batt@develer.com>
36  */
37
38 #include <fs/battfs.h>
39
40 #include <cfg/debug.h>
41 #include <cfg/test.h>
42
43 #include <stdio.h>
44 #include <stdlib.h>
45 #include <string.h>
46
47 #define FILE_SIZE 32768
48 #define PAGE_SIZE 128
49 #define PAGE_COUNT FILE_SIZE / PAGE_SIZE
50
51 #if UNIT_TEST
52
53 FILE *fp;
54 const char test_filename[]="battfs_disk.bin";
55
56
57 static bool disk_open(struct BattFsSuper *d)
58 {
59         fp = fopen(test_filename, "r+b");
60         ASSERT(fp);
61         fseek(fp, 0, SEEK_END);
62         d->page_size = PAGE_SIZE;
63         d->page_count = ftell(fp) / d->page_size;
64         d->page_array = malloc(d->page_count * sizeof(pgcnt_t));
65         //TRACEMSG("page_size:%d, page_count:%d\n", d->page_size, d->page_count);
66         return (fp && d->page_array);
67 }
68
69 static size_t disk_page_read(struct BattFsSuper *d, pgcnt_t page, pgaddr_t addr, void *buf, size_t size)
70 {
71         //TRACEMSG("page:%d, addr:%d, size:%d\n", page, addr, size);
72         fseek(fp, page * d->page_size + addr, SEEK_SET);
73         return fread(buf, 1, size, fp);
74 }
75
76 static size_t disk_page_write(struct BattFsSuper *d, pgcnt_t page, pgaddr_t addr, const void *buf, size_t size)
77 {
78         //TRACEMSG("page:%d, addr:%d, size:%d\n", page, addr, size);
79         fseek(fp, page * d->page_size + addr, SEEK_SET);
80         return fwrite(buf, 1, size, fp);
81 }
82
83 static bool disk_page_erase(struct BattFsSuper *d, pgcnt_t page)
84 {
85         //TRACEMSG("page:%d\n", page);
86         fseek(fp, page * d->page_size, SEEK_SET);
87
88         for (int i = 0; i < d->page_size; i++)
89                 if (fputc(0xff, fp) == EOF)
90                         return false;
91         return true;
92 }
93
94 static bool disk_close(struct BattFsSuper *d)
95 {
96         //TRACE;
97         free(d->page_array);
98         return (fclose(fp) != EOF);
99 }
100
101 static void testCheck(BattFsSuper *disk, pgcnt_t *reference)
102 {
103         ASSERT(battfs_init(disk));
104
105         for (int i = 0; i < disk->page_count; i++)
106         {
107                 if (disk->page_array[i] != reference[i])
108                 {
109                         kprintf("Error at addr %d: page_array read", i);
110                         for (pgcnt_t i = 0; i < disk->page_count; i++)
111                         {
112                                 if (!(i % 16))
113                                         kputchar('\n');
114                                 kprintf("%04d ", disk->page_array[i]);
115                         }
116                         kputchar('\n');
117                         kprintf("Expected:");
118                         for (pgcnt_t i = 0; i < disk->page_count; i++)
119                         {
120                                 if (!(i % 16))
121                                         kputchar('\n');
122                                 kprintf("%04d ", reference[i]);
123                         }
124                         kputchar('\n');
125                         battfs_close(disk);
126                         exit(2);
127                 }
128         }
129         battfs_close(disk);
130 }
131
132 static void test1(BattFsSuper *disk)
133 {
134         pgcnt_t ref[PAGE_COUNT];
135         kprintf("Test1: disk new\n");
136
137         FILE *fpt = fopen(test_filename, "w+");
138
139         for (int i = 0; i < FILE_SIZE; i++)
140                 fputc(0xff, fpt);
141         fclose(fpt);
142         for (int i = 0; i < PAGE_COUNT; i++)
143                 ref[i] = i;
144
145         testCheck(disk, ref);
146         kprintf("Test1: passed\n");
147 }
148
149 static void test2(BattFsSuper *disk)
150 {
151         pgcnt_t ref[PAGE_COUNT];
152         kprintf("Test2: disk full with 1 contiguos file\n");
153
154
155         fp = fopen(test_filename, "w+");
156
157         for (int i = 0; i < PAGE_COUNT; i++)
158         {
159                 battfs_writeTestBlock(disk, i, 0, 0, 0, i);
160                 ref[i] = i;
161         }
162         fclose(fp);
163
164         testCheck(disk, ref);
165         kprintf("Test2: passed\n");
166 }
167
168
169 static void test3(BattFsSuper *disk)
170 {
171         pgcnt_t ref[PAGE_COUNT];
172         kprintf("Test3: disk half full with 1 contiguos file, rest unformatted\n");
173
174
175         fp = fopen(test_filename, "w+");
176
177         for (int i = 0; i < PAGE_COUNT / 2; i++)
178         {
179                 battfs_writeTestBlock(disk, i, 0, 0, 0, i);
180                 ref[i] = i;
181         }
182         fseek(fp, FILE_SIZE / 2, SEEK_SET);
183         for (int i = FILE_SIZE / 2; i < FILE_SIZE; i++)
184                 fputc(0xff, fp);
185         fclose(fp);
186
187         for (int i = PAGE_COUNT / 2; i < PAGE_COUNT; i++)
188         {
189                 ref[i] = i;
190         }
191
192
193         testCheck(disk, ref);
194         kprintf("Test3: passed\n");
195 }
196
197 #if 0
198 static void test4(BattFsSuper *disk)
199 {
200         pgcnt_t ref[PAGE_COUNT];
201         kprintf("Test4: disk half full with 1 contiguos file, rest marked free\n");
202
203
204         fp = fopen(test_filename, "w+");
205
206         for (int i = 0; i < PAGE_COUNT / 2; i++)
207         {
208                 battfs_writeTestBlock(disk, i, 0, 0, 0, i);
209                 ref[i] = i;
210         }
211         for (int i = PAGE_COUNT / 2; i < PAGE_COUNT; i++)
212         {
213                 battfs_writeTestBlock(disk, i, 0, 0, 0, i);
214                 ref[i] = i;
215         }
216         fclose(fp);
217
218
219         testCheck(disk, ref);
220         kprintf("Test4: passed\n");
221 }
222
223 static void test5(BattFsSuper *disk)
224 {
225         pgcnt_t ref[PAGE_COUNT];
226         kprintf("Test5: disk 1/3 full with 1 contiguos file, 1/3 marked free, rest unformatted\n");
227
228
229         fp = fopen(test_filename, "w+");
230
231         for (int i = 0; i < FILE_SIZE; i++)
232                 fputc(0xff, fp);
233
234         for (int i = 0; i < PAGE_COUNT / 3; i++)
235         {
236                 battfs_writeTestBlock(disk, i, 0, 0, 0, i);
237                 ref[i] = i;
238         }
239         for (int i = PAGE_COUNT / 3; i < 2 * (PAGE_COUNT / 3); i++)
240         {
241                 battfs_writeTestBlock(disk, i, 0, 0, 0, i);
242                 ref[i + PAGE_COUNT / 3 + 1] = i;
243         }
244         fclose(fp);
245
246         for (int i = PAGE_COUNT / 3; i < 2 * (PAGE_COUNT / 3) + 1; i++)
247                 ref[i] = PAGE_COUNT + PAGE_COUNT / 3 - i - 1;
248
249         testCheck(disk, ref);
250         kprintf("Test5: passed\n");
251 }
252 #endif
253
254 static void test6(BattFsSuper *disk)
255 {
256         pgcnt_t ref[4];
257         kprintf("Test6: 1 file with 1 old seq num, 1 free block\n");
258
259
260         fp = fopen(test_filename, "w+");
261         // page, inode, seq, fill, pgoff
262         battfs_writeTestBlock(disk, 0, 0, 0, 0, 0);
263         battfs_writeTestBlock(disk, 1, 0, 0, 0, 1);
264         battfs_writeTestBlock(disk, 2, 0, 1, 0, 1);
265         disk->erase(disk, 3);
266
267
268         fclose(fp);
269         ref[0] = 0;
270         ref[1] = 2;
271         ref[2] = 1;
272         ref[3] = 3;
273
274         testCheck(disk, ref);
275         kprintf("Test6: passed\n");
276 }
277
278 static void test7(BattFsSuper *disk)
279 {
280         pgcnt_t ref[4];
281         kprintf("Test7: 1 file with 1 old seq num, 1 free block\n");
282
283
284         fp = fopen(test_filename, "w+");
285         // page, inode, seq, fill, pgoff
286         battfs_writeTestBlock(disk, 0, 0, 0, 0, 0);
287         battfs_writeTestBlock(disk, 1, 0, 1, 0, 1);
288         battfs_writeTestBlock(disk, 2, 0, 0, 0, 1);
289         disk->erase(disk, 3);
290
291         fclose(fp);
292         ref[0] = 0;
293         ref[1] = 1;
294         ref[2] = 2;
295         ref[3] = 3;
296
297         testCheck(disk, ref);
298         kprintf("Test7: passed\n");
299 }
300
301 static void test8(BattFsSuper *disk)
302 {
303         pgcnt_t ref[4];
304         kprintf("Test8: 1 file with 1 old seq num, 1 free block\n");
305
306
307         fp = fopen(test_filename, "w+");
308
309         // page, inode, seq, fill, pgoff
310         disk->erase(disk, 0);
311         battfs_writeTestBlock(disk, 1, 0, 0, 0, 0);
312         battfs_writeTestBlock(disk, 2, 0, 1, 0, 1);
313         battfs_writeTestBlock(disk, 3, 0, 0, 0, 1);
314
315
316         fclose(fp);
317         ref[0] = 1;
318         ref[1] = 2;
319         ref[2] = 0;
320         ref[3] = 3;
321
322         testCheck(disk, ref);
323         kprintf("Test8: passed\n");
324 }
325
326 static void test9(BattFsSuper *disk)
327 {
328         pgcnt_t ref[8];
329         kprintf("Test9: 2 file with old seq num, 2 free block\n");
330
331
332         fp = fopen(test_filename, "w+");
333
334         // page, inode, seq, fill, pgoff
335         disk->erase(disk, 0);
336         battfs_writeTestBlock(disk, 1, 0, 0, 0, 0);
337         battfs_writeTestBlock(disk, 2, 0, 3, 0, 1);
338         battfs_writeTestBlock(disk, 3, 0, 0, 0, 1);
339         disk->erase(disk, 4);
340         battfs_writeTestBlock(disk, 5, 4, 0, 0, 0);
341         battfs_writeTestBlock(disk, 6, 4, 1, 0, 1);
342         battfs_writeTestBlock(disk, 7, 4, 0, 0, 1);
343
344
345         fclose(fp);
346         ref[0] = 1;
347         ref[1] = 2;
348         ref[2] = 5;
349         ref[3] = 6;
350         ref[4] = 0;
351         ref[5] = 3;
352         ref[6] = 4;
353         ref[7] = 7;
354
355         testCheck(disk, ref);
356         kprintf("Test9: passed\n");
357 }
358
359 static void test10(BattFsSuper *disk)
360 {
361         BattFs fd1;
362         BattFs fd2;
363         kprintf("Test10: open file test, inode 0 and inode 4\n");
364
365         fp = fopen(test_filename, "w+");
366
367         int PAGE_FILL = PAGE_SIZE - BATTFS_HEADER_LEN;
368         unsigned int INODE = 0;
369         unsigned int INODE2 = 4;
370         unsigned int INEXISTENT_INODE = 123;
371         unsigned int MODE = 0;
372
373         // page, inode, seq, fill, pgoff
374         disk->erase(disk, 0);
375         battfs_writeTestBlock(disk, 1, INODE, 0, PAGE_FILL, 0);
376         battfs_writeTestBlock(disk, 2, INODE, 3, PAGE_FILL, 1);
377         battfs_writeTestBlock(disk, 3, INODE, 0, PAGE_FILL, 1);
378         disk->erase(disk, 4);
379         battfs_writeTestBlock(disk, 5, INODE2, 0, PAGE_FILL, 0);
380         battfs_writeTestBlock(disk, 6, INODE2, 1, PAGE_FILL, 1);
381         battfs_writeTestBlock(disk, 7, INODE2, 0, PAGE_FILL, 1);
382
383         fclose(fp);
384
385         ASSERT(battfs_init(disk));
386         ASSERT(!battfs_fileExists(disk, INEXISTENT_INODE));
387
388         ASSERT(battfs_fileExists(disk, INODE));
389         ASSERT(battfs_fileopen(disk, &fd1, INODE, MODE));
390         ASSERT(fd1.fd.size == PAGE_FILL * 2);
391         ASSERT(fd1.fd.seek_pos == 0);
392         ASSERT(fd1.mode == MODE);
393         ASSERT(fd1.inode == INODE);
394         ASSERT(fd1.start == &disk->page_array[0]);
395         ASSERT(fd1.disk == disk);
396         ASSERT(LIST_HEAD(&disk->file_opened_list) == &fd1.link);
397
398         ASSERT(kfile_reopen(&fd1.fd) == &fd1.fd);
399         ASSERT(fd1.fd.size == PAGE_FILL * 2);
400         ASSERT(fd1.fd.seek_pos == 0);
401         ASSERT(fd1.mode == MODE);
402         ASSERT(fd1.inode == INODE);
403         ASSERT(fd1.start == &disk->page_array[0]);
404         ASSERT(fd1.disk == disk);
405         ASSERT(LIST_HEAD(&disk->file_opened_list) == &fd1.link);
406
407         ASSERT(battfs_fileExists(disk, INODE2));
408         ASSERT(battfs_fileopen(disk, &fd2, INODE2, MODE));
409         ASSERT(fd2.fd.size == PAGE_FILL * 2);
410         ASSERT(fd2.fd.seek_pos == 0);
411         ASSERT(fd2.mode == MODE);
412         ASSERT(fd2.inode == INODE2);
413         ASSERT(fd2.start == &disk->page_array[2]);
414         ASSERT(fd2.disk == disk);
415         ASSERT(LIST_HEAD(&disk->file_opened_list)->succ == &fd2.link);
416
417         ASSERT(kfile_close(&fd1.fd) == 0);
418         ASSERT(kfile_close(&fd2.fd) == 0);
419         ASSERT(LIST_EMPTY(&disk->file_opened_list));
420         ASSERT(battfs_close(disk));
421
422         kprintf("Test10: passed\n");
423 }
424
425 static void test11(BattFsSuper *disk)
426 {
427         BattFs fd1;
428         uint8_t buf[16];
429
430         kprintf("Test11: read file test\n");
431
432         fp = fopen(test_filename, "w+");
433
434         unsigned int PAGE_FILL = PAGE_SIZE - BATTFS_HEADER_LEN;
435         unsigned int INODE = 0;
436         unsigned int INODE2 = 4;
437         unsigned int MODE = 0;
438
439         disk->erase(disk, 0);
440         battfs_writeTestBlock(disk, 1, INODE, 0, PAGE_FILL, 0);
441         battfs_writeTestBlock(disk, 2, INODE, 3, PAGE_FILL, 1);
442         battfs_writeTestBlock(disk, 3, INODE, 0, PAGE_FILL, 1);
443         disk->erase(disk, 4);
444         battfs_writeTestBlock(disk, 5, INODE2, 0, PAGE_FILL, 0);
445         battfs_writeTestBlock(disk, 6, INODE2, 1, PAGE_FILL, 1);
446         battfs_writeTestBlock(disk, 7, INODE2, 0, PAGE_FILL, 1);
447
448         fclose(fp);
449
450         ASSERT(battfs_init(disk));
451         ASSERT(battfs_fileopen(disk, &fd1, INODE, MODE));
452         ASSERT(kfile_read(&fd1.fd, buf, sizeof(buf)) == sizeof(buf));
453         ASSERT(fd1.fd.seek_pos == sizeof(buf));
454         for (size_t i = 0; i < sizeof(buf); i++)
455                 ASSERT(buf[i] == 0);
456
457         ASSERT(kfile_close(&fd1.fd) == 0);
458         ASSERT(battfs_close(disk));
459
460         kprintf("Test11: passed\n");
461 }
462
463 static void test12(BattFsSuper *disk)
464 {
465         BattFs fd1;
466
467         kprintf("Test12: read file test across page boundary and seek test\n");
468
469         fp = fopen(test_filename, "w+");
470
471         const unsigned int PAGE_FILL = PAGE_SIZE - BATTFS_HEADER_LEN;
472         unsigned int INODE = 0;
473         unsigned int MODE = 0;
474         uint8_t buf[PAGE_FILL + BATTFS_HEADER_LEN / 2];
475
476         disk->erase(disk, 0);
477         battfs_writeTestBlock(disk, 1, INODE, 0, PAGE_FILL, 0);
478         battfs_writeTestBlock(disk, 2, INODE, 3, PAGE_FILL, 1);
479         battfs_writeTestBlock(disk, 3, INODE, 0, PAGE_FILL, 1);
480         disk->erase(disk, 4);
481         battfs_writeTestBlock(disk, 5, INODE, 0, PAGE_FILL, 2);
482         battfs_writeTestBlock(disk, 6, INODE, 1, PAGE_FILL, 3);
483         battfs_writeTestBlock(disk, 7, INODE, 0, PAGE_FILL, 3);
484
485         fclose(fp);
486
487         ASSERT(battfs_init(disk));
488         ASSERT(battfs_fileopen(disk, &fd1, INODE, MODE));
489
490         ASSERT(kfile_read(&fd1.fd, buf, sizeof(buf)) == sizeof(buf));
491         ASSERT(fd1.fd.seek_pos == (kfile_off_t)sizeof(buf));
492         for (size_t i = 0; i < sizeof(buf); i++)
493                 ASSERT(buf[i] == 0);
494
495         ASSERT(kfile_read(&fd1.fd, buf, sizeof(buf)) == sizeof(buf));
496         ASSERT(fd1.fd.seek_pos == (kfile_off_t)sizeof(buf) * 2);
497         for (size_t i = 0; i < sizeof(buf); i++)
498                 ASSERT(buf[i] == 0);
499
500         ASSERT(kfile_read(&fd1.fd, buf, sizeof(buf)) == sizeof(buf));
501         ASSERT(fd1.fd.seek_pos == (kfile_off_t)sizeof(buf) * 3);
502         for (size_t i = 0; i < sizeof(buf); i++)
503                 ASSERT(buf[i] == 0);
504
505         ASSERT(kfile_read(&fd1.fd, buf, sizeof(buf)) == PAGE_FILL * 4 - sizeof(buf) * 3);
506         ASSERT(fd1.fd.seek_pos == (kfile_off_t)fd1.fd.size);
507         for (size_t i = 0; i < PAGE_FILL * 4 - sizeof(buf) * 3; i++)
508                 ASSERT(buf[i] == 0);
509
510         ASSERT(kfile_seek(&fd1.fd, 0, KSM_SEEK_SET) == 0);
511         ASSERT(fd1.fd.seek_pos == 0);
512
513         ASSERT(kfile_seek(&fd1.fd, 0, KSM_SEEK_END) == (kfile_off_t)fd1.fd.size);
514         ASSERT(fd1.fd.seek_pos = (kfile_off_t)fd1.fd.size);
515
516         ASSERT(kfile_close(&fd1.fd) == 0);
517         ASSERT(battfs_close(disk));
518
519         kprintf("Test12: passed\n");
520 }
521
522
523 int battfs_testRun(void)
524 {
525         BattFsSuper disk;
526
527         disk.open = disk_open;
528         disk.read = disk_page_read;
529         disk.write = disk_page_write;
530         disk.erase = disk_page_erase;
531         disk.close = disk_close;
532         test1(&disk);
533         test2(&disk);
534         test3(&disk);
535         //test4(&disk);
536         //test5(&disk);
537         test6(&disk);
538         test7(&disk);
539         test8(&disk);
540         test9(&disk);
541         test10(&disk);
542         test11(&disk);
543         test12(&disk);
544         kprintf("All tests passed!\n");
545
546         return 0;
547 }
548
549 int battfs_testSetup(void)
550 {
551         return 0;
552 }
553
554 int battfs_testTearDown(void)
555 {
556         return 0;
557 }
558
559 TEST_MAIN(battfs)
560
561 #include <fs/battfs.c>
562 #include <kern/kfile.c>
563 #include <drv/kdebug.c>
564 #include <mware/formatwr.c>
565 #include <mware/hex.c>
566
567 #endif // _TEST