/*****************************************************************************
 * $Id: config_file.cc,v 1.18 2006/08/03 02:17:21 devel Exp $
 * @file
 * @author	Jim E. Brooks  http://www.jimbrooks.org
 * @brief	Test of ConfigFile class.
 *//*
 * LEGAL:	COPYRIGHT (C) 2004 JIM E. BROOKS
 *          THIS SOURCE CODE IS RELEASED UNDER THE TERMS
 *          OF THE GNU GENERAL PUBLIC LICENSE (GPL).
 *****************************************************************************/

#define TESTING 1
#include "test.hh"
#include "gfx_config_file.hh"
using namespace gfx;

static const char fname[]		= "/tmp/gfx_config_file_test.cfg";
static const char progname[]	= "test";

/*****************************************************************************
 * Test.
 *****************************************************************************/
bool
Test1( void )
{
	// ------------------------------------------------------------------------
	// First series of tests are for when no configuration file exists yet.
	// ------------------------------------------------------------------------

	unlink( fname ); // ensure configuration file doesn't exist

	ConfigFile config( progname, fname );

	int			right_highscore	= 536000;
	string		right_game		= "pacman";
	double		right_offset	= 1.2345;
	int			highscore;
	string		game;
	double		offset;

	// Test writing.
	if ( ! config.Write( "highscore", right_highscore ) )
	{
		cerr << "FAIL: Write(highscore) \n";
		return false;
	}

	if ( ! config.Write( "game", right_game ) )
	{
		cerr << "FAIL: Write(game) \n";
		return false;
	}

	if ( ! config.Write( "offset", right_offset ) )
	{
		cerr << "FAIL: Write(highscore) \n";
		return false;
	}

	// Test reading.
	if ( config.Read( "highscore", highscore ) && highscore == right_highscore )
		{ cerr << "(ok) highscore = " << highscore << endl; }
	else
		{ cerr << "FAIL: Read(highscore)\n"; return false; }

	if ( config.Read( "game", game ) && game == right_game )
		{ cerr << "(ok) game      = " << game << endl; }
	else
		{ cerr << "FAIL: Read(game)\n"; return false; }

	if ( config.Read( "offset", offset ) && offset == right_offset )
		{ cerr << "(ok) offset    = " << offset << endl; }
	else
		{ cerr << "FAIL: Read(offset)\n"; return false; }

	return true;
}

/*****************************************************************************
 * Test.
 *****************************************************************************/
bool
Test2( void )
{
	// ------------------------------------------------------------------------
	// Second series of tests are for when a configuration file DOES exist.
	// ------------------------------------------------------------------------

	ConfigFile config( progname, fname );

	int			right_highscore	= 536000;
	string		right_game		= "pacman";
	double		right_offset	= 1.2345;
	int			highscore;
	string		game;
	double		offset;

	// Test reading.
	if ( config.Read( "highscore", highscore ) && highscore == right_highscore )
		{ cerr << "(ok) highscore = " << highscore << endl; }
	else
		{ cerr << "FAIL: Read(highscore)\n"; return false; }

	if ( config.Read( "game", game ) && game == right_game )
		{ cerr << "(ok) game[]    = " << game << endl; }
	else
		{ cerr << "FAIL: Read(game)\n"; return false; }

	if ( config.Read( "offset", offset ) && offset == right_offset )
		{ cerr << "(ok) offset    = " << offset << endl; }
	else
		{ cerr << "FAIL: Read(offset)\n"; return false; }

	return true;
}

/*****************************************************************************
 * 
 *****************************************************************************/
bool
Test3( void )
{
	// ------------------------------------------------------------------------
	// Test giving different values using the same key/type.
	// ------------------------------------------------------------------------

	ConfigFile config( progname, fname );

	cerr << "Testing changing value of same key..." << endl;

	const char key_highscore[] = "highscore_changing";
	int	right_highscore	= 1234;
	int highscore;

	//
	right_highscore = 0xabcd;
	if ( ! config.Write( key_highscore, right_highscore ) )
	{
		cerr << "FAIL: Write(highscore) \n";
		return false;
	}
	if ( ! config.Read( key_highscore, highscore ) || highscore != right_highscore )
		{ cerr << "FAIL: Read(highscore)\n"; return false; }

	//
	right_highscore = 0;
	if ( ! config.Write( key_highscore, right_highscore ) )
	{
		cerr << "FAIL: Write(highscore) \n";
		return false;
	}
	if ( ! config.Read( key_highscore, highscore ) || highscore != right_highscore )
		{ cerr << "FAIL: Read(highscore)"; return false; }

	//
	right_highscore = 123467;
	if ( ! config.Write( key_highscore, right_highscore ) )
	{
		cerr << "FAIL: Write(highscore) \n";
		return false;
	}
	if ( ! config.Read( key_highscore, highscore ) || highscore != right_highscore )
		{ cerr << "FAIL: Read(highscore)\n"; return false; }

	cerr << "ok." << endl;

	return true;
}

