[flang] update character tests to use gtest

Move character tests to gtest, according to reviews from revision
D97349. Create a new temporary directory parallel to old runtime
unittests directory to facilitate the transition. Once patches for all
tests have been accepted using GTest, the old directory may be removed.
The new directory is required because LLVM's CMake unit test
infrastructure requires that the test depends on all source files in
the `CMAKE_CURRENT_SOURCE_DIR` directory.

Reviewed By: awarzynski

Differential Revision: https://reviews.llvm.org/D97403
This commit is contained in:
Asher Mancinelli 2021-03-09 08:31:12 +00:00 committed by Andrzej Warzynski
parent 4289a7f1d7
commit 95193ac5ba
5 changed files with 291 additions and 94 deletions

View File

@ -40,6 +40,7 @@ add_subdirectory(Optimizer)
add_subdirectory(Decimal)
add_subdirectory(Evaluate)
add_subdirectory(Runtime)
add_subdirectory(RuntimeGTest)
if (FLANG_BUILD_NEW_DRIVER)
add_subdirectory(Frontend)

View File

@ -46,8 +46,3 @@ add_flang_nongtest_unittest(list-input
RuntimeTesting
FortranRuntime
)
add_flang_nongtest_unittest(character
RuntimeTesting
FortranRuntime
)

View File

@ -1,89 +0,0 @@
// Basic sanity tests of CHARACTER API; exhaustive testing will be done
// in Fortran.
#include "../../runtime/character.h"
#include "testing.h"
#include <cstring>
using namespace Fortran::runtime;
static void AppendAndPad(std::size_t limit) {
char x[8];
std::size_t xLen{0};
std::memset(x, 0, sizeof x);
xLen = RTNAME(CharacterAppend1)(x, limit, xLen, "abc", 3);
xLen = RTNAME(CharacterAppend1)(x, limit, xLen, "DE", 2);
RTNAME(CharacterPad1)(x, limit, xLen);
if (xLen > limit) {
Fail() << "xLen " << xLen << ">" << limit << '\n';
}
if (x[limit]) {
Fail() << "x[" << limit << "]='" << x[limit] << "'\n";
x[limit] = '\0';
}
if (std::memcmp(x, "abcDE ", limit)) {
Fail() << "x = '" << x << "'\n";
}
}
static void TestCharCompare(const char *x, const char *y, std::size_t xBytes,
std::size_t yBytes, int expect) {
int cmp{RTNAME(CharacterCompareScalar1)(x, y, xBytes, yBytes)};
if (cmp != expect) {
char buf[2][8];
std::memset(buf, 0, sizeof buf);
std::memcpy(buf[0], x, xBytes);
std::memcpy(buf[1], y, yBytes);
Fail() << "compare '" << buf[0] << "'(" << xBytes << ") to '" << buf[1]
<< "'(" << yBytes << "), got " << cmp << ", should be " << expect
<< '\n';
}
}
static void Compare(const char *x, const char *y, std::size_t xBytes,
std::size_t yBytes, int expect) {
TestCharCompare(x, y, xBytes, yBytes, expect);
TestCharCompare(y, x, yBytes, xBytes, -expect);
}
static void Scan(
const char *str, const char *set, bool back, std::size_t expect) {
auto res{RTNAME(Scan1)(str, std::strlen(str), set, std::strlen(set), back)};
if (res != expect) {
Fail() << "Scan(" << str << ',' << set << ",back=" << back << "): got "
<< res << ", should be " << expect << '\n';
}
}
static void Verify(
const char *str, const char *set, bool back, std::size_t expect) {
auto res{RTNAME(Verify1)(str, std::strlen(str), set, std::strlen(set), back)};
if (res != expect) {
Fail() << "Verify(" << str << ',' << set << ",back=" << back << "): got "
<< res << ", should be " << expect << '\n';
}
}
int main() {
StartTests();
for (std::size_t j{0}; j < 8; ++j) {
AppendAndPad(j);
}
Compare("abc", "abc", 3, 3, 0);
Compare("abc", "def", 3, 3, -1);
Compare("ab ", "abc", 3, 2, 0);
Compare("abc", "abc", 2, 3, -1);
Scan("abc", "abc", false, 1);
Scan("abc", "abc", true, 3);
Scan("abc", "cde", false, 3);
Scan("abc", "cde", true, 3);
Scan("abc", "x", false, 0);
Scan("", "x", false, 0);
Verify("abc", "abc", false, 0);
Verify("abc", "abc", true, 0);
Verify("abc", "cde", false, 1);
Verify("abc", "cde", true, 2);
Verify("abc", "x", false, 1);
Verify("", "x", false, 0);
return EndTests();
}

