#include "srd-preproc-cmd-common.hh"
#include "srd-preproc-location.hh"
using namespace lw;


class SRDPreprocTrackingTest : public CppUnit::TestFixture
{
	CPPUNIT_TEST_SUITE( SRDPreprocTrackingTest );

		CPPUNIT_TEST( testTopLevel );

		CPPUNIT_TEST( testVar );
		CPPUNIT_TEST( testVarGet );

		CPPUNIT_TEST( testCall );
		CPPUNIT_TEST( testCalls );
		CPPUNIT_TEST( testCallRecursive );

		CPPUNIT_TEST( testEval );
		CPPUNIT_TEST( testEvalCalls );

		CPPUNIT_TEST( testCommandOutput );

#if 0
		CPPUNIT_TEST( testMacroBody );
		CPPUNIT_TEST( testMacroBodyCall );
		CPPUNIT_TEST( testMacroBodyEval );
		CPPUNIT_TEST( testCallMacroBody );
		CPPUNIT_TEST( testEvalMacroBody );

		CPPUNIT_TEST( testMacroOutput );
		CPPUNIT_TEST( testMacroOutputCall );
		CPPUNIT_TEST( testMacroOutputEval );
		CPPUNIT_TEST( testCallMacroOutput );
		CPPUNIT_TEST( testEvalMacroOutput );

#endif
//		CPPUNIT_TEST( testErrorTopLevel );
#if 0
		CPPUNIT_TEST( testErrorCall );
#endif

	CPPUNIT_TEST_SUITE_END( );

   public:
	void testTopLevel( );

	void testVar( );
	void testVarGet( );

	void testCall( );
	void testCalls( );
	void testCallRecursive( );

	void testEval( );
	void testEvalCalls( );

	void testCommandOutput( );

#if 0
	void testMacroBody( );
	void testMacroBodyCall( );
	void testMacroBodyEval( );
	void testCallMacroBody( );
	void testEvalMacroBody( );

	void testMacroOutput( );
	void testMacroOutputCall( );
	void testMacroOutputEval( );
	void testCallMacroOutput( );
	void testEvalMacroOutput( );

#endif
	void testErrorTopLevel( );
#if 0
	void testErrorCall( );
#endif
};
CPPUNIT_TEST_SUITE_REGISTRATION( SRDPreprocTrackingTest );

/*----------------------------------------------------------------------------*/

void SRDPreprocTrackingTest::testTopLevel( )
{
	T_SRDErrors errors;
	T_SRDList output( process(
				"a\n"
				"(-scope b)\n"
				, errors ) );
	CPPUNIT_ASSERT( check( "a b" , output ) );
	CPPUNIT_ASSERT_EQUAL( 0u , errors.size( ) );

	M_CKTOKDEPTH_( 0 , 0 );
		M_CKTOKLOC_( 0 , "test" , 1 , 1 );
	M_CKTOKDEPTH_( 1 , 0 );
		M_CKTOKLOC_( 1 , "test" , 2 , 9 );
}

/*----------------------------------------------------------------------------*/

void SRDPreprocTrackingTest::testVar( )
{
	T_SRDErrors errors;
	T_SRDList output( process(
				"(-set var value)\n"
				"$var\n"
				, errors ) );
	CPPUNIT_ASSERT( check( "value" , output ) );
	CPPUNIT_ASSERT_EQUAL( 0u , errors.size( ) );

	M_CKTOKDEPTH_( 0 , 1 );
		M_CKTOKLOC_( 0 , "$var" , 0 , 0 );
		M_CKTOKCHAIN_( 0 , 0 , SUBSTITUTED , "test" , 2 , 1 , 0 );
}

void SRDPreprocTrackingTest::testVarGet( )
{
	T_SRDErrors errors;
	T_SRDList output( process(
				"(-set (var vn) value var)\n"
				"(-get var $vn)\n"
				, errors ) );
	CPPUNIT_ASSERT( check( "value value" , output ) );
	CPPUNIT_ASSERT_EQUAL( 0u , errors.size( ) );

	M_CKTOKDEPTH_( 0 , 1 );
		M_CKTOKLOC_( 0 , "$var" , 0 , 0 );
		M_CKTOKCHAIN_( 0 , 0 , SUBSTITUTED , "test" , 2 , 2 , 0 );
	M_CKTOKDEPTH_( 1 , 1 );
		M_CKTOKLOC_( 1 , "$var" , 0 , 0 );
		M_CKTOKCHAIN_( 1 , 0 , SUBSTITUTED , "test" , 2 , 2 , 0 );
}

