// Copyright (c) 1997-2009 Nokia Corporation and/or its subsidiary(-ies).
// All rights reserved.
// This component and the accompanying materials are made available
// under the terms of "Eclipse Public License v1.0"
// which accompanies this distribution, and is available
// at the URL "http://www.eclipse.org/legal/epl-v10.html".
//
// Initial Contributors:
// Nokia Corporation - initial contribution.
//
// Contributors:
//
// Description:
//


#include <e32test.h>
#include <flogger.h>
#include <f32file.h>

GLDEF_D RTest test(_L("FLOGGER Test Code"));
GLDEF_D RFs fs;

_LIT(KTestLogFileName1,"Log1.txt");
_LIT(KTestLogFileName2,"Log2.txt");
_LIT(KTestLogDir1,"Test1");
_LIT(KTestLogDir2,"Test2");
_LIT(KTestLogDir3,"Test3");
_LIT(KTestLogDir4,"Test4");
_LIT(KTestLogDir5,"Test5");
_LIT(KTestLogFullDir1,"c:\\Logs\\Test1\\");
_LIT(KTestLogFullDir2,"c:\\Logs\\Test2\\");
_LIT(KTestLogFullDir3,"c:\\Logs\\Test3\\");
_LIT(KTestLogFullDir4,"c:\\Logs\\Test4\\");
_LIT(KTestLogFullDir5,"c:\\Logs\\Test5\\");
_LIT(KTestLogFile1,"c:\\Logs\\Test1\\Log1.txt");
_LIT(KTestLogFile2,"c:\\Logs\\Test1\\Log2.txt");
_LIT(KTestLogFile3,"c:\\Logs\\Test2\\Log1.txt");
_LIT(KTestLogFile4,"c:\\Logs\\Test3\\Log1.txt");

// 2.2.5 Wait for shutdown after closure of session 
LOCAL_C void TestWaitForShutDown()
	{

	
	test.Printf(_L("\nWaiting for FLogger server shutdown"));
	TInt i;
	for (i=30; i>0; i--)
		{
		TFullName name=_L("*");
		_LIT(serverName,"FLogger server");
		name.Append(serverName);
		TFindThread find(name);
		if(find.Next(name)==KErrNone)
			test.Printf(_L("."));
		else
			break;
		User::After(1000000);
		}
	
	test(i);
	test.Printf(_L("\nFLogger Server Shutdown after %d secs\n"), 29-i);
	}

LOCAL_C TInt DeleteFolder(const TDesC& aFolder)
	{

	TUint temp;
	_LIT(KLogDir,"c:\\Logs\\");
	TInt ret=fs.Att(KLogDir,temp);
	if (ret==KErrPathNotFound)
		return KErrNone;
	else
		{
		TInt exists=fs.Att(aFolder,temp);
		if (exists==KErrPathNotFound)
			return KErrNone;
		
		if (exists!=KErrNotFound)
			{
			TFileName file1=aFolder;
			file1.Append(KTestLogFileName1);
			ret=fs.Delete(file1);
			if (ret!=KErrNone && ret!=KErrNotFound)
				return ret;
			TFileName file2=aFolder;
			file2.Append(KTestLogFileName1);
			ret=fs.Delete(file2);
			if (ret!=KErrNone && ret!=KErrNotFound)
				return ret;
			}

		CFileMan* fileman=NULL;
		TRAP(ret,fileman=CFileMan::NewL(fs));
		TFileName folder;
		folder.Copy(aFolder.Left(aFolder.Length()-1));
		ret=fileman->RmDir(folder);
		delete fileman;
		return ret;
		}
	}

LOCAL_C void CreateFolderL(const TDesC& aFolder)
	{

	TInt ret=fs.MkDirAll(aFolder);
	if (ret!=KErrNone && ret!=KErrAlreadyExists)
		User::Leave(ret);
	}

