0580495feff209f39a5b522332bec16c5e7b5bd7
[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 static uint8_t page_buffer[PAGE_SIZE];
57
58 static bool disk_open(struct BattFsSuper *d)
59 {
60         fp = fopen(test_filename, "r+b");
61         ASSERT(fp);
62         fseek(fp, 0, SEEK_END);
63         d->page_size = PAGE_SIZE;
64         d->page_count = ftell(fp) / d->page_size;
65         d->page_array = malloc(d->page_count * sizeof(pgcnt_t));
66         //TRACEMSG("page_size:%d, page_count:%d\n", d->page_size, d->page_count);
67         return (fp && d->page_array);
68 }
69
70 static size_t disk_page_read(struct BattFsSuper *d, pgcnt_t page, pgaddr_t addr, void *buf, size_t size)
71 {
72         //TRACEMSG("page:%d, addr:%d, size:%d\n", page, addr, size);
73         fseek(fp, page * d->page_size + addr, SEEK_SET);
74         return fread(buf, 1, size, fp);
75 }
76
77 static size_t disk_buffer_write(struct BattFsSuper *d, pgaddr_t addr, const void *buf, size_t size)
78 {
79         //TRACEMSG("page:%d, addr:%d, size:%d\n", page, addr, size);
80         ASSERT(addr + size <= d->page_size);
81         memcpy(&page_buffer[addr], buf, size);
82
83         return size;
84 }
85
86 static bool disk_page_load(struct BattFsSuper *d, pgcnt_t page)
87 {
88         fseek(fp, page * d->page_size, SEEK_SET);
89         return fread(page_buffer, 1, d->page_size, fp) == d->page_size;
90 }
91
92 static bool disk_page_save(struct BattFsSuper *d, pgcnt_t page)
93 {
94         fseek(fp, page * d->page_size, SEEK_SET);
95         return fwrite(page_buffer, 1, d->page_size, fp) == d->page_size;
96 }
97
98 static bool disk_page_erase(struct BattFsSuper *d, pgcnt_t page)
99 {
100         //TRACEMSG("page:%d\n", page);
101         fseek(fp, page * d->page_size, SEEK_SET);
102
103         for (int i = 0; i < d->page_size; i++)
104                 if (fputc(0xff, fp) == EOF)
105                         return false;
106         return true;
107 }
108
109 static bool disk_close(struct BattFsSuper *d)
110 {
111         //TRACE;
112         free(d->page_array);
113         return (fclose(fp) != EOF);
114 }
115
116 static void testCheck(BattFsSuper *disk, pgcnt_t *reference)
117 {
118         ASSERT(battfs_init(disk));
119
120         for (int i = 0; i < disk->page_count; i++)
121         {
122                 if (disk->page_array[i] != reference[i])
123                 {
124                         kprintf("Error at addr %d: page_array read", i);
125                         for (pgcnt_t i = 0; i < disk->page_count; i++)
126                         {
127                                 if (!(i % 16))
128                                         kputchar('\n');
129                                 kprintf("%04d ", disk->page_array[i]);
130                         }
131                         kputchar('\n');
132                         kprintf("Expected:");
133                         for (pgcnt_t i = 0; i < disk->page_count; i++)
134                         {
135                                 if (!(i % 16))
136                                         kputchar('\n');
137                                 kprintf("%04d ", reference[i]);
138                         }
139                         kputchar('\n');
140                         battfs_close(disk);
141                         exit(2);
142                 }
143         }
144         battfs_close(disk);
145 }
146
147 static void test1(BattFsSuper *disk)
148 {
149         pgcnt_t ref[PAGE_COUNT];
150         kprintf("Test1: disk new\n");
151
152         FILE *fpt = fopen(test_filename, "w+");
153
154         for (int i = 0; i < FILE_SIZE; i++)
155                 fputc(0xff, fpt);
156         fclose(fpt);
157         for (int i = 0; i < PAGE_COUNT; i++)
158                 ref[i] = i;
159
160         testCheck(disk, ref);
161         kprintf("Test1: passed\n");
162 }
163
164 static void test2(BattFsSuper *disk)
165 {
166         pgcnt_t ref[PAGE_COUNT];
167         kprintf("Test2: disk full with 1 contiguos file\n");
168
169
170         fp = fopen(test_filename, "w+");
171
172         for (int i = 0; i < PAGE_COUNT; i++)
173         {
174                 battfs_writeTestBlock(disk, i, 0, 0, 0, i);
175                 ref[i] = i;
176         }
177         fclose(fp);
178
179         testCheck(disk, ref);
180         kprintf("Test2: passed\n");
181 }
182
183
184 static void test3(BattFsSuper *disk)
185 {
186         pgcnt_t ref[PAGE_COUNT];
187         kprintf("Test3: disk half full with 1 contiguos file, rest unformatted\n");
188
189
190         fp = fopen(test_filename, "w+");
191
192         for (int i = 0; i < PAGE_COUNT / 2; i++)
193         {
194                 battfs_writeTestBlock(disk, i, 0, 0, 0, i);
195                 ref[i] = i;
196         }
197         fseek(fp, FILE_SIZE / 2, SEEK_SET);
198         for (int i = FILE_SIZE / 2; i < FILE_SIZE; i++)
199                 fputc(0xff, fp);
200         fclose(fp);
201
202         for (int i = PAGE_COUNT / 2; i < PAGE_COUNT; i++)
203         {
204                 ref[i] = i;
205         }
206
207
208         testCheck(disk, ref);
209         kprintf("Test3: passed\n");
210 }
211
212 #if 0
213 static void test4(BattFsSuper *disk)
214 {
215         pgcnt_t ref[PAGE_COUNT];
216         kprintf("Test4: disk half full with 1 contiguos file, rest marked free\n");
217
218
219         fp = fopen(test_filename, "w+");
220
221         for (int i = 0; i < PAGE_COUNT / 2; i++)
222         {
223                 battfs_writeTestBlock(disk, i, 0, 0, 0, i);
224                 ref[i] = i;
225         }
226         for (int i = PAGE_COUNT / 2; i < PAGE_COUNT; i++)
227         {
228                 battfs_writeTestBlock(disk, i, 0, 0, 0, i);
229                 ref[i] = i;
230         }
231         fclose(fp);
232
233
234         testCheck(disk, ref);
235         kprintf("Test4: passed\n");
236 }
237
238 static void test5(BattFsSuper *disk)
239 {
240         pgcnt_t ref[PAGE_COUNT];
241         kprintf("Test5: disk 1/3 full with 1 contiguos file, 1/3 marked free, rest unformatted\n");
242
243
244         fp = fopen(test_filename, "w+");
245
246         for (int i = 0; i < FILE_SIZE; i++)
247                 fputc(0xff, fp);
248
249         for (int i = 0; i < PAGE_COUNT / 3; i++)
250         {
251                 battfs_writeTestBlock(disk, i, 0, 0, 0, i);
252                 ref[i] = i;
253         }
254         for (int i = PAGE_COUNT / 3; i < 2 * (PAGE_COUNT / 3); i++)
255         {
256                 battfs_writeTestBlock(disk, i, 0, 0, 0, i);
257                 ref[i + PAGE_COUNT / 3 + 1] = i;
258         }
259         fclose(fp);
260
261         for (int i = PAGE_COUNT / 3; i < 2 * (PAGE_COUNT / 3) + 1; i++)
262                 ref[i] = PAGE_COUNT + PAGE_COUNT / 3 - i - 1;
263
264         testCheck(disk, ref);
265         kprintf("Test5: passed\n");
266 }
267 #endif
268
269 static void test6(BattFsSuper *disk)
270 {
271         pgcnt_t ref[4];
272         kprintf("Test6: 1 file with 1 old seq num, 1 free block\n");
273
274
275         fp = fopen(test_filename, "w+");
276         // page, inode, seq, fill, pgoff
277         battfs_writeTestBlock(disk, 0, 0, 0, 0, 0);
278         battfs_writeTestBlock(disk, 1, 0, 0, 0, 1);
279         battfs_writeTestBlock(disk, 2, 0, 1, 0, 1);
280         disk->erase(disk, 3);
281
282
283         fclose(fp);
284         ref[0] = 0;
285         ref[1] = 2;
286         ref[2] = 1;
287         ref[3] = 3;
288
289         testCheck(disk, ref);
290         kprintf("Test6: passed\n");
291 }
292
293 static void test7(BattFsSuper *disk)
294 {
295         pgcnt_t ref[4];
296         kprintf("Test7: 1 file with 1 old seq num, 1 free block\n");
297
298
299         fp = fopen(test_filename, "w+");
300         // page, inode, seq, fill, pgoff
301         battfs_writeTestBlock(disk, 0, 0, 0, 0, 0);
302         battfs_writeTestBlock(disk, 1, 0, 1, 0, 1);
303         battfs_writeTestBlock(disk, 2, 0, 0, 0, 1);
304         disk->erase(disk, 3);
305
306         fclose(fp);
307         ref[0] = 0;
308         ref[1] = 1;
309         ref[2] = 2;
310         ref[3] = 3;
311
312         testCheck(disk, ref);
313         kprintf("Test7: passed\n");
314 }
315
316 static void test8(BattFsSuper *disk)
317 {
318         pgcnt_t ref[4];
319         kprintf("Test8: 1 file with 1 old seq num, 1 free block\n");
320
321
322         fp = fopen(test_filename, "w+");
323
324         // page, inode, seq, fill, pgoff
325         disk->erase(disk, 0);
326         battfs_writeTestBlock(disk, 1, 0, 0, 0, 0);
327         battfs_writeTestBlock(disk, 2, 0, 1, 0, 1);
328         battfs_writeTestBlock(disk, 3, 0, 0, 0, 1);
329
330
331         fclose(fp);
332         ref[0] = 1;
333         ref[1] = 2;
334         ref[2] = 0;
335         ref[3] = 3;
336
337         testCheck(disk, ref);
338         kprintf("Test8: passed\n");
339 }
340
341 static void test9(BattFsSuper *disk)
342 {
343         pgcnt_t ref[8];
344         kprintf("Test9: 2 file with old seq num, 2 free block\n");
345
346
347         fp = fopen(test_filename, "w+");
348
349         // page, inode, seq, fill, pgoff
350         disk->erase(disk, 0);
351         battfs_writeTestBlock(disk, 1, 0, 0, 0, 0);
352         battfs_writeTestBlock(disk, 2, 0, 3, 0, 1);
353         battfs_writeTestBlock(disk, 3, 0, 0, 0, 1);
354         disk->erase(disk, 4);
355         battfs_writeTestBlock(disk, 5, 4, 0, 0, 0);
356         battfs_writeTestBlock(disk, 6, 4, 1, 0, 1);
357         battfs_writeTestBlock(disk, 7, 4, 0, 0, 1);
358
359
360         fclose(fp);
361         ref[0] = 1;
362         ref[1] = 2;
363         ref[2] = 5;
364         ref[3] = 6;
365         ref[4] = 0;
366         ref[5] = 3;
367         ref[6] = 4;
368         ref[7] = 7;
369
370         testCheck(disk, ref);
371         kprintf("Test9: passed\n");
372 }
373
374 static void test10(BattFsSuper *disk)
375 {
376         BattFs fd1;
377         BattFs fd2;
378         kprintf("Test10: open file test, inode 0 and inode 4\n");
379
380         fp = fopen(test_filename, "w+");
381
382         int PAGE_FILL = PAGE_SIZE - BATTFS_HEADER_LEN;
383         unsigned int INODE = 0;
384         unsigned int INODE2 = 4;
385         unsigned int INEXISTENT_INODE = 123;
386         unsigned int MODE = 0;
387
388         // page, inode, seq, fill, pgoff
389         disk->erase(disk, 0);
390         battfs_writeTestBlock(disk, 1, INODE, 0, PAGE_FILL, 0);
391         battfs_writeTestBlock(disk, 2, INODE, 3, PAGE_FILL, 1);
392         battfs_writeTestBlock(disk, 3, INODE, 0, PAGE_FILL, 1);
393         disk->erase(disk, 4);
394         battfs_writeTestBlock(disk, 5, INODE2, 0, PAGE_FILL, 0);
395         battfs_writeTestBlock(disk, 6, INODE2, 1, PAGE_FILL, 1);
396         battfs_writeTestBlock(disk, 7, INODE2, 0, PAGE_FILL, 1);
397
398         fclose(fp);
399
400         ASSERT(battfs_init(disk));
401         ASSERT(!battfs_fileExists(disk, INEXISTENT_INODE));
402
403         ASSERT(battfs_fileExists(disk, INODE));
404         ASSERT(battfs_fileopen(disk, &fd1, INODE, MODE));
405         ASSERT(fd1.fd.size == PAGE_FILL * 2);
406         ASSERT(fd1.fd.seek_pos == 0);
407         ASSERT(fd1.mode == MODE);
408         ASSERT(fd1.inode == INODE);
409         ASSERT(fd1.start == &disk->page_array[0]);
410         ASSERT(fd1.disk == disk);
411         ASSERT(LIST_HEAD(&disk->file_opened_list) == &fd1.link);
412
413         ASSERT(kfile_reopen(&fd1.fd) == &fd1.fd);
414         ASSERT(fd1.fd.size == PAGE_FILL * 2);
415         ASSERT(fd1.fd.seek_pos == 0);
416         ASSERT(fd1.mode == MODE);
417         ASSERT(fd1.inode == INODE);
418         ASSERT(fd1.start == &disk->page_array[0]);
419         ASSERT(fd1.disk == disk);
420         ASSERT(LIST_HEAD(&disk->file_opened_list) == &fd1.link);
421
422         ASSERT(battfs_fileExists(disk, INODE2));
423         ASSERT(battfs_fileopen(disk, &fd2, INODE2, MODE));
424         ASSERT(fd2.fd.size == PAGE_FILL * 2);
425         ASSERT(fd2.fd.seek_pos == 0);
426         ASSERT(fd2.mode == MODE);
427         ASSERT(fd2.inode == INODE2);
428         ASSERT(fd2.start == &disk->page_array[2]);
429         ASSERT(fd2.disk == disk);
430         ASSERT(LIST_HEAD(&disk->file_opened_list)->succ == &fd2.link);
431
432         ASSERT(kfile_close(&fd1.fd) == 0);
433         ASSERT(kfile_close(&fd2.fd) == 0);
434         ASSERT(LIST_EMPTY(&disk->file_opened_list));
435         ASSERT(battfs_close(disk));
436
437         kprintf("Test10: passed\n");
438 }
439
440 static void test11(BattFsSuper *disk)
441 {
442         BattFs fd1;
443         uint8_t buf[16];
444
445         kprintf("Test11: read file test\n");
446
447         fp = fopen(test_filename, "w+");
448
449         unsigned int PAGE_FILL = PAGE_SIZE - BATTFS_HEADER_LEN;
450         unsigned int INODE = 0;
451         unsigned int INODE2 = 4;
452         unsigned int MODE = 0;
453
454         disk->erase(disk, 0);
455         battfs_writeTestBlock(disk, 1, INODE, 0, PAGE_FILL, 0);
456         battfs_writeTestBlock(disk, 2, INODE, 3, PAGE_FILL, 1);
457         battfs_writeTestBlock(disk, 3, INODE, 0, PAGE_FILL, 1);
458         disk->erase(disk, 4);
459         battfs_writeTestBlock(disk, 5, INODE2, 0, PAGE_FILL, 0);
460         battfs_writeTestBlock(disk, 6, INODE2, 1, PAGE_FILL, 1);
461         battfs_writeTestBlock(disk, 7, INODE2, 0, PAGE_FILL, 1);
462
463         fclose(fp);
464
465         ASSERT(battfs_init(disk));
466         ASSERT(battfs_fileopen(disk, &fd1, INODE, MODE));
467         ASSERT(kfile_read(&fd1.fd, buf, sizeof(buf)) == sizeof(buf));
468         ASSERT(fd1.fd.seek_pos == sizeof(buf));
469         for (size_t i = 0; i < sizeof(buf); i++)
470                 ASSERT(buf[i] == 0);
471
472         ASSERT(kfile_close(&fd1.fd) == 0);
473         ASSERT(battfs_close(disk));
474
475         kprintf("Test11: passed\n");
476 }
477
478 static void test12(BattFsSuper *disk)
479 {
480         BattFs fd1;
481
482         kprintf("Test12: read file test across page boundary and seek test\n");
483
484         fp = fopen(test_filename, "w+");
485
486         const unsigned int PAGE_FILL = PAGE_SIZE - BATTFS_HEADER_LEN;
487         unsigned int INODE = 0;
488         unsigned int MODE = 0;
489         uint8_t buf[PAGE_FILL + BATTFS_HEADER_LEN / 2];
490
491         disk->erase(disk, 0);
492         battfs_writeTestBlock(disk, 1, INODE, 0, PAGE_FILL, 0);
493         battfs_writeTestBlock(disk, 2, INODE, 3, PAGE_FILL, 1);
494         battfs_writeTestBlock(disk, 3, INODE, 0, PAGE_FILL, 1);
495         disk->erase(disk, 4);
496         battfs_writeTestBlock(disk, 5, INODE, 0, PAGE_FILL, 2);
497         battfs_writeTestBlock(disk, 6, INODE, 1, PAGE_FILL, 3);
498         battfs_writeTestBlock(disk, 7, INODE, 0, PAGE_FILL, 3);
499
500         fclose(fp);
501
502         ASSERT(battfs_init(disk));
503         ASSERT(battfs_fileopen(disk, &fd1, INODE, MODE));
504
505         ASSERT(kfile_read(&fd1.fd, buf, sizeof(buf)) == sizeof(buf));
506         ASSERT(fd1.fd.seek_pos == (kfile_off_t)sizeof(buf));
507         for (size_t i = 0; i < sizeof(buf); i++)
508                 ASSERT(buf[i] == 0);
509
510         ASSERT(kfile_read(&fd1.fd, buf, sizeof(buf)) == sizeof(buf));
511         ASSERT(fd1.fd.seek_pos == (kfile_off_t)sizeof(buf) * 2);
512         for (size_t i = 0; i < sizeof(buf); i++)
513                 ASSERT(buf[i] == 0);
514
515         ASSERT(kfile_read(&fd1.fd, buf, sizeof(buf)) == sizeof(buf));
516         ASSERT(fd1.fd.seek_pos == (kfile_off_t)sizeof(buf) * 3);
517         for (size_t i = 0; i < sizeof(buf); i++)
518                 ASSERT(buf[i] == 0);
519
520         ASSERT(kfile_read(&fd1.fd, buf, sizeof(buf)) == PAGE_FILL * 4 - sizeof(buf) * 3);
521         ASSERT(fd1.fd.seek_pos == (kfile_off_t)fd1.fd.size);
522         for (size_t i = 0; i < PAGE_FILL * 4 - sizeof(buf) * 3; i++)
523                 ASSERT(buf[i] == 0);
524
525         ASSERT(kfile_seek(&fd1.fd, 0, KSM_SEEK_SET) == 0);
526         ASSERT(fd1.fd.seek_pos == 0);
527
528         ASSERT(kfile_seek(&fd1.fd, 0, KSM_SEEK_END) == (kfile_off_t)fd1.fd.size);
529         ASSERT(fd1.fd.seek_pos = (kfile_off_t)fd1.fd.size);
530
531         ASSERT(kfile_close(&fd1.fd) == 0);
532         ASSERT(battfs_close(disk));
533
534         kprintf("Test12: passed\n");
535 }
536
537
538 int battfs_testRun(void)
539 {
540         BattFsSuper disk;
541
542         disk.open = disk_open;
543         disk.read = disk_page_read;
544         disk.load = disk_page_load;
545         disk.bufferWrite = disk_buffer_write;
546         disk.save = disk_page_save;
547         disk.erase = disk_page_erase;
548         disk.close = disk_close;
549         test1(&disk);
550         test2(&disk);
551         test3(&disk);
552         //test4(&disk);
553         //test5(&disk);
554         test6(&disk);
555         test7(&disk);
556         test8(&disk);
557         test9(&disk);
558         test10(&disk);
559         test11(&disk);
560         test12(&disk);
561         kprintf("All tests passed!\n");
562
563         return 0;
564 }
565
566 int battfs_testSetup(void)
567 {
568         return 0;
569 }
570
571 int battfs_testTearDown(void)
572 {
573         return 0;
574 }
575
576 TEST_MAIN(battfs)
577
578 #include <fs/battfs.c>
579 #include <kern/kfile.c>
580 #include <drv/kdebug.c>
581 #include <mware/formatwr.c>
582 #include <mware/hex.c>
583
584 #endif // _TEST