/*----------------------------------------------------------------------------*/

void SRDPreprocTrackingTest::testCall( )
{
	T_SRDErrors errors;
	T_SRDList output( process(
				"(-set fn (-raw ( () b )))\n"
				"(-bless fn)\n"
				"a ($fn)\n"
				, errors ) );
	CPPUNIT_ASSERT( check( "a b" , output ) );
	CPPUNIT_ASSERT_EQUAL( 0u , errors.size( ) );

	M_CKTOKDEPTH_( 0 , 0 );
		M_CKTOKLOC_( 0 , "test" , 3 , 1 );
	M_CKTOKDEPTH_( 1 , 1 );
		M_CKTOKLOC_( 1 , "test" , 1 , 21 );
		M_CKTOKCHAIN_( 1 , 0 , CALLED , "test" , 3 , 4 , 0 );
}

void SRDPreprocTrackingTest::testCalls( )
{
	T_SRDErrors errors;
	T_SRDList output( process(
				"(-set ( fn1 fn2 ) (-raw\n"
					"((d)\n"
						"I ($fn2 $d) )\n"
					"((d)\n"
						"got $d)\n"
				"))\n"
				"(-bless fn1 fn2)\n"
				"($fn1 it)\n"
				, errors ) );
	CPPUNIT_ASSERT( check( "I got it" , output ) );
	CPPUNIT_ASSERT_EQUAL( 0u , errors.size( ) );

	M_CKTOKDEPTH_( 0 , 1 );
		M_CKTOKLOC_( 0 , "test" , 3 , 1 );
		M_CKTOKCHAIN_( 0 , 0 , CALLED , "test" , 8 , 2 , 0 );
	M_CKTOKDEPTH_( 1 , 2 );
		M_CKTOKLOC_( 1 , "test" , 5 , 1 );
		M_CKTOKCHAIN_( 1 , 0 , CALLED , "test" , 3 , 4 , 0 );
		M_CKTOKCHAIN_( 1 , 1 , CALLED , "test" , 8 , 2 , 0 );
	M_CKTOKDEPTH_( 2 , 3 );
		M_CKTOKLOC_( 2 , "$d" , 0 , 0 );
		M_CKTOKCHAIN_( 2 , 0 , SUBSTITUTED , "test" , 5 , 5 , 0 );
		M_CKTOKCHAIN_( 2 , 1 , CALLED , "test" , 3 , 4 , 0 );
		M_CKTOKCHAIN_( 2 , 2 , CALLED , "test" , 8 , 2 , 0 );
}

void SRDPreprocTrackingTest::testCallRecursive( )
{
	T_SRDErrors errors;
	T_SRDList output( process(
				"(-set fn (-raw ( (d)\n"
					"$d\n"
					"(-if (-gt $d 0) (\n"
						"($fn (-sub $d 1))\n"
					")))))\n"
				"(-bless fn)\n"
				"($fn 6)\n"
				, errors ) );
	CPPUNIT_ASSERT( check( "6 5 4 3 2 1 0" , output ) );
	CPPUNIT_ASSERT_EQUAL( 0u , errors.size( ) );

	M_CKTOKDEPTH_( 0 , 2 );
	M_CKTOKCHAIN_( 0 , 0 , SUBSTITUTED , "test" , 2 , 1 , 0 );
	M_CKTOKCHAIN_( 0 , 1 , CALLED , "test" , 7 , 2 , 0 );

	for ( auto i = 1u ; i < 7 ; i ++ ) {
		M_CKTOKDEPTH_( i , 3 );
		M_CKTOKCHAIN_( i , 0 , SUBSTITUTED , "test" , 2 , 1 , 0 );
		M_CKTOKCHAIN_( i , 1 , CALLED , "test" , 4 , 2 , i - 1 );
		M_CKTOKCHAIN_( i , 2 , CALLED , "test" , 7 , 2 , 0 );
	}
}

