/* PolymorphicValue(Test) - verify handling of opaque polymorphic values Copyright (C) Lumiera.org 2011, Hermann Vosseler 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., 675 Mass Ave, Cambridge, MA 02139, USA. * *****************************************************/ #include "lib/test/run.hpp" #include "lib/test/test-helper.hpp" #include "lib/util.hpp" #include "lib/util-foreach.hpp" #include "lib/polymorphic-value.hpp" //#include "lib/bool-checkable.hpp" #include //#include #include namespace lib { namespace test{ using ::Test; // using util::isnil; using util::for_each; using util::unConst; using util::isSameObject; // using lumiera::error::LUMIERA_ERROR_INVALID; using lumiera::error::LUMIERA_ERROR_ASSERTION; // using std::vector; // using std::cout; // using std::endl; namespace { // test dummy hierarchy // Note: largely varying space requirements // correct function depending on concrete class struct Interface { virtual ~Interface() {} virtual long apiFunc() =0; virtual long& localSum() =0; bool operator== (Interface const& o) const { return unConst(this)->localSum() == unConst(o).localSum(); } }; const uint MAX_RAND = 1000; const uint MAX_SIZ = sizeof(long[113]); /////////////////////TODO: using just 111 causes SEGV ---> suspect the HandlingAdapter mixin to require additional storage long _checkSum = 0; long _callSum = 0; uint _created = 0; template struct Imp : Interface { long localData_[ii]; ~Imp() { mark (-1 * localSum()); CHECK (0 == localSum()); } Imp() { REQUIRE (0 < ii); localSum() = 0; mark(ii); ++ _created; } Imp (Imp const& o) { ++ _created; copyData (o); _checkSum += localSum(); }// adjust, because we've gotten two identical instances Imp& operator= (Imp const& o) { _checkSum -= localSum(); copyData (o); _checkSum += localSum(); return *this; } private: virtual long apiFunc() { long rr = ii * (rand() % MAX_RAND); mark (rr); _callSum += rr; return rr; } long& localSum() { return localData_[ii-1]; } void mark (long markerValue) { localSum() += markerValue; _checkSum += markerValue; } void copyData (Imp const& o) { for (uint i=0; i PolyVal; typedef std::vector TestList; /********************************************************************************** * @test build a bunch of PolymorphicValue objects. Handle them like copyable * value objects, without knowing the exact implementation type; moreover * execute implementation internals only disclosed to the concrete subtype. * Verify correctness through checksums. */ class PolymorphicValue_test : public Test { virtual void run (Arg) { _checkSum = 0; _callSum = 0; _created = 0; { verifyBasics(); TestList objs = createOpaqueValues (); for_each (objs, operate); } CHECK (0 == _checkSum); // all dead verifyOverrunProtection(); } TestList createOpaqueValues () { TestList list; list.push_back (PolyVal::build > () ); list.push_back (PolyVal::build > () ); list.push_back (PolyVal::build >() ); list.push_back (PolyVal::build > () ); list.push_back (PolyVal::build > () ); return list; } //note: copy static void operate (PolyVal& elm) { PolyVal myLocalVal(elm); CHECK (elm == myLocalVal); long prevSum = _callSum; Interface& subject = myLocalVal; long randVal = subject.apiFunc(); CHECK (prevSum + randVal == _callSum); CHECK (elm != myLocalVal); elm = myLocalVal; CHECK (elm == myLocalVal); CHECK (!isSameObject (elm, myLocalVal)); CHECK (sizeof(myLocalVal) <= MAX_SIZ + polyvalue::Trait::ADMIN_OVERHEAD + _ALIGN_); } void verifyBasics() { long prevSum = _checkSum; uint prevCnt = _created; PolyVal val = PolyVal::build >(); CHECK (prevSum+111 == _checkSum); // We got one primary ctor call CHECK (prevCnt+1 <= _created); // Note: usually, the compiler optimises CHECK (prevCnt+2 >= _created); // and skips the spurious copy-operation CHECK (sizeof(PolyVal) > sizeof(Imp<111>)); Interface& embedded = val; CHECK (isSameObject(embedded,val)); CHECK (INSTANCEOF(Imp<111>, &embedded)); } void verifyOverrunProtection() { #if false ///////////////////////////////////////////////////////////////////////////////////////////////TICKET #537 : restore throwing ASSERT VERIFY_ERROR (ASSERTION, PolyVal::build >() ); #endif ///////////////////////////////////////////////////////////////////////////////////////////////TICKET #537 : restore throwing ASSERT } }; LAUNCHER (PolymorphicValue_test, "unit common"); }} // namespace lib::test