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