/*----------------------------------------------------------------------------*/

void SRDPreprocTrackingTest::testEval( )
{
	T_SRDErrors errors;
	T_SRDList output( process(
				"(-set (x y f)\n"
					"(-raw $y)\n"
					"x\n"
					"(() (-raw a (-raw $y) b))\n"
				")\n"
				"(-bless f)\n"
				"(-eval x $y $x ($f))\n"
				, errors ) );
	CPPUNIT_ASSERT( check( "x x x a x b" , output ) );
	CPPUNIT_ASSERT_EQUAL( 0u , errors.size( ) );

	M_CKTOKDEPTH_( 0 , 0 );
		M_CKTOKLOC_( 0 , "test" , 7 , 8 );
	M_CKTOKDEPTH_( 1 , 1 );
		M_CKTOKLOC_( 1 , "$y" , 0 , 0 );
		M_CKTOKCHAIN_( 1 , 0 , SUBSTITUTED , "test" , 7 , 10 , 0 );
	M_CKTOKDEPTH_( 2 , 2 );
		M_CKTOKLOC_( 2 , "$y" , 0 , 0 );
		M_CKTOKCHAIN_( 2 , 0 , SUBSTITUTED , "$x" , 0 , 0 , 0 );
		M_CKTOKCHAIN_( 2 , 1 , EVALUATED , "test" , 7 , 2 , 0 );
	M_CKTOKDEPTH_( 3 , 1 );
		M_CKTOKLOC_( 3 , "test" , 4 , 11 );
		M_CKTOKCHAIN_( 3 , 0 , CALLED , "test" , 7 , 17 , 0 );
	M_CKTOKDEPTH_( 4 , 2 );
		M_CKTOKLOC_( 4 , "$y" , 0 , 0 );
		M_CKTOKCHAIN_( 4 , 0 , SUBSTITUTED , "test" , 4 , 19 , 0 );
		M_CKTOKCHAIN_( 4 , 1 , EVALUATED , "test" , 7 , 2 , 0 );
	M_CKTOKDEPTH_( 5 , 1 );
		M_CKTOKLOC_( 5 , "test" , 4 , 23 );
		M_CKTOKCHAIN_( 5 , 0 , CALLED , "test" , 7 , 17 , 0 );
}