/*****************************************************************************
 * Test.
 *****************************************************************************/
bool
Test4( void )
{
	// ------------------------------------------------------------------------
	// Delete test.
	// ------------------------------------------------------------------------

	ConfigFile config( progname, fname );

//	int			right_highscore	= 536000;
	string		right_game		= "pacman";
	double		right_offset	= 1.2345;
	int			highscore;
	string		game;
	double		offset;

	// Test deleting
	if ( config.Remove( "highscore" ) )
		{ cerr << "(ok) deleted highscore \n"; }
	else
		{ cerr << "FAIL: Remove(highscore)\n"; return false; }
	

	// Test reading.
	if ( config.Read( "highscore", highscore ) )		// deleted
		{ cerr << "FAIL: highscore should be deleted\n"; return false; }

	if ( config.Read( "game", game ) && game == right_game )
		{ cerr << "(ok) game[]    = " << game << endl; }
	else
		{ cerr << "FAIL: Read(game)\n"; return false; }

	if ( config.Read( "offset", offset ) && offset == right_offset )
		{ cerr << "(ok) offset    = " << offset << endl; }
	else
		{ cerr << "FAIL: Read(offset)\n"; return false; }

	return true;
}

/*****************************************************************************
 * Test.
 *****************************************************************************/
bool
Test5( void )
{
	// ------------------------------------------------------------------------
	// Corner cases, bad args.
	// ------------------------------------------------------------------------

	ConfigFile config( progname, fname );

	string s;

	// Test a string containing whitespace.
	const char ws_key[] = "_key_whitespace";
	string ws_val = "\tthis string has whitespace\n";
	config.Write( ws_key, ws_val );
	if ( config.Read( ws_key, s ) && s == ws_val )
	{ cerr << "(ok) reading string with whitespace" << endl; }
	else
	{ cerr << "FAIL: reading string with whitespace" << endl; return false; }

	// Test a empty string value.
	const char empty_string_key[] = "_key_empty_string";
	config.Write( empty_string_key, "" );
	s = "dummy";
	if ( config.Read( empty_string_key, s ) && s == "" )
	{ cerr << "(ok) reading empty string" << endl; }
	else
	{ cerr << "FAIL: reading empty string" << endl; return false; }

	const char key_big[] =
	"AAAAAAAAAAAAAAAAAAAAABBBBBBBBBBBBBBBBBBBBBBBBBBBBBCCCCCCCCCCCCCCCCCCCCCCCCCC"
	"DDDDDDDDDDDDDDDDEEEEEEEEEEEEEEEEEEEEEEEEEEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"
	"GGGGGGGGGGGGGGGGGGGGGGGGGGGHHHHHHHHHHHHHHHHHHHHHHHHHHIIIIIIIIIIIIIIIIIIIIIII"
	"KKKKKKKKKKKKKKKKKKKKLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLMMMMMMMMMMMMMMMMMMMMMMMM"
	"NNNNNNNNNNNNNNNNNNOOOOOOOOOOOOOOOOOOOOOOOPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP";
	string val_string_big =
	"QQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRR"
	"SSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTT"
	"UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV"
	"WWWWWWWWWWWWWWWWWWWWWWWXXXXXXXXXXXXXXXXXXXXXXXXYYYYYYYYYYYYYYYYYYYYYYYYYYYYY";

	// NULL args aren't tested -- let 'em die.
	// This won't succeed but it shouldn't cause a crash.
	string str;
	config.Write( key_big, val_string_big );
	if ( config.Read( key_big, str ) )
	{ cerr << "(ok) too big " << str << endl; }

	return true;
}

/*****************************************************************************
 * Test.
 *****************************************************************************/
