corelib/tests/srd-preproc-core.cc

245 lines
7 KiB
C++

#include <lw/lib/SRDPreproc.hh>
#include <lw/lib/SRDText.hh>
#include <lw/lib/SRDIO.hh>
#include <cppunit/extensions/HelperMacros.h>
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 ) );
}