void SRDPreprocTrackingTest::testEvalCalls( )
{
	T_SRDErrors errors;
	T_SRDList output( process(
				"(-set (x y f)\n"
					"(-raw ($f 2))\n"
					"(-raw $x)\n"
					"(-raw ((x) a $x b))\n"
				")\n"
				"(-bless f)\n"
				"(-eval ($f 1) $x $y $x)\n"
				, errors ) );
#if 0
	printf( "\n\n" );
	for ( auto i = 0u ; i < output.size( ) ; i ++ ) {
		PrintLoc_( &output[ i ].location( ) );
		printf( "\n" );
	}
#endif
	CPPUNIT_ASSERT( check( "a 1 b a 2 b ($f 2) a 2 b" , output ) );

	M_CKTOKDEPTH_( 0 , 1 );
		M_CKTOKLOC_( 0 , "test" , 4 , 12 );
		M_CKTOKCHAIN_( 0 , 0 , CALLED , "test" , 7 , 9 , 0 );
	M_CKTOKDEPTH_( 1 , 2 );
		M_CKTOKLOC_( 1 , "$x" , 0 , 0 );
		M_CKTOKCHAIN_( 1 , 0 , SUBSTITUTED , "test" , 4 , 14 , 0 );
		M_CKTOKCHAIN_( 1 , 1 , CALLED , "test" , 7 , 9 , 0 );
	M_CKTOKDEPTH_( 2 , 1 );
		M_CKTOKLOC_( 2 , "test" , 4 , 17 );
		M_CKTOKCHAIN_( 2 , 0 , CALLED , "test" , 7 , 9 , 0 );

	M_CKTOKDEPTH_( 3 , 2 );
		M_CKTOKLOC_( 3 , "test" , 4 , 12 );
		M_CKTOKCHAIN_( 3 , 0 , CALLED , "$x" , 0 , 1 , 0 );
		M_CKTOKCHAIN_( 3 , 1 , EVALUATED , "test" , 7 , 2 , 0 );
	M_CKTOKDEPTH_( 4 , 3 );
		M_CKTOKLOC_( 4 , "$x" , 0 , 0 );
		M_CKTOKCHAIN_( 4 , 0 , SUBSTITUTED , "test" , 4 , 14 , 0 );
		M_CKTOKCHAIN_( 4 , 1 , CALLED , "$x" , 0 , 1 , 0 );
		M_CKTOKCHAIN_( 4 , 2 , EVALUATED , "test" , 7 , 2 , 0 );
	M_CKTOKDEPTH_( 5 , 2 );
		M_CKTOKLOC_( 5 , "test" , 4 , 17 );
		M_CKTOKCHAIN_( 5 , 0 , CALLED , "$x" , 0 , 1 , 0 );
		M_CKTOKCHAIN_( 5 , 1 , EVALUATED , "test" , 7 , 2 , 0 );

	for ( auto i = 0u ; i < 4 ; i ++ ) {
		M_CKTOKDEPTH_( i + 6 , 2 );
		M_CKTOKLOC_( i + 6 , "$x" , 0 , i );
		M_CKTOKCHAIN_( i + 6 , 0 , SUBSTITUTED , "$y" , 0 , 0 , 0 );
		M_CKTOKCHAIN_( i + 6 , 1 , EVALUATED , "test" , 7 , 2 , 0 );
	}

	M_CKTOKDEPTH_( 10 , 2 );
		M_CKTOKLOC_( 10 , "test" , 4 , 12 );
		M_CKTOKCHAIN_( 10 , 0 , CALLED , "$x" , 0 , 1 , 0 );
		M_CKTOKCHAIN_( 10 , 1 , EVALUATED , "test" , 7 , 2 , 0 );
	M_CKTOKDEPTH_( 11 , 3 );
		M_CKTOKLOC_( 11 , "$x" , 0 , 0 );
		M_CKTOKCHAIN_( 11 , 0 , SUBSTITUTED , "test" , 4 , 14 , 0 );
		M_CKTOKCHAIN_( 11 , 1 , CALLED , "$x" , 0 , 1 , 0 );
		M_CKTOKCHAIN_( 11 , 2 , EVALUATED , "test" , 7 , 2 , 0 );
	M_CKTOKDEPTH_( 12 , 2 );
		M_CKTOKLOC_( 12 , "test" , 4 , 17 );
		M_CKTOKCHAIN_( 12 , 0 , CALLED , "$x" , 0 , 1 , 0 );
		M_CKTOKCHAIN_( 12 , 1 , EVALUATED , "test" , 7 , 2 , 0 );
}

/*----------------------------------------------------------------------------*/

void SRDPreprocTrackingTest::testCommandOutput( )
{
	T_SRDErrors errors;
	T_SRDList output( process(
				"(-add 1 2)\n"
				"(-is-set x)\n"
				"(-type-of w)\n"
				"(-eq a b)\n"
				"(-to-string x \"x\")\n"
				"(-length abcdef)\n"
				, errors ) );
	CPPUNIT_ASSERT( check( "3 0 word 0 \"x\" \"x\" 6" , output ) );
	CPPUNIT_ASSERT_EQUAL( 0u , errors.size( ) );

	M_CKTOKDEPTH_( 0 , 1 );
		M_CKTOKLOC_( 0 , "-add" , 0 , 0 );
		M_CKTOKCHAIN_( 0 , 0 , GENERATED , "test" , 1 , 2 , 0 );
	M_CKTOKDEPTH_( 1 , 1 );
		M_CKTOKLOC_( 1 , "-is-set" , 0 , 0 );
		M_CKTOKCHAIN_( 1 , 0 , GENERATED , "test" , 2 , 2 , 0 );
	M_CKTOKDEPTH_( 2 , 1 );
		M_CKTOKLOC_( 2 , "-type-of" , 0 , 0 );
		M_CKTOKCHAIN_( 2 , 0 , GENERATED , "test" , 3 , 2 , 0 );
	M_CKTOKDEPTH_( 3 , 1 );
		M_CKTOKLOC_( 3 , "-eq" , 0 , 0 );
		M_CKTOKCHAIN_( 3 , 0 , GENERATED , "test" , 4 , 2 , 0 );
	M_CKTOKDEPTH_( 4 , 1 );
		M_CKTOKLOC_( 4 , "-to-string" , 0 , 0 );
		M_CKTOKCHAIN_( 4 , 0 , GENERATED , "test" , 5 , 2 , 0 );
	M_CKTOKDEPTH_( 5 , 0 );
		M_CKTOKLOC_( 5 , "test" , 5 , 15 );
	M_CKTOKDEPTH_( 6 , 1 );
		M_CKTOKLOC_( 6 , "-length" , 0 , 0 );
		M_CKTOKCHAIN_( 6 , 0 , GENERATED , "test" , 6 , 2 , 0 );
}

