James Kuszmaul | 847927d | 2024-05-23 15:33:18 -0700 | [diff] [blame] | 1 | #include "aos/util/status.h" |
| 2 | |
| 3 | #include <filesystem> |
| 4 | |
| 5 | #include "gmock/gmock.h" |
| 6 | #include "gtest/gtest.h" |
| 7 | |
| 8 | #include "aos/realtime.h" |
| 9 | #include "aos/testing/path.h" |
| 10 | |
| 11 | DECLARE_bool(die_on_malloc); |
| 12 | |
| 13 | namespace aos::testing { |
James Kuszmaul | 053d42a | 2024-05-30 16:46:08 -0700 | [diff] [blame^] | 14 | class ErrorTest : public ::testing::Test { |
James Kuszmaul | 847927d | 2024-05-23 15:33:18 -0700 | [diff] [blame] | 15 | protected: |
James Kuszmaul | 053d42a | 2024-05-30 16:46:08 -0700 | [diff] [blame^] | 16 | ErrorTest() {} |
James Kuszmaul | 847927d | 2024-05-23 15:33:18 -0700 | [diff] [blame] | 17 | }; |
| 18 | |
James Kuszmaul | 847927d | 2024-05-23 15:33:18 -0700 | [diff] [blame] | 19 | // Tests that we can construct an errored status in realtime code. |
James Kuszmaul | 053d42a | 2024-05-30 16:46:08 -0700 | [diff] [blame^] | 20 | TEST_F(ErrorTest, RealtimeError) { |
| 21 | std::optional<Error> error; |
James Kuszmaul | 847927d | 2024-05-23 15:33:18 -0700 | [diff] [blame] | 22 | { |
| 23 | aos::ScopedRealtime realtime; |
James Kuszmaul | 053d42a | 2024-05-30 16:46:08 -0700 | [diff] [blame^] | 24 | error = Error::MakeError("Hello, World!"); |
James Kuszmaul | 847927d | 2024-05-23 15:33:18 -0700 | [diff] [blame] | 25 | } |
| 26 | const int line = __LINE__ - 2; |
| 27 | ASSERT_TRUE(error.has_value()); |
James Kuszmaul | 847927d | 2024-05-23 15:33:18 -0700 | [diff] [blame] | 28 | EXPECT_NE(0, error->code()); |
| 29 | EXPECT_EQ(std::string("Hello, World!"), error->message()); |
| 30 | ASSERT_TRUE(error->source_location().has_value()); |
| 31 | EXPECT_EQ( |
| 32 | std::string("status_test.cc"), |
| 33 | std::filesystem::path(error->source_location()->file_name()).filename()); |
| 34 | EXPECT_EQ( |
| 35 | std::string("virtual void " |
James Kuszmaul | 053d42a | 2024-05-30 16:46:08 -0700 | [diff] [blame^] | 36 | "aos::testing::ErrorTest_RealtimeError_Test::TestBody()"), |
James Kuszmaul | 847927d | 2024-05-23 15:33:18 -0700 | [diff] [blame] | 37 | error->source_location()->function_name()); |
| 38 | EXPECT_EQ(line, error->source_location()->line()); |
| 39 | EXPECT_LT(1, error->source_location()->column()); |
| 40 | EXPECT_THAT( |
| 41 | error->ToString(), |
| 42 | ::testing::HasSubstr(absl::StrFormat( |
| 43 | "status_test.cc:%d in virtual void " |
James Kuszmaul | 053d42a | 2024-05-30 16:46:08 -0700 | [diff] [blame^] | 44 | "aos::testing::ErrorTest_RealtimeError_Test::TestBody(): Errored " |
| 45 | "with code of 1 and message: Hello, World!", |
James Kuszmaul | 847927d | 2024-05-23 15:33:18 -0700 | [diff] [blame] | 46 | line))); |
| 47 | } |
| 48 | |
James Kuszmaul | 053d42a | 2024-05-30 16:46:08 -0700 | [diff] [blame^] | 49 | // Tests that the ResultExitCode() function will correctly transform a Result<> |
| 50 | // object into an exit code suitable for exiting a program. |
| 51 | TEST_F(ErrorTest, ExitCode) { |
| 52 | static_assert(0 == static_cast<int>(Error::StatusCode::kOk)); |
| 53 | EXPECT_EQ(static_cast<int>(Error::StatusCode::kOk), |
| 54 | ResultExitCode(Result<void>{})); |
| 55 | EXPECT_EQ(static_cast<int>(Error::StatusCode::kError), |
| 56 | ResultExitCode(Error::MakeUnexpectedError(""))); |
| 57 | } |
| 58 | |
James Kuszmaul | 0494202 | 2024-05-29 10:57:56 -0700 | [diff] [blame] | 59 | // Malloc hooks don't work with asan/msan. |
| 60 | #if !__has_feature(address_sanitizer) && !__has_feature(memory_sanitizer) |
James Kuszmaul | 847927d | 2024-05-23 15:33:18 -0700 | [diff] [blame] | 61 | // Tests that we do indeed malloc (and catch it) on an extra-long error message |
| 62 | // (this is mostly intended to ensure that the test setup is working correctly). |
James Kuszmaul | 053d42a | 2024-05-30 16:46:08 -0700 | [diff] [blame^] | 63 | TEST(ErrorDeathTest, BlowsUpOnRealtimeAllocation) { |
| 64 | std::string message(" ", Error::kStaticMessageLength + 1); |
James Kuszmaul | 847927d | 2024-05-23 15:33:18 -0700 | [diff] [blame] | 65 | EXPECT_DEATH( |
| 66 | { |
| 67 | aos::ScopedRealtime realtime; |
| 68 | aos::CheckRealtime(); |
James Kuszmaul | 053d42a | 2024-05-30 16:46:08 -0700 | [diff] [blame^] | 69 | Error foo = Error::MakeError(message); |
James Kuszmaul | 847927d | 2024-05-23 15:33:18 -0700 | [diff] [blame] | 70 | }, |
| 71 | "Malloced"); |
| 72 | } |
| 73 | |
James Kuszmaul | 0494202 | 2024-05-29 10:57:56 -0700 | [diff] [blame] | 74 | #endif |
| 75 | |
James Kuszmaul | 847927d | 2024-05-23 15:33:18 -0700 | [diff] [blame] | 76 | // Tests that we can use arbitrarily-sized string literals for error messages. |
James Kuszmaul | 053d42a | 2024-05-30 16:46:08 -0700 | [diff] [blame^] | 77 | TEST_F(ErrorTest, StringLiteralError) { |
| 78 | std::optional<Error> error; |
James Kuszmaul | 847927d | 2024-05-23 15:33:18 -0700 | [diff] [blame] | 79 | const char *message = |
| 80 | "Hellllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllll" |
| 81 | "llllllllllllllloooooooooooooooooooooooooooooooooooooooooooo, " |
| 82 | "World!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" |
| 83 | "!!!!!!!!!!!!!!"; |
James Kuszmaul | 053d42a | 2024-05-30 16:46:08 -0700 | [diff] [blame^] | 84 | ASSERT_LT(Error::kStaticMessageLength, strlen(message)); |
James Kuszmaul | 847927d | 2024-05-23 15:33:18 -0700 | [diff] [blame] | 85 | { |
| 86 | aos::ScopedRealtime realtime; |
James Kuszmaul | 053d42a | 2024-05-30 16:46:08 -0700 | [diff] [blame^] | 87 | error = Error::MakeStringLiteralError(message); |
James Kuszmaul | 847927d | 2024-05-23 15:33:18 -0700 | [diff] [blame] | 88 | } |
| 89 | ASSERT_TRUE(error.has_value()); |
James Kuszmaul | 847927d | 2024-05-23 15:33:18 -0700 | [diff] [blame] | 90 | EXPECT_EQ(message, error->message()); |
| 91 | ASSERT_TRUE(error->source_location().has_value()); |
| 92 | EXPECT_EQ( |
| 93 | std::string("status_test.cc"), |
| 94 | std::filesystem::path(error->source_location()->file_name()).filename()); |
| 95 | } |
| 96 | |
| 97 | // Tests that the CheckExpected() call works as intended. |
James Kuszmaul | 053d42a | 2024-05-30 16:46:08 -0700 | [diff] [blame^] | 98 | TEST(ErrorDeathTest, CheckExpected) { |
| 99 | tl::expected<int, Error> expected; |
James Kuszmaul | 847927d | 2024-05-23 15:33:18 -0700 | [diff] [blame] | 100 | expected.emplace(971); |
| 101 | EXPECT_EQ(971, CheckExpected(expected)) |
| 102 | << "Should have gotten out the emplaced value on no error."; |
James Kuszmaul | 053d42a | 2024-05-30 16:46:08 -0700 | [diff] [blame^] | 103 | expected = Error::MakeUnexpectedError("Hello, World!"); |
James Kuszmaul | 847927d | 2024-05-23 15:33:18 -0700 | [diff] [blame] | 104 | EXPECT_DEATH(CheckExpected(expected), "Hello, World!") |
| 105 | << "An error message including the error string should have been printed " |
| 106 | "on death."; |
James Kuszmaul | 053d42a | 2024-05-30 16:46:08 -0700 | [diff] [blame^] | 107 | EXPECT_DEATH(CheckExpected<void>(Error::MakeUnexpectedError("void expected")), |
James Kuszmaul | 847927d | 2024-05-23 15:33:18 -0700 | [diff] [blame] | 108 | "void expected") |
| 109 | << "A void expected should work with CheckExpected()."; |
| 110 | } |
| 111 | } // namespace aos::testing |