//===- 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 #include 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 symbolTable{}; ScopedHashTableScope 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::ScopeTy; std::stack ExpectedValues; std::stack> Scopes; Scopes.emplace(std::make_unique(symbolTable)); ExpectedValues.emplace(kLocalValue); symbolTable.insert(kGlobalName, kLocalValue); Scopes.emplace(std::make_unique(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::ScopeTy; SymbolTableScopeTy funScope(symbolTable); symbolTable.insert(kGlobalName, kLocalValue); SymbolTableScopeTy funScope2(symbolTable); symbolTable.insert(kGlobalName, kLocalValue2); std::stack expectedValues{{kLocalValue, kLocalValue2}}; std::stack 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. }