Anastasia Klimchuk has submitted this change. ( https://review.coreboot.org/c/flashrom/+/69620 )
(
9 is the latest approved patch-set. No files were changed between the latest approved patch-set and the submitted one. )Change subject: tests: Add selfcheck to unit tests ......................................................................
tests: Add selfcheck to unit tests
Add unit tests for programmer_table, flashchips, and board_matches structs. The tests are derived from the selfcheck function, checking that the required fields have been filled in.
BUG=b:140595239 BRANCH=None TEST=meson test
Change-Id: I41cd014d9bf909296b6c28e3e00548e6883ff41a Signed-off-by: Evan Benn evanbenn@chromium.org Reviewed-on: https://review.coreboot.org/c/flashrom/+/69620 Reviewed-by: Edward O'Callaghan quasisec@chromium.org Reviewed-by: Anastasia Klimchuk aklm@chromium.org Tested-by: build bot (Jenkins) no-reply@coreboot.org --- M board_enable.c M include/programmer.h M tests/meson.build A tests/selfcheck.c M tests/tests.c M tests/tests.h 6 files changed, 196 insertions(+), 0 deletions(-)
Approvals: build bot (Jenkins): Verified Edward O'Callaghan: Looks good to me, approved Anastasia Klimchuk: Looks good to me, approved
diff --git a/board_enable.c b/board_enable.c index 4903c0f..bf26173 100644 --- a/board_enable.c +++ b/board_enable.c @@ -2524,6 +2524,7 @@ #endif { 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, NULL, P3, NULL, NULL, 0, NT, NULL}, /* end marker */ }; +const size_t board_matches_size = ARRAY_SIZE(board_matches);
int selfcheck_board_enables(void) { diff --git a/include/programmer.h b/include/programmer.h index 16448ea..7bcef02 100644 --- a/include/programmer.h +++ b/include/programmer.h @@ -193,6 +193,7 @@ };
extern const struct board_match board_matches[]; +extern const size_t board_matches_size;
struct board_info { const char *vendor; diff --git a/tests/meson.build b/tests/meson.build index e846d91..b8a5ba8 100644 --- a/tests/meson.build +++ b/tests/meson.build @@ -22,6 +22,7 @@ 'layout.c', 'chip.c', 'chip_wp.c', + 'selfcheck.c', )
if not programmer.get('dummy').get('active') diff --git a/tests/selfcheck.c b/tests/selfcheck.c new file mode 100644 index 0000000..aeccf18 --- /dev/null +++ b/tests/selfcheck.c @@ -0,0 +1,156 @@ +/* + * This file is part of the flashrom project. + * + * Copyright 2022 Google LLC + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include "flash.h" +#include "string.h" + +#include "include/test.h" +#include "programmer.h" +#include "tests.h" +#include <cmocka.h> + + +#define assert_table(assertion, message, index, name) \ + do { \ + if (!(assertion)) \ + fail_msg(message " for index:%zu name:%s", (index), (name) ? (name) : "unknown"); \ + } while (0) + + +void selfcheck_programmer_table(void **state) +{ + (void)state; /* unused */ + + size_t i; + for (i = 0; i < programmer_table_size; i++) { + const struct programmer_entry *const p = programmer_table[i]; + assert_table(p, "programmer entry is null", i, "unknown"); + assert_table(p->name, "programmer name is null", i, p->name); + bool type_good = false; + switch (p->type) { + case PCI: + case USB: + case OTHER: + type_good = true; + } + assert_table(type_good, "programmer type is invalid", i, p->name); + /* internal has its device list stored separately. */ + if (strcmp("internal", p->name) != 0) + assert_table(p->devs.note, "programmer devs.note is null", i, p->name); + assert_table(p->init, "programmer init is null", i, p->name); + } +} + +void selfcheck_flashchips_table(void **state) +{ + (void)state; /* unused */ + + size_t i; + assert_true(flashchips_size > 1); + assert_true(flashchips[flashchips_size - 1].name == NULL); + for (i = 0; i < flashchips_size - 1; i++) { + const struct flashchip *chip = &flashchips[i]; + assert_table(chip->vendor, "chip vendor is null", i, chip->name); + assert_table(chip->name, "chip name is null", i, chip->name); + assert_table(chip->bustype != BUS_NONE, "chip bustype is BUS_NONE", i, chip->name); + } +} + +void selfcheck_eraseblocks(void **state) +{ + (void)state; /* unused */ + + size_t chip_index; + for (chip_index = 0; chip_index < flashchips_size - 1; chip_index++) { + size_t i, j, k; + const struct flashchip *chip = &flashchips[chip_index]; + unsigned int prev_eraseblock_count = chip->total_size * 1024; + + for (k = 0; k < NUM_ERASEFUNCTIONS; k++) { + unsigned int done = 0; + struct block_eraser eraser = chip->block_erasers[k]; + unsigned int curr_eraseblock_count = 0; + + for (i = 0; i < NUM_ERASEREGIONS; i++) { + /* Blocks with zero size are bugs in flashchips.c. */ + if (eraser.eraseblocks[i].count && !eraser.eraseblocks[i].size) { + fail_msg("Flash chip %s erase function %zu region %zu has size 0", + chip->name, k, i); + } + /* Blocks with zero count are bugs in flashchips.c. */ + if (!eraser.eraseblocks[i].count && eraser.eraseblocks[i].size) { + fail_msg("Flash chip %s erase function %zu region %zu has count 0", + chip->name, k, i); + } + done += eraser.eraseblocks[i].count * eraser.eraseblocks[i].size; + curr_eraseblock_count += eraser.eraseblocks[i].count; + } + /* Empty eraseblock definition with erase function. */ + if (!done && eraser.block_erase) { + printf("Strange: Empty eraseblock definition with non-empty erase function chip %s function %zu. Not an error.\n", + chip->name, k); + } + + if (!done) + continue; + if (done != chip->total_size * 1024) { + fail_msg( + "Flash chip %s erase function %zu region walking resulted in 0x%06x bytes total, expected 0x%06x bytes.", + chip->name, k, done, chip->total_size * 1024); + assert_true(false); + } + + if (!eraser.block_erase) + continue; + /* Check if there are identical erase functions for different + * layouts. That would imply "magic" erase functions. The + * easiest way to check this is with function pointers. + */ + for (j = k + 1; j < NUM_ERASEFUNCTIONS; j++) { + if (eraser.block_erase == chip->block_erasers[j].block_erase) { + fail_msg("Flash chip %s erase function %zu and %zu are identical.", + chip->name, k, j); + } + } + if (curr_eraseblock_count > prev_eraseblock_count) { + fail_msg("Flash chip %s erase function %zu is not in order", chip->name, k); + } + prev_eraseblock_count = curr_eraseblock_count; + } + } +} + +#if CONFIG_INTERNAL == 1 +void selfcheck_board_matches_table(void **state) +{ + (void)state; /* unused */ + + size_t i; + + assert_true(board_matches_size > 1); + assert_true(board_matches[board_matches_size - 1].vendor_name == NULL); + for (i = 0; i < board_matches_size - 1; i++) { + const struct board_match *b = &board_matches[i]; + assert_table(b->vendor_name, "board vendor_name is null", i, b->board_name); + assert_table(b->board_name, "board boad_name is null", i, b->board_name); + if ((!b->first_vendor || !b->first_device || !b->second_vendor || !b->second_device) + || ((!b->lb_vendor) ^ (!b->lb_part)) || (!b->max_rom_decode_parallel && !b->enable)) + fail_msg("Board enable for %s %s is misdefined.\n", b->vendor_name, b->board_name); + } +} + +#else + SKIP_TEST(selfcheck_board_matches_table) +#endif /* CONFIG_INTERNAL */ diff --git a/tests/tests.c b/tests/tests.c index fe70204..abbac64 100644 --- a/tests/tests.c +++ b/tests/tests.c @@ -381,6 +381,15 @@ }; ret |= cmocka_run_group_tests_name("helpers.c tests", helpers_tests, NULL, NULL);
+ const struct CMUnitTest selfcheck[] = { + cmocka_unit_test(selfcheck_programmer_table), + cmocka_unit_test(selfcheck_flashchips_table), + cmocka_unit_test(selfcheck_eraseblocks), + cmocka_unit_test(selfcheck_board_matches_table), + }; + ret |= cmocka_run_group_tests_name("selfcheck.c tests", selfcheck, + NULL, NULL); + const struct CMUnitTest flashrom_tests[] = { cmocka_unit_test(flashbuses_to_text_test_success), }; diff --git a/tests/tests.h b/tests/tests.h index bcca9e8..b36ac70 100644 --- a/tests/tests.h +++ b/tests/tests.h @@ -89,4 +89,10 @@ void full_chip_erase_with_wp_dummyflasher_test_success(void **state); void partial_chip_erase_with_wp_dummyflasher_test_success(void **state);
+/* selfcheck.c */ +void selfcheck_programmer_table(void **state); +void selfcheck_flashchips_table(void **state); +void selfcheck_eraseblocks(void **state); +void selfcheck_board_matches_table(void **state); + #endif /* TESTS_H */