#if 0
void SRDPreprocTrackingTest::testCallRecursive( )
{
	T_SRDErrors errors;
	T_SRDList output( process(
				"(-set fn (-raw ( (d)\n"
					"(-if $d (\n"
						"($fn (-sub $d 1))\n"
					") (\n"
						"(-error)\n"
					")))))\n"
				"(-bless fn)\n"
				"($fn 6)\n"
				, errors ) );
	CPPUNIT_ASSERT( check( "" , output ) );
	CPPUNIT_ASSERT_EQUAL( 1u , errors.size( ) );

	M_CKERR_( 0 , "user error" , 5 , 1 );
	M_CKERRDEPTH_( 0 , 2 );
	M_CKERRCHAIN_( 0 , 0 , E_SRDLocationChaining::CALLED , 3 , 1 , 6 );
	M_CKERRCHAIN_( 0 , 1 , E_SRDLocationChaining::CALLED , 8 , 1 , 1 );
}

void SRDPreprocTrackingTest::testCalls( )
{
	T_SRDErrors errors;
	T_SRDList output( process(
				"(-set fn1 (-raw ( (d)\n"
					"(-if $d (\n"
						"($fn1 (-sub $d 1))\n"
					") (\n"
						"($fn2 4)\n"
					")))))\n"
				"(-set fn2 (-raw ( (d)\n"
					"(-if $d (\n"
						"($fn2 (-sub $d 1))\n"
					") (\n"
						"(-error)\n"
					")))))\n"
				"(-bless fn1 fn2)\n"
				"($fn1 6)\n"
				, errors ) );
	CPPUNIT_ASSERT( check( "" , output ) );
	CPPUNIT_ASSERT_EQUAL( 1u , errors.size( ) );

	M_CKERR_( 0 , "user error" , 11 , 1 );
	M_CKERRDEPTH_( 0 , 4 );
	M_CKERRCHAIN_( 0 , 0 , E_SRDLocationChaining::CALLED , 9 , 1 , 4 );
	M_CKERRCHAIN_( 0 , 1 , E_SRDLocationChaining::CALLED , 5 , 1 , 1 );
	M_CKERRCHAIN_( 0 , 2 , E_SRDLocationChaining::CALLED , 3 , 1 , 6 );
	M_CKERRCHAIN_( 0 , 3 , E_SRDLocationChaining::CALLED , 14 , 1 , 1 );
}

/*----------------------------------------------------------------------------*/

void SRDPreprocTrackingTest::testEval( )
{
	T_SRDErrors errors;
	T_SRDList output( process(
				"(-eval\n"
					"( (-raw -error ) )\n"
				")\n"
				, errors ) );
	CPPUNIT_ASSERT( check( "" , output ) );
	CPPUNIT_ASSERT_EQUAL( 1u , errors.size( ) );

	M_CKERR_( 0 , "user error" , 2 , 1 );
	M_CKERRDEPTH_( 0 , 1 );
	M_CKERRCHAIN_( 0 , 0 , E_SRDLocationChaining::EVALUATED , 1 , 1 , 1 );
}

