Anastasia Klimchuk has uploaded this change for review. ( https://review.coreboot.org/c/flashrom/+/67535 )
Change subject: [WIP] Unit tests for erase function selection algo ......................................................................
[WIP] Unit tests for erase function selection algo
This patch at the moment for testing only and not ready for an actual code review.
Change-Id: I8f3fdefb76e71f6f8dc295d9dead5f38642aace7 Signed-off-by: Anastasia Klimchuk aklm@chromium.org --- A tests/erase_func_algo.c M tests/meson.build M tests/tests.c M tests/tests.h 4 files changed, 236 insertions(+), 0 deletions(-)
git pull ssh://review.coreboot.org:29418/flashrom refs/changes/35/67535/1
diff --git a/tests/erase_func_algo.c b/tests/erase_func_algo.c new file mode 100644 index 0000000..4be1294 --- /dev/null +++ b/tests/erase_func_algo.c @@ -0,0 +1,214 @@ +/* + * This unit test suite is WIP and its purpose is to help with testing + * new algo for erase function selection. + * + * Not ready for proper code review. + */ + +#include <include/test.h> +#include <stdio.h> +#include <string.h> + +#include "tests.h" +#include "chipdrivers.h" +#include "flash.h" +#include "io_mock.h" +#include "libflashrom.h" +#include "programmer.h" + +#define LOG_ERASE_FUNC printf("%s called with blockaddr=0x%x, blocklen=0x%x\n", __func__, blockaddr, blocklen) + +#define ERASE_VALUE 0xff +#define MOCK_CHIP_SIZE 16 +#define CHIPS_NUM 3 /* How many small chip test cases. */ + +struct test_region { + size_t start; + size_t end; + const char *name; +}; + +static struct chip_state { + unsigned int ind; /* Index of currently executed test case */ + uint8_t buf[CHIPS_NUM][MOCK_CHIP_SIZE]; /* Contents of the mock chip. */ + struct test_region regions[CHIPS_NUM][MOCK_CHIP_SIZE]; /* layout regions for each test case */ + struct flashchip chips[CHIPS_NUM]; /* List of chips, same index as in buf */ +} g_chip_state; + +static int read_chip(struct flashctx *flash, uint8_t *buf, unsigned int start, unsigned int len) +{ + printf("Read chip called with start=0x%x, len=0x%x\n", start, len); + + assert_in_range(start + len, 0, MOCK_CHIP_SIZE); + + memcpy(buf, &g_chip_state.buf[g_chip_state.ind][start], len); + return 0; +} + +static int write_chip(struct flashctx *flash, const uint8_t *buf, unsigned int start, unsigned int len) +{ + printf("Write chip called with start=0x%x, len=0x%x\n", start, len); + + assert_in_range(start + len, 0, MOCK_CHIP_SIZE); + + memcpy(&g_chip_state.buf[g_chip_state.ind][start], buf, len); + return 0; +} + +static int block_erase_chip(unsigned int blockaddr, unsigned int blocklen) +{ + //printf("Block erase called with blockaddr=0x%x, blocklen=0x%x\n", blockaddr, blocklen); + + assert_in_range(blockaddr + blocklen, 0, MOCK_CHIP_SIZE); + + memset(&g_chip_state.buf[g_chip_state.ind][blockaddr], ERASE_VALUE, blocklen); + return 0; +} + +/* + * Naming convention for mock erase functions: + * erase_<size of erase block> + */ + +static int erase_1(struct flashctx *flash, unsigned int blockaddr, unsigned int blocklen) +{ + LOG_ERASE_FUNC; + return block_erase_chip(blockaddr, blocklen); +} + +static int erase_2(struct flashctx *flash, unsigned int blockaddr, unsigned int blocklen) +{ + LOG_ERASE_FUNC; + return block_erase_chip(blockaddr, blocklen); +} + +static int erase_4(struct flashctx *flash, unsigned int blockaddr, unsigned int blocklen) +{ + LOG_ERASE_FUNC; + return block_erase_chip(blockaddr, blocklen); +} + +static int erase_8(struct flashctx *flash, unsigned int blockaddr, unsigned int blocklen) +{ + LOG_ERASE_FUNC; + return block_erase_chip(blockaddr, blocklen); +} + +static int erase_16(struct flashctx *flash, unsigned int blockaddr, unsigned int blocklen) +{ + LOG_ERASE_FUNC; + return block_erase_chip(blockaddr, blocklen); +} + +static const struct flashchip chip_small_size = { + .vendor = "aklm", + .total_size = MOCK_CHIP_SIZE, + .tested = TEST_OK_PREW, + .read = read_chip, + .write = write_chip, + .block_erasers = + { + { + .eraseblocks = { {1, MOCK_CHIP_SIZE} }, + .block_erase = erase_1, + }, { + .eraseblocks = { {2, MOCK_CHIP_SIZE / 2} }, + .block_erase = erase_2, + }, { + .eraseblocks = { {4, MOCK_CHIP_SIZE / 4} }, + .block_erase = erase_4, + }, { + .eraseblocks = { {8, MOCK_CHIP_SIZE / 8} }, + .block_erase = erase_8, + }, { + .eraseblocks = { {16, MOCK_CHIP_SIZE / 16} }, + .block_erase = erase_16, + } + }, +}; + +static void setup_chip(struct flashrom_flashctx *flashctx, struct flashrom_layout **layout, + const char *programmer_param, unsigned int ind) +{ + flashctx->chip = &g_chip_state.chips[ind]; + + printf("Creating layout for test case #%d... ", ind); + assert_int_equal(0, flashrom_layout_new(layout)); + /* Regions from test case. */ + int i = 0; + while (g_chip_state.regions[ind][i].name != NULL) { + assert_int_equal(0, flashrom_layout_add_region(*layout, + g_chip_state.regions[ind][i].start, + g_chip_state.regions[ind][i].end, + g_chip_state.regions[ind][i].name)); + assert_int_equal(0, flashrom_layout_include_region(*layout, g_chip_state.regions[ind][i].name)); + i++; + } + + flashrom_layout_set(flashctx, *layout); + printf("done\n"); + + /* + * We need some programmer (any), and dummy is a very good one, + * because it doesn't need any mocking. So no extra complexity + * from a programmer side, and test can focus on working with the chip. + */ + printf("Dummyflasher initialising with param="%s"... ", programmer_param); + assert_int_equal(0, programmer_init(&programmer_dummy, programmer_param)); + /* Assignment below normally happens while probing, but this test is not probing. */ + flashctx->mst = ®istered_masters[0]; + printf("done\n"); +} + +static void teardown(struct flashrom_layout **layout) +{ + printf("Dummyflasher shutdown... "); + assert_int_equal(0, programmer_shutdown()); + printf("done\n"); + + printf("Releasing layout... "); + flashrom_layout_release(*layout); + printf("done\n"); +} + +/* + * Setup all test cases: the same chip definition is used. + * initial contents of buf is different + * layout region is different + */ +static struct chip_state g_chip_state = { + .chips = {chip_small_size, chip_small_size, chip_small_size}, + .regions = { + {{0, MOCK_CHIP_SIZE - 1, "whole chip"}}, + {{0, MOCK_CHIP_SIZE/2 - 1, "part1"}, {MOCK_CHIP_SIZE/2, MOCK_CHIP_SIZE - 1, "part2"}}, + {{0, 10, "odd1"}, {11, 15, "odd2"}}, + }, + .buf = { + {0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf}, + {0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff}, + {0xff, 0x0, 0xff, 0x0, 0xff, 0x0, 0xff, 0x0, 0xff, 0x0, 0xff, 0xff, 0xff, 0xff, 0xff}, + }, +}; + +void erase_function_algo_test_success(void **state) +{ + (void) state; /* unused */ + + struct flashrom_flashctx flashctx = { 0 }; + const char *param = ""; /* Default values for all params. */ + + g_chip_state.ind = 0; /* Let's go! */ + + while (g_chip_state.ind < CHIPS_NUM) { + struct flashrom_layout *layout; + setup_chip(&flashctx, &layout, param, g_chip_state.ind); + + printf("Erase test case #%d started.\n", g_chip_state.ind); + int ret = flashrom_flash_erase(&flashctx); + printf("Erase test case ##%d returned %d.\n", g_chip_state.ind, ret); + + teardown(&layout); + + g_chip_state.ind++; + }; +} diff --git a/tests/meson.build b/tests/meson.build index b629998..61b8a09 100644 --- a/tests/meson.build +++ b/tests/meson.build @@ -31,6 +31,7 @@ 'layout.c', 'chip.c', 'chip_wp.c', + 'erase_func_algo.c', ]
mocks = [ diff --git a/tests/tests.c b/tests/tests.c index 7a448d4..d30a5ae 100644 --- a/tests/tests.c +++ b/tests/tests.c @@ -459,5 +459,10 @@ }; ret |= cmocka_run_group_tests_name("chip_wp.c tests", chip_wp_tests, NULL, NULL);
+ const struct CMUnitTest erase_func_algo_tests[] = { + cmocka_unit_test(erase_function_algo_test_success), + }; + ret |= cmocka_run_group_tests_name("erase_func_algo.c tests", erase_func_algo_tests, NULL, NULL); + return ret; } diff --git a/tests/tests.h b/tests/tests.h index cdbf01c..ec868c6 100644 --- a/tests/tests.h +++ b/tests/tests.h @@ -86,4 +86,7 @@ void full_chip_erase_with_wp_dummyflasher_test_success(void **state); void partial_chip_erase_with_wp_dummyflasher_test_success(void **state);
+/* erase_func_algo.c */ +void erase_function_algo_test_success(void **state); + #endif /* TESTS_H */