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