Files
ResInsight/ApplicationLibCode/UnitTests/RiaStringPool-Test.cpp
T
Magne Sjaastad e41b1be924 Refactor RifEclipseSummaryAddress to use string pool indices
Replaced direct string members with indices into RiaStringPool for vector, well, group, and LGR names. Updated all constructors, accessors, and logic to use the string pool for storage and retrieval. This change reduces memory usage and improves performance for repeated string values.

Fixes by clang-format
2026-02-05 13:49:00 +01:00

335 lines
11 KiB
C++

#include "gtest/gtest.h"
#include "RiaStringPool.h"
#include <algorithm>
#include <set>
#include <thread>
#include <vector>
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
TEST( RiaStringPoolTest, EmptyStringPreAllocated )
{
auto& pool = RiaStringPool::instance();
auto emptyIndex = pool.getIndex( "" );
EXPECT_EQ( pool.getEmptyIndex(), emptyIndex );
EXPECT_EQ( "", pool.getString( emptyIndex ) );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
TEST( RiaStringPoolTest, BasicStringStorage )
{
auto& pool = RiaStringPool::instance();
std::string testStr = "FOPT";
auto index = pool.getIndex( testStr );
EXPECT_EQ( testStr, pool.getString( index ) );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
TEST( RiaStringPoolTest, DuplicateStringsReturnSameIndex )
{
auto& pool = RiaStringPool::instance();
std::string testStr = "WOPT:WELL1";
auto index1 = pool.getIndex( testStr );
auto index2 = pool.getIndex( testStr );
auto index3 = pool.getIndex( testStr );
EXPECT_EQ( index1, index2 );
EXPECT_EQ( index2, index3 );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
TEST( RiaStringPoolTest, MultipleUniqueStrings )
{
auto& pool = RiaStringPool::instance();
std::vector<std::string> testStrings = { "FOPT", "WOPT:WELL1", "GOPT:GROUP1", "BPR:10,20,30", "ROPR" };
std::vector<RiaStringPool::IndexType> indices;
for ( const auto& str : testStrings )
{
indices.push_back( pool.getIndex( str ) );
}
// All indices should be unique
std::set<RiaStringPool::IndexType> uniqueIndices( indices.begin(), indices.end() );
EXPECT_EQ( testStrings.size(), uniqueIndices.size() );
// Verify retrieval
for ( size_t i = 0; i < testStrings.size(); ++i )
{
EXPECT_EQ( testStrings[i], pool.getString( indices[i] ) );
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
TEST( RiaStringPoolTest, OutOfRangeThrows )
{
auto& pool = RiaStringPool::instance();
// Attempt to access index far beyond current size
EXPECT_THROW( pool.getString( 9999999 ), std::out_of_range );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
TEST( RiaStringPoolTest, ThreadSafety )
{
auto& pool = RiaStringPool::instance();
const int numThreads = 10;
const int stringsPerThread = 100;
std::vector<std::thread> threads;
std::vector<std::vector<RiaStringPool::IndexType>> threadResults( numThreads );
// Create threads that all add the same strings
for ( int t = 0; t < numThreads; ++t )
{
threads.emplace_back(
[&pool, &threadResults, t, stringsPerThread]()
{
for ( int i = 0; i < stringsPerThread; ++i )
{
std::string str = "STRING_" + std::to_string( i );
auto index = pool.getIndex( str );
threadResults[t].push_back( index );
}
} );
}
// Wait for all threads to complete
for ( auto& thread : threads )
{
thread.join();
}
// Verify all threads got the same indices for the same strings
for ( int i = 1; i < numThreads; ++i )
{
EXPECT_EQ( threadResults[0].size(), threadResults[i].size() );
for ( size_t j = 0; j < threadResults[0].size(); ++j )
{
EXPECT_EQ( threadResults[0][j], threadResults[i][j] );
}
}
// Verify string retrieval
for ( int i = 0; i < stringsPerThread; ++i )
{
std::string expectedStr = "STRING_" + std::to_string( i );
auto index = threadResults[0][i];
EXPECT_EQ( expectedStr, pool.getString( index ) );
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
TEST( RiaStringPoolTest, LargeNumberOfStrings )
{
auto& pool = RiaStringPool::instance();
const int numStrings = 10000;
std::vector<RiaStringPool::IndexType> indices;
// Add many unique strings
for ( int i = 0; i < numStrings; ++i )
{
std::string str = "VECTOR_" + std::to_string( i ) + "_DATA";
indices.push_back( pool.getIndex( str ) );
}
// Verify all can be retrieved
for ( int i = 0; i < numStrings; ++i )
{
std::string expectedStr = "VECTOR_" + std::to_string( i ) + "_DATA";
EXPECT_EQ( expectedStr, pool.getString( indices[i] ) );
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
TEST( RiaStringPoolTest, SpecialCharacters )
{
auto& pool = RiaStringPool::instance();
std::vector<std::string> specialStrings = { "String with spaces",
"String:with:colons",
"String/with/slashes",
"String,with,commas",
"String-with-dashes",
"String_with_underscores",
"String.with.dots",
"String|with|pipes",
"String@with@at",
"String#with#hash" };
for ( const auto& str : specialStrings )
{
auto index = pool.getIndex( str );
EXPECT_EQ( str, pool.getString( index ) );
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
TEST( RiaStringPoolTest, VeryLongStrings )
{
auto& pool = RiaStringPool::instance();
// Create a very long string
std::string longStr( 10000, 'A' );
longStr += "_UNIQUE";
auto index = pool.getIndex( longStr );
EXPECT_EQ( longStr, pool.getString( index ) );
// Verify same index on duplicate
auto index2 = pool.getIndex( longStr );
EXPECT_EQ( index, index2 );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
TEST( RiaStringPoolTest, ConcurrentInsertAndRead )
{
auto& pool = RiaStringPool::instance();
const int numWriteThreads = 5;
const int numReadThreads = 5;
const int stringsPerWrite = 50;
std::vector<std::thread> threads;
// Create strings in multiple write threads
for ( int t = 0; t < numWriteThreads; ++t )
{
threads.emplace_back(
[&pool, t, stringsPerWrite]()
{
for ( int i = 0; i < stringsPerWrite; ++i )
{
std::string str = "WRITE_" + std::to_string( t ) + "_" + std::to_string( i );
pool.getIndex( str );
}
} );
}
// Read strings concurrently
for ( int t = 0; t < numReadThreads; ++t )
{
threads.emplace_back(
[&pool, t, stringsPerWrite]()
{
for ( int i = 0; i < stringsPerWrite; ++i )
{
// Try to read strings that might be being created
std::string str = "WRITE_0_" + std::to_string( i );
auto index = pool.getIndex( str );
// Should not crash even if racing with writes
EXPECT_EQ( str, pool.getString( index ) );
}
} );
}
for ( auto& thread : threads )
{
thread.join();
}
// Verify all written strings are accessible
for ( int t = 0; t < numWriteThreads; ++t )
{
for ( int i = 0; i < stringsPerWrite; ++i )
{
std::string str = "WRITE_" + std::to_string( t ) + "_" + std::to_string( i );
auto index = pool.getIndex( str );
EXPECT_EQ( str, pool.getString( index ) );
}
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
TEST( RiaStringPoolTest, InvalidIndex )
{
auto& pool = RiaStringPool::instance();
// Test with INVALID_INDEX constant
EXPECT_THROW( pool.getString( RiaStringPool::INVALID_INDEX ), std::out_of_range );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
TEST( RiaStringPoolTest, SimilarStrings )
{
auto& pool = RiaStringPool::instance();
// Test strings that are similar but not identical
std::vector<std::string> similarStrings = { "WOPT:WELL-1", "WOPT:WELL-2", "WOPT:WELL-10", "WOPT:WELL-1A", "WOPT:WELL_1", "WOPT: WELL-1" };
std::vector<RiaStringPool::IndexType> indices;
for ( const auto& str : similarStrings )
{
indices.push_back( pool.getIndex( str ) );
}
// All should have different indices
std::set<RiaStringPool::IndexType> uniqueIndices( indices.begin(), indices.end() );
EXPECT_EQ( similarStrings.size(), uniqueIndices.size() );
// Verify each string retrieval
for ( size_t i = 0; i < similarStrings.size(); ++i )
{
EXPECT_EQ( similarStrings[i], pool.getString( indices[i] ) );
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
TEST( RiaStringPoolTest, CommonSummaryVectorNames )
{
auto& pool = RiaStringPool::instance();
// Test with realistic summary vector names
std::vector<std::string> vectorNames =
{ "FOPT", "FWPT", "FGPT", "FOPR", "FWPR", "FGPR", "WOPT:PROD-1", "WWPT:PROD-1", "WBHP:PROD-1", "WOPT:INJ-1", "GOPT:FIELD", "BPR:10,15,20" };
// Store indices
std::vector<RiaStringPool::IndexType> indices;
for ( const auto& name : vectorNames )
{
indices.push_back( pool.getIndex( name ) );
}
// Request same strings again - should get same indices
for ( size_t i = 0; i < vectorNames.size(); ++i )
{
auto index = pool.getIndex( vectorNames[i] );
EXPECT_EQ( indices[i], index );
EXPECT_EQ( vectorNames[i], pool.getString( index ) );
}
}