kerneltest/e32test/property/t_prop_ldd.cpp
author Tom Cosgrove <tom.cosgrove@nokia.com>
Fri, 28 May 2010 16:29:07 +0100
changeset 30 8aab599e3476
parent 0 a41df078684a
permissions -rw-r--r--
Fix for bug 2283 (RVCT 4.0 support is missing from PDK 3.0.h) Have multiple extension sections in the bld.inf, one for each version of the compiler. The RVCT version building the tools will build the runtime libraries for its version, but make sure we extract all the other versions from zip archives. Also add the archive for RVCT4.

// Copyright (c) 2002-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:
//

#include "t_prop_ldd.h"
#include <kernel/kernel.h>
#include "nk_priv.h"

class DPropLDevice : public DLogicalDevice
	{
public:
	DPropLDevice();
	virtual TInt Install();
	virtual void GetCaps(TDes8& aDes) const;
	virtual TInt Create(DLogicalChannelBase*& aChannel);
	};

class DPropLChannel : public DLogicalChannelBase
	{
public:
	DPropLChannel();
	~DPropLChannel();

	virtual TInt DoCreate(TInt aUnit, const TDesC8* anInfo, const TVersion& aVer);
	virtual TInt Request(TInt aFunction, TAny* a1, TAny* a2);

private:
	TInt Basic(RPropChannel::TBasicInfo* aInfo);

	static void CompleteFn(TAny* aPtr, TInt aReason);
	TInt iReason;
	NFastSemaphore iSem;

	};

DECLARE_STANDARD_LDD()
//
// Create a new device
//
	{
	return new DPropLDevice;
	}

DPropLDevice::DPropLDevice()
//
// Constructor
//
	{
	//iUnitsMask=0;
	iVersion = TVersion(1,0,1);
	// iParseMask = 0;
	}

TInt DPropLDevice::Install()
//
// Install the device driver.
//
	{
	TInt r = SetName(&KPropLdName);
	return r;
	}

void DPropLDevice::GetCaps(TDes8&) const
//
// Return the Comm capabilities.
//
	{
	}

TInt DPropLDevice::Create(DLogicalChannelBase*& aChannel)
//
// Create a channel on the device.
//
	{
	aChannel = new DPropLChannel;
	return aChannel ? KErrNone : KErrNoMemory;
	}

DPropLChannel::DPropLChannel() 
	{
	NKern::FSSetOwner(&iSem, NKern::CurrentThread());
	}

TInt DPropLChannel::DoCreate(TInt /*aUnit*/, const TDesC8* /* aInfo*/ , const TVersion& aVer)
//
// Create the channel from the passed info.
//
	{
	if (!Kern::QueryVersionSupported(TVersion(1,0,1),aVer))
		return KErrNotSupported;
	return KErrNone;
	}

DPropLChannel::~DPropLChannel()
	{
	}


