Ptr<CTestDoubleNamedString> SetupObjectsForDehollowfication(void)
{
	Ptr<CTestNamedString>			cNS1;
	Ptr<CTestNamedString>			cNS2;
	Ptr<CTestNamedString>			cNS3;
	Ptr<CTestNamedString>			cDiamond;
	Ptr<CTestDoubleNamedString>		pDouble;
	Ptr<CRoot>						pRoot;
	Ptr<CString>					cS1;
	Ptr<CString>					cS2;

	pRoot = ORoot();

	cDiamond = ONMalloc(CTestNamedString, "Diamond")->Init();

	cS1 = OMalloc(CString)->Init("CS1");
	cNS1 = ONMalloc(CTestNamedString, "NS1")->Init(cS1, cDiamond, "NS1");

	cNS2 = ONMalloc(CTestNamedString, "NS2")->Init(ONull, cDiamond, "NS2");

	cNS3 = ONMalloc(CTestNamedString, "NS3")->Init(ONull, cNS1, "NS3");

	cS2 = OMalloc(CString)->Init("CS2");
	cDiamond->Init(cS2, ONull, "Diamond");

	pDouble = ONMalloc(CTestDoubleNamedString, "Double")->Init(ONull, cNS2, cNS3);

	pRoot->Add(pDouble);
	return pDouble;
}
void TestKillLongCyclicSelfPointer(void)
{
	ObjectsInit();

	Ptr<CRoot>				pRoot;
	Ptr<CTestNamedObject>	pObject1;
	Ptr<CTestNamedObject>	pObject2;
	Ptr<CTestNamedObject>	pObjectBase;
	BOOL					bResult;

	pRoot = ORoot();

	pObjectBase = OMalloc(CTestNamedObject);
	pObject1 = OMalloc(CTestNamedObject);
	pObjectBase->Init(0);
	pObject1->Init(1);
	pObjectBase->mpNamedTest1 = pObject1;
	pObject1->mpNamedTest1 = pObjectBase;

	pRoot->Add(pObjectBase);

	//pObject should be destroyed here and not cause a stack overflow.
	bResult = pRoot->Remove(pObjectBase);
	AssertTrue(bResult);

	ObjectsKill();
}
void TestObjectGraphDeserialiserBuildGraph1(void)
{
	Ptr<CTestSaveableObject2>	cStart1;
	Ptr<CTestSaveableObject2>	cStart2;
	Ptr<CRoot>					cRoot;
	Ptr<CTestSaveableObject1>	cShared;
	Ptr<CString>				cString1;
	Ptr<CString>				cString2;
	Ptr<CTestInteger>			cIgnored;

	cRoot = ORoot();
	cStart1 = ONMalloc(CTestSaveableObject2, "Ow/Start 1")->Init("Battery");
	cStart2 = ONMalloc(CTestSaveableObject2, "Ow/Start 2")->Init("Charger");
	cShared = ONMalloc(CTestSaveableObject1, "Ow/Shared")->Init();
	cString1 = OMalloc(CString)->Init("Black");
	cString2 = OMalloc(CString)->Init("Jack");
	cIgnored = OMalloc(CTestInteger)->Init(0, 1, 0);
	
	cRoot->Add(cStart1);
	cRoot->Add(cStart2);

	cStart1->mp1 = cShared;
	cStart2->mp1 = cShared;

	cShared->miInt = 89;
	cShared->mpObject = cShared;

	cStart1->mp2 = cString1;
	cStart2->mp2 = cString2;

	cRoot->Add(cIgnored);
}
void TestEmbeddedObjectAddDistToRoot(void)
{
	ObjectsInit();

	Ptr<CRoot>				pRoot = ORoot();
	Ptr<CGameWorld>			pWorld = OMalloc(CGameWorld)->Init();

	pRoot->Add(pWorld);

	Ptr<CClusterMissile>	pMissile = ONMalloc(CClusterMissile, "Frank")->Init(pWorld);
	Ptr<CHarrier>			pHarrier = OMalloc(CHarrier)->Init(pWorld);
	
	pWorld->AddPlayer(pHarrier);
	AssertInt(3, pHarrier->GetDistToRoot());

	pRoot->Add(pMissile);

	AssertInt(2, pMissile->GetDistToRoot());
	AssertInt(2, pMissile->mcMissile1.GetDistToRoot());
	AssertInt(2, pMissile->mcMissile2.GetDistToRoot());

	pMissile->mcMissile1.SetTarget(pHarrier);

	AssertInt(3, pHarrier->GetDistToRoot());

	ObjectsKill();
}
void TestEmbeddedStackPointersComplex(void)
{
	ObjectsInit();

	CEmbeddedComplex			cComplexOnStack1;
	CEmbeddedComplex			cComplexOnStack2;
	Ptr<CTestObject>			pTestObject1;
	STestObjectKilledNotifier	sKillNotifier1;
	Ptr<CTestObject>			pTestObject2;
	STestObjectKilledNotifier	sKillNotifier2;

	cComplexOnStack1.Class();
	cComplexOnStack2.Class();
	cComplexOnStack1.Init();
	cComplexOnStack2.Init();

	pTestObject1 = OMalloc(CTestObject);
	pTestObject1->Init(&sKillNotifier1);
	pTestObject2 = OMalloc(CTestObject);
	pTestObject2->Init(&sKillNotifier2);

	AssertInt(0, cComplexOnStack1.GetDistToStack());
	AssertInt(0, cComplexOnStack1.NumStackFroms());
	AssertInt(0, cComplexOnStack2.GetDistToStack());
	AssertInt(0, cComplexOnStack2.NumStackFroms());

	cComplexOnStack1.mpTest = &cComplexOnStack2;
	cComplexOnStack1.mcSimple.mpTest = &cComplexOnStack2;
	cComplexOnStack1.mcContainer.mcOne.mpTest = pTestObject1;
	cComplexOnStack2.mcContainer.mcOne.mpTest = pTestObject1;

	AssertInt(0, cComplexOnStack1.GetDistToStack());
	AssertInt(0, cComplexOnStack1.NumStackFroms());
	AssertInt(3, cComplexOnStack1.NumPointerTos());
	AssertInt(0, cComplexOnStack2.GetDistToStack());
	AssertInt(2, cComplexOnStack2.NumStackFroms());
	AssertInt(1, cComplexOnStack2.NumPointerTos());

	AssertFalse(sKillNotifier1.bKilled);
	AssertFalse(sKillNotifier2.bKilled);
	TestEmbeddedStackPointersComplex(&cComplexOnStack1, &cComplexOnStack2);
	AssertFalse(sKillNotifier1.bKilled);
	AssertFalse(sKillNotifier2.bKilled);

	AssertInt(0, cComplexOnStack1.GetDistToStack());
	AssertInt(0, cComplexOnStack1.NumStackFroms());
	AssertInt(0, cComplexOnStack2.GetDistToStack());
	AssertInt(2, cComplexOnStack2.NumStackFroms());

	ObjectsKill();
}
void TestEmbeddedObjectRemoveDistToRoot(void)
{
	ObjectsInit();

	Ptr<CRoot>				pRoot = ORoot();
	Ptr<CGameWorld>			pWorld = OMalloc(CGameWorld)->Init();

	pRoot->Add(pWorld);

	Ptr<CClusterMissile>	pMissile = ONMalloc(CClusterMissile, "Frank")->Init(pWorld);
	Ptr<CHarrier>			pHarrier = OMalloc(CHarrier)->Init(pWorld);
	Ptr<CMissile>			pHolder = OMalloc(CMissile)->Init(pWorld);
	
	pWorld->AddTickable(pHolder);
	AssertInt(4, pHolder->GetDistToRoot());

	pHolder->SetTarget(pHarrier);
	AssertInt(5, pHarrier->GetDistToRoot());

	Ptr<CClusterLauncher>	pLauncher = OMalloc(CClusterLauncher)->Init();

	pRoot->Add(pLauncher);
	AssertInt(2, pLauncher->GetDistToRoot());

	pLauncher->mpMissile = pMissile;

	AssertInt(3, pMissile->GetDistToRoot());
	AssertInt(3, pMissile->mcMissile1.GetDistToRoot());
	AssertInt(3, pMissile->mcMissile2.GetDistToRoot());
	AssertInt(5, pHarrier->GetDistToRoot());
	AssertInt(1, pHarrier->NumHeapFroms());

	pMissile->mcMissile1.SetTarget(pHarrier);
	AssertInt(4, pHarrier->GetDistToRoot());
	AssertInt(2, pHarrier->NumHeapFroms());

	pWorld->RemoveTickable(pHolder);
	pHolder = NULL;

	AssertInt(4, pHarrier->GetDistToRoot());
	AssertInt(1, pHarrier->NumHeapFroms());

	pRoot->Add(pHarrier);
	AssertInt(2, pHarrier->GetDistToRoot());

	pRoot->Remove(pHarrier);
	AssertInt(4, pHarrier->GetDistToRoot());

	ObjectsKill();
}
void TestKillSelfPointer2(void)
{
	ObjectsInit();

	Ptr<CRoot>				pRoot;
	Ptr<CTestNamedObject>	pObject;
	BOOL					bResult;

	pRoot = ORoot();

	pObject = OMalloc(CTestNamedObject);
	pObject->Init(1);
	pObject->mpNamedTest1 = pObject;

	pRoot->Add(pObject);
	AssertInt(1, pRoot->NumObjects());

	AssertLongLongInt(3, gcObjects.NumMemoryIndexes());

	//pObject should not be destroyed here and not cause a stack overflow.
	bResult = pRoot->Remove(pObject);
	AssertTrue(bResult);
	AssertInt(0, pRoot->NumObjects());
	AssertLongLongInt(3, gcObjects.NumMemoryIndexes());

	//If there were cyclic pointers then the object cannot tell it should be freed when a stack pointer is removed.
	pObject = NULL;
	AssertLongLongInt(2, gcObjects.NumMemoryIndexes());

	ObjectsKill();
}
void TestKillSelfPointer1(void)
{
	ObjectsInit();

	Ptr<CRoot>				pRoot;
	Ptr<CTestNamedObject>	pObject;
	BOOL					bResult;
	CBaseObject*			pvObject;

	pRoot = ORoot();

	pObject = OMalloc(CTestNamedObject);
	pObject->Init(1);
	pObject->mpNamedTest1 = pObject;

	pRoot->Add(pObject);
	AssertInt(1, pRoot->NumObjects());

	AssertLongLongInt(3, gcObjects.NumMemoryIndexes());

	pvObject = pObject.BaseObject();
	pObject = NULL;

	//pObject should be destroyed here and not cause a stack overflow.
	bResult = pRoot->Remove(pvObject);
	AssertTrue(bResult);
	AssertInt(0, pRoot->NumObjects());

	AssertLongLongInt(2, gcObjects.NumMemoryIndexes());

	ObjectsKill();
}
void TestObjectsObjectKillInGraph(void)
{
	Ptr<CTestNamedString>	cNS1;
	Ptr<CTestNamedString>	cNS2;
	Ptr<CRoot>				pRoot;
	Ptr<CString>			cS1;
	Ptr<CString>			cS2;
	CTestNamedString*		pcNS2;
	CString*				pcS2;

	ObjectsInit();

	pRoot = ORoot();

	cS1 = OMalloc(CString);
	cS1->Init("CS1");
	cNS1 = ONMalloc(CTestNamedString, "NS1")->Init(cS1, ONull, "NS1");

	cS2 = OMalloc(CString)->Init("CS2");
	cNS2 = ONMalloc(CTestNamedString, "NS2")->Init(cS2, cNS1, "NS2");

	pRoot->Add(cNS2);
	
	AssertPointer(cNS2->mpAnother.Object(), cNS1.Object());
	AssertLongLongInt(6, gcObjects.NumMemoryIndexes());
	pcNS2 = &cNS2;
	cNS2 = NULL;
	pRoot = NULL;
	cS1 = NULL;
	pcS2 = &cS2;
	cS2 = NULL;
	AssertLongLongInt(6, gcObjects.NumMemoryIndexes());

	cNS1->Kill();

	AssertNull(pcNS2->mpAnother.Object());
	AssertLongLongInt(4, gcObjects.NumMemoryIndexes());
	AssertPointer(pcNS2->mszString.Object(), pcS2);

	ObjectsKill();
}
void TestObjectsObjectKillInArrayInGraph(void)
{
	Ptr<CTestNamedString>	cNS1;
	Ptr<CArrayObject>		cA1;
	Ptr<CArrayObject>		cA2;
	Ptr<CRoot>				pRoot;
	Ptr<CString>			cS1;

	ObjectsInit();

	pRoot = ORoot();

	cS1 = OMalloc(CString)->Init("CS1");
	cNS1 = ONMalloc(CTestNamedString, "NS1")->Init(cS1, ONull, "NS1");

	cA1 = OMalloc(CArrayObject)->Init();
	cA2 = OMalloc(CArrayObject)->Init();

	cA1->Add(cNS1);
	cA2->Add(cNS1);

	pRoot->Add(cA1);
	pRoot->Add(cA2);

	AssertInt(1, cA1->NumPointerTos());
	AssertInt(1, cA2->NumPointerTos());
	AssertLongLongInt(6, gcObjects.NumMemoryIndexes());
	pRoot = NULL;
	cS1 = NULL;
	AssertLongLongInt(6, gcObjects.NumMemoryIndexes());

	cNS1->Kill();
	AssertLongLongInt(4, gcObjects.NumMemoryIndexes());

	AssertInt(0, cA1->NumPointerTos());
	AssertInt(0, cA2->NumPointerTos());


	ObjectsKill();
}
void TestEmbeddedObjectPointTo(void)
{
	BOOL		bResult;
	CFileUtil	cFileUtil;
	OIndex		oiComplex;
	char*		szClassName;
	
	cFileUtil.RemoveDir("Output/EmbeddedObject");

	MemoryInit();
	ObjectsInit("Output/EmbeddedObject/");
	SetupEmbeddedObjectConstructors();

	Ptr<CRoot> pRoot = ORoot();
	Ptr<CEmbeddedComplex> pComplex = OMalloc(CEmbeddedComplex)->Init();
	oiComplex = pComplex->GetOI();

	Ptr<CEmbeddedContainer> pContainer = &pComplex->mcContainer;
	pRoot->Add(pContainer);

	bResult = gcObjects.Flush(TRUE, TRUE);
	AssertTrue(bResult);

	ObjectsKill();
	MemoryKill();

	AssertNull(&pContainer);

	MemoryInit();
	ObjectsInit("Output/EmbeddedObject/");
	SetupEmbeddedObjectConstructors();

	pRoot = gcObjects.GetRoot();
	AssertTrue(pRoot.IsNotNull());
	pContainer = pRoot->Get(0);
	AssertTrue(pContainer.IsHollow());
	AssertInt(0, pContainer.Object()->GetNumEmbedded());
	AssertLongLongInt(-1, pContainer.GetIndex());

	szClassName = pContainer->ClassName();
	AssertString("CEmbeddedContainer", szClassName);

	pComplex = pContainer->GetEmbeddingContainer();
	//Kinda feels like this test just stopped...

	ObjectsKill();
	MemoryKill();
}
void TestEmbeddedStackPointersEmbeddedDistPassThruPointer(void)
{
	ObjectsInit();

	CEmbeddedTest*		pcTest;
	CEmbeddedComplex	cComplex;
	Ptr<CEmbeddedTest>	pTest;
	
	cComplex.Class();
	cComplex.Init();
	cComplex.mai[0] = 1234;
	cComplex.mai[1] = 7890;

	AssertInt(0, cComplex.GetDistToStack());
	AssertInt(0, cComplex.NumStackFroms());

	Ptr<CEmbeddedComplex> pComplex;
	pComplex = &cComplex;

	AssertInt(1, cComplex.NumStackFroms());
	AssertInt(1234, pComplex->mai[0]);
	AssertInt(7890, pComplex->mai[1]);

	AssertInt(0, cComplex.GetDistToStack());

	pTest = OMalloc(CEmbeddedTest);
	pcTest = (CEmbeddedTest*)pTest.Object();

	pTest->Init();
	cComplex.mpTest = pTest;

	AssertInt(UNKNOWN_DIST_TO_STACK, pcTest->GetDistToStack());
	AssertInt(2, pComplex->mpTest->NumStackFroms());
	AssertInt(1, cComplex.NumStackFroms());

	pTest = NULL;
	AssertInt(UNKNOWN_DIST_TO_STACK, pcTest->GetDistToStack());
	AssertLongLongInt(1, gcObjects.NumMemoryIndexes());
	AssertInt(1, pComplex->mpTest->NumStackFroms());
	AssertInt(1, cComplex.NumStackFroms());

	cComplex.Kill();

	AssertLongLongInt(0, gcObjects.NumMemoryIndexes());

	ObjectsKill();
}
CPointer SetupObjectReaderChunkedChunkFile(void)
{
	Ptr<CTestNamedString>	cNS1;
	Ptr<CTestNamedString>	cNS2;
	Ptr<CTestNamedString>	cNS3;
	Ptr<CTestNamedString>	cNS4;
	Ptr<CTestInteger>		cI1;
	Ptr<CTestInteger>		cI2;
	Ptr<CTestInteger>		cI3;
	Ptr<CTestWithArray>		cA1;
	Ptr<CTestWithArray>		cA2;
	Ptr<CString>			sz1;
	Ptr<CString>			sz2;
	Ptr<CString>			sz3;

	cNS1 = ONMalloc(CTestNamedString, "NamedString 1")->Init();
	cNS2 = ONMalloc(CTestNamedString, "NamedString 2")->Init();
	cNS3 = ONMalloc(CTestNamedString, "NamedString 3")->Init();
	cNS4 = ONMalloc(CTestNamedString, "NamedString 4")->Init();

	cI1 = OMalloc(CTestInteger)->Init(3, 2, 1);
	AssertLongLongInt(5LL, cI1->GetOI());
	cI2 = OMalloc(CTestInteger)->Init(543, 3, 4);
	AssertLongLongInt(6LL, cI2->GetOI());
	cI3 = OMalloc(CTestInteger)->Init(10, 8192, 7);
	AssertLongLongInt(7LL, cI3->GetOI());

	cA1 = ONMalloc(CTestWithArray, "Array 1")->Init("Something with One", 1);
	cA2 = ONMalloc(CTestWithArray, "Array X")->Init("An with 2", 2);

	sz1 = OMalloc(CString)->Init("String 1");
	sz2 = OMalloc(CString)->Init("Ye!");
	sz3 = OMalloc(CString)->Init("3");

	cNS1->Init(sz1, cNS2, "In Named 1");
	cNS2->Init(sz1, cNS3, "Another in 2");
	cNS3->Init(sz3, cNS1, "Three");
	cNS4->Init(ONull, ONull, "Nulloid!");

	cA1->Add(sz2);
	cA1->Add(cNS1);
	cA1->Add(cI1);
	cA1->Add(cNS3);
	cA1->Add(cI2);
	cA1->Add(cA2);

	cA2->Add(cI3);
	cA2->Add(cNS2);
	cA2->Add(cI1);
	cA2->Add(cNS4);

	return cA1;
}
void TestEmbeddedStackPointersKill(void)
{
	ObjectsInit();

	CEmbeddedComplex			cComplex;
	STestObjectKilledNotifier	sKillNotifier;

	cComplex.Class();
	cComplex.Init();
	cComplex.mai[0] = 1234;
	cComplex.mai[1] = 7890;

	cComplex.mpTest = OMalloc(CTestObject)->Init(&sKillNotifier);
	AssertInt(0, cComplex.NumStackFroms());
	AssertInt(1, cComplex.mpTest->NumStackFroms());
	AssertLongLongInt(1, gcObjects.NumMemoryIndexes());

	cComplex.Kill();

	AssertTrue(sKillNotifier.bKilled);
	AssertLongLongInt(0, gcObjects.NumMemoryIndexes());
}
void TestRemappingOfOIs(CObjectWriter* pcWriter, CObjectReader* pcReader)
{
	CFileUtil					cFileUtil;
	Ptr<CTestSaveableObject2>	cBase;
	Ptr<CTestSaveableObject2>	cStart1;
	Ptr<CRoot>					cRoot;
	Ptr<CString>				szOne;
	Ptr<CString>				cString1;
	Ptr<CString>				cString2;
	CObjectGraphSerialiser		cGraphSerialiser;
	CObjectGraphDeserialiser	cGraphDeserialiser;
	Ptr<CTestSaveableObject1>	cShared;
	int							i;
	CObjectAllocator			cAllocator;
	CDependentReadObjects		cDependentReadObjects;

	cFileUtil.MakeDir("Output/GraphDeserialiser/Simple/Remapping");

	ObjectsInit("Output/GraphDeserialiser/Simple/Remapping");
	TestObjectGraphDeserialiserAddConstructors();
	TestObjectGraphDeserialiserBuildGraph1();

	cBase = gcObjects.Get("Ow/Start 1");
	AssertTrue(cBase.IsNotNull());
	AssertLongLongInt(3, cBase->GetOI());
	cString1 = gcObjects.Get(6LL);
	AssertString("Black", cString1->Text());
	AssertLongLongInt(6LL, cString1->GetOI());
	cString2 = gcObjects.Get(7LL);
	AssertString("Jack", cString2->Text());
	AssertLongLongInt(7LL, cString2->GetOI());

	cGraphSerialiser.Init(pcWriter);
	AssertTrue(cGraphSerialiser.Write(&cBase));
	cGraphSerialiser.Kill();
	pcWriter->Kill();

	ObjectsKill();

	ObjectsInit("Output/GraphDeserialiser/Simple/Remapping");
	TestObjectGraphDeserialiserAddConstructors();

	cRoot = ORoot();

	for (i = 0; i < 20; i++)
	{
		szOne = OMalloc(CString);
		szOne->Init("Hello World ");
		szOne->Append(i);
		cRoot->Add(szOne);
		AssertLongLongInt(3+i, szOne->GetOI());
	}

	cAllocator.Init(&gcObjects);
	cDependentReadObjects.Init();
	cGraphDeserialiser.Init(pcReader, FALSE, &cAllocator, &cDependentReadObjects, gcObjects.GetMemory());
	cStart1 = cGraphDeserialiser.Read("Ow/Start 1");
	AssertTrue(cStart1.IsNotNull());
	AssertLongLongInt(23, cStart1->GetOI());

	AssertTrue(cStart1->mp1.IsNotNull());
	AssertString("CTestSaveableObject1", cStart1->mp1->ClassName());
	cShared = cStart1->mp1;
	AssertLongLongInt(25, cShared->GetOI());

	AssertTrue(cStart1->mp2.IsNotNull());
	AssertString("CString", cStart1->mp2->ClassName());
	cString1 = cStart1->mp2;
	AssertLongLongInt(24, cString1->GetOI());
	cGraphDeserialiser.Kill();
	cDependentReadObjects.Kill();
	cAllocator.Kill();

	for (i = 0; i < 20; i++)
	{
		szOne = OMalloc(CString);
		szOne->Init("Hello World ");
		szOne->Append(i + 20);
		cRoot->Add(szOne);
		AssertLongLongInt(26+i, szOne->GetOI());
	}

	pcReader->Kill();

	ObjectsKill();
}
void TestObjectWriterChunkedSerialised(void)
{	
	ObjectsInit();

	CObjectWriterChunked		cWriter;
	CObjectGraphSerialiser		cGraphSerialiser;

	Ptr<CTestWithArray>			pcObject1;
	Ptr<CTestInteger>			pcObject2;
	Ptr<CTestInteger>			pcObject3;
	Ptr<CTestInteger>			pcObject4;
	CChunkFileNames				cChunkFile;
	int							iLength;
	char						szTest[4];

	pcObject1 = ONMalloc(CTestWithArray, "Base/Level 1/Warning");
	pcObject1->Init("Talking Clock", 17);

	pcObject2 = OMalloc(CTestInteger);
	pcObject2->Init(2, 9, 937);
	pcObject1->Add(pcObject2);

	pcObject3 = OMalloc(CTestInteger);
	pcObject3->Init(3, 7321, 7);
	pcObject1->Add(pcObject3);

	pcObject4 = OMalloc(CTestInteger);
	pcObject4->Init(4, 5, 6);
	pcObject1->Add(pcObject4);

	cWriter.Init("Output\\ObjectWriterChunked\\Test\\", "Base/Level 1", "ChunkFile");

	cGraphSerialiser.Init(&cWriter);
	AssertTrue(cGraphSerialiser.Write(&pcObject1));
	cGraphSerialiser.Kill();

	cWriter.Kill();

	AssertFile("Input/ChunkFile.DRG", "Output/ObjectWriterChunked/Test/Base/Level 1/ChunkFile.DRG");

	cChunkFile.Init(DiskFile("Output/ObjectWriterChunked/Test/Base/Level 1/ChunkFile.DRG"));
	AssertTrue(cChunkFile.ReadOpen());

	//CTestWithArray pcObject1
	AssertTrue(cChunkFile.ReadChunkBegin("Warning"));
	AssertTrue(cChunkFile.ReadInt(&iLength));
	AssertInt(106, iLength);
	AssertTrue(cChunkFile.ReadData(szTest, 4));
	AssertString("NAM", szTest);
	AssertTrue(cChunkFile.ReadChunkEnd());

	//CArrayObject
	AssertTrue(cChunkFile.ReadChunkBegin("Unnamed/0000000000000002"));
	AssertTrue(cChunkFile.ReadInt(&iLength));
	AssertInt(101, iLength);
	AssertTrue(cChunkFile.ReadData(szTest, 4));
	AssertString("IDX", szTest);
	AssertTrue(cChunkFile.ReadChunkEnd());

	//CTestInteger pcObject2
	AssertTrue(cChunkFile.ReadChunkBegin("Unnamed/0000000000000003"));
	AssertTrue(cChunkFile.ReadInt(&iLength));
	AssertInt(45, iLength);
	AssertTrue(cChunkFile.ReadData(szTest, 4));
	AssertString("IDX", szTest);
	AssertTrue(cChunkFile.ReadChunkEnd());

	//CTestInteger pcObject3
	AssertTrue(cChunkFile.ReadChunkBegin("Unnamed/0000000000000004"));
	AssertTrue(cChunkFile.ReadInt(&iLength));
	AssertInt(45, iLength);
	AssertTrue(cChunkFile.ReadData(szTest, 4));
	AssertString("IDX", szTest);
	AssertTrue(cChunkFile.ReadChunkEnd());

	//CTestInteger pcObject4
	AssertTrue(cChunkFile.ReadChunkBegin("Unnamed/0000000000000005"));
	AssertTrue(cChunkFile.ReadInt(&iLength));
	AssertInt(45, iLength);
	AssertTrue(cChunkFile.ReadData(szTest, 4));
	AssertString("IDX", szTest);
	AssertTrue(cChunkFile.ReadChunkEnd());

	AssertTrue(cChunkFile.ReadClose());
	cChunkFile.Kill();

	ObjectsKill();
}
Beispiel #17
0
void TestKillBestPractice(void)
{
	ObjectsInit();

	//Generally an object will be killed if all pointers to it a removed.
	//Sometimes we'd rather not try and remove all the pointers we just want the object to die.
	//In the example below if a missile hits a jet then both objects should be removed;
	//regardless of whether anything else points to them.
	//Those objects that did point to them will be updated to point to NULL.

	Ptr<CRoot>			pRoot;
	Ptr<CGameWorld>		pWorld;

	pRoot = ORoot();

	AssertLongLongInt(0, gcObjects.NumDatabaseNames());
	pWorld = OMalloc(CGameWorld);
	pWorld->Init();

	pRoot->Add(pWorld);

	Ptr<CHarrier> pHarrier = ONMalloc(CHarrier, "Harrier");
	pHarrier->Init(pWorld);

	Ptr<CJeep> pJeep = ONMalloc(CJeep, "Jeep");
	pJeep->Init(pWorld);

	pWorld->AddPlayer(pHarrier);
	pWorld->AddPlayer(pJeep);

	SStateOnKill	sHarrierBefore;
	SStateOnKill	sHarrierAfter;
	SStateOnKill	sJeepBefore;
	SStateOnKill	sJeepAfter;

	pHarrier->SetKillHook(&sHarrierBefore, &sHarrierAfter);
	pJeep->SetKillHook(&sJeepBefore, &sJeepAfter);

	SStateOnKill	sGooseBefore;
	SStateOnKill	sGooseAfter;
	SStateOnKill	sMaverickBefore;
	SStateOnKill	sMaverickAfter;

	Ptr<CRedJet>	pRedJetGoose = ONMalloc(CRedJet, "Goose");
	Ptr<CRedJet>	pRedJetMaverick = ONMalloc(CRedJet, "Maverick");

	pRedJetGoose->Init(pWorld);
	pRedJetMaverick->Init(pWorld);

	pRedJetGoose->SetKillHook(&sGooseBefore, &sGooseAfter);
	pRedJetMaverick->SetKillHook(&sMaverickBefore, &sMaverickAfter);

	Ptr<CMissile> pMissile1 = pHarrier->FireMissile(pRedJetGoose);
	Ptr<CMissile> pMissile2 = pHarrier->FireMissile(pRedJetGoose);
	Ptr<CMissile> pMissile3 = pHarrier->FireMissile(pRedJetMaverick);

	AssertString("Kill not called", sMaverickBefore.cPicture.mszPretenedImAPicture);
	AssertString("Kill not called", sMaverickAfter.cPicture.mszPretenedImAPicture);
	AssertLongLongInt(12, gcObjects.NumMemoryIndexes());
	AssertLongLongInt(5, gcObjects.NumMemoryNames());
	AssertLongLongInt(0, gcObjects.NumDatabaseObjects());
	AssertLongLongInt(0, gcObjects.NumDatabaseNames());
	AssertInt(2, pWorld.GetDistToRoot());
	AssertInt(3, pHarrier.GetDistToRoot());
	AssertInt(3, pJeep.GetDistToRoot());
	AssertInt(4, pRedJetGoose.GetDistToRoot());
	AssertInt(4, pRedJetMaverick.GetDistToRoot());
	AssertInt(4, pMissile1.GetDistToRoot());
	AssertInt(4, pMissile2.GetDistToRoot());
	AssertInt(4, pMissile3.GetDistToRoot());
	AssertInt(2, pRedJetMaverick->NumHeapFroms());
	AssertInt(3, pHarrier->GetMissiles()->NumElements());

	OIndex oiMissile3 = pMissile3->GetOI();
	AssertLongLongInt(12LL, oiMissile3);

	pMissile3->Kill();  //<-- This is what is being tested.
	pMissile3 = gcObjects.TestGetFromMemory(oiMissile3);
	AssertTrue(pMissile3.IsNull());

	AssertString("Kill not called", sMaverickBefore.cPicture.mszPretenedImAPicture);
	AssertString("Kill not called", sMaverickAfter.cPicture.mszPretenedImAPicture);
	AssertLongLongInt(11, gcObjects.NumMemoryIndexes());
	AssertLongLongInt(5, gcObjects.NumMemoryNames());
	AssertLongLongInt(0, gcObjects.NumDatabaseObjects());
	AssertLongLongInt(0, gcObjects.NumDatabaseNames());
	AssertInt(2, pWorld.GetDistToRoot());
	AssertInt(3, pHarrier.GetDistToRoot());
	AssertInt(3, pJeep.GetDistToRoot());
	AssertInt(4, pRedJetGoose.GetDistToRoot());
	AssertInt(4, pRedJetMaverick.GetDistToRoot());
	AssertInt(4, pMissile1.GetDistToRoot());
	AssertInt(4, pMissile2.GetDistToRoot());
	AssertInt(1, pRedJetMaverick->NumHeapFroms());
	AssertInt(2, pHarrier->GetMissiles()->NumElements());

	AssertString("Kill not called", sGooseBefore.cPicture.mszPretenedImAPicture);
	AssertString("Kill not called", sGooseAfter.cPicture.mszPretenedImAPicture);

	pRedJetGoose->Kill();
	AssertString("012345678901234", sGooseBefore.cPicture.mszPretenedImAPicture);
	AssertString("Alas I am Dead!", sGooseAfter.cPicture.mszPretenedImAPicture);
	AssertInt(1, pMissile1->NumTos());
	CPointer pTarget1(pMissile1->GetTarget());
	AssertTrue(pTarget1.IsNull());
	AssertInt(1, pMissile2->NumTos());
	CPointer pTarget2 = pMissile2->GetTarget();
	AssertTrue(pTarget2.IsNull());
	AssertLongLongInt(10, gcObjects.NumMemoryIndexes());
	AssertLongLongInt(4, gcObjects.NumMemoryNames());
	AssertLongLongInt(0, gcObjects.NumDatabaseObjects());
	AssertLongLongInt(0, gcObjects.NumDatabaseNames());
	AssertInt(2, pWorld.GetDistToRoot());
	AssertInt(3, pHarrier.GetDistToRoot());
	AssertInt(3, pJeep.GetDistToRoot());
	AssertInt(4, pRedJetMaverick.GetDistToRoot());
	AssertInt(4, pMissile1.GetDistToRoot());
	AssertInt(4, pMissile2.GetDistToRoot());

	pMissile1->Kill();
	pMissile2->Kill();
	AssertInt(0, pHarrier->GetMissiles()->NumElements());
	AssertTrue(pMissile1.IsNull());
	AssertTrue(pMissile2.IsNull());

	pJeep = NULL;
	pRedJetMaverick = NULL;
	pHarrier = NULL;

	//pHarrier.maMissiles.moi == 6
	//pWorld.maTickables.moi == 4
	//pWorld is pointed to from:
	//  pRoot.mpObjects
	//  pHarrier
	//  pJeep
	//  pRedJetMaverick

	pRoot->Remove(pWorld);
	//ERROR: (baseobject.cpp:1159) void __thiscall CBaseObject::ValidateCanFindRoot(void) Object {02596128 [ 4]:CArrayObject(128) 6} has a positive dist to root and should be able to find the Root object.

	AssertLongLongInt(8, gcObjects.NumMemoryIndexes());
	pWorld = NULL;

	AssertLongLongInt(2, gcObjects.NumMemoryIndexes());
	AssertLongLongInt(1, gcObjects.NumMemoryNames());
	AssertLongLongInt(0, gcObjects.NumDatabaseObjects());
	AssertLongLongInt(0, gcObjects.NumDatabaseNames());

	AssertInt('X', sHarrierBefore.sPoint.x);
	AssertInt('Y', sHarrierBefore.sPoint.y);
	AssertInt('Z', sHarrierBefore.sPoint.z);
	AssertString("012345678901234", sHarrierBefore.cPicture.mszPretenedImAPicture);
	AssertString("Alas I am Dead!", sHarrierAfter.cPicture.mszPretenedImAPicture);
	AssertString("012345678901234", sJeepBefore.cPicture.mszPretenedImAPicture);
	AssertString("Alas I am Dead!", sJeepAfter.cPicture.mszPretenedImAPicture);

	ObjectsKill();
}
void TestEmbeddedObjectContainerDehollowfication(void)
{
	BOOL		bResult;
	CFileUtil	cFileUtil;
	char*		szClassName;
	OIndex		oiComplex;

	cFileUtil.RemoveDir("Output/EmbeddedObject");

	MemoryInit();
	ObjectsInit("Output/EmbeddedObject/");
	SetupEmbeddedObjectConstructors();

	Ptr<CRoot> pRoot = ORoot();
	Ptr<CEmbeddedComplex> pComplex = OMalloc(CEmbeddedComplex)->Init();
	oiComplex = pComplex->GetOI();

	pRoot->Add(pComplex);

	bResult = gcObjects.Flush(TRUE, TRUE);
	AssertTrue(bResult);

	ObjectsKill();
	MemoryKill();

	AssertInt(176, sizeof(CEmbeddedTest));
	AssertInt(544, sizeof(CEmbeddedContainer));
	AssertInt(1032, sizeof(CEmbeddedComplex));

	MemoryInit();
	ObjectsInit("Output/EmbeddedObject/");
	SetupEmbeddedObjectConstructors();

	pRoot = gcObjects.GetRoot();
	AssertTrue(pRoot.IsNotNull());
	pComplex = pRoot->Get(0);
	AssertTrue(pComplex.IsHollow());
	
	szClassName = pComplex->ClassName();
	AssertString("CEmbeddedComplex", szClassName);
	AssertLongLongInt(oiComplex, pComplex.GetIndex());

	AssertInt(1, pComplex->mai[0]);
	AssertInt(2, pComplex->mai[1]);
	
	AssertLongLongInt(INVALID_O_INDEX, pComplex->mcSimple.GetOI());
	AssertInt(85, pComplex->mcSimple.miAmANumber);
	AssertFloat(58.0f, pComplex->mcSimple.mfSoAmI, 0);

	AssertLongLongInt(INVALID_O_INDEX, pComplex->mcContainer.GetOI());
	AssertInt(73, pComplex->mcContainer.mi);
	AssertFloat(666.0f, pComplex->mcContainer.mf, 0);
	AssertString("And", pComplex->mcContainer.msz);

	AssertLongLongInt(INVALID_O_INDEX, pComplex->mcContainer.mcOne.GetOI());
	AssertInt(85, pComplex->mcContainer.mcOne.miAmANumber);
	AssertFloat(58.0f, pComplex->mcContainer.mcOne.mfSoAmI, 0);

	AssertLongLongInt(INVALID_O_INDEX, pComplex->mcContainer.mcTwo.GetOI());
	AssertInt(85, pComplex->mcContainer.mcTwo.miAmANumber);
	AssertFloat(58.0f, pComplex->mcContainer.mcTwo.mfSoAmI, 0);

	AssertLongLongInt(3, gcObjects.NumMemoryIndexes());

	ObjectsKill();
	MemoryKill();
}
void TestEmbeddedObjectKill(void)
{
	char	szClusterMissileState[64];
	char	szMissile1State[64];

	ObjectsInit();

	Ptr<CRoot> pRoot = ORoot();
	Ptr<CGameWorld> pWorld = OMalloc(CGameWorld)->Init();

	pRoot->Add(pWorld);

	Ptr<CClusterMissile> pClusterMissile = ONMalloc(CClusterMissile, "Anna")->Init(pWorld);
	pWorld = NULL;

	Ptr<CPointerContainer> pPointerPointer = OMalloc(CPointerContainer);
	pRoot->Add(pPointerPointer);
	pPointerPointer->Init(&pClusterMissile->mcMissile1);

	Ptr<CPointerContainer> pPointerPointer2 = OMalloc(CPointerContainer);
	pRoot->Add(pPointerPointer2);
	pPointerPointer2->Init(&pClusterMissile);

	//The number of allocated object shouldn't change until all the froms are removed
	//both from the embedded object and the 'normal' object.
	AssertLongLongInt(7, gcObjects.GetMemory()->NumIndexed());
	AssertLongLongInt(7, gcUnknowns.NumElements());

	pClusterMissile->SetKillString(szClusterMissileState);
	pClusterMissile->mcMissile1.SetKillString(szMissile1State);

	AssertInt(2, pClusterMissile->NumHeapFroms());
	AssertInt(1, pClusterMissile->CEmbeddedObject::NumHeapFroms());
	AssertInt(1, pClusterMissile->mcMissile1.NumHeapFroms());
	strcpy(szClusterMissileState, "Alive");
	strcpy(szMissile1State, "Alive");

	pPointerPointer->Clear();

	AssertInt(1, pClusterMissile->NumHeapFroms());
	AssertInt(1, pClusterMissile->CEmbeddedObject::NumHeapFroms());
	AssertInt(0, pClusterMissile->mcMissile1.NumHeapFroms());
	AssertString("Alive", szClusterMissileState);
	AssertString("Alive", szMissile1State);

	pPointerPointer->mp = &pClusterMissile->mcMissile1;

	AssertInt(2, pClusterMissile->NumHeapFroms());
	AssertInt(1, pClusterMissile->CEmbeddedObject::NumHeapFroms());
	AssertInt(1, pClusterMissile->mcMissile1.NumHeapFroms());

	pPointerPointer2->Clear();

	AssertInt(1, pClusterMissile->NumHeapFroms());
	AssertInt(0, pClusterMissile->CEmbeddedObject::NumHeapFroms());
	AssertInt(1, pClusterMissile->mcMissile1.NumHeapFroms());
	AssertString("Alive", szClusterMissileState);
	AssertString("Alive", szMissile1State);

	pClusterMissile = NULL;

	//Make sure nothing has been de-allocated.
	AssertLongLongInt(7, gcObjects.GetMemory()->NumIndexed());
	AssertLongLongInt(7, gcUnknowns.NumElements());

	pPointerPointer->Clear();

	AssertString("Killed", szClusterMissileState);
	AssertString("Killed", szMissile1State);

	AssertLongLongInt(6, gcObjects.GetMemory()->NumIndexed());
	AssertLongLongInt(6, gcUnknowns.NumElements());

	gcObjects.Flush(TRUE, FALSE);

	AssertLongLongInt(0, gcObjects.GetMemory()->NumIndexed());
	AssertLongLongInt(0, gcUnknowns.NumElements());

	ObjectsKill();
}
Beispiel #20
0
void TestKillCanFindRoot(void)
{
	ObjectsInit();

	Ptr<CRoot>			pRoot;
	Ptr<CGameWorld>		pWorld;
	CGameWorld*			pcWorld;

	pRoot = ORoot();

	pWorld = OMalloc(CGameWorld);
	pWorld->Init();

	pRoot->Add(pWorld);

	Ptr<CHarrier> pHarrier = ONMalloc(CHarrier, "Harrier");
	pHarrier->Init(pWorld);

	Ptr<CJeep> pJeep = ONMalloc(CJeep, "Jeep");
	pJeep->Init(pWorld);

	pWorld->AddPlayer(pHarrier);
	pWorld->AddPlayer(pJeep);

	SStateOnKill	sHarrierBefore;
	SStateOnKill	sHarrierAfter;
	SStateOnKill	sJeepBefore;
	SStateOnKill	sJeepAfter;

	pHarrier->SetKillHook(&sHarrierBefore, &sHarrierAfter);
	pJeep->SetKillHook(&sJeepBefore, &sJeepAfter);

	SStateOnKill	sGooseBefore;
	SStateOnKill	sGooseAfter;
	SStateOnKill	sMaverickBefore;
	SStateOnKill	sMaverickAfter;

	Ptr<CRedJet>	pRedJetGoose = ONMalloc(CRedJet, "Goose");
	Ptr<CRedJet>	pRedJetMaverick = ONMalloc(CRedJet, "Maverick");

	pRedJetGoose->Init(pWorld);
	pRedJetMaverick->Init(pWorld);

	pRedJetGoose->SetKillHook(&sGooseBefore, &sGooseAfter);
	pRedJetMaverick->SetKillHook(&sMaverickBefore, &sMaverickAfter);

	AssertTrue(pJeep->CanFindRoot());
	AssertTrue(pRedJetMaverick->CanFindRoot());
	AssertTrue(pHarrier->CanFindRoot());
	AssertTrue(pHarrier->GetMissiles()->CanFindRoot());
	AssertTrue(pRedJetGoose->CanFindRoot());
	AssertTrue(pWorld->CanFindRoot());
	AssertTrue(pWorld->GetTickables()->CanFindRoot());
	AssertTrue(pRoot->CanFindRoot());
	AssertTrue(pRoot->TestGetSet()->CanFindRoot());
	AssertLongLongInt(9, gcObjects.NumMemoryIndexes());

	//     
	// 4        ArrayObject[6](4)
	// 4                 ^
	// 4                 |                     pRedJetGoose[8,Goose](4)
	// 4                 |                            ^/
	//                   |                           //  pRedJetMaverick[9,Maverick](4)
	// 3  pHarrier[5,Harrier](3)   pJeep[7,Jeep](3) //   ^/  
	// 3                |^     ^   /^     ^        //   //
	// 3                ||      \ //      |       //   //
	// 3                ||       //       |      //   //
	// 3                ||      //\       |     //   //
	// 3                ||     //  \      |    /.   //
	// 3                ||    //   ArrayObject[4](3)/
	//                  ||   //    ^          .    /
	// 2                ||  //    /          /    /
	// 2                v| v/    /          v    v 
	// 2               pWorld[3](2)---------------
	//                   ^
	// 1                 |
	// 1             SetObject[2](1)
	//                   ^
	// 0                 |
	// 0              pRoot[1,GraphRoot](0)
	//  

	pRoot->Remove(pWorld);
	AssertFalse(pJeep->CanFindRoot());
	AssertFalse(pRedJetMaverick->CanFindRoot());
	AssertFalse(pHarrier->CanFindRoot());
	AssertFalse(pHarrier->GetMissiles()->CanFindRoot());  //The destruction of the pointer created by pHarrier->GetMissiles() set a lot of the root distances to -2.
	AssertFalse(pRedJetGoose->CanFindRoot());
	AssertFalse(pWorld->CanFindRoot());
	AssertFalse(pWorld->GetTickables()->CanFindRoot());
	AssertTrue(pRoot->CanFindRoot());
	AssertTrue(pRoot->TestGetSet()->CanFindRoot());
	AssertInt(-1, pJeep->GetDistToRoot());
	AssertInt(-1, pRedJetMaverick->GetDistToRoot());
	AssertInt(-1, pHarrier->GetDistToRoot());
	AssertInt(-1, pHarrier->GetMissiles()->GetDistToRoot());
	AssertInt(-1, pRedJetGoose->GetDistToRoot());
	AssertInt(-1, pWorld->GetDistToRoot());
	AssertInt(-1, pWorld->GetTickables()->GetDistToRoot());
	AssertLongLongInt(9, gcObjects.NumMemoryIndexes());
	AssertLongLongInt(5, gcObjects.NumMemoryNames());
	AssertLongLongInt(0, gcObjects.NumDatabaseObjects());
	AssertLongLongInt(0, gcObjects.NumDatabaseNames());

	pJeep = NULL;
	pRedJetMaverick = NULL;
	pHarrier = NULL;
	pRedJetGoose = NULL;
	pcWorld = &pWorld;
	pWorld = NULL;

	AssertLongLongInt(2, gcObjects.NumMemoryIndexes());
	AssertLongLongInt(1, gcObjects.NumMemoryNames());

	AssertInt('X', sHarrierBefore.sPoint.x);
	AssertInt('Y', sHarrierBefore.sPoint.y);
	AssertInt('Z', sHarrierBefore.sPoint.z);
	AssertString("012345678901234", sHarrierBefore.cPicture.mszPretenedImAPicture);
	AssertString("Alas I am Dead!", sHarrierAfter.cPicture.mszPretenedImAPicture);
	AssertString("012345678901234", sJeepBefore.cPicture.mszPretenedImAPicture);
	AssertString("Alas I am Dead!", sJeepAfter.cPicture.mszPretenedImAPicture);

	ObjectsKill();
}
Ptr<CTestDoubleNamedString> SetupDehollowficationScene(void)
{
	Ptr<CTestNamedString>			cNS1;
	Ptr<CTestNamedString>			cNS2;
	Ptr<CTestNamedString>			cDiamond;
	Ptr<CTestDoubleNamedString>	cDouble;
	Ptr<CString>					sz1;
	Ptr<CString>					sz3;
	Ptr<CString>					sz2;
	Ptr<CString>					sz4;
	Ptr<CRoot>						cRoot;
	Ptr<CTestNamedString>			cNS3;

	cRoot = ORoot();

	cDiamond = ONMalloc(CTestNamedString, "Diamond End");
	sz1 = OMalloc(CString);

	cNS1 = ONMalloc(CTestNamedString, "NamedString 1");
	cNS1->Init(sz1, cDiamond, "Hello");
	sz1->Init("World");

	cNS2 = ONMalloc(CTestNamedString, "NamedString 2");
	sz2 = OMalloc(CString);

	cNS2->Init(sz2, cDiamond, "12345");
	sz2->Init("6789");

	sz3 = OMalloc(CString);
	sz3->Init("End");
	cDiamond->Init(sz3, ONull, "Before Swine");

	sz4 = OMalloc(CString);
	sz4->Init("Start");
	cDouble = ONMalloc(CTestDoubleNamedString, "Double Start");
	cDouble->Init(sz4, cNS1, ONull);

	cRoot->Add(cDouble);

	cDouble->mpSplit1 = cNS2;

	cNS3 = ONMalloc(CTestNamedString, "NamedString 3");
	cNS3->Init(sz1, ONull, "Random");

	cRoot->Add(cNS3);

//
//      sz3
//       |
//    cDiamond
//      / \
// sz2 /   \  sz1
//  | /     \  |
//  cNS2    cNS1
//    \     /
//     \   / sz4
//      \ /  /
//    cDouble   sz1 
//       \       |
//        \    cNS3
//         \   /
//          \ /
//          Set
//           |
//         cRoot
//       

	return cDouble;
}
void TestObjectsObjectSave(void)
{
	CFileUtil						cFileUtil;
	Ptr<CTestDoubleNamedString>		pDouble;
	BOOL							bResult;
	CIndexedConfig					cConfig;

	cFileUtil.RemoveDir("Output");
	cFileUtil.MakeDir("Output/ObjectSave");
	cConfig.OptimiseForStreaming("Output/ObjectSave");
	cConfig.SetObjectCacheSize(128 MB);

	ObjectsInit(&cConfig);

	pDouble = SetupObjectsForDehollowfication();

	AssertLongLongInt(0, gcObjects.NumDatabaseObjects());
	AssertLongLongInt(9, gcObjects.NumMemoryIndexes());
	AssertLongLongInt(6, gcObjects.NumMemoryNames());
	AssertTrue(pDouble.IsDirty());
	
	bResult = gcObjects.Save(pDouble.BaseObject());
	AssertTrue(bResult);
	AssertTrue(pDouble.IsDirty());  //This object is *still* dirty after save.  Almost no objects will answer true to IsDirty.

	AssertLongLongInt(1, gcObjects.NumDatabaseObjects());
	AssertLongLongInt(9, gcObjects.NumMemoryIndexes());
	AssertLongLongInt(6, gcObjects.NumMemoryNames());
	AssertInt(106, pDouble->SerialisedSize());
	AssertLongLongInt(1, gcObjects.NumDatabaseObjectsCached(106));
	AssertLongLongInt(0, gcObjects.NumDatabaseObjectsCached(118));

	bResult = gcObjects.Save(pDouble.BaseObject());
	AssertTrue(bResult);
	AssertLongLongInt(1, gcObjects.NumDatabaseObjects());
	AssertInt(106, pDouble->SerialisedSize());
	AssertLongLongInt(1, gcObjects.NumDatabaseObjectsCached(106));
	AssertLongLongInt(0, gcObjects.NumDatabaseObjectsCached(118));
	
	pDouble->mszString = OMalloc(CString);
	pDouble->mszString->Init("A String");

	bResult = gcObjects.Save(pDouble.BaseObject());
	AssertTrue(bResult);
	AssertLongLongInt(1, gcObjects.NumDatabaseObjects());
	AssertInt(118, pDouble->SerialisedSize());
	AssertLongLongInt(0, gcObjects.NumDatabaseObjectsCached(106));
	AssertLongLongInt(1, gcObjects.NumDatabaseObjectsCached(118));

	pDouble->mszString = OMalloc(CString);
	pDouble->mszString->Init("Different Object");

	AssertInt(118, pDouble->SerialisedSize());
	bResult = gcObjects.Save(pDouble.BaseObject());
	AssertTrue(bResult);
	AssertLongLongInt(1, gcObjects.NumDatabaseObjects());
	AssertInt(118, pDouble->SerialisedSize());
	AssertLongLongInt(0, gcObjects.NumDatabaseObjectsCached(106));
	AssertLongLongInt(1, gcObjects.NumDatabaseObjectsCached(118));

	ObjectsKill();
}