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