summaryrefslogtreecommitdiff
path: root/tests/unittests/libmtd_test.c
diff options
context:
space:
mode:
Diffstat (limited to 'tests/unittests/libmtd_test.c')
-rw-r--r--tests/unittests/libmtd_test.c491
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);
+}