Allow 'expected errors' in tests for RDResult returns

* This fixes the issue that tests of out-of-bounds and error behaviour trigger
  debugbreaks. We don't apply this to RDCERR (currently) as it would generate
  more code overall and it's easier to convert any new deliberate test errors.
This commit is contained in:
baldurk
2024-10-04 10:31:12 +01:00
parent 354dc784a4
commit 5d0a85e8ca
5 changed files with 60 additions and 3 deletions
+29 -2
View File
@@ -49,17 +49,44 @@ struct RDResult
bool operator==(ResultCode result) const { return code == result; }
bool operator!=(ResultCode result) const { return code != result; }
operator ResultDetails() const;
#if ENABLED(ENABLE_UNIT_TESTS)
static bool testErrorExpected;
#endif
};
DECLARE_REFLECTION_STRUCT(RDResult);
#if ENABLED(ENABLE_UNIT_TESTS)
#define EXPECT_ERROR() RDResult::testErrorExpected = true;
#define PRINT_ERROR(...) \
if(RDResult::testErrorExpected) \
{ \
RDCLOG("Expected error: " __VA_ARGS__); \
RDResult::testErrorExpected = false; \
} \
else \
RDCERR(__VA_ARGS__);
#define DID_ERROR_HAPPEN() (RDResult::testErrorExpected == false)
#else
#define EXPECT_ERROR()
#define PRINT_ERROR RDCERR
#define DID_ERROR_HAPPEN() false
#endif
// helper macros since we often want to print the error message that gets returned.
// one helper returns immediately, the other sets a result and prints - to allow cleanup
#define RETURN_ERROR_RESULT_INTERNAL(code, msg, ...) \
do \
{ \
RDResult CONCAT(res, __LINE__)(code, StringFormat::Fmt(STRING_LITERAL(msg), __VA_ARGS__)); \
RDCERR("%s", CONCAT(res, __LINE__).message.c_str()); \
PRINT_ERROR("%s", CONCAT(res, __LINE__).message.c_str()); \
return CONCAT(res, __LINE__); \
} while(0)
@@ -67,7 +94,7 @@ DECLARE_REFLECTION_STRUCT(RDResult);
do \
{ \
res = RDResult(code, StringFormat::Fmt(STRING_LITERAL(msg), __VA_ARGS__)); \
RDCERR("%s", res.message.c_str()); \
PRINT_ERROR("%s", res.message.c_str()); \
} while(0)
#define RETURN_WARNING_RESULT_INTERNAL(code, msg, ...) \
@@ -25,6 +25,7 @@
#pragma once
#include "common/common.h"
#include "common/formatting.h"
namespace LLVMBC
{
@@ -166,10 +167,17 @@ public:
m_Bits += (alignedByteOffs - byteOffs);
}
bool IsErrored() { return m_Error != ResultCode::Succeeded; }
RDResult GetError() { return m_Error; }
private:
const byte *m_Bits, *m_Start, *m_End;
size_t m_Offset;
// result indicating if an error has been encountered and the stream is now invalid, with details
// of what happened
RDResult m_Error;
void Advance(size_t N)
{
m_Offset += N;
@@ -188,7 +196,7 @@ private:
{
if(BitOffset() + bitsToRead > BitLength())
{
RDCERR("Reading off end of bitstream");
SET_ERROR_RESULT(m_Error, ResultCode::InternalError, "Reading off end of bitstream");
// read 0s off the end of the stream.
// set any whole bytes to 0:
@@ -402,14 +402,19 @@ TEST_CASE("Check LLVM bitreader", "[llvm]")
uint32_t val1 = b.fixed<uint32_t>(17);
CHECK(val1 == 0x18040);
EXPECT_ERROR();
// second read is partially out of bounds, we should read all 0s
uint32_t val2 = b.fixed<uint32_t>(16);
CHECK(val2 == 0);
CHECK(DID_ERROR_HAPPEN());
// should be exactly at the end of the stream
CHECK(b.AtEndOfStream());
CHECK(b.ByteOffset() == sizeof(bits));
CHECK(b.BitOffset() == sizeof(bits) * 8);
CHECK(b.IsErrored());
}
SECTION("Check fixed encoding")
+4
View File
@@ -40,6 +40,10 @@
Threading::CriticalSection detailStringLock;
rdcarray<const rdcstr *> detailStrings;
#if ENABLED(ENABLE_UNIT_TESTS)
bool RDResult::testErrorExpected = false;
#endif
RDResult::operator ResultDetails() const
{
RDCCOMPILE_ASSERT(ResultCode(0) == ResultCode::Succeeded,
+13
View File
@@ -87,9 +87,12 @@ TEST_CASE("Test basic stream I/O operations", "[streamio]")
CHECK_FALSE(reader.IsErrored());
CHECK(reader.AtEnd());
EXPECT_ERROR();
// reading off the end should read 0s and move to error state
reader.Read(test);
CHECK(test == 0);
CHECK(DID_ERROR_HAPPEN());
CHECK(reader.IsErrored());
};
@@ -98,9 +101,11 @@ TEST_CASE("Test stream I/O with invalid/broken outputs", "[streamio]")
{
SECTION("NULL file writer")
{
EXPECT_ERROR();
StreamWriter writer((FILE *)NULL, Ownership::Stream);
CHECK(writer.IsErrored());
CHECK(DID_ERROR_HAPPEN());
uint32_t test = 5;
writer.Write(test);
@@ -110,9 +115,11 @@ TEST_CASE("Test stream I/O with invalid/broken outputs", "[streamio]")
SECTION("NULL socket writer")
{
EXPECT_ERROR();
StreamWriter writer((Network::Socket *)NULL, Ownership::Stream);
CHECK(writer.IsErrored());
CHECK(DID_ERROR_HAPPEN());
uint32_t test = 5;
writer.Write(test);
@@ -122,9 +129,11 @@ TEST_CASE("Test stream I/O with invalid/broken outputs", "[streamio]")
SECTION("NULL file reader")
{
EXPECT_ERROR();
StreamReader reader((FILE *)NULL, 0, Ownership::Stream);
CHECK(reader.IsErrored());
CHECK(DID_ERROR_HAPPEN());
uint32_t test = 5;
reader.Read(test);
@@ -134,9 +143,11 @@ TEST_CASE("Test stream I/O with invalid/broken outputs", "[streamio]")
SECTION("NULL file reader")
{
EXPECT_ERROR();
StreamReader reader((FILE *)NULL);
CHECK(reader.IsErrored());
CHECK(DID_ERROR_HAPPEN());
uint32_t test = 5;
reader.Read(test);
@@ -146,9 +157,11 @@ TEST_CASE("Test stream I/O with invalid/broken outputs", "[streamio]")
SECTION("NULL socket reader")
{
EXPECT_ERROR();
StreamReader reader((Network::Socket *)NULL, Ownership::Stream);
CHECK(reader.IsErrored());
CHECK(DID_ERROR_HAPPEN());
uint32_t test = 5;
reader.Read(test);