// Copyright (c) 1996-2009 Nokia Corporation and/or its subsidiary(-ies).
// All rights reserved.
// This component and the accompanying materials are made available
// under the terms of the License "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:
// f32test\server\t_rcount.cpp
// 
//

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

#include "../server/t_server.h"

GLDEF_D RTest test(_L("T_RCOUNT"));
const TInt KHeapSize=0x2000;

LOCAL_C void Test1()
//
// Test resource counting success
//
	{

	test.Start(_L("Test resource count success"));
	RFs TheFs;
	TheFs.Connect();
	RFile file;
	TheFs.ResourceCountMarkStart();
	TInt count=TheFs.ResourceCount();
	test(count==0);
	TFileName name=_L("Z:\\Test\\T_FILE.CPP");
	name[0] = gExeFileName[0];
	test.Printf(_L("%S\n"),&name);
	TInt r=file.Open(TheFs,name,EFileRead);
	test(r==KErrNone);
	count=TheFs.ResourceCount();
	test(count==1);
	file.Close();
	count=TheFs.ResourceCount();
	test(count==0);
	TheFs.ResourceCountMarkEnd();
	TheFs.Close();
	}

LOCAL_C TInt TestPanic(TAny*)
//
// The Test thread
//
	{

	User::SetJustInTime(EFalse);
	RFs fs;
	TInt r=fs.Connect();
	test(r==KErrNone);
	RFile file;
	fs.ResourceCountMarkStart();
	TFileName name=_L("Z:\\Test\\T_FILE.CPP");
	name[0] = gExeFileName[0];

	r=file.Open(fs,name,EFileRead);
	test(r==KErrNone);
	TInt count=fs.ResourceCount();
	test(count==1);
	fs.ResourceCountMarkEnd(); // MarkEnd without close
	fs.Close();
	return KErrNone;
	}

LOCAL_C void Test2()
//
// Test resource count failure
//
	{

	test.Next(_L("Test resource count failure"));
	TRequestStatus stat;	
	RThread t;
	TInt r=t.Create(_L("TestPanicThread"),TestPanic,KDefaultStackSize,KHeapSize,KHeapSize,NULL);
	test(r==KErrNone);
	t.Logon(stat);
	t.Resume();
	User::WaitForRequest(stat);	
	test(t.ExitReason()==CSession2::ESesFoundResCountHeaven);
	test(t.ExitType()==EExitPanic);
	CLOSE_AND_WAIT(t);
	}


_LIT(KDirName1, "c:\\f32-tst");
_LIT(KFileName1, "c:\\crash001.txt");
_LIT(KFileName2, "c:\\crash002.txt");

LOCAL_C TInt SendBadHandle1(TAny *)
//
// Thread is panicked when server leaves when DoFsSubCloseL() calls CObjectIx::AtL().
// Avoid case where thread is panicked by CObjectIx::Remove() because
// ! (i<iHighWaterMark) closing the first file removes all of the CObjects.
//
	{
	RFs fs;
	test(fs.Connect() == KErrNone);

	RFile f1;
	test(f1.Replace(fs, KFileName1, EFileWrite) == KErrNone);
	RFile fc(f1);

	f1.Close();
	fc.Close();									// file server panics thread here

	test(EFalse);
	fs.Close();
	return KErrNone;							// shouldn't reach here
	}


LOCAL_C TInt SendBadHandle2(TAny *)
//
// Thread is panicked when server leaves when DoFsSubClose() calls CObjectIx::AtL().
// Avoid case where thread is panicked by CObjectIx() because ! pR->obj, with handle
// having been already removed.
//
	{
	RFs fs;
	test(fs.Connect() == KErrNone);

	RFile f1;
	test(f1.Replace(fs, KFileName1, EFileWrite) == KErrNone);
	RFile f2;
	test(f2.Replace(fs, KFileName2, EFileWrite) == KErrNone);

	RFile fc(f1);
	f1.Close();
	fc.Close();									// file server panics thread here

	test(EFalse);
	fs.Close();
	return KErrNone;							// shouldn't reach here
	}


LOCAL_C TInt SendBadHandle3(TAny*)
//
// Setup a bad RFile handle then try to write to the file, 
// the thread should get paniced by the file server
//
	{
	RFs f;
	TInt r = f.Connect();
	test(r==KErrNone);

	RFile a;
	r=a.Replace(f,KFileName1,EFileWrite);
	test(r==KErrNone);
	RFile b(a);
	a.Close();
	
	r=b.Write(_L8("testing testing"));
	
	//thread should get paniced here so should not reach this
	
	test(EFalse);
	f.Close();	

	return KErrNone;
	}


LOCAL_C TInt SendBadHandle4(TAny*)
//
// Setup a bad RDir handle then try to read the Directory, 
// the thread should get panniced by the server
//
	{
	RFs f;
	TInt r = f.Connect();
	test(r==KErrNone);

	RDir a;
	r=a.Open(f,KDirName1,KEntryAttNormal);
	test(r==KErrNone);
	RDir b(a);
	a.Close();
	
	TEntryArray dummyarray;
	r=b.Read(dummyarray);
	
	//thread should get paniced here so should not reach this
	
	test(EFalse);
	f.Close();	

	return KErrNone;
	}

