diff options
Diffstat (limited to 'tests/unittests/libmtd_test.c')
-rw-r--r-- | tests/unittests/libmtd_test.c | 491 |
1 files changed, 491 insertions, 0 deletions
diff --git a/tests/unittests/libmtd_test.c b/tests/unittests/libmtd_test.c new file mode 100644 index 0000000..fc28dc0 --- /dev/null +++ b/tests/unittests/libmtd_test.c @@ -0,0 +1,491 @@ +#include <stdarg.h> +#include <setjmp.h> +#include <stddef.h> +#include <stdint.h> +#include <unistd.h> +#include <stdlib.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/ioctl.h> +#include <unistd.h> +#include <cmocka.h> + +#include "mtd/mtd-user.h" +#include "libmtd.h" +#include "libmtd_int.h" + +#include "test_lib.h" + +static libmtd_t mock_libmtd_open() +{ + /* create a mock object for libmtd, not using sysfs */ + expect_open(SYSFS_ROOT "/class/mtd/mtd0/name", O_RDONLY, 4); + expect_close(4,0); + libmtd_t lib = libmtd_open(); + assert_non_null(lib); + return lib; +} + +static void test_libmtd_open(void **state) +{ + expect_open(SYSFS_ROOT "/class/mtd/mtd0/name", O_RDONLY, 4); + expect_close(4,0); + struct libmtd *lib = libmtd_open(); + assert_non_null(lib); + assert_string_equal(lib->sysfs_mtd, SYSFS_ROOT "/class/mtd"); + assert_string_equal(lib->mtd, SYSFS_ROOT "/class/mtd/mtd%d"); + assert_string_equal(lib->mtd_name, SYSFS_ROOT "/class/mtd/mtd%d/name"); + assert_string_equal(lib->mtd_dev, SYSFS_ROOT "/class/mtd/mtd%d/dev"); + assert_string_equal(lib->mtd_type, SYSFS_ROOT "/class/mtd/mtd%d/type"); + assert_string_equal(lib->mtd_eb_size, SYSFS_ROOT "/class/mtd/mtd%d/erasesize"); + assert_string_equal(lib->mtd_size, SYSFS_ROOT "/class/mtd/mtd%d/size"); + assert_string_equal(lib->mtd_min_io_size, SYSFS_ROOT "/class/mtd/mtd%d/writesize"); + assert_string_equal(lib->mtd_subpage_size, SYSFS_ROOT "/class/mtd/mtd%d/subpagesize"); + assert_string_equal(lib->mtd_oob_size, SYSFS_ROOT "/class/mtd/mtd%d/oobsize"); + assert_string_equal(lib->mtd_region_cnt, SYSFS_ROOT "/class/mtd/mtd%d/numeraseregions"); + assert_string_equal(lib->mtd_flags, SYSFS_ROOT "/class/mtd/mtd%d/flags"); + + libmtd_close(lib); + (void) state; +} + +static void test_mtd_dev_present(void **state) +{ + int ret; + libmtd_t lib = mock_libmtd_open(); + expect_stat(SYSFS_ROOT "/class/mtd/mtd0", 0); + ret = mtd_dev_present(lib, 0); + assert_int_equal(ret, 1); + libmtd_close(lib); + (void) state; +} + +static void test_mtd_mark_bad(void **state) +{ + struct mtd_dev_info mtd; + loff_t seek; + int eb = 12; + memset(&mtd, 0, sizeof(mtd)); + mtd.bb_allowed = 1; + mtd.eb_cnt = 1024; + mtd.eb_size = 128; + seek = (loff_t)eb * mtd.eb_size; + expect_ioctl(MEMSETBADBLOCK, 0, &seek, sizeof(seek)); + int r = mtd_mark_bad(&mtd, 4, eb); + assert_int_equal(r, 0); + + (void) state; +} + +static void test_mtd_is_bad(void **state) +{ + struct mtd_dev_info mtd; + loff_t seek; + int eb = 0x42; + memset(&mtd, 0, sizeof(mtd)); + mtd.bb_allowed = 1; + mtd.eb_cnt = 1024; + mtd.eb_size = 128; + seek = (loff_t)eb * mtd.eb_size; + expect_ioctl(MEMGETBADBLOCK, 0, &seek, sizeof(seek)); + int r = mtd_is_bad(&mtd, 4, eb); + assert_int_equal(r, 0); + + (void) state; +} + +static void test_mtd_lock(void **state) +{ + int eb = 0xBA; + struct mtd_dev_info mtd; + memset(&mtd, 0, sizeof(mtd)); + mtd.bb_allowed = 1; + mtd.eb_cnt = 1024; + mtd.eb_size = 128; + struct erase_info_user ei; + memset(&ei, 0, sizeof(ei)); + ei.start = eb * mtd.eb_size; + ei.length = mtd.eb_size; + expect_ioctl(MEMLOCK, 0, &ei, sizeof(ei)); + int r = mtd_lock(&mtd, 4, eb); + assert_int_equal(r, 0); + + (void) state; +} + +static void test_mtd_unlock(void **state) +{ + int eb = 0xBA; + struct mtd_dev_info mtd; + memset(&mtd, 0, sizeof(mtd)); + mtd.bb_allowed = 1; + mtd.eb_cnt = 1024; + mtd.eb_size = 128; + struct erase_info_user ei; + memset(&ei, 0, sizeof(ei)); + ei.start = eb * mtd.eb_size; + ei.length = mtd.eb_size; + expect_ioctl(MEMUNLOCK, 0, &ei, sizeof(ei)); + int r = mtd_unlock(&mtd, 4, eb); + assert_int_equal(r, 0); + + (void) state; +} + +static void test_mtd_is_locked(void **state) +{ + int eb = 0xBA; + struct mtd_dev_info mtd; + memset(&mtd, 0, sizeof(mtd)); + mtd.bb_allowed = 1; + mtd.eb_cnt = 1024; + mtd.eb_size = 128; + struct erase_info_user ei; + memset(&ei, 0, sizeof(ei)); + ei.start = eb * mtd.eb_size; + ei.length = mtd.eb_size; + expect_ioctl(MEMISLOCKED, 0, &ei, sizeof(ei)); + int r = mtd_is_locked(&mtd, 4, eb); + assert_int_equal(r, 0); + + (void) state; +} + +static void test_mtd_regioninfo(void **state) +{ + struct region_info_user req; + struct region_info_user rr; + memset(&req, 0, sizeof(req)); + memset(&rr, 0, sizeof(rr)); + int mock_fd = 4; + int regidx = 0xAA; + rr.regionindex = regidx; + expect_ioctl(MEMGETREGIONINFO, 0, &rr, sizeof(rr)); + int r = mtd_regioninfo(mock_fd, regidx, &req); + assert_int_equal(r, 0); + + (void) state; +} + +static void test_mtd_erase_multi(void **state) +{ + struct libmtd *lib = mock_libmtd_open(); + struct mtd_dev_info mtd; + struct erase_info_user ei; + struct erase_info_user64 ei64; + int eb = 0x3C; + int blocks = 3; + memset(&ei, 0, sizeof(ei)); + memset(&ei64, 0, sizeof(ei64)); + memset(&mtd, 0, sizeof(mtd)); + mtd.bb_allowed = 1; + mtd.eb_cnt = 1024; + mtd.eb_size = 128; + ei64.start = (uint64_t)eb * mtd.eb_size; + ei64.length = (uint64_t)mtd.eb_size * blocks; + ei.start = ei64.start; + ei.length = ei64.length; + /* non offs64 first */ + lib->offs64_ioctls = OFFS64_IOCTLS_NOT_SUPPORTED; + expect_ioctl(MEMERASE, 0, &ei, sizeof(ei)); + int r = mtd_erase_multi(lib, &mtd, 4, eb, blocks); + assert_int_equal(r, 0); + + lib->offs64_ioctls = OFFS64_IOCTLS_SUPPORTED; + expect_ioctl(MEMERASE64, 0, &ei64, sizeof(ei64)); + r = mtd_erase_multi(lib, &mtd, 4, eb, blocks); + assert_int_equal(r, 0); + + libmtd_close(lib); + (void) state; +} + +/* this is the same as above but with blocks == 1 and a + * different function call. + * libmtd is mapping mtd_erase to mtd_erase_multi with 1 block + */ +static void test_mtd_erase(void **state) +{ + struct libmtd *lib = mock_libmtd_open(); + struct mtd_dev_info mtd; + struct erase_info_user ei; + struct erase_info_user64 ei64; + int eb = 0x3C; + int blocks = 1; + memset(&ei, 0, sizeof(ei)); + memset(&ei64, 0, sizeof(ei64)); + memset(&mtd, 0, sizeof(mtd)); + mtd.bb_allowed = 1; + mtd.eb_cnt = 1024; + mtd.eb_size = 128; + ei64.start = (uint64_t)eb * mtd.eb_size; + ei64.length = (uint64_t)mtd.eb_size * blocks; + ei.start = ei64.start; + ei.length = ei64.length; + /* non offs64 first */ + lib->offs64_ioctls = OFFS64_IOCTLS_NOT_SUPPORTED; + expect_ioctl(MEMERASE, 0, &ei, sizeof(ei)); + int r = mtd_erase(lib, &mtd, 4, eb); + assert_int_equal(r, 0); + + lib->offs64_ioctls = OFFS64_IOCTLS_SUPPORTED; + expect_ioctl(MEMERASE64, 0, &ei64, sizeof(ei64)); + r = mtd_erase(lib, &mtd, 4, eb); + assert_int_equal(r, 0); + + libmtd_close(lib); + (void) state; + +} + +static void test_mtd_read(void **state) +{ + int mock_fd = 4; + int eb = 0xE0; + int offs = 43; + int len = 28; + off_t seek; + char buf[28]; + struct mtd_dev_info mtd; + memset(&mtd, 0, sizeof(mtd)); + mtd.bb_allowed = 1; + mtd.eb_cnt = 1024; + mtd.eb_size = 128; + seek = (off_t)eb * mtd.eb_size + offs; + expect_lseek(seek, SEEK_SET, seek); + expect_read(len, len); + int r = mtd_read(&mtd, mock_fd, eb, offs, &buf, len); + assert_int_equal(r, 0); + + (void) state; +} + +static void test_mtd_write_nooob(void **state) +{ + struct libmtd *lib = mock_libmtd_open(); + int mock_fd = 4; + int eb = 0xE0; + int offs = 64; + int len = 64; + off_t seek; + char buf[64]; + memset(buf, 0xAA, len); + struct mtd_dev_info mtd; + memset(&mtd, 0, sizeof(mtd)); + mtd.bb_allowed = 1; + mtd.eb_cnt = 1024; + mtd.eb_size = 128; + mtd.subpage_size = 64; + seek = (off_t)eb * mtd.eb_size + offs; + expect_lseek(seek, SEEK_SET, seek); + expect_write(buf, len, len); + int r = mtd_write(lib, &mtd, mock_fd, eb, offs, buf, len, NULL, 0, 0); + assert_int_equal(r, 0); + + libmtd_close(lib); + (void)state; +} + +static void test_mtd_write_withoob(void **state) +{ + struct libmtd *lib = mock_libmtd_open(); + int mock_fd = 4; + int eb = 0xE0; + int offs = 64; + int len = 64; + int oob_len = 64; + uint8_t mode = 3; + off_t seek; + char buf[64], oob_data[64]; + struct mtd_dev_info mtd; + struct mtd_write_req req; + memset(buf, 0xAA, len); + memset(oob_data, 0xBA, oob_len); + memset(&mtd, 0, sizeof(mtd)); + memset(&req, 0, sizeof(req)); + mtd.bb_allowed = 1; + mtd.eb_cnt = 1024; + mtd.eb_size = 128; + mtd.subpage_size = 64; + seek = (off_t)eb * mtd.eb_size + offs; + req.start = seek; + req.len = len; + req.ooblen = oob_len; + req.usr_data = (uint64_t)(unsigned long)buf; + req.usr_oob = (uint64_t)(unsigned long)oob_data; + req.mode = mode; + expect_ioctl(MEMWRITE, 0, &req, sizeof(req)); + int r = mtd_write(lib, &mtd, mock_fd, eb, offs, buf, len, oob_data, oob_len, mode); + assert_int_equal(r, 0); + + libmtd_close(lib); + (void) state; +} + +static void test_mtd_read_oob(void **state) +{ + struct libmtd *lib = mock_libmtd_open(); + struct mtd_dev_info mtd; + struct mtd_oob_buf64 oob64; + struct mtd_oob_buf oob; + int mock_fd = 4; + uint64_t start = 0, length = 64; + char buf[64]; + memset(buf, 0xCD, 64); + memset(&oob, 0, sizeof(oob)); + memset(&oob64, 0, sizeof(oob64)); + memset(&mtd, 0, sizeof(mtd)); + mtd.bb_allowed = 1; + mtd.eb_cnt = 1024; + mtd.eb_size = 128; + mtd.subpage_size = 64; + mtd.oob_size = 128; + oob64.start = start; + oob64.length = length; + oob64.usr_ptr = (uint64_t)(unsigned long)buf; + oob.start = oob64.start; + oob.length = oob64.length; + oob.ptr = buf; + + lib->offs64_ioctls = OFFS64_IOCTLS_NOT_SUPPORTED; + expect_ioctl(MEMREADOOB, 0, &oob, sizeof(oob)); + int r = mtd_read_oob(lib, &mtd, mock_fd, start, length, buf); + assert_int_equal(r, 0); + + lib->offs64_ioctls = OFFS64_IOCTLS_SUPPORTED; + expect_ioctl(MEMREADOOB64, 0, &oob64, sizeof(oob64)); + r = mtd_read_oob(lib, &mtd, mock_fd, start, length, buf); + assert_int_equal(r, 0); + + libmtd_close(lib); + (void) state; +} + +/* basically the same as above but write calls */ +static void test_mtd_write_oob(void **state) +{ + struct libmtd *lib = mock_libmtd_open(); + struct mtd_dev_info mtd; + struct mtd_oob_buf64 oob64; + struct mtd_oob_buf oob; + int mock_fd = 4; + uint64_t start = 0, length = 64; + char buf[64]; + memset(buf, 0xCD, 64); + memset(&oob, 0, sizeof(oob)); + memset(&oob64, 0, sizeof(oob64)); + memset(&mtd, 0, sizeof(mtd)); + mtd.bb_allowed = 1; + mtd.eb_cnt = 1024; + mtd.eb_size = 128; + mtd.subpage_size = 64; + mtd.oob_size = 128; + oob64.start = start; + oob64.length = length; + oob64.usr_ptr = (uint64_t)(unsigned long)buf; + oob.start = oob64.start; + oob.length = oob64.length; + oob.ptr = buf; + + lib->offs64_ioctls = OFFS64_IOCTLS_NOT_SUPPORTED; + expect_ioctl(MEMWRITEOOB, 0, &oob, sizeof(oob)); + int r = mtd_write_oob(lib, &mtd, mock_fd, start, length, buf); + assert_int_equal(r, 0); + + lib->offs64_ioctls = OFFS64_IOCTLS_SUPPORTED; + expect_ioctl(MEMWRITEOOB64, 0, &oob64, sizeof(oob64)); + r = mtd_write_oob(lib, &mtd, mock_fd, start, length, buf); + assert_int_equal(r, 0); + + libmtd_close(lib); + (void)state; +} + +static void test_mtd_get_info(void **state) +{ + struct libmtd *lib = mock_libmtd_open(); + struct mtd_info info; + memset(&info, 0, sizeof(info)); + int r = mtd_get_info(lib, &info); + assert_int_equal(info.sysfs_supported, 1); + assert_int_equal(info.highest_mtd_num, 0); + assert_int_equal(info.lowest_mtd_num, 0); + assert_int_equal(info.mtd_dev_cnt, 1); + assert_int_equal(r, 0); + + libmtd_close(lib); + (void)state; +} + +static void test_mtd_get_dev_info1(void **state) +{ + struct libmtd *lib = mock_libmtd_open(); + struct mtd_dev_info info; + int dev_num = 0; + memset(&info, 0, sizeof(info)); + expect_stat(SYSFS_ROOT "/class/mtd/mtd0", 0); + expect_open(SYSFS_ROOT "/class/mtd/mtd0/dev", O_RDONLY, 0); + expect_read_real(50,0); + expect_read(1,0); + expect_close(3,1); + expect_open(SYSFS_ROOT "/class/mtd/mtd0/name", O_RDONLY, 0); + expect_read_real(128,0); + expect_read(1,0); + expect_close(3,1); + expect_open(SYSFS_ROOT "/class/mtd/mtd0/type", O_RDONLY, 4); + expect_read(65,0); + expect_read(1,0); + expect_close(4,0); + expect_open(SYSFS_ROOT "/class/mtd/mtd0/erasesize", O_RDONLY, 0); + expect_read_real(50, 0); + expect_close(3,1); + expect_open(SYSFS_ROOT "/class/mtd/mtd0/size", O_RDONLY, 0); + expect_read_real(50,0); + expect_close(3,1); + expect_open(SYSFS_ROOT "/class/mtd/mtd0/writesize", O_RDONLY, 0); + expect_read_real(50,0); + expect_close(3,1); + expect_open(SYSFS_ROOT "/class/mtd/mtd0/subpagesize", O_RDONLY, 0); + expect_read_real(50,0); + expect_close(3,1); + expect_open(SYSFS_ROOT "/class/mtd/mtd0/oobsize", O_RDONLY, 0); + expect_read_real(50,0); + expect_close(3,1); + expect_open(SYSFS_ROOT "/class/mtd/mtd0/numeraseregions", O_RDONLY, 0); + expect_read_real(50,0); + expect_close(3,1); + expect_open(SYSFS_ROOT "/class/mtd/mtd0/flags", O_RDONLY, 0); + expect_read_real(50,0); + expect_close(3,1); + int r = mtd_get_dev_info1(lib, dev_num, &info); + assert_int_equal(r, 0); + /* TODO check values */ + + libmtd_close(lib); + (void)state; +} + +int main(void) +{ + const struct CMUnitTest tests[] = { + cmocka_unit_test(test_libmtd_open), + cmocka_unit_test(test_mtd_is_bad), + cmocka_unit_test(test_mtd_mark_bad), + cmocka_unit_test(test_mtd_lock), + cmocka_unit_test(test_mtd_unlock), + cmocka_unit_test(test_mtd_is_locked), + cmocka_unit_test(test_mtd_regioninfo), + cmocka_unit_test(test_mtd_erase_multi), + cmocka_unit_test(test_mtd_erase), + cmocka_unit_test(test_mtd_read), + cmocka_unit_test(test_mtd_write_nooob), + cmocka_unit_test(test_mtd_write_withoob), + cmocka_unit_test(test_mtd_read_oob), + cmocka_unit_test(test_mtd_write_oob), + cmocka_unit_test(test_mtd_dev_present), + cmocka_unit_test(test_mtd_get_info), + cmocka_unit_test(test_mtd_get_dev_info1), + }; + + return cmocka_run_group_tests(tests, NULL, NULL); +} |