mirror of
https://github.com/OPM/ResInsight.git
synced 2026-10-26 15:10:22 -05:00
349 lines
12 KiB
C++
349 lines
12 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 ) );
|
||
|
|
}
|
||
|
|
}
|