LOCAL_C TInt SendBadHandle5(TAny*)
//
// Setup a bad RFormat handle then try to call next on the Format object, 
// the thread should get panniced by the server
//
	{

#if defined(__EPOC32__)
	_LIT(KDrive1, "C:\\");
#else
	_LIT(KDrive1, "X:\\");
#endif

	RFs f;
	TInt r = f.Connect();
	test(r==KErrNone);

	RFormat a;
	TInt count;
	r=a.Open(f,KDrive1,EQuickFormat,count);
	test(r==KErrNone);
	RFormat b(a);
	a.Close();
	
	r=b.Next(count);
	
	//thread should get paniced here so should not reach this
	
	test(EFalse);
	f.Close();	

	return KErrNone;
	}


LOCAL_C TInt SendBadHandle6(TAny*)
//
// Setup a bad RRawDisk handle then try to call read on the raw disk object, 
// the thread should get panniced by the server
//
	{

#if defined(__EPOC32__)
	const TInt KDrive1 = EDriveC;
#else
	const TInt KDrive1 = EDriveX;
#endif
	
	RFs f;
	TInt r = f.Connect();
	test(r==KErrNone);

	RRawDisk a;
    r=a.Open(f,KDrive1);

	test(r==KErrNone);
	RRawDisk b(a);
	a.Close();
	TBuf8<19> buffer;
	r=b.Read(0,buffer);
	
	//thread should get paniced here so should not reach this
	
	test(EFalse);
	f.Close();	

	return KErrNone;
	}





LOCAL_C void Test3()
//
//	Test how the file server copes with bad handles
//
	{
	test.Start(_L("RunTests()"));

	TRequestStatus rs;

	RThread t1;
	User::SetJustInTime(EFalse);
	test(t1.Create(_L("Handle1Test"), SendBadHandle1, KDefaultStackSize, KHeapSize, KHeapSize, NULL) == KErrNone);
	t1.Logon(rs);
	t1.Resume();
	User::WaitForRequest(rs);
	User::SetJustInTime(ETrue);
	test(t1.ExitType() == EExitPanic);
	test(t1.ExitReason() == KErrBadHandle);
	CLOSE_AND_WAIT(t1);

	RThread t2;
	User::SetJustInTime(EFalse);
	test(t2.Create(_L("Handle2Test"), SendBadHandle2, KDefaultStackSize, KHeapSize, KHeapSize, NULL) == KErrNone);
	t2.Logon(rs);
	t2.Resume();
	User::WaitForRequest(rs);
	User::SetJustInTime(ETrue);
	test(t2.ExitType() == EExitPanic);
	test(t2.ExitReason() == KErrBadHandle);
	CLOSE_AND_WAIT(t2);

	RThread t3;
	User::SetJustInTime(EFalse);
	test(t3.Create(_L("Handle2Test"), SendBadHandle3, KDefaultStackSize, KHeapSize, KHeapSize, NULL) == KErrNone);
	t3.Logon(rs);
	t3.Resume();
	User::WaitForRequest(rs);
	User::SetJustInTime(ETrue);
	test(t3.ExitType() == EExitPanic);
	test(t3.ExitReason() == KErrBadHandle);
	CLOSE_AND_WAIT(t3);

	RThread t4;
	User::SetJustInTime(EFalse);
	test(t4.Create(_L("Handle2Test"), SendBadHandle4, KDefaultStackSize, KHeapSize, KHeapSize, NULL) == KErrNone);
	t4.Logon(rs);
	t4.Resume();
	User::WaitForRequest(rs);
	User::SetJustInTime(ETrue);
	test(t4.ExitType() == EExitPanic);
	test(t4.ExitReason() == KErrBadHandle);
	CLOSE_AND_WAIT(t4);

	RThread t5;
	User::SetJustInTime(EFalse);
	test(t5.Create(_L("Handle2Test"), SendBadHandle5, KDefaultStackSize, KHeapSize, KHeapSize, NULL) == KErrNone);
	t5.Logon(rs);
	t5.Resume();
	User::WaitForRequest(rs);
	User::SetJustInTime(ETrue);
	test(t5.ExitType() == EExitPanic);
	test(t5.ExitReason() == KErrBadHandle);
	CLOSE_AND_WAIT(t5);

	RThread t6;
	User::SetJustInTime(EFalse);
	test(t6.Create(_L("Handle2Test"), SendBadHandle6, KDefaultStackSize, KHeapSize, KHeapSize, NULL) == KErrNone);
	t6.Logon(rs);
	t6.Resume();
	User::WaitForRequest(rs);
	User::SetJustInTime(ETrue);
	test(t6.ExitType() == EExitPanic);
	test(t6.ExitReason() == KErrBadHandle);
	CLOSE_AND_WAIT(t6);

	User::SetJustInTime(ETrue);
	test.End();
	
    }


LOCAL_C void DoTestsL()
//
// Call all tests
//
	{
	Test1();
	Test2();
	Test3();
	}

GLDEF_C void CallTestsL(void)
//
// Test resource counting
//
    {

	test.Title();
	test.Start(_L("Starting T_RCOUNT test"));

	DoTestsL();

	test.End();
	test.End();
	test.Close();

	return;
    }

