test_compat.toml 37 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278
  1. # Test for compatibility between different littlefs versions
  2. #
  3. # Note, these tests are a bit special. They expect to be linked against two
  4. # different versions of littlefs:
  5. # - lfs => the new/current version of littlefs
  6. # - lfsp => the previous version of littlefs
  7. #
  8. # If lfsp is not linked, and LFSP is not defined, these tests will alias
  9. # the relevant lfs types/functions as necessary so at least the tests can
  10. # themselves be tested locally.
  11. #
  12. # But to get value from these tests, it's expected that the previous version
  13. # of littlefs be linked in during CI, with the help of scripts/changeprefix.py
  14. #
  15. # alias littlefs symbols as needed
  16. #
  17. # there may be a better way to do this, but oh well, explicit aliases works
  18. code = '''
  19. #ifdef LFSP
  20. #define STRINGIZE(x) STRINGIZE_(x)
  21. #define STRINGIZE_(x) #x
  22. #include STRINGIZE(LFSP)
  23. #else
  24. #define LFSP_VERSION LFS_VERSION
  25. #define LFSP_VERSION_MAJOR LFS_VERSION_MAJOR
  26. #define LFSP_VERSION_MINOR LFS_VERSION_MINOR
  27. #define lfsp_t lfs_t
  28. #define lfsp_config lfs_config
  29. #define lfsp_format lfs_format
  30. #define lfsp_mount lfs_mount
  31. #define lfsp_unmount lfs_unmount
  32. #define lfsp_dir_t lfs_dir_t
  33. #define lfsp_info lfs_info
  34. #define LFSP_TYPE_REG LFS_TYPE_REG
  35. #define LFSP_TYPE_DIR LFS_TYPE_DIR
  36. #define lfsp_mkdir lfs_mkdir
  37. #define lfsp_dir_open lfs_dir_open
  38. #define lfsp_dir_read lfs_dir_read
  39. #define lfsp_dir_close lfs_dir_close
  40. #define lfsp_file_t lfs_file_t
  41. #define LFSP_O_RDONLY LFS_O_RDONLY
  42. #define LFSP_O_WRONLY LFS_O_WRONLY
  43. #define LFSP_O_CREAT LFS_O_CREAT
  44. #define LFSP_O_EXCL LFS_O_EXCL
  45. #define LFSP_SEEK_SET LFS_SEEK_SET
  46. #define lfsp_file_open lfs_file_open
  47. #define lfsp_file_write lfs_file_write
  48. #define lfsp_file_read lfs_file_read
  49. #define lfsp_file_seek lfs_file_seek
  50. #define lfsp_file_close lfs_file_close
  51. #endif
  52. '''
  53. ## forward-compatibility tests ##
  54. # test we can mount in a new version
  55. [cases.test_compat_forward_mount]
  56. if = 'LFS_VERSION_MAJOR == LFSP_VERSION_MAJOR'
  57. code = '''
  58. // create the previous version
  59. struct lfsp_config cfgp;
  60. memcpy(&cfgp, cfg, sizeof(cfgp));
  61. lfsp_t lfsp;
  62. lfsp_format(&lfsp, &cfgp) => 0;
  63. // confirm the previous mount works
  64. lfsp_mount(&lfsp, &cfgp) => 0;
  65. lfsp_unmount(&lfsp) => 0;
  66. // now test the new mount
  67. lfs_t lfs;
  68. lfs_mount(&lfs, cfg) => 0;
  69. lfs_unmount(&lfs) => 0;
  70. '''
  71. # test we can read dirs in a new version
  72. [cases.test_compat_forward_read_dirs]
  73. defines.COUNT = 5
  74. if = 'LFS_VERSION_MAJOR == LFSP_VERSION_MAJOR'
  75. code = '''
  76. // create the previous version
  77. struct lfsp_config cfgp;
  78. memcpy(&cfgp, cfg, sizeof(cfgp));
  79. lfsp_t lfsp;
  80. lfsp_format(&lfsp, &cfgp) => 0;
  81. // write COUNT dirs
  82. lfsp_mount(&lfsp, &cfgp) => 0;
  83. for (lfs_size_t i = 0; i < COUNT; i++) {
  84. char name[8];
  85. sprintf(name, "dir%03d", i);
  86. lfsp_mkdir(&lfsp, name) => 0;
  87. }
  88. lfsp_unmount(&lfsp) => 0;
  89. // mount the new version
  90. lfs_t lfs;
  91. lfs_mount(&lfs, cfg) => 0;
  92. // can we list the directories?
  93. lfs_dir_t dir;
  94. lfs_dir_open(&lfs, &dir, "/") => 0;
  95. struct lfs_info info;
  96. lfs_dir_read(&lfs, &dir, &info) => 1;
  97. assert(info.type == LFS_TYPE_DIR);
  98. assert(strcmp(info.name, ".") == 0);
  99. lfs_dir_read(&lfs, &dir, &info) => 1;
  100. assert(info.type == LFS_TYPE_DIR);
  101. assert(strcmp(info.name, "..") == 0);
  102. for (lfs_size_t i = 0; i < COUNT; i++) {
  103. lfs_dir_read(&lfs, &dir, &info) => 1;
  104. assert(info.type == LFS_TYPE_DIR);
  105. char name[8];
  106. sprintf(name, "dir%03d", i);
  107. assert(strcmp(info.name, name) == 0);
  108. }
  109. lfs_dir_read(&lfs, &dir, &info) => 0;
  110. lfs_dir_close(&lfs, &dir) => 0;
  111. lfs_unmount(&lfs) => 0;
  112. '''
  113. # test we can read files in a new version
  114. [cases.test_compat_forward_read_files]
  115. defines.COUNT = 5
  116. defines.SIZE = [4, 32, 512, 8192]
  117. defines.CHUNK = 4
  118. if = 'LFS_VERSION_MAJOR == LFSP_VERSION_MAJOR'
  119. code = '''
  120. // create the previous version
  121. struct lfsp_config cfgp;
  122. memcpy(&cfgp, cfg, sizeof(cfgp));
  123. lfsp_t lfsp;
  124. lfsp_format(&lfsp, &cfgp) => 0;
  125. // write COUNT files
  126. lfsp_mount(&lfsp, &cfgp) => 0;
  127. uint32_t prng = 42;
  128. for (lfs_size_t i = 0; i < COUNT; i++) {
  129. lfsp_file_t file;
  130. char name[8];
  131. sprintf(name, "file%03d", i);
  132. lfsp_file_open(&lfsp, &file, name,
  133. LFSP_O_WRONLY | LFSP_O_CREAT | LFSP_O_EXCL) => 0;
  134. for (lfs_size_t j = 0; j < SIZE; j += CHUNK) {
  135. uint8_t chunk[CHUNK];
  136. for (lfs_size_t k = 0; k < CHUNK; k++) {
  137. chunk[k] = TEST_PRNG(&prng) & 0xff;
  138. }
  139. lfsp_file_write(&lfsp, &file, chunk, CHUNK) => CHUNK;
  140. }
  141. lfsp_file_close(&lfsp, &file) => 0;
  142. }
  143. lfsp_unmount(&lfsp) => 0;
  144. // mount the new version
  145. lfs_t lfs;
  146. lfs_mount(&lfs, cfg) => 0;
  147. // can we list the files?
  148. lfs_dir_t dir;
  149. lfs_dir_open(&lfs, &dir, "/") => 0;
  150. struct lfs_info info;
  151. lfs_dir_read(&lfs, &dir, &info) => 1;
  152. assert(info.type == LFS_TYPE_DIR);
  153. assert(strcmp(info.name, ".") == 0);
  154. lfs_dir_read(&lfs, &dir, &info) => 1;
  155. assert(info.type == LFS_TYPE_DIR);
  156. assert(strcmp(info.name, "..") == 0);
  157. for (lfs_size_t i = 0; i < COUNT; i++) {
  158. lfs_dir_read(&lfs, &dir, &info) => 1;
  159. assert(info.type == LFS_TYPE_REG);
  160. char name[8];
  161. sprintf(name, "file%03d", i);
  162. assert(strcmp(info.name, name) == 0);
  163. assert(info.size == SIZE);
  164. }
  165. lfs_dir_read(&lfs, &dir, &info) => 0;
  166. // now can we read the files?
  167. prng = 42;
  168. for (lfs_size_t i = 0; i < COUNT; i++) {
  169. lfs_file_t file;
  170. char name[8];
  171. sprintf(name, "file%03d", i);
  172. lfs_file_open(&lfs, &file, name, LFS_O_RDONLY) => 0;
  173. for (lfs_size_t j = 0; j < SIZE; j += CHUNK) {
  174. uint8_t chunk[CHUNK];
  175. lfs_file_read(&lfs, &file, chunk, CHUNK) => CHUNK;
  176. for (lfs_size_t k = 0; k < CHUNK; k++) {
  177. assert(chunk[k] == TEST_PRNG(&prng) & 0xff);
  178. }
  179. }
  180. lfs_file_close(&lfs, &file) => 0;
  181. }
  182. lfs_unmount(&lfs) => 0;
  183. '''
  184. # test we can read files in dirs in a new version
  185. [cases.test_compat_forward_read_files_in_dirs]
  186. defines.COUNT = 5
  187. defines.SIZE = [4, 32, 512, 8192]
  188. defines.CHUNK = 4
  189. if = 'LFS_VERSION_MAJOR == LFSP_VERSION_MAJOR'
  190. code = '''
  191. // create the previous version
  192. struct lfsp_config cfgp;
  193. memcpy(&cfgp, cfg, sizeof(cfgp));
  194. lfsp_t lfsp;
  195. lfsp_format(&lfsp, &cfgp) => 0;
  196. // write COUNT files+dirs
  197. lfsp_mount(&lfsp, &cfgp) => 0;
  198. uint32_t prng = 42;
  199. for (lfs_size_t i = 0; i < COUNT; i++) {
  200. char name[16];
  201. sprintf(name, "dir%03d", i);
  202. lfsp_mkdir(&lfsp, name) => 0;
  203. lfsp_file_t file;
  204. sprintf(name, "dir%03d/file%03d", i, i);
  205. lfsp_file_open(&lfsp, &file, name,
  206. LFSP_O_WRONLY | LFSP_O_CREAT | LFSP_O_EXCL) => 0;
  207. for (lfs_size_t j = 0; j < SIZE; j += CHUNK) {
  208. uint8_t chunk[CHUNK];
  209. for (lfs_size_t k = 0; k < CHUNK; k++) {
  210. chunk[k] = TEST_PRNG(&prng) & 0xff;
  211. }
  212. lfsp_file_write(&lfsp, &file, chunk, CHUNK) => CHUNK;
  213. }
  214. lfsp_file_close(&lfsp, &file) => 0;
  215. }
  216. lfsp_unmount(&lfsp) => 0;
  217. // mount the new version
  218. lfs_t lfs;
  219. lfs_mount(&lfs, cfg) => 0;
  220. // can we list the directories?
  221. lfs_dir_t dir;
  222. lfs_dir_open(&lfs, &dir, "/") => 0;
  223. struct lfs_info info;
  224. lfs_dir_read(&lfs, &dir, &info) => 1;
  225. assert(info.type == LFS_TYPE_DIR);
  226. assert(strcmp(info.name, ".") == 0);
  227. lfs_dir_read(&lfs, &dir, &info) => 1;
  228. assert(info.type == LFS_TYPE_DIR);
  229. assert(strcmp(info.name, "..") == 0);
  230. for (lfs_size_t i = 0; i < COUNT; i++) {
  231. lfs_dir_read(&lfs, &dir, &info) => 1;
  232. assert(info.type == LFS_TYPE_DIR);
  233. char name[8];
  234. sprintf(name, "dir%03d", i);
  235. assert(strcmp(info.name, name) == 0);
  236. }
  237. lfs_dir_read(&lfs, &dir, &info) => 0;
  238. lfs_dir_close(&lfs, &dir) => 0;
  239. // can we list the files?
  240. for (lfs_size_t i = 0; i < COUNT; i++) {
  241. char name[8];
  242. sprintf(name, "dir%03d", i);
  243. lfs_dir_t dir;
  244. lfs_dir_open(&lfs, &dir, name) => 0;
  245. struct lfs_info info;
  246. lfs_dir_read(&lfs, &dir, &info) => 1;
  247. assert(info.type == LFS_TYPE_DIR);
  248. assert(strcmp(info.name, ".") == 0);
  249. lfs_dir_read(&lfs, &dir, &info) => 1;
  250. assert(info.type == LFS_TYPE_DIR);
  251. assert(strcmp(info.name, "..") == 0);
  252. lfs_dir_read(&lfs, &dir, &info) => 1;
  253. assert(info.type == LFS_TYPE_REG);
  254. sprintf(name, "file%03d", i);
  255. assert(strcmp(info.name, name) == 0);
  256. assert(info.size == SIZE);
  257. lfs_dir_read(&lfs, &dir, &info) => 0;
  258. lfs_dir_close(&lfs, &dir) => 0;
  259. }
  260. // now can we read the files?
  261. prng = 42;
  262. for (lfs_size_t i = 0; i < COUNT; i++) {
  263. lfs_file_t file;
  264. char name[16];
  265. sprintf(name, "dir%03d/file%03d", i, i);
  266. lfs_file_open(&lfs, &file, name, LFS_O_RDONLY) => 0;
  267. for (lfs_size_t j = 0; j < SIZE; j += CHUNK) {
  268. uint8_t chunk[CHUNK];
  269. lfs_file_read(&lfs, &file, chunk, CHUNK) => CHUNK;
  270. for (lfs_size_t k = 0; k < CHUNK; k++) {
  271. assert(chunk[k] == TEST_PRNG(&prng) & 0xff);
  272. }
  273. }
  274. lfs_file_close(&lfs, &file) => 0;
  275. }
  276. lfs_unmount(&lfs) => 0;
  277. '''
  278. # test we can write dirs in a new version
  279. [cases.test_compat_forward_write_dirs]
  280. defines.COUNT = 10
  281. if = 'LFS_VERSION_MAJOR == LFSP_VERSION_MAJOR'
  282. code = '''
  283. // create the previous version
  284. struct lfsp_config cfgp;
  285. memcpy(&cfgp, cfg, sizeof(cfgp));
  286. lfsp_t lfsp;
  287. lfsp_format(&lfsp, &cfgp) => 0;
  288. // write COUNT/2 dirs
  289. lfsp_mount(&lfsp, &cfgp) => 0;
  290. for (lfs_size_t i = 0; i < COUNT/2; i++) {
  291. char name[8];
  292. sprintf(name, "dir%03d", i);
  293. lfsp_mkdir(&lfsp, name) => 0;
  294. }
  295. lfsp_unmount(&lfsp) => 0;
  296. // mount the new version
  297. lfs_t lfs;
  298. lfs_mount(&lfs, cfg) => 0;
  299. // write another COUNT/2 dirs
  300. for (lfs_size_t i = COUNT/2; i < COUNT; i++) {
  301. char name[8];
  302. sprintf(name, "dir%03d", i);
  303. lfs_mkdir(&lfs, name) => 0;
  304. }
  305. // can we list the directories?
  306. lfs_dir_t dir;
  307. lfs_dir_open(&lfs, &dir, "/") => 0;
  308. struct lfs_info info;
  309. lfs_dir_read(&lfs, &dir, &info) => 1;
  310. assert(info.type == LFS_TYPE_DIR);
  311. assert(strcmp(info.name, ".") == 0);
  312. lfs_dir_read(&lfs, &dir, &info) => 1;
  313. assert(info.type == LFS_TYPE_DIR);
  314. assert(strcmp(info.name, "..") == 0);
  315. for (lfs_size_t i = 0; i < COUNT; i++) {
  316. lfs_dir_read(&lfs, &dir, &info) => 1;
  317. assert(info.type == LFS_TYPE_DIR);
  318. char name[8];
  319. sprintf(name, "dir%03d", i);
  320. assert(strcmp(info.name, name) == 0);
  321. }
  322. lfs_dir_read(&lfs, &dir, &info) => 0;
  323. lfs_dir_close(&lfs, &dir) => 0;
  324. lfs_unmount(&lfs) => 0;
  325. '''
  326. # test we can write files in a new version
  327. [cases.test_compat_forward_write_files]
  328. defines.COUNT = 5
  329. defines.SIZE = [4, 32, 512, 8192]
  330. defines.CHUNK = 2
  331. if = 'LFS_VERSION_MAJOR == LFSP_VERSION_MAJOR'
  332. code = '''
  333. // create the previous version
  334. struct lfsp_config cfgp;
  335. memcpy(&cfgp, cfg, sizeof(cfgp));
  336. lfsp_t lfsp;
  337. lfsp_format(&lfsp, &cfgp) => 0;
  338. // write half COUNT files
  339. lfsp_mount(&lfsp, &cfgp) => 0;
  340. uint32_t prng = 42;
  341. for (lfs_size_t i = 0; i < COUNT; i++) {
  342. // write half
  343. lfsp_file_t file;
  344. char name[8];
  345. sprintf(name, "file%03d", i);
  346. lfsp_file_open(&lfsp, &file, name,
  347. LFSP_O_WRONLY | LFSP_O_CREAT | LFSP_O_EXCL) => 0;
  348. for (lfs_size_t j = 0; j < SIZE/2; j += CHUNK) {
  349. uint8_t chunk[CHUNK];
  350. for (lfs_size_t k = 0; k < CHUNK; k++) {
  351. chunk[k] = TEST_PRNG(&prng) & 0xff;
  352. }
  353. lfsp_file_write(&lfsp, &file, chunk, CHUNK) => CHUNK;
  354. }
  355. lfsp_file_close(&lfsp, &file) => 0;
  356. // skip the other half but keep our prng reproducible
  357. for (lfs_size_t j = SIZE/2; j < SIZE; j++) {
  358. TEST_PRNG(&prng);
  359. }
  360. }
  361. lfsp_unmount(&lfsp) => 0;
  362. // mount the new version
  363. lfs_t lfs;
  364. lfs_mount(&lfs, cfg) => 0;
  365. // write half COUNT files
  366. prng = 42;
  367. for (lfs_size_t i = 0; i < COUNT; i++) {
  368. // skip half but keep our prng reproducible
  369. for (lfs_size_t j = 0; j < SIZE/2; j++) {
  370. TEST_PRNG(&prng);
  371. }
  372. // write the other half
  373. lfs_file_t file;
  374. char name[8];
  375. sprintf(name, "file%03d", i);
  376. lfs_file_open(&lfs, &file, name, LFS_O_WRONLY) => 0;
  377. lfs_file_seek(&lfs, &file, SIZE/2, LFS_SEEK_SET) => SIZE/2;
  378. for (lfs_size_t j = SIZE/2; j < SIZE; j += CHUNK) {
  379. uint8_t chunk[CHUNK];
  380. for (lfs_size_t k = 0; k < CHUNK; k++) {
  381. chunk[k] = TEST_PRNG(&prng) & 0xff;
  382. }
  383. lfs_file_write(&lfs, &file, chunk, CHUNK) => CHUNK;
  384. }
  385. lfs_file_close(&lfs, &file) => 0;
  386. }
  387. // can we list the files?
  388. lfs_dir_t dir;
  389. lfs_dir_open(&lfs, &dir, "/") => 0;
  390. struct lfs_info info;
  391. lfs_dir_read(&lfs, &dir, &info) => 1;
  392. assert(info.type == LFS_TYPE_DIR);
  393. assert(strcmp(info.name, ".") == 0);
  394. lfs_dir_read(&lfs, &dir, &info) => 1;
  395. assert(info.type == LFS_TYPE_DIR);
  396. assert(strcmp(info.name, "..") == 0);
  397. for (lfs_size_t i = 0; i < COUNT; i++) {
  398. lfs_dir_read(&lfs, &dir, &info) => 1;
  399. assert(info.type == LFS_TYPE_REG);
  400. char name[8];
  401. sprintf(name, "file%03d", i);
  402. assert(strcmp(info.name, name) == 0);
  403. assert(info.size == SIZE);
  404. }
  405. lfs_dir_read(&lfs, &dir, &info) => 0;
  406. // now can we read the files?
  407. prng = 42;
  408. for (lfs_size_t i = 0; i < COUNT; i++) {
  409. lfs_file_t file;
  410. char name[8];
  411. sprintf(name, "file%03d", i);
  412. lfs_file_open(&lfs, &file, name, LFS_O_RDONLY) => 0;
  413. for (lfs_size_t j = 0; j < SIZE; j += CHUNK) {
  414. uint8_t chunk[CHUNK];
  415. lfs_file_read(&lfs, &file, chunk, CHUNK) => CHUNK;
  416. for (lfs_size_t k = 0; k < CHUNK; k++) {
  417. assert(chunk[k] == TEST_PRNG(&prng) & 0xff);
  418. }
  419. }
  420. lfs_file_close(&lfs, &file) => 0;
  421. }
  422. lfs_unmount(&lfs) => 0;
  423. '''
  424. # test we can write files in dirs in a new version
  425. [cases.test_compat_forward_write_files_in_dirs]
  426. defines.COUNT = 5
  427. defines.SIZE = [4, 32, 512, 8192]
  428. defines.CHUNK = 2
  429. if = 'LFS_VERSION_MAJOR == LFSP_VERSION_MAJOR'
  430. code = '''
  431. // create the previous version
  432. struct lfsp_config cfgp;
  433. memcpy(&cfgp, cfg, sizeof(cfgp));
  434. lfsp_t lfsp;
  435. lfsp_format(&lfsp, &cfgp) => 0;
  436. // write half COUNT files
  437. lfsp_mount(&lfsp, &cfgp) => 0;
  438. uint32_t prng = 42;
  439. for (lfs_size_t i = 0; i < COUNT; i++) {
  440. char name[16];
  441. sprintf(name, "dir%03d", i);
  442. lfsp_mkdir(&lfsp, name) => 0;
  443. // write half
  444. lfsp_file_t file;
  445. sprintf(name, "dir%03d/file%03d", i, i);
  446. lfsp_file_open(&lfsp, &file, name,
  447. LFSP_O_WRONLY | LFSP_O_CREAT | LFSP_O_EXCL) => 0;
  448. for (lfs_size_t j = 0; j < SIZE/2; j += CHUNK) {
  449. uint8_t chunk[CHUNK];
  450. for (lfs_size_t k = 0; k < CHUNK; k++) {
  451. chunk[k] = TEST_PRNG(&prng) & 0xff;
  452. }
  453. lfsp_file_write(&lfsp, &file, chunk, CHUNK) => CHUNK;
  454. }
  455. lfsp_file_close(&lfsp, &file) => 0;
  456. // skip the other half but keep our prng reproducible
  457. for (lfs_size_t j = SIZE/2; j < SIZE; j++) {
  458. TEST_PRNG(&prng);
  459. }
  460. }
  461. lfsp_unmount(&lfsp) => 0;
  462. // mount the new version
  463. lfs_t lfs;
  464. lfs_mount(&lfs, cfg) => 0;
  465. // write half COUNT files
  466. prng = 42;
  467. for (lfs_size_t i = 0; i < COUNT; i++) {
  468. // skip half but keep our prng reproducible
  469. for (lfs_size_t j = 0; j < SIZE/2; j++) {
  470. TEST_PRNG(&prng);
  471. }
  472. // write the other half
  473. lfs_file_t file;
  474. char name[16];
  475. sprintf(name, "dir%03d/file%03d", i, i);
  476. lfs_file_open(&lfs, &file, name, LFS_O_WRONLY) => 0;
  477. lfs_file_seek(&lfs, &file, SIZE/2, LFS_SEEK_SET) => SIZE/2;
  478. for (lfs_size_t j = SIZE/2; j < SIZE; j += CHUNK) {
  479. uint8_t chunk[CHUNK];
  480. for (lfs_size_t k = 0; k < CHUNK; k++) {
  481. chunk[k] = TEST_PRNG(&prng) & 0xff;
  482. }
  483. lfs_file_write(&lfs, &file, chunk, CHUNK) => CHUNK;
  484. }
  485. lfs_file_close(&lfs, &file) => 0;
  486. }
  487. // can we list the directories?
  488. lfs_dir_t dir;
  489. lfs_dir_open(&lfs, &dir, "/") => 0;
  490. struct lfs_info info;
  491. lfs_dir_read(&lfs, &dir, &info) => 1;
  492. assert(info.type == LFS_TYPE_DIR);
  493. assert(strcmp(info.name, ".") == 0);
  494. lfs_dir_read(&lfs, &dir, &info) => 1;
  495. assert(info.type == LFS_TYPE_DIR);
  496. assert(strcmp(info.name, "..") == 0);
  497. for (lfs_size_t i = 0; i < COUNT; i++) {
  498. lfs_dir_read(&lfs, &dir, &info) => 1;
  499. assert(info.type == LFS_TYPE_DIR);
  500. char name[8];
  501. sprintf(name, "dir%03d", i);
  502. assert(strcmp(info.name, name) == 0);
  503. }
  504. lfs_dir_read(&lfs, &dir, &info) => 0;
  505. lfs_dir_close(&lfs, &dir) => 0;
  506. // can we list the files?
  507. for (lfs_size_t i = 0; i < COUNT; i++) {
  508. char name[8];
  509. sprintf(name, "dir%03d", i);
  510. lfs_dir_t dir;
  511. lfs_dir_open(&lfs, &dir, name) => 0;
  512. struct lfs_info info;
  513. lfs_dir_read(&lfs, &dir, &info) => 1;
  514. assert(info.type == LFS_TYPE_DIR);
  515. assert(strcmp(info.name, ".") == 0);
  516. lfs_dir_read(&lfs, &dir, &info) => 1;
  517. assert(info.type == LFS_TYPE_DIR);
  518. assert(strcmp(info.name, "..") == 0);
  519. lfs_dir_read(&lfs, &dir, &info) => 1;
  520. assert(info.type == LFS_TYPE_REG);
  521. sprintf(name, "file%03d", i);
  522. assert(strcmp(info.name, name) == 0);
  523. assert(info.size == SIZE);
  524. lfs_dir_read(&lfs, &dir, &info) => 0;
  525. lfs_dir_close(&lfs, &dir) => 0;
  526. }
  527. // now can we read the files?
  528. prng = 42;
  529. for (lfs_size_t i = 0; i < COUNT; i++) {
  530. lfs_file_t file;
  531. char name[16];
  532. sprintf(name, "dir%03d/file%03d", i, i);
  533. lfs_file_open(&lfs, &file, name, LFS_O_RDONLY) => 0;
  534. for (lfs_size_t j = 0; j < SIZE; j += CHUNK) {
  535. uint8_t chunk[CHUNK];
  536. lfs_file_read(&lfs, &file, chunk, CHUNK) => CHUNK;
  537. for (lfs_size_t k = 0; k < CHUNK; k++) {
  538. assert(chunk[k] == TEST_PRNG(&prng) & 0xff);
  539. }
  540. }
  541. lfs_file_close(&lfs, &file) => 0;
  542. }
  543. lfs_unmount(&lfs) => 0;
  544. '''
  545. ## backwards-compatibility tests ##
  546. # test we can mount in an old version
  547. [cases.test_compat_backward_mount]
  548. if = 'LFS_VERSION == LFSP_VERSION'
  549. code = '''
  550. // create the new version
  551. lfs_t lfs;
  552. lfs_format(&lfs, cfg) => 0;
  553. // confirm the new mount works
  554. lfs_mount(&lfs, cfg) => 0;
  555. lfs_unmount(&lfs) => 0;
  556. // now test the previous mount
  557. struct lfsp_config cfgp;
  558. memcpy(&cfgp, cfg, sizeof(cfgp));
  559. lfsp_t lfsp;
  560. lfsp_mount(&lfsp, &cfgp) => 0;
  561. lfsp_unmount(&lfsp) => 0;
  562. '''
  563. # test we can read dirs in an old version
  564. [cases.test_compat_backward_read_dirs]
  565. defines.COUNT = 5
  566. if = 'LFS_VERSION == LFSP_VERSION'
  567. code = '''
  568. // create the new version
  569. lfs_t lfs;
  570. lfs_format(&lfs, cfg) => 0;
  571. // write COUNT dirs
  572. lfs_mount(&lfs, cfg) => 0;
  573. for (lfs_size_t i = 0; i < COUNT; i++) {
  574. char name[8];
  575. sprintf(name, "dir%03d", i);
  576. lfs_mkdir(&lfs, name) => 0;
  577. }
  578. lfs_unmount(&lfs) => 0;
  579. // mount the new version
  580. struct lfsp_config cfgp;
  581. memcpy(&cfgp, cfg, sizeof(cfgp));
  582. lfsp_t lfsp;
  583. lfsp_mount(&lfsp, &cfgp) => 0;
  584. // can we list the directories?
  585. lfsp_dir_t dir;
  586. lfsp_dir_open(&lfsp, &dir, "/") => 0;
  587. struct lfsp_info info;
  588. lfsp_dir_read(&lfsp, &dir, &info) => 1;
  589. assert(info.type == LFSP_TYPE_DIR);
  590. assert(strcmp(info.name, ".") == 0);
  591. lfsp_dir_read(&lfsp, &dir, &info) => 1;
  592. assert(info.type == LFSP_TYPE_DIR);
  593. assert(strcmp(info.name, "..") == 0);
  594. for (lfs_size_t i = 0; i < COUNT; i++) {
  595. lfsp_dir_read(&lfsp, &dir, &info) => 1;
  596. assert(info.type == LFSP_TYPE_DIR);
  597. char name[8];
  598. sprintf(name, "dir%03d", i);
  599. assert(strcmp(info.name, name) == 0);
  600. }
  601. lfsp_dir_read(&lfsp, &dir, &info) => 0;
  602. lfsp_dir_close(&lfsp, &dir) => 0;
  603. lfsp_unmount(&lfsp) => 0;
  604. '''
  605. # test we can read files in an old version
  606. [cases.test_compat_backward_read_files]
  607. defines.COUNT = 5
  608. defines.SIZE = [4, 32, 512, 8192]
  609. defines.CHUNK = 4
  610. if = 'LFS_VERSION == LFSP_VERSION'
  611. code = '''
  612. // create the new version
  613. lfs_t lfs;
  614. lfs_format(&lfs, cfg) => 0;
  615. // write COUNT files
  616. lfs_mount(&lfs, cfg) => 0;
  617. uint32_t prng = 42;
  618. for (lfs_size_t i = 0; i < COUNT; i++) {
  619. lfs_file_t file;
  620. char name[8];
  621. sprintf(name, "file%03d", i);
  622. lfs_file_open(&lfs, &file, name,
  623. LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0;
  624. for (lfs_size_t j = 0; j < SIZE; j += CHUNK) {
  625. uint8_t chunk[CHUNK];
  626. for (lfs_size_t k = 0; k < CHUNK; k++) {
  627. chunk[k] = TEST_PRNG(&prng) & 0xff;
  628. }
  629. lfs_file_write(&lfs, &file, chunk, CHUNK) => CHUNK;
  630. }
  631. lfs_file_close(&lfs, &file) => 0;
  632. }
  633. lfs_unmount(&lfs) => 0;
  634. // mount the previous version
  635. struct lfsp_config cfgp;
  636. memcpy(&cfgp, cfg, sizeof(cfgp));
  637. lfsp_t lfsp;
  638. lfsp_mount(&lfsp, &cfgp) => 0;
  639. // can we list the files?
  640. lfsp_dir_t dir;
  641. lfsp_dir_open(&lfsp, &dir, "/") => 0;
  642. struct lfsp_info info;
  643. lfsp_dir_read(&lfsp, &dir, &info) => 1;
  644. assert(info.type == LFSP_TYPE_DIR);
  645. assert(strcmp(info.name, ".") == 0);
  646. lfsp_dir_read(&lfsp, &dir, &info) => 1;
  647. assert(info.type == LFSP_TYPE_DIR);
  648. assert(strcmp(info.name, "..") == 0);
  649. for (lfs_size_t i = 0; i < COUNT; i++) {
  650. lfsp_dir_read(&lfsp, &dir, &info) => 1;
  651. assert(info.type == LFSP_TYPE_REG);
  652. char name[8];
  653. sprintf(name, "file%03d", i);
  654. assert(strcmp(info.name, name) == 0);
  655. assert(info.size == SIZE);
  656. }
  657. lfsp_dir_read(&lfsp, &dir, &info) => 0;
  658. // now can we read the files?
  659. prng = 42;
  660. for (lfs_size_t i = 0; i < COUNT; i++) {
  661. lfsp_file_t file;
  662. char name[8];
  663. sprintf(name, "file%03d", i);
  664. lfsp_file_open(&lfsp, &file, name, LFSP_O_RDONLY) => 0;
  665. for (lfs_size_t j = 0; j < SIZE; j += CHUNK) {
  666. uint8_t chunk[CHUNK];
  667. lfsp_file_read(&lfsp, &file, chunk, CHUNK) => CHUNK;
  668. for (lfs_size_t k = 0; k < CHUNK; k++) {
  669. assert(chunk[k] == TEST_PRNG(&prng) & 0xff);
  670. }
  671. }
  672. lfsp_file_close(&lfsp, &file) => 0;
  673. }
  674. lfsp_unmount(&lfsp) => 0;
  675. '''
  676. # test we can read files in dirs in an old version
  677. [cases.test_compat_backward_read_files_in_dirs]
  678. defines.COUNT = 5
  679. defines.SIZE = [4, 32, 512, 8192]
  680. defines.CHUNK = 4
  681. if = 'LFS_VERSION == LFSP_VERSION'
  682. code = '''
  683. // create the new version
  684. lfs_t lfs;
  685. lfs_format(&lfs, cfg) => 0;
  686. // write COUNT files+dirs
  687. lfs_mount(&lfs, cfg) => 0;
  688. uint32_t prng = 42;
  689. for (lfs_size_t i = 0; i < COUNT; i++) {
  690. char name[16];
  691. sprintf(name, "dir%03d", i);
  692. lfs_mkdir(&lfs, name) => 0;
  693. lfs_file_t file;
  694. sprintf(name, "dir%03d/file%03d", i, i);
  695. lfs_file_open(&lfs, &file, name,
  696. LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0;
  697. for (lfs_size_t j = 0; j < SIZE; j += CHUNK) {
  698. uint8_t chunk[CHUNK];
  699. for (lfs_size_t k = 0; k < CHUNK; k++) {
  700. chunk[k] = TEST_PRNG(&prng) & 0xff;
  701. }
  702. lfs_file_write(&lfs, &file, chunk, CHUNK) => CHUNK;
  703. }
  704. lfs_file_close(&lfs, &file) => 0;
  705. }
  706. lfs_unmount(&lfs) => 0;
  707. // mount the previous version
  708. struct lfsp_config cfgp;
  709. memcpy(&cfgp, cfg, sizeof(cfgp));
  710. lfsp_t lfsp;
  711. lfsp_mount(&lfsp, &cfgp) => 0;
  712. // can we list the directories?
  713. lfsp_dir_t dir;
  714. lfsp_dir_open(&lfsp, &dir, "/") => 0;
  715. struct lfsp_info info;
  716. lfsp_dir_read(&lfsp, &dir, &info) => 1;
  717. assert(info.type == LFSP_TYPE_DIR);
  718. assert(strcmp(info.name, ".") == 0);
  719. lfsp_dir_read(&lfsp, &dir, &info) => 1;
  720. assert(info.type == LFSP_TYPE_DIR);
  721. assert(strcmp(info.name, "..") == 0);
  722. for (lfs_size_t i = 0; i < COUNT; i++) {
  723. lfsp_dir_read(&lfsp, &dir, &info) => 1;
  724. assert(info.type == LFSP_TYPE_DIR);
  725. char name[8];
  726. sprintf(name, "dir%03d", i);
  727. assert(strcmp(info.name, name) == 0);
  728. }
  729. lfsp_dir_read(&lfsp, &dir, &info) => 0;
  730. lfsp_dir_close(&lfsp, &dir) => 0;
  731. // can we list the files?
  732. for (lfs_size_t i = 0; i < COUNT; i++) {
  733. char name[8];
  734. sprintf(name, "dir%03d", i);
  735. lfsp_dir_t dir;
  736. lfsp_dir_open(&lfsp, &dir, name) => 0;
  737. struct lfsp_info info;
  738. lfsp_dir_read(&lfsp, &dir, &info) => 1;
  739. assert(info.type == LFSP_TYPE_DIR);
  740. assert(strcmp(info.name, ".") == 0);
  741. lfsp_dir_read(&lfsp, &dir, &info) => 1;
  742. assert(info.type == LFSP_TYPE_DIR);
  743. assert(strcmp(info.name, "..") == 0);
  744. lfsp_dir_read(&lfsp, &dir, &info) => 1;
  745. assert(info.type == LFSP_TYPE_REG);
  746. sprintf(name, "file%03d", i);
  747. assert(strcmp(info.name, name) == 0);
  748. assert(info.size == SIZE);
  749. lfsp_dir_read(&lfsp, &dir, &info) => 0;
  750. lfsp_dir_close(&lfsp, &dir) => 0;
  751. }
  752. // now can we read the files?
  753. prng = 42;
  754. for (lfs_size_t i = 0; i < COUNT; i++) {
  755. lfsp_file_t file;
  756. char name[16];
  757. sprintf(name, "dir%03d/file%03d", i, i);
  758. lfsp_file_open(&lfsp, &file, name, LFSP_O_RDONLY) => 0;
  759. for (lfs_size_t j = 0; j < SIZE; j += CHUNK) {
  760. uint8_t chunk[CHUNK];
  761. lfsp_file_read(&lfsp, &file, chunk, CHUNK) => CHUNK;
  762. for (lfs_size_t k = 0; k < CHUNK; k++) {
  763. assert(chunk[k] == TEST_PRNG(&prng) & 0xff);
  764. }
  765. }
  766. lfsp_file_close(&lfsp, &file) => 0;
  767. }
  768. lfsp_unmount(&lfsp) => 0;
  769. '''
  770. # test we can write dirs in an old version
  771. [cases.test_compat_backward_write_dirs]
  772. defines.COUNT = 10
  773. if = 'LFS_VERSION == LFSP_VERSION'
  774. code = '''
  775. // create the new version
  776. lfs_t lfs;
  777. lfs_format(&lfs, cfg) => 0;
  778. // write COUNT/2 dirs
  779. lfs_mount(&lfs, cfg) => 0;
  780. for (lfs_size_t i = 0; i < COUNT/2; i++) {
  781. char name[8];
  782. sprintf(name, "dir%03d", i);
  783. lfs_mkdir(&lfs, name) => 0;
  784. }
  785. lfs_unmount(&lfs) => 0;
  786. // mount the previous version
  787. struct lfsp_config cfgp;
  788. memcpy(&cfgp, cfg, sizeof(cfgp));
  789. lfsp_t lfsp;
  790. lfsp_mount(&lfsp, &cfgp) => 0;
  791. // write another COUNT/2 dirs
  792. for (lfs_size_t i = COUNT/2; i < COUNT; i++) {
  793. char name[8];
  794. sprintf(name, "dir%03d", i);
  795. lfsp_mkdir(&lfsp, name) => 0;
  796. }
  797. // can we list the directories?
  798. lfsp_dir_t dir;
  799. lfsp_dir_open(&lfsp, &dir, "/") => 0;
  800. struct lfsp_info info;
  801. lfsp_dir_read(&lfsp, &dir, &info) => 1;
  802. assert(info.type == LFSP_TYPE_DIR);
  803. assert(strcmp(info.name, ".") == 0);
  804. lfsp_dir_read(&lfsp, &dir, &info) => 1;
  805. assert(info.type == LFSP_TYPE_DIR);
  806. assert(strcmp(info.name, "..") == 0);
  807. for (lfs_size_t i = 0; i < COUNT; i++) {
  808. lfsp_dir_read(&lfsp, &dir, &info) => 1;
  809. assert(info.type == LFSP_TYPE_DIR);
  810. char name[8];
  811. sprintf(name, "dir%03d", i);
  812. assert(strcmp(info.name, name) == 0);
  813. }
  814. lfsp_dir_read(&lfsp, &dir, &info) => 0;
  815. lfsp_dir_close(&lfsp, &dir) => 0;
  816. lfsp_unmount(&lfsp) => 0;
  817. '''
  818. # test we can write files in an old version
  819. [cases.test_compat_backward_write_files]
  820. defines.COUNT = 5
  821. defines.SIZE = [4, 32, 512, 8192]
  822. defines.CHUNK = 2
  823. if = 'LFS_VERSION == LFSP_VERSION'
  824. code = '''
  825. // create the previous version
  826. lfs_t lfs;
  827. lfs_format(&lfs, cfg) => 0;
  828. // write half COUNT files
  829. lfs_mount(&lfs, cfg) => 0;
  830. uint32_t prng = 42;
  831. for (lfs_size_t i = 0; i < COUNT; i++) {
  832. // write half
  833. lfs_file_t file;
  834. char name[8];
  835. sprintf(name, "file%03d", i);
  836. lfs_file_open(&lfs, &file, name,
  837. LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0;
  838. for (lfs_size_t j = 0; j < SIZE/2; j += CHUNK) {
  839. uint8_t chunk[CHUNK];
  840. for (lfs_size_t k = 0; k < CHUNK; k++) {
  841. chunk[k] = TEST_PRNG(&prng) & 0xff;
  842. }
  843. lfs_file_write(&lfs, &file, chunk, CHUNK) => CHUNK;
  844. }
  845. lfs_file_close(&lfs, &file) => 0;
  846. // skip the other half but keep our prng reproducible
  847. for (lfs_size_t j = SIZE/2; j < SIZE; j++) {
  848. TEST_PRNG(&prng);
  849. }
  850. }
  851. lfs_unmount(&lfs) => 0;
  852. // mount the new version
  853. struct lfsp_config cfgp;
  854. memcpy(&cfgp, cfg, sizeof(cfgp));
  855. lfsp_t lfsp;
  856. lfsp_mount(&lfsp, &cfgp) => 0;
  857. // write half COUNT files
  858. prng = 42;
  859. for (lfs_size_t i = 0; i < COUNT; i++) {
  860. // skip half but keep our prng reproducible
  861. for (lfs_size_t j = 0; j < SIZE/2; j++) {
  862. TEST_PRNG(&prng);
  863. }
  864. // write the other half
  865. lfsp_file_t file;
  866. char name[8];
  867. sprintf(name, "file%03d", i);
  868. lfsp_file_open(&lfsp, &file, name, LFSP_O_WRONLY) => 0;
  869. lfsp_file_seek(&lfsp, &file, SIZE/2, LFSP_SEEK_SET) => SIZE/2;
  870. for (lfs_size_t j = SIZE/2; j < SIZE; j += CHUNK) {
  871. uint8_t chunk[CHUNK];
  872. for (lfs_size_t k = 0; k < CHUNK; k++) {
  873. chunk[k] = TEST_PRNG(&prng) & 0xff;
  874. }
  875. lfsp_file_write(&lfsp, &file, chunk, CHUNK) => CHUNK;
  876. }
  877. lfsp_file_close(&lfsp, &file) => 0;
  878. }
  879. // can we list the files?
  880. lfsp_dir_t dir;
  881. lfsp_dir_open(&lfsp, &dir, "/") => 0;
  882. struct lfsp_info info;
  883. lfsp_dir_read(&lfsp, &dir, &info) => 1;
  884. assert(info.type == LFSP_TYPE_DIR);
  885. assert(strcmp(info.name, ".") == 0);
  886. lfsp_dir_read(&lfsp, &dir, &info) => 1;
  887. assert(info.type == LFSP_TYPE_DIR);
  888. assert(strcmp(info.name, "..") == 0);
  889. for (lfs_size_t i = 0; i < COUNT; i++) {
  890. lfsp_dir_read(&lfsp, &dir, &info) => 1;
  891. assert(info.type == LFSP_TYPE_REG);
  892. char name[8];
  893. sprintf(name, "file%03d", i);
  894. assert(strcmp(info.name, name) == 0);
  895. assert(info.size == SIZE);
  896. }
  897. lfsp_dir_read(&lfsp, &dir, &info) => 0;
  898. // now can we read the files?
  899. prng = 42;
  900. for (lfs_size_t i = 0; i < COUNT; i++) {
  901. lfsp_file_t file;
  902. char name[8];
  903. sprintf(name, "file%03d", i);
  904. lfsp_file_open(&lfsp, &file, name, LFSP_O_RDONLY) => 0;
  905. for (lfs_size_t j = 0; j < SIZE; j += CHUNK) {
  906. uint8_t chunk[CHUNK];
  907. lfsp_file_read(&lfsp, &file, chunk, CHUNK) => CHUNK;
  908. for (lfs_size_t k = 0; k < CHUNK; k++) {
  909. assert(chunk[k] == TEST_PRNG(&prng) & 0xff);
  910. }
  911. }
  912. lfsp_file_close(&lfsp, &file) => 0;
  913. }
  914. lfsp_unmount(&lfsp) => 0;
  915. '''
  916. # test we can write files in dirs in an old version
  917. [cases.test_compat_backward_write_files_in_dirs]
  918. defines.COUNT = 5
  919. defines.SIZE = [4, 32, 512, 8192]
  920. defines.CHUNK = 2
  921. if = 'LFS_VERSION == LFSP_VERSION'
  922. code = '''
  923. // create the previous version
  924. lfs_t lfs;
  925. lfs_format(&lfs, cfg) => 0;
  926. // write half COUNT files
  927. lfs_mount(&lfs, cfg) => 0;
  928. uint32_t prng = 42;
  929. for (lfs_size_t i = 0; i < COUNT; i++) {
  930. char name[16];
  931. sprintf(name, "dir%03d", i);
  932. lfs_mkdir(&lfs, name) => 0;
  933. // write half
  934. lfs_file_t file;
  935. sprintf(name, "dir%03d/file%03d", i, i);
  936. lfs_file_open(&lfs, &file, name,
  937. LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0;
  938. for (lfs_size_t j = 0; j < SIZE/2; j += CHUNK) {
  939. uint8_t chunk[CHUNK];
  940. for (lfs_size_t k = 0; k < CHUNK; k++) {
  941. chunk[k] = TEST_PRNG(&prng) & 0xff;
  942. }
  943. lfs_file_write(&lfs, &file, chunk, CHUNK) => CHUNK;
  944. }
  945. lfs_file_close(&lfs, &file) => 0;
  946. // skip the other half but keep our prng reproducible
  947. for (lfs_size_t j = SIZE/2; j < SIZE; j++) {
  948. TEST_PRNG(&prng);
  949. }
  950. }
  951. lfs_unmount(&lfs) => 0;
  952. // mount the new version
  953. struct lfsp_config cfgp;
  954. memcpy(&cfgp, cfg, sizeof(cfgp));
  955. lfsp_t lfsp;
  956. lfsp_mount(&lfsp, &cfgp) => 0;
  957. // write half COUNT files
  958. prng = 42;
  959. for (lfs_size_t i = 0; i < COUNT; i++) {
  960. // skip half but keep our prng reproducible
  961. for (lfs_size_t j = 0; j < SIZE/2; j++) {
  962. TEST_PRNG(&prng);
  963. }
  964. // write the other half
  965. lfsp_file_t file;
  966. char name[16];
  967. sprintf(name, "dir%03d/file%03d", i, i);
  968. lfsp_file_open(&lfsp, &file, name, LFSP_O_WRONLY) => 0;
  969. lfsp_file_seek(&lfsp, &file, SIZE/2, LFSP_SEEK_SET) => SIZE/2;
  970. for (lfs_size_t j = SIZE/2; j < SIZE; j += CHUNK) {
  971. uint8_t chunk[CHUNK];
  972. for (lfs_size_t k = 0; k < CHUNK; k++) {
  973. chunk[k] = TEST_PRNG(&prng) & 0xff;
  974. }
  975. lfsp_file_write(&lfsp, &file, chunk, CHUNK) => CHUNK;
  976. }
  977. lfsp_file_close(&lfsp, &file) => 0;
  978. }
  979. // can we list the directories?
  980. lfsp_dir_t dir;
  981. lfsp_dir_open(&lfsp, &dir, "/") => 0;
  982. struct lfsp_info info;
  983. lfsp_dir_read(&lfsp, &dir, &info) => 1;
  984. assert(info.type == LFSP_TYPE_DIR);
  985. assert(strcmp(info.name, ".") == 0);
  986. lfsp_dir_read(&lfsp, &dir, &info) => 1;
  987. assert(info.type == LFSP_TYPE_DIR);
  988. assert(strcmp(info.name, "..") == 0);
  989. for (lfs_size_t i = 0; i < COUNT; i++) {
  990. lfsp_dir_read(&lfsp, &dir, &info) => 1;
  991. assert(info.type == LFSP_TYPE_DIR);
  992. char name[8];
  993. sprintf(name, "dir%03d", i);
  994. assert(strcmp(info.name, name) == 0);
  995. }
  996. lfsp_dir_read(&lfsp, &dir, &info) => 0;
  997. lfsp_dir_close(&lfsp, &dir) => 0;
  998. // can we list the files?
  999. for (lfs_size_t i = 0; i < COUNT; i++) {
  1000. char name[8];
  1001. sprintf(name, "dir%03d", i);
  1002. lfsp_dir_t dir;
  1003. lfsp_dir_open(&lfsp, &dir, name) => 0;
  1004. struct lfsp_info info;
  1005. lfsp_dir_read(&lfsp, &dir, &info) => 1;
  1006. assert(info.type == LFSP_TYPE_DIR);
  1007. assert(strcmp(info.name, ".") == 0);
  1008. lfsp_dir_read(&lfsp, &dir, &info) => 1;
  1009. assert(info.type == LFSP_TYPE_DIR);
  1010. assert(strcmp(info.name, "..") == 0);
  1011. lfsp_dir_read(&lfsp, &dir, &info) => 1;
  1012. assert(info.type == LFSP_TYPE_REG);
  1013. sprintf(name, "file%03d", i);
  1014. assert(strcmp(info.name, name) == 0);
  1015. assert(info.size == SIZE);
  1016. lfsp_dir_read(&lfsp, &dir, &info) => 0;
  1017. lfsp_dir_close(&lfsp, &dir) => 0;
  1018. }
  1019. // now can we read the files?
  1020. prng = 42;
  1021. for (lfs_size_t i = 0; i < COUNT; i++) {
  1022. lfsp_file_t file;
  1023. char name[16];
  1024. sprintf(name, "dir%03d/file%03d", i, i);
  1025. lfsp_file_open(&lfsp, &file, name, LFSP_O_RDONLY) => 0;
  1026. for (lfs_size_t j = 0; j < SIZE; j += CHUNK) {
  1027. uint8_t chunk[CHUNK];
  1028. lfsp_file_read(&lfsp, &file, chunk, CHUNK) => CHUNK;
  1029. for (lfs_size_t k = 0; k < CHUNK; k++) {
  1030. assert(chunk[k] == TEST_PRNG(&prng) & 0xff);
  1031. }
  1032. }
  1033. lfsp_file_close(&lfsp, &file) => 0;
  1034. }
  1035. lfsp_unmount(&lfsp) => 0;
  1036. '''
  1037. ## incompatiblity tests ##
  1038. # test that we fail to mount after a major version bump
  1039. [cases.test_compat_major_incompat]
  1040. in = 'lfs.c'
  1041. code = '''
  1042. // create a superblock
  1043. lfs_t lfs;
  1044. lfs_format(&lfs, cfg) => 0;
  1045. // bump the major version
  1046. //
  1047. // note we're messing around with internals to do this! this
  1048. // is not a user API
  1049. lfs_mount(&lfs, cfg) => 0;
  1050. lfs_mdir_t mdir;
  1051. lfs_dir_fetch(&lfs, &mdir, (lfs_block_t[2]){0, 1}) => 0;
  1052. lfs_superblock_t superblock = {
  1053. .version = LFS_DISK_VERSION + 0x00010000,
  1054. .block_size = lfs.cfg->block_size,
  1055. .block_count = lfs.cfg->block_count,
  1056. .name_max = lfs.name_max,
  1057. .file_max = lfs.file_max,
  1058. .attr_max = lfs.attr_max,
  1059. };
  1060. lfs_superblock_tole32(&superblock);
  1061. lfs_dir_commit(&lfs, &mdir, LFS_MKATTRS(
  1062. {LFS_MKTAG(LFS_TYPE_INLINESTRUCT, 0, sizeof(superblock)),
  1063. &superblock})) => 0;
  1064. lfs_unmount(&lfs) => 0;
  1065. // mount should now fail
  1066. lfs_mount(&lfs, cfg) => LFS_ERR_INVAL;
  1067. '''
  1068. # test that we fail to mount after a minor version bump
  1069. [cases.test_compat_minor_incompat]
  1070. in = 'lfs.c'
  1071. code = '''
  1072. // create a superblock
  1073. lfs_t lfs;
  1074. lfs_format(&lfs, cfg) => 0;
  1075. // bump the minor version
  1076. //
  1077. // note we're messing around with internals to do this! this
  1078. // is not a user API
  1079. lfs_mount(&lfs, cfg) => 0;
  1080. lfs_mdir_t mdir;
  1081. lfs_dir_fetch(&lfs, &mdir, (lfs_block_t[2]){0, 1}) => 0;
  1082. lfs_superblock_t superblock = {
  1083. .version = LFS_DISK_VERSION + 0x00000001,
  1084. .block_size = lfs.cfg->block_size,
  1085. .block_count = lfs.cfg->block_count,
  1086. .name_max = lfs.name_max,
  1087. .file_max = lfs.file_max,
  1088. .attr_max = lfs.attr_max,
  1089. };
  1090. lfs_superblock_tole32(&superblock);
  1091. lfs_dir_commit(&lfs, &mdir, LFS_MKATTRS(
  1092. {LFS_MKTAG(LFS_TYPE_INLINESTRUCT, 0, sizeof(superblock)),
  1093. &superblock})) => 0;
  1094. lfs_unmount(&lfs) => 0;
  1095. // mount should now fail
  1096. lfs_mount(&lfs, cfg) => LFS_ERR_INVAL;
  1097. '''