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