blob: 0363a08cc0f0314f11ee934e5fbee25359c15877 [file] [log] [blame]
//===- llvm/unittests/Frontend/OpenMPDirectiveNameParserTest.cpp ----------===//
//
// 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 "llvm/ADT/Sequence.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/Frontend/OpenMP/DirectiveNameParser.h"
#include "llvm/Frontend/OpenMP/OMP.h"
#include "gtest/gtest.h"
#include <cctype>
#include <sstream>
#include <string>
#include <tuple>
#include <vector>
using namespace llvm;
static const omp::DirectiveNameParser &getParser() {
static omp::DirectiveNameParser Parser(omp::SourceLanguage::C |
omp::SourceLanguage::Fortran);
return Parser;
}
static std::vector<std::string> tokenize(StringRef S) {
std::vector<std::string> Tokens;
using TokenIterator = std::istream_iterator<std::string>;
std::string Copy = S.str();
std::istringstream Stream(Copy);
for (auto I = TokenIterator(Stream), E = TokenIterator(); I != E; ++I)
Tokens.push_back(*I);
return Tokens;
}
static std::string &prepareParamName(std::string &Name) {
for (size_t I = 0, E = Name.size(); I != E; ++I) {
// The parameter name must only have alphanumeric characters.
if (!isalnum(Name[I]))
Name[I] = 'X';
}
return Name;
}
namespace llvm {
template <> struct enum_iteration_traits<omp::Directive> {
static constexpr bool is_iterable = true;
};
} // namespace llvm
// Test tokenizing.
class Tokenize : public testing::TestWithParam<omp::Directive> {};
static bool isEqual(const SmallVector<StringRef> &A,
const std::vector<std::string> &B) {
if (A.size() != B.size())
return false;
for (size_t I = 0, E = A.size(); I != E; ++I) {
if (A[I] != StringRef(B[I]))
return false;
}
return true;
}
TEST_P(Tokenize, T) {
omp::Directive DirId = GetParam();
StringRef Name = omp::getOpenMPDirectiveName(DirId, omp::FallbackVersion);
SmallVector<StringRef> tokens1 = omp::DirectiveNameParser::tokenize(Name);
std::vector<std::string> tokens2 = tokenize(Name);
ASSERT_TRUE(isEqual(tokens1, tokens2));
}
static std::string
getParamName1(const testing::TestParamInfo<Tokenize::ParamType> &Info) {
omp::Directive DirId = Info.param;
std::string Name =
omp::getOpenMPDirectiveName(DirId, omp::FallbackVersion).str();
return prepareParamName(Name);
}
INSTANTIATE_TEST_SUITE_P(
DirectiveNameParserTest, Tokenize,
testing::ValuesIn(
llvm::enum_seq(static_cast<omp::Directive>(0),
static_cast<omp::Directive>(omp::Directive_enumSize))),
getParamName1);
// Test parsing of valid names.
using ValueType = std::tuple<omp::Directive, unsigned>;
class ParseValid : public testing::TestWithParam<ValueType> {};
TEST_P(ParseValid, T) {
auto [DirId, Version] = GetParam();
if (DirId == omp::Directive::OMPD_unknown)
return;
std::string Name = omp::getOpenMPDirectiveName(DirId, Version).str();
// Tokenize and parse
auto &Parser = getParser();
auto *State = Parser.initial();
ASSERT_TRUE(State != nullptr);
std::vector<std::string> Tokens = tokenize(Name);
for (auto &Tok : Tokens) {
State = Parser.consume(State, Tok);
ASSERT_TRUE(State != nullptr);
}
ASSERT_EQ(State->Value, DirId);
}
static std::string
getParamName2(const testing::TestParamInfo<ParseValid::ParamType> &Info) {
auto [DirId, Version] = Info.param;
std::string Name = omp::getOpenMPDirectiveName(DirId, Version).str() + "v" +
std::to_string(Version);
return prepareParamName(Name);
}
INSTANTIATE_TEST_SUITE_P(
DirectiveNameParserTest, ParseValid,
testing::Combine(testing::ValuesIn(llvm::enum_seq(
static_cast<omp::Directive>(0),
static_cast<omp::Directive>(omp::Directive_enumSize))),
testing::ValuesIn(omp::getOpenMPVersions())),
getParamName2);
// Test parsing of invalid names
class ParseInvalid : public testing::TestWithParam<std::string> {};
TEST_P(ParseInvalid, T) {
std::string Name = GetParam();
auto &Parser = getParser();
auto *State = Parser.initial();
ASSERT_TRUE(State != nullptr);
std::vector<std::string> Tokens = tokenize(Name);
for (auto &Tok : Tokens)
State = Parser.consume(State, Tok);
ASSERT_TRUE(State == nullptr || State->Value == omp::Directive::OMPD_unknown);
}
namespace {
using namespace std;
INSTANTIATE_TEST_SUITE_P(DirectiveNameParserTest, ParseInvalid,
testing::Values(
// Names that contain invalid tokens
"bad"s, "target teams invalid"s,
"target sections parallel"s,
"target teams distribute parallel for wrong"s,
// Valid beginning, but not a complete name
"begin declare"s,
// Complete name with extra tokens
"distribute simd target"s));
} // namespace