kerneltest/e32test/mmu/t_kblockmap.cpp
changeset 0 a41df078684a
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kerneltest/e32test/mmu/t_kblockmap.cpp	Mon Oct 19 15:55:17 2009 +0100
@@ -0,0 +1,586 @@
+// Copyright (c) 2006-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:
+// e32test\mmu\t_kblockmap.cpp
+// Unit tests for TKernBlockMap
+// 002 Test Initialise error checking
+// 003 Test processing of user-side block map into extent list
+// 004 Test processing of user-side block map into extent list, block size > read unit size
+// 005 Test Read error checking
+// 006 Test Read
+// 
+//
+
+//! @SYMTestCaseID			KBASE-T_KBLOCKMAP-0338
+//! @SYMTestType			UT
+//! @SYMPREQ				PREQ1110
+//! @SYMTestCaseDesc		Demand Paging Kernel Blockmap tests
+//! @SYMTestActions			001 Unit tests the TKernBlockMap class
+//! @SYMTestExpectedResults All tests should pass.
+//! @SYMTestPriority        High
+//! @SYMTestStatus          Implemented
+
+#include <e32test.h>
+#include <e32debug.h>
+#include <memmodel/epoc/mmubase/kblockmap.h>
+
+RTest test(_L("T_KBLOCKMAP"));
+
+#define test_noError(x) { TInt _r = (x); if (_r < 0) HandleError(_r, __LINE__); }
+#define test_notNull(x) { TAny* _a = (TAny*)(x); if (_a == NULL) HandleNull(__LINE__); }
+#define test_equal(e, a) { TInt _e = (e); TInt _a = (a); if (_e != _a) HandleNotEqual(_e, _a, __LINE__); }
+
+void HandleError(TInt aError, TInt aLine)
+	{
+	test.Printf(_L("Error %d\n"), aError);
+	test.operator()(EFalse, aLine);
+	}
+
+void HandleNull(TInt aLine)
+	{
+	test.Printf(_L("Null value\n"));
+	test.operator()(EFalse, aLine);
+	}
+
+void HandleNotEqual(TInt aExpected, TInt aActual, TInt aLine)
+	{
+	test.Printf(_L("Expected 0x%x but got 0x%x\n"), aExpected, aActual);
+	test.operator()(EFalse, aLine);
+	}
+
+/// An list of "pod" objects which can be initialised by passing a variable number of TUints to its
+/// constructor
+template <class T>
+class CList
+	{
+public:
+	CList();
+	CList(TInt aCount, ...);
+	virtual ~CList();
+	inline TInt Count() const { return iCount; }
+	const T* Entries() const { return iEntries; }
+	const T& operator[](TInt aIndex) const;
+protected:
+	void Set(TInt aCount, VA_LIST aList);
+private:
+	const CList<T>& operator=(const CList<T>&);
+	TInt iCount;
+	T* iEntries;
+	};
+
+template <class T>
+CList<T>::CList()
+	: iCount(0), iEntries(NULL)
+	{
+	__ASSERT_COMPILE(sizeof(T) % sizeof(TUint32) == 0);
+	}
+
+template <class T>
+CList<T>::CList(TInt aCount, ...)
+	: iCount(aCount)
+	{
+	VA_LIST list;
+	VA_START(list, aCount);
+	Set(aCount, list);
+	}
+
+template <class T>
+CList<T>::~CList()
+	{
+	User::Free(iEntries);
+	iEntries = NULL;
+	}
+
+template <class T>
+void CList<T>::Set(TInt aCount, VA_LIST aList)
+	{
+	iCount = aCount;
+	test(iEntries == NULL);
+	iEntries = (T*)User::Alloc(sizeof(T) * iCount);
+	test_notNull(iEntries);
+	TInt argCount = iCount * (sizeof(T) / sizeof(TUint32));
+	for (TInt i = 0 ; i < argCount ; ++i)
+		((TUint32*)iEntries)[i] = VA_ARG(aList, TUint32);
+	}
+
+template <class T>
+const T& CList<T>::operator[](TInt aIndex) const
+	{
+	test(aIndex < iCount);
+	return iEntries[aIndex];
+	}
+
+/// Holds all the data associated with the user-side representation of a block map
+class CBlockMap : public CList<TBlockMapEntryBase>
+	{
+public:
+	CBlockMap(TUint aBlockGranularity,
+			  TUint aBlockStartOffset,
+			  TInt64 aStartBlockAddress,
+			  TUint aReadUnitShift,
+			  TUint aCodeLengthInFile,
+			  TUint aEntriesSize,
+			  ...);
+	inline const SBlockMapInfoBase& Info() const { return iInfo; }
+	inline TInt ReadUnitShift() const { return iReadUnitShift; }
+	inline TInt CodeLengthInFile() const { return iCodeLengthInFile; }
+	inline TInt EntriesSize() const { return iEntriesSize; }
+private:
+	SBlockMapInfoBase iInfo;
+	TBlockMapEntryBase* iEntries;
+	TUint iReadUnitShift;
+	TUint iCodeLengthInFile;
+	TUint iEntriesSize;
+	};
+
+CBlockMap::CBlockMap(TUint aBlockGranularity,
+					 TUint aBlockStartOffset,
+					 TInt64 aStartBlockAddress,
+					 TUint aReadUnitShift,
+					 TUint aCodeLengthInFile,
+					 TUint aEntriesSize,
+					 ...)
+	{
+	iInfo.iBlockGranularity = aBlockGranularity;
+	iInfo.iBlockStartOffset = aBlockStartOffset;
+	iInfo.iStartBlockAddress = aStartBlockAddress;
+	// don't care about iInfo.iLocalDriveNumber for test purposes
+	iReadUnitShift = aReadUnitShift;
+	iCodeLengthInFile = aCodeLengthInFile;
+	iEntriesSize = aEntriesSize;
+	iEntries = (TBlockMapEntryBase*)User::Alloc(iEntriesSize);
+
+	VA_LIST list;
+	VA_START(list, aEntriesSize);
+	Set(iEntriesSize / sizeof(TBlockMapEntryBase), list);
+	}
+
+/// A list of extents, for comparison with those generated by the kernel block map processing code
+class CExtentList : public CList<TBlockMap::SExtent>
+	{
+public:
+	typedef TBlockMap::SExtent SExtent;
+	CExtentList(TInt aCount, ...);
+	void Dump() const;
+	};
+
+CExtentList::CExtentList(TInt aCount, ...)
+	{
+	VA_LIST list;
+	VA_START(list, aCount);
+	Set(aCount, list);
+	}
+
+void CExtentList::Dump() const
+	{
+	RDebug::Printf("CExtentList:\n");
+	const CExtentList& self = *this;
+	for (TInt i = 0 ; i < Count() ; ++i)
+		RDebug::Printf("  %d: %08x -> %08x: %08x\n", i, self[i].iDataOffset, self[i+1].iDataOffset, self[i].iBlockNumber);
+	}
+
+TBool operator==(const TBlockMap::SExtent& a, const TBlockMap::SExtent& b)
+	{
+	return a.iDataOffset == b.iDataOffset && a.iBlockNumber == b.iBlockNumber;
+	}
+
+TBool operator!=(const TBlockMap::SExtent& a, const TBlockMap::SExtent& b)
+	{
+	return !(a == b);
+	}
+
+TBool CompareExtentsEqual(const TBlockMap& aBlockMap, const CExtentList& aExtentList)
+	{
+	if (aBlockMap.Count() != aExtentList.Count())
+		return EFalse;
+	for (TInt i = 0 ; i < aBlockMap.Count() ; ++i)
+		{
+		if (aBlockMap.Extent(i) != aExtentList[i])
+			return EFalse;
+		}
+	return ETrue;
+	}
+
+TInt MakeKernBlockMap(TBlockMap& aKbm, const CBlockMap& aUbm)
+	{
+	TBlockMapEntryBase* buffer = (TBlockMapEntryBase*)User::Alloc(aUbm.EntriesSize());
+	test_notNull(buffer);
+	Mem::Copy(buffer, aUbm.Entries(), aUbm.EntriesSize());
+	return aKbm.Initialise(aUbm.Info(),
+						   buffer,
+						   aUbm.EntriesSize(),
+						   aUbm.ReadUnitShift(),
+						   aUbm.CodeLengthInFile());
+}
+
+void MakeKernBlockMapAndTestExtents(const CBlockMap& aUbm, const CExtentList& aExpectedExtentList)
+	{
+	TBlockMap kbm;
+	test_noError(MakeKernBlockMap(kbm, aUbm));
+	TBool equal = CompareExtentsEqual(kbm, aExpectedExtentList);
+	if (!equal)
+		{
+		aExpectedExtentList.Dump();
+#ifdef _DEBUG
+		kbm.Dump();
+#endif
+		}
+	test(equal);
+	}
+
+// Tests
+
+void TestInitialiseErrors()
+	{
+	test.Next(_L("Test Initialise error checking"));
+	TBlockMap kbm;
+
+	// Block size must be a power of two
+	test_equal(KErrArgument, MakeKernBlockMap(kbm, CBlockMap(513, 0, 0, 9, 1, 8, 1, 0)));
+
+	// Block size must be greater than or equal to the read unit size
+	test_equal(KErrArgument, MakeKernBlockMap(kbm, CBlockMap(512, 0, 0, 10, 1, 8, 1, 0)));
+
+	// Block start offset must be less than or equal to block size
+	test_equal(KErrArgument, MakeKernBlockMap(kbm, CBlockMap(512, 513, 0, 9, 1, 8, 1, 0)));
+
+	// Block zero address must be a multiple of the block size
+	test_equal(KErrArgument, MakeKernBlockMap(kbm, CBlockMap(512, 0, 1, 9, 1, 8, 1, 0)));
+
+	// Code length in file must be greater than zero
+	test_equal(KErrArgument, MakeKernBlockMap(kbm, CBlockMap(512, 0, 0, 9, 0, 8, 1, 0)));
+
+	// Size of entries array must be multiple of the size of one entry
+	test_equal(KErrArgument, MakeKernBlockMap(kbm, CBlockMap(512, 0, 0, 9, 1, 9, 1, 0)));
+
+	// Size of entries must be non-zero
+	test_equal(KErrArgument, MakeKernBlockMap(kbm, CBlockMap(512, 0, 0, 9, 1, 0)));
+	
+	// Size of block map must be greater or equal to size of data in file
+	test_equal(KErrArgument, MakeKernBlockMap(kbm, CBlockMap(512, 0, 0, 9, 513, 8, 1, 0)));
+	}
+
+	// blockGranularity, startOffset, blockZeroAddress, readUnitShift, codeLengthInFile, entriesSize, (numberOfBlocks, startBlock)+
+
+void TestExtentList()
+	{
+	test.Next(_L("Test processing of user-side block map into extent list"));
+
+	//  +-------+-------+-------+-------+-------+-------+-------+-------+-------+-------
+	//  |=      |       |       |       |       |       |       |       |       |
+	//  +-------+-------+-------+-------+-------+-------+-------+-------+-------+-------	
+	MakeKernBlockMapAndTestExtents(CBlockMap(512, 0, 0, 9, 1, 8, 1, 0),
+								   CExtentList(1, 0, 0));
+
+	//  +-------+-------+-------+-------+-------+-------+-------+-------+-------+-------
+	//  |       |=      |       |       |       |       |       |       |       |
+	//  +-------+-------+-------+-------+-------+-------+-------+-------+-------+-------	
+	MakeKernBlockMapAndTestExtents(CBlockMap(512, 0, 512, 9, 1, 8, 1, 0),
+								   CExtentList(1, 0, 1));
+	
+	//  +-------+-------+-------+-------+-------+-------+-------+-------+-------+-------
+	//  |       | =     |       |       |       |       |       |       |       |
+	//  +-------+-------+-------+-------+-------+-------+-------+-------+-------+-------	
+	MakeKernBlockMapAndTestExtents(CBlockMap(512, 23, 512, 9, 1, 8, 1, 0),
+								   CExtentList(1, -23, 1));
+
+	//  +-------+-------+-------+-------+-------+-------+-------+-------+-------+-------
+	//  |       |       |       | =     |       |       |       |       |       |
+	//  +-------+-------+-------+-------+-------+-------+-------+-------+-------+-------	
+	MakeKernBlockMapAndTestExtents(CBlockMap(512, 23, 512, 9, 1, 8, 1, 2),
+								   CExtentList(1, -23, 3));
+
+	//  +-------+-------+-------+-------+-------+-------+-------+-------+-------+-------
+	//  |       |       |       | ======|       |       |       |       |       |
+	//  +-------+-------+-------+-------+-------+-------+-------+-------+-------+-------	
+	MakeKernBlockMapAndTestExtents(CBlockMap(512, 23, 512, 9, 489, 8, 1, 2),
+								   CExtentList(1, -23, 3));
+
+	//  +-------+-------+-------+-------+-------+-------+-------+-------+-------+-------
+	//  |       |       |       | ========      |       |       |       |       |
+	//  +-------+-------+-------+-------+-------+-------+-------+-------+-------+-------	
+	MakeKernBlockMapAndTestExtents(CBlockMap(512, 23, 512, 9, 600, 8, 2, 2),
+								   CExtentList(1, -23, 3));
+	
+	//  +-------+-------+-------+-------+-------+-------+-------+-------+-------+-------
+	//  |       |       |       | ==============|       |==     |       |       |
+	//  +-------+-------+-------+-------+-------+-------+-------+-------+-------+-------	
+	MakeKernBlockMapAndTestExtents(CBlockMap(512, 23, 512, 9, 1100, 16, 2, 2, 1, 5),
+								   CExtentList(2, -23, 3, 1001, 6));
+
+	//  +-------+-------+-------+-------+-------+-------+-------+-------+-------+-------
+	//  |       |       |       | ==============|       |=======|       |       |
+	//  +-------+-------+-------+-------+-------+-------+-------+-------+-------+-------	
+	MakeKernBlockMapAndTestExtents(CBlockMap(512, 23, 512, 9, 1513, 16, 2, 2, 1, 5),
+								   CExtentList(2, -23, 3, 1001, 6));
+	
+	//  +-------+-------+-------+-------+-------+-------+-------+-------+-------+-------
+	//  |       |       |       | ==============|       |=======|=      |       |
+	//  +-------+-------+-------+-------+-------+-------+-------+-------+-------+-------	
+	MakeKernBlockMapAndTestExtents(CBlockMap(512, 23, 512, 9, 1540, 16, 2, 2, 2, 5),
+								   CExtentList(2, -23, 3, 1001, 6));
+	}
+
+void TestExtentListScaled()
+	{
+	test.Next(_L("Test processing of user-side block map into extent list, block size > read unit size"));
+
+	//  +-------+-------+-------+-------+-------+-------+-------+-------+-------+-------
+	//  |=  :   |   :   |   :   |   :   |   :   |   :   |   :   |   :   |   :   |
+	//  +-------+-------+-------+-------+-------+-------+-------+-------+-------+-------	
+	MakeKernBlockMapAndTestExtents(CBlockMap(512, 0, 0, 8, 1, 8, 1, 0),
+								   CExtentList(1, 0, 0));
+
+	//  +-------+-------+-------+-------+-------+-------+-------+-------+-------+-------
+	//  |   :   |=  :   |   :   |   :   |   :   |   :   |   :   |   :   |   :   |
+	//  +-------+-------+-------+-------+-------+-------+-------+-------+-------+-------	
+	MakeKernBlockMapAndTestExtents(CBlockMap(512, 0, 512, 8, 1, 8, 1, 0),
+								   CExtentList(1, 0, 2));
+	
+	//  +-------+-------+-------+-------+-------+-------+-------+-------+-------+-------
+	//  |   :   | = :   |   :   |   :   |   :   |   :   |   :   |   :   |   :   |
+	//  +-------+-------+-------+-------+-------+-------+-------+-------+-------+-------	
+	MakeKernBlockMapAndTestExtents(CBlockMap(512, 23, 512, 8, 1, 8, 1, 0),
+								   CExtentList(1, -23, 2));
+
+	//  +-------+-------+-------+-------+-------+-------+-------+-------+-------+-------
+	//  |   :   |   : = |   :   |   :   |   :   |   :   |   :   |   :   |   :   |
+	//  +-------+-------+-------+-------+-------+-------+-------+-------+-------+-------	
+	MakeKernBlockMapAndTestExtents(CBlockMap(512, 280, 512, 8, 1, 8, 1, 0),
+								   CExtentList(1, -24, 3));
+
+	//  +-------+-------+-------+-------+-------+-------+-------+-------+-------+-------
+	//  |   :   |   :   |   :   |   : = |   :   |   :   |   :   |   :   |   :   |
+	//  +-------+-------+-------+-------+-------+-------+-------+-------+-------+-------	
+	MakeKernBlockMapAndTestExtents(CBlockMap(512, 280, 512, 8, 1, 8, 1, 2),
+								   CExtentList(1, -24, 7));
+
+	//  +-------+-------+-------+-------+-------+-------+-------+-------+-------+-------
+	//  |   :   |   :   |   :   |   : ==|   :   |   :   |   :   |   :   |   :   |
+	//  +-------+-------+-------+-------+-------+-------+-------+-------+-------+-------	
+	MakeKernBlockMapAndTestExtents(CBlockMap(512, 280, 512, 8, 232, 8, 1, 2),
+								   CExtentList(1, -24, 7));
+
+	//  +-------+-------+-------+-------+-------+-------+-------+-------+-------+-------
+	//  |   :   |   :   |   :   |   : ====  :   |   :   |   :   |   :   |   :   |
+	//  +-------+-------+-------+-------+-------+-------+-------+-------+-------+-------	
+	MakeKernBlockMapAndTestExtents(CBlockMap(512, 280, 512, 8, 333, 8, 2, 2),
+								   CExtentList(1, -24, 7));
+
+	//  +-------+-------+-------+-------+-------+-------+-------+-------+-------+-------
+	//  |   :   |   :   |   :   |   : ========  |   :   |   :   |   :   |   :   |
+	//  +-------+-------+-------+-------+-------+-------+-------+-------+-------+-------	
+	MakeKernBlockMapAndTestExtents(CBlockMap(512, 280, 512, 8, 666, 8, 2, 2),
+								   CExtentList(1, -24, 7));
+
+	//  +-------+-------+-------+-------+-------+-------+-------+-------+-------+-------
+	//  |   :   |   :   |   :   |   : ==========|   :   |   :   |   :   |   :   |
+	//  +-------+-------+-------+-------+-------+-------+-------+-------+-------+-------	
+	MakeKernBlockMapAndTestExtents(CBlockMap(512, 280, 512, 8, 744, 8, 2, 2),
+								   CExtentList(1, -24, 7));
+
+	//  +-------+-------+-------+-------+-------+-------+-------+-------+-------+-------
+	//  |   :   |   :   |   :   |   : ==========|   :   |== :   |   :   |   :   |
+	//  +-------+-------+-------+-------+-------+-------+-------+-------+-------+-------	
+	MakeKernBlockMapAndTestExtents(CBlockMap(512, 280, 512, 8, 888, 16, 2, 2, 1, 5),
+								   CExtentList(2, -24, 7, 744, 12));
+
+	//  +-------+-------+-------+-------+-------+-------+-------+-------+-------+-------
+	//  |   :   |   :   |   :   |   : ==========|   :   |=======|   :   |   :   |
+	//  +-------+-------+-------+-------+-------+-------+-------+-------+-------+-------	
+	MakeKernBlockMapAndTestExtents(CBlockMap(512, 280, 512, 8, 1256, 16, 2, 2, 1, 5),
+								   CExtentList(2, -24, 7, 744, 12));
+
+	//  +-------+-------+-------+-------+-------+-------+-------+-------+-------+-------
+	//  |   :   |   :   |   :   |   : ==========|   :   |=========  :   |   :   |
+	//  +-------+-------+-------+-------+-------+-------+-------+-------+-------+-------	
+	MakeKernBlockMapAndTestExtents(CBlockMap(512, 280, 512, 8, 1350, 16, 2, 2, 2, 5),
+								   CExtentList(2, -24, 7, 744, 12));
+	}
+
+/// Holds the expected arguments for one call to the read function
+struct SReadEntry
+	{
+	TLinAddr iBuffer;
+	TInt iBlockNumber;
+	TInt iBlockCount;
+	};
+
+/// Holds a list of expected arguments for all calls to the read function
+class CReadInfo : public CList<SReadEntry>
+	{
+public:
+	CReadInfo(TInt aReturnVal, TInt aCount, ...);
+	const SReadEntry& Next();
+	void Done() const;
+	TInt ReturnVal() const { return iReturnVal; }
+private:
+	TInt iPos;
+	TInt iReturnVal;
+	};
+
+CReadInfo::CReadInfo(TInt aReturnVal, TInt aCount, ...)
+	: iPos(0), iReturnVal(aReturnVal)
+	{
+	VA_LIST list;
+	VA_START(list, aCount);
+	Set(aCount, list);
+	}
+
+const SReadEntry& CReadInfo::Next()
+	{
+	const CList<SReadEntry>& self = *this;
+	return self[iPos++];
+	}
+
+void CReadInfo::Done() const
+	{
+	test_equal(Count(), iPos);
+	}
+
+TInt ReadFunc(TAny* aArg, TAny*, TLinAddr aBuffer, TInt aBlockNumber, TInt aBlockCount)
+	{
+	CReadInfo& info = *(CReadInfo*)aArg;
+	const SReadEntry& expected = info.Next();
+	test_equal(expected.iBuffer, aBuffer);
+	test_equal(expected.iBlockNumber, aBlockNumber);
+	test_equal(expected.iBlockCount, aBlockCount);
+	return KErrNone;
+	}
+
+void TestRead(const TBlockMap& aBlockMap,
+			  TLinAddr aBuffer,
+			  TInt aPos,
+			  TInt aLength,
+			  TInt aReadUnitShift,
+			  const CReadInfo& aExpected)
+	{
+	test_equal(aExpected.ReturnVal(),
+			   aBlockMap.Read(aBuffer, aPos, aLength, aReadUnitShift, ReadFunc, (TAny*)&aExpected, (TAny*)NULL));
+	aExpected.Done();
+	}
+
+void TestReadErrors()
+	{
+	test.Next(_L("Test Read error checking"));
+
+	TBlockMap kbm, kbm2;
+	
+	//  +-------+-------+-------+-------+-------+-------+-------+-------+-------+-------
+	//  |=      |       |       |       |       |       |       |       |       |
+	//  +-------+-------+-------+-------+-------+-------+-------+-------+-------+-------	
+	test_noError(MakeKernBlockMap(kbm, CBlockMap(512, 0, 0, 9, 1, 8, 1, 0)));
+
+	//  +-------+-------+-------+-------+-------+-------+-------+-------+-------+-------
+	//  |   :   |   :   |   :   |   : ==========|   :   |=========  :   |   :   |
+	//  +-------+-------+-------+-------+-------+-------+-------+-------+-------+-------	
+	test_noError(MakeKernBlockMap(kbm2, CBlockMap(512, 280, 512, 8, 1350, 16, 2, 2, 2, 5)));
+
+	// Test read start position is outside block map
+	TestRead(kbm, 0, 1, 1, 9, CReadInfo(KErrArgument, 0));
+	TestRead(kbm2, 0, 1350, 1, 8, CReadInfo(KErrArgument, 0));
+
+	// Test read start position is negative
+	TestRead(kbm, 0, -1, 1, 9, CReadInfo(KErrArgument, 0));
+	TestRead(kbm2, 0, -1, 1, 8, CReadInfo(KErrArgument, 0));
+
+	// Test read length exceeds block map length 
+	TestRead(kbm, 0, 0, 2, 9, CReadInfo(KErrArgument, 1, 0, 0, 1));
+	TestRead(kbm2, 0, 1349, 2, 8, CReadInfo(KErrArgument, 1, 0, 14, 1));
+	}
+
+void TestReads()
+	{
+	test.Next(_L("Test Read"));
+
+	//  +-------+-------+-------+-------+-------+-------+-------+-------+-------+-------
+	//  |=======================|       |       |       |       |       |       |
+	//  +-------+-------+-------+-------+-------+-------+-------+-------+-------+-------
+	
+	TBlockMap kbm2;
+	test_noError(MakeKernBlockMap(kbm2, CBlockMap(512, 0, 0, 9, 1536, 8, 3, 0)));
+
+	// Test correct number of blocks read
+	TestRead(kbm2, 0, 0, 512, 9, CReadInfo(0, 1, 0, 0, 1));
+	TestRead(kbm2, 0, 0, 513, 9, CReadInfo(0, 1, 0, 0, 2));
+	TestRead(kbm2, 0, 0, 1024, 9, CReadInfo(0, 1, 0, 0, 2));
+	TestRead(kbm2, 0, 0, 1025, 9, CReadInfo(0, 1, 0, 0, 3));
+	TestRead(kbm2, 0, 0, 1536, 9, CReadInfo(0, 1, 0, 0, 3));
+
+	// Test start offset not aligned to read unit
+	TestRead(kbm2, 0, 1, 511, 9, CReadInfo(1, 1, 0, 0, 1));
+	TestRead(kbm2, 0, 256, 256, 9, CReadInfo(256, 1, 0, 0, 1));
+	TestRead(kbm2, 0, 511, 1, 9, CReadInfo(511, 1, 0, 0, 1));
+	TestRead(kbm2, 0, 513, 511, 9, CReadInfo(1, 1, 0, 1, 1));
+	TestRead(kbm2, 0, 1023, 1, 9, CReadInfo(511, 1, 0, 1, 1));
+
+	//  +-------+-------+-------+-------+-------+-------+-------+-------+-------+-------
+	//  |=======|       |=======|       |=======|       |       |       |       |
+	//  +-------+-------+-------+-------+-------+-------+-------+-------+-------+-------
+	
+	TBlockMap kbm;
+	test_noError(MakeKernBlockMap(kbm, CBlockMap(512, 0, 0, 9, 1536, 24, 1, 0, 1, 3, 1, 5)));
+
+	// Test correct block selected for read
+	TestRead(kbm, 0, 0, 1, 9, CReadInfo(0, 1, 0, 0, 1));
+	TestRead(kbm, 0, 256, 1, 9, CReadInfo(256, 1, 0, 0, 1));
+	TestRead(kbm, 0, 511, 1, 9, CReadInfo(511, 1, 0, 0, 1));
+	TestRead(kbm, 0, 512, 1, 9, CReadInfo(0, 1, 0, 3, 1));
+	TestRead(kbm, 0, 768, 1, 9, CReadInfo(256, 1, 0, 3, 1));
+	TestRead(kbm, 0, 1023, 1, 9, CReadInfo(511, 1, 0, 3, 1));
+	TestRead(kbm, 0, 1535, 1, 9, CReadInfo(511, 1, 0, 5, 1));
+
+	// Test reading multiple blocks
+	TestRead(kbm, 0, 0, 513, 9, CReadInfo(0, 2, 0, 0, 1, 512, 3, 1));
+	TestRead(kbm, 0, 0, 1024, 9, CReadInfo(0, 2, 0, 0, 1, 512, 3, 1));
+	TestRead(kbm, 0, 0, 1025, 9, CReadInfo(0, 3, 0, 0, 1, 512, 3, 1, 1024, 5, 1));
+	TestRead(kbm, 0, 0, 1536, 9, CReadInfo(0, 3, 0, 0, 1, 512, 3, 1, 1024, 5, 1));
+
+
+	//  +-------+-------+-------+-------+-------+-------+-------+-------+-------+-------
+	//  |   ====|       |=======|       |=======|       |       |       |       |
+	//  +-------+-------+-------+-------+-------+-------+-------+-------+-------+-------
+	
+	TBlockMap kbm3;
+	test_noError(MakeKernBlockMap(kbm3, CBlockMap(512, 256, 0, 9, 1280, 24, 1, 0, 1, 3, 1, 5)));
+
+	// Test correct block selected for read
+	TestRead(kbm3, 0, 0, 1, 9, CReadInfo(256, 1, 0, 0, 1));
+	TestRead(kbm3, 0, 255, 1, 9, CReadInfo(511, 1, 0, 0, 1));
+	TestRead(kbm3, 0, 256, 1, 9, CReadInfo(0, 1, 0, 3, 1));
+	TestRead(kbm3, 0, 767, 1, 9, CReadInfo(511, 1, 0, 3, 1));
+	TestRead(kbm3, 0, 768, 1, 9, CReadInfo(0, 1, 0, 5, 1));
+
+	// Test reading multiple blocks
+	TestRead(kbm3, 0, 0, 256, 9, CReadInfo(256, 1, 0, 0, 1));
+	TestRead(kbm3, 0, 0, 257, 9, CReadInfo(256, 2, 0, 0, 1, 512, 3, 1));
+	TestRead(kbm3, 0, 0, 768, 9, CReadInfo(256, 2, 0, 0, 1, 512, 3, 1));
+	TestRead(kbm3, 0, 0, 769, 9, CReadInfo(256, 3, 0, 0, 1, 512, 3, 1, 1024, 5, 1));
+	TestRead(kbm3, 0, 0, 1280, 9, CReadInfo(256, 3, 0, 0, 1, 512, 3, 1, 1024, 5, 1));
+	}
+
+TInt E32Main()
+	{
+	test.Title();
+	test.Start(_L("Unit tests the TKernBlockMap class"));
+
+	TestInitialiseErrors();
+	TestExtentList();
+	TestExtentListScaled();
+	TestReadErrors();
+	TestReads();
+ 
+	test.End();
+
+	return KErrNone;
+	}