LOCAL_C void WriteToLog(RFileLogger& aLog)
	{

	// 16 bit writes
	TUint num1=100;
	aLog.WriteFormat(_L("Writing a number to the log: %d"),num1);
	test(aLog.LastError()==KErrNone);
	TUint num2=200;
	aLog.WriteFormat(_L("Writing two numbers to the log: %d, %d"),num1,num2);
	test(aLog.LastError()==KErrNone);
	aLog.SetDateAndTime(ETrue,ETrue);
	aLog.Write(_L("Line should begin with date and time"));
	test(aLog.LastError()==KErrNone);
	aLog.SetDateAndTime(ETrue,EFalse);
	aLog.Write(_L("Line should begin with date only"));
	test(aLog.LastError()==KErrNone);
	aLog.SetDateAndTime(EFalse,ETrue);
	aLog.Write(_L("Line should begin with time only"));
	test(aLog.LastError()==KErrNone);
	aLog.SetDateAndTime(EFalse,EFalse);
	aLog.Write(_L("Line should begin with nothing"));
	test(aLog.LastError()==KErrNone);
	aLog.Write(_L(""));
	test(aLog.LastError()==KErrNone);
	aLog.Write(_L("There should be a blank line above and below this one"));
	test(aLog.LastError()==KErrNone);
	aLog.Write(_L(""));
	test(aLog.LastError()==KErrNone);

	// 8 bit writes
	aLog.WriteFormat(_L8("Writing a number to the log: %d"),num1);
	test(aLog.LastError()==KErrNone);
	aLog.WriteFormat(_L8("Writing two numbers to the log: %d, %d"),num1,num2);
	test(aLog.LastError()==KErrNone);
	aLog.SetDateAndTime(ETrue,ETrue);
	aLog.Write(_L8("Line should begin with date and time"));
	test(aLog.LastError()==KErrNone);
	aLog.SetDateAndTime(ETrue,EFalse);
	aLog.Write(_L8("Line should begin with date only"));
	test(aLog.LastError()==KErrNone);
	aLog.SetDateAndTime(EFalse,ETrue);
	aLog.Write(_L8("Line should begin with time only"));
	test(aLog.LastError()==KErrNone);
	aLog.SetDateAndTime(EFalse,EFalse);
	aLog.Write(_L8("Line should begin with nothing"));
	test(aLog.LastError()==KErrNone);
	aLog.Write(_L8(""));
	test(aLog.LastError()==KErrNone);
	aLog.Write(_L8("There should be a blank line above and below this one"));
	test(aLog.LastError()==KErrNone);
	aLog.Write(_L8(""));
	test(aLog.LastError()==KErrNone);

// 2.2.1.5 Dump hexadecimal values
	// Hex dump
	const TText* hdr=_S("123456");
	const TText* mgn=_S("      ");
	const TUint8* ptr=_S8("abcdefghijklmnopqrstuvwxyz");
	TInt len=26;
	aLog.HexDump(hdr, mgn, ptr, len);
	test(aLog.LastError()==KErrNone);
	aLog.HexDump(NULL, mgn, ptr, len);
	test(aLog.LastError()==KErrNone);
	aLog.HexDump(hdr, NULL, ptr, len);
	test(aLog.LastError()==KErrNone);
	aLog.HexDump(hdr, mgn, NULL, len);
	test(aLog.LastError()==KErrNone);
	aLog.SetDateAndTime(ETrue,ETrue);
	aLog.HexDump(hdr, mgn, ptr, len);
	test(aLog.LastError()==KErrNone);
	aLog.HexDump(NULL, mgn, ptr, len);
	test(aLog.LastError()==KErrNone);
	aLog.HexDump(hdr, NULL, ptr, len);
	test(aLog.LastError()==KErrNone);
	aLog.HexDump(hdr, mgn, NULL, len);	
	test(aLog.LastError()==KErrNone);
	}

// 2.2.1 Writing to two open log files at a time 
// 2.2.1.3 Files are different 
LOCAL_C void testTwoClientsL(TBool aValid)
	{

	if (!aValid)
		test(DeleteFolder(KTestLogFullDir1)==KErrNone);
	else
		CreateFolderL(KTestLogFullDir1);

	RFileLogger log1;
	test(log1.Connect()==KErrNone);
	RFileLogger log2;
	test(log2.Connect()==KErrNone);

	log1.CreateLog(KTestLogDir1,KTestLogFileName1,EFileLoggingModeOverwrite);
	test(log1.LastError()==KErrNone);
	test(log1.LogValid()==aValid);
	
	log2.CreateLog(KTestLogDir1,KTestLogFileName2,EFileLoggingModeOverwrite);
	test(log2.LastError()==KErrNone);
	test(log2.LogValid()==aValid);
	
	log1.Write(_L("This is written to log 1"));
	test(log1.LastError()==KErrNone);
	test(log1.LogValid()==aValid);
	log2.Write(_L("This is written to log 2"));
	test(log2.LastError()==KErrNone);
	test(log2.LogValid()==aValid);

	WriteToLog(log1);
	WriteToLog(log2);

	log1.CloseLog();
	log2.CloseLog();

	TUint temp;
	if (aValid)
		{
		test(fs.Att(KTestLogFile1,temp)==KErrNone);
		test(fs.Att(KTestLogFile2,temp)==KErrNone);
		}
	else
		{
		test(fs.Att(KTestLogFile1,temp)==KErrPathNotFound);
		test(fs.Att(KTestLogFile2,temp)==KErrPathNotFound);
		}

	log1.Close();
	log2.Close();
	}

