xo-expression2: + StringTable + utest [WIP] [FAILING]

This commit is contained in:
Roland Conybeare 2026-01-15 20:52:09 -05:00
commit 27e255f574
8 changed files with 388 additions and 1 deletions

View file

@ -0,0 +1,160 @@
/** @file StringTable.test.cpp
*
* @author Roland Conybeare, Jan 2026
**/
#include <xo/expression2/StringTable.hpp>
#include <catch2/catch.hpp>
#include <cstring>
namespace xo {
using xo::scm::StringTable;
using xo::scm::DString;
namespace ut {
TEST_CASE("StringTable-lookup-empty", "[expression2][StringTable]")
{
StringTable table(1024);
// lookup on empty table returns nullptr
REQUIRE(table.lookup("foo") == nullptr);
REQUIRE(table.lookup("") == nullptr);
}
TEST_CASE("StringTable-intern", "[expression2][StringTable]")
{
StringTable table(1024);
const DString * s1 = table.intern("hello");
REQUIRE(s1 != nullptr);
REQUIRE(std::strcmp(s1->chars(), "hello") == 0);
REQUIRE(s1->size() == 5);
}
TEST_CASE("StringTable-intern-idempotent", "[expression2][StringTable]")
{
StringTable table(1024);
const DString * s1 = table.intern("hello");
const DString * s2 = table.intern("hello");
// same key returns same pointer
REQUIRE(s1 != nullptr);
REQUIRE(s2 != nullptr);
REQUIRE(s1 == s2);
}
TEST_CASE("StringTable-lookup-after-intern", "[expression2][StringTable]")
{
StringTable table(1024);
REQUIRE(table.lookup("hello") == nullptr);
const DString * s1 = table.intern("hello");
const DString * s2 = table.lookup("hello");
REQUIRE(s2 != nullptr);
REQUIRE(s1 == s2);
}
TEST_CASE("StringTable-multiple-strings", "[expression2][StringTable]")
{
StringTable table(1024);
const DString * s1 = table.intern("apple");
const DString * s2 = table.intern("banana");
const DString * s3 = table.intern("cherry");
// all different pointers
REQUIRE(s1 != s2);
REQUIRE(s2 != s3);
REQUIRE(s1 != s3);
// correct contents
REQUIRE(std::strcmp(s1->chars(), "apple") == 0);
REQUIRE(std::strcmp(s2->chars(), "banana") == 0);
REQUIRE(std::strcmp(s3->chars(), "cherry") == 0);
// lookup still works
REQUIRE(table.lookup("apple") == s1);
REQUIRE(table.lookup("banana") == s2);
REQUIRE(table.lookup("cherry") == s3);
REQUIRE(table.lookup("date") == nullptr);
}
TEST_CASE("StringTable-intern-empty-string", "[expression2][StringTable]")
{
StringTable table(1024);
const DString * s1 = table.intern("");
REQUIRE(s1 != nullptr);
REQUIRE(s1->size() == 0);
REQUIRE(s1->chars()[0] == '\0');
// idempotent for empty string too
const DString * s2 = table.intern("");
REQUIRE(s1 == s2);
}
TEST_CASE("StringTable-verify_ok", "[expression2][StringTable]")
{
StringTable table(4096);
{
INFO("1. empty table");
// empty table passes verify_ok
REQUIRE(table.verify_ok());
}
// after interning strings, still passes
{
INFO("2. intern(hello)");
table.intern("hello");
REQUIRE(table.verify_ok());
}
{
INFO("3. intern(world)");
table.intern("world");
REQUIRE(table.verify_ok());
}
{
INFO("4. intern(foo)");
table.intern("foo");
REQUIRE(table.verify_ok());
}
{
INFO("5. intern(bar)");
table.intern("bar");
REQUIRE(table.verify_ok());
}
// idempotent intern doesn't break invariants
{
INFO("6. intern(hello)");
table.intern("hello");
REQUIRE(table.verify_ok());
}
{
INFO("7. intern(world)");
table.intern("world");
REQUIRE(table.verify_ok());
}
}
} /*namespace ut*/
} /*namespace xo*/
/* end StringTable.test.cpp */