#include #include using namespace ebcl; class UnionTest : public CppUnit::TestFixture { CPPUNIT_TEST_SUITE( UnionTest ); CPPUNIT_TEST( testDefaultConsSimple ); CPPUNIT_TEST( testDefaultConsObject ); CPPUNIT_TEST( testNoDefaultCons ); CPPUNIT_TEST( testInPlaceCons ); CPPUNIT_TEST( testDestruct ); CPPUNIT_TEST( testMoveCons ); CPPUNIT_TEST( testMoveAss ); CPPUNIT_TEST( testMoveConsNoCopy ); CPPUNIT_TEST( testMoveAssNoCopy ); CPPUNIT_TEST( testCopyCons ); CPPUNIT_TEST( testCopyAss ); CPPUNIT_TEST( testCopyConsNoMove ); CPPUNIT_TEST( testCopyAssNoMove ); CPPUNIT_TEST( testMoveContentsCons ); CPPUNIT_TEST( testMoveContentsAss ); CPPUNIT_TEST( testCopyContentsCons ); CPPUNIT_TEST( testCopyContentsAss ); CPPUNIT_TEST( testSwap ); CPPUNIT_TEST( testTypeInfo ); CPPUNIT_TEST( testTargetModify ); CPPUNIT_TEST( testValue ); CPPUNIT_TEST( testValueModify ); CPPUNIT_TEST( testValueException ); CPPUNIT_TEST_SUITE_END( ); public: void tearDown( ) override; void testDefaultConsSimple( ); void testDefaultConsObject( ); void testNoDefaultCons( ); void testInPlaceCons( ); void testDestruct( ); void testMoveCons( ); void testMoveAss( ); void testMoveConsNoCopy( ); void testMoveAssNoCopy( ); void testCopyCons( ); void testCopyAss( ); void testCopyConsNoMove( ); void testCopyAssNoMove( ); void testMoveContentsCons( ); void testMoveContentsAss( ); void testCopyContentsCons( ); void testCopyContentsAss( ); void testSwap( ); void testTypeInfo( ); void testTargetModify( ); void testValue( ); void testValueModify( ); void testValueException( ); }; CPPUNIT_TEST_SUITE_REGISTRATION( UnionTest ); /*----------------------------------------------------------------------------*/ namespace { struct T_DefCons_ { int x; T_DefCons_( ) noexcept : x( 123 ) { } }; struct T_NoDefCons_ { int x; T_NoDefCons_( ) = delete; explicit T_NoDefCons_( int x ) noexcept : x( x ) { } }; struct T_NoMove_ { int x; T_NoMove_( ) = delete; explicit T_NoMove_( int x ) noexcept : x( x ) { } T_NoMove_( T_NoMove_ const& o ) noexcept : x( o.x ) { } T_NoMove_( T_NoMove_&& ) noexcept = delete; }; struct T_NoCopy_ { int x; T_NoCopy_( ) = delete; explicit T_NoCopy_( int x ) noexcept : x( x ) { } T_NoCopy_( T_NoCopy_ const& ) noexcept = delete; T_NoCopy_( T_NoCopy_&& o ) noexcept : x( o.x ) { } }; int consCounter = 0; int delCounter = 0; int mvCounter = 0; int cpCounter = 0; struct T_Counter_ { int value; T_Counter_( ) noexcept : value( 0 ) { consCounter ++; } explicit T_Counter_( int x ) noexcept : value( x ) { consCounter ++; } T_Counter_( T_Counter_ const& o ) noexcept : value( o.value ) { cpCounter ++; } T_Counter_( T_Counter_&& o ) noexcept : value( o.value ) { mvCounter ++; } ~T_Counter_( ) { delCounter ++; } }; #define M_COUNTS_(C,D,CP,M) \ do { \ CPPUNIT_ASSERT_EQUAL( int( C ) , consCounter ); \ CPPUNIT_ASSERT_EQUAL( int( D ) , delCounter ); \ CPPUNIT_ASSERT_EQUAL( int( CP ) , cpCounter ); \ CPPUNIT_ASSERT_EQUAL( int( M ) , mvCounter ); \ } while ( 0 ) } // namespace void UnionTest::tearDown( ) { consCounter = delCounter = mvCounter = cpCounter = 0; } /*----------------------------------------------------------------------------*/ void UnionTest::testDefaultConsSimple( ) { const T_Union< uint32_t , T_DefCons_ > u; CPPUNIT_ASSERT( u.hasType< uint32_t >( ) ); CPPUNIT_ASSERT( u.target< uint32_t >( ) != nullptr ); CPPUNIT_ASSERT_EQUAL( 0u , *( u.target< uint32_t >( ) ) ); } void UnionTest::testDefaultConsObject( ) { const T_Union< T_DefCons_ , uint32_t > u; CPPUNIT_ASSERT( u.hasType< T_DefCons_ >( ) ); CPPUNIT_ASSERT( u.target< T_DefCons_ >( ) != nullptr ); CPPUNIT_ASSERT_EQUAL( 123 , u.target< T_DefCons_ >( )->x ); } void UnionTest::testNoDefaultCons( ) { constexpr bool r( !std::is_default_constructible< T_Union< T_NoDefCons_ , uint32_t > >::value ); CPPUNIT_ASSERT( r ); } void UnionTest::testInPlaceCons( ) { const T_Union< uint32_t , T_NoDefCons_ > u( Construct< T_NoDefCons_ >( ) , 456 ); CPPUNIT_ASSERT( u.hasType< T_NoDefCons_ >( ) ); CPPUNIT_ASSERT( u.target< T_NoDefCons_ >( ) != nullptr ); CPPUNIT_ASSERT_EQUAL( 456 , u.target< T_NoDefCons_ >( )->x ); } void UnionTest::testDestruct( ) { { T_Union< T_Counter_ , uint32_t > u0( Construct< T_Counter_ >( ) , 123 ); } M_COUNTS_( 1 , 1 , 0 , 0 ); } /*----------------------------------------------------------------------------*/ void UnionTest::testMoveCons( ) { T_Union< T_Counter_ , uint32_t > u0( Construct< T_Counter_ >( ) , 123 ); T_Union< T_Counter_ , uint32_t > u1( std::move( u0 ) ); M_COUNTS_( 1 , 0 , 0 , 1 ); CPPUNIT_ASSERT( u1.hasType< T_Counter_ >( ) ); CPPUNIT_ASSERT( u1.target< T_Counter_ >( ) != nullptr ); CPPUNIT_ASSERT_EQUAL( 123 , u1.target< T_Counter_ >( )->value ); } void UnionTest::testMoveAss( ) { T_Union< T_Counter_ , uint32_t > u0( Construct< T_Counter_ >( ) , 123 ); T_Union< T_Counter_ , uint32_t > u1( Construct< T_Counter_ >( ) , 456 ); M_COUNTS_( 2 , 0 , 0 , 0 ); u1 = std::move( u0 ); M_COUNTS_( 2 , 1 , 0 , 1 ); CPPUNIT_ASSERT( u1.hasType< T_Counter_ >( ) ); CPPUNIT_ASSERT( u1.target< T_Counter_ >( ) != nullptr ); CPPUNIT_ASSERT_EQUAL( 123 , u1.target< T_Counter_ >( )->value ); } void UnionTest::testMoveConsNoCopy( ) { T_Union< T_Counter_ , T_NoCopy_ > u0( Construct< T_Counter_ >( ) , 123 ); T_Union< T_Counter_ , T_NoCopy_ > u1( std::move( u0 ) ); M_COUNTS_( 1 , 0 , 0 , 1 ); CPPUNIT_ASSERT( u1.hasType< T_Counter_ >( ) ); CPPUNIT_ASSERT( u1.target< T_Counter_ >( ) != nullptr ); CPPUNIT_ASSERT_EQUAL( 123 , u1.target< T_Counter_ >( )->value ); } void UnionTest::testMoveAssNoCopy( ) { T_Union< T_Counter_ , T_NoCopy_ > u0( Construct< T_Counter_ >( ) , 123 ); T_Union< T_Counter_ , T_NoCopy_ > u1( Construct< T_Counter_ >( ) , 456 ); M_COUNTS_( 2 , 0 , 0 , 0 ); u1 = std::move( u0 ); M_COUNTS_( 2 , 1 , 0 , 1 ); CPPUNIT_ASSERT( u1.hasType< T_Counter_ >( ) ); CPPUNIT_ASSERT( u1.target< T_Counter_ >( ) != nullptr ); CPPUNIT_ASSERT_EQUAL( 123 , u1.target< T_Counter_ >( )->value ); } /*----------------------------------------------------------------------------*/ void UnionTest::testCopyCons( ) { T_Union< T_Counter_ , uint32_t > u0( Construct< T_Counter_ >( ) , 123 ); T_Union< T_Counter_ , uint32_t > u1( u0 ); M_COUNTS_( 1 , 0 , 1 , 0 ); CPPUNIT_ASSERT( u1.hasType< T_Counter_ >( ) ); CPPUNIT_ASSERT( u1.target< T_Counter_ >( ) != nullptr ); CPPUNIT_ASSERT_EQUAL( 123 , u1.target< T_Counter_ >( )->value ); } void UnionTest::testCopyAss( ) { T_Union< T_Counter_ , uint32_t > u0( Construct< T_Counter_ >( ) , 123 ); T_Union< T_Counter_ , uint32_t > u1( Construct< T_Counter_ >( ) , 456 ); M_COUNTS_( 2 , 0 , 0 , 0 ); u1 = u0; M_COUNTS_( 2 , 1 , 1 , 0 ); CPPUNIT_ASSERT( u1.hasType< T_Counter_ >( ) ); CPPUNIT_ASSERT( u1.target< T_Counter_ >( ) != nullptr ); CPPUNIT_ASSERT_EQUAL( 123 , u1.target< T_Counter_ >( )->value ); } void UnionTest::testCopyConsNoMove( ) { T_Union< T_Counter_ , T_NoMove_ > u0( Construct< T_Counter_ >( ) , 123 ); T_Union< T_Counter_ , T_NoMove_ > u1( u0 ); M_COUNTS_( 1 , 0 , 1 , 0 ); CPPUNIT_ASSERT( u1.hasType< T_Counter_ >( ) ); CPPUNIT_ASSERT( u1.target< T_Counter_ >( ) != nullptr ); CPPUNIT_ASSERT_EQUAL( 123 , u1.target< T_Counter_ >( )->value ); } void UnionTest::testCopyAssNoMove( ) { T_Union< T_Counter_ , T_NoMove_ > u0( Construct< T_Counter_ >( ) , 123 ); T_Union< T_Counter_ , T_NoMove_ > u1( Construct< T_Counter_ >( ) , 456 ); M_COUNTS_( 2 , 0 , 0 , 0 ); u1 = u0; M_COUNTS_( 2 , 1 , 1 , 0 ); CPPUNIT_ASSERT( u1.hasType< T_Counter_ >( ) ); CPPUNIT_ASSERT( u1.target< T_Counter_ >( ) != nullptr ); CPPUNIT_ASSERT_EQUAL( 123 , u1.target< T_Counter_ >( )->value ); } /*----------------------------------------------------------------------------*/ void UnionTest::testMoveContentsCons( ) { T_Counter_ c( 123 ); T_Union< T_Counter_ , uint32_t > u( std::move( c ) ); M_COUNTS_( 1 , 0 , 0 , 1 ); CPPUNIT_ASSERT( u.hasType< T_Counter_ >( ) ); CPPUNIT_ASSERT( u.target< T_Counter_ >( ) != nullptr ); CPPUNIT_ASSERT_EQUAL( 123 , u.target< T_Counter_ >( )->value ); } void UnionTest::testMoveContentsAss( ) { T_Union< T_Counter_ , uint32_t > u( Construct< T_Counter_ >( ) , 456 ); M_COUNTS_( 1 , 0 , 0 , 0 ); u = T_Counter_( 123 ); M_COUNTS_( 2 , 2 , 0 , 1 ); CPPUNIT_ASSERT( u.hasType< T_Counter_ >( ) ); CPPUNIT_ASSERT( u.target< T_Counter_ >( ) != nullptr ); CPPUNIT_ASSERT_EQUAL( 123 , u.target< T_Counter_ >( )->value ); } void UnionTest::testCopyContentsCons( ) { T_Counter_ c( 123 ); T_Union< T_Counter_ , uint32_t > u( c ); M_COUNTS_( 1 , 0 , 1 , 0 ); CPPUNIT_ASSERT( u.hasType< T_Counter_ >( ) ); CPPUNIT_ASSERT( u.target< T_Counter_ >( ) != nullptr ); CPPUNIT_ASSERT_EQUAL( 123 , u.target< T_Counter_ >( )->value ); } void UnionTest::testCopyContentsAss( ) { T_Counter_ c( 123 ); T_Union< T_Counter_ , uint32_t > u( Construct< T_Counter_ >( ) , 456 ); M_COUNTS_( 2 , 0 , 0 , 0 ); u = c; M_COUNTS_( 2 , 1 , 1 , 0 ); CPPUNIT_ASSERT( u.hasType< T_Counter_ >( ) ); CPPUNIT_ASSERT( u.target< T_Counter_ >( ) != nullptr ); CPPUNIT_ASSERT_EQUAL( 123 , u.target< T_Counter_ >( )->value ); } /*----------------------------------------------------------------------------*/ void UnionTest::testSwap( ) { T_Union< T_Counter_ , uint32_t > u0( Construct< T_Counter_ >( ) , 123 ); T_Union< T_Counter_ , uint32_t > u1( Construct< T_Counter_ >( ) , 456 ); M_COUNTS_( 2 , 0 , 0 , 0 ); swap( u0 , u1 ); M_COUNTS_( 2 , 3 , 0 , 3 ); CPPUNIT_ASSERT( u0.hasType< T_Counter_ >( ) ); CPPUNIT_ASSERT( u0.target< T_Counter_ >( ) != nullptr ); CPPUNIT_ASSERT_EQUAL( 456 , u0.target< T_Counter_ >( )->value ); CPPUNIT_ASSERT( u1.hasType< T_Counter_ >( ) ); CPPUNIT_ASSERT( u1.target< T_Counter_ >( ) != nullptr ); CPPUNIT_ASSERT_EQUAL( 123 , u1.target< T_Counter_ >( )->value ); } /*----------------------------------------------------------------------------*/ void UnionTest::testTypeInfo( ) { T_Union< T_DefCons_ , uint32_t > u; CPPUNIT_ASSERT( u.typeInfo( ) == typeid( T_DefCons_ ) ); u = 1u; CPPUNIT_ASSERT( u.typeInfo( ) == typeid( uint32_t ) ); } void UnionTest::testTargetModify( ) { T_Union< T_DefCons_ , uint32_t > u; u.target< T_DefCons_ >( )->x = 987; CPPUNIT_ASSERT( u.hasType< T_DefCons_ >( ) ); CPPUNIT_ASSERT( u.target< T_DefCons_ >( ) != nullptr ); CPPUNIT_ASSERT_EQUAL( 987 , u.target< T_DefCons_ >( )->x ); } /*----------------------------------------------------------------------------*/ void UnionTest::testValue( ) { T_Union< uint32_t , T_DefCons_ > u( 123u ); CPPUNIT_ASSERT( u.hasType< uint32_t >( ) ); CPPUNIT_ASSERT( u.target< uint32_t >( ) != nullptr ); CPPUNIT_ASSERT_EQUAL( 123u , u.value< uint32_t >( ) ); } void UnionTest::testValueModify( ) { T_Union< uint32_t , T_DefCons_ > u( 123u ); CPPUNIT_ASSERT( u.hasType< uint32_t >( ) ); CPPUNIT_ASSERT( u.target< uint32_t >( ) != nullptr ); u.value< uint32_t >( ) = 456; CPPUNIT_ASSERT_EQUAL( 456u , u.value< uint32_t >( ) ); } void UnionTest::testValueException( ) { T_Union< uint32_t , T_DefCons_ > u( T_DefCons_{} ); CPPUNIT_ASSERT( u.hasType< T_DefCons_ >( ) ); try { u.value< uint32_t >( ) = 456u; CPPUNIT_FAIL( "exception not thrown" ); } catch ( std::bad_cast const& ) { // OK } }