blob: 9187e758ebc452eba6a40ed323cde3e3a613a157 [file] [log] [blame]
/* 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 <fcntl.h>
#include <getopt.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#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 = "fast-verify",
.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;
}