blob: fe77c61d065d9fb8f68afd624ebdfacf137c0330 [file] [log] [blame]
#include "aos/util/status.h"
#include <filesystem>
#include "gmock/gmock.h"
#include "gtest/gtest.h"
#include "aos/realtime.h"
#include "aos/testing/path.h"
namespace aos::testing {
class ErrorTest : public ::testing::Test {
protected:
ErrorTest() {}
};
// Tests that we can construct an errored status in realtime code.
TEST_F(ErrorTest, RealtimeError) {
std::optional<Error> error;
{
aos::ScopedRealtime realtime;
error = Error::MakeError("Hello, World!");
}
const int line = __LINE__ - 2;
ASSERT_TRUE(error.has_value());
EXPECT_NE(0, error->code());
EXPECT_EQ(std::string("Hello, World!"), error->message());
ASSERT_TRUE(error->source_location().has_value());
EXPECT_EQ(
std::string("status_test.cc"),
std::filesystem::path(error->source_location()->file_name()).filename());
EXPECT_EQ(
std::string("virtual void "
"aos::testing::ErrorTest_RealtimeError_Test::TestBody()"),
error->source_location()->function_name());
EXPECT_EQ(line, error->source_location()->line());
EXPECT_LT(1, error->source_location()->column());
EXPECT_THAT(
error->ToString(),
::testing::HasSubstr(absl::StrFormat(
"status_test.cc:%d in virtual void "
"aos::testing::ErrorTest_RealtimeError_Test::TestBody(): Errored "
"with code of 1 and message: Hello, World!",
line)));
}
// Tests that the ResultExitCode() function will correctly transform a Result<>
// object into an exit code suitable for exiting a program.
TEST_F(ErrorTest, ExitCode) {
static_assert(0 == static_cast<int>(Error::StatusCode::kOk));
EXPECT_EQ(static_cast<int>(Error::StatusCode::kOk),
ResultExitCode(Result<void>{}));
EXPECT_EQ(static_cast<int>(Error::StatusCode::kError),
ResultExitCode(Error::MakeUnexpectedError("")));
}
// Malloc hooks don't work with asan/msan.
#if !__has_feature(address_sanitizer) && !__has_feature(memory_sanitizer)
// Tests that we do indeed malloc (and catch it) on an extra-long error message
// (this is mostly intended to ensure that the test setup is working correctly).
TEST(ErrorDeathTest, BlowsUpOnRealtimeAllocation) {
std::string message(" ", Error::kStaticMessageLength + 1);
EXPECT_DEATH(
{
aos::ScopedRealtime realtime;
aos::CheckRealtime();
Error foo = Error::MakeError(message);
},
"Malloced");
}
#endif
// Tests that we can use arbitrarily-sized string literals for error messages.
TEST_F(ErrorTest, StringLiteralError) {
std::optional<Error> error;
const char *message =
"Hellllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllll"
"llllllllllllllloooooooooooooooooooooooooooooooooooooooooooo, "
"World!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
"!!!!!!!!!!!!!!";
ASSERT_LT(Error::kStaticMessageLength, strlen(message));
{
aos::ScopedRealtime realtime;
error = Error::MakeStringLiteralError(message);
}
ASSERT_TRUE(error.has_value());
EXPECT_EQ(message, error->message());
ASSERT_TRUE(error->source_location().has_value());
EXPECT_EQ(
std::string("status_test.cc"),
std::filesystem::path(error->source_location()->file_name()).filename());
}
// Tests that the CheckExpected() call works as intended.
TEST(ErrorDeathTest, CheckExpected) {
tl::expected<int, Error> expected;
expected.emplace(971);
EXPECT_EQ(971, CheckExpected(expected))
<< "Should have gotten out the emplaced value on no error.";
expected = Error::MakeUnexpectedError("Hello, World!");
EXPECT_DEATH(CheckExpected(expected), "Hello, World!")
<< "An error message including the error string should have been printed "
"on death.";
EXPECT_DEATH(CheckExpected<void>(Error::MakeUnexpectedError("void expected")),
"void expected")
<< "A void expected should work with CheckExpected().";
}
} // namespace aos::testing