// 2.2.2 Static appends 
LOCAL_C void testStaticWrites(TBool aValid)
	{
	
	if (!aValid)
		test(DeleteFolder(KTestLogFullDir2)==KErrNone);
	else
		{
		TRAPD(ret,(CreateFolderL(KTestLogFullDir2)));
		test(ret==KErrNone);
		}

	RFileLogger::Write(KTestLogDir2,KTestLogFileName1,EFileLoggingModeAppend,_L("Writing to the log"));
	TUint num1=100;
	RFileLogger::WriteFormat(KTestLogDir2(),KTestLogFileName1(),EFileLoggingModeAppend,_L("Writing a number to the log: %d"),num1);
	TUint num2=200;
	RFileLogger::WriteFormat(KTestLogDir2(),KTestLogFileName1(),EFileLoggingModeAppend,_L("Writing two numbers to the log: %d, %d"),num1,num2);

	RFileLogger::Write(KTestLogDir2,KTestLogFileName1,EFileLoggingModeAppend,_L8("Writing to the log"));
	RFileLogger::WriteFormat(KTestLogDir2(),KTestLogFileName1(),EFileLoggingModeAppend,_L8("Writing a number to the log: %d"),num1);
	RFileLogger::WriteFormat(KTestLogDir2(),KTestLogFileName1(),EFileLoggingModeAppend,_L8("Writing two numbers to the log: %d, %d"),num1,num2);

	const TText* hdr=_S("123456");
	const TText* mgn=_S("      ");
	const TUint8* ptr=_S8("abcdefghijklmnopqrstuvwxyz");
	TInt len=26;
	RFileLogger::HexDump(KTestLogDir2(),KTestLogFileName1(),EFileLoggingModeAppend, hdr, mgn, ptr, len);
		
	TUint temp;
	if (aValid)
		test(fs.Att(KTestLogFile3,temp)==KErrNone);
	else
		test(fs.Att(KTestLogFile3,temp)==KErrPathNotFound);
	}

// 2.2.1 Writing to two open log files at a time 
// 2.2.1.4 Files are the same 
LOCAL_C void testTwoClientsOneFileL(TBool aValid)
	{

	if (!aValid)
		test(DeleteFolder(KTestLogFullDir3)==KErrNone);
	else
		CreateFolderL(KTestLogFullDir3);

	RFileLogger log1;
	test(log1.Connect()==KErrNone);
	RFileLogger log2;
	test(log2.Connect()==KErrNone);

	log1.CreateLog(KTestLogDir3,KTestLogFileName1,EFileLoggingModeOverwrite);
	test(log1.LastError()==KErrNone);
	test(log1.LogValid()==aValid);
	
	log2.CreateLog(KTestLogDir3,KTestLogFileName1,EFileLoggingModeOverwrite);
	test(log2.LastError()==KErrNone);
	test(log2.LogValid()==aValid);
	
	log1.Write(_L("This is written from log session 1"));
	test(log1.LastError()==KErrNone);
	test(log1.LogValid()==aValid);
	log2.Write(_L("This is written from log session 2"));
	test(log2.LastError()==KErrNone);
	test(log2.LogValid()==aValid);

	WriteToLog(log1);
	WriteToLog(log2);

	log1.CloseLog();
	log2.CloseLog();

	TUint temp;
	if (aValid)
		test(fs.Att(KTestLogFile4,temp)==KErrNone);
	else
		test(fs.Att(KTestLogFile4,temp)==KErrPathNotFound);

	log1.Close();
	log2.Close();
	}

// 2.2.4 Invalid operations
//
// Check that buffers larger than KLogBufferSize can be written without error.
LOCAL_C void testInvalidOps1L()
	{

	CreateFolderL(KTestLogFullDir4);

	RFileLogger log;
	test(log.Connect()==KErrNone);

	log.CreateLog(KTestLogDir4,KTestLogFileName1,EFileLoggingModeOverwrite);
	test(log.LastError()==KErrNone);
	test(log.LogValid());

	TBuf<151> longBuf;
	TChar ch('X');
	longBuf.Fill(ch,151);
	test(longBuf.Length()==151);
	log.Write(longBuf);					// only those chars which will fit will be written
	test(log.LastError()==KErrNone);

	TBuf8<151> longBuf8;
	longBuf8.Fill(ch,151);
	test(longBuf8.Length()==151);
	log.Write(longBuf8);				// only those chars which will fit will be written
	test(log.LastError()==KErrNone);

	log.Close();
	}
	
