blob: b86213e43092924204364efd260662c1e6079137 [file] [log] [blame] [edit]
// Copyright 2020 The Fuchsia Authors
//
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file or at
// https://opensource.org/licenses/MIT
#include <lib/unittest/unittest.h>
#include <lib/zbitl/view.h>
#include <ktl/span.h>
#include "tests.h"
// zbitl is primarily tested by its host/userland unit tests.
// This serves to test some basic cases in the kernel and phys
// environments specifically, mostly just to make sure it compiles.
#define ASSERT_IS_OK(result) ASSERT_TRUE(result.is_ok())
namespace {
// `zbi --output=$OUTPUT_ZBI; hexdump -v -e '1/1 "\\x%02x"' $OUTPUT_ZBI`.
alignas(ZBI_ALIGNMENT) constexpr char kEmptyZbi[] =
"\x42\x4f\x4f\x54\x00\x00\x00\x00\xe6\xf7\x8c\x86\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00"
"\x00\x29\x17\x78\xb5\xd6\xe8\x87\x4a";
// ```
// zbi --output=$OUTPUT_ZBI --type CMDLINE --entry "hello world"
// hexdump -v -e '1/1 "\\x%02x"' $OUTPUT_ZBI
// ```
alignas(ZBI_ALIGNMENT) constexpr char kSimpleZbi[] =
"\x42\x4f\x4f\x54\x30\x00\x00\x00\xe6\xf7\x8c\x86\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00"
"\x00\x29\x17\x78\xb5\xd6\xe8\x87\x4a\x43\x4d\x44\x4c\x0c\x00\x00\x00\x00\x00\x00\x00\x00\x00"
"\x03\x00\x00\x00\x00\x00\x00\x00\x00\x00\x29\x17\x78\xb5\x77\xa5\x78\x81\x68\x65\x6c\x6c\x6f"
"\x20\x77\x6f\x72\x6c\x64\x00\x00\x00\x00\x00";
// The above, but with a payload byte changed.
alignas(ZBI_ALIGNMENT) constexpr char kBadCrcZbi[] =
"\x42\x4f\x4f\x54\x30\x00\x00\x00\xe6\xf7\x8c\x86\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00"
"\x00\x29\x17\x78\xb5\xd6\xe8\x87\x4a\x43\x4d\x44\x4c\x0c\x00\x00\x00\x00\x00\x00\x00\x00\x00"
"\x03\x00\x00\x00\x00\x00\x00\x00\x00\x00\x29\x17\x78\xb5\x77\xa5\x78\x81\x00\x65\x6c\x6c\x6f"
"\x20\x77\x6f\x72\x6c\x64\x00\x00\x00\x00\x00";
constexpr char kHelloWorld[] = "hello world";
bool EmptyZbiTest() {
BEGIN_TEST;
zbitl::View zbi(ktl::span<const char>{kEmptyZbi, sizeof(kEmptyZbi)});
ASSERT_IS_OK(zbi.container_header());
for (auto [header, payload] : zbi) {
EXPECT_EQ(header->type, header->type);
EXPECT_TRUE(false, "should not be reached");
}
ASSERT_IS_OK(zbi.take_error());
END_TEST;
}
bool SimpleZbiTest() {
BEGIN_TEST;
zbitl::View zbi(ktl::span<const char>{kSimpleZbi, sizeof(kSimpleZbi)});
ASSERT_IS_OK(zbi.container_header());
size_t num_items = 0;
for (auto [header, payload] : zbi) {
EXPECT_EQ(static_cast<uint32_t>(ZBI_TYPE_CMDLINE), header->type);
switch (num_items++) {
case 0:
ASSERT_EQ(sizeof(kHelloWorld), payload.size());
EXPECT_EQ(0, memcmp(kHelloWorld, payload.data(), payload.size()));
break;
}
EXPECT_TRUE(header->flags & ZBI_FLAG_VERSION);
}
EXPECT_EQ(1u, num_items);
ASSERT_IS_OK(zbi.take_error());
END_TEST;
}
bool BadCrcZbiTest() {
BEGIN_TEST;
zbitl::View<ktl::span<const char>, zbitl::Checking::kCrc> zbi({kBadCrcZbi, sizeof(kBadCrcZbi)});
ASSERT_IS_OK(zbi.container_header());
for (auto [header, payload] : zbi) {
EXPECT_EQ(header->type, header->type);
EXPECT_TRUE(false, "should not be reached");
}
auto error = zbi.take_error();
ASSERT_TRUE(error.is_error());
// The error should not be storage-related.
EXPECT_FALSE(error.error_value().storage_error);
END_TEST;
}
bool MutationTest() {
BEGIN_TEST;
alignas(ZBI_ALIGNMENT) char contents[sizeof(kSimpleZbi)];
memcpy(contents, kSimpleZbi, sizeof(contents));
// Storage type is mutable.
zbitl::View zbi(ktl::span<char>{contents, sizeof(contents)});
ASSERT_IS_OK(zbi.container_header());
size_t num_items = 0;
for (auto it = zbi.begin(); it != zbi.end(); ++it) {
auto [header, payload] = *it;
EXPECT_EQ(static_cast<uint32_t>(ZBI_TYPE_CMDLINE), header->type);
switch (num_items++) {
case 0:
ASSERT_EQ(sizeof(kHelloWorld), payload.size());
EXPECT_EQ(0, memcmp(kHelloWorld, payload.data(), payload.size()));
// GCC's -Wmissing-field-initializers is buggy: it should allow
// designated initializers without all fields, but doesn't (in C++?).
zbi_header_t discard{};
discard.type = ZBI_TYPE_DISCARD;
ASSERT_TRUE(zbi.EditHeader(it, discard).is_ok());
break;
}
EXPECT_TRUE(header->flags & ZBI_FLAG_VERSION);
}
EXPECT_EQ(1u, num_items);
num_items = 0;
for (auto [header, payload] : zbi) {
EXPECT_EQ(static_cast<uint32_t>(ZBI_TYPE_DISCARD), header->type);
switch (num_items++) {
case 0:
ASSERT_EQ(sizeof(kHelloWorld), payload.size());
EXPECT_EQ(0, memcmp(kHelloWorld, payload.data(), payload.size()));
break;
}
EXPECT_TRUE(header->flags & ZBI_FLAG_VERSION);
}
EXPECT_EQ(1u, num_items);
ASSERT_IS_OK(zbi.take_error());
END_TEST;
}
} // namespace
UNITTEST_START_TESTCASE(zbitl_tests)
UNITTEST("empty", EmptyZbiTest)
UNITTEST("simple", SimpleZbiTest)
UNITTEST("bad CRC", BadCrcZbiTest)
UNITTEST("mutation", MutationTest)
UNITTEST_END_TESTCASE(zbitl_tests, "zbitl", "Tests of ZBI template library")