diff --git a/tests/test_dseek.toml b/tests/test_dseek.toml index 42cbd80c..b61c444f 100644 --- a/tests/test_dseek.toml +++ b/tests/test_dseek.toml @@ -288,10 +288,395 @@ code = ''' lfsr_unmount(&lfs) => 0; ''' -# test dir read works when under filesystem modifications -# -# this is a bit complex and subtle +# test neighbor changes don't mess with an unrelated dir read +[cases.test_dseek_read_neighbor_mkdirs] +defines.N = 5 +# where in the dir read do we mkdir? +defines.I = 'range(6)' +defines.PARENT = true +# bit 0x2 = left neighbor +# bit 0x1 = right neighbor +defines.NEIGHBORS = [0x1, 0x2, 0x3] +# more neighbors ensures mdir splits which can be its own source +# of problems +defines.NEIGHBOR_N = [1, 10, 100] +# 0 => don't seek +# 1 => seek +# 2 => rewind then seek +# 3 => seek with offset before mutation +# 4 => rewind then seek with offset before mutation +defines.SEEK = [0, 1, 2, 3, 4] +# neighbors only make sense if we have a parent +if = 'PARENT || NEIGHBORS == 0' +code = ''' + lfs_t lfs; + lfsr_format(&lfs, CFG) => 0; + lfsr_mount(&lfs, CFG) => 0; + if (PARENT) { + lfsr_mkdir(&lfs, "pricklypear") => 0; + + if (NEIGHBORS & 0x2) { + assert(lfs_crc32c(0, "a_IplRNrPH", 10) == 0x00000000); + lfsr_mkdir(&lfs, "a_IplRNrPH") => 0; + } + + if (NEIGHBORS & 0x1) { + assert(lfs_crc32c(0, "f_VtoMnwRH", 10) == 0xffffffff); + lfsr_mkdir(&lfs, "f_VtoMnwRH") => 0; + } + } + + // create our directories + for (lfs_size_t i = 0; i < N; i++) { + char name[256]; + sprintf(name, "%s/dir%04d", (PARENT ? "pricklypear" : ""), i); + lfsr_mkdir(&lfs, name) => 0; + } + + // start reading + lfsr_dir_t dir; + lfsr_dir_open(&lfs, &dir, (PARENT ? "pricklypear" : "/")) => 0; + struct lfs_info info; + lfsr_dir_read(&lfs, &dir, &info) => 0; + assert(strcmp(info.name, ".") == 0); + assert(info.type == LFS_TYPE_DIR); + lfsr_dir_read(&lfs, &dir, &info) => 0; + assert(strcmp(info.name, "..") == 0); + assert(info.type == LFS_TYPE_DIR); + + // read until I + for (lfs_size_t i = 0; i < I; i++) { + char name[256]; + sprintf(name, "dir%04d", i); + lfsr_dir_read(&lfs, &dir, &info) => 0; + assert(strcmp(info.name, name) == 0); + assert(info.type == LFS_TYPE_DIR); + } + + // since modification is unrelated, the dir position should go unchanged + lfs_soff_t off = lfsr_dir_tell(&lfs, &dir); + assert(off == I+2); + + // make unrelated dirs + if (NEIGHBORS & 0x2) { + for (lfs_size_t i = 0; i < NEIGHBOR_N; i++) { + char name[256]; + sprintf(name, "a_IplRNrPH/a_%04d", i); + lfsr_mkdir(&lfs, name) => 0; + } + } + + if (NEIGHBORS & 0x1) { + for (lfs_size_t i = 0; i < NEIGHBOR_N; i++) { + char name[256]; + sprintf(name, "f_VtoMnwRH/f_%04d", i); + lfsr_mkdir(&lfs, name) => 0; + } + } + + // seek after mkdir? + if (SEEK) { + // note dir pos after reaching end of dir can be anything + lfs_soff_t off_ = lfsr_dir_tell(&lfs, &dir); + assert(off_ >= 0); + if (I < N) { + assert(off_ == off); + } + + if (SEEK == 2 || SEEK == 4) { + lfsr_dir_rewind(&lfs, &dir) => 0; + } + + if (SEEK == 3 || SEEK == 4) { + lfsr_dir_seek(&lfs, &dir, off) => 0; + } else { + lfsr_dir_seek(&lfs, &dir, off_) => 0; + } + } + + // we should be able to keep reading where we left off + for (lfs_size_t i = I; i < N; i++) { + char name[256]; + sprintf(name, "dir%04d", i); + lfsr_dir_read(&lfs, &dir, &info) => 0; + assert(strcmp(info.name, name) == 0); + assert(info.type == LFS_TYPE_DIR); + } + + lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT; + lfsr_dir_close(&lfs, &dir) => 0; + + lfsr_unmount(&lfs) => 0; +''' + +[cases.test_dseek_read_neighbor_rms] +defines.N = 5 +# where in the dir read do we mkdir? +defines.I = 'range(6)' +defines.PARENT = true +# bit 0x2 = left neighbor +# bit 0x1 = right neighbor +defines.NEIGHBORS = [0x1, 0x2, 0x3] +# more neighbors ensures mdir splits which can be its own source +# of problems +defines.NEIGHBOR_N = [1, 10, 100] +# 0 => don't seek +# 1 => seek +# 2 => rewind then seek +# 3 => seek with offset before mutation +# 4 => rewind then seek with offset before mutation +defines.SEEK = [0, 1, 2, 3, 4] +# neighbors only make sense if we have a parent +if = 'PARENT || NEIGHBORS == 0' +code = ''' + lfs_t lfs; + lfsr_format(&lfs, CFG) => 0; + lfsr_mount(&lfs, CFG) => 0; + + if (PARENT) { + lfsr_mkdir(&lfs, "pricklypear") => 0; + + if (NEIGHBORS & 0x2) { + assert(lfs_crc32c(0, "a_IplRNrPH", 10) == 0x00000000); + lfsr_mkdir(&lfs, "a_IplRNrPH") => 0; + for (lfs_size_t i = 0; i < NEIGHBOR_N; i++) { + char name[256]; + sprintf(name, "a_IplRNrPH/a_%04d", i); + lfsr_mkdir(&lfs, name) => 0; + } + } + + if (NEIGHBORS & 0x1) { + assert(lfs_crc32c(0, "f_VtoMnwRH", 10) == 0xffffffff); + lfsr_mkdir(&lfs, "f_VtoMnwRH") => 0; + for (lfs_size_t i = 0; i < NEIGHBOR_N; i++) { + char name[256]; + sprintf(name, "f_VtoMnwRH/f_%04d", i); + lfsr_mkdir(&lfs, name) => 0; + } + } + } + + // create our directories + for (lfs_size_t i = 0; i < N; i++) { + char name[256]; + sprintf(name, "%s/dir%04d", (PARENT ? "pricklypear" : ""), i); + lfsr_mkdir(&lfs, name) => 0; + } + + // start reading + lfsr_dir_t dir; + lfsr_dir_open(&lfs, &dir, (PARENT ? "pricklypear" : "/")) => 0; + struct lfs_info info; + lfsr_dir_read(&lfs, &dir, &info) => 0; + assert(strcmp(info.name, ".") == 0); + assert(info.type == LFS_TYPE_DIR); + lfsr_dir_read(&lfs, &dir, &info) => 0; + assert(strcmp(info.name, "..") == 0); + assert(info.type == LFS_TYPE_DIR); + + // read until I + for (lfs_size_t i = 0; i < I; i++) { + char name[256]; + sprintf(name, "dir%04d", i); + lfsr_dir_read(&lfs, &dir, &info) => 0; + assert(strcmp(info.name, name) == 0); + assert(info.type == LFS_TYPE_DIR); + } + + // since modification is unrelated, the dir position should go unchanged + lfs_soff_t off = lfsr_dir_tell(&lfs, &dir); + assert(off == I+2); + + // remove unrelated dirs + if (NEIGHBORS & 0x2) { + for (lfs_size_t i = 0; i < NEIGHBOR_N; i++) { + char name[256]; + sprintf(name, "a_IplRNrPH/a_%04d", i); + lfsr_remove(&lfs, name) => 0; + } + } + + if (NEIGHBORS & 0x1) { + for (lfs_size_t i = 0; i < NEIGHBOR_N; i++) { + char name[256]; + sprintf(name, "f_VtoMnwRH/f_%04d", i); + lfsr_remove(&lfs, name) => 0; + } + } + + // seek after mkdir? + if (SEEK) { + // note dir pos after reaching end of dir can be anything + lfs_soff_t off_ = lfsr_dir_tell(&lfs, &dir); + assert(off_ >= 0); + if (I < N) { + assert(off_ == off); + } + + if (SEEK == 2 || SEEK == 4) { + lfsr_dir_rewind(&lfs, &dir) => 0; + } + + if (SEEK == 3 || SEEK == 4) { + lfsr_dir_seek(&lfs, &dir, off) => 0; + } else { + lfsr_dir_seek(&lfs, &dir, off_) => 0; + } + } + + // we should be able to keep reading where we left off + for (lfs_size_t i = I; i < N; i++) { + char name[256]; + sprintf(name, "dir%04d", i); + lfsr_dir_read(&lfs, &dir, &info) => 0; + assert(strcmp(info.name, name) == 0); + assert(info.type == LFS_TYPE_DIR); + } + + lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT; + lfsr_dir_close(&lfs, &dir) => 0; + + lfsr_unmount(&lfs) => 0; +''' + +[cases.test_dseek_read_neighbor_mvs] +defines.N = 5 +# where in the dir read do we mkdir? +defines.I = 'range(6)' +defines.PARENT = true +# bit 0x2 = left neighbor +# bit 0x1 = right neighbor +defines.NEIGHBORS = [0x1, 0x2, 0x3] +# more neighbors ensures mdir splits which can be its own source +# of problems +defines.NEIGHBOR_N = [1, 10, 100] +# 0 => don't seek +# 1 => seek +# 2 => rewind then seek +# 3 => seek with offset before mutation +# 4 => rewind then seek with offset before mutation +defines.SEEK = [0, 1, 2, 3, 4] +# neighbors only make sense if we have a parent +if = 'PARENT || NEIGHBORS == 0' +code = ''' + lfs_t lfs; + lfsr_format(&lfs, CFG) => 0; + lfsr_mount(&lfs, CFG) => 0; + + if (PARENT) { + lfsr_mkdir(&lfs, "pricklypear") => 0; + + if (NEIGHBORS & 0x2) { + assert(lfs_crc32c(0, "a_IplRNrPH", 10) == 0x00000000); + lfsr_mkdir(&lfs, "a_IplRNrPH") => 0; + for (lfs_size_t i = 0; i < NEIGHBOR_N; i++) { + char name[256]; + sprintf(name, "a_IplRNrPH/a_%04d", i); + lfsr_mkdir(&lfs, name) => 0; + } + } + + if (NEIGHBORS & 0x1) { + assert(lfs_crc32c(0, "f_VtoMnwRH", 10) == 0xffffffff); + lfsr_mkdir(&lfs, "f_VtoMnwRH") => 0; + for (lfs_size_t i = 0; i < NEIGHBOR_N; i++) { + char name[256]; + sprintf(name, "f_VtoMnwRH/f_%04d", i); + lfsr_mkdir(&lfs, name) => 0; + } + } + } + + // create our directories + for (lfs_size_t i = 0; i < N; i++) { + char name[256]; + sprintf(name, "%s/dir%04d", (PARENT ? "pricklypear" : ""), i); + lfsr_mkdir(&lfs, name) => 0; + } + + // start reading + lfsr_dir_t dir; + lfsr_dir_open(&lfs, &dir, (PARENT ? "pricklypear" : "/")) => 0; + struct lfs_info info; + lfsr_dir_read(&lfs, &dir, &info) => 0; + assert(strcmp(info.name, ".") == 0); + assert(info.type == LFS_TYPE_DIR); + lfsr_dir_read(&lfs, &dir, &info) => 0; + assert(strcmp(info.name, "..") == 0); + assert(info.type == LFS_TYPE_DIR); + + // read until I + for (lfs_size_t i = 0; i < I; i++) { + char name[256]; + sprintf(name, "dir%04d", i); + lfsr_dir_read(&lfs, &dir, &info) => 0; + assert(strcmp(info.name, name) == 0); + assert(info.type == LFS_TYPE_DIR); + } + + // since modification is unrelated, the dir position should go unchanged + lfs_soff_t off = lfsr_dir_tell(&lfs, &dir); + assert(off == I+2); + + // rename unrelated dirs + if (NEIGHBORS & 0x2) { + for (lfs_size_t i = 0; i < NEIGHBOR_N; i++) { + char name[256]; + sprintf(name, "a_IplRNrPH/a_%04d", i); + char name_[256]; + sprintf(name_, "a_IplRNrPH/b_%04d", i); + lfsr_rename(&lfs, name, name_) => 0; + } + } + + if (NEIGHBORS & 0x1) { + for (lfs_size_t i = 0; i < NEIGHBOR_N; i++) { + char name[256]; + sprintf(name, "f_VtoMnwRH/f_%04d", i); + char name_[256]; + sprintf(name_, "f_VtoMnwRH/b_%04d", i); + lfsr_rename(&lfs, name, name_) => 0; + } + } + + // seek after mkdir? + if (SEEK) { + // note dir pos after reaching end of dir can be anything + lfs_soff_t off_ = lfsr_dir_tell(&lfs, &dir); + assert(off_ >= 0); + if (I < N) { + assert(off_ == off); + } + + if (SEEK == 2 || SEEK == 4) { + lfsr_dir_rewind(&lfs, &dir) => 0; + } + + if (SEEK == 3 || SEEK == 4) { + lfsr_dir_seek(&lfs, &dir, off) => 0; + } else { + lfsr_dir_seek(&lfs, &dir, off_) => 0; + } + } + + // we should be able to keep reading where we left off + for (lfs_size_t i = I; i < N; i++) { + char name[256]; + sprintf(name, "dir%04d", i); + lfsr_dir_read(&lfs, &dir, &info) => 0; + assert(strcmp(info.name, name) == 0); + assert(info.type == LFS_TYPE_DIR); + } + + lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT; + lfsr_dir_close(&lfs, &dir) => 0; + + lfsr_unmount(&lfs) => 0; +''' + +# test dir read has somewhat reasonable behaviour when the dir is modified [cases.test_dseek_read_with_mkdirs] defines.N = 5 # where in the dir read do we mkdir?