forked from OSchip/llvm-project
[flang] Unittests for runtime terminator
Create test fixture for runtime tests which enables verification of failure cases. Test some runtime IO APIs for failure cases. Support testing efforts in D98303. Expand on effort discussed in D98601. Reviewed By: awarzynski Differential Revision: https://reviews.llvm.org/D98652
This commit is contained in:
parent
1a6ab32f33
commit
168b206cd8
|
@ -1,5 +1,7 @@
|
|||
add_flang_unittest(FlangRuntimeTests
|
||||
CharacterTest.cpp
|
||||
RuntimeCrashTest.cpp
|
||||
CrashHandlerFixture.cpp
|
||||
)
|
||||
|
||||
target_link_libraries(FlangRuntimeTests
|
||||
|
|
|
@ -0,0 +1,34 @@
|
|||
//===-- flang/unittests/RuntimeGTest/CrashHandlerFixture.cpp ----*- C++ -*-===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
#include "CrashHandlerFixture.h"
|
||||
#include "../../runtime/terminator.h"
|
||||
#include <cstdarg>
|
||||
#include <cstdlib>
|
||||
|
||||
// Replaces Fortran runtime's crash handler so we can verify the crash message
|
||||
[[noreturn]] static void CatchCrash(
|
||||
const char *sourceFile, int sourceLine, const char *message, va_list &ap) {
|
||||
char buffer[1000];
|
||||
std::vsnprintf(buffer, sizeof buffer, message, ap);
|
||||
va_end(ap);
|
||||
llvm::errs()
|
||||
<< "Test "
|
||||
<< ::testing::UnitTest::GetInstance()->current_test_info()->name()
|
||||
<< " crashed in file "
|
||||
<< (sourceFile ? sourceFile : "unknown source file") << '(' << sourceLine
|
||||
<< "): " << buffer << '\n';
|
||||
std::exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
// Register the crash handler above when creating each unit test in this suite
|
||||
void CrashHandlerFixture::SetUp() {
|
||||
static bool isCrashHanlderRegistered{false};
|
||||
if (not isCrashHanlderRegistered)
|
||||
Fortran::runtime::Terminator::RegisterCrashHandler(CatchCrash);
|
||||
isCrashHanlderRegistered = true;
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
//===-- flang/unittests/RuntimeGTest/CrashHandlerFixture.h ------*- C++ -*-===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
/// Test fixture registers a custom crash handler to ensure death tests fail
|
||||
/// with expected message.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
#ifndef LLVM_FLANG_UNITTESTS_RUNTIMEGTEST_CRASHHANDLERFIXTURE_H
|
||||
#define LLVM_FLANG_UNITTESTS_RUNTIMEGTEST_CRASHHANDLERFIXTURE_H
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
struct CrashHandlerFixture : testing::Test {
|
||||
void SetUp();
|
||||
};
|
||||
|
||||
#endif
|
|
@ -0,0 +1,157 @@
|
|||
//===-- flang/unittests/RuntimeGTest/CrashHandlerFixture.cpp ----*- C++ -*-===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
/// Selected APIs are tested here to support development of unit tests for other
|
||||
/// runtime components and ensure the test fixture handles crashes as we expect.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
#include "CrashHandlerFixture.h"
|
||||
#include "../../runtime/io-api.h"
|
||||
#include "../../runtime/terminator.h"
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
using namespace Fortran::runtime;
|
||||
using namespace Fortran::runtime::io;
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// Test crashes through direct calls to terminator methods
|
||||
//------------------------------------------------------------------------------
|
||||
struct TestTerminator : CrashHandlerFixture {};
|
||||
|
||||
#define TEST_CRASH_HANDLER_MESSAGE \
|
||||
"Intentionally crashing runtime for unit test"
|
||||
|
||||
TEST(TestTerminator, CrashTest) {
|
||||
static Fortran::runtime::Terminator t;
|
||||
ASSERT_DEATH(t.Crash(TEST_CRASH_HANDLER_MESSAGE), TEST_CRASH_HANDLER_MESSAGE);
|
||||
}
|
||||
|
||||
#undef TEST_CRASH_HANDLER_MESSAGE
|
||||
|
||||
TEST(TestTerminator, CheckFailedLocationTest) {
|
||||
static Fortran::runtime::Terminator t;
|
||||
ASSERT_DEATH(t.CheckFailed("predicate", "someFileName", 789),
|
||||
"RUNTIME_CHECK\\(predicate\\) failed at someFileName\\(789\\)");
|
||||
}
|
||||
|
||||
TEST(TestTerminator, CheckFailedTest) {
|
||||
static Fortran::runtime::Terminator t;
|
||||
ASSERT_DEATH(t.CheckFailed("predicate"),
|
||||
"RUNTIME_CHECK\\(predicate\\) failed at \\(null\\)\\(0\\)");
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// Test misuse of io api
|
||||
//------------------------------------------------------------------------------
|
||||
struct TestIOCrash : CrashHandlerFixture {};
|
||||
|
||||
TEST(TestIOCrash, FormatDescriptorWriteMismatchTest) {
|
||||
static constexpr int bufferSize{4};
|
||||
static char buffer[bufferSize];
|
||||
static const char *format{"(A4)"};
|
||||
auto *cookie{IONAME(BeginInternalFormattedOutput)(
|
||||
buffer, bufferSize, format, std::strlen(format))};
|
||||
ASSERT_DEATH(IONAME(OutputInteger64)(cookie, 0xfeedface),
|
||||
"Data edit descriptor 'A' may not be used with an INTEGER data item");
|
||||
}
|
||||
|
||||
TEST(TestIOCrash, InvalidFormatCharacterTest) {
|
||||
static constexpr int bufferSize{1};
|
||||
static char buffer[bufferSize];
|
||||
static const char *format{"(C1)"};
|
||||
auto *cookie{IONAME(BeginInternalFormattedOutput)(
|
||||
buffer, bufferSize, format, std::strlen(format))};
|
||||
ASSERT_DEATH(IONAME(OutputInteger64)(cookie, 0xfeedface),
|
||||
"Unknown 'C' edit descriptor in FORMAT");
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// Test buffer overwrites with Output* functions
|
||||
/// Each test performs the tested IO operation correctly first, before causing
|
||||
/// an overwrite to demonstrate that the failure is caused by the overwrite and
|
||||
/// not a misuse of the API.
|
||||
//------------------------------------------------------------------------------
|
||||
TEST(TestIOCrash, OverwriteBufferAsciiTest) {
|
||||
static constexpr int bufferSize{4};
|
||||
static char buffer[bufferSize];
|
||||
static const char *format{"(A4)"};
|
||||
auto *cookie{IONAME(BeginInternalFormattedOutput)(
|
||||
buffer, bufferSize, format, std::strlen(format))};
|
||||
IONAME(OutputAscii)(cookie, "four", bufferSize);
|
||||
ASSERT_DEATH(IONAME(OutputAscii)(cookie, "Too many characters!", 20),
|
||||
"Internal write overran available records");
|
||||
}
|
||||
|
||||
TEST(TestIOCrash, OverwriteBufferCharacterTest) {
|
||||
static constexpr int bufferSize{1};
|
||||
static char buffer[bufferSize];
|
||||
static const char *format{"(A1)"};
|
||||
auto *cookie{IONAME(BeginInternalFormattedOutput)(
|
||||
buffer, bufferSize, format, std::strlen(format))};
|
||||
IONAME(OutputCharacter)(cookie, "a", 1);
|
||||
ASSERT_DEATH(IONAME(OutputCharacter)(cookie, "a", 1),
|
||||
"Internal write overran available records");
|
||||
}
|
||||
|
||||
TEST(TestIOCrash, OverwriteBufferLogicalTest) {
|
||||
static constexpr int bufferSize{1};
|
||||
static char buffer[bufferSize];
|
||||
static const char *format{"(L1)"};
|
||||
auto *cookie{IONAME(BeginInternalFormattedOutput)(
|
||||
buffer, bufferSize, format, std::strlen(format))};
|
||||
IONAME(OutputLogical)(cookie, true);
|
||||
ASSERT_DEATH(IONAME(OutputLogical)(cookie, true),
|
||||
"Internal write overran available records");
|
||||
}
|
||||
|
||||
TEST(TestIOCrash, OverwriteBufferRealTest) {
|
||||
static constexpr int bufferSize{1};
|
||||
static char buffer[bufferSize];
|
||||
static const char *format{"(F1)"};
|
||||
auto *cookie{IONAME(BeginInternalFormattedOutput)(
|
||||
buffer, bufferSize, format, std::strlen(format))};
|
||||
IONAME(OutputReal32)(cookie, 1.);
|
||||
EXPECT_DEATH(IONAME(OutputReal32)(cookie, 1.),
|
||||
"Internal write overran available records");
|
||||
|
||||
std::memset(buffer, '\0', bufferSize);
|
||||
cookie = IONAME(BeginInternalFormattedOutput)(
|
||||
buffer, bufferSize, format, std::strlen(format));
|
||||
IONAME(OutputReal64)(cookie, 1.);
|
||||
EXPECT_DEATH(IONAME(OutputReal64)(cookie, 1.),
|
||||
"Internal write overran available records");
|
||||
}
|
||||
|
||||
TEST(TestIOCrash, OverwriteBufferComplexTest) {
|
||||
static constexpr int bufferSize{8};
|
||||
static char buffer[bufferSize];
|
||||
static const char *format{"(Z1,Z1)"};
|
||||
auto *cookie{IONAME(BeginInternalFormattedOutput)(
|
||||
buffer, bufferSize, format, std::strlen(format))};
|
||||
IONAME(OutputComplex32)(cookie, 1., 1.);
|
||||
EXPECT_DEATH(IONAME(OutputComplex32)(cookie, 1., 1.),
|
||||
"Internal write overran available records");
|
||||
|
||||
std::memset(buffer, '\0', bufferSize);
|
||||
cookie = IONAME(BeginInternalFormattedOutput)(
|
||||
buffer, bufferSize, format, std::strlen(format));
|
||||
IONAME(OutputComplex64)(cookie, 1., 1.);
|
||||
EXPECT_DEATH(IONAME(OutputComplex64)(cookie, 1., 1.),
|
||||
"Internal write overran available records");
|
||||
}
|
||||
|
||||
TEST(TestIOCrash, OverwriteBufferIntegerTest) {
|
||||
static constexpr int bufferSize{1};
|
||||
static char buffer[bufferSize];
|
||||
static const char *format{"(I1)"};
|
||||
auto *cookie{IONAME(BeginInternalFormattedOutput)(
|
||||
buffer, bufferSize, format, std::strlen(format))};
|
||||
IONAME(OutputInteger64)(cookie, 0xdeadbeef);
|
||||
ASSERT_DEATH(IONAME(OutputInteger64)(cookie, 0xdeadbeef),
|
||||
"Internal write overran available records");
|
||||
}
|
Loading…
Reference in New Issue