diff -r c55016431358 -r 0a7b44b10206 symport/e32test/system/t_ctrap.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/symport/e32test/system/t_ctrap.cpp Thu Jun 25 15:59:54 2009 +0100 @@ -0,0 +1,1592 @@ +// Copyright (c) 1995-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 "Symbian Foundation License v1.0" +// which accompanies this distribution, and is available +// at the URL "http://www.symbianfoundation.org/legal/sfl-v10.html". +// +// Initial Contributors: +// Nokia Corporation - initial contribution. +// +// Contributors: +// +// Description: +// e32test\system\t_ctrap.cpp +// Overview: +// Test the CCleanup, CTrapCleanup and TAutoClose classes +// API Information: +// CCleanup, CTrapCleanup, TAutoClose +// Details: +// - Test cleanup stack reallocation during cleanup. +// - Test cleanup stack modifications during the cleanup operation +// will cause a panic. +// - Test single-level cleanup of cells, objects, items and a mix: +// Create a CCleanup object, call a combination of methods, verify +// the results are as expected and verify the heap has not been +// corrupted. +// - Test multi-level cleanup of cells, objects, items and a mix: +// Create a CCleanup object, call a combination of methods, verify +// the results are as expected and verify the heap has not been +// corrupted. +// - Test a variety of special case cleanup tasks. Verify that the +// results are as expected. +// - Test CTrapCleanup cleanup of objects that either exit normally +// or leave. Also test the cleanup of multiple objects that leave. +// Verify results are as expected. +// - Test TAutoClose: create a TAutoClose object, verify that it is +// closed when it goes out of scope, push it on the cleanup stack, +// verify cleanup results are as expected. +// - Test that the Cleanup stack can go re-entrant. +// - Ensure that the stack is properly balanced with and without +// leaving. +// Platforms/Drives/Compatibility: +// All. +// Assumptions/Requirement/Pre-requisites: +// Failures and causes: +// Base Port information: +// +// + +#define __E32TEST_EXTENSION__ + +#include +#include +#include + + +const TInt KInitialCount=2; +const TInt KInitialCountAll=3; +const TInt KLeaveValue=0x12345678; +const TInt KMaxAlloc=6; + +static const TInt KHeapSize = 0x2000; + +enum TWhat {EPop,EPopAndDestroy,EMulti,ENull}; + +class CTest : public CBase + { +public: + void ConstructL(); +private: + TInt iData; + }; + +class CTest2: public CBase + { +public: + ~CTest2(); + }; + +class CTest3: public CBase + { +public: + ~CTest3(); + }; + +class RItem + { +public: + RItem() : iOpen(EFalse) {} + void Open() {iOpen=ETrue;} + void Close() {iOpen=EFalse;} + operator TCleanupItem() {return TCleanupItem(Cleanup,this);} + TBool IsOpen() const {return(iOpen);} +private: + static void Cleanup(TAny* aPtr); +private: + TBool iOpen; + }; + +LOCAL_D RTest test(_L("T_CTRAP")); +LOCAL_D TAny* gP1; +LOCAL_D CBufFlat* gP2; + + +LOCAL_C void ReallocateStackL() + { + TInt n = 0; + for(TInt i = 0; i < KMaxAlloc; ++i) + { + HBufC *p1 = HBufC::NewLC(4); //Stack re-allocation will be performed due to the additional objects pushed + //into the cleanup stack + n = p1->Length(); //include this line to avoid warnigs for unused "p1" variable + } + test.Printf(_L("ReallocateStackL(): PopAndDestroy KMaxAlloc pointers\n")); + CleanupStack::PopAndDestroy(KMaxAlloc); + } + +CTest2::~CTest2() + { + TInt err = KErrNoMemory; + + test.Printf(_L("~CTest2(): call ReallocateStackL()\n")); + + TRAP(err, ReallocateStackL() ); + } + +CTest3::~CTest3() + { + RDebug::Printf("~CTest3(): Modify Cleanup stack by pushing items"); + + TInt n = 0; + for(TInt i = 0; i < KMaxAlloc; ++i) + { + HBufC *p1 = HBufC::NewLC(4); //Stack re-allocation will be performed due to the additional objects pushed + //into the cleanup stack + n = p1->Length(); //include this line to avoid warnigs for unused "p1" variable + } + } + +#ifndef __TOOLS2__ +LOCAL_C void ModifyStack() + { + CTest3* ptr6 = new(ELeave)CTest3; + CleanupStack::PushL(ptr6); + + RDebug::Printf("ModifyStack(): PopAndDestroy ptr6"); + CleanupStack::PopAndDestroy(); + } + +LOCAL_C TInt PanicStackModifiedFn(TAny* aNopFn) + { + __UHEAP_MARK; + CTrapCleanup* cleanup = CTrapCleanup::New(); + + aNopFn = NULL; //avoid warnings for unused "aNopFn" variable + + TInt err = KErrNoMemory; + + RDebug::Printf("PanicStackModifiedFn(): call TRAP(err, ModifyStack())"); + + if(NULL != cleanup) + { + TRAP(err, ModifyStack()); + delete cleanup; + } + __UHEAP_MARKEND; + return err; + } + +LOCAL_C void PushAndCleanupL() + { + CTest2* ptr1 = new(ELeave)CTest2; + CleanupStack::PushL(ptr1); + + CTest2* ptr2 = new(ELeave)CTest2; + CleanupStack::PushL(ptr2); + + CTest2* ptr3 = new(ELeave)CTest2; + CleanupStack::PushL(ptr3); + + test.Printf(_L("PushAndCleanupL(): PopAndDestroy ptr3, ptr2 and ptr1\n")); + CleanupStack::PopAndDestroy(3); + + CTest2* ptr4 = new(ELeave)CTest2; + CleanupStack::PushL(ptr4); + + CTest2* ptr5 = new(ELeave)CTest2; + CleanupStack::PushL(ptr5); + + test.Printf(_L("PushAndCleanupL(): PopAndDestroy ptr5 and ptr4\n")); + CleanupStack::PopAndDestroy(); + CleanupStack::PopAndDestroy(); + } + +LOCAL_C void testDestructorStackReallocation() + { + __UHEAP_MARK; + CTrapCleanup* cleanup = CTrapCleanup::New(); + + TInt err = KErrNoMemory; + + if(NULL != cleanup) + { + TRAP(err, PushAndCleanupL()); + delete cleanup; + } + __UHEAP_MARKEND; + + test_KErrNone(err); + + test.Printf(_L("Verify cleanup stack modification during cleanup operation causes EClnStackModified panic\n")); + + // + //To verify the above case a new thread is created which does modify the cleanup stack during cleanup. + //The exit reason is then checked for the appropriate value(EClnStackModified) + // + + RThread panicThread; + + TInt r = panicThread.Create(_L("Panic EClnStackModified Thread"), PanicStackModifiedFn, KDefaultStackSize, KHeapSize, KHeapSize, NULL); + + test_KErrNone(r); + + TRequestStatus panicThreadStatus; + panicThread.Logon(panicThreadStatus); + + //don't want just in time debugging as we trap panics + TBool justInTime=User::JustInTime(); + User::SetJustInTime(EFalse); + + panicThread.Resume(); + + User::WaitForRequest(panicThreadStatus); + + test_Equal(EExitPanic, panicThread.ExitType()); + test_Equal(EClnStackModified, panicThread.ExitReason()); + + User::SetJustInTime(justInTime); + + CLOSE_AND_WAIT(panicThread); + } +#endif + +LOCAL_C void createMultiL() +// +// Create an object on the cleanup list and leave +// + { + + CBufFlat* pT=CBufFlat::NewL(8); + User::LeaveIfNull(pT); + CleanupStack::PushL(pT); + __UHEAP_CHECK(3); + User::Leave(KLeaveValue+1); + } + +LOCAL_C void createL(TWhat aWhat,TBool aLeave) +// +// Create objects and then either leave or return. +// Optionally pop them again. +// + { + + gP1=User::AllocL(0x10); + test.Printf(_L("createL 1")); + CleanupStack::PushL(gP1); + test.Printf(_L("createL 2")); + __UHEAP_CHECK(1); + test.Printf(_L("createL 3")); + gP2=CBufFlat::NewL(8); + test.Printf(_L("createL 4")); + User::LeaveIfNull(gP2); + test.Printf(_L("createL 5")); + CleanupStack::PushL(gP2); + test.Printf(_L("createL 6")); + __UHEAP_CHECK(2); + test.Printf(_L("createL 7")); + if (aWhat==EPop) + { + test.Printf(_L("createL 8")); + CleanupStack::Pop(); + test.Printf(_L("createL 9")); + CleanupStack::Pop(1); + test.Printf(_L("createL 10")); + } + if (aWhat==EPopAndDestroy) + { + test.Printf(_L("createL 11")); + CleanupStack::PopAndDestroy(); + test.Printf(_L("createL 12")); + CleanupStack::PopAndDestroy(1); + test.Printf(_L("createL 13")); + } + if (aWhat==EMulti) + { + test.Printf(_L("createL 14")); + TRAPD(r,createMultiL()) + test.Printf(_L("createL 15")); + test(r==(KLeaveValue+1)); + test.Printf(_L("createL 16")); + __UHEAP_CHECK(2); + test.Printf(_L("createL 17")); + } + if (aLeave) + { + test.Printf(_L("createL 18")); + User::Leave(KLeaveValue); + } + test.Printf(_L("createL 19")); + } + +LOCAL_C void createAllL(TBool aLeave) +// +// Call all functions which autmatically put objects on the cleanup list. +// + { + + __UHEAP_CHECK(KInitialCountAll); + TLex* pL=new(ELeave) TLex; // ::new, 1 cell + CleanupStack::PushL(pL); // Push + __UHEAP_CHECK(KInitialCountAll+1); + CTest* pT=new(ELeave) CTest; // CBase::new, 1 cell + CleanupStack::PushL(pT); // Push + __UHEAP_CHECK(KInitialCountAll+2); + pT->ConstructL(); // 1 more cell // Push + __UHEAP_CHECK(KInitialCountAll+3); + User::AllocLC(0x10); // Test RHeap::AllocLC as well // Push + __UHEAP_CHECK(KInitialCountAll+4); + _L("Hello").AllocLC(); // Test HBufC::NewLC() as well // Push + __UHEAP_CHECK(KInitialCountAll+5); + HBufC* pH=HBufC::NewMaxLC(8); // Push + test(pH->Length()==8); + __UHEAP_CHECK(KInitialCountAll+6); + if (aLeave) + User::Leave(KLeaveValue); + // new behavior for TCleanupTrapHander requires Pushes to the + // cleanup stack to be balanced by Pops + CleanupStack::PopAndDestroy(6); + } + +LOCAL_C void testSingleLevelCellsCleanup() +// +// Test single level cells cleanup +// + { + + test.Start(_L("Creating")); +// + __UHEAP_MARK; + CCleanup* pC=CCleanup::New(); + test(pC!=NULL); +// + __UHEAP_MARK; +// + test.Next(_L("PopAll when empty")); + pC->NextLevel(); + pC->PopAll(); + pC->NextLevel(); + pC->PopAndDestroyAll(); + __UHEAP_CHECK(0); +// + test.Next(_L("Push and pop")); + TAny* p=User::Alloc(0x10); + test(p!=NULL); + __UHEAP_CHECK(1); + pC->NextLevel(); + pC->PushL(p); + pC->Pop(); + __UHEAP_CHECK(1); + User::Free(p); + __UHEAP_CHECK(0); + pC->PopAll(); + __UHEAP_CHECK(0); +// + test.Next(_L("Push and pop N")); + TAny* p1=User::Alloc(0x10); + test(p1!=NULL); + __UHEAP_CHECK(1); + TAny* p2=User::Alloc(0x10); + test(p2!=NULL); + __UHEAP_CHECK(2); + pC->NextLevel(); + pC->PushL(p1); + pC->PushL(p2); + pC->Pop(2); + __UHEAP_CHECK(2); + User::Free(p1); + User::Free(p2); + __UHEAP_CHECK(0); + pC->PopAll(); + __UHEAP_CHECK(0); +// + test.Next(_L("Push and pop all")); + p1=User::Alloc(0x10); + test(p1!=NULL); + __UHEAP_CHECK(1); + p2=User::Alloc(0x10); + test(p2!=NULL); + __UHEAP_CHECK(2); + TAny* p3=User::Alloc(0x10); + test(p3!=NULL); + __UHEAP_CHECK(3); + pC->NextLevel(); + pC->PushL(p1); + pC->PushL(p2); + pC->PushL(p3); + pC->PopAll(); + __UHEAP_CHECK(3); + User::Free(p1); + User::Free(p2); + User::Free(p3); + __UHEAP_CHECK(0); +// + test.Next(_L("Push and pop and destroy")); + p=User::Alloc(0x10); + test(p!=NULL); + __UHEAP_CHECK(1); + pC->NextLevel(); + pC->PushL(p); + pC->PopAndDestroy(); + __UHEAP_CHECK(0); + pC->PopAll(); +// + test.Next(_L("Push and pop and destroy N")); + p1=User::Alloc(0x10); + test(p1!=NULL); + __UHEAP_CHECK(1); + p2=User::Alloc(0x10); + test(p2!=NULL); + __UHEAP_CHECK(2); + pC->NextLevel(); + pC->PushL(p1); + pC->PushL(p2); + pC->PopAndDestroy(2); + __UHEAP_CHECK(0); + pC->PopAll(); + __UHEAP_CHECK(0); +// + test.Next(_L("Push and pop and destroy all")); + p1=User::Alloc(0x10); + test(p1!=NULL); + __UHEAP_CHECK(1); + p2=User::Alloc(0x10); + test(p2!=NULL); + __UHEAP_CHECK(2); + p3=User::Alloc(0x10); + test(p3!=NULL); + __UHEAP_CHECK(3); + pC->NextLevel(); + pC->PushL(p1); + pC->PushL(p2); + pC->PushL(p3); + pC->PopAndDestroyAll(); + __UHEAP_CHECK(0); +// + __UHEAP_MARKEND; +// + delete pC; + __UHEAP_MARKEND; +// + test.End(); + } + +LOCAL_C void testSingleLevelObjCleanup() +// +// Test single level object cleanup +// + { + + test.Start(_L("Creating")); +// + __UHEAP_MARK; + CCleanup* pC=CCleanup::New(); + test(pC!=NULL); +// + __UHEAP_MARK; +// + test.Next(_L("Push and pop")); + CBufFlat* p=CBufFlat::NewL(8); + test(p!=NULL); + __UHEAP_CHECK(1); + pC->NextLevel(); + pC->PushL(p); + pC->Pop(); + __UHEAP_CHECK(1); + User::Free(p); + __UHEAP_CHECK(0); + pC->PopAll(); + __UHEAP_CHECK(0); +// + test.Next(_L("Push and pop N")); + CBufFlat* p1=CBufFlat::NewL(8); + test(p1!=NULL); + __UHEAP_CHECK(1); + CBufFlat* p2=CBufFlat::NewL(8); + test(p2!=NULL); + __UHEAP_CHECK(2); + pC->NextLevel(); + pC->PushL(p1); + pC->PushL(p2); + pC->Pop(2); + __UHEAP_CHECK(2); + User::Free(p1); + User::Free(p2); + __UHEAP_CHECK(0); + pC->PopAll(); + __UHEAP_CHECK(0); +// + test.Next(_L("Push and pop all")); + p1=CBufFlat::NewL(8); + test(p1!=NULL); + __UHEAP_CHECK(1); + p2=CBufFlat::NewL(8); + test(p2!=NULL); + __UHEAP_CHECK(2); + CBufFlat* p3=CBufFlat::NewL(8); + test(p3!=NULL); + __UHEAP_CHECK(3); + pC->NextLevel(); + pC->PushL(p1); + pC->PushL(p2); + pC->PushL(p3); + pC->PopAll(); + __UHEAP_CHECK(3); + User::Free(p1); + User::Free(p2); + User::Free(p3); + __UHEAP_CHECK(0); +// + test.Next(_L("Push and pop and destroy")); + p=CBufFlat::NewL(8); + test(p!=NULL); + __UHEAP_CHECK(1); + pC->NextLevel(); + pC->PushL(p); + pC->PopAndDestroy(); + __UHEAP_CHECK(0); + pC->PopAll(); +// + test.Next(_L("Push and pop and destroy N")); + p1=CBufFlat::NewL(8); + test(p1!=NULL); + __UHEAP_CHECK(1); + p2=CBufFlat::NewL(8); + test(p2!=NULL); + __UHEAP_CHECK(2); + pC->NextLevel(); + pC->PushL(p1); + pC->PushL(p2); + pC->PopAndDestroy(2); + __UHEAP_CHECK(0); + pC->PopAll(); + __UHEAP_CHECK(0); +// + test.Next(_L("Push and pop and destroy all")); + p1=CBufFlat::NewL(8); + test(p1!=NULL); + __UHEAP_CHECK(1); + p2=CBufFlat::NewL(8); + test(p2!=NULL); + __UHEAP_CHECK(2); + p3=CBufFlat::NewL(8); + test(p3!=NULL); + __UHEAP_CHECK(3); + pC->NextLevel(); + pC->PushL(p1); + pC->PushL(p2); + pC->PushL(p3); + pC->PopAndDestroyAll(); + __UHEAP_CHECK(0); +// + __UHEAP_MARKEND; +// + delete pC; + __UHEAP_MARKEND; +// + test.End(); + } + +LOCAL_C void testSingleLevelItemCleanup() +// +// Test single level object cleanup +// + { + + test.Start(_L("Creating")); +// + __UHEAP_MARK; + CCleanup* pC=CCleanup::New(); + test(pC!=NULL); +// + __UHEAP_MARK; +// + test.Next(_L("Push and pop")); + RItem r; + r.Open(); + test(r.IsOpen()); + pC->NextLevel(); + pC->PushL(r); + pC->Pop(); + test(r.IsOpen()); + r.Close(); + test(!r.IsOpen()); + pC->PopAll(); +// + test.Next(_L("Push and pop N")); + RItem r1; + r1.Open(); + RItem r2; + r2.Open(); + pC->NextLevel(); + pC->PushL(r1); + pC->PushL(r2); + pC->Pop(2); + test(r1.IsOpen()); + test(r2.IsOpen()); + r1.Close(); + r2.Close(); + pC->PopAll(); +// + test.Next(_L("Push and pop all")); + r1.Open(); + r2.Open(); + RItem r3; + r3.Open(); + pC->NextLevel(); + pC->PushL(r1); + pC->PushL(r2); + pC->PushL(r3); + pC->PopAll(); + test(r1.IsOpen()); + test(r2.IsOpen()); + test(r3.IsOpen()); + r1.Close(); + r2.Close(); + r3.Close(); +// + test.Next(_L("Push and pop and destroy")); + r.Open(); + pC->NextLevel(); + pC->PushL(r); + pC->PopAndDestroy(); + test(!r.IsOpen()); + pC->PopAll(); +// + test.Next(_L("Push and pop and destroy N")); + r1.Open(); + r2.Open(); + pC->NextLevel(); + pC->PushL(r1); + pC->PushL(r2); + pC->PopAndDestroy(2); + test(!r1.IsOpen()); + test(!r2.IsOpen()); + pC->PopAll(); +// + test.Next(_L("Push and pop and destroy all")); + r1.Open(); + r2.Open(); + r3.Open(); + pC->NextLevel(); + pC->PushL(r1); + pC->PushL(r2); + pC->PushL(r3); + pC->PopAndDestroyAll(); + test(!r1.IsOpen()); + test(!r2.IsOpen()); + test(!r3.IsOpen()); +// + __UHEAP_MARKEND; +// + delete pC; + __UHEAP_MARKEND; +// + test.End(); + } + +LOCAL_C void testSingleLevelMixCleanup() +// +// Test single level mixed cleanup +// + { + + test.Start(_L("Creating")); +// + __UHEAP_MARK; + CCleanup* pC=CCleanup::New(); + test(pC!=NULL); +// + __UHEAP_MARK; +// + test.Next(_L("PushO PushC PushI and pop N")); + CBufFlat* p1=CBufFlat::NewL(8); + test(p1!=NULL); + __UHEAP_CHECK(1); + TAny* p2=User::Alloc(0x10); + test(p2!=NULL); + __UHEAP_CHECK(2); + RItem r; + r.Open(); + pC->NextLevel(); + pC->PushL(p1); + pC->PushL(p2); + pC->PushL(r); + pC->Pop(3); + __UHEAP_CHECK(2); + test(r.IsOpen()); + User::Free(p1); + User::Free(p2); + r.Close(); + __UHEAP_CHECK(0); + pC->PopAll(); + __UHEAP_CHECK(0); +// + test.Next(_L("PushO PushI PushC PushO and pop all")); + p1=CBufFlat::NewL(8); + test(p1!=NULL); + __UHEAP_CHECK(1); + r.Open(); + p2=User::Alloc(0x10); + test(p2!=NULL); + __UHEAP_CHECK(2); + CBufFlat* p3=CBufFlat::NewL(8); + test(p3!=NULL); + __UHEAP_CHECK(3); + pC->NextLevel(); + pC->PushL(p1); + pC->PushL(r); + pC->PushL(p2); + pC->PushL(p3); + pC->PopAll(); + __UHEAP_CHECK(3); + test(r.IsOpen()); + User::Free(p1); + User::Free(p2); + User::Free(p3); + r.Close(); + __UHEAP_CHECK(0); +// + test.Next(_L("PushO PushC PushI and pop and destroy N")); + p1=CBufFlat::NewL(8); + test(p1!=NULL); + __UHEAP_CHECK(1); + p2=User::Alloc(0x10); + test(p2!=NULL); + __UHEAP_CHECK(2); + r.Open(); + pC->NextLevel(); + pC->PushL(p1); + pC->PushL(p2); + pC->PushL(r); + pC->PopAndDestroy(3); + test(!r.IsOpen()); + __UHEAP_CHECK(0); + pC->PopAll(); + __UHEAP_CHECK(0); +// + test.Next(_L("PushO PushI PushC PushO and pop and destroy all")); + p1=CBufFlat::NewL(8); + test(p1!=NULL); + __UHEAP_CHECK(1); + r.Open(); + p2=User::Alloc(0x10); + test(p2!=NULL); + __UHEAP_CHECK(2); + p3=CBufFlat::NewL(8); + test(p3!=NULL); + __UHEAP_CHECK(3); + pC->NextLevel(); + pC->PushL(p1); + pC->PushL(r); + pC->PushL(p2); + pC->PushL(p3); + pC->PopAndDestroyAll(); + test(!r.IsOpen()); + __UHEAP_CHECK(0); +// + __UHEAP_MARKEND; +// + delete pC; + __UHEAP_MARKEND; +// + test.End(); + } + +LOCAL_C void testMultiLevelCellsCleanup() +// +// Test multi level cells cleanup +// + { + + test.Start(_L("Creating")); +// + __UHEAP_MARK; + CCleanup* pC=CCleanup::New(); + test(pC!=NULL); +// + __UHEAP_MARK; +// + test.Next(_L("Nest push push nest push popall popall")); + TAny* p1=User::Alloc(0x10); + test(p1!=NULL); + __UHEAP_CHECK(1); + TAny* p2=User::Alloc(0x10); + test(p2!=NULL); + __UHEAP_CHECK(2); + TAny* p3=User::Alloc(0x10); + test(p3!=NULL); + __UHEAP_CHECK(3); + pC->NextLevel(); + pC->PushL(p1); + pC->PushL(p2); + pC->NextLevel(); + pC->PushL(p3); + pC->PopAll(); + __UHEAP_CHECK(3); + pC->PopAll(); + __UHEAP_CHECK(3); + User::Free(p1); + User::Free(p2); + User::Free(p3); + __UHEAP_CHECK(0); +// + test.Next(_L("Nest push push nest push popallD popallD")); + p1=User::Alloc(0x10); + test(p1!=NULL); + __UHEAP_CHECK(1); + p2=User::Alloc(0x10); + test(p2!=NULL); + __UHEAP_CHECK(2); + p3=User::Alloc(0x10); + test(p3!=NULL); + __UHEAP_CHECK(3); + pC->NextLevel(); + pC->PushL(p1); + pC->PushL(p2); + pC->NextLevel(); + pC->PushL(p3); + pC->PopAndDestroyAll(); + __UHEAP_CHECK(2); + pC->PopAndDestroyAll(); + __UHEAP_CHECK(0); +// + __UHEAP_MARKEND; +// + delete pC; + __UHEAP_MARKEND; +// + test.End(); + } + +LOCAL_C void testMultiLevelObjCleanup() +// +// Test multi level object cleanup +// + { + + test.Start(_L("Creating")); +// + __UHEAP_MARK; + CCleanup* pC=CCleanup::New(); + test(pC!=NULL); +// + __UHEAP_MARK; +// + test.Next(_L("Nest push push nest push popall popall")); + CBufFlat* p1=CBufFlat::NewL(8); + test(p1!=NULL); + __UHEAP_CHECK(1); + CBufFlat* p2=CBufFlat::NewL(8); + test(p2!=NULL); + __UHEAP_CHECK(2); + CBufFlat* p3=CBufFlat::NewL(8); + test(p3!=NULL); + __UHEAP_CHECK(3); + pC->NextLevel(); + pC->PushL(p1); + pC->PushL(p2); + pC->NextLevel(); + pC->PushL(p3); + pC->PopAll(); + __UHEAP_CHECK(3); + pC->PopAll(); + __UHEAP_CHECK(3); + User::Free(p1); + User::Free(p2); + User::Free(p3); + __UHEAP_CHECK(0); +// + test.Next(_L("Nest push push nest push popallD popallD")); + p1=CBufFlat::NewL(8); + test(p1!=NULL); + __UHEAP_CHECK(1); + p2=CBufFlat::NewL(8); + test(p2!=NULL); + __UHEAP_CHECK(2); + p3=CBufFlat::NewL(8); + test(p3!=NULL); + __UHEAP_CHECK(3); + pC->NextLevel(); + pC->PushL(p1); + pC->PushL(p2); + pC->NextLevel(); + pC->PushL(p3); + pC->PopAndDestroyAll(); + __UHEAP_CHECK(2); + pC->PopAndDestroyAll(); + __UHEAP_CHECK(0); +// + __UHEAP_MARKEND; +// + delete pC; + __UHEAP_MARKEND; +// + test.End(); + } + +LOCAL_C void testMultiLevelItemCleanup() +// +// Test multi level item cleanup +// + { + + test.Start(_L("Creating")); +// + __UHEAP_MARK; + CCleanup* pC=CCleanup::New(); + test(pC!=NULL); +// + __UHEAP_MARK; +// + test.Next(_L("Nest push push nest push popall popall")); + RItem r1; + r1.Open(); + RItem r2; + r2.Open(); + RItem r3; + r3.Open(); + pC->NextLevel(); + pC->PushL(r1); + pC->PushL(r2); + pC->NextLevel(); + pC->PushL(r3); + pC->PopAll(); + test(r1.IsOpen()); + test(r2.IsOpen()); + test(r3.IsOpen()); + pC->PopAll(); + test(r1.IsOpen()); + test(r2.IsOpen()); + test(r3.IsOpen()); + r1.Close(); + r2.Close(); + r3.Close(); +// + test.Next(_L("Nest push push nest push popallD popallD")); + r1.Open(); + r2.Open(); + r3.Open(); + pC->NextLevel(); + pC->PushL(r1); + pC->PushL(r2); + pC->NextLevel(); + pC->PushL(r3); + pC->PopAndDestroyAll(); + test(r1.IsOpen()); + test(r2.IsOpen()); + test(!r3.IsOpen()); + pC->PopAndDestroyAll(); + test(!r1.IsOpen()); + test(!r2.IsOpen()); + test(!r3.IsOpen()); +// + __UHEAP_MARKEND; +// + delete pC; + __UHEAP_MARKEND; +// + test.End(); + } + +LOCAL_C void testMultiLevelMixCleanup() +// +// Test multi level mixed cleanup +// + { + + test.Start(_L("Creating")); +// + __UHEAP_MARK; + CCleanup* pC=CCleanup::New(); + test(pC!=NULL); +// + __UHEAP_MARK; +// + test.Next(_L("Nest pushO pushC nest pushI popall popall")); + CBufFlat* p1=CBufFlat::NewL(8); + test(p1!=NULL); + __UHEAP_CHECK(1); + TAny* p2=User::Alloc(0x10); + test(p2!=NULL); + __UHEAP_CHECK(2); + RItem r3; + r3.Open(); + pC->NextLevel(); + pC->PushL(p1); + pC->PushL(p2); + pC->NextLevel(); + pC->PushL(r3); + pC->PopAll(); + __UHEAP_CHECK(2); + test(r3.IsOpen()); + pC->PopAll(); + __UHEAP_CHECK(2); + test(r3.IsOpen()); + User::Free(p1); + User::Free(p2); + r3.Close(); + __UHEAP_CHECK(0); +// + test.Next(_L("Nest pushO pushC nest pushI popallD popallD")); + p1=CBufFlat::NewL(8); + test(p1!=NULL); + __UHEAP_CHECK(1); + p2=User::Alloc(0x10); + test(p2!=NULL); + __UHEAP_CHECK(2); + r3.Open(); + pC->NextLevel(); + pC->PushL(p1); + pC->PushL(p2); + pC->NextLevel(); + pC->PushL(r3); + pC->PopAndDestroyAll(); + __UHEAP_CHECK(2); + test(!r3.IsOpen()); + pC->PopAndDestroyAll(); + test(!r3.IsOpen()); + __UHEAP_CHECK(0); +// + __UHEAP_MARKEND; +// + delete pC; + __UHEAP_MARKEND; +// + test.End(); + } + +LOCAL_C void testSpecialCaseCleanup() +// +// Test special case cleanup +// + { + + test.Start(_L("Creating")); +// + __UHEAP_MARK; + CCleanup* pC=CCleanup::New(); + test(pC!=NULL); + __UHEAP_CHECK(KInitialCount); +// + test.Next(_L("Nest push push push fail")); + CBufFlat* p1=CBufFlat::NewL(8); + test(p1!=NULL); + __UHEAP_CHECK(KInitialCount+1); + CBufFlat* p2=CBufFlat::NewL(8); + test(p2!=NULL); + __UHEAP_CHECK(KInitialCount+2); + CBufFlat* p3=CBufFlat::NewL(8); + test(p3!=NULL); + __UHEAP_CHECK(KInitialCount+3); + CBufFlat* p4=CBufFlat::NewL(8); + test(p4!=NULL); + __UHEAP_CHECK(KInitialCount+4); + CBufFlat* p5=CBufFlat::NewL(8); + test(p5!=NULL); + __UHEAP_CHECK(KInitialCount+5); + CBufFlat* p6=CBufFlat::NewL(8); + test(p6!=NULL); + __UHEAP_CHECK(KInitialCount+6); + pC->NextLevel(); + pC->PushL(p1); + pC->PushL(p2); + pC->PushL(p3); + pC->PushL(p4); + pC->PushL(p5); +// +// The granularity is 4 so this should try and grow the array +// since room is always made for a free slot. We set the allocator +// to fail so that we can test that the free slot is re-established +// when we do the cleanup. This test only works in debug mode. +// + __UHEAP_FAILNEXT(1); + TRAPD(r,pC->PushL(p6)); +#if defined(_DEBUG) + test(r==KErrNoMemory); +#endif + __UHEAP_CHECK(KInitialCount+6); + pC->PopAndDestroyAll(); + __UHEAP_CHECK(KInitialCount); +// + test.Next(_L("Nest push push push push popallD")); + p1=CBufFlat::NewL(8); + test(p1!=NULL); + __UHEAP_CHECK(KInitialCount+1); + p2=CBufFlat::NewL(8); + test(p2!=NULL); + __UHEAP_CHECK(KInitialCount+2); + p3=CBufFlat::NewL(8); + test(p3!=NULL); + __UHEAP_CHECK(KInitialCount+3); + p4=CBufFlat::NewL(8); + test(p4!=NULL); + __UHEAP_CHECK(KInitialCount+4); + pC->NextLevel(); + pC->PushL(p1); + pC->NextLevel(); + pC->PushL(p2); + pC->PushL(p3); + pC->PushL(p4); + pC->PopAndDestroyAll(); + __UHEAP_CHECK(KInitialCount+1); + pC->PopAndDestroyAll(); + __UHEAP_CHECK(KInitialCount); +// + test.Next(_L("Destroy cleanup object")); +// + p1=CBufFlat::NewL(8); + test(p1!=NULL); + __UHEAP_CHECK(KInitialCount+1); + p2=CBufFlat::NewL(8); + test(p2!=NULL); + __UHEAP_CHECK(KInitialCount+2); + p3=CBufFlat::NewL(8); + test(p3!=NULL); + __UHEAP_CHECK(KInitialCount+3); + p4=CBufFlat::NewL(8); + test(p4!=NULL); + __UHEAP_CHECK(KInitialCount+4); + pC->NextLevel(); + pC->PushL(p1); + pC->NextLevel(); + pC->PushL(p2); + pC->PushL(p3); + pC->PushL(p4); + delete pC; + __UHEAP_CHECK(0); +// + __UHEAP_MARKEND; +// + test.End(); + } + +LOCAL_C void testUnTrap() +// +// Test cleanup with normal exits +// + { + + test.Start(_L("Creating")); +// + __UHEAP_MARK; + CTrapCleanup* pT=CTrapCleanup::New(); + test(pT!=NULL); + __UHEAP_CHECK(KInitialCountAll); +// + __UHEAP_MARK; +// + test.Next(_L("PushC PushO EPop cleanup empty")); + TRAPD(r,createL(EPop,EFalse)) + test.Next(_L("PushC PushO EPop cleanup empty 1")); + test(r==KErrNone); + test.Next(_L("PushC PushO EPop cleanup empty 2")); + __UHEAP_CHECK(2); + test.Next(_L("PushC PushO EPop cleanup empty 3")); + User::Free(gP1); + test.Next(_L("PushC PushO EPop cleanup empty 4")); + delete gP2; + test.Next(_L("PushC PushO EPop cleanup empty 5")); + __UHEAP_CHECK(0); +// + test.Next(_L("PushC PushO EPopAndDestroy cleanup empty")); + TRAP(r,createL(EPopAndDestroy,EFalse)) + test(r==KErrNone); + __UHEAP_CHECK(0); +// +/* +// Change of behavior for TCleanupTrapHandler means that the current +// cleanup stack must be empty when UnTrap is called. IE. calls to +// Push should be balanced with a Pop within the same function. + test.Next(_L("PushC PushO ENull cleanup 2 objects")); + TRAP(r,createL(ENull,EFalse)) + test(r==KErrNone); + __UHEAP_CHECK(0); +*/ + __UHEAP_MARKEND; +// + test.Next(_L("Test all LC functions")); + TRAP(r,createAllL(EFalse)) + test(r==KErrNone); + __UHEAP_CHECK(KInitialCountAll); +// + delete pT; + __UHEAP_MARKEND; +// + test.End(); + } + +LOCAL_C void testLeave() +// +// Test cleanup with leave exits +// + { + + test.Start(_L("Creating")); +// + __UHEAP_MARK; + CTrapCleanup* pT=CTrapCleanup::New(); + test(pT!=NULL); + __UHEAP_CHECK(KInitialCountAll); +// + __UHEAP_MARK; +// + test.Next(_L("PushC PushO EPop cleanup empty and leave")); + TRAPD(r,createL(EPop,ETrue)) + test(r==KLeaveValue); + __UHEAP_CHECK(2); + User::Free(gP1); + delete gP2; + __UHEAP_CHECK(0); +// + test.Next(_L("PushC PushO EPopAndDestroy cleanup empty and leave")); + TRAP(r,createL(EPopAndDestroy,ETrue)) + test(r==KLeaveValue); + __UHEAP_CHECK(0); +// + test.Next(_L("PushC PushO ENull cleanup 2 objects and leave")); + TRAP(r,createL(ENull,ETrue)) + test(r==KLeaveValue); + __UHEAP_CHECK(0); + __UHEAP_MARKEND; +// + test.Next(_L("Test all LC functions and leave")); + TRAP(r,createAllL(ETrue)) + test(r==KLeaveValue); + __UHEAP_CHECK(KInitialCountAll); +// + delete pT; + __UHEAP_MARKEND; +// + test.End(); + } + +LOCAL_C void testMultiLeave() +// +// Test cleanup with multiple leave exits +// + { + + test.Start(_L("Creating")); +// + __UHEAP_MARK; + CTrapCleanup* pT=CTrapCleanup::New(); + test(pT!=NULL); +// + __UHEAP_MARK; +// + test.Next(_L("PushC PushO nest PushO cleanup leave leave")); + TRAPD(r,createL(EMulti,ETrue)) + test(r==KLeaveValue); + __UHEAP_CHECK(0); + __UHEAP_MARKEND; +// + delete pT; + __UHEAP_MARKEND; +// + test.End(); + } + +LOCAL_C void addNullItemL() + { + CleanupStack::PushL((TAny*)0); + } + +LOCAL_C void addCellL() + { + User::AllocLC(4); + } + +LOCAL_C void useCleanupStackL() + { + addNullItemL(); + addCellL(); + CleanupStack::PopAndDestroy(); + CleanupStack::Pop(); + } + +LOCAL_C void reentrantCleanup(TAny*) +// +// A cleanup operation which uses a trap harness and the cleanup stack +// + { + TRAPD(ignore,useCleanupStackL()) + } + +LOCAL_C void addReentrantItemL() + { + CleanupStack::PushL(TCleanupItem(reentrantCleanup)); + } + +LOCAL_C void addItemsL(TInt aCount) +// +// add number of reentrant items to make stack fail +// + { + while (--aCount>=0) + addReentrantItemL(); +#if !defined(_DEBUG) + User::Leave(KErrNoMemory); // heap failure not available +#endif + } + +const TInt KInitialStackSize=8; // from UC_CLN.CPP +const TInt KGrowItems=KInitialStackSize-3; + +LOCAL_C void testReentrancyL() +// +// Test the Cleanup stack can go re-entrant +// + { + + test.Next(_L("PopAndDestroy()")); + __UHEAP_MARK; + addNullItemL(); + addCellL(); + addReentrantItemL(); + CleanupStack::PopAndDestroy(2); + CleanupStack::Pop(); + __UHEAP_MARKEND; +// + test.Next(_L("cleanup after a leave")); + addNullItemL(); + TRAPD(r,addReentrantItemL();User::Leave(KLeaveValue);) + test(r==KLeaveValue); + CleanupStack::Pop(); +// + test.Next(_L("cleanup after stack failure")); + // Ensuring stack reallocate fails by placing following cell + TInt* forceAlloc=(TInt*)User::AllocL(4); + for (TInt i=0;i tim; + tim.iObj.CreateLocal(); + test.Next(_L("Push it on the cleanup stack")); + tim.PushL(); + test.Next(_L("Leave before object goes out of scope")); + User::Leave(KErrGeneral); + tim.Pop(); + } + +LOCAL_C void testAutoClose() +// +// Test the TAutoClose class +// + { + + // Kill the granules + RTimer s[20]; + TInt i; + for (i=0; i<20; i++) + s[i].CreateLocal(); + for (i=0; i<20; i++) + s[i].Close(); + + __KHEAP_MARK; + test.Start(_L("Make a TAutoClose object")); + { + TAutoClose tim; + tim.iObj.CreateLocal(); + + test.Next(_L("Let it fall out of scope")); + } + test.Next(_L("Check the object has closed")); + __KHEAP_CHECK(0); + + TRAPD(r, testAutoCloseL()); + test.Next(_L("Check object has been closed and cleaned up after leave")); + __KHEAP_MARKEND; + test.End(); + } +#endif // __TOOLS2__ + +void CTest::ConstructL() +// +// Allocate a cell with CBase::new +// + { + + TLex* pL=new(ELeave) TLex; + CleanupStack::PushL(pL); + } + +void RItem::Cleanup(TAny* aPtr) +// +// Invoke the Close member on the RItem at aPtr +// + { + + ((RItem*)aPtr)->Close(); + } + +LOCAL_C TInt getStackPointer() + { + static TUint8 there; + TUint8 here; + return &here-&there; + } +LOCAL_C void sheLeavesMe(TBool sheLeavesMeNot) + { + if (!sheLeavesMeNot) + User::Leave(KErrBadName); // Montague + } + +LOCAL_C void testStackBalance() +// +// Ensure that we get the stack properly balanced +// + { + + TInt i; + TInt r=KErrNone; + test.Start(_L("Stack balance without leaving")); + TInt before=getStackPointer(); + for (i=0; i<20;i++) + TRAP(r,sheLeavesMe(ETrue)); + TInt after=getStackPointer(); + test(r==KErrNone); + test(before==after); + +// + test.Next(_L("Stack balance after Leave")); + before=getStackPointer(); + for (i=0; i<20;i++) + TRAP(r,sheLeavesMe(EFalse)); + after=getStackPointer(); + test(r==KErrBadName); + test(before==after); +// + test.End(); + } + +void Inc(TAny* aPtr) + { + ++(*(TInt*)aPtr); + } + +void testTrapIgnore() + { + test.Start(_L("Create cleanup")); + CCleanup* pC=CCleanup::New(); + test(pC!=NULL); + TInt count = 0; + + test.Next(_L("TRAP_IGNORE with no leave")); + TRAP_IGNORE( + CleanupStack::PushL(TCleanupItem(Inc,&count)); + CleanupStack::Pop(); + ); + test(count==0); + + test.Next(_L("TRAP_IGNORE with leave")); + TRAP_IGNORE( + CleanupStack::PushL(TCleanupItem(Inc,&count)); + User::Leave(KErrGeneral); + ); + test(count==1); + + delete pC; + test.End(); + } + +GLDEF_C TInt E32Main() + { + test.Title(); + + test.Start(_L("Test destructor causing stack reallocation")); +#ifndef __TOOLS2__ + testDestructorStackReallocation(); +#endif // __TOOLS2__ + + test.Next(_L("CCleanup single level tests just alloc cells")); + testSingleLevelCellsCleanup(); + + test.Next(_L("CCleanup single level tests just objects")); + testSingleLevelObjCleanup(); + + test.Next(_L("CCleanup single level tests just items")); + testSingleLevelItemCleanup(); + + test.Next(_L("CCleanup single level tests mixed")); + testSingleLevelMixCleanup(); + + test.Next(_L("CCleanup multi level tests just alloc cells")); + testMultiLevelCellsCleanup(); + + test.Next(_L("CCleanup multi level tests just objects")); + testMultiLevelObjCleanup(); + + test.Next(_L("CCleanup multi level tests just items")); + testMultiLevelItemCleanup(); + + test.Next(_L("CCleanup multi level tests mixed")); + testMultiLevelMixCleanup(); + + test.Next(_L("CCleanup special case test")); + testSpecialCaseCleanup(); + + test.Next(_L("Install trap handler")); + CTrapCleanup* pT=CTrapCleanup::New(); + test(pT!=NULL); + + test.Next(_L("Untrap handling tests")); + testUnTrap(); + + test.Next(_L("Leave handling tests")); + testLeave(); + + test.Next(_L("Multi level leave handling tests")); + testMultiLeave(); + +#ifndef __TOOLS2__ + test.Next(_L("Test TAutoClose")); + testAutoClose(); +#endif // __TOOLS2__ + + test.Next(_L("Test Re-entrancy of cleanup stack")); + testReentrancy(); + + test.Next(_L("Test stack safety of TRAP and Leave")); +#ifdef _DEBUG + testStackBalance(); +#endif + + test.Next(_L("Test TRAP_IGNORE")); + testTrapIgnore(); + + test.End(); + return(0); + } +