1 /*
2  * Copyright (c) 2019 Peter Bigot Consulting, LLC
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 /* Basic littlefs operations:
8  * * create
9  * * write
10  * * stat
11  * * read
12  * * seek
13  * * tell
14  * * truncate
15  * * unlink
16  * * sync
17  */
18 
19 #include <string.h>
20 #include <zephyr/ztest.h>
21 #include "testfs_tests.h"
22 #include "testfs_lfs.h"
23 #include <lfs.h>
24 
25 #include <zephyr/fs/littlefs.h>
26 
mount(struct fs_mount_t * mp)27 static int mount(struct fs_mount_t *mp)
28 {
29 	TC_PRINT("mounting %s\n", mp->mnt_point);
30 
31 	zassert_equal(fs_mount(mp), 0,
32 		      "mount failed");
33 
34 	return TC_PASS;
35 }
36 
clear_partition(struct fs_mount_t * mp)37 static int clear_partition(struct fs_mount_t *mp)
38 {
39 	TC_PRINT("clearing partition %s\n", mp->mnt_point);
40 
41 	zassert_equal(testfs_lfs_wipe_partition(mp),
42 		      TC_PASS,
43 		      "failed to wipe partition");
44 
45 	return TC_PASS;
46 }
47 
clean_statvfs(const struct fs_mount_t * mp)48 static int clean_statvfs(const struct fs_mount_t *mp)
49 {
50 	struct fs_statvfs stat;
51 
52 	TC_PRINT("checking clean statvfs of %s\n", mp->mnt_point);
53 
54 	zassert_equal(fs_statvfs(mp->mnt_point, &stat), 0,
55 		      "statvfs failed");
56 
57 	TC_PRINT("%s: bsize %lu ; frsize %lu ; blocks %lu ; bfree %lu\n",
58 		 mp->mnt_point,
59 		 stat.f_bsize, stat.f_frsize, stat.f_blocks, stat.f_bfree);
60 	zassert_equal(stat.f_bsize, 16,
61 		      "bsize fail");
62 	zassert_equal(stat.f_frsize, 4096,
63 		      "frsize fail");
64 	zassert_equal(stat.f_blocks, 16,
65 		      "blocks fail");
66 	zassert_equal(stat.f_bfree, stat.f_blocks - 2U,
67 		      "bfree fail");
68 
69 	return TC_PASS;
70 }
71 
check_medium(void)72 static int check_medium(void)
73 {
74 	struct fs_mount_t *mp = &testfs_medium_mnt;
75 	struct fs_statvfs stat;
76 
77 	zassert_equal(clear_partition(mp), TC_PASS,
78 		      "clear partition failed");
79 
80 	zassert_equal(fs_mount(mp), 0,
81 		      "medium mount failed");
82 
83 	zassert_equal(fs_statvfs(mp->mnt_point, &stat), 0,
84 		      "statvfs failed");
85 
86 	TC_PRINT("%s: bsize %lu ; frsize %lu ; blocks %lu ; bfree %lu\n",
87 		 mp->mnt_point,
88 		 stat.f_bsize, stat.f_frsize, stat.f_blocks, stat.f_bfree);
89 	zassert_equal(stat.f_bsize, MEDIUM_IO_SIZE,
90 		      "bsize fail");
91 	zassert_equal(stat.f_frsize, 4096,
92 		      "frsize fail");
93 	zassert_equal(stat.f_blocks, 240,
94 		      "blocks fail");
95 	zassert_equal(stat.f_bfree, stat.f_blocks - 2U,
96 		      "bfree fail");
97 
98 	zassert_equal(fs_unmount(mp), 0,
99 		      "medium unmount failed");
100 
101 	return TC_PASS;
102 }
103 
check_large(void)104 static int check_large(void)
105 {
106 	struct fs_mount_t *mp = &testfs_large_mnt;
107 	struct fs_statvfs stat;
108 
109 	zassert_equal(clear_partition(mp), TC_PASS,
110 		      "clear partition failed");
111 
112 	zassert_equal(fs_mount(mp), 0,
113 		      "large mount failed");
114 
115 	zassert_equal(fs_statvfs(mp->mnt_point, &stat), 0,
116 		      "statvfs failed");
117 
118 	TC_PRINT("%s: bsize %lu ; frsize %lu ; blocks %lu ; bfree %lu\n",
119 		 mp->mnt_point,
120 		 stat.f_bsize, stat.f_frsize, stat.f_blocks, stat.f_bfree);
121 	zassert_equal(stat.f_bsize, LARGE_IO_SIZE,
122 		      "bsize fail");
123 	zassert_equal(stat.f_frsize, 32768,
124 		      "frsize fail");
125 	zassert_equal(stat.f_blocks, 96,
126 		      "blocks fail");
127 	zassert_equal(stat.f_bfree, stat.f_blocks - 2U,
128 		      "bfree fail");
129 
130 	zassert_equal(fs_unmount(mp), 0,
131 		      "large unmount failed");
132 
133 	return TC_PASS;
134 }
135 
num_files(struct fs_mount_t * mp)136 static int num_files(struct fs_mount_t *mp)
137 {
138 	struct testfs_path path;
139 	char name[2] = { 0 };
140 	const char *pstr;
141 	struct fs_file_t files[CONFIG_FS_LITTLEFS_NUM_FILES];
142 	size_t fi = 0;
143 	int rc;
144 
145 	memset(files, 0, sizeof(files));
146 
147 	TC_PRINT("CONFIG_FS_LITTLEFS_NUM_FILES=%u\n", CONFIG_FS_LITTLEFS_NUM_FILES);
148 	while (fi < ARRAY_SIZE(files)) {
149 		struct fs_file_t *const file = &files[fi];
150 
151 		name[0] = 'A' + fi;
152 		pstr = testfs_path_init(&path, mp,
153 					name,
154 					TESTFS_PATH_END);
155 
156 		TC_PRINT("opening %s\n", pstr);
157 		rc = fs_open(file, pstr, FS_O_CREATE | FS_O_RDWR);
158 		zassert_equal(rc, 0, "open %s failed: %d", pstr, rc);
159 
160 		rc = testfs_write_incrementing(file, 0, TESTFS_BUFFER_SIZE);
161 		zassert_equal(rc, TESTFS_BUFFER_SIZE, "write %s failed: %d", pstr, rc);
162 
163 		++fi;
164 	}
165 
166 	while (fi-- != 0)  {
167 		struct fs_file_t *const file = &files[fi];
168 
169 		name[0] = 'A' + fi;
170 		pstr = testfs_path_init(&path, mp,
171 					name,
172 					TESTFS_PATH_END);
173 
174 		TC_PRINT("Close and unlink %s\n", pstr);
175 
176 		rc = fs_close(file);
177 		zassert_equal(rc, 0, "close %s failed: %d", pstr, rc);
178 
179 		rc = fs_unlink(pstr);
180 		zassert_equal(rc, 0, "unlink %s failed: %d", pstr, rc);
181 	}
182 
183 	return TC_PASS;
184 }
185 
num_dirs(struct fs_mount_t * mp)186 static int num_dirs(struct fs_mount_t *mp)
187 {
188 	struct testfs_path path;
189 	char name[3] = "Dx";
190 	const char *pstr;
191 	struct fs_dir_t dirs[CONFIG_FS_LITTLEFS_NUM_DIRS];
192 	size_t di = 0;
193 	int rc;
194 
195 	memset(dirs, 0, sizeof(dirs));
196 
197 	TC_PRINT("CONFIG_FS_LITTLEFS_NUM_DIRS=%u\n", CONFIG_FS_LITTLEFS_NUM_DIRS);
198 	while (di < ARRAY_SIZE(dirs)) {
199 		struct fs_dir_t *const dir = &dirs[di];
200 
201 		name[1] = 'A' + di;
202 		pstr = testfs_path_init(&path, mp,
203 					name,
204 					TESTFS_PATH_END);
205 
206 		TC_PRINT("making and opening directory %s\n", pstr);
207 		rc = fs_mkdir(pstr);
208 		zassert_equal(rc, 0, "mkdir %s failed: %d", pstr, rc);
209 
210 		rc = fs_opendir(dir, pstr);
211 		zassert_equal(rc, 0, "opendir %s failed: %d", name, rc);
212 
213 		++di;
214 	}
215 
216 	while (di-- != 0)  {
217 		struct fs_dir_t *const dir = &dirs[di];
218 
219 		name[1] = 'A' + di;
220 		pstr = testfs_path_init(&path, mp,
221 					name,
222 					TESTFS_PATH_END);
223 
224 		TC_PRINT("Close and rmdir %s\n", pstr);
225 
226 		rc = fs_closedir(dir);
227 		zassert_equal(rc, 0, "closedir %s failed: %d", name, rc);
228 
229 		rc = fs_unlink(pstr);
230 		zassert_equal(rc, 0, "unlink %s failed: %d", name, rc);
231 	}
232 
233 	return TC_PASS;
234 }
235 
236 void test_fs_basic(void);
237 
238 /* Mount structure needed by test_fs_basic tests. */
239 struct fs_mount_t *fs_basic_test_mp = &testfs_small_mnt;
240 
ZTEST(littlefs,test_lfs_basic)241 ZTEST(littlefs, test_lfs_basic)
242 {
243 	struct fs_mount_t *mp = &testfs_small_mnt;
244 
245 	zassert_equal(clear_partition(mp), TC_PASS,
246 		      "clear partition failed");
247 
248 	/* Common basic tests.
249 	 * (File system is mounted and unmounted during that test.)
250 	 */
251 	test_fs_basic();
252 
253 	/* LittleFS specific tests */
254 
255 	zassert_equal(mount(mp), TC_PASS,
256 		      "clean mount failed");
257 
258 	zassert_equal(clean_statvfs(mp), TC_PASS,
259 		      "clean statvfs failed");
260 
261 	zassert_equal(num_files(mp), TC_PASS,
262 		      "num_files failed");
263 
264 	zassert_equal(num_dirs(mp), TC_PASS,
265 		      "num_dirs failed");
266 
267 	TC_PRINT("unmounting %s\n", mp->mnt_point);
268 	zassert_equal(fs_unmount(mp), 0,
269 		      "unmount small failed");
270 
271 	if (IS_ENABLED(CONFIG_APP_TEST_CUSTOM)) {
272 		zassert_equal(check_medium(), TC_PASS,
273 			      "check medium failed");
274 
275 		zassert_equal(check_large(), TC_PASS,
276 			      "check large failed");
277 	}
278 }
279