blob: 8ce5c7cecf998e0df060c25b08e0ceb2bfd06030 [file] [log] [blame]
//===- ScopedHashTableTest.cpp - ScopedHashTable unit tests ---------------===//
//
// 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/ScopedHashTable.h"
#include "llvm/ADT/StringRef.h"
#include "gtest/gtest.h"
#include <memory>
#include <stack>
using ::llvm::ScopedHashTable;
using ::llvm::ScopedHashTableScope;
using ::llvm::StringLiteral;
using ::llvm::StringRef;
using ::testing::Test;
class ScopedHashTableTest : public Test {
protected:
ScopedHashTableTest() { symbolTable.insert(kGlobalName, kGlobalValue); }
ScopedHashTable<StringRef, StringRef> symbolTable{};
ScopedHashTableScope<StringRef, StringRef> globalScope{symbolTable};
static constexpr StringLiteral kGlobalName = "global";
static constexpr StringLiteral kGlobalValue = "gvalue";
static constexpr StringLiteral kLocalName = "local";
static constexpr StringLiteral kLocalValue = "lvalue";
static constexpr StringLiteral kLocalValue2 = "lvalue2";
};
TEST_F(ScopedHashTableTest, AccessWithNoActiveScope) {
EXPECT_EQ(symbolTable.count(kGlobalName), 1U);
}
TEST_F(ScopedHashTableTest, AccessWithAScope) {
[[maybe_unused]] ScopedHashTableScope<StringRef, StringRef> varScope(
symbolTable);
EXPECT_EQ(symbolTable.count(kGlobalName), 1U);
}
TEST_F(ScopedHashTableTest, InsertInScope) {
[[maybe_unused]] ScopedHashTableScope<StringRef, StringRef> varScope(
symbolTable);
symbolTable.insert(kLocalName, kLocalValue);
EXPECT_EQ(symbolTable.count(kLocalName), 1U);
}
TEST_F(ScopedHashTableTest, InsertInLinearSortedScope) {
[[maybe_unused]] ScopedHashTableScope<StringRef, StringRef> varScope(
symbolTable);
[[maybe_unused]] ScopedHashTableScope<StringRef, StringRef> varScope2(
symbolTable);
[[maybe_unused]] ScopedHashTableScope<StringRef, StringRef> varScope3(
symbolTable);
symbolTable.insert(kLocalName, kLocalValue);
EXPECT_EQ(symbolTable.count(kLocalName), 1U);
}
TEST_F(ScopedHashTableTest, InsertInOutedScope) {
{
[[maybe_unused]] ScopedHashTableScope<StringRef, StringRef> varScope(
symbolTable);
symbolTable.insert(kLocalName, kLocalValue);
}
EXPECT_EQ(symbolTable.count(kLocalName), 0U);
}
TEST_F(ScopedHashTableTest, OverrideInScope) {
[[maybe_unused]] ScopedHashTableScope<StringRef, StringRef> funScope(
symbolTable);
symbolTable.insert(kLocalName, kLocalValue);
{
[[maybe_unused]] ScopedHashTableScope<StringRef, StringRef> varScope(
symbolTable);
symbolTable.insert(kLocalName, kLocalValue2);
EXPECT_EQ(symbolTable.lookup(kLocalName), kLocalValue2);
}
EXPECT_EQ(symbolTable.lookup(kLocalName), kLocalValue);
}
TEST_F(ScopedHashTableTest, GetCurScope) {
EXPECT_EQ(symbolTable.getCurScope(), &globalScope);
{
ScopedHashTableScope<StringRef, StringRef> funScope(symbolTable);
ScopedHashTableScope<StringRef, StringRef> funScope2(symbolTable);
EXPECT_EQ(symbolTable.getCurScope(), &funScope2);
{
ScopedHashTableScope<StringRef, StringRef> blockScope(symbolTable);
EXPECT_EQ(symbolTable.getCurScope(), &blockScope);
}
EXPECT_EQ(symbolTable.getCurScope(), &funScope2);
}
EXPECT_EQ(symbolTable.getCurScope(), &globalScope);
}
TEST_F(ScopedHashTableTest, PopScope) {
using SymbolTableScopeTy = ScopedHashTable<StringRef, StringRef>::ScopeTy;
std::stack<StringRef> ExpectedValues;
std::stack<std::unique_ptr<SymbolTableScopeTy>> Scopes;
Scopes.emplace(std::make_unique<SymbolTableScopeTy>(symbolTable));
ExpectedValues.emplace(kLocalValue);
symbolTable.insert(kGlobalName, kLocalValue);
Scopes.emplace(std::make_unique<SymbolTableScopeTy>(symbolTable));
ExpectedValues.emplace(kLocalValue2);
symbolTable.insert(kGlobalName, kLocalValue2);
while (symbolTable.getCurScope() != &globalScope) {
EXPECT_EQ(symbolTable.getCurScope(), Scopes.top().get());
EXPECT_EQ(symbolTable.lookup(kGlobalName), ExpectedValues.top());
ExpectedValues.pop();
Scopes.pop(); // destructs the SymbolTableScopeTy instance implicitly
// calling Scopes.top()->~SymbolTableScopeTy();
EXPECT_NE(symbolTable.getCurScope(), nullptr);
}
ASSERT_TRUE(ExpectedValues.empty());
ASSERT_TRUE(Scopes.empty());
EXPECT_EQ(symbolTable.lookup(kGlobalName), kGlobalValue);
}
TEST_F(ScopedHashTableTest, DISABLED_PopScopeOnStack) {
using SymbolTableScopeTy = ScopedHashTable<StringRef, StringRef>::ScopeTy;
SymbolTableScopeTy funScope(symbolTable);
symbolTable.insert(kGlobalName, kLocalValue);
SymbolTableScopeTy funScope2(symbolTable);
symbolTable.insert(kGlobalName, kLocalValue2);
std::stack<StringRef> expectedValues{{kLocalValue, kLocalValue2}};
std::stack<SymbolTableScopeTy *> expectedScopes{{&funScope, &funScope2}};
while (symbolTable.getCurScope() != &globalScope) {
EXPECT_EQ(symbolTable.getCurScope(), expectedScopes.top());
expectedScopes.pop();
EXPECT_EQ(symbolTable.lookup(kGlobalName), expectedValues.top());
expectedValues.pop();
symbolTable.getCurScope()->~SymbolTableScopeTy();
EXPECT_NE(symbolTable.getCurScope(), nullptr);
}
// We have imbalanced scopes here:
// Assertion `HT.CurScope == this && "Scope imbalance!"' failed
// HT.CurScope is a pointer to the `globalScope` while
// `SymbolTableScopeTy.this` is still a pointer to `funScope2`.
// There is no way to write an assert on an assert in googletest so that we
// mark the test case as DISABLED.
}