Add filesystem consistency check.
[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", 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("addr:%d, size:%d", addr, size);
80         ASSERT(addr + size <= d->page_size);
81         memcpy(&page_buffer[addr], buf, size);
82
83         return size;
84 }
85
86 static size_t disk_buffer_read(struct BattFsSuper *d, pgaddr_t addr, void *buf, size_t size)
87 {
88         //TRACEMSG("addr:%d, size:%d", addr, size);
89         ASSERT(addr + size <= d->page_size);
90         memcpy(buf, &page_buffer[addr], size);
91
92         return size;
93 }
94
95 static bool disk_page_load(struct BattFsSuper *d, pgcnt_t page)
96 {
97         //TRACEMSG("page:%d", page);
98         fseek(fp, page * d->page_size, SEEK_SET);
99         return fread(page_buffer, 1, d->page_size, fp) == d->page_size;
100 }
101
102 static bool disk_page_save(struct BattFsSuper *d, pgcnt_t page)
103 {
104         //TRACEMSG("page:%d", page);
105         fseek(fp, page * d->page_size, SEEK_SET);
106         return fwrite(page_buffer, 1, d->page_size, fp) == d->page_size;
107 }
108
109 static bool disk_page_erase(struct BattFsSuper *d, pgcnt_t page)
110 {
111         //TRACEMSG("page:%d", page);
112         fseek(fp, page * d->page_size, SEEK_SET);
113
114         for (int i = 0; i < d->page_size; i++)
115                 if (fputc(0xff, fp) == EOF)
116                         return false;
117         return true;
118 }
119
120 static bool disk_close(struct BattFsSuper *d)
121 {
122         //TRACE;
123         free(d->page_array);
124         return (fclose(fp) != EOF);
125 }
126
127 static void testCheck(BattFsSuper *disk, pgcnt_t *reference)
128 {
129         ASSERT(battfs_init(disk));
130
131         for (int i = 0; i < disk->page_count; i++)
132         {
133                 if (disk->page_array[i] != reference[i])
134                 {
135                         kprintf("Error at addr %d: page_array read", i);
136                         for (pgcnt_t i = 0; i < disk->page_count; i++)
137                         {
138                                 if (!(i % 16))
139                                         kputchar('\n');
140                                 kprintf("%04d ", disk->page_array[i]);
141                         }
142                         kputchar('\n');
143                         kprintf("Expected:");
144                         for (pgcnt_t i = 0; i < disk->page_count; i++)
145                         {
146                                 if (!(i % 16))
147                                         kputchar('\n');
148                                 kprintf("%04d ", reference[i]);
149                         }
150                         kputchar('\n');
151                         battfs_close(disk);
152                         exit(2);
153                 }
154         }
155         ASSERT(battfs_fsck(disk));
156         battfs_close(disk);
157 }
158
159 static void diskNew(BattFsSuper *disk)
160 {
161         pgcnt_t ref[PAGE_COUNT];
162         TRACEMSG("1: disk new\n");
163
164         FILE *fpt = fopen(test_filename, "w+");
165
166         for (int i = 0; i < FILE_SIZE; i++)
167                 fputc(0xff, fpt);
168         fclose(fpt);
169         for (int i = 0; i < PAGE_COUNT; i++)
170                 ref[i] = i;
171
172         testCheck(disk, ref);
173         TRACEMSG("1: passed\n");
174 }
175
176 static void disk1File(BattFsSuper *disk)
177 {
178         pgcnt_t ref[PAGE_COUNT];
179         TRACEMSG("2: disk full with 1 contiguos file\n");
180
181
182         fp = fopen(test_filename, "w+");
183
184         for (int i = 0; i < PAGE_COUNT; i++)
185         {
186                 battfs_writeTestBlock(disk, i, 0, 0, disk->data_size, i);
187                 ref[i] = i;
188         }
189         fclose(fp);
190
191         testCheck(disk, ref);
192         TRACEMSG("2: passed\n");
193 }
194
195
196 static void diskHalfFile(BattFsSuper *disk)
197 {
198         pgcnt_t ref[PAGE_COUNT];
199         TRACEMSG("3: disk half full with 1 contiguos file, rest unformatted\n");
200
201
202         fp = fopen(test_filename, "w+");
203
204         for (int i = 0; i < PAGE_COUNT / 2; i++)
205         {
206                 battfs_writeTestBlock(disk, i, 0, 0, disk->data_size, i);
207                 ref[i] = i;
208         }
209         fseek(fp, FILE_SIZE / 2, SEEK_SET);
210         for (int i = FILE_SIZE / 2; i < FILE_SIZE; i++)
211                 fputc(0xff, fp);
212         fclose(fp);
213
214         for (int i = PAGE_COUNT / 2; i < PAGE_COUNT; i++)
215         {
216                 ref[i] = i;
217         }
218
219
220         testCheck(disk, ref);
221         TRACEMSG("3: passed\n");
222 }
223
224
225 static void oldSeq1(BattFsSuper *disk)
226 {
227         pgcnt_t ref[4];
228         TRACEMSG("6: 1 file with 1 old seq num, 1 free block\n");
229
230
231         fp = fopen(test_filename, "w+");
232         // page, inode, seq, fill, pgoff
233         battfs_writeTestBlock(disk, 0, 0, 0, disk->data_size, 0);
234         battfs_writeTestBlock(disk, 1, 0, 0, disk->data_size, 1);
235         battfs_writeTestBlock(disk, 2, 0, 1, disk->data_size, 1);
236         disk->erase(disk, 3);
237
238
239         fclose(fp);
240         ref[0] = 0;
241         ref[1] = 2;
242         ref[2] = 1;
243         ref[3] = 3;
244
245         testCheck(disk, ref);
246         TRACEMSG("6: passed\n");
247 }
248
249 static void oldSeq2(BattFsSuper *disk)
250 {
251         pgcnt_t ref[4];
252         TRACEMSG("7: 1 file with 1 old seq num, 1 free block\n");
253
254
255         fp = fopen(test_filename, "w+");
256         // page, inode, seq, fill, pgoff
257         battfs_writeTestBlock(disk, 0, 0, 0, disk->data_size, 0);
258         battfs_writeTestBlock(disk, 1, 0, 1, disk->data_size, 1);
259         battfs_writeTestBlock(disk, 2, 0, 0, disk->data_size, 1);
260         disk->erase(disk, 3);
261
262         fclose(fp);
263         ref[0] = 0;
264         ref[1] = 1;
265         ref[2] = 2;
266         ref[3] = 3;
267
268         testCheck(disk, ref);
269         TRACEMSG("7: passed\n");
270 }
271
272 static void oldSeq3(BattFsSuper *disk)
273 {
274         pgcnt_t ref[4];
275         TRACEMSG("8: 1 file with 1 old seq num, 1 free block\n");
276
277
278         fp = fopen(test_filename, "w+");
279
280         // page, inode, seq, fill, pgoff
281         disk->erase(disk, 0);
282         battfs_writeTestBlock(disk, 1, 0, 0, disk->data_size, 0);
283         battfs_writeTestBlock(disk, 2, 0, 1, disk->data_size, 1);
284         battfs_writeTestBlock(disk, 3, 0, 0, disk->data_size, 1);
285
286
287         fclose(fp);
288         ref[0] = 1;
289         ref[1] = 2;
290         ref[2] = 0;
291         ref[3] = 3;
292
293         testCheck(disk, ref);
294         TRACEMSG("8: passed\n");
295 }
296
297 static void oldSeq2File(BattFsSuper *disk)
298 {
299         pgcnt_t ref[8];
300         TRACEMSG("9: 2 file with old seq num, 2 free block\n");
301
302
303         fp = fopen(test_filename, "w+");
304
305         // page, inode, seq, fill, pgoff
306         disk->erase(disk, 0);
307         battfs_writeTestBlock(disk, 1, 0, 0, disk->data_size, 0);
308         battfs_writeTestBlock(disk, 2, 0, 3, disk->data_size, 1);
309         battfs_writeTestBlock(disk, 3, 0, 0, disk->data_size, 1);
310         disk->erase(disk, 4);
311         battfs_writeTestBlock(disk, 5, 4, 0, disk->data_size, 0);
312         battfs_writeTestBlock(disk, 6, 4, 1, disk->data_size, 1);
313         battfs_writeTestBlock(disk, 7, 4, 0, disk->data_size, 1);
314
315
316         fclose(fp);
317         ref[0] = 1;
318         ref[1] = 2;
319         ref[2] = 5;
320         ref[3] = 6;
321         ref[4] = 0;
322         ref[5] = 3;
323         ref[6] = 4;
324         ref[7] = 7;
325
326         testCheck(disk, ref);
327         TRACEMSG("9: passed\n");
328 }
329
330 static void openFile(BattFsSuper *disk)
331 {
332         BattFs fd1;
333         BattFs fd2;
334         TRACEMSG("10: open file test, inode 0 and inode 4\n");
335
336         fp = fopen(test_filename, "w+");
337
338         int PAGE_FILL = PAGE_SIZE - BATTFS_HEADER_LEN;
339         inode_t INODE = 0;
340         inode_t INODE2 = 4;
341         inode_t INEXISTENT_INODE = 123;
342         unsigned int MODE = 0;
343
344         // page, inode, seq, fill, pgoff
345         disk->erase(disk, 0);
346         battfs_writeTestBlock(disk, 1, INODE, 0, PAGE_FILL, 0);
347         battfs_writeTestBlock(disk, 2, INODE, 3, PAGE_FILL, 1);
348         battfs_writeTestBlock(disk, 3, INODE, 0, PAGE_FILL, 1);
349         disk->erase(disk, 4);
350         battfs_writeTestBlock(disk, 5, INODE2, 0, PAGE_FILL, 0);
351         battfs_writeTestBlock(disk, 6, INODE2, 1, PAGE_FILL, 1);
352         battfs_writeTestBlock(disk, 7, INODE2, 0, PAGE_FILL, 1);
353
354         fclose(fp);
355
356         ASSERT(battfs_init(disk));
357         ASSERT(!battfs_fileExists(disk, INEXISTENT_INODE));
358
359         ASSERT(battfs_fileExists(disk, INODE));
360         ASSERT(battfs_fileopen(disk, &fd1, INODE, MODE));
361         ASSERT(fd1.fd.size == PAGE_FILL * 2);
362         ASSERT(fd1.fd.seek_pos == 0);
363         ASSERT(fd1.mode == MODE);
364         ASSERT(fd1.inode == INODE);
365         ASSERT(fd1.start == &disk->page_array[0]);
366         ASSERT(fd1.disk == disk);
367         ASSERT(LIST_HEAD(&disk->file_opened_list) == &fd1.link);
368
369         ASSERT(kfile_reopen(&fd1.fd) == &fd1.fd);
370         ASSERT(fd1.fd.size == PAGE_FILL * 2);
371         ASSERT(fd1.fd.seek_pos == 0);
372         ASSERT(fd1.mode == MODE);
373         ASSERT(fd1.inode == INODE);
374         ASSERT(fd1.start == &disk->page_array[0]);
375         ASSERT(fd1.disk == disk);
376         ASSERT(LIST_HEAD(&disk->file_opened_list) == &fd1.link);
377
378         ASSERT(battfs_fileExists(disk, INODE2));
379         ASSERT(battfs_fileopen(disk, &fd2, INODE2, MODE));
380         ASSERT(fd2.fd.size == PAGE_FILL * 2);
381         ASSERT(fd2.fd.seek_pos == 0);
382         ASSERT(fd2.mode == MODE);
383         ASSERT(fd2.inode == INODE2);
384         ASSERT(fd2.start == &disk->page_array[2]);
385         ASSERT(fd2.disk == disk);
386         ASSERT(LIST_HEAD(&disk->file_opened_list)->succ == &fd2.link);
387
388         ASSERT(kfile_close(&fd1.fd) == 0);
389         ASSERT(kfile_close(&fd2.fd) == 0);
390         ASSERT(LIST_EMPTY(&disk->file_opened_list));
391         ASSERT(battfs_fsck(disk));
392         ASSERT(battfs_close(disk));
393
394         TRACEMSG("10: passed\n");
395 }
396
397 static void readFile(BattFsSuper *disk)
398 {
399         BattFs fd1;
400         uint8_t buf[16];
401
402         TRACEMSG("11: read file test\n");
403
404         fp = fopen(test_filename, "w+");
405
406         unsigned int PAGE_FILL = PAGE_SIZE - BATTFS_HEADER_LEN;
407         inode_t INODE = 0;
408         inode_t INODE2 = 4;
409         unsigned int MODE = 0;
410
411         disk->erase(disk, 0);
412         battfs_writeTestBlock(disk, 1, INODE, 0, PAGE_FILL, 0);
413         battfs_writeTestBlock(disk, 2, INODE, 3, PAGE_FILL, 1);
414         battfs_writeTestBlock(disk, 3, INODE, 0, PAGE_FILL, 1);
415         disk->erase(disk, 4);
416         battfs_writeTestBlock(disk, 5, INODE2, 0, PAGE_FILL, 0);
417         battfs_writeTestBlock(disk, 6, INODE2, 1, PAGE_FILL, 1);
418         battfs_writeTestBlock(disk, 7, INODE2, 0, PAGE_FILL, 1);
419
420         fclose(fp);
421
422         ASSERT(battfs_init(disk));
423         ASSERT(battfs_fileopen(disk, &fd1, INODE, MODE));
424         ASSERT(kfile_read(&fd1.fd, buf, sizeof(buf)) == sizeof(buf));
425         ASSERT(fd1.fd.seek_pos == sizeof(buf));
426         for (size_t i = 0; i < sizeof(buf); i++)
427                 ASSERT(buf[i] == 0xff);
428
429         ASSERT(kfile_close(&fd1.fd) == 0);
430         ASSERT(battfs_fsck(disk));
431         ASSERT(battfs_close(disk));
432
433         TRACEMSG("11: passed\n");
434 }
435
436 static void readAcross(BattFsSuper *disk)
437 {
438         BattFs fd1;
439
440         TRACEMSG("12: read file test across page boundary and seek test\n");
441
442         fp = fopen(test_filename, "w+");
443
444         const unsigned int PAGE_FILL = PAGE_SIZE - BATTFS_HEADER_LEN;
445         inode_t INODE = 0;
446         unsigned int MODE = 0;
447         uint8_t buf[PAGE_FILL + BATTFS_HEADER_LEN / 2];
448
449         disk->erase(disk, 0);
450         battfs_writeTestBlock(disk, 1, INODE, 0, PAGE_FILL, 0);
451         battfs_writeTestBlock(disk, 2, INODE, 3, PAGE_FILL, 1);
452         battfs_writeTestBlock(disk, 3, INODE, 0, PAGE_FILL, 1);
453         disk->erase(disk, 4);
454         battfs_writeTestBlock(disk, 5, INODE, 0, PAGE_FILL, 2);
455         battfs_writeTestBlock(disk, 6, INODE, 1, PAGE_FILL, 3);
456         battfs_writeTestBlock(disk, 7, INODE, 0, PAGE_FILL, 3);
457
458         fclose(fp);
459
460         ASSERT(battfs_init(disk));
461         ASSERT(battfs_fileopen(disk, &fd1, INODE, MODE));
462
463         ASSERT(kfile_read(&fd1.fd, buf, sizeof(buf)) == sizeof(buf));
464         ASSERT(fd1.fd.seek_pos == (kfile_off_t)sizeof(buf));
465         for (size_t i = 0; i < sizeof(buf); i++)
466                 ASSERT(buf[i] == 0xff);
467
468         ASSERT(kfile_read(&fd1.fd, buf, sizeof(buf)) == sizeof(buf));
469         ASSERT(fd1.fd.seek_pos == (kfile_off_t)sizeof(buf) * 2);
470         for (size_t i = 0; i < sizeof(buf); i++)
471                 ASSERT(buf[i] == 0xff);
472
473         ASSERT(kfile_read(&fd1.fd, buf, sizeof(buf)) == sizeof(buf));
474         ASSERT(fd1.fd.seek_pos == (kfile_off_t)sizeof(buf) * 3);
475         for (size_t i = 0; i < sizeof(buf); i++)
476                 ASSERT(buf[i] == 0xff);
477
478         ASSERT(kfile_read(&fd1.fd, buf, sizeof(buf)) == PAGE_FILL * 4 - sizeof(buf) * 3);
479         ASSERT(fd1.fd.seek_pos == (kfile_off_t)fd1.fd.size);
480         for (size_t i = 0; i < PAGE_FILL * 4 - sizeof(buf) * 3; i++)
481                 ASSERT(buf[i] == 0xff);
482
483         ASSERT(kfile_seek(&fd1.fd, 0, KSM_SEEK_SET) == 0);
484         ASSERT(fd1.fd.seek_pos == 0);
485
486         ASSERT(kfile_seek(&fd1.fd, 0, KSM_SEEK_END) == (kfile_off_t)fd1.fd.size);
487         ASSERT(fd1.fd.seek_pos = (kfile_off_t)fd1.fd.size);
488
489         ASSERT(kfile_close(&fd1.fd) == 0);
490         ASSERT(battfs_fsck(disk));
491         ASSERT(battfs_close(disk));
492
493         TRACEMSG("12: passed\n");
494 }
495
496
497 static void writeFile(BattFsSuper *disk)
498 {
499         BattFs fd1;
500         uint8_t buf[PAGE_SIZE - BATTFS_HEADER_LEN];
501
502         TRACEMSG("13: write file test\n");
503
504         fp = fopen(test_filename, "w+");
505
506         unsigned int PAGE_FILL = PAGE_SIZE - BATTFS_HEADER_LEN;
507         inode_t INODE = 0;
508         inode_t INODE2 = 4;
509         unsigned int MODE = 0;
510
511         disk->erase(disk, 0);
512         battfs_writeTestBlock(disk, 1, INODE, 0, PAGE_FILL, 0);
513         battfs_writeTestBlock(disk, 2, INODE, 3, PAGE_FILL, 1);
514         battfs_writeTestBlock(disk, 3, INODE, 0, PAGE_FILL, 1);
515         disk->erase(disk, 4);
516         battfs_writeTestBlock(disk, 5, INODE2, 0, PAGE_FILL, 0);
517         battfs_writeTestBlock(disk, 6, INODE2, 1, PAGE_FILL, 1);
518         battfs_writeTestBlock(disk, 7, INODE2, 0, PAGE_FILL, 1);
519
520         fclose(fp);
521
522         for (size_t i = 0; i < sizeof(buf); i++)
523                 buf[i] = i;
524
525         ASSERT(battfs_init(disk));
526         ASSERT(battfs_fileopen(disk, &fd1, INODE, MODE));
527         ASSERT(kfile_write(&fd1.fd, buf, sizeof(buf)) == sizeof(buf));
528         ASSERT(fd1.fd.seek_pos == sizeof(buf));
529         ASSERT(kfile_seek(&fd1.fd, 0, KSM_SEEK_SET) == 0);
530         ASSERT(fd1.fd.seek_pos == 0);
531
532         memset(buf, 0, sizeof(buf));
533         ASSERT(kfile_read(&fd1.fd, buf, sizeof(buf)) == sizeof(buf));
534         for (size_t i = 0; i < sizeof(buf); i++)
535                 ASSERT(buf[i] == i);
536
537         ASSERT(kfile_close(&fd1.fd) == 0);
538         ASSERT(battfs_fsck(disk));
539         ASSERT(battfs_close(disk));
540
541         TRACEMSG("13: passed\n");
542 }
543
544 static void writeAcross(BattFsSuper *disk)
545 {
546         BattFs fd1;
547
548         TRACEMSG("14: write file test across page boundary and seek test\n");
549
550         fp = fopen(test_filename, "w+");
551
552         const unsigned int PAGE_FILL = PAGE_SIZE - BATTFS_HEADER_LEN;
553         inode_t INODE = 0;
554         unsigned int MODE = 0;
555         uint8_t buf[PAGE_FILL + BATTFS_HEADER_LEN / 2];
556
557         disk->erase(disk, 0);
558         battfs_writeTestBlock(disk, 1, INODE, 0, PAGE_FILL, 0);
559         battfs_writeTestBlock(disk, 2, INODE, 3, PAGE_FILL, 1);
560         battfs_writeTestBlock(disk, 3, INODE, 0, PAGE_FILL, 1);
561         disk->erase(disk, 4);
562         battfs_writeTestBlock(disk, 5, INODE, 0, PAGE_FILL, 2);
563         battfs_writeTestBlock(disk, 6, INODE, 1, PAGE_FILL, 3);
564         battfs_writeTestBlock(disk, 7, INODE, 0, PAGE_FILL, 3);
565
566         fclose(fp);
567
568         ASSERT(battfs_init(disk));
569         ASSERT(battfs_fileopen(disk, &fd1, INODE, MODE));
570
571         uint8_t val = 0;
572         for (size_t i = 0; i < sizeof(buf); i++)
573                 buf[i] = val++;
574         ASSERT(kfile_write(&fd1.fd, buf, sizeof(buf)) == sizeof(buf));
575         ASSERT(fd1.fd.seek_pos == (kfile_off_t)sizeof(buf));
576
577         for (size_t i = 0; i < sizeof(buf); i++)
578                 buf[i] = val++;
579         ASSERT(kfile_write(&fd1.fd, buf, sizeof(buf)) == sizeof(buf));
580         ASSERT(fd1.fd.seek_pos == (kfile_off_t)sizeof(buf) * 2);
581
582         for (size_t i = 0; i < sizeof(buf); i++)
583                 buf[i] = val++;
584         ASSERT(kfile_write(&fd1.fd, buf, sizeof(buf)) == sizeof(buf));
585         ASSERT(fd1.fd.seek_pos == (kfile_off_t)sizeof(buf) * 3);
586
587         ASSERT(kfile_seek(&fd1.fd, 0, KSM_SEEK_SET) == 0);
588         ASSERT(fd1.fd.seek_pos == 0);
589         val = 0;
590
591         memset(buf, 0, sizeof(buf));
592         ASSERT(kfile_read(&fd1.fd, buf, sizeof(buf)) == sizeof(buf));
593         for (size_t i = 0; i < sizeof(buf); i++)
594                 ASSERT(buf[i] == val++);
595
596         memset(buf, 0, sizeof(buf));
597         ASSERT(kfile_read(&fd1.fd, buf, sizeof(buf)) == sizeof(buf));
598         for (size_t i = 0; i < sizeof(buf); i++)
599                 ASSERT(buf[i] == val++);
600
601         memset(buf, 0, sizeof(buf));
602         ASSERT(kfile_read(&fd1.fd, buf, sizeof(buf)) == sizeof(buf));
603         for (size_t i = 0; i < sizeof(buf); i++)
604                 ASSERT(buf[i] == val++);
605
606         ASSERT(fd1.fd.seek_pos == (kfile_off_t)sizeof(buf) * 3);
607
608         ASSERT(kfile_close(&fd1.fd) == 0);
609         ASSERT(battfs_fsck(disk));
610         ASSERT(battfs_close(disk));
611
612         TRACEMSG("14: passed\n");
613 }
614
615 static void createFile(BattFsSuper *disk)
616 {
617         TRACEMSG("15: file creation on new disk\n");
618
619         FILE *fpt = fopen(test_filename, "w+");
620
621         for (int i = 0; i < FILE_SIZE; i++)
622                 fputc(0xff, fpt);
623         fclose(fpt);
624
625         BattFs fd1;
626         inode_t INODE = 0;
627         unsigned int MODE = BATTFS_CREATE;
628
629         ASSERT(battfs_init(disk));
630         ASSERT(battfs_fileopen(disk, &fd1, INODE, MODE));
631         for (int i = 0; i < FILE_SIZE / 2; i++)
632                 ASSERT(kfile_putc(i, &fd1.fd) != EOF);
633
634         ASSERT(fd1.fd.seek_pos == FILE_SIZE / 2);
635         ASSERT(fd1.fd.size == FILE_SIZE / 2);
636         ASSERT(kfile_close(&fd1.fd) == 0);
637         ASSERT(battfs_fsck(disk));
638         ASSERT(battfs_close(disk));
639
640         ASSERT(battfs_init(disk));
641         ASSERT(battfs_fileopen(disk, &fd1, INODE, 0));
642         ASSERT(fd1.fd.size == FILE_SIZE / 2);
643         ASSERT(fd1.fd.seek_pos == 0);
644
645         uint8_t buf[FILE_SIZE / 2];
646         memset(buf, 0, sizeof(buf));
647         ASSERT(kfile_read(&fd1.fd, buf, FILE_SIZE / 2) == FILE_SIZE / 2);
648
649         for (int i = 0; i < FILE_SIZE / 2; i++)
650                 ASSERT(buf[i] == (i & 0xff));
651
652         ASSERT(fd1.fd.seek_pos == FILE_SIZE / 2);
653         ASSERT(kfile_close(&fd1.fd) == 0);
654         ASSERT(battfs_fsck(disk));
655         ASSERT(battfs_close(disk));
656
657
658         TRACEMSG("15: passed\n");
659 }
660
661 static void multipleWrite(BattFsSuper *disk)
662 {
663         TRACEMSG("16: multiple write on file\n");
664
665         FILE *fpt = fopen(test_filename, "w+");
666
667         for (int i = 0; i < FILE_SIZE; i++)
668                 fputc(0xff, fpt);
669         fclose(fpt);
670
671         BattFs fd1;
672         inode_t INODE = 0;
673         unsigned int MODE = BATTFS_CREATE;
674         uint8_t buf[1000];
675
676         ASSERT(battfs_init(disk));
677         ASSERT(battfs_fileopen(disk, &fd1, INODE, MODE));
678
679         int j;
680         for (j = 1; j < 1013; j++)
681         {
682                 for (unsigned i = 0; i < sizeof(buf); i++)
683                         buf[i] = j+i;
684
685                 ASSERT(kfile_write(&fd1.fd, buf, sizeof(buf)) == sizeof(buf));
686                 ASSERT(fd1.fd.seek_pos == sizeof(buf));
687                 ASSERT(fd1.fd.size == sizeof(buf));
688                 ASSERT(kfile_seek(&fd1.fd, 0, KSM_SEEK_SET) == 0);
689                 memset(buf, 0, sizeof(buf));
690                 ASSERT(kfile_read(&fd1.fd, buf, sizeof(buf)) == sizeof(buf));
691                 ASSERT(fd1.fd.seek_pos == sizeof(buf));
692                 for (unsigned i = 0; i < sizeof(buf); i++)
693                         ASSERT(buf[i] == ((j+i) & 0xff));
694                 ASSERT(kfile_seek(&fd1.fd, 0, KSM_SEEK_SET) == 0);
695                 ASSERT(disk->free_bytes == disk->disk_size - sizeof(buf));
696         }
697         ASSERT(kfile_close(&fd1.fd) == 0);
698         ASSERT(battfs_fsck(disk));
699         ASSERT(battfs_close(disk));
700
701         ASSERT(battfs_init(disk));
702         ASSERT(disk->free_bytes == disk->disk_size - sizeof(buf));
703         ASSERT(battfs_fileopen(disk, &fd1, INODE, 0));
704         ASSERT(fd1.fd.size == sizeof(buf));
705         memset(buf, 0, sizeof(buf));
706         ASSERT(kfile_read(&fd1.fd, buf, sizeof(buf)) == sizeof(buf));
707         for (unsigned i = 0; i < sizeof(buf); i++)
708                         ASSERT(buf[i] == ((j-1+i) & 0xff));
709         ASSERT(kfile_close(&fd1.fd) == 0);
710         ASSERT(battfs_fsck(disk));
711         ASSERT(battfs_close(disk));
712
713
714         TRACEMSG("16: passed\n");
715 }
716
717 static void increaseFile(BattFsSuper *disk)
718 {
719         TRACEMSG("17: increasing dimension of a file with multiple open files.\n");
720
721         FILE *fpt = fopen(test_filename, "w+");
722
723         for (int i = 0; i < FILE_SIZE / 10; i++)
724                 fputc(0xff, fpt);
725         fclose(fpt);
726
727         BattFs fd1,fd2;
728         inode_t INODE1 = 1, INODE2 = 2;
729         unsigned int MODE = BATTFS_CREATE;
730         uint8_t buf[1000];
731
732         ASSERT(battfs_init(disk));
733         ASSERT(battfs_fileopen(disk, &fd1, INODE1, MODE));
734         ASSERT(battfs_fileopen(disk, &fd2, INODE2, MODE));
735         for (unsigned i = 0; i < sizeof(buf); i++)
736                 ASSERT(kfile_putc(i, &fd2.fd) != EOF);
737         ASSERT(kfile_seek(&fd2.fd, 0, KSM_SEEK_SET) == 0);
738         memset(buf, 0, sizeof(buf));
739         ASSERT(kfile_read(&fd2.fd, buf, sizeof(buf)) == sizeof(buf));
740
741         for (unsigned i = 0; i < sizeof(buf); i++)
742                 ASSERT(buf[i] == (i & 0xff));
743         ASSERT(kfile_seek(&fd2.fd, 0, KSM_SEEK_SET) == 0);
744
745         for (unsigned i = 0; i < sizeof(buf); i++)
746                 ASSERT(kfile_putc(i, &fd1.fd) != EOF);
747
748         memset(buf, 0, sizeof(buf));
749         ASSERT(kfile_read(&fd2.fd, buf, sizeof(buf)) == sizeof(buf));
750
751         for (unsigned i = 0; i < sizeof(buf); i++)
752                 ASSERT(buf[i] == (i & 0xff));
753
754         ASSERT(kfile_close(&fd1.fd) == 0);
755         ASSERT(kfile_close(&fd2.fd) == 0);
756         ASSERT(battfs_fsck(disk));
757         ASSERT(battfs_close(disk));
758
759         TRACEMSG("17: passed\n");
760 }
761
762 static void readEOF(BattFsSuper *disk)
763 {
764         BattFs fd1;
765         uint8_t buf[16];
766
767         TRACEMSG("18: reading over EOF test\n");
768
769         fp = fopen(test_filename, "w+");
770
771         unsigned int PAGE_FILL = PAGE_SIZE - BATTFS_HEADER_LEN;
772         inode_t INODE = 0;
773         inode_t INODE2 = 4;
774         unsigned int MODE = 0;
775
776         disk->erase(disk, 0);
777         battfs_writeTestBlock(disk, 1, INODE, 0, PAGE_FILL, 0);
778         battfs_writeTestBlock(disk, 2, INODE, 3, PAGE_FILL, 1);
779         battfs_writeTestBlock(disk, 3, INODE, 0, PAGE_FILL, 1);
780         disk->erase(disk, 4);
781         battfs_writeTestBlock(disk, 5, INODE2, 0, PAGE_FILL, 0);
782         battfs_writeTestBlock(disk, 6, INODE2, 1, PAGE_FILL, 1);
783         battfs_writeTestBlock(disk, 7, INODE2, 0, PAGE_FILL, 1);
784
785         fclose(fp);
786
787         ASSERT(battfs_init(disk));
788         ASSERT(battfs_fileopen(disk, &fd1, INODE, MODE));
789         ASSERT(kfile_seek(&fd1.fd, fd1.fd.size + 10, SEEK_SET) == fd1.fd.size + 10);
790         ASSERT(fd1.fd.seek_pos == fd1.fd.size + 10);
791         ASSERT(kfile_read(&fd1.fd, buf, sizeof(buf)) == 0);
792
793         ASSERT(kfile_close(&fd1.fd) == 0);
794         ASSERT(battfs_fsck(disk));
795         ASSERT(battfs_close(disk));
796
797         TRACEMSG("18: passed\n");
798 }
799
800 static void writeEOF(BattFsSuper *disk)
801 {
802         TRACEMSG("19: writing over EOF test\n");
803
804         FILE *fpt = fopen(test_filename, "w+");
805
806         for (int i = 0; i < FILE_SIZE / 5; i++)
807                 fputc(0xff, fpt);
808         fclose(fpt);
809
810         BattFs fd1;
811         inode_t INODE = 0;
812         unsigned int MODE = BATTFS_CREATE;
813         uint8_t buf[FILE_SIZE / 13];
814
815         for (int i = 0; i < 2; i++)
816                 buf[i] = i;
817
818         ASSERT(battfs_init(disk));
819         disk_size_t prev_free = disk->free_bytes;
820         ASSERT(battfs_fileopen(disk, &fd1, INODE, MODE));
821         ASSERT(fd1.fd.size == 0);
822
823         ASSERT(kfile_seek(&fd1.fd, 2, KSM_SEEK_END) == 2);
824         ASSERT(kfile_write(&fd1.fd, buf, 2));
825         ASSERT(fd1.fd.seek_pos == 4);
826         ASSERT(fd1.fd.size == 4);
827         ASSERT(disk->free_bytes == prev_free - 4);
828         ASSERT(kfile_seek(&fd1.fd, 0, KSM_SEEK_SET) == 0);
829         memset(buf, 0, 2);
830         ASSERT(kfile_read(&fd1.fd, buf, 2) == 2);
831         for (int i = 0; i < 2; i++)
832                 ASSERT(buf[i] == 0);
833
834         memset(buf, 0, 2);
835         ASSERT(kfile_read(&fd1.fd, buf, 2) == 2);
836         for (int i = 0; i < 2; i++)
837                 ASSERT(buf[i] == (i & 0xff));
838
839         ASSERT(kfile_seek(&fd1.fd, sizeof(buf), KSM_SEEK_END) == sizeof(buf) + 4);
840         for (unsigned i = 0; i < sizeof(buf); i++)
841                 buf[i] = i;
842         ASSERT(kfile_write(&fd1.fd, buf, sizeof(buf)));
843         ASSERT(fd1.fd.seek_pos == sizeof(buf) * 2 + 4);
844         ASSERT(fd1.fd.size == sizeof(buf) * 2 + 4);
845         ASSERT(disk->free_bytes == prev_free - sizeof(buf) * 2 - 4);
846
847         ASSERT(kfile_seek(&fd1.fd, 0, KSM_SEEK_SET) == 0);
848
849         memset(buf, 0, 2);
850         ASSERT(kfile_read(&fd1.fd, buf, 2) == 2);
851         ASSERT(fd1.fd.seek_pos == 2);
852         for (int i = 0; i < 2; i++)
853                 ASSERT(buf[i] == 0);
854
855         memset(buf, 0, 2);
856         ASSERT(kfile_read(&fd1.fd, buf, 2) == 2);
857         ASSERT(fd1.fd.seek_pos == 4);
858         for (int i = 0; i < 2; i++)
859                 ASSERT(buf[i] == (i & 0xff));
860
861         memset(buf, 0, 4);
862         ASSERT(kfile_read(&fd1.fd, buf, sizeof(buf)) == sizeof(buf));
863         ASSERT(fd1.fd.seek_pos == sizeof(buf) + 4);
864         for (unsigned i = 0; i < sizeof(buf); i++)
865                 ASSERT(buf[i] == 0);
866
867         memset(buf, 0, sizeof(buf));
868         ASSERT(kfile_read(&fd1.fd, buf, sizeof(buf)) == sizeof(buf));
869         for (unsigned i = 0; i < sizeof(buf); i++)
870                 ASSERT(buf[i] == (i & 0xff));
871
872         ASSERT(kfile_close(&fd1.fd) == 0);
873         ASSERT(battfs_fsck(disk));
874         ASSERT(battfs_close(disk));
875
876         TRACEMSG("19: passed\n");
877
878 }
879
880
881 int battfs_testRun(void)
882 {
883         BattFsSuper disk;
884
885         disk.open = disk_open;
886         disk.read = disk_page_read;
887         disk.load = disk_page_load;
888         disk.bufferWrite = disk_buffer_write;
889         disk.bufferRead = disk_buffer_read;
890         disk.save = disk_page_save;
891         disk.erase = disk_page_erase;
892         disk.close = disk_close;
893
894         diskNew(&disk);
895         disk1File(&disk);
896         diskHalfFile(&disk);
897         oldSeq1(&disk);
898         oldSeq2(&disk);
899         oldSeq3(&disk);
900         oldSeq2File(&disk);
901         openFile(&disk);
902         readFile(&disk);
903         readAcross(&disk);
904         writeFile(&disk);
905         writeAcross(&disk);
906         createFile(&disk);
907         multipleWrite(&disk);
908         increaseFile(&disk);
909         readEOF(&disk);
910         writeEOF(&disk);
911
912         kprintf("All tests passed!\n");
913
914         return 0;
915 }
916
917 int battfs_testSetup(void)
918 {
919         return 0;
920 }
921
922 int battfs_testTearDown(void)
923 {
924         return 0;
925 }
926
927 TEST_MAIN(battfs)
928
929 #include <fs/battfs.c>
930 #include <kern/kfile.c>
931 #include <drv/kdebug.c>
932 #include <mware/formatwr.c>
933 #include <mware/hex.c>
934
935 #endif // _TEST