5b5c4631fd5b0fc97cd22a4b143f8f5e2997892b
[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] = PAGE_COUNT - i - 1;
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, MARK_PAGE_VALID);
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, MARK_PAGE_VALID);
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] = PAGE_COUNT + PAGE_COUNT / 2 - i - 1;
190         }
191
192
193         testCheck(disk, ref);
194         kprintf("Test3: passed\n");
195 }
196
197 static void test4(BattFsSuper *disk)
198 {
199         pgcnt_t ref[PAGE_COUNT];
200         kprintf("Test4: disk half full with 1 contiguos file, rest marked free\n");
201
202
203         fp = fopen(test_filename, "w+");
204
205         for (int i = 0; i < PAGE_COUNT / 2; i++)
206         {
207                 battfs_writeTestBlock(disk, i, 0, 0, 0, i, MARK_PAGE_VALID);
208                 ref[i] = i;
209         }
210         for (int i = PAGE_COUNT / 2; i < PAGE_COUNT; i++)
211         {
212                 battfs_writeTestBlock(disk, i, 0, 0, 0, i, i);
213                 ref[i] = i;
214         }
215         fclose(fp);
216
217
218         testCheck(disk, ref);
219         kprintf("Test4: passed\n");
220 }
221
222 static void test5(BattFsSuper *disk)
223 {
224         pgcnt_t ref[PAGE_COUNT];
225         kprintf("Test5: disk 1/3 full with 1 contiguos file, 1/3 marked free, rest unformatted\n");
226
227
228         fp = fopen(test_filename, "w+");
229
230         for (int i = 0; i < FILE_SIZE; i++)
231                 fputc(0xff, fp);
232
233         for (int i = 0; i < PAGE_COUNT / 3; i++)
234         {
235                 battfs_writeTestBlock(disk, i, 0, 0, 0, i, MARK_PAGE_VALID);
236                 ref[i] = i;
237         }
238         for (int i = PAGE_COUNT / 3; i < 2 * (PAGE_COUNT / 3); i++)
239         {
240                 battfs_writeTestBlock(disk, i, 0, 0, 0, i, i);
241                 ref[i + PAGE_COUNT / 3 + 1] = i;
242         }
243         fclose(fp);
244
245         for (int i = PAGE_COUNT / 3; i < 2 * (PAGE_COUNT / 3) + 1; i++)
246                 ref[i] = PAGE_COUNT + PAGE_COUNT / 3 - i - 1;
247
248         testCheck(disk, ref);
249         kprintf("Test5: passed\n");
250 }
251
252 static void test6(BattFsSuper *disk)
253 {
254         pgcnt_t ref[4];
255         kprintf("Test6: 1 file with 1 old seq num, 1 free block\n");
256
257
258         fp = fopen(test_filename, "w+");
259
260         battfs_writeTestBlock(disk, 0, 0, 0, 0, 0, MARK_PAGE_VALID);
261         battfs_writeTestBlock(disk, 1, 0, 0, 0, 1, MARK_PAGE_VALID);
262         battfs_writeTestBlock(disk, 2, 0, 1, 0, 1, MARK_PAGE_VALID);
263         battfs_writeTestBlock(disk, 3, 0, 0, 0, 0, 123);
264
265         fclose(fp);
266         ref[0] = 0;
267         ref[1] = 2;
268         ref[2] = 3;
269         ref[3] = 1;
270
271         testCheck(disk, ref);
272         kprintf("Test6: passed\n");
273 }
274
275 static void test7(BattFsSuper *disk)
276 {
277         pgcnt_t ref[4];
278         kprintf("Test7: 1 file with 1 old seq num, 1 free block\n");
279
280
281         fp = fopen(test_filename, "w+");
282
283         battfs_writeTestBlock(disk, 0, 0, 0, 0, 0, MARK_PAGE_VALID);
284         battfs_writeTestBlock(disk, 1, 0, 1, 0, 1, MARK_PAGE_VALID);
285         battfs_writeTestBlock(disk, 2, 0, 0, 0, 1, MARK_PAGE_VALID);
286         battfs_writeTestBlock(disk, 3, 0, 0, 0, 0, 123);
287
288         fclose(fp);
289         ref[0] = 0;
290         ref[1] = 1;
291         ref[2] = 3;
292         ref[3] = 2;
293
294         testCheck(disk, ref);
295         kprintf("Test7: passed\n");
296 }
297
298 static void test8(BattFsSuper *disk)
299 {
300         pgcnt_t ref[4];
301         kprintf("Test8: 1 file with 1 old seq num, 1 free block\n");
302
303
304         fp = fopen(test_filename, "w+");
305
306         battfs_writeTestBlock(disk, 0, 0, 0, 0, 0, 1235);
307         battfs_writeTestBlock(disk, 1, 0, 0, 0, 0, MARK_PAGE_VALID);
308         battfs_writeTestBlock(disk, 2, 0, 1, 0, 1, MARK_PAGE_VALID);
309         battfs_writeTestBlock(disk, 3, 0, 0, 0, 1, MARK_PAGE_VALID);
310
311
312         fclose(fp);
313         ref[0] = 1;
314         ref[1] = 2;
315         ref[2] = 0;
316         ref[3] = 3;
317
318         testCheck(disk, ref);
319         kprintf("Test8: passed\n");
320 }
321
322 static void test9(BattFsSuper *disk)
323 {
324         pgcnt_t ref[8];
325         kprintf("Test9: 2 file with old seq num, 2 free block\n");
326
327
328         fp = fopen(test_filename, "w+");
329
330         battfs_writeTestBlock(disk, 0, 0, 0, 0, 0, 1235);
331         battfs_writeTestBlock(disk, 1, 0, 0, 0, 0, MARK_PAGE_VALID);
332         battfs_writeTestBlock(disk, 2, 0, 3, 0, 1, MARK_PAGE_VALID);
333         battfs_writeTestBlock(disk, 3, 0, 0, 0, 1, MARK_PAGE_VALID);
334         battfs_writeTestBlock(disk, 4, 0, 0, 0, 0, 1236);
335         battfs_writeTestBlock(disk, 5, 4, 0, 0, 0, MARK_PAGE_VALID);
336         battfs_writeTestBlock(disk, 6, 4, 1, 0, 1, MARK_PAGE_VALID);
337         battfs_writeTestBlock(disk, 7, 4, 0, 0, 1, MARK_PAGE_VALID);
338
339
340         fclose(fp);
341         ref[0] = 1;
342         ref[1] = 3;
343         ref[2] = 5;
344         ref[3] = 6;
345         ref[4] = 0;
346         ref[5] = 4;
347         ref[6] = 2;
348         ref[7] = 7;
349
350         testCheck(disk, ref);
351         kprintf("Test9: passed\n");
352 }
353
354 static void test10(BattFsSuper *disk)
355 {
356         BattFS fd1;
357         BattFS fd2;
358         kprintf("Test10: open file test, inode 0 and inode 4\n");
359
360         fp = fopen(test_filename, "w+");
361
362         unsigned int PAGE_FILL = 116;
363         unsigned int INODE = 0;
364         unsigned int INODE2 = 4;
365         unsigned int INEXISTENT_INODE = 123;
366         unsigned int MODE = 0;
367
368         battfs_writeTestBlock(disk, 0, 123, 0, PAGE_FILL, 0, 1235);
369         battfs_writeTestBlock(disk, 1, INODE, 0, PAGE_FILL, 0, MARK_PAGE_VALID);
370         battfs_writeTestBlock(disk, 2, INODE, 3, PAGE_FILL, 1, MARK_PAGE_VALID);
371         battfs_writeTestBlock(disk, 3, INODE, 0, PAGE_FILL, 1, MARK_PAGE_VALID);
372         battfs_writeTestBlock(disk, 4, INODE2, 0, PAGE_FILL, 0, 1236);
373         battfs_writeTestBlock(disk, 5, INODE2, 0, PAGE_FILL, 0, MARK_PAGE_VALID);
374         battfs_writeTestBlock(disk, 6, INODE2, 1, PAGE_FILL, 1, MARK_PAGE_VALID);
375         battfs_writeTestBlock(disk, 7, INODE2, 0, PAGE_FILL, 1, MARK_PAGE_VALID);
376
377         fclose(fp);
378
379         ASSERT(battfs_init(disk));
380         ASSERT(!battfs_fileExists(disk, INEXISTENT_INODE));
381
382         ASSERT(battfs_fileExists(disk, INODE));
383         ASSERT(battfs_fileopen(disk, &fd1, INODE, MODE));
384         ASSERT(fd1.fd.size == PAGE_FILL * 2);
385         ASSERT(fd1.fd.seek_pos == 0);
386         ASSERT(fd1.mode == MODE);
387         ASSERT(fd1.inode == INODE);
388         ASSERT(fd1.start == &disk->page_array[0]);
389         ASSERT(fd1.disk == disk);
390         ASSERT(LIST_HEAD(&disk->file_opened_list) == &fd1.link);
391
392         ASSERT(kfile_reopen(&fd1.fd) == &fd1.fd);
393         ASSERT(fd1.fd.size == PAGE_FILL * 2);
394         ASSERT(fd1.fd.seek_pos == 0);
395         ASSERT(fd1.mode == MODE);
396         ASSERT(fd1.inode == INODE);
397         ASSERT(fd1.start == &disk->page_array[0]);
398         ASSERT(fd1.disk == disk);
399         ASSERT(LIST_HEAD(&disk->file_opened_list) == &fd1.link);
400
401         ASSERT(battfs_fileExists(disk, INODE2));
402         ASSERT(battfs_fileopen(disk, &fd2, INODE2, MODE));
403         ASSERT(fd2.fd.size == PAGE_FILL * 2);
404         ASSERT(fd2.fd.seek_pos == 0);
405         ASSERT(fd2.mode == MODE);
406         ASSERT(fd2.inode == INODE2);
407         ASSERT(fd2.start == &disk->page_array[2]);
408         ASSERT(fd2.disk == disk);
409         ASSERT(LIST_HEAD(&disk->file_opened_list)->succ == &fd2.link);
410
411         ASSERT(kfile_close(&fd1.fd) == 0);
412         ASSERT(kfile_close(&fd2.fd) == 0);
413         ASSERT(LIST_EMPTY(&disk->file_opened_list));
414         ASSERT(battfs_close(disk));
415
416         kprintf("Test10: passed\n");
417 }
418
419 static void test11(BattFsSuper *disk)
420 {
421         BattFS fd1;
422         uint8_t buf[16];
423
424         kprintf("Test11: read file test\n");
425
426         fp = fopen(test_filename, "w+");
427
428         unsigned int PAGE_FILL = 116;
429         unsigned int INODE = 0;
430         unsigned int INODE2 = 4;
431         unsigned int MODE = 0;
432
433         battfs_writeTestBlock(disk, 0, 123, 0, PAGE_FILL, 0, 1235);
434         battfs_writeTestBlock(disk, 1, INODE, 0, PAGE_FILL, 0, MARK_PAGE_VALID);
435         battfs_writeTestBlock(disk, 2, INODE, 3, PAGE_FILL, 1, MARK_PAGE_VALID);
436         battfs_writeTestBlock(disk, 3, INODE, 0, PAGE_FILL, 1, MARK_PAGE_VALID);
437         battfs_writeTestBlock(disk, 4, INODE2, 0, PAGE_FILL, 0, 1236);
438         battfs_writeTestBlock(disk, 5, INODE2, 0, PAGE_FILL, 0, MARK_PAGE_VALID);
439         battfs_writeTestBlock(disk, 6, INODE2, 1, PAGE_FILL, 1, MARK_PAGE_VALID);
440         battfs_writeTestBlock(disk, 7, INODE2, 0, PAGE_FILL, 1, MARK_PAGE_VALID);
441
442         fclose(fp);
443
444         ASSERT(battfs_init(disk));
445         ASSERT(battfs_fileopen(disk, &fd1, INODE, MODE));
446         ASSERT(kfile_read(&fd1.fd, buf, sizeof(buf)) == sizeof(buf));
447         ASSERT(fd1.fd.seek_pos == sizeof(buf));
448         for (size_t i = 0; i < sizeof(buf); i++)
449                 ASSERT(buf[i] == 0);
450
451         ASSERT(kfile_close(&fd1.fd) == 0);
452         ASSERT(battfs_close(disk));
453
454         kprintf("Test11: passed\n");
455 }
456
457 static void test12(BattFsSuper *disk)
458 {
459         BattFS fd1;
460
461         kprintf("Test12: read file test across page boundary and seek test\n");
462
463         fp = fopen(test_filename, "w+");
464
465         const unsigned int PAGE_FILL = 116;
466         unsigned int INODE = 0;
467         unsigned int MODE = 0;
468         uint8_t buf[PAGE_FILL + 10];
469
470         battfs_writeTestBlock(disk, 0, 123, 0, PAGE_FILL, 0, 1235);
471         battfs_writeTestBlock(disk, 1, INODE, 0, PAGE_FILL, 0, MARK_PAGE_VALID);
472         battfs_writeTestBlock(disk, 2, INODE, 3, PAGE_FILL, 1, MARK_PAGE_VALID);
473         battfs_writeTestBlock(disk, 3, INODE, 0, PAGE_FILL, 1, MARK_PAGE_VALID);
474         battfs_writeTestBlock(disk, 4, INODE, 0, PAGE_FILL, 0, 1236);
475         battfs_writeTestBlock(disk, 5, INODE, 0, PAGE_FILL, 2, MARK_PAGE_VALID);
476         battfs_writeTestBlock(disk, 6, INODE, 1, PAGE_FILL, 3, MARK_PAGE_VALID);
477         battfs_writeTestBlock(disk, 7, INODE, 0, PAGE_FILL, 3, MARK_PAGE_VALID);
478
479         fclose(fp);
480
481         ASSERT(battfs_init(disk));
482         ASSERT(battfs_fileopen(disk, &fd1, INODE, MODE));
483
484         ASSERT(kfile_read(&fd1.fd, buf, sizeof(buf)) == sizeof(buf));
485         ASSERT(fd1.fd.seek_pos == (kfile_off_t)sizeof(buf));
486         for (size_t i = 0; i < sizeof(buf); i++)
487                 ASSERT(buf[i] == 0);
488
489         ASSERT(kfile_read(&fd1.fd, buf, sizeof(buf)) == sizeof(buf));
490         ASSERT(fd1.fd.seek_pos == (kfile_off_t)sizeof(buf) * 2);
491         for (size_t i = 0; i < sizeof(buf); i++)
492                 ASSERT(buf[i] == 0);
493
494         ASSERT(kfile_read(&fd1.fd, buf, sizeof(buf)) == sizeof(buf));
495         ASSERT(fd1.fd.seek_pos == (kfile_off_t)sizeof(buf) * 3);
496         for (size_t i = 0; i < sizeof(buf); i++)
497                 ASSERT(buf[i] == 0);
498
499         ASSERT(kfile_read(&fd1.fd, buf, sizeof(buf)) == 86);
500         ASSERT(fd1.fd.seek_pos == (kfile_off_t)fd1.fd.size);
501         for (size_t i = 0; i < 86; i++)
502                 ASSERT(buf[i] == 0);
503
504         ASSERT(kfile_seek(&fd1.fd, 0, KSM_SEEK_SET) == 0);
505         ASSERT(fd1.fd.seek_pos == 0);
506
507         ASSERT(kfile_seek(&fd1.fd, 0, KSM_SEEK_END) == (kfile_off_t)fd1.fd.size);
508         ASSERT(fd1.fd.seek_pos = (kfile_off_t)fd1.fd.size);
509
510         ASSERT(kfile_close(&fd1.fd) == 0);
511         ASSERT(battfs_close(disk));
512
513         kprintf("Test12: passed\n");
514 }
515
516
517 int battfs_testRun(void)
518 {
519         BattFsSuper disk;
520
521         disk.open = disk_open;
522         disk.read = disk_page_read;
523         disk.write = disk_page_write;
524         disk.erase = disk_page_erase;
525         disk.close = disk_close;
526         test1(&disk);
527         test2(&disk);
528         test3(&disk);
529         test4(&disk);
530         test5(&disk);
531         test6(&disk);
532         test7(&disk);
533         test8(&disk);
534         test9(&disk);
535         test10(&disk);
536         test11(&disk);
537         test12(&disk);
538         kprintf("All tests passed!\n");
539
540         return 0;
541 }
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 <kern/kfile.c>
557 #include <drv/kdebug.c>
558 #include <mware/formatwr.c>
559 #include <mware/hex.c>
560
561 #endif // _TEST