/* Copyright 2020 The Chromium OS Authors. All rights reserved. * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. * * Tests for host flashrom utilities. */ /* For strdup */ #define _POSIX_C_SOURCE 200809L #include #include #include #include #include #include #include #include "2common.h" #include "2return_codes.h" #include "host_misc.h" #include "flashrom.h" #include "subprocess.h" #include "test_common.h" #define MOCK_TMPFILE_NAME "/tmp/vb2_unittest" #define MOCK_ROM_CONTENTS "bloop123" static bool flashrom_mock_success = true; static enum { FLASHROM_NONE, FLASHROM_READ, FLASHROM_WRITE } captured_operation; static enum { FLASHROM_VERIFY_UNSPECIFIED, FLASHROM_VERIFY_FAST, } captured_verify; static const char *captured_op_filename; static const char *captured_region_param; static const char *captured_programmer; static uint8_t *captured_rom_contents; static uint32_t captured_rom_size; /* Mocked mkstemp for tests. */ int mkstemp(char *template_name) { strncpy(template_name, MOCK_TMPFILE_NAME, strlen(template_name)); return open(template_name, O_RDWR | O_CREAT | O_TRUNC, 0666); } /* Mocked subprocess_run for tests. */ int subprocess_run(const char *const argv[], struct subprocess_target *input, struct subprocess_target *output, struct subprocess_target *error) { int argc; int opt; int rv; /* getopt_long wants an int instead of an enum, bummer... */ int captured_verify_int = FLASHROM_VERIFY_UNSPECIFIED; struct option long_opts[] = { { .name = "noverify-all", .has_arg = no_argument, .flag = &captured_verify_int, .val = FLASHROM_VERIFY_FAST, }, }; /* Reset static variables to their defaults. */ captured_operation = FLASHROM_NONE; captured_operation = FLASHROM_VERIFY_UNSPECIFIED; captured_op_filename = NULL; captured_region_param = NULL; captured_programmer = NULL; captured_rom_contents = NULL; captured_rom_size = 0; optind = 0; /* Count the number of arguments, a required formalism for getopt. */ for (argc = 0; argv[argc]; argc++) continue; /* We only understand the subset of arguments used by the wrapper library. If it's updated to support more modes of operation, this unit test code should be updated too. */ while ((opt = getopt_long(argc, (char *const *)argv, ":p:r:w:i:", long_opts, NULL)) != -1) { /* Always consume the next argument if it does not start with a dash. We have to muck with getopt's global variables to make this happen. */ if (opt == ':' && argv[optind] && argv[optind][0] != '-') { optarg = strdup(argv[optind]); optind++; opt = optopt; } else if (optarg && optarg[0] == '-') { optarg = NULL; optind--; } else if (optarg) { optarg = strdup(optarg); } switch (opt) { case 'p': captured_programmer = optarg; break; case 'r': captured_operation = FLASHROM_READ; captured_op_filename = optarg; break; case 'w': captured_operation = FLASHROM_WRITE; captured_op_filename = optarg; break; case 'i': captured_region_param = optarg; break; case 0: /* long option */ break; default: return 1; } } if (optind != argc) { /* Extra arguments we don't understand. */ return 1; } rv = !flashrom_mock_success; captured_verify = captured_verify_int; if (captured_operation == FLASHROM_READ) { /* Write the mocked string we read from the ROM. */ rv |= vb2_write_file(MOCK_TMPFILE_NAME, MOCK_ROM_CONTENTS, strlen(MOCK_ROM_CONTENTS)); } else if (captured_operation == FLASHROM_WRITE) { /* Capture the buffer contents we wrote to the ROM. */ rv |= vb2_read_file(MOCK_TMPFILE_NAME, &captured_rom_contents, &captured_rom_size); } return rv; } static void test_read_whole_chip(void) { uint8_t *buf; uint32_t buf_sz; TEST_SUCC(flashrom_read("someprog", NULL, &buf, &buf_sz), "Flashrom read succeeds"); TEST_STR_EQ(captured_programmer, "someprog", "Using specified programmer"); TEST_EQ(captured_operation, FLASHROM_READ, "Doing a read operation"); TEST_EQ(captured_verify, FLASHROM_VERIFY_UNSPECIFIED, "Verification not enabled"); TEST_STR_EQ(captured_op_filename, MOCK_TMPFILE_NAME, "Reading to correct file"); TEST_PTR_EQ(captured_region_param, NULL, "Not operating on a region"); TEST_EQ(buf_sz, strlen(MOCK_ROM_CONTENTS), "Contents correct size"); TEST_SUCC(memcmp(buf, MOCK_ROM_CONTENTS, buf_sz), "Buffer has correct contents"); free(buf); } static void test_read_region(void) { uint8_t *buf; uint32_t buf_sz; TEST_SUCC(flashrom_read("someprog", "SOME_REGION", &buf, &buf_sz), "Flashrom read succeeds"); TEST_STR_EQ(captured_programmer, "someprog", "Using specified programmer"); TEST_EQ(captured_operation, FLASHROM_READ, "Doing a read operation"); TEST_EQ(captured_verify, FLASHROM_VERIFY_UNSPECIFIED, "Verification not enabled"); TEST_PTR_EQ(captured_op_filename, NULL, "Not doing a read of the whole ROM"); TEST_STR_EQ(captured_region_param, "SOME_REGION:" MOCK_TMPFILE_NAME, "Reading to correct file and from correct region"); TEST_EQ(buf_sz, strlen(MOCK_ROM_CONTENTS), "Contents correct size"); TEST_SUCC(memcmp(buf, MOCK_ROM_CONTENTS, buf_sz), "Buffer has correct contents"); free(buf); } static void test_read_failure(void) { uint8_t *buf; uint32_t buf_sz; flashrom_mock_success = false; TEST_NEQ(flashrom_read("someprog", "SOME_REGION", &buf, &buf_sz), VB2_SUCCESS, "Flashrom read fails"); flashrom_mock_success = true; } static void test_write_whole_chip(void) { uint8_t buf[sizeof(MOCK_ROM_CONTENTS) - 1]; memcpy(buf, MOCK_ROM_CONTENTS, sizeof(buf)); TEST_SUCC(flashrom_write("someprog", NULL, buf, sizeof(buf)), "Flashrom write succeeds"); TEST_STR_EQ(captured_programmer, "someprog", "Using specified programmer"); TEST_EQ(captured_operation, FLASHROM_WRITE, "Doing a write operation"); TEST_EQ(captured_verify, FLASHROM_VERIFY_FAST, "Fast verification enabled"); TEST_STR_EQ(captured_op_filename, MOCK_TMPFILE_NAME, "Writing to correct file"); TEST_PTR_EQ(captured_region_param, NULL, "Not operating on a region"); TEST_EQ(captured_rom_size, strlen(MOCK_ROM_CONTENTS), "Contents correct size"); TEST_SUCC(memcmp(captured_rom_contents, MOCK_ROM_CONTENTS, captured_rom_size), "Buffer has correct contents"); } static void test_write_region(void) { uint8_t buf[sizeof(MOCK_ROM_CONTENTS) - 1]; memcpy(buf, MOCK_ROM_CONTENTS, sizeof(buf)); TEST_SUCC(flashrom_write("someprog", "SOME_REGION", buf, sizeof(buf)), "Flashrom write succeeds"); TEST_STR_EQ(captured_programmer, "someprog", "Using specified programmer"); TEST_EQ(captured_operation, FLASHROM_WRITE, "Doing a write operation"); TEST_EQ(captured_verify, FLASHROM_VERIFY_FAST, "Fast verification enabled"); TEST_PTR_EQ(captured_op_filename, NULL, "Not doing a write of the whole ROM"); TEST_STR_EQ(captured_region_param, "SOME_REGION:" MOCK_TMPFILE_NAME, "Writing to correct file and from correct region"); TEST_EQ(captured_rom_size, strlen(MOCK_ROM_CONTENTS), "Contents correct size"); TEST_SUCC(memcmp(captured_rom_contents, MOCK_ROM_CONTENTS, captured_rom_size), "Buffer has correct contents"); } static void test_write_failure(void) { uint8_t buf[20] = { 0 }; flashrom_mock_success = false; TEST_NEQ(flashrom_write("someprog", "SOME_REGION", buf, sizeof(buf)), VB2_SUCCESS, "Flashrom write fails"); flashrom_mock_success = true; } int main(int argc, char *argv[]) { test_read_whole_chip(); test_read_region(); test_read_failure(); test_write_whole_chip(); test_write_region(); test_write_failure(); return gTestSuccess ? 0 : 255; }