blob: 140f8296f73d806deb1cd74327f4575f349ca427 [file]
// Copyright 2026 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/boot-shim/boot-properties.h"
#include <lib/linux-boot-config/linux-boot-config.h>
#include <utility>
#include <vector>
#include <zxtest/zxtest.h>
namespace {
TEST(BootPropertiesTest, Empty) {
boot_shim::BootProperties props("");
EXPECT_NOT_OK(props.GetProperty("foo"));
}
TEST(BootPropertiesTest, CmdlineSimple) {
boot_shim::BootProperties props("foo=bar baz=qux");
auto res = props.GetProperty("foo");
ASSERT_OK(res);
EXPECT_EQ(res.value(), "bar");
auto res2 = props.GetProperty("baz");
ASSERT_OK(res2);
EXPECT_EQ(res2.value(), "qux");
EXPECT_NOT_OK(props.GetProperty("missing"));
}
TEST(BootPropertiesTest, CmdlineFlag) {
boot_shim::BootProperties props("enable_feature other=1");
auto res = props.GetProperty("enable_feature");
ASSERT_OK(res);
EXPECT_TRUE(res.value().empty());
}
TEST(BootPropertiesTest, CmdlineQuotes) {
boot_shim::BootProperties props("key1=\"quoted_val\" key2=\"another_val\"");
auto res1 = props.GetProperty("key1");
ASSERT_OK(res1);
EXPECT_EQ(res1.value(), "quoted_val");
auto res2 = props.GetProperty("key2");
ASSERT_OK(res2);
EXPECT_EQ(res2.value(), "another_val");
}
TEST(BootPropertiesTest, CmdlinePrefixCollision) {
boot_shim::BootProperties props("prefix_other=wrong prefix=correct");
auto res = props.GetProperty("prefix");
ASSERT_OK(res);
EXPECT_EQ(res.value(), "correct");
}
TEST(BootPropertiesTest, CmdlineLastWins) {
boot_shim::BootProperties props("key=first key=second");
auto res = props.GetProperty("key");
ASSERT_OK(res);
EXPECT_EQ(res.value(), "second");
}
TEST(BootPropertiesTest, BootconfigLookup) {
constexpr std::string_view kBootconfigData =
"kernel.param = foo\n"
"driver.option = \"value1\"\n"
"system.mode = normal\n";
linux_boot_config::LinuxBootConfig bootconfig(kBootconfigData);
boot_shim::BootProperties props("system.mode=recovery", bootconfig);
// Bootconfig takes precedence over cmdline.
auto mode = props.GetProperty("system.mode");
ASSERT_OK(mode);
EXPECT_EQ(mode.value(), "normal");
auto option = props.GetProperty("driver.option");
ASSERT_OK(option);
EXPECT_EQ(option.value(), "value1");
auto param = props.GetProperty("kernel.param");
ASSERT_OK(param);
EXPECT_EQ(param.value(), "foo");
}
TEST(BootPropertiesTest, BootconfigFallbackToCmdline) {
constexpr std::string_view kBootconfigData = "kernel.param = foo\n";
linux_boot_config::LinuxBootConfig bootconfig(kBootconfigData);
boot_shim::BootProperties props("fallback_key=cmdline_value", bootconfig);
auto res = props.GetProperty("fallback_key");
ASSERT_OK(res);
EXPECT_EQ(res.value(), "cmdline_value");
}
TEST(BootPropertiesTest, BootconfigHierarchical) {
constexpr std::string_view kBootconfigData =
"system {\n"
" name = target\n"
" version = \"2.0\"\n"
"}\n";
linux_boot_config::LinuxBootConfig bootconfig(kBootconfigData);
boot_shim::BootProperties props("", bootconfig);
auto name = props.GetProperty("system.name");
ASSERT_OK(name);
EXPECT_EQ(name.value(), "target");
auto ver = props.GetProperty("system.version");
ASSERT_OK(ver);
EXPECT_EQ(ver.value(), "2.0");
}
TEST(BootPropertiesTest, BootconfigLastWins) {
constexpr std::string_view kBootconfigData =
"test.key = first\n"
"test.key = second\n";
linux_boot_config::LinuxBootConfig bootconfig(kBootconfigData);
boot_shim::BootProperties props("", bootconfig);
auto res = props.GetProperty("test.key");
ASSERT_OK(res);
EXPECT_EQ(res.value(), "second");
}
TEST(BootPropertiesTest, BootconfigArrayReturnsFirst) {
constexpr std::string_view kBootconfigData = "test.key = \"first\", \"second\", \"third\"\n";
linux_boot_config::LinuxBootConfig bootconfig(kBootconfigData);
boot_shim::BootProperties props("", bootconfig);
auto res = props.GetProperty("test.key");
ASSERT_OK(res);
EXPECT_EQ(res.value(), "first");
}
TEST(BootPropertiesTest, BootconfigAppendDoesNotOverwriteBase) {
constexpr std::string_view kBootconfigData =
"test.key = base\n"
"test.key += appended\n";
linux_boot_config::LinuxBootConfig bootconfig(kBootconfigData);
boot_shim::BootProperties props("", bootconfig);
auto res = props.GetProperty("test.key");
ASSERT_OK(res);
EXPECT_EQ(res.value(), "base");
}
TEST(BootPropertiesTest, BootconfigOverrideOverwritesBase) {
constexpr std::string_view kBootconfigData =
"test.key = base\n"
"test.key := overridden\n";
linux_boot_config::LinuxBootConfig bootconfig(kBootconfigData);
boot_shim::BootProperties props("", bootconfig);
auto res = props.GetProperty("test.key");
ASSERT_OK(res);
EXPECT_EQ(res.value(), "overridden");
}
TEST(BootPropertiesTest, EnumeratePropertyBootconfig) {
constexpr std::string_view kBootconfigData = "test.key = \"alpha\", \"beta\"\n";
linux_boot_config::LinuxBootConfig bootconfig(kBootconfigData);
boot_shim::BootProperties props("", bootconfig);
std::vector<std::pair<std::string_view, linux_boot_config::Value::Action>> visited;
props.EnumerateProperty("test.key",
[&](std::string_view val, linux_boot_config::Value::Action act) {
visited.emplace_back(val, act);
});
ASSERT_EQ(visited.size(), 2);
EXPECT_EQ(visited[0].first, "alpha");
EXPECT_EQ(visited[0].second, linux_boot_config::Value::Action::kDefine);
EXPECT_EQ(visited[1].first, "beta");
EXPECT_EQ(visited[1].second, linux_boot_config::Value::Action::kAppend);
}
TEST(BootPropertiesTest, EnumeratePropertyCmdline) {
boot_shim::BootProperties props("test.key=cmdline_val");
std::vector<std::pair<std::string_view, linux_boot_config::Value::Action>> visited;
props.EnumerateProperty("test.key",
[&](std::string_view val, linux_boot_config::Value::Action act) {
visited.emplace_back(val, act);
});
ASSERT_EQ(visited.size(), 1);
EXPECT_EQ(visited[0].first, "cmdline_val");
EXPECT_EQ(visited[0].second, linux_boot_config::Value::Action::kDefine);
}
TEST(BootPropertiesTest, EnumeratePropertyBootconfigFallback) {
constexpr std::string_view kBootconfigData = "other.key = other_val\n";
linux_boot_config::LinuxBootConfig bootconfig(kBootconfigData);
boot_shim::BootProperties props("test.key=cmdline_fallback", bootconfig);
std::vector<std::pair<std::string_view, linux_boot_config::Value::Action>> visited;
props.EnumerateProperty("test.key",
[&](std::string_view val, linux_boot_config::Value::Action act) {
visited.emplace_back(val, act);
});
ASSERT_EQ(visited.size(), 1);
EXPECT_EQ(visited[0].first, "cmdline_fallback");
EXPECT_EQ(visited[0].second, linux_boot_config::Value::Action::kDefine);
}
} // namespace