Skip to content

[ADT] Add a unittest for the ScopedHashTable class #120183

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions llvm/unittests/ADT/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ add_llvm_unittest(ADTTests
SCCIteratorTest.cpp
STLExtrasTest.cpp
STLForwardCompatTest.cpp
ScopedHashTableTest.cpp
ScopeExitTest.cpp
SequenceTest.cpp
SetOperationsTest.cpp
Expand Down
145 changes: 145 additions & 0 deletions llvm/unittests/ADT/ScopedHashTableTest.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
//===- 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 varScope(symbolTable);
EXPECT_EQ(symbolTable.count(kGlobalName), 1U);
}

TEST_F(ScopedHashTableTest, InsertInScope) {
[[maybe_unused]] ScopedHashTableScope varScope(symbolTable);
symbolTable.insert(kLocalName, kLocalValue);
EXPECT_EQ(symbolTable.count(kLocalName), 1U);
}

TEST_F(ScopedHashTableTest, InsertInLinearSortedScope) {
[[maybe_unused]] ScopedHashTableScope varScope(symbolTable);
[[maybe_unused]] ScopedHashTableScope varScope2(symbolTable);
[[maybe_unused]] ScopedHashTableScope varScope3(symbolTable);
symbolTable.insert(kLocalName, kLocalValue);
EXPECT_EQ(symbolTable.count(kLocalName), 1U);
}

TEST_F(ScopedHashTableTest, InsertInOutedScope) {
{
[[maybe_unused]] ScopedHashTableScope varScope(symbolTable);
symbolTable.insert(kLocalName, kLocalValue);
}
EXPECT_EQ(symbolTable.count(kLocalName), 0U);
}

TEST_F(ScopedHashTableTest, OverrideInScope) {
[[maybe_unused]] ScopedHashTableScope funScope(symbolTable);
symbolTable.insert(kLocalName, kLocalValue);
{
[[maybe_unused]] ScopedHashTableScope 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 funScope(symbolTable);
ScopedHashTableScope funScope2(symbolTable);
EXPECT_EQ(symbolTable.getCurScope(), &funScope2);
{
ScopedHashTableScope 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.
}
Loading