void SRDPreprocTrackingTest::testEvalCall( )
{
	T_SRDErrors errors;
	T_SRDList output( process(
				"(-set fn (-raw ( (d)\n"
					"(-if $d (\n"
						"($fn (-sub $d 1))\n"
					") (\n"
						"(-error)\n"
					")))))\n"
				"(-bless fn)\n"
				"(-eval (-raw ($fn 6)))\n"
				, errors ) );
	CPPUNIT_ASSERT( check( "" , output ) );
	CPPUNIT_ASSERT_EQUAL( 1u , errors.size( ) );

	M_CKERR_( 0 , "user error" , 5 , 1 );
	M_CKERRDEPTH_( 0 , 3 );
	M_CKERRCHAIN_( 0 , 0 , E_SRDLocationChaining::CALLED , 3 , 1 , 6 );
	M_CKERRCHAIN_( 0 , 1 , E_SRDLocationChaining::CALLED , 8 , 14 , 1 );
	M_CKERRCHAIN_( 0 , 2 , E_SRDLocationChaining::EVALUATED , 8 , 1 , 1 );
}

void SRDPreprocTrackingTest::testCallEval( )
{
	T_SRDErrors errors;
	T_SRDList output( process(
				"(-set fn (-raw ( (d)\n"
					"(-if $d (\n"
						"($fn (-sub $d 1))\n"
					") (\n"
						"(-eval (-raw (-error)))\n"
					")))))\n"
				"(-bless fn)\n"
				"($fn 6)\n"
				, errors ) );
	CPPUNIT_ASSERT( check( "" , output ) );
	CPPUNIT_ASSERT_EQUAL( 1u , errors.size( ) );

	M_CKERR_( 0 , "user error" , 5 , 14 );
	M_CKERRDEPTH_( 0 , 3 );
	M_CKERRCHAIN_( 0 , 0 , E_SRDLocationChaining::EVALUATED , 5 , 1 , 1 );
	M_CKERRCHAIN_( 0 , 1 , E_SRDLocationChaining::CALLED , 3 , 1 , 6 );
	M_CKERRCHAIN_( 0 , 2 , E_SRDLocationChaining::CALLED , 8 , 1 , 1 );
}

/*----------------------------------------------------------------------------*/

void SRDPreprocTrackingTest::testMacroBody( )
{
	T_SRDErrors errors;
	T_SRDList output( process(
				"(-set-macro m (-raw ( () (-error) )))\n"
				"(m)\n"
				, errors ) );
	CPPUNIT_ASSERT( check( "" , output ) );
	CPPUNIT_ASSERT_EQUAL( 1u , errors.size( ) );

	M_CKERR_( 0 , "user error" , 1 , 26 );
	M_CKERRDEPTH_( 0 , 1 );
	M_CKERRCHAIN_( 0 , 0 , E_SRDLocationChaining::CALLED , 2 , 1 , 1 );
}

void SRDPreprocTrackingTest::testMacroBodyCall( )
{
	T_SRDErrors errors;
	T_SRDList output( process(
				"(-set fn (-raw ( () (-error) )))\n"
				"(-bless fn)\n"
				"(-set-macro m (-raw ( () ($fn) )))\n"
				"(m)\n"
				, errors ) );
	CPPUNIT_ASSERT( check( "" , output ) );
	CPPUNIT_ASSERT_EQUAL( 1u , errors.size( ) );

	M_CKERR_( 0 , "user error" , 1 , 21 );
	M_CKERRDEPTH_( 0 , 2 );
	M_CKERRCHAIN_( 0 , 0 , E_SRDLocationChaining::CALLED , 3 , 26 , 1 );
	M_CKERRCHAIN_( 0 , 1 , E_SRDLocationChaining::CALLED , 4 , 1 , 1 );
}

