corelib/tests/srd-parser-cfg.cc

785 lines
23 KiB
C++
Raw Normal View History

#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 );
}