bool
Test6( void )
{
	// ------------------------------------------------------------------------
	// Test Access() and more interesting keys/values.
	// ------------------------------------------------------------------------

	ConfigFile config( progname, fname );

	int			right_int1		= -1;
	int			right_int2		= 0x88889999;
	int			right_int3		= 0;
	string		right_str		= "ABCDzxcv123409~!@#$%&*\"*(){}[];',.//<>?";
	double		right_float		= 123456.430000;

	int			val_int1		= 0xdead;
	int			val_int2		= 0xdead;
	int			val_int3		= 0xdead;
	string		val_str			= "";
	double		val_float		= 0;

	static const char key_int1[]	= "___int1____";
	static const char key_int2[]	= "___int 2____";
	static const char key_int3[]	= "___int3____";
	static const char key_str[]		= "___String____";
	static const char key_float[]	= "___Float#1____";

	int res;

	cerr << "Testing Access()..." << endl;

	// Test writing by Access().
	if ( ! config.Access( ConfigFile::eAccess_WRITE, key_int1, right_int1 ) )
		{ cerr << "FAIL: Access(WRITE,int1)\n"; return false; }

	if ( ! config.Access( ConfigFile::eAccess_WRITE, key_int2, right_int2 ) )
		{ cerr << "FAIL: Access(WRITE,int2)\n"; return false; }

	if ( ! config.Access( ConfigFile::eAccess_WRITE, key_int3, right_int3 ) )
		{ cerr << "FAIL: Access(WRITE,int3)\n"; return false; }

	if ( ! config.Access( ConfigFile::eAccess_WRITE, key_str, right_str ) )
		{ cerr << "FAIL: Access(WRITE,str)\n"; return false; }

	if ( ! config.Access( ConfigFile::eAccess_WRITE, key_float, right_float ) )
		{ cerr << "FAIL: Access(WRITE,float)\n"; return false; }

	// Test reading by Access().
	res = config.Access( ConfigFile::eAccess_READ, key_int1, val_int1 );
	if ( ! res || val_int1 != right_int1 )
		{ cerr << "FAIL: Access(WRITE,int1)\n"; return false; }

	res = config.Access( ConfigFile::eAccess_READ, key_int2, val_int2 );
	if ( ! res || val_int2 != right_int2 )
		{ cerr << "FAIL: Access(WRITE,int2)\n"; return false; }

	res = config.Access( ConfigFile::eAccess_READ, key_int3, val_int3 );
	if ( ! res || val_int3 != right_int3 )
		{ cerr << "FAIL: Access(WRITE,int3)\n"; return false; }

	res = config.Access( ConfigFile::eAccess_READ, key_str, val_str );
	if ( ! res || val_str != right_str )
		{ cerr << "FAIL: Access(WRITE,str)\n"; return false; }

	res = config.Access( ConfigFile::eAccess_READ, key_float, val_float );
	if ( ! res || val_float < right_float - 0.2 || val_float > right_float + 0.2 )
		{ cerr << "FAIL: Access(WRITE,float)\n"; return false; }

	cerr << "ok." << endl;

	return true;
}

/*****************************************************************************
 * Test.
 *****************************************************************************/
bool
Test7( void )
{
	// ------------------------------------------------------------------------
	// Corner cases, bad args.
	// ------------------------------------------------------------------------

	int i;
	cerr << "--- THIS SHOULD PRINT ERRORS due to bad filename ---" << endl;
	ConfigFile config( progname, "/a/b/c/doesnt_exist" );
	if ( config.IfValid() )         		{ cerr << "IfValid() is wrong \n"; return false; }
	if ( config.Write( "abc", (int)123 ) )	{ cerr << "Write() is wrong \n"; return false; }
	if ( config.Read( "abc", i ) )			{ cerr << "Read() is wrong \n"; return false; }
	if ( config.Remove( "abc" ) )			{ cerr << "Remove() is wrong \n"; return false; }
	cerr << "---  ---\n" << endl;
	return true;
}

/*****************************************************************************
 * main.
 *****************************************************************************/
int
main( int argc, char** argv )
{
	GFX_INIT( argv[0] );
	int res = 1;
	if ( Test1() && Test2() && Test3() && Test4() && Test5() && Test6() && Test7() )
	{
		cerr << "Test PASSED.\n";
		res = 0;
	}
	else
	{
		cerr << "Test FAILED!\n";
		res = 1;
	}
	GFX_CLEANUP();
	exit( res );
}