void SRDPreprocTrackingTest::testMacroBodyEval( )
{
	T_SRDErrors errors;
	T_SRDList output( process(
				"(-set-macro m (-raw ( () (-eval (-raw (-error))) )))\n"
				"(m)\n"
				, errors ) );
	CPPUNIT_ASSERT( check( "" , output ) );
	CPPUNIT_ASSERT_EQUAL( 1u , errors.size( ) );

	M_CKERR_( 0 , "user error" , 1 , 39 );
	M_CKERRDEPTH_( 0 , 2 );
	M_CKERRCHAIN_( 0 , 0 , E_SRDLocationChaining::EVALUATED , 1 , 26 , 1 );
	M_CKERRCHAIN_( 0 , 1 , E_SRDLocationChaining::CALLED , 2 , 1 , 1 );
}

void SRDPreprocTrackingTest::testCallMacroBody( )
{
	T_SRDErrors errors;
	T_SRDList output( process(
				"(-set-macro m (-raw ( () (-error) )))\n"
				"(-set fn (-raw ( () (m))))\n"
				"(-bless fn)\n"
				"($fn)\n"
				, errors ) );
	CPPUNIT_ASSERT( check( "" , output ) );
	CPPUNIT_ASSERT_EQUAL( 1u , errors.size( ) );

	M_CKERR_( 0 , "user error" , 1 , 26 );
	M_CKERRDEPTH_( 0 , 2 );
	M_CKERRCHAIN_( 0 , 0 , E_SRDLocationChaining::CALLED , 2 , 21 , 1 );
	M_CKERRCHAIN_( 0 , 1 , E_SRDLocationChaining::CALLED , 4 , 1 , 1 );
}

void SRDPreprocTrackingTest::testEvalMacroBody( )
{
	T_SRDErrors errors;
	T_SRDList output( process(
				"(-set-macro m (-raw ( () (-error) )))\n"
				"(-eval (-raw (m)))\n"
				, errors ) );
	CPPUNIT_ASSERT( check( "" , output ) );
	CPPUNIT_ASSERT_EQUAL( 1u , errors.size( ) );

	M_CKERR_( 0 , "user error" , 1 , 26 );
	M_CKERRDEPTH_( 0 , 2 );
	M_CKERRCHAIN_( 0 , 0 , E_SRDLocationChaining::CALLED , 2 , 14 , 1 );
	M_CKERRCHAIN_( 0 , 1 , E_SRDLocationChaining::EVALUATED , 2 , 1 , 1 );
}

/*----------------------------------------------------------------------------*/

void SRDPreprocTrackingTest::testMacroOutput( )
{
	T_SRDErrors errors;
	T_SRDList output( process(
				"(-set-macro m (-raw ( () (-raw (-error)) )))\n"
				"(m)\n"
				, errors ) );
	CPPUNIT_ASSERT( check( "" , output ) );
	CPPUNIT_ASSERT_EQUAL( 1u , errors.size( ) );

	M_CKERR_( 0 , "user error" , 1 , 32 );
	M_CKERRDEPTH_( 0 , 3 );
	M_CKERRCHAIN_( 0 , 0 , E_SRDLocationChaining::EVALUATED , 2 , 1 , 1 );
	M_CKERRCHAIN_( 0 , 1 , E_SRDLocationChaining::GENERATED , 1 , 32 , 1 );
	M_CKERRCHAIN_( 0 , 2 , E_SRDLocationChaining::CALLED , 2 , 1 , 1 );
}

void SRDPreprocTrackingTest::testMacroOutputCall( )
{
	T_SRDErrors errors;
	T_SRDList output( process(
				"(-set fn (-raw ( () (-error) )))\n"
				"(-bless fn)\n"
				"(-set-macro m (-raw ( () (-raw ($fn)) )))\n"
				"(m)\n"
				, errors ) );
	CPPUNIT_ASSERT( check( "" , output ) );
	CPPUNIT_ASSERT_EQUAL( 1u , errors.size( ) );

	M_CKERR_( 0 , "user error" , 1 , 21 );
	M_CKERRDEPTH_( 0 , 4 );
	M_CKERRCHAIN_( 0 , 0 , E_SRDLocationChaining::CALLED , 3 , 32 , 1 );
	M_CKERRCHAIN_( 0 , 1 , E_SRDLocationChaining::EVALUATED , 4 , 1 , 1 );
	M_CKERRCHAIN_( 0 , 2 , E_SRDLocationChaining::GENERATED , 3 , 32 , 1 );
	M_CKERRCHAIN_( 0 , 3 , E_SRDLocationChaining::CALLED , 4 , 1 , 1 );
}

