#include #include #include #include using namespace lw; class SRDPreprocCoreTest : public CppUnit::TestFixture { CPPUNIT_TEST_SUITE( SRDPreprocCoreTest ); CPPUNIT_TEST( testEmptyInput ); CPPUNIT_TEST( testBasicInput ); CPPUNIT_TEST( testCommentsSkipped ); CPPUNIT_TEST( testCommandWordInInput ); CPPUNIT_TEST( testBadCommand ); CPPUNIT_TEST( testBadVariable ); CPPUNIT_TEST( testUnterminatedLists ); CPPUNIT_TEST( testTooManyErrorsInside ); CPPUNIT_TEST( testTooManyErrorsAtEnd ); CPPUNIT_TEST_SUITE_END( ); public: void testEmptyInput( ); void testBasicInput( ); void testCommentsSkipped( ); void testCommandWordInInput( ); void testBadCommand( ); void testBadVariable( ); void testUnterminatedLists( ); void testTooManyErrorsInside( ); void testTooManyErrorsAtEnd( ); }; CPPUNIT_TEST_SUITE_REGISTRATION( SRDPreprocCoreTest ); /*----------------------------------------------------------------------------*/ // M_PRINTERR_( index ) - Print an error message #define M_PRINTERR_( IDX ) \ do { \ auto const& _e( errors[ IDX ] ); \ char err[ _e.error( ).size( ) + 1 ]; \ err[ sizeof( err ) - 1 ] = 0; \ memcpy( err , _e.error( ).data( ) , \ sizeof( err ) - 1 ); \ printf( "ERR %s l. %u c. %lu\n" , err , \ _e.location( ).line( ) , \ _e.location( ).character( ) ); \ } while ( 0 ) // M_CKERR_( index , string , line , character ) - Check an error #define M_CKERR_( IDX , STR , L , C ) \ do { \ auto const& _e( errors[ IDX ] ); \ CPPUNIT_ASSERT( T_String( STR ) == _e.error( ) ); \ CPPUNIT_ASSERT_EQUAL( uint32_t( L ) , \ _e.location( ).line( ) ); \ CPPUNIT_ASSERT_EQUAL( size_t( C ) , \ _e.location( ).character( ) ); \ } while ( 0 ) namespace { T_SRDList process( char const* const input , T_SRDErrors& errors , const bool clearFlushToken = true ) { T_SRDMemoryTarget mt( false ); mt.clearFlushToken( clearFlushToken ); mt.start( errors ); T_SRDPreprocessorConfig cmd; cmd.addBuiltinCommands( ); T_SRDPreprocessor pp( cmd , mt ); T_SRDLexer lexer( T_String( "test" ) , errors , pp ); pp.start( errors ); char const* ptr = input; while ( *ptr != 0 ) { lexer.processCharacter( *ptr ++ ); } lexer.processEnd( ); mt.end( errors ); return mt.list( ); } bool checkMatch( T_SRDList const& expected , T_SRDList const& actual ) { const uint32_t nExpected( expected.size( ) ); const uint32_t nActual( actual.size( ) ); bool ok( nExpected == nActual ); const uint32_t nCheck( std::min( nExpected , nActual ) ); for ( uint32_t i = 0 ; i < nCheck ; i ++ ) { T_SRDToken const& tExpected( expected[ i ] ); T_SRDToken const& tActual( actual[ i ] ); if ( tExpected.type( ) != tActual.type( ) ) { std::cerr << "Expected token at " << tExpected.location( ).line( ) << ":" << tExpected.location( ).character( ) << " has type " << int( tExpected.type( ) ) << "; actual token has type " << int( tActual.type( ) ) << "\n"; ok = false; } else if ( tExpected.stringValue( ) != tActual.stringValue( ) ) { std::cerr << "Expected token at " << tExpected.location( ).line( ) << ":" << tExpected.location( ).character( ) << " has different text\n"; ok = false; } } if ( nExpected != nActual ) { std::cerr << "List size mismatch (" << nExpected << " expected, " << nActual << " found)\n"; } return ok; } bool check( char const* expected , T_SRDList const& actual ) { T_SRDMemoryTarget mt( false ); T_SRDErrors errors; T_SRDLexer lexer( T_String( "expected" ) , errors , mt ); mt.start( errors ); char const* ptr = expected; while ( *ptr != 0 ) { lexer.processCharacter( *ptr ++ ); } lexer.processEnd( ); return checkMatch( mt.list( ) , actual ); } } /*----------------------------------------------------------------------------*/ void SRDPreprocCoreTest::testEmptyInput( ) { T_SRDErrors errors; T_SRDList output( process( "" , errors ) ); CPPUNIT_ASSERT_EQUAL( uint32_t( 0 ) , errors.size( ) ); CPPUNIT_ASSERT( check( "" , output ) ); } void SRDPreprocCoreTest::testBasicInput( ) { T_SRDErrors errors; T_SRDList output( process( "this is a simple test 123 \"yes\" ( a test )" , errors ) ); CPPUNIT_ASSERT_EQUAL( uint32_t( 0 ) , errors.size( ) ); CPPUNIT_ASSERT( check( "this is a simple test 123 \"yes\" ( a test )" , output ) ); } void SRDPreprocCoreTest::testCommentsSkipped( ) { T_SRDErrors errors; T_SRDList output( process( "a {comment!} ( is #skipped!\n)" , errors ) ); CPPUNIT_ASSERT_EQUAL( uint32_t( 0 ) , errors.size( ) ); CPPUNIT_ASSERT( check( "a ( is )" , output ) ); } void SRDPreprocCoreTest::testCommandWordInInput( ) { T_SRDErrors errors; T_SRDList output( process( "-blah" , errors ) ); CPPUNIT_ASSERT_EQUAL( uint32_t( 0 ) , errors.size( ) ); CPPUNIT_ASSERT( check( "-blah" , output ) ); } void SRDPreprocCoreTest::testBadCommand( ) { T_SRDErrors errors; T_SRDList output( process( "( -blah )" , errors ) ); CPPUNIT_ASSERT_EQUAL( uint32_t( 1 ) , errors.size( ) ); M_CKERR_( 0 , "unknown command" , 1 , 3 ); CPPUNIT_ASSERT( check( "( -blah )" , output ) ); } void SRDPreprocCoreTest::testBadVariable( ) { T_SRDErrors errors; T_SRDList output( process( "$blah does not exist" , errors ) ); CPPUNIT_ASSERT_EQUAL( uint32_t( 1 ) , errors.size( ) ); M_CKERR_( 0 , "unknown variable" , 1 , 1 ); CPPUNIT_ASSERT( check( "does not exist" , output ) ); } void SRDPreprocCoreTest::testUnterminatedLists( ) { T_SRDErrors errors; T_SRDList output( process( "( ( ) ( (" , errors ) ); CPPUNIT_ASSERT_EQUAL( uint32_t( 3 ) , errors.size( ) ); M_CKERR_( 0 , "unterminated list" , 1 , 1 ); M_CKERR_( 1 , "unterminated list" , 1 , 7 ); M_CKERR_( 2 , "unterminated list" , 1 , 9 ); CPPUNIT_ASSERT( check( "( ( ) ( ( ) ) )" , output ) ); } namespace { T_StringBuilder RepeatError_( char const* string ) { T_StringBuilder sb; for ( uint32_t i = 0 ; i < T_SRDErrors::MAX_ERRORS * 2 ; i ++ ) { if ( i > 0 ) { sb << ' '; } sb << string; } sb << " x" << '\0'; return sb; } } void SRDPreprocCoreTest::testTooManyErrorsInside( ) { T_StringBuilder input( RepeatError_( "$x" ) ); T_SRDErrors errors; T_SRDList output( process( input.data( ) , errors ) ); CPPUNIT_ASSERT_EQUAL( uint32_t( T_SRDErrors::MAX_ERRORS + 1 ) , errors.size( ) ); M_CKERR_( T_SRDErrors::MAX_ERRORS , "too many errors" , 1 , T_SRDErrors::MAX_ERRORS * 3 - 2 ); CPPUNIT_ASSERT( check( "" , output ) ); } void SRDPreprocCoreTest::testTooManyErrorsAtEnd( ) { T_StringBuilder input( RepeatError_( "(" ) ); T_StringBuilder expectedOutput; for ( uint32_t i = 0 ; i < T_SRDErrors::MAX_ERRORS * 2 ; i ++ ) { expectedOutput << '('; } expectedOutput << 'x'; for ( uint32_t i = 0 ; i < T_SRDErrors::MAX_ERRORS * 2 ; i ++ ) { expectedOutput << ')'; } expectedOutput << '\0'; T_SRDErrors errors; T_SRDList output( process( input.data( ) , errors ) ); CPPUNIT_ASSERT_EQUAL( uint32_t( T_SRDErrors::MAX_ERRORS + 1 ) , errors.size( ) ); M_CKERR_( T_SRDErrors::MAX_ERRORS , "too many errors" , 1 , T_SRDErrors::MAX_ERRORS * 2 - 1 ); CPPUNIT_ASSERT( check( expectedOutput.data( ) , output ) ); }