// Copyright (C) 2002-2003 Chad C. Yates cyates@uidaho.edu // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation; either version 2 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program; if not, write to the Free Software // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. // // As a special exception to the GNU General Public License, permission is // granted for additional uses of the text contained in its release // of Common C++. // // The exception is that, if you link the Common C++ library with other // files to produce an executable, this does not by itself cause the // resulting executable to be covered by the GNU General Public License. // Your use of that executable is in no way restricted on account of // linking the Common C++ library code into it. // // This exception does not however invalidate any other reasons why // the executable file might be covered by the GNU General Public License. // // This exception applies only to the code released under the // name Common C++. If you copy code from other releases into a copy of // Common C++, as the General Public License permits, the exception does // not apply to the code that you add in this way. To avoid misleading // anyone as to the status of such modified files, you must delete // this exception notice from them. // // If you write modifications of your own for Common C++, it is your choice // whether to permit this exception to apply to your modifications. // If you do not wish that, delete this exception notice. #include "Test_Engine.h" #include CPPUNIT_TEST_SUITE_REGISTRATION(EngineTest); void EngineTest::setUp() { // Create an example object with some sub objects and various data elements complexObject.iInteger = 5; complexObject.strString = "String 1"; complexObject.strString2 = "String 2"; complexObject.uninitializedNullPtr = NULL; // initialized here instead of constructor to see if it will be unpersisted as a null (vs defaulting to null from the constructor) for(int i = 0; i < 10; i++) complexObject.numbers.push_back(i); complexObject.strings.push_back("a"); complexObject.strings.push_back("b"); complexObject.strings.push_back("c"); complexObject.strings.push_back("d"); complexObject.strings.push_back("e"); complexObject.moreStrings.push_back("z"); complexObject.moreStrings.push_back("y"); complexObject.moreStrings.push_back("x"); complexObject.moreStrings.push_back("w"); complexObject.moreStrings.push_back("v"); complexObject.subObjectPtr = new TestSub; complexObject.subObjectPtr2 = complexObject.subObjectPtr; // set to point to the same thing as subObjectPtr to test unpersisting of shared instances complexObject.subObjectPtr->iInteger = 5; complexObject.subObjectPtr->strString = "SubStringPtr 1"; complexObject.subObjectPtr->strString2 = "SubStringPtr 2"; for(int j = 10; j < 20; j++) complexObject.subObjectPtr->numbers.push_back(j); complexObject.subObjectRef.iInteger = 5; complexObject.subObjectRef.strString = "SubString2 1"; complexObject.subObjectRef.strString2 = "SubString2 2"; for(int k = 30; k < 35; k++) complexObject.subObjectRef.numbers.push_back(k); // make a std::deque of TestSub objects for(int l = 0; l < 2; l++) { TestSub newSubObject; newSubObject.iInteger = l; char tmp[50]; sprintf(tmp, "test %d", l+1); newSubObject.strString = tmp; for(int k = 30; k < 35; k++) newSubObject.numbers.push_back(k); complexObject.subObjects.push_back(newSubObject); } } void EngineTest::tearDown() {} void EngineTest::testPrimitives() { // write primitive types std::fstream outputArchive("EnginePrimitiveTest.dat", std::ios::out|std::ios::binary); Engine outputEngine(outputArchive, ost::Engine::modeWrite); TEST_PRIMITIVE_OUTPUT(int8, 0x01); TEST_PRIMITIVE_OUTPUT(uint8, 0x01); TEST_PRIMITIVE_OUTPUT(int16, 0x0123); TEST_PRIMITIVE_OUTPUT(uint16, 0x0123); TEST_PRIMITIVE_OUTPUT(int32, 0x01234567); TEST_PRIMITIVE_OUTPUT(uint32, 0x01234567); //TEST_PRIMITIVE_OUTPUT(int64, 0x0123456789ABCDEF); // warning: integer constant larger than the maximum value of an unsigned long int //TEST_PRIMITIVE_OUTPUT(uint64, 0x0123456789ABCDEF); // warning: integer constant larger than the maximum value of an unsigned long int TEST_PRIMITIVE_OUTPUT(float, 3.141592653589793238462643f); TEST_PRIMITIVE_OUTPUT(double, 3.141592653589793238462643); TEST_PRIMITIVE_OUTPUT(string, "abcdefghijklmnopqrstuvwxyz0123456789"); outputEngine.sync(); // flush Engine buffers before closing file outputArchive.close(); // read primitive types back in and check std::fstream inputArchive("EnginePrimitiveTest.dat", std::ios::in|std::ios::binary); Engine inputEngine(inputArchive, ost::Engine::modeRead); TEST_PRIMITIVE_INPUT(int8); TEST_PRIMITIVE_INPUT(uint8); TEST_PRIMITIVE_INPUT(int16); TEST_PRIMITIVE_INPUT(uint16); TEST_PRIMITIVE_INPUT(int32); TEST_PRIMITIVE_INPUT(uint32); //TEST_PRIMITIVE_INPUT(int64); //TEST_PRIMITIVE_INPUT(uint64); TEST_PRIMITIVE_INPUT(float); TEST_PRIMITIVE_INPUT(double); TEST_PRIMITIVE_INPUT(string); inputArchive.close(); } void EngineTest::testRawBinary() { int i; // write raw binary data std::fstream outputArchive("EngineRawBinaryTest.dat", std::ios::out|std::ios::binary); Engine outputEngine(outputArchive, ost::Engine::modeWrite); unsigned int binaryBuffer[BINARY_BUFFER_SIZE]; for(i = 0; i < BINARY_BUFFER_SIZE; i++) binaryBuffer[i] = i; outputEngine.writeBinary((const uint8*) binaryBuffer, sizeof(binaryBuffer)); outputEngine.sync(); // flush Engine buffers before closing file outputArchive.close(); // read binary data back in and check std::fstream inputArchive("EngineRawBinaryTest.dat", std::ios::in|std::ios::binary); Engine inputEngine(inputArchive, ost::Engine::modeRead); unsigned int binaryBuffer2[BINARY_BUFFER_SIZE]; inputEngine.readBinary((uint8*) binaryBuffer2, sizeof(binaryBuffer2)); inputArchive.close(); for(i = 0; i < BINARY_BUFFER_SIZE; i++) CPPUNIT_ASSERT(binaryBuffer[i] == binaryBuffer2[i]); } void EngineTest::testSTLVector() { int i; // write STL data std::fstream outputArchive("EngineSTLVectorTest.dat", std::ios::out|std::ios::binary); Engine outputEngine(outputArchive, ost::Engine::modeWrite); std::vector intVector; std::vector* pIntVector = new std::vector; for(i = 0; i < STL_CONTAINER_SIZE; i++) { intVector.push_back(i); pIntVector->push_back(i); } outputEngine << intVector; outputEngine << *pIntVector; outputEngine.sync(); // flush Engine buffers before closing file outputArchive.close(); // read STL std::vector back in and check std::fstream inputArchive("EngineSTLVectorTest.dat", std::ios::in|std::ios::binary); Engine inputEngine(inputArchive, ost::Engine::modeRead); std::vector intVector2; inputEngine >> intVector2; CPPUNIT_ASSERT(intVector == intVector2); std::vector* pIntVector2 = new std::vector; inputEngine >> *pIntVector2; CPPUNIT_ASSERT(*pIntVector == *pIntVector2); delete pIntVector2; inputArchive.close(); delete pIntVector; } void EngineTest::testSTLDeque() { int i; // write STL std::deque data std::fstream outputArchive("EngineSTLDequeTest.dat", std::ios::out|std::ios::binary); Engine outputEngine(outputArchive, ost::Engine::modeWrite); std::deque intDeque; std::deque* pIntDeque = new std::deque; for(i = 0; i < STL_CONTAINER_SIZE; i++) { intDeque.push_back(i); pIntDeque->push_back(i); } outputEngine << intDeque; outputEngine << *pIntDeque; outputEngine.sync(); // flush Engine buffers before closing file outputArchive.close(); // read STL std::deque back in and check std::fstream inputArchive("EngineSTLDequeTest.dat", std::ios::in|std::ios::binary); Engine inputEngine(inputArchive, ost::Engine::modeRead); std::deque intDeque2; inputEngine >> intDeque2; CPPUNIT_ASSERT(intDeque == intDeque2); std::deque* pIntDeque2 = new std::deque; inputEngine >> *pIntDeque2; CPPUNIT_ASSERT(*pIntDeque == *pIntDeque2); delete pIntDeque2; inputArchive.close(); delete pIntDeque; } void EngineTest::testSTLMap() { int i; // write STL std::map data std::fstream outputArchive("EngineSTLMapTest.dat", std::ios::out|std::ios::binary); Engine outputEngine(outputArchive, ost::Engine::modeWrite); std::map intMap; std::map* pIntMap = new std::map; for(i = 0; i < STL_CONTAINER_SIZE; i++) { intMap.insert(std::pair(i, i+10)); pIntMap->insert(std::pair(i, i+11)); } outputEngine << intMap; outputEngine << *pIntMap; outputEngine.sync(); // flush Engine buffers before closing file outputArchive.close(); // read STL std::map back in and check std::fstream inputArchive("EngineSTLMapTest.dat", std::ios::in|std::ios::binary); Engine inputEngine(inputArchive, ost::Engine::modeRead); std::map intMap2; inputEngine >> intMap2; CPPUNIT_ASSERT(intMap == intMap2); std::map* pIntMap2 = new std::map; inputEngine >> *pIntMap2; CPPUNIT_ASSERT(*pIntMap == *pIntMap2); delete pIntMap2; inputArchive.close(); delete pIntMap; } void EngineTest::testComplexObject() { // write BaseObject hierarchy std::fstream outputArchive("EngineComplexObjectTest.dat", std::ios::out|std::ios::binary); Engine outputEngine(outputArchive, ost::Engine::modeWrite); outputEngine << complexObject; outputEngine.sync(); // flush Engine buffers before closing file outputArchive.close(); // Unpersist a new object structure into an uninitialized object { Test* myObjPtr = NULL; // must initialize pointer or new persistence engine will think it is already allocated std::fstream inputArchive("EngineComplexObjectTest.dat", std::ios::in); Engine inputEngine(inputArchive, ost::Engine::modeRead); inputEngine >> myObjPtr; inputArchive.close(); CPPUNIT_ASSERT_MESSAGE("Unpersisted into unallocated pointer == Original", *myObjPtr == complexObject); CPPUNIT_ASSERT_MESSAGE("nullPtr is NULL", myObjPtr->nullPtr == NULL); CPPUNIT_ASSERT_MESSAGE("uninitializedNullPtr is NULL", myObjPtr->uninitializedNullPtr == NULL); myObjPtr->subObjectPtr->strString2 = "Changed SubStringPtr 1"; CPPUNIT_ASSERT_MESSAGE("subObjectPtr.strString2 should always equal subObjectPtr2.strString2", myObjPtr->subObjectPtr->strString2 == myObjPtr->subObjectPtr2->strString2); CPPUNIT_ASSERT_MESSAGE("subObjectPtr.strString2 should now equal 'Changed SubStringPtr 1'", myObjPtr->subObjectPtr->strString2 == "Changed SubStringPtr 1"); CPPUNIT_ASSERT_MESSAGE("subObjectPtr.strString2 should still equal subObjectPtr2.strString2", myObjPtr->subObjectPtr->strString2 == myObjPtr->subObjectPtr2->strString2); } // Unpersist a new object structure into an instantiated class variable { Test myObjInstance; std::fstream inputArchive("EngineComplexObjectTest.dat", std::ios::in); Engine inputEngine(inputArchive, ost::Engine::modeRead); inputEngine >> myObjInstance; inputArchive.close(); CPPUNIT_ASSERT_MESSAGE("Unpersisted into default constructed instance == Original", myObjInstance == complexObject); CPPUNIT_ASSERT_MESSAGE("nullPtr is NULL", myObjInstance.nullPtr == NULL); CPPUNIT_ASSERT_MESSAGE("UninitializedNullPtr is NULL", myObjInstance.uninitializedNullPtr == NULL); } // Unpersist a new object structure into a pre-initialized pointer to an object { Test* myObjAllocatedPtr = new Test; std::fstream inputArchive("EngineComplexObjectTest.dat", std::ios::in); Engine inputEngine(inputArchive, ost::Engine::modeRead); inputEngine >> myObjAllocatedPtr; outputEngine.sync(); // flush Engine buffers before closing file inputArchive.close(); CPPUNIT_ASSERT_MESSAGE("Unpersisted into pre-allocated pointer", *myObjAllocatedPtr == complexObject); CPPUNIT_ASSERT_MESSAGE("nullPtr is NULL", myObjAllocatedPtr->nullPtr == NULL); CPPUNIT_ASSERT_MESSAGE("uninitializedNullPtr is NULL", myObjAllocatedPtr->uninitializedNullPtr == NULL); } } void EngineTest::testModeExceptions() { // write primitive types std::fstream outputArchive("EnginePrimitiveTest.dat", std::ios::in|std::ios::binary); Engine outputEngine(outputArchive, ost::Engine::modeWrite); int32 test_Int32 = 0x01234567; try { outputEngine << test_Int32; //CPPUNIT_FAIL("Call to persist to an input stream should throw an exception"); } catch(PersistException &ex) { CPPUNIT_ASSERT_MESSAGE(ex.getString(), true); } outputArchive.close(); }