void SRDPreprocTrackingTest::testMacroOutputEval( )
{
	T_SRDErrors errors;
	T_SRDList output( process(
				"(-set-macro m (-raw ( () (-raw\n"
					"(-eval (-raw (-error)))\n"
				") )))\n"
				"(m)\n"
				, errors ) );
	CPPUNIT_ASSERT( check( "" , output ) );
	CPPUNIT_ASSERT_EQUAL( 1u , errors.size( ) );

	M_CKERR_( 0 , "user error" , 2 , 14 );
	M_CKERRDEPTH_( 0 , 4 );
	M_CKERRCHAIN_( 0 , 0 , E_SRDLocationChaining::EVALUATED , 2 , 1 , 1 );
	M_CKERRCHAIN_( 0 , 1 , E_SRDLocationChaining::EVALUATED , 4 , 1 , 1 );
	M_CKERRCHAIN_( 0 , 2 , E_SRDLocationChaining::GENERATED , 2 , 1 , 1 );
	M_CKERRCHAIN_( 0 , 3 , E_SRDLocationChaining::CALLED , 4 , 1 , 1 );
}

void SRDPreprocTrackingTest::testCallMacroOutput( )
{
	T_SRDErrors errors;
	T_SRDList output( process(
				"(-set-macro m (-raw ( () (-raw\n"
					"(-error)\n"
				") )))\n"
				"(-set fn (-raw ( () (m) )))\n"
				"(-bless fn)\n"
				"($fn)\n"
				, errors ) );
	CPPUNIT_ASSERT( check( "" , output ) );
	CPPUNIT_ASSERT_EQUAL( 1u , errors.size( ) );

	M_CKERR_( 0 , "user error" , 2 , 1 );
	M_CKERRDEPTH_( 0 , 4 );
	M_CKERRCHAIN_( 0 , 0 , E_SRDLocationChaining::EVALUATED , 4 , 21 , 1 );
	M_CKERRCHAIN_( 0 , 1 , E_SRDLocationChaining::GENERATED , 2 , 1 , 1 );
	M_CKERRCHAIN_( 0 , 2 , E_SRDLocationChaining::CALLED , 4 , 21 , 1 );
	M_CKERRCHAIN_( 0 , 3 , E_SRDLocationChaining::CALLED , 6 , 1 , 1 );
}

void SRDPreprocTrackingTest::testEvalMacroOutput( )
{
	T_SRDErrors errors;
	T_SRDList output( process(
				"(-set-macro m (-raw ( () (-raw\n"
					"(-error)\n"
				") )))\n"
				"(-eval (-raw (m)))\n"
				, errors ) );
	CPPUNIT_ASSERT( check( "" , output ) );
	CPPUNIT_ASSERT_EQUAL( 1u , errors.size( ) );

	M_CKERR_( 0 , "user error" , 2 , 1 );
	M_CKERRDEPTH_( 0 , 4 );
	M_CKERRCHAIN_( 0 , 0 , EVALUATED , 4 , 14 , 1 );
	M_CKERRCHAIN_( 0 , 1 , GENERATED , 2 , 1 , 1 );
	M_CKERRCHAIN_( 0 , 2 , CALLED , 4 , 14 , 1 );
	M_CKERRCHAIN_( 0 , 3 , EVALUATED , 4 , 1 , 1 );
}
#endif

/*----------------------------------------------------------------------------*/

void SRDPreprocTrackingTest::testErrorTopLevel( )
{
	T_SRDErrors errors;
	T_SRDList output( process(
				"(-error)\n"
				"(-scope (-error))\n"
				, errors ) );
	CPPUNIT_ASSERT( check( "" , output ) );
	CPPUNIT_ASSERT_EQUAL( 2u , errors.size( ) );

	M_CKERR_( 0 , "user error" , 1 , 2 );
	M_CKERRDEPTH_( 0 , 0 );

	M_CKERR_( 1 , "user error" , 2 , 10 );
	M_CKERRDEPTH_( 1 , 0 );
}