#define BASIC_ERROR(aRes, aCond) \
	{\
	if (!(aCond)) \
		{ \
		Kern::Printf("Test '" #aCond "' fails; r = %d;\n\tfile '" __FILE__ "'; line %d;\n", aRes, __LINE__); \
		prop.Close(); \
		return EFalse; \
		} \
	}

void DPropLChannel::CompleteFn(TAny* aPtr, TInt aReason)
	{ // static
	DPropLChannel* self = (DPropLChannel*) aPtr;
	self->iReason = aReason;
	NKern::FSSignal(&self->iSem);
	}

TBool DPropLChannel::Basic(RPropChannel::TBasicInfo* aInfo)
	{

	TUid category = aInfo->iCategory;
	TUint key = aInfo->iKey;
	TUint count = aInfo->iCount;
	RProperty::TType type = aInfo->iType;

	for (TUint i = 0; i < count; ++i)
		{
		RPropertyRef prop;
		TInt r = prop.Open(category, key);
		BASIC_ERROR(r, r == KErrNotFound);
		r = prop.Attach(category, key);
		BASIC_ERROR(r, r == KErrNone);

		//	Defines the attributes and access control for a property. This can only be done 
		//	once for each property. Subsequent attempts to define the same property will return
		//	KErrAlreadyExists.

		TSecurityPolicy policy;

		r = prop.Define(type, policy, policy);
		BASIC_ERROR(r, r == KErrNone);
		r = prop.Define(type, policy, policy);
		BASIC_ERROR(r, r == KErrAlreadyExists);
		r = prop.Delete();
		BASIC_ERROR(r, r == KErrNone);

		// Define fails with KErrArgument if wrong type or attribute was specified.
		r = prop.Define(RProperty::ETypeLimit, policy, policy);
		BASIC_ERROR(r, r == KErrArgument);

		static _LIT_SECURITY_POLICY_PASS(KPassPolicy);
		TSecurityPolicy badPolicy;
		*(TInt*)&badPolicy = -1;

		r = prop.Define(type, badPolicy, policy);
		BASIC_ERROR(r, r == KErrArgument);
		r = prop.Define(type, KPassPolicy, badPolicy);
		BASIC_ERROR(r, r == KErrArgument);
	
		if (type == RProperty::EInt)
			{
			// Define fails with KErrArgument if aType is TInt and aPreallocate is not 0
			r = prop.Define(type, KPassPolicy, KPassPolicy, 16);
			BASIC_ERROR(r, r == KErrArgument);

			// Following defintion the property has a default value, 0 for integer properties
			r = prop.Define(RProperty::EInt, KPassPolicy, KPassPolicy);
			BASIC_ERROR(r, r == KErrNone);
			TInt value;
			r = prop.Get(value);
			BASIC_ERROR(r, r == KErrNone);
			BASIC_ERROR(value, value == 0);
			r = prop.Delete();
			BASIC_ERROR(r, r == KErrNone);
			}
		else 
			{
			// Defne fails with KErrTooBig if aPeallocate is grater than KMaxPropertySize.
			r = prop.Define(RProperty::EByteArray, KPassPolicy, KPassPolicy, RProperty::KMaxPropertySize);
			BASIC_ERROR(r, r == KErrNone);
			r = prop.Delete();
			BASIC_ERROR(r, r == KErrNone);
			r = prop.Define(RProperty::EByteArray, KPassPolicy, KPassPolicy, RProperty::KMaxPropertySize+1);
			BASIC_ERROR(r, r == KErrTooBig);

			// Following defintion the property has a default value, zero-length data for byte-array and text 
			// properties. 
			r = prop.Define(RProperty::EByteArray, KPassPolicy, KPassPolicy);
			BASIC_ERROR(r, r == KErrNone);
			TBuf8<16> buf;
			r = prop.Get(buf);
			BASIC_ERROR(r, r == KErrNone);
			BASIC_ERROR(buf.Size(), buf.Size() == 0);
			r = prop.Delete();
			BASIC_ERROR(r, r == KErrNone);
			}

		// Pending subscriptions for this property will not be completed until a new value is published.
		TPropertySubsRequest subs(CompleteFn, this);
		iReason = KRequestPending;
		r = prop.Subscribe(subs);
		r = prop.Define(type, KPassPolicy, KPassPolicy);
		BASIC_ERROR(r, r == KErrNone);
		BASIC_ERROR(iReason, iReason == KRequestPending);
		r = prop.Delete();
		BASIC_ERROR(r, r == KErrNone);
		NKern::FSWait(&iSem);
		BASIC_ERROR(iReason, iReason == KErrNotFound);

		// If the property has not been defined Delete() fails with KErrNotFound.
		r = prop.Delete();
		BASIC_ERROR(r, r == KErrNotFound);

		// When deleted any pending subscriptions for the property will be completed with KErrNotFound.
		r = prop.Define(type, KPassPolicy, KPassPolicy);
		BASIC_ERROR(r, r == KErrNone);
		iReason = KRequestPending;
		r = prop.Subscribe(subs);
		BASIC_ERROR(r, r == KErrNone);
		BASIC_ERROR(iReason, iReason == KRequestPending);
		r = prop.Delete();
		BASIC_ERROR(r, r == KErrNone);
		NKern::FSWait(&iSem);
		BASIC_ERROR(iReason, iReason == KErrNotFound);

		// Any new request will not complete until the property is defined and published again.
		iReason = KRequestPending;
		r = prop.Subscribe(subs);
		BASIC_ERROR(r, r == KErrNone);
		BASIC_ERROR(iReason, iReason == KRequestPending);
		r = prop.Define(type, KPassPolicy, KPassPolicy);
		BASIC_ERROR(r, r == KErrNone);
		BASIC_ERROR(iReason, iReason == KRequestPending);
		if (type == RProperty::EInt)
			{
			r = prop.Set(1);
			BASIC_ERROR(r, r == KErrNone);
			}
		else
			{
			TBuf8<16> buf((TUint8*) "Foo");
			r = prop.Set(buf);
			BASIC_ERROR(r, r == KErrNone);
			}
		NKern::FSWait(&iSem);
		BASIC_ERROR(iReason, iReason == KErrNone);
		r = prop.Delete();
		BASIC_ERROR(r, r == KErrNone);

		// If the property has not been defined Set()/Get() fail with KErrNotFound.
			{
			TInt value;
			TBuf8<16> buf;
			if (type == RProperty::EInt)
				{
				r = prop.Get(value);
				BASIC_ERROR(r, r == KErrNotFound);
				r = prop.Set(value);
				BASIC_ERROR(r, r == KErrNotFound);
				}
			else
				{
				r = prop.Get(buf);
				BASIC_ERROR(r, r == KErrNotFound);
				r = prop.Set(buf);
				BASIC_ERROR(r, r == KErrNotFound);
				}
			}

		r = prop.Define(type, KPassPolicy, KPassPolicy);
		BASIC_ERROR(r, r == KErrNone);

		// If the property is larger than KMaxPropertySize Set() fails with KErrTooBig
			{
			if (type ==  RProperty::EByteArray)
				{
				TBuf8<RProperty::KMaxPropertySize + 1> buf(RProperty::KMaxPropertySize + 1);
				r = prop.Set(buf);
				BASIC_ERROR(r, r == KErrTooBig);
				}
			}

		// When type of operation mismatch with the property type Set()/Get() fails with KErrArgument.
			{
			if (type !=  RProperty::EInt)
				{
				TInt value;
				r = prop.Get(value);
				BASIC_ERROR(r, r == KErrArgument);
				r = prop.Set(value);
				BASIC_ERROR(r, r == KErrArgument);
				}
			else
				{
				TBuf8<16> buf;
				r = prop.Get(buf);
				BASIC_ERROR(r, r == KErrArgument);
				r = prop.Set(buf);
				BASIC_ERROR(r, r == KErrArgument);
				}
			}

		// Get/Set
		if (type == RProperty::EInt)
			{
			r = prop.Set(1);
			BASIC_ERROR(r, r == KErrNone);
			TInt value = 0;
			r = prop.Get(value);
			BASIC_ERROR(r, r == KErrNone);
			BASIC_ERROR(value, value == 1);
			}
		else 
			{
			TBuf8<16> ibuf((TUint8*)"Foo");
			TBuf8<16> obuf;
			r = prop.Set(ibuf);
			BASIC_ERROR(r, r == KErrNone);
			r = prop.Get(obuf);
			BASIC_ERROR(r, r == KErrNone);
			r = obuf.Compare(ibuf);
			BASIC_ERROR(r, r == 0);
			}

		// If the supplied buffer is too small Get() fails with KErrOverflow and the truncated value is reported.
		if (type == RProperty::EByteArray)
			{
			TBuf8<16> ibuf((TUint8*) "0123456789012345");
			TBuf8<16> obuf((TUint8*) "abcdefghigklmnop");
			TPtr8 optr((TUint8*) obuf.Ptr(), 0, 15);
			r = prop.Set(ibuf);
			BASIC_ERROR(r, r == KErrNone);
			r = prop.Get(optr);
			BASIC_ERROR(r, r == KErrOverflow);
			BASIC_ERROR(optr.Length(), optr.Length() == 15); 
			BASIC_ERROR(obuf[14], obuf[14] == '4'); 
			BASIC_ERROR(obuf[15], obuf[15] == 'p');
			}

		// The calling thread will have the specified request status signalled when the property is next updated.
		iReason = KRequestPending;
		r = prop.Subscribe(subs);
		BASIC_ERROR(r, r == KErrNone);
		BASIC_ERROR(iReason, iReason == KRequestPending);
		if (type == RProperty::EInt)
			{
			r = prop.Set(1);
			BASIC_ERROR(r, r == KErrNone);
			}
		else
			{
			TBuf8<16> buf((TUint8*) "Foo");
			r = prop.Set(buf);
			BASIC_ERROR(r, r == KErrNone);
			}
		NKern::FSWait(&iSem);
		BASIC_ERROR(iReason, iReason == KErrNone);

		r = prop.Delete();
		BASIC_ERROR(r, r == KErrNone);

		// Cancel an outstanding subscription request.
		// If it has not already completed, the request is completed with KErrCancelled.
		iReason = KRequestPending;
		r = prop.Subscribe(subs);
		BASIC_ERROR(r, r == KErrNone);
		BASIC_ERROR(iReason, iReason == KRequestPending);
		prop.Cancel(subs);		
		NKern::FSWait(&iSem);
		BASIC_ERROR(iReason, iReason == KErrCancel);

		r = prop.Define(type, KPassPolicy, KPassPolicy);
		BASIC_ERROR(r, r == KErrNone);

		iReason = KRequestPending;
		r = prop.Subscribe(subs);
		BASIC_ERROR(r, r == KErrNone);
		BASIC_ERROR(iReason, iReason == KRequestPending);
		if (type == RProperty::EInt)
			{
			r = prop.Set(1);
			BASIC_ERROR(r, r == KErrNone);
			}
		else
			{
			TBuf8<16> buf((TUint8*) "Foo");
			r = prop.Set(buf);
			BASIC_ERROR(r, r == KErrNone);
			}
		NKern::FSWait(&iSem);
		BASIC_ERROR(iReason, iReason == KErrNone);
		prop.Cancel(subs);		
		BASIC_ERROR(iReason, iReason == KErrNone);

		iReason = KRequestPending;
		r = prop.Subscribe(subs);
		BASIC_ERROR(r, r == KErrNone);
		BASIC_ERROR(iReason, iReason == KRequestPending);
		prop.Cancel(subs);		
		NKern::FSWait(&iSem);
		BASIC_ERROR(iReason, iReason == KErrCancel);

		r = prop.Delete();
		BASIC_ERROR(r, r == KErrNone);

		prop.Close();
		}
	return ETrue;
	}

//
// Client requests.
//
TBool DPropLChannel::Request(TInt aFunction, TAny* a1, TAny*)
	{
	TBool r;
	switch (aFunction)
		{
		case RPropChannel::EBasicTests:
			RPropChannel::TBasicInfo info;
			kumemget32(&info, a1, sizeof(info));
			NKern::ThreadEnterCS();
			r = Basic(&info);
			NKern::ThreadLeaveCS();
			break;	
		default:
			r = EFalse;
			break;
		}
	return r;
	}