authenticationservices/authenticationserver/test/tauthcliserv/step_authexpr_eval.cpp
changeset 29 ece3df019add
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/authenticationservices/authenticationserver/test/tauthcliserv/step_authexpr_eval.cpp	Tue Nov 24 09:06:03 2009 +0200
@@ -0,0 +1,697 @@
+/*
+* Copyright (c) 2005-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: 
+* This file contains functions which are used to
+* test evaluating authentication expressions.
+*
+*/
+
+
+#include "tauthcliservstep.h"
+
+using namespace AuthServer;
+
+typedef TTestPluginInterface::TCallEntry TCE;
+
+#define elemCount(___x)		(sizeof(___x) / sizeof(___x[0]))
+
+static TAuthExpressionWrapper BuildLeftAnd(TInt aRemainingLevels);
+static TAuthExpressionWrapper BuildRightAnd(TInt aRemainingLevels);
+static TAuthExpressionWrapper BuildBalancedAnd(TInt aRemainingLevels);
+static TAuthExpressionWrapper BuildFailedAnd(TInt aRemainingLevels);
+static TAuthExpressionWrapper BuildSuccessfulOr(TInt aRemainingLevels);
+
+
+// -------- CTStepActSch --------
+
+
+// -------- CTStepAuthExprEval --------
+
+
+void TTestPluginInterface::Evaluate(TPluginId aPluginId, TIdentityId& aIdentity,
+		   CAuthExpressionImpl::TType /*aType*/, TRequestStatus& aStatus)
+/**
+	Implement MEvaluatorPluginInterface by completing
+	the request with an identity equal to the plugin id.
+ */
+	{
+	const TCallEntry ce(aPluginId);
+	TInt r = iCallLog.Append(ce);
+	
+	// this can be KErrNoMemory in OOM tests
+	if (r == KErrNone)
+		{
+		if (aPluginId == KTestPluginUnknown)
+			aIdentity = KUnknownIdentity;
+		else
+			aIdentity = static_cast<TIdentityId>(aPluginId);
+		}
+		
+	aStatus = KRequestPending;
+	TRequestStatus* rs = &aStatus;
+	User::RequestComplete(rs, r);
+	}
+
+
+void TTestPluginInterface::Evaluate(TAuthPluginType aPluginType, TIdentityId& aIdentity, 
+									CAuthExpressionImpl::TType /*aType*/, TRequestStatus& aStatus)
+/**
+	Implement MEvaluatorPluginInterface by completing
+	the request with an identity equal to the plugin type.
+ */
+	{
+	const TCallEntry ce(aPluginType);
+	TInt r = iCallLog.Append(ce);
+	
+	// this can be KerrNoMemory in OOM tests
+	if (r == KErrNone)
+		aIdentity = static_cast<TIdentityId>(aPluginType);
+	
+	aStatus = KRequestPending;
+	TRequestStatus* rs = &aStatus;
+	User::RequestComplete(rs, KErrNone);
+	}
+
+
+bool TTestPluginInterface::TCallEntry::operator==(const TTestPluginInterface::TCallEntry& aRhs) const
+	{
+	if (iCallType != aRhs.iCallType)
+		return false;
+	
+	if (iCallType == CAuthExpressionImpl::EPluginId)
+		return iPluginId == aRhs.iPluginId;
+	else
+		return iPluginType == aRhs.iPluginType;
+	}
+
+
+void TTestClientInterface::EvaluationSucceeded(TIdentityId aIdentityId)
+/**
+	Implement MEvaluatorClientInterface by recording
+	that the evaluation succeeded, and the resulting identity.
+ */
+	{
+	iMode = ESucceeded;
+	iIdentityId = aIdentityId;
+
+	CActiveScheduler::Stop();
+	}
+
+
+void TTestClientInterface::EvaluationFailed(TInt aReason)
+/**
+	Implement MEvaluatorClientInterface by recording
+	that the evaluation failed, and the failure reason.
+ */
+	{
+	iMode = EFailed;
+	iReason = aReason;
+	
+	CActiveScheduler::Stop();
+	}
+
+
+CLaunchEval* CLaunchEval::NewL()
+/**
+	Factory function allocates new instance of CLaunchEval.
+	
+	@return					New instance of CLaunchEval.
+ */
+	{
+	CLaunchEval* self = new(ELeave) CLaunchEval();
+	CleanupStack::PushL(self);
+	self->ConstructL();
+	CleanupStack::Pop(self);
+	return self;
+	}
+
+
+CLaunchEval::CLaunchEval()
+/**
+	Set timer priority and add self to active scheduler.
+ */
+:	CActive(CActive::EPriorityStandard)
+	{
+	CActiveScheduler::Add(this);
+	}
+
+
+void CLaunchEval::ConstructL()
+/**
+	Allocate evaluator and initialize superclass timer.
+ */
+	{
+//	CTimer::ConstructL();
+	iEval = CEvaluator::NewL(&iPluginInterface, &iClientInterface);
+	}
+
+
+CLaunchEval::~CLaunchEval()
+/**
+	Deletes evaluator which was allocated for this object.
+ */
+	{
+	ResetInterfaces();
+	delete iEval;
+	}
+
+
+void CLaunchEval::ResetInterfaces()
+/**
+	Free resources used by plugin and client interfaces.
+ */
+	{
+	iPluginInterface.iCallLog.Reset();
+	iClientInterface.iMode = TTestClientInterface::ENone;
+	}
+
+
+void CLaunchEval::Evaluate(const CAuthExpression* aExpr)
+/**
+	Queue this timer object and start the active
+	scheduler.  This function returns when the evaluation
+	has completed.
+	
+	This object's client and plugin interfaces are reset
+	before the expression is evaluated, so they can be
+	tested by the function which calls this.
+	
+	@param	aExpr			Expression to evaluate.
+ */
+	{
+	ResetInterfaces();
+	iExpr = aExpr;			// store so can see in RunL
+	
+	// signal this object.  This ensures there
+	// is a pending active object before the scheduler
+	// is started.
+	iStatus = KRequestPending;
+	TRequestStatus* rs = &iStatus;
+	User::RequestComplete(rs, KErrNone);
+	SetActive();
+	
+	// block until the evaluation has completed.
+	CActiveScheduler::Start();
+	}
+
+
+void CLaunchEval::RunL()
+/**
+	Implement CActive by launching the evaluation.
+	At this point the active scheduler should have
+	been started.
+ */
+	{
+	iEval->Evaluate(static_cast<const CAuthExpressionImpl*>(iExpr));
+	}
+
+
+void CLaunchEval::DoCancel()
+/**
+	Implement CActive by cancelling the evaluation
+	which is currently in progress.
+	
+	Not yet implemented.
+ */
+	{
+	// empty.
+	}
+
+
+CTStepAuthExprEval::CTStepAuthExprEval()
+/**
+	Record this test step's name.
+ */
+	{
+	SetTestStepName(KTStepAuthExprTypePncBadRight);
+	}
+
+
+TVerdict CTStepAuthExprEval::doTestStepL()
+	{
+ 	CActiveScheduler::Install(iActSchd);
+ 	User::SetJustInTime(ETrue);
+ 	
+ 	__UHEAP_MARK;
+	TestEvalCreateL();
+	TestEvalSimpleL();
+	TestEvalAndL();
+	TestEvalOrL();
+	TestRPNReallocL();
+	__UHEAP_MARKEND;
+	
+	return EPass;
+	}
+
+
+void CTStepAuthExprEval::TestEvalCreateL()
+/**
+	Test allocating and deleting an evaluator,
+	without using it for anything.
+ */
+	{
+	__UHEAP_MARK;
+	
+	TTestClientInterface tci;
+	TTestPluginInterface tpi;
+	
+	CEvaluator* ev = CEvaluator::NewL(&tpi, &tci);
+	delete ev;
+	
+	__UHEAP_MARKEND;
+	}
+
+
+void CTStepAuthExprEval::TestEvalSimpleL()
+/**
+	Test evaluating a simple plugin id, and
+	evaluating a simple plugin type.
+ */
+	{
+	__UHEAP_MARK;
+	
+	CLaunchEval* le = CLaunchEval::NewL();
+	CleanupStack::PushL(le);
+
+	// simple plugin id	
+	CAuthExpression* aeId = AuthExpr(KTestPluginId0);
+	User::LeaveIfNull(aeId);
+	le->Evaluate(aeId);
+	delete aeId;
+	
+	const TCE aceI0[] = {TCE(KTestPluginId0)};
+	TestEvalResultL(le, KTestPluginId0, aceI0, elemCount(aceI0));
+	
+	// simple plugin type
+	CAuthExpression* aeType = AuthExpr(EAuthBiometric);
+	User::LeaveIfNull(aeType);
+	le->Evaluate(aeType);
+	delete aeType;
+	
+	const TCE aceTB[] = {TCE(EAuthBiometric)};
+	TestEvalResultL(le, EAuthBiometric, aceTB, elemCount(aceTB));
+	
+	CleanupStack::PopAndDestroy(le);
+	
+	__UHEAP_MARKEND;
+	}
+
+
+void CTStepAuthExprEval::TestEvalAndL()
+/**
+	Test evaluating simple AND expressions.
+ */
+	{
+	__UHEAP_MARK;
+	
+	CLaunchEval* le = CLaunchEval::NewL();
+	CleanupStack::PushL(le);
+
+	// U & U = U (sc)
+	CAuthExpression* aeUU = AuthAnd(AuthExpr(KTestPluginUnknown), AuthExpr(KTestPluginUnknown));
+	User::LeaveIfNull(aeUU);
+	le->Evaluate(aeUU);
+	delete aeUU;
+
+	const TCE aceUU[] = {TCE(KTestPluginUnknown)};
+	TestEvalResultL(le, KUnknownIdentity, aceUU, elemCount(aceUU));
+
+	// U & I1 = U (sc)
+	CAuthExpression* aeUI1 = AuthAnd(AuthExpr(KTestPluginUnknown), AuthExpr(KTestPluginId1));
+	User::LeaveIfNull(aeUI1);
+	le->Evaluate(aeUI1);
+	delete aeUI1;
+	
+	const TCE aceUI1[] = {TCE(KTestPluginUnknown)};
+	TestEvalResultL(le, KUnknownIdentity, aceUI1, elemCount(aceUI1));
+	
+	// I1 & U = U
+	CAuthExpression* aeI1U = AuthAnd(AuthExpr(KTestPluginId1), AuthExpr(KTestPluginUnknown));
+	User::LeaveIfNull(aeI1U);
+	le->Evaluate(aeI1U);
+	delete aeI1U;
+
+	const TCE aceI1U[] = {TCE(KTestPluginId1), TCE(KTestPluginUnknown)};
+	TestEvalResultL(le, KUnknownIdentity, aceI1U, elemCount(aceI1U));
+	
+	// I1 & I1 = I1
+	CAuthExpression* aeI1I1 = AuthAnd(AuthExpr(KTestPluginId1), AuthExpr(KTestPluginId1));
+	User::LeaveIfNull(aeI1I1);
+	le->Evaluate(aeI1I1);
+	delete aeI1I1;
+
+	const TCE aceI1I1[] = {TCE(KTestPluginId1), TCE(KTestPluginId1)};
+	TestEvalResultL(le, KTestPluginId1, aceI1I1, elemCount(aceI1I1));
+	
+	// I1 & I2 = U
+	CAuthExpression* aeI1I2 = AuthAnd(AuthExpr(KTestPluginId1), AuthExpr(KTestPluginId2));
+	User::LeaveIfNull(aeI1I2);
+	le->Evaluate(aeI1I2);
+	delete aeI1I2;
+	
+	const TCE aceI1I2[] = {TCE(KTestPluginId1), TCE(KTestPluginId2)};
+	TestEvalResultL(le, KUnknownIdentity, aceI1I2, elemCount(aceI1I2));
+	
+	CleanupStack::PopAndDestroy(le);
+	
+	__UHEAP_MARKEND;
+	}
+
+
+void CTStepAuthExprEval::TestEvalOrL()
+/**
+	Test evaluating simple OR expressions.
+ */
+	{
+	__UHEAP_MARK;
+	
+	CLaunchEval* le = CLaunchEval::NewL();
+	CleanupStack::PushL(le);
+
+	// U | U = U
+	CAuthExpression* aeUU = AuthOr(AuthExpr(KTestPluginUnknown), AuthExpr(KTestPluginUnknown));
+	User::LeaveIfNull(aeUU);
+	le->Evaluate(aeUU);
+	delete aeUU;
+	
+	const TCE aceUU[] = {TCE(KTestPluginUnknown), TCE(KTestPluginUnknown)};
+	TestEvalResultL(le, KUnknownIdentity, aceUU, elemCount(aceUU));
+	
+	// U | I1 = I1
+	CAuthExpression* aeUI1 = AuthOr(AuthExpr(KTestPluginUnknown), AuthExpr(KTestPluginId1));
+	User::LeaveIfNull(aeUI1);
+	le->Evaluate(aeUI1);
+	delete aeUI1;
+	
+	const TCE aceUI1[] = {TCE(KTestPluginUnknown), TCE(KTestPluginId1)};
+	TestEvalResultL(le, KTestPluginId1, aceUI1, elemCount(aceUI1));
+	
+	// I1 | U = I1 (sc)
+	CAuthExpression* aeI1U = AuthOr(AuthExpr(KTestPluginId1), AuthExpr(KTestPluginUnknown));
+	User::LeaveIfNull(aeI1U);
+	le->Evaluate(aeI1U);
+	delete aeI1U;
+	
+	const TCE aceI1U[] = {TCE(KTestPluginId1)};
+	TestEvalResultL(le, KTestPluginId1, aceI1U, elemCount(aceI1U));
+	
+	// I1 | I1 = I1 (sc)
+	CAuthExpression* aeI1I1 = AuthOr(AuthExpr(KTestPluginId1), AuthExpr(KTestPluginId1));
+	User::LeaveIfNull(aeI1I1);
+	le->Evaluate(aeI1I1);
+	delete aeI1I1;
+	
+	const TCE aceI1I1[] = {TCE(KTestPluginId1)};
+	TestEvalResultL(le, KTestPluginId1, aceI1I1, elemCount(aceI1I1));
+	
+	// I1 | I2 = I1 (sc)
+	CAuthExpression* aeI1I2 = AuthOr(AuthExpr(KTestPluginId1), AuthExpr(KTestPluginId2));
+	User::LeaveIfNull(aeI1I2);
+	le->Evaluate(aeI1I2);
+	delete aeI1I2;
+	
+	const TCE aceI1I2[] = {TCE(KTestPluginId1)};
+	TestEvalResultL(le, KTestPluginId1, aceI1I2, elemCount(aceI1I2));
+	
+	CleanupStack::PopAndDestroy(le);
+	
+	__UHEAP_MARKEND;
+	}
+
+
+void CTStepAuthExprEval::TestEvalResultL(
+	CLaunchEval* aLaunchEval, TIdentityId aIdentityId,
+	const TTestPluginInterface::TCallEntry* aExpEntries, TInt aEntryCount)
+/**
+	Test the evaluation produced the expected result, and
+	that the expected plugins were called in the right order.
+ */
+	{
+	const TTestClientInterface& cli = aLaunchEval->iClientInterface;
+	TESTL(cli.iMode == TTestClientInterface::ESucceeded);
+	TESTL(cli.iIdentityId == aIdentityId);
+	
+	const RArray<TCE>& log = aLaunchEval->iPluginInterface.iCallLog;
+	
+	TESTL(log.Count() == aEntryCount);
+	for (TInt i = 0; i < aEntryCount; ++i)
+		{
+		TESTL(log[i] == aExpEntries[i]);
+		}
+	}
+
+
+static TAuthExpressionWrapper BuildLeftAnd(TInt aRemainingLevels)
+/**
+	Build an expression where the left side is an
+	AND expression and the right side is a plugin ID.
+	
+	@param	aRemainingLevels The number of layers to build
+							below this layer.  If
+							aRemainingLevels == 0 this function
+							returns a simple plugin ID expression.
+ */
+	{
+	return (aRemainingLevels == 0)
+		?	AuthExpr(KTestPluginId1)
+		:	AuthAnd(BuildLeftAnd(aRemainingLevels - 1), AuthExpr(KTestPluginId1));
+	}
+
+
+static TAuthExpressionWrapper BuildRightAnd(TInt aRemainingLevels)
+/**
+	Build an expression where the left side is a
+	plugin ID and the right side is an AND expression.
+
+	@param	aRemainingLevels The number of layers to build
+							below this layer.  If
+							aRemainingLevels == 0 this function
+							returns a simple plugin ID expression.
+ */
+	{
+	return (aRemainingLevels == 0)
+		?	AuthExpr(KTestPluginId1)
+		:	AuthAnd(AuthExpr(KTestPluginId1), BuildRightAnd(aRemainingLevels - 1));
+	}
+
+
+static TAuthExpressionWrapper BuildBalancedAnd(TInt aRemainingLevels)
+/**
+	Build an expression where both the left and right side
+	have the same depth, aRemainingLevels - 1.
+	
+	@param	aRemainingLevels The number of layers to build
+							below this layer.  If
+							aRemainingLevels == 0 this function
+							returns a simple plugin ID expression.
+ */
+	{
+	return (aRemainingLevels == 0)
+		?	AuthExpr(KTestPluginId1)
+		:	AuthAnd(
+				BuildBalancedAnd(aRemainingLevels - 1),
+				BuildBalancedAnd(aRemainingLevels - 1));
+	}
+
+
+static TAuthExpressionWrapper BuildFailedAnd(TInt aRemainingLevels)
+/**
+	This function creates an expression where the left node
+	is a simple plugin ID expression and the right node is
+	built recursively with this function.  The final AND node
+	has a left unknown plugin ID.
+	
+	This causes an unknown plugin ID to be automatically pushed
+	onto the RPN stack as a right value before the compounder is used.
+	
+	@param	aRemainingLevels Number of levels to generate after this.
+							If aRemainingLevels == 1 this function
+							creates an AND node where the left node
+							is unknown.  Otherwise it generates an
+							AND node where the left node is a known
+							plugin ID and the right node is generated
+							recursively.
+ */
+	{
+	return (aRemainingLevels == 1)
+		?	AuthAnd(AuthExpr(KTestPluginUnknown), AuthExpr(KTestPluginId1))
+		:	AuthAnd(AuthExpr(KTestPluginId1), BuildFailedAnd(aRemainingLevels - 1));
+	}
+
+
+static TAuthExpressionWrapper BuildSuccessfulOr(TInt aRemainingLevels)
+/**
+	This function creates an AND node where the left node
+	is a known plugin ID, and the right right node is generated
+	recursively.  This creates a right-descent list, but the
+	penultimate node is an OR expression whose left node is a
+	known plugin ID.
+	
+	This puts a series of known plugin IDs on the RPN stack from
+	the left nodes of the AND nodes.  When the OR node is evaluated
+	the left node is known, and so automatically put on the
+	RPN stack.
+	
+	This means that an OR right node is automatically put on the
+	RPN stack at a known point, which is used to stress test failing
+	to append an OR right expression in OOM.
+
+	@param	aRemainingLevels Number of levels to generate after this.
+							If aRemainingLevels == 1 this function
+							generates an OR node.  Otherwise it creates
+							and AND node as described above.
+ */
+	{
+	return (aRemainingLevels == 1)
+		?	AuthOr(AuthExpr(KTestPluginId1), AuthExpr(KTestPluginId1))
+		:	AuthAnd(AuthExpr(KTestPluginId1), BuildSuccessfulOr(aRemainingLevels - 1));
+	}
+
+
+void CTStepAuthExprEval::TestRPNReallocL()
+/**
+	Create a deeply nested expression which is
+	deep enough that the evaluator has to reallocate
+	its RPN stack, and checks the evaluation fails
+	gracefully in OOM.
+ */
+	{
+	__UHEAP_MARK;
+	
+	RunOomTestsL(BuildLeftAnd, KTestPluginId1, 0);
+	RunOomTestsL(BuildRightAnd, KTestPluginId1, 0);
+	RunOomTestsL(BuildBalancedAnd, KTestPluginId1, 0);
+	RunOomTestsL(BuildFailedAnd, KUnknownIdentity, 1);
+	RunOomTestsL(BuildSuccessfulOr, KTestPluginId1, 1);
+	
+	__UHEAP_MARKEND;
+	}
+
+	
+void CTStepAuthExprEval::RunOomTestsL(
+	TAuthExpressionWrapper (*aAllocator)(TInt),
+	TIdentityId aExpectedIdentity, TInt aInitDepth)
+/**
+	Attempt to evaluate the supplied expresision in OOM.
+	
+	Running in OOM will both fail the evaluation, when the
+	plugin interface attempts to append to the call log, and
+	when the evaluator attempts to extend the RPN stack.
+	
+	OOM can only be tested in debug builds.  In release builds,
+	this function evaluates the expression at each depth and
+	tests the evaluator produces the correct result.
+	
+	@param	aAllocator		Function which allocates the expression.
+	@param	aExpectedIdentity Identity which should be returned on
+							successful evaluation.
+	@param	aInitDepth		Initial depth.
+ */
+	{
+	CLaunchEval* le = CLaunchEval::NewL();
+	User::LeaveIfNull(le);
+	CleanupStack::PushL(le);
+	
+	const volatile TTestClientInterface& cli = le->iClientInterface;
+	
+	// depth starts at zero because, even though RPN stack
+	// is not used, the evaluator will attempt to grow its
+	// call log, and so fail the evaluation.  (This test is
+	// therefore also used to test failed plugin evaluations.)
+	
+	// max depth is 13 because CStepControl::StartL creates
+	// a worker thread with a 1MB maximum heap.  The
+	// number of allocated node cells for a balanced tree
+	// is 2^(depth+1) - 1.  When depth==13, there are
+	// 16383 cells using 327,672 bytes excluding cell headers.
+	// Allocation fails for depth == 14.
+	
+	const TInt KMaxDepth = 13;
+	for (TInt depth = aInitDepth; depth <= KMaxDepth; ++depth)
+		{
+		CAuthExpression* ae = aAllocator(depth);
+		User::LeaveIfNull(ae);
+		CleanupStack::PushL(ae);
+		
+		// OOM testing only available in debug builds
+#ifndef _DEBUG
+		le->Evaluate(ae);
+		TESTL(cli.iMode == TTestClientInterface::ESucceeded);
+		TESTL(cli.iIdentityId == aExpectedIdentity);
+#else
+		TInt i = 0;
+		do
+			{
+			// Ideally, the heap would be marked before and
+			// after the evaluation.  However, CEvaluator uses
+			// an CArrayFixFlat<TIdentityId> to store the RPN stack.
+			// When the first item is inserted, it allocates a
+			// CBufBase object to hold the data.  This object
+			// is reset but not deleted when the RPN stack is
+			// reset, so there will be a heap imbalance of one
+			// if anything was added to the RPN stack, even though
+			// the stack is reset.
+			
+			TInt preSize;
+			TInt preCount = User::AllocSize(preSize);
+//			__UHEAP_MARK;
+			
+			__UHEAP_SETFAIL(RAllocator::EDeterministic, i);
+			le->Evaluate(ae);
+			__UHEAP_RESET;
+			
+			TESTL(	cli.iMode == TTestClientInterface::EFailed
+				||	cli.iMode == TTestClientInterface::ESucceeded);
+			
+			if (cli.iMode == TTestClientInterface::EFailed)
+				{
+				TESTL(cli.iReason == KErrNoMemory);
+				}
+			else
+				{
+				TESTL(cli.iIdentityId == aExpectedIdentity);
+				}
+			
+			// clear call log so heap checking will work
+			le->iPluginInterface.iCallLog.Reset();
+			++i;
+
+			TInt postSize;
+			TInt postCount = User::AllocSize(postSize);			
+			TESTL(postCount == preCount || postCount == preCount + 1);
+//			__UHEAP_MARKEND;
+			} while (cli.iMode != TTestClientInterface::ESucceeded);
+		
+		// test evaluation still succeeds and failed allocation
+		// was not ignored
+		TInt limit = 2 * i;
+		while (i++ < limit)
+			{
+			__UHEAP_SETFAIL(RAllocator::EDeterministic, i++);
+			le->Evaluate(ae);
+			__UHEAP_RESET;
+			
+			TESTL(cli.iMode == TTestClientInterface::ESucceeded);
+			TESTL(cli.iIdentityId == aExpectedIdentity);
+			}
+
+		// clear plugin call log to reset mem usage for next iteration.
+		le->iPluginInterface.iCallLog.Reset();
+#endif	// #else #ifndef _DEBUG
+		CleanupStack::PopAndDestroy(ae);
+		}
+	
+	CleanupStack::PopAndDestroy(le);
+	}
+