785 lines
23 KiB
C++
785 lines
23 KiB
C++
|
#include <lw/lib/SRDParserConfig.hh>
|
||
|
#include <cppunit/extensions/HelperMacros.h>
|
||
|
using namespace lw;
|
||
|
|
||
|
|
||
|
class SRDParserConfigTest : public CppUnit::TestFixture
|
||
|
{
|
||
|
CPPUNIT_TEST_SUITE( SRDParserConfigTest );
|
||
|
CPPUNIT_TEST( testWordIndex );
|
||
|
|
||
|
CPPUNIT_TEST( testRuleSimple );
|
||
|
CPPUNIT_TEST( testRuleABStarABB );
|
||
|
CPPUNIT_TEST( testMergedRules );
|
||
|
CPPUNIT_TEST( testRulesMultiContexts );
|
||
|
|
||
|
CPPUNIT_TEST( testContextIDs );
|
||
|
CPPUNIT_TEST( testEnumIDs );
|
||
|
|
||
|
CPPUNIT_TEST( testUnusedEnums );
|
||
|
CPPUNIT_TEST( testUnusedContexts );
|
||
|
|
||
|
CPPUNIT_TEST( testContextInheritance );
|
||
|
|
||
|
CPPUNIT_TEST( testErrorMissingCtxRule );
|
||
|
CPPUNIT_TEST( testErrorMissingCtxParent );
|
||
|
CPPUNIT_TEST( testErrorMissingEnum );
|
||
|
CPPUNIT_TEST( testErrorEmptyContext );
|
||
|
CPPUNIT_TEST( testErrorEmptyRule );
|
||
|
CPPUNIT_TEST( testErrorEmptyAlt );
|
||
|
CPPUNIT_TEST( testErrorEmptyRepeat );
|
||
|
CPPUNIT_TEST( testErrorRecursiveInheritance );
|
||
|
CPPUNIT_TEST( testErrorAmbiguousRules );
|
||
|
|
||
|
CPPUNIT_TEST( testErrorUBRSimpleOK );
|
||
|
CPPUNIT_TEST( testErrorUBRSimpleUnbalancedStart );
|
||
|
CPPUNIT_TEST( testErrorUBRSimpleUnbalancedEnd );
|
||
|
CPPUNIT_TEST( testErrorUBRAltsOKContained );
|
||
|
CPPUNIT_TEST( testErrorUBRAltsOKBalancing );
|
||
|
CPPUNIT_TEST( testErrorUBRAltsDifferent );
|
||
|
CPPUNIT_TEST( testErrorUBRAltsUnbalanced );
|
||
|
CPPUNIT_TEST( testErrorUBRRepsOK );
|
||
|
CPPUNIT_TEST( testErrorUBRRepsUnbalanced );
|
||
|
|
||
|
CPPUNIT_TEST( testTransition );
|
||
|
CPPUNIT_TEST_SUITE_END( );
|
||
|
|
||
|
void checkMergedRules( T_SRDParserConfig const& c );
|
||
|
|
||
|
public:
|
||
|
void testWordIndex( );
|
||
|
|
||
|
void testRuleSimple( );
|
||
|
void testRuleABStarABB( );
|
||
|
void testMergedRules( );
|
||
|
void testRulesMultiContexts( );
|
||
|
|
||
|
void testContextIDs( );
|
||
|
void testEnumIDs( );
|
||
|
|
||
|
void testUnusedEnums( );
|
||
|
void testUnusedContexts( );
|
||
|
|
||
|
void testContextInheritance( );
|
||
|
|
||
|
void testErrorMissingCtxRule( );
|
||
|
void testErrorMissingCtxParent( );
|
||
|
void testErrorMissingEnum( );
|
||
|
void testErrorEmptyContext( );
|
||
|
void testErrorEmptyRule( );
|
||
|
void testErrorEmptyAlt( );
|
||
|
void testErrorEmptyRepeat( );
|
||
|
void testErrorRecursiveInheritance( );
|
||
|
void testErrorAmbiguousRules( );
|
||
|
|
||
|
void testErrorUBRSimpleOK( );
|
||
|
void testErrorUBRSimpleUnbalancedStart( );
|
||
|
void testErrorUBRSimpleUnbalancedEnd( );
|
||
|
void testErrorUBRAltsOKContained( );
|
||
|
void testErrorUBRAltsOKBalancing( );
|
||
|
void testErrorUBRAltsDifferent( );
|
||
|
void testErrorUBRAltsUnbalanced( );
|
||
|
void testErrorUBRRepsOK( );
|
||
|
void testErrorUBRRepsUnbalanced( );
|
||
|
|
||
|
void testTransition( );
|
||
|
};
|
||
|
CPPUNIT_TEST_SUITE_REGISTRATION( SRDParserConfigTest );
|
||
|
|
||
|
/*----------------------------------------------------------------------------*/
|
||
|
|
||
|
void SRDParserConfigTest::checkMergedRules( T_SRDParserConfig const& c )
|
||
|
{
|
||
|
CPPUNIT_ASSERT_EQUAL( uint32_t( 1 ) , c.startStates.size( ) );
|
||
|
CPPUNIT_ASSERT_EQUAL( uint32_t( 0 ) , c.startStates[ 0 ] );
|
||
|
|
||
|
CPPUNIT_ASSERT_EQUAL( uint32_t( 8 ) , c.endStates.size( ) );
|
||
|
CPPUNIT_ASSERT_EQUAL( uint32_t( T_SRDParserConfig::INVALID_END ) , c.endStates[ 0 ] );
|
||
|
CPPUNIT_ASSERT_EQUAL( uint32_t( 0 ) , c.endStates[ 1 ] );
|
||
|
CPPUNIT_ASSERT_EQUAL( uint32_t( T_SRDParserConfig::INVALID_END ) , c.endStates[ 2 ] );
|
||
|
CPPUNIT_ASSERT_EQUAL( uint32_t( T_SRDParserConfig::INVALID_END ) , c.endStates[ 3 ] );
|
||
|
CPPUNIT_ASSERT_EQUAL( uint32_t( 2 ) , c.endStates[ 4 ] );
|
||
|
CPPUNIT_ASSERT_EQUAL( uint32_t( 1 ) , c.endStates[ 5 ] );
|
||
|
CPPUNIT_ASSERT_EQUAL( uint32_t( 2 ) , c.endStates[ 6 ] );
|
||
|
CPPUNIT_ASSERT_EQUAL( uint32_t( 2 ) , c.endStates[ 7 ] );
|
||
|
|
||
|
CPPUNIT_ASSERT_EQUAL( uint32_t( 8 ) , c.transitions.size( ) );
|
||
|
CPPUNIT_ASSERT_EQUAL( uint32_t( 1 ) , c.transitions.sizeOf( 0 ) );
|
||
|
CPPUNIT_ASSERT_EQUAL( uint32_t( 2 ) , c.transitions.sizeOf( 1 ) );
|
||
|
CPPUNIT_ASSERT_EQUAL( uint32_t( 1 ) , c.transitions.sizeOf( 2 ) );
|
||
|
CPPUNIT_ASSERT_EQUAL( uint32_t( 1 ) , c.transitions.sizeOf( 3 ) );
|
||
|
CPPUNIT_ASSERT_EQUAL( uint32_t( 1 ) , c.transitions.sizeOf( 4 ) );
|
||
|
CPPUNIT_ASSERT_EQUAL( uint32_t( 0 ) , c.transitions.sizeOf( 5 ) );
|
||
|
CPPUNIT_ASSERT_EQUAL( uint32_t( 1 ) , c.transitions.sizeOf( 6 ) );
|
||
|
CPPUNIT_ASSERT_EQUAL( uint32_t( 0 ) , c.transitions.sizeOf( 7 ) );
|
||
|
|
||
|
// 0: "a" -> 1
|
||
|
{
|
||
|
auto const& t( c.transitions.get( 0 , 0 ) );
|
||
|
CPPUNIT_ASSERT( E_SRDTransitionType::WORD == t.type );
|
||
|
CPPUNIT_ASSERT_EQUAL( uint32_t( 0 ) , t.index );
|
||
|
CPPUNIT_ASSERT_EQUAL( uint32_t( 1 ) , t.next );
|
||
|
}
|
||
|
|
||
|
// 1: "a" -> 2
|
||
|
{
|
||
|
auto const& t( c.transitions.get( 1 , 0 ) );
|
||
|
CPPUNIT_ASSERT( E_SRDTransitionType::WORD == t.type );
|
||
|
CPPUNIT_ASSERT_EQUAL( uint32_t( 0 ) , t.index );
|
||
|
CPPUNIT_ASSERT_EQUAL( uint32_t( 2 ) , t.next );
|
||
|
}
|
||
|
// 1: "b" -> 3
|
||
|
{
|
||
|
auto const& t( c.transitions.get( 1 , 1 ) );
|
||
|
CPPUNIT_ASSERT( E_SRDTransitionType::WORD == t.type );
|
||
|
CPPUNIT_ASSERT_EQUAL( uint32_t( 1 ) , t.index );
|
||
|
CPPUNIT_ASSERT_EQUAL( uint32_t( 3 ) , t.next );
|
||
|
}
|
||
|
|
||
|
// 2: "a" -> 4
|
||
|
{
|
||
|
auto const& t( c.transitions.get( 2 , 0 ) );
|
||
|
CPPUNIT_ASSERT( E_SRDTransitionType::WORD == t.type );
|
||
|
CPPUNIT_ASSERT_EQUAL( uint32_t( 0 ) , t.index );
|
||
|
CPPUNIT_ASSERT_EQUAL( uint32_t( 4 ) , t.next );
|
||
|
}
|
||
|
|
||
|
// 3: "a" -> 5
|
||
|
{
|
||
|
auto const& t( c.transitions.get( 3 , 0 ) );
|
||
|
CPPUNIT_ASSERT( E_SRDTransitionType::WORD == t.type );
|
||
|
CPPUNIT_ASSERT_EQUAL( uint32_t( 0 ) , t.index );
|
||
|
CPPUNIT_ASSERT_EQUAL( uint32_t( 5 ) , t.next );
|
||
|
}
|
||
|
|
||
|
// 4: "a" -> 6
|
||
|
{
|
||
|
auto const& t( c.transitions.get( 4 , 0 ) );
|
||
|
CPPUNIT_ASSERT( E_SRDTransitionType::WORD == t.type );
|
||
|
CPPUNIT_ASSERT_EQUAL( uint32_t( 0 ) , t.index );
|
||
|
CPPUNIT_ASSERT_EQUAL( uint32_t( 6 ) , t.next );
|
||
|
}
|
||
|
|
||
|
// 6: "a" -> 7
|
||
|
{
|
||
|
auto const& t( c.transitions.get( 6 , 0 ) );
|
||
|
CPPUNIT_ASSERT( E_SRDTransitionType::WORD == t.type );
|
||
|
CPPUNIT_ASSERT_EQUAL( uint32_t( 0 ) , t.index );
|
||
|
CPPUNIT_ASSERT_EQUAL( uint32_t( 7 ) , t.next );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/*----------------------------------------------------------------------------*/
|
||
|
|
||
|
void SRDParserConfigTest::testWordIndex( )
|
||
|
{
|
||
|
T_SRDParserDefs d( T_String( "test" ) );
|
||
|
{
|
||
|
using namespace SRD;
|
||
|
d.context( T_String( "test" ) )
|
||
|
<< ( Rule( ) << "test" << "and" << "test" );
|
||
|
d.context( T_String( "unused" ) )
|
||
|
<< ( Rule( ) << "not" << "in" << "the" << "index" );
|
||
|
}
|
||
|
|
||
|
T_SRDParserConfig c( d );
|
||
|
CPPUNIT_ASSERT_EQUAL( uint32_t( 2 ) , c.words.size( ) );
|
||
|
CPPUNIT_ASSERT( c.words[ 0 ] == T_String( "test" ) );
|
||
|
CPPUNIT_ASSERT( c.words[ 1 ] == T_String( "and" ) );
|
||
|
}
|
||
|
|
||
|
/*----------------------------------------------------------------------------*/
|
||
|
|
||
|
void SRDParserConfigTest::testRuleSimple( )
|
||
|
{
|
||
|
T_SRDParserDefs d( T_String( "test" ) );
|
||
|
{
|
||
|
using namespace SRD;
|
||
|
d.context( T_String( "test" ) )
|
||
|
<< ( Rule( ) << "test" );
|
||
|
}
|
||
|
|
||
|
T_SRDParserConfig c( d );
|
||
|
CPPUNIT_ASSERT_EQUAL( uint32_t( 1 ) , c.contexts.size( ) );
|
||
|
CPPUNIT_ASSERT_EQUAL( uint32_t( 1 ) , c.startStates.size( ) );
|
||
|
CPPUNIT_ASSERT_EQUAL( uint32_t( 0 ) , c.startStates[ 0 ] );
|
||
|
|
||
|
CPPUNIT_ASSERT_EQUAL( uint32_t( 2 ) , c.endStates.size( ) );
|
||
|
CPPUNIT_ASSERT_EQUAL( uint32_t( T_SRDParserConfig::INVALID_END ) , c.endStates[ 0 ] );
|
||
|
CPPUNIT_ASSERT_EQUAL( uint32_t( 0 ) , c.endStates[ 1 ] );
|
||
|
|
||
|
CPPUNIT_ASSERT_EQUAL( uint32_t( 2 ) , c.transitions.size( ) );
|
||
|
CPPUNIT_ASSERT_EQUAL( uint32_t( 1 ) , c.transitions.sizeOf( 0 ) );
|
||
|
CPPUNIT_ASSERT_EQUAL( uint32_t( 0 ) , c.transitions.sizeOf( 1 ) );
|
||
|
|
||
|
auto const& t( c.transitions.get( 0 , 0 ) );
|
||
|
CPPUNIT_ASSERT( E_SRDTransitionType::WORD == t.type );
|
||
|
CPPUNIT_ASSERT_EQUAL( uint32_t( 0 ) , t.index );
|
||
|
CPPUNIT_ASSERT_EQUAL( uint32_t( 1 ) , t.next );
|
||
|
}
|
||
|
|
||
|
void SRDParserConfigTest::testRuleABStarABB( )
|
||
|
{
|
||
|
T_SRDParserDefs d( T_String( "test" ) );
|
||
|
{
|
||
|
using namespace SRD;
|
||
|
d.context( T_String( "test" ) )
|
||
|
<< ( Rule( )
|
||
|
<< ( AtLeast( 0 ) << ( Alt( ) << "a" << "b" ) )
|
||
|
<< "a" << "b" << "b" );
|
||
|
}
|
||
|
|
||
|
T_SRDParserConfig c( d );
|
||
|
CPPUNIT_ASSERT_EQUAL( uint32_t( 1 ) , c.contexts.size( ) );
|
||
|
CPPUNIT_ASSERT_EQUAL( uint32_t( 1 ) , c.startStates.size( ) );
|
||
|
CPPUNIT_ASSERT_EQUAL( uint32_t( 0 ) , c.startStates[ 0 ] );
|
||
|
|
||
|
CPPUNIT_ASSERT_EQUAL( uint32_t( 4 ) , c.endStates.size( ) );
|
||
|
CPPUNIT_ASSERT_EQUAL( uint32_t( T_SRDParserConfig::INVALID_END ) , c.endStates[ 0 ] );
|
||
|
CPPUNIT_ASSERT_EQUAL( uint32_t( T_SRDParserConfig::INVALID_END ) , c.endStates[ 1 ] );
|
||
|
CPPUNIT_ASSERT_EQUAL( uint32_t( T_SRDParserConfig::INVALID_END ) , c.endStates[ 2 ] );
|
||
|
CPPUNIT_ASSERT_EQUAL( uint32_t( 0 ) , c.endStates[ 3 ] );
|
||
|
|
||
|
CPPUNIT_ASSERT_EQUAL( uint32_t( 4 ) , c.transitions.size( ) );
|
||
|
CPPUNIT_ASSERT_EQUAL( uint32_t( 2 ) , c.transitions.sizeOf( 0 ) );
|
||
|
CPPUNIT_ASSERT_EQUAL( uint32_t( 2 ) , c.transitions.sizeOf( 1 ) );
|
||
|
CPPUNIT_ASSERT_EQUAL( uint32_t( 2 ) , c.transitions.sizeOf( 2 ) );
|
||
|
CPPUNIT_ASSERT_EQUAL( uint32_t( 2 ) , c.transitions.sizeOf( 3 ) );
|
||
|
|
||
|
// 0: "a" -> 1
|
||
|
{
|
||
|
auto const& t( c.transitions.get( 0 , 0 ) );
|
||
|
CPPUNIT_ASSERT( E_SRDTransitionType::WORD == t.type );
|
||
|
CPPUNIT_ASSERT_EQUAL( uint32_t( 0 ) , t.index );
|
||
|
CPPUNIT_ASSERT_EQUAL( uint32_t( 1 ) , t.next );
|
||
|
}
|
||
|
// 0: "b" -> 0
|
||
|
{
|
||
|
auto const& t( c.transitions.get( 0 , 1 ) );
|
||
|
CPPUNIT_ASSERT( E_SRDTransitionType::WORD == t.type );
|
||
|
CPPUNIT_ASSERT_EQUAL( uint32_t( 1 ) , t.index );
|
||
|
CPPUNIT_ASSERT_EQUAL( uint32_t( 0 ) , t.next );
|
||
|
}
|
||
|
|
||
|
// 1: "a" -> 1
|
||
|
{
|
||
|
auto const& t( c.transitions.get( 1 , 0 ) );
|
||
|
CPPUNIT_ASSERT( E_SRDTransitionType::WORD == t.type );
|
||
|
CPPUNIT_ASSERT_EQUAL( uint32_t( 0 ) , t.index );
|
||
|
CPPUNIT_ASSERT_EQUAL( uint32_t( 1 ) , t.next );
|
||
|
}
|
||
|
// 1: "b" -> 2
|
||
|
{
|
||
|
auto const& t( c.transitions.get( 1 , 1 ) );
|
||
|
CPPUNIT_ASSERT( E_SRDTransitionType::WORD == t.type );
|
||
|
CPPUNIT_ASSERT_EQUAL( uint32_t( 1 ) , t.index );
|
||
|
CPPUNIT_ASSERT_EQUAL( uint32_t( 2 ) , t.next );
|
||
|
}
|
||
|
|
||
|
// 2: "a" -> 1
|
||
|
{
|
||
|
auto const& t( c.transitions.get( 2 , 0 ) );
|
||
|
CPPUNIT_ASSERT( E_SRDTransitionType::WORD == t.type );
|
||
|
CPPUNIT_ASSERT_EQUAL( uint32_t( 0 ) , t.index );
|
||
|
CPPUNIT_ASSERT_EQUAL( uint32_t( 1 ) , t.next );
|
||
|
}
|
||
|
// 2: "b" -> 3
|
||
|
{
|
||
|
auto const& t( c.transitions.get( 2 , 1 ) );
|
||
|
CPPUNIT_ASSERT( E_SRDTransitionType::WORD == t.type );
|
||
|
CPPUNIT_ASSERT_EQUAL( uint32_t( 1 ) , t.index );
|
||
|
CPPUNIT_ASSERT_EQUAL( uint32_t( 3 ) , t.next );
|
||
|
}
|
||
|
|
||
|
// 3: "a" -> 1
|
||
|
{
|
||
|
auto const& t( c.transitions.get( 3 , 0 ) );
|
||
|
CPPUNIT_ASSERT( E_SRDTransitionType::WORD == t.type );
|
||
|
CPPUNIT_ASSERT_EQUAL( uint32_t( 0 ) , t.index );
|
||
|
CPPUNIT_ASSERT_EQUAL( uint32_t( 1 ) , t.next );
|
||
|
}
|
||
|
// 3: "b" -> 0
|
||
|
{
|
||
|
auto const& t( c.transitions.get( 3 , 1 ) );
|
||
|
CPPUNIT_ASSERT( E_SRDTransitionType::WORD == t.type );
|
||
|
CPPUNIT_ASSERT_EQUAL( uint32_t( 1 ) , t.index );
|
||
|
CPPUNIT_ASSERT_EQUAL( uint32_t( 0 ) , t.next );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void SRDParserConfigTest::testMergedRules( )
|
||
|
{
|
||
|
T_SRDParserDefs d( T_String( "test" ) );
|
||
|
{
|
||
|
using namespace SRD;
|
||
|
d.context( T_String( "test" ) )
|
||
|
<< ( Rule( ) << "a" )
|
||
|
<< ( Rule( ) << "a" << "b" << "a" )
|
||
|
<< ( Rule( ) << ( Between( 3 , 5 ) << "a" ) );
|
||
|
}
|
||
|
|
||
|
T_SRDParserConfig c( d );
|
||
|
CPPUNIT_ASSERT_EQUAL( uint32_t( 1 ) , c.contexts.size( ) );
|
||
|
checkMergedRules( c );
|
||
|
}
|
||
|
|
||
|
void SRDParserConfigTest::testRulesMultiContexts( )
|
||
|
{
|
||
|
T_SRDParserDefs d( T_String( "test" ) );
|
||
|
{
|
||
|
using namespace SRD;
|
||
|
d.context( T_String( "test" ) )
|
||
|
<< ( Rule( ) << "test" << EnterContext( "other" ) );
|
||
|
d.context( T_String( "other" ) )
|
||
|
<< ( Rule( ) << "test" );
|
||
|
}
|
||
|
|
||
|
T_SRDParserConfig c( d );
|
||
|
CPPUNIT_ASSERT_EQUAL( uint32_t( 2 ) , c.contexts.size( ) );
|
||
|
CPPUNIT_ASSERT_EQUAL( uint32_t( 2 ) , c.startStates.size( ) );
|
||
|
CPPUNIT_ASSERT_EQUAL( uint32_t( 0 ) , c.startStates[ 0 ] );
|
||
|
CPPUNIT_ASSERT_EQUAL( uint32_t( 2 ) , c.startStates[ 1 ] );
|
||
|
|
||
|
CPPUNIT_ASSERT_EQUAL( uint32_t( 4 ) , c.endStates.size( ) );
|
||
|
CPPUNIT_ASSERT_EQUAL( uint32_t( T_SRDParserConfig::INVALID_END ) , c.endStates[ 0 ] );
|
||
|
CPPUNIT_ASSERT_EQUAL( uint32_t( 0 ) , c.endStates[ 1 ] );
|
||
|
CPPUNIT_ASSERT_EQUAL( uint32_t( T_SRDParserConfig::INVALID_END ) , c.endStates[ 2 ] );
|
||
|
CPPUNIT_ASSERT_EQUAL( uint32_t( 0 ) , c.endStates[ 3 ] );
|
||
|
|
||
|
CPPUNIT_ASSERT_EQUAL( uint32_t( 4 ) , c.transitions.size( ) );
|
||
|
CPPUNIT_ASSERT_EQUAL( uint32_t( 1 ) , c.transitions.sizeOf( 0 ) );
|
||
|
CPPUNIT_ASSERT_EQUAL( uint32_t( 0 ) , c.transitions.sizeOf( 1 ) );
|
||
|
CPPUNIT_ASSERT_EQUAL( uint32_t( 1 ) , c.transitions.sizeOf( 2 ) );
|
||
|
CPPUNIT_ASSERT_EQUAL( uint32_t( 0 ) , c.transitions.sizeOf( 3 ) );
|
||
|
|
||
|
{
|
||
|
auto const& t( c.transitions.get( 0 , 0 ) );
|
||
|
CPPUNIT_ASSERT( E_SRDTransitionType::WORD == t.type );
|
||
|
CPPUNIT_ASSERT_EQUAL( uint32_t( 0 ) , t.index );
|
||
|
CPPUNIT_ASSERT_EQUAL( uint32_t( 1 ) , t.next );
|
||
|
}
|
||
|
{
|
||
|
auto const& t( c.transitions.get( 2 , 0 ) );
|
||
|
CPPUNIT_ASSERT( E_SRDTransitionType::WORD == t.type );
|
||
|
CPPUNIT_ASSERT_EQUAL( uint32_t( 0 ) , t.index );
|
||
|
CPPUNIT_ASSERT_EQUAL( uint32_t( 3 ) , t.next );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/*----------------------------------------------------------------------------*/
|
||
|
|
||
|
void SRDParserConfigTest::testContextIDs( )
|
||
|
{
|
||
|
T_SRDParserDefs d( T_String( "test" ) );
|
||
|
{
|
||
|
using namespace SRD;
|
||
|
d.context( T_String( "test" ) )
|
||
|
<< ( Rule( ) << "test" << EnterContext( "other" ) )
|
||
|
<< ( Rule( ) << "test" << "number" << "two"
|
||
|
<< EnterContext( "other" ) )
|
||
|
<< ( Rule( ) << "yet" << "another" << "test"
|
||
|
<< EnterContext( "other" ) )
|
||
|
<< ( Rule( ) << "moar" << EnterContext( "moar" ) )
|
||
|
;
|
||
|
d.context( T_String( "other" ) )
|
||
|
<< ( Rule( ) << "test" );
|
||
|
|
||
|
d.context( T_String( "moar" ) )
|
||
|
<< ( Rule( ) << "test" );
|
||
|
}
|
||
|
|
||
|
T_SRDParserConfig c( d );
|
||
|
CPPUNIT_ASSERT_EQUAL( uint32_t( 3 ) , c.ruleContexts.size( ) );
|
||
|
CPPUNIT_ASSERT_EQUAL( uint32_t( 4 ) , c.ruleContexts.sizeOf( 0 ) );
|
||
|
CPPUNIT_ASSERT_EQUAL( uint32_t( 1 ) , c.ruleContexts.sizeOf( 1 ) );
|
||
|
CPPUNIT_ASSERT_EQUAL( uint32_t( 1 ) , c.ruleContexts.sizeOf( 2 ) );
|
||
|
|
||
|
CPPUNIT_ASSERT_EQUAL( uint32_t( 1 ) , c.ruleContexts[ 0 ] );
|
||
|
CPPUNIT_ASSERT_EQUAL( uint32_t( 1 ) , c.ruleContexts[ 1 ] );
|
||
|
CPPUNIT_ASSERT_EQUAL( uint32_t( 1 ) , c.ruleContexts[ 2 ] );
|
||
|
CPPUNIT_ASSERT_EQUAL( uint32_t( 2 ) , c.ruleContexts[ 3 ] );
|
||
|
CPPUNIT_ASSERT_EQUAL( uint32_t( T_SRDParserConfig::INVALID_END ) , c.ruleContexts[ 4 ] );
|
||
|
CPPUNIT_ASSERT_EQUAL( uint32_t( T_SRDParserConfig::INVALID_END ) , c.ruleContexts[ 5 ] );
|
||
|
}
|
||
|
|
||
|
void SRDParserConfigTest::testEnumIDs( )
|
||
|
{
|
||
|
T_String n( T_String::Pooled( "test" ) );
|
||
|
T_SRDParserDefs d( n );
|
||
|
{
|
||
|
using namespace SRD;
|
||
|
d.enumeration( n ) << "a" << "b";
|
||
|
d.context( n )
|
||
|
<< ( Rule( ) << Enum( "test" ) );
|
||
|
}
|
||
|
|
||
|
T_SRDParserConfig c( d );
|
||
|
|
||
|
CPPUNIT_ASSERT_EQUAL( uint32_t( 1 ) , c.enums.size( ) );
|
||
|
CPPUNIT_ASSERT( c.enums[ 0 ].name( ) == n );
|
||
|
|
||
|
CPPUNIT_ASSERT_EQUAL( uint32_t( 1 ) , c.contexts.size( ) );
|
||
|
CPPUNIT_ASSERT_EQUAL( uint32_t( 1 ) , c.startStates.size( ) );
|
||
|
CPPUNIT_ASSERT_EQUAL( uint32_t( 0 ) , c.startStates[ 0 ] );
|
||
|
|
||
|
CPPUNIT_ASSERT_EQUAL( uint32_t( 2 ) , c.endStates.size( ) );
|
||
|
CPPUNIT_ASSERT_EQUAL( uint32_t( T_SRDParserConfig::INVALID_END ) , c.endStates[ 0 ] );
|
||
|
CPPUNIT_ASSERT_EQUAL( uint32_t( 0 ) , c.endStates[ 1 ] );
|
||
|
|
||
|
CPPUNIT_ASSERT_EQUAL( uint32_t( 2 ) , c.transitions.size( ) );
|
||
|
CPPUNIT_ASSERT_EQUAL( uint32_t( 1 ) , c.transitions.sizeOf( 0 ) );
|
||
|
CPPUNIT_ASSERT_EQUAL( uint32_t( 0 ) , c.transitions.sizeOf( 1 ) );
|
||
|
|
||
|
auto const& t( c.transitions.get( 0 , 0 ) );
|
||
|
CPPUNIT_ASSERT( E_SRDTransitionType::ENUM == t.type );
|
||
|
CPPUNIT_ASSERT_EQUAL( uint32_t( 0 ) , t.index );
|
||
|
CPPUNIT_ASSERT_EQUAL( uint32_t( 1 ) , t.next );
|
||
|
}
|
||
|
|
||
|
/*----------------------------------------------------------------------------*/
|
||
|
|
||
|
void SRDParserConfigTest::testUnusedEnums( )
|
||
|
{
|
||
|
T_SRDParserDefs d( T_String( "test" ) );
|
||
|
{
|
||
|
using namespace SRD;
|
||
|
d.context( T_String( "test" ) )
|
||
|
<< ( Rule( ) << "test" );
|
||
|
d.enumeration( T_String( "Blah" ) )
|
||
|
<< "a" << "b";
|
||
|
}
|
||
|
|
||
|
T_SRDParserConfig c( d );
|
||
|
CPPUNIT_ASSERT_EQUAL( uint32_t( 0 ) , c.enums.size( ) );
|
||
|
}
|
||
|
|
||
|
void SRDParserConfigTest::testUnusedContexts( )
|
||
|
{
|
||
|
T_SRDParserDefs d( T_String( "test" ) );
|
||
|
{
|
||
|
using namespace SRD;
|
||
|
d.context( T_String( "test" ) )
|
||
|
<< ( Rule( ) << "test" );
|
||
|
d.context( T_String( "other" ) )
|
||
|
<< ( Rule( ) << "test" );
|
||
|
}
|
||
|
|
||
|
T_SRDParserConfig c( d );
|
||
|
CPPUNIT_ASSERT_EQUAL( uint32_t( 1 ) , c.contexts.size( ) );
|
||
|
CPPUNIT_ASSERT( c.contexts[ 0 ].name( ) == T_String( "test" ) );
|
||
|
}
|
||
|
|
||
|
/*----------------------------------------------------------------------------*/
|
||
|
|
||
|
void SRDParserConfigTest::testContextInheritance( )
|
||
|
{
|
||
|
const T_String n0( T_String::Pooled( "test" ) );
|
||
|
const T_String n1( T_String::Pooled( "child" ) );
|
||
|
|
||
|
T_SRDParserDefs d( n0 );
|
||
|
{
|
||
|
using namespace SRD;
|
||
|
d.context( n0 )
|
||
|
<< ( Rule( ) << "a" );
|
||
|
d.context( n1 , n0 )
|
||
|
<< ( Rule( ) << "a" << "b" << "a" )
|
||
|
<< ( Rule( ) << ( Between( 3 , 5 ) << "a" ) );
|
||
|
d.defaultContext( n1 );
|
||
|
}
|
||
|
|
||
|
T_SRDParserConfig c( d );
|
||
|
CPPUNIT_ASSERT_EQUAL( uint32_t( 1 ) , c.contexts.size( ) );
|
||
|
CPPUNIT_ASSERT( c.contexts[ 0 ].name( ) == n1 );
|
||
|
checkMergedRules( c );
|
||
|
}
|
||
|
|
||
|
/*----------------------------------------------------------------------------*/
|
||
|
|
||
|
void SRDParserConfigTest::testErrorMissingCtxRule( )
|
||
|
{
|
||
|
T_SRDParserDefs d( T_String( "test" ) );
|
||
|
{
|
||
|
using namespace SRD;
|
||
|
d.context( T_String( "test" ) )
|
||
|
<< ( Rule( ) << "a" << EnterContext( "nope" ) );
|
||
|
}
|
||
|
CPPUNIT_ASSERT_THROW( NewOwned< T_SRDParserConfig >( d ) , X_SRDParserConfig );
|
||
|
}
|
||
|
|
||
|
void SRDParserConfigTest::testErrorMissingCtxParent( )
|
||
|
{
|
||
|
T_SRDParserDefs d( T_String( "test" ) );
|
||
|
{
|
||
|
using namespace SRD;
|
||
|
d.context( T_String( "fail" ) , T_String( "parent" ) )
|
||
|
<< ( Rule( ) << "a" );
|
||
|
d.defaultContext( T_String( "fail" ) );
|
||
|
}
|
||
|
CPPUNIT_ASSERT_THROW( NewOwned< T_SRDParserConfig >( d ) , X_SRDParserConfig );
|
||
|
}
|
||
|
|
||
|
void SRDParserConfigTest::testErrorMissingEnum( )
|
||
|
{
|
||
|
T_SRDParserDefs d( T_String( "test" ) );
|
||
|
{
|
||
|
using namespace SRD;
|
||
|
d.context( T_String( "test" ) )
|
||
|
<< ( Rule( ) << Enum( "nope" ) );
|
||
|
}
|
||
|
CPPUNIT_ASSERT_THROW( NewOwned< T_SRDParserConfig >( d ) , X_SRDParserConfig );
|
||
|
}
|
||
|
|
||
|
void SRDParserConfigTest::testErrorEmptyContext( )
|
||
|
{
|
||
|
T_SRDParserDefs d( T_String( "test" ) );
|
||
|
CPPUNIT_ASSERT_THROW( NewOwned< T_SRDParserConfig >( d ) , X_SRDParserConfig );
|
||
|
}
|
||
|
|
||
|
void SRDParserConfigTest::testErrorEmptyRule( )
|
||
|
{
|
||
|
T_SRDParserDefs d( T_String( "test" ) );
|
||
|
{
|
||
|
using namespace SRD;
|
||
|
d.context( T_String( "test" ) ) << Rule( );
|
||
|
}
|
||
|
CPPUNIT_ASSERT_THROW( NewOwned< T_SRDParserConfig >( d ) , X_SRDParserConfig );
|
||
|
}
|
||
|
|
||
|
void SRDParserConfigTest::testErrorEmptyAlt( )
|
||
|
{
|
||
|
T_SRDParserDefs d( T_String( "test" ) );
|
||
|
{
|
||
|
using namespace SRD;
|
||
|
d.context( T_String( "test" ) ) << ( Rule( ) << Alt( ) );
|
||
|
}
|
||
|
CPPUNIT_ASSERT_THROW( NewOwned< T_SRDParserConfig >( d ) , X_SRDParserConfig );
|
||
|
}
|
||
|
|
||
|
void SRDParserConfigTest::testErrorEmptyRepeat( )
|
||
|
{
|
||
|
T_SRDParserDefs d( T_String( "test" ) );
|
||
|
{
|
||
|
using namespace SRD;
|
||
|
d.context( T_String( "test" ) ) << ( Rule( ) << Opt( ) );
|
||
|
}
|
||
|
CPPUNIT_ASSERT_THROW( NewOwned< T_SRDParserConfig >( d ) , X_SRDParserConfig );
|
||
|
}
|
||
|
|
||
|
void SRDParserConfigTest::testErrorRecursiveInheritance( )
|
||
|
{
|
||
|
T_SRDParserDefs d( T_String( "test" ) );
|
||
|
{
|
||
|
using namespace SRD;
|
||
|
d.context( T_String( "fail" ) , T_String( "parent" ) )
|
||
|
<< ( Rule( ) << "a" );
|
||
|
d.context( T_String( "parent" ) , T_String( "fail" ) )
|
||
|
<< ( Rule( ) << "b" );
|
||
|
d.defaultContext( T_String( "fail" ) );
|
||
|
}
|
||
|
CPPUNIT_ASSERT_THROW( NewOwned< T_SRDParserConfig >( d ) , X_SRDParserConfig );
|
||
|
}
|
||
|
|
||
|
void SRDParserConfigTest::testErrorAmbiguousRules( )
|
||
|
{
|
||
|
T_SRDParserDefs d( T_String( "test" ) );
|
||
|
{
|
||
|
using namespace SRD;
|
||
|
d.context( T_String( "test" ) )
|
||
|
<< ( Rule( ) << ( AtLeast( 1 ) << "a" ) )
|
||
|
<< ( Rule( ) << "a" )
|
||
|
;
|
||
|
}
|
||
|
CPPUNIT_ASSERT_THROW( NewOwned< T_SRDParserConfig >( d ) , X_SRDParserConfig );
|
||
|
}
|
||
|
|
||
|
/*----------------------------------------------------------------------------*/
|
||
|
|
||
|
void SRDParserConfigTest::testErrorUBRSimpleOK( )
|
||
|
{
|
||
|
T_SRDParserDefs d( T_String( "test" ) );
|
||
|
{
|
||
|
using namespace SRD;
|
||
|
d.context( T_String( "test" ) )
|
||
|
<< ( Rule( ) << LStart( ) << "a" << LEnd( ) )
|
||
|
;
|
||
|
}
|
||
|
T_SRDParserConfig{ d };
|
||
|
}
|
||
|
|
||
|
void SRDParserConfigTest::testErrorUBRSimpleUnbalancedStart( )
|
||
|
{
|
||
|
T_SRDParserDefs d( T_String( "test" ) );
|
||
|
{
|
||
|
using namespace SRD;
|
||
|
d.context( T_String( "test" ) )
|
||
|
<< ( Rule( ) << LStart( ) << "a" )
|
||
|
;
|
||
|
}
|
||
|
CPPUNIT_ASSERT_THROW( T_SRDParserConfig{ d } , X_SRDParserConfig );
|
||
|
}
|
||
|
|
||
|
void SRDParserConfigTest::testErrorUBRSimpleUnbalancedEnd( )
|
||
|
{
|
||
|
T_SRDParserDefs d( T_String( "test" ) );
|
||
|
{
|
||
|
using namespace SRD;
|
||
|
d.context( T_String( "test" ) )
|
||
|
<< ( Rule( ) << "a" << LEnd( ) )
|
||
|
;
|
||
|
}
|
||
|
CPPUNIT_ASSERT_THROW( T_SRDParserConfig{ d } , X_SRDParserConfig );
|
||
|
}
|
||
|
|
||
|
void SRDParserConfigTest::testErrorUBRAltsOKContained( )
|
||
|
{
|
||
|
T_SRDParserDefs d( T_String( "test" ) );
|
||
|
{
|
||
|
using namespace SRD;
|
||
|
d.context( T_String( "test" ) )
|
||
|
<< ( Rule( )
|
||
|
<< ( Alt( )
|
||
|
<< ( Sub( ) << LStart( ) << "a" << LEnd( ) )
|
||
|
<< ( Sub( ) << LStart( ) << "b" << LEnd( ) )
|
||
|
<< "c" ) )
|
||
|
;
|
||
|
}
|
||
|
T_SRDParserConfig{ d };
|
||
|
}
|
||
|
|
||
|
void SRDParserConfigTest::testErrorUBRAltsOKBalancing( )
|
||
|
{
|
||
|
T_SRDParserDefs d( "test" );
|
||
|
{
|
||
|
using namespace SRD;
|
||
|
d.context( "test" )
|
||
|
<< ( Rule( )
|
||
|
<< ( Alt( )
|
||
|
<< ( Sub( ) << LStart( ) << "a" )
|
||
|
<< ( Sub( ) << LStart( ) << "b" ) )
|
||
|
<< "c"
|
||
|
<< ( Alt( )
|
||
|
<< ( Sub( ) << "d" << LEnd( ) )
|
||
|
<< ( Sub( ) << "e" << LEnd( ) ) ) )
|
||
|
;
|
||
|
}
|
||
|
T_SRDParserConfig{ d };
|
||
|
}
|
||
|
|
||
|
void SRDParserConfigTest::testErrorUBRAltsDifferent( )
|
||
|
{
|
||
|
T_SRDParserDefs d( "test" );
|
||
|
{
|
||
|
using namespace SRD;
|
||
|
d.context( "test" )
|
||
|
<< ( Rule( )
|
||
|
<< ( Alt( ) << LStart( ) << LEnd( ) ) );
|
||
|
}
|
||
|
CPPUNIT_ASSERT_THROW( T_SRDParserConfig{ d } , X_SRDParserConfig );
|
||
|
}
|
||
|
|
||
|
void SRDParserConfigTest::testErrorUBRAltsUnbalanced( )
|
||
|
{
|
||
|
T_SRDParserDefs d( "test" );
|
||
|
{
|
||
|
using namespace SRD;
|
||
|
d.context( "test" )
|
||
|
<< ( Rule( )
|
||
|
<< ( Alt( )
|
||
|
<< ( Sub( ) << LStart( ) << "a" )
|
||
|
<< ( Sub( ) << LStart( ) << "b" ) ) );
|
||
|
}
|
||
|
CPPUNIT_ASSERT_THROW( T_SRDParserConfig{ d } , X_SRDParserConfig );
|
||
|
}
|
||
|
|
||
|
void SRDParserConfigTest::testErrorUBRRepsOK( )
|
||
|
{
|
||
|
T_SRDParserDefs d( "test" );
|
||
|
{
|
||
|
using namespace SRD;
|
||
|
d.context( "test" )
|
||
|
<< ( Rule( )
|
||
|
<< ( Times( 5 ) << LStart( ) )
|
||
|
<< ( Times( 3 ) << LEnd( ) )
|
||
|
<< LEnd( ) << LEnd( ) );
|
||
|
}
|
||
|
T_SRDParserConfig{ d };
|
||
|
}
|
||
|
|
||
|
void SRDParserConfigTest::testErrorUBRRepsUnbalanced( )
|
||
|
{
|
||
|
T_SRDParserDefs d( "test" );
|
||
|
{
|
||
|
using namespace SRD;
|
||
|
d.context( "test" )
|
||
|
<< ( Rule( )
|
||
|
<< ( Between( 1 , 5 ) << LStart( ) )
|
||
|
<< ( Between( 1 , 5 ) << LEnd( ) ) );
|
||
|
}
|
||
|
CPPUNIT_ASSERT_THROW( T_SRDParserConfig{ d } , X_SRDParserConfig );
|
||
|
}
|
||
|
|
||
|
/*----------------------------------------------------------------------------*/
|
||
|
|
||
|
void SRDParserConfigTest::testTransition( )
|
||
|
{
|
||
|
#define M_DO_TRANS( STATE , TOK ) \
|
||
|
uint32_t state( STATE ); \
|
||
|
bool result = c.transition( state , TOK )
|
||
|
|
||
|
#define M_CHECK_TRANS_OK( STATE , TOK , OUT ) \
|
||
|
do { \
|
||
|
M_DO_TRANS( STATE , TOK ); \
|
||
|
CPPUNIT_ASSERT( result ); \
|
||
|
CPPUNIT_ASSERT_EQUAL( uint32_t( OUT ) , state ); \
|
||
|
} while ( 0 )
|
||
|
|
||
|
#define M_CHECK_TRANS_FAIL( STATE , TOK ) \
|
||
|
do { \
|
||
|
M_DO_TRANS( STATE , TOK ); \
|
||
|
CPPUNIT_ASSERT( !result ); \
|
||
|
CPPUNIT_ASSERT_EQUAL( uint32_t( STATE ) , state ); \
|
||
|
} while ( 0 )
|
||
|
|
||
|
T_SRDParserDefs d( T_String( "test" ) );
|
||
|
{
|
||
|
using namespace SRD;
|
||
|
d.enumeration( T_String( "test" ) )
|
||
|
<< "a" << "b";
|
||
|
d.context( T_String( "test" ) )
|
||
|
<< ( Rule( ) << Int32( ) << "a" << Enum( "test" ) << Word( )
|
||
|
<< ( Alt( )
|
||
|
<< ( Sub( ) << "a" << "a" )
|
||
|
<< ( Sub( ) << Enum( "test" ) << "b" )
|
||
|
<< ( Sub( ) << Word( ) << "c" ) ) )
|
||
|
;
|
||
|
}
|
||
|
|
||
|
T_SRDParserConfig c( d );
|
||
|
T_SRDToken tInt( T_SRDToken::Integer( 1 ) ) ,
|
||
|
tWordA( T_SRDToken::Word( T_String( "a" ) ) ) ,
|
||
|
tWordB( T_SRDToken::Word( T_String( "b" ) ) ) ,
|
||
|
tWordC( T_SRDToken::Word( T_String( "c" ) ) );
|
||
|
|
||
|
M_CHECK_TRANS_OK( 0 , tInt , 1 );
|
||
|
M_CHECK_TRANS_FAIL( 0 , tWordA );
|
||
|
|
||
|
M_CHECK_TRANS_FAIL( 1 , tInt );
|
||
|
M_CHECK_TRANS_OK( 1 , tWordA , 2 );
|
||
|
M_CHECK_TRANS_FAIL( 1 , tWordB );
|
||
|
|
||
|
M_CHECK_TRANS_FAIL( 2 , tInt );
|
||
|
M_CHECK_TRANS_OK( 2 , tWordA , 3 );
|
||
|
M_CHECK_TRANS_OK( 2 , tWordB , 3 );
|
||
|
M_CHECK_TRANS_FAIL( 2 , tWordC );
|
||
|
|
||
|
M_CHECK_TRANS_FAIL( 3 , tInt );
|
||
|
M_CHECK_TRANS_OK( 3 , tWordA , 4 );
|
||
|
M_CHECK_TRANS_OK( 3 , tWordB , 4 );
|
||
|
M_CHECK_TRANS_OK( 3 , tWordC , 4 );
|
||
|
|
||
|
M_CHECK_TRANS_FAIL( 4 , tInt );
|
||
|
M_CHECK_TRANS_OK( 4 , tWordA , 6 );
|
||
|
M_CHECK_TRANS_OK( 4 , tWordB , 7 );
|
||
|
M_CHECK_TRANS_OK( 4 , tWordC , 5 );
|
||
|
}
|