blob: fc28dc09f9de91bab9e1e5bae539c75ad2b2432c [file] [log] [blame]
#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);
}