View File

@ -0,0 +1,8 @@
add_flang_unittest(FlangRuntimeTests
CharacterTest.cpp
)
target_link_libraries(FlangRuntimeTests
PRIVATE
FortranRuntime
)

View File

@ -0,0 +1,282 @@
//===-- flang/unittests/RuntimeGTest/CharacterTest.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 "../../runtime/character.h"
#include "gtest/gtest.h"
#include <cstring>
#include <functional>
#include <tuple>
#include <vector>
using namespace Fortran::runtime;
TEST(CharacterTests, AppendAndPad) {
static constexpr int limitMax{8};
static char buffer[limitMax];
static std::size_t offset{0};
for (std::size_t limit{0}; limit < limitMax; ++limit, offset = 0) {
std::memset(buffer, 0, sizeof buffer);
// Ensure appending characters does not overrun the limit
offset = RTNAME(CharacterAppend1)(buffer, limit, offset, "abc", 3);
offset = RTNAME(CharacterAppend1)(buffer, limit, offset, "DE", 2);
ASSERT_LE(offset, limit) << "offset " << offset << ">" << limit;
// Ensure whitespace padding does not overrun limit, the string is still
// null-terminated, and string matches the expected value up to the limit.
RTNAME(CharacterPad1)(buffer, limit, offset);
EXPECT_EQ(buffer[limit], '\0')
<< "buffer[" << limit << "]='" << buffer[limit] << "'";
buffer[limit] = buffer[limit] ? '\0' : buffer[limit];
ASSERT_EQ(std::memcmp(buffer, "abcDE ", limit), 0)
<< "buffer = '" << buffer << "'";
}
}
TEST(CharacterTests, CharacterAppend1Overrun) {
static constexpr int bufferSize{4};
static constexpr std::size_t limit{2};
static char buffer[bufferSize];
static std::size_t offset{0};
std::memset(buffer, 0, sizeof buffer);
offset = RTNAME(CharacterAppend1)(buffer, limit, offset, "1234", bufferSize);
ASSERT_EQ(offset, limit) << "CharacterAppend1 did not halt at limit = "
<< limit << ", but at offset = " << offset;
}
//------------------------------------------------------------------------------
/// Tests and infrastructure for character comparison functions
//------------------------------------------------------------------------------
template <typename CHAR>
using ComparisonFuncTy =
std::function<int(const CHAR *, const CHAR *, std::size_t, std::size_t)>;
using ComparisonFuncsTy = std::tuple<ComparisonFuncTy<char>,
ComparisonFuncTy<char16_t>, ComparisonFuncTy<char32_t>>;
// These comparison functions are the systems under test in the
// CharacterComparisonTests test cases.
static ComparisonFuncsTy comparisonFuncs{
RTNAME(CharacterCompareScalar1),
RTNAME(CharacterCompareScalar2),
RTNAME(CharacterCompareScalar4),
};
// Types of _values_ over which comparison tests are parameterized
template <typename CHAR>
using ComparisonParametersTy =
std::vector<std::tuple<const CHAR *, const CHAR *, int, int, int>>;
using ComparisonTestCasesTy = std::tuple<ComparisonParametersTy<char>,
ComparisonParametersTy<char16_t>, ComparisonParametersTy<char32_t>>;
static ComparisonTestCasesTy comparisonTestCases{
{
std::make_tuple("abc", "abc", 3, 3, 0),
std::make_tuple("abc", "def", 3, 3, -1),
std::make_tuple("ab ", "abc", 3, 2, 0),
std::make_tuple("abc", "abc", 2, 3, -1),
},
{
std::make_tuple(u"abc", u"abc", 3, 3, 0),
std::make_tuple(u"abc", u"def", 3, 3, -1),
std::make_tuple(u"ab ", u"abc", 3, 2, 0),
std::make_tuple(u"abc", u"abc", 2, 3, -1),
},
{
std::make_tuple(U"abc", U"abc", 3, 3, 0),
std::make_tuple(U"abc", U"def", 3, 3, -1),
std::make_tuple(U"ab ", U"abc", 3, 2, 0),
std::make_tuple(U"abc", U"abc", 2, 3, -1),
}};
template <typename CHAR>
struct CharacterComparisonTests : public ::testing::Test {
CharacterComparisonTests()
: parameters{std::get<ComparisonParametersTy<CHAR>>(comparisonTestCases)},
characterComparisonFunc{
std::get<ComparisonFuncTy<CHAR>>(comparisonFuncs)} {}
ComparisonParametersTy<CHAR> parameters;
ComparisonFuncTy<CHAR> characterComparisonFunc;
};
using CharacterTypes = ::testing::Types<char, char16_t, char32_t>;
TYPED_TEST_CASE(CharacterComparisonTests, CharacterTypes);
TYPED_TEST(CharacterComparisonTests, CompareCharacters) {
for (auto &[x, y, xBytes, yBytes, expect] : this->parameters) {
int cmp{this->characterComparisonFunc(x, y, xBytes, yBytes)};
TypeParam buf[2][8];
std::memset(buf, 0, sizeof buf);
std::memcpy(buf[0], x, xBytes);
std::memcpy(buf[1], y, yBytes);
ASSERT_EQ(cmp, expect) << "compare '" << x << "'(" << xBytes << ") to '"
<< y << "'(" << yBytes << "), got " << cmp
<< ", should be " << expect << '\n';
// Perform the same test with the parameters reversed and the difference
// negated
std::swap(x, y);
std::swap(xBytes, yBytes);
expect = -expect;
cmp = this->characterComparisonFunc(x, y, xBytes, yBytes);
std::memset(buf, 0, sizeof buf);
std::memcpy(buf[0], x, xBytes);
std::memcpy(buf[1], y, yBytes);
ASSERT_EQ(cmp, expect) << "compare '" << x << "'(" << xBytes << ") to '"
<< y << "'(" << yBytes << "), got " << cmp
<< ", should be " << expect << '\n';
}
}
//------------------------------------------------------------------------------
/// Tests and infrastructure for Scan functions
//------------------------------------------------------------------------------
template <typename CHAR>
using ScanFuncTy = std::function<int(
const CHAR *, std::size_t, const CHAR *, std::size_t, bool)>;
using ScanFuncsTy =
std::tuple<ScanFuncTy<char>, ScanFuncTy<char16_t>, ScanFuncTy<char32_t>>;
// These functions are the systems under test in CharacterScanTests test cases.
static ScanFuncsTy scanFuncs{
RTNAME(Scan1),
RTNAME(Scan2),
RTNAME(Scan4),
};
// Types of _values_ over which tests are parameterized
template <typename CHAR>
using ScanParametersTy =
std::vector<std::tuple<const CHAR *, const CHAR *, bool, int>>;
using ScanTestCasesTy = std::tuple<ScanParametersTy<char>,
ScanParametersTy<char16_t>, ScanParametersTy<char32_t>>;
static ScanTestCasesTy scanTestCases{
{
std::make_tuple("abc", "abc", false, 1),
std::make_tuple("abc", "abc", true, 3),
std::make_tuple("abc", "cde", false, 3),
std::make_tuple("abc", "cde", true, 3),
std::make_tuple("abc", "x", false, 0),
std::make_tuple("", "x", false, 0),
},
{
std::make_tuple(u"abc", u"abc", false, 1),
std::make_tuple(u"abc", u"abc", true, 3),
std::make_tuple(u"abc", u"cde", false, 3),
std::make_tuple(u"abc", u"cde", true, 3),
std::make_tuple(u"abc", u"x", false, 0),
std::make_tuple(u"", u"x", false, 0),
},
{
std::make_tuple(U"abc", U"abc", false, 1),
std::make_tuple(U"abc", U"abc", true, 3),
std::make_tuple(U"abc", U"cde", false, 3),
std::make_tuple(U"abc", U"cde", true, 3),
std::make_tuple(U"abc", U"x", false, 0),
std::make_tuple(U"", U"x", false, 0),
}};
template <typename CHAR> struct CharacterScanTests : public ::testing::Test {
CharacterScanTests()
: parameters{std::get<ScanParametersTy<CHAR>>(scanTestCases)},
characterScanFunc{std::get<ScanFuncTy<CHAR>>(scanFuncs)} {}
ScanParametersTy<CHAR> parameters;
ScanFuncTy<CHAR> characterScanFunc;
};
// Type-parameterized over the same character types as CharacterComparisonTests
TYPED_TEST_CASE(CharacterScanTests, CharacterTypes);
TYPED_TEST(CharacterScanTests, ScanCharacters) {
for (auto const &[str, set, back, expect] : this->parameters) {
auto res{
this->characterScanFunc(str, std::char_traits<TypeParam>::length(str),
set, std::char_traits<TypeParam>::length(set), back)};
ASSERT_EQ(res, expect) << "Scan(" << str << ',' << set << ",back=" << back
<< "): got " << res << ", should be " << expect;
}
}
//------------------------------------------------------------------------------
/// Tests and infrastructure for Verify functions
//------------------------------------------------------------------------------
template <typename CHAR>
using VerifyFuncTy = std::function<int(
const CHAR *, std::size_t, const CHAR *, std::size_t, bool)>;
using VerifyFuncsTy = std::tuple<VerifyFuncTy<char>, VerifyFuncTy<char16_t>,
VerifyFuncTy<char32_t>>;
// These functions are the systems under test in CharacterVerifyTests test cases
static VerifyFuncsTy verifyFuncs{
RTNAME(Verify1),
RTNAME(Verify2),
RTNAME(Verify4),
};
// Types of _values_ over which tests are parameterized
template <typename CHAR>
using VerifyParametersTy =
std::vector<std::tuple<const CHAR *, const CHAR *, bool, int>>;
using VerifyTestCasesTy = std::tuple<VerifyParametersTy<char>,
VerifyParametersTy<char16_t>, VerifyParametersTy<char32_t>>;
static VerifyTestCasesTy verifyTestCases{
{
std::make_tuple("abc", "abc", false, 0),
std::make_tuple("abc", "abc", true, 0),
std::make_tuple("abc", "cde", false, 1),
std::make_tuple("abc", "cde", true, 2),
std::make_tuple("abc", "x", false, 1),
std::make_tuple("", "x", false, 0),
},
{
std::make_tuple(u"abc", u"abc", false, 0),
std::make_tuple(u"abc", u"abc", true, 0),
std::make_tuple(u"abc", u"cde", false, 1),
std::make_tuple(u"abc", u"cde", true, 2),
std::make_tuple(u"abc", u"x", false, 1),
std::make_tuple(u"", u"x", false, 0),
},
{
std::make_tuple(U"abc", U"abc", false, 0),
std::make_tuple(U"abc", U"abc", true, 0),
std::make_tuple(U"abc", U"cde", false, 1),
std::make_tuple(U"abc", U"cde", true, 2),
std::make_tuple(U"abc", U"x", false, 1),
std::make_tuple(U"", U"x", false, 0),
}};
template <typename CHAR> struct CharacterVerifyTests : public ::testing::Test {
CharacterVerifyTests()
: parameters{std::get<VerifyParametersTy<CHAR>>(verifyTestCases)},
characterVerifyFunc{std::get<VerifyFuncTy<CHAR>>(verifyFuncs)} {}
VerifyParametersTy<CHAR> parameters;
VerifyFuncTy<CHAR> characterVerifyFunc;
};
// Type-parameterized over the same character types as CharacterComparisonTests
TYPED_TEST_CASE(CharacterVerifyTests, CharacterTypes);
TYPED_TEST(CharacterVerifyTests, VerifyCharacters) {
for (auto const &[str, set, back, expect] : this->parameters) {
auto res{
this->characterVerifyFunc(str, std::char_traits<TypeParam>::length(str),
set, std::char_traits<TypeParam>::length(set), back)};
ASSERT_EQ(res, expect) << "Verify(" << str << ',' << set << ",back=" << back
<< "): got " << res << ", should be " << expect;
}
}