// Check that overlong directory names as well as file names cause an overflow error.
LOCAL_C void testInvalidOps2L()
	{

	CreateFolderL(KTestLogFullDir4);

	RFileLogger log;
	test(log.Connect()==KErrNone);

	TFileName dirName, fileName;
	dirName.SetLength(dirName.MaxLength());
	log.CreateLog(dirName,KTestLogFileName1,EFileLoggingModeOverwrite);
	test(log.LastError()==KErrOverflow);

	fileName.SetLength(fileName.MaxLength());
	log.CreateLog(KTestLogDir1,fileName,EFileLoggingModeOverwrite);
	test(log.LastError()==KErrOverflow);

	log.Close();
	}

// 2.2.3 Access counting 
LOCAL_C void TestAccessCountingL(TBool aValid)
	{

	if (aValid)
		CreateFolderL(KTestLogFullDir5);
	else
		DeleteFolder(KTestLogFullDir5);

	RFileLogger log;
	test(log.Connect()==KErrNone);

	log.CreateLog(KTestLogDir5,KTestLogFileName1,EFileLoggingModeOverwrite);
	test(log.LastError()==KErrNone);

	log.CloseLog();

	log.CreateLog(KTestLogDir5,KTestLogFileName1,EFileLoggingModeOverwrite);
	test(log.LastError()==KErrNone);

	log.CloseLog();

	log.CreateLog(KTestLogDir5,KTestLogFileName1,EFileLoggingModeOverwrite);
	test(log.LastError()==KErrNone);

	log.Close();

// Test closing log twice

	test(log.Connect()==KErrNone);

	log.CreateLog(KTestLogDir5,KTestLogFileName1,EFileLoggingModeOverwrite);
	test(log.LastError()==KErrNone);

	log.CloseLog();
	log.CloseLog();			// timer will be running if file exists
	User::After(6000000);
	log.CloseLog();			// timer will have expired
	log.Close();

// Test closing session twice

	test(log.Connect()==KErrNone);

	log.Close();
	log.Close();			// timer will be running
	TestWaitForShutDown();
	log.Close();			// timer will have expired
	}

LOCAL_C void doExampleL()
	{

	User::LeaveIfError(fs.Connect());

	// delete all files and folders
	DeleteFolder(KTestLogFullDir1);	// ignore return value
	DeleteFolder(KTestLogFullDir2);	// ignore return value
	DeleteFolder(KTestLogFullDir3);	// ignore return value
	DeleteFolder(KTestLogFullDir4);

	test.Printf(_L("\nDo tests with Folders not existing....\n"));

	test.Start(_L("Two Sessions logging to different files: PDS-FILELOGGER-UT-4001"));
	testTwoClientsL(EFalse);	// folders do not exist
	
	test.Next(_L("Two sessions logging to one file: PDS-FILELOGGER-UT-4002"));
	testTwoClientsOneFileL(EFalse);		// folders do not exist
	
	test.Next(_L("Static logging: PDS-FILELOGGER-UT-4003"));
	testStaticWrites(EFalse);		// folders do not exist

	test.Next(_L("Test Closing and Access Counting: PDS-FILELOGGER-UT-4004"));
	TestAccessCountingL(EFalse);

	test.Printf(_L("\nDo tests with Folders existing....\n"));

	test.Start(_L("Two Sessions logging to different files: PDS-FILELOGGER-UT-4001"));
	testTwoClientsL(ETrue);		// folders exist

	test.Next(_L("Two sessions logging to one file: PDS-FILELOGGER-UT-4002"));
	testTwoClientsOneFileL(ETrue);		// folders exist

	test.Next(_L("Static logging: PDS-FILELOGGER-UT-4003"));
	testStaticWrites(ETrue);		// folders exist

	test.Next(_L("Invalid Operations: PDS-FILELOGGER-UT-4005"));
	testInvalidOps1L();
	test.Next(_L("Invalid Operations: PDS-FILELOGGER-UT-4006"));
	testInvalidOps2L();

	test.Next(_L("Test Closing and Access Counting: PDS-FILELOGGER-UT-4004"));
	TestAccessCountingL(ETrue);

	RFileLogger log;
	test(log.Connect()==KErrNone);
	log.Close();

	TestWaitForShutDown();
	test.End();

	fs.Close();
	}

GLDEF_C TInt E32Main()
	{

	CTrapCleanup* cleanup=CTrapCleanup::New();

	__UHEAP_MARK;
	
	test.Title();

	TRAPD(ret,doExampleL());
	test(ret==KErrNone);
	
    test.End();
	test.Close();

	__UHEAP_MARKEND;

	delete cleanup;
	User::Heap().Check();
	return KErrNone;
	}
