rob@76: /* rob@76: oscpack -- Open Sound Control (OSC) packet manipulation library rob@76: http://www.rossbencina.com/code/oscpack rob@76: rob@76: Copyright (c) 2004-2013 Ross Bencina rob@76: rob@76: Permission is hereby granted, free of charge, to any person obtaining rob@76: a copy of this software and associated documentation files rob@76: (the "Software"), to deal in the Software without restriction, rob@76: including without limitation the rights to use, copy, modify, merge, rob@76: publish, distribute, sublicense, and/or sell copies of the Software, rob@76: and to permit persons to whom the Software is furnished to do so, rob@76: subject to the following conditions: rob@76: rob@76: The above copyright notice and this permission notice shall be rob@76: included in all copies or substantial portions of the Software. rob@76: rob@76: THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, rob@76: EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF rob@76: MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. rob@76: IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR rob@76: ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF rob@76: CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION rob@76: WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. rob@76: */ rob@76: rob@76: /* rob@76: The text above constitutes the entire oscpack license; however, rob@76: the oscpack developer(s) also make the following non-binding requests: rob@76: rob@76: Any person wishing to distribute modifications to the Software is rob@76: requested to send the modifications to the original developer so that rob@76: they can be incorporated into the canonical version. It is also rob@76: requested that these non-binding requests be included whenever the rob@76: above license is reproduced. rob@76: */ rob@76: #include "OscUnitTests.h" rob@76: rob@76: #include rob@76: #include rob@76: #include rob@76: rob@76: #include "osc/OscReceivedElements.h" rob@76: #include "osc/OscPrintReceivedElements.h" rob@76: #include "osc/OscOutboundPacketStream.h" rob@76: rob@76: #if defined(__BORLANDC__) // workaround for BCB4 release build intrinsics bug rob@76: namespace std { rob@76: using ::__strcmp__; // avoid error: E2316 '__strcmp__' is not a member of 'std'. rob@76: using ::__strcpy__; // avoid error: E2316 '__strcpy__' is not a member of 'std'. rob@76: } rob@76: #endif rob@76: rob@76: namespace osc{ rob@76: rob@76: static int passCount_=0, failCount_=0; rob@76: rob@76: void PrintTestSummary() rob@76: { rob@76: std::cout << (passCount_+failCount_) << " tests run, " << passCount_ << " passed, " << failCount_ << " failed.\n"; rob@76: } rob@76: rob@76: void pass_equality( const char *slhs, const char *srhs, const char *file, int line ) rob@76: { rob@76: ++passCount_; rob@76: std::cout << file << "(" << line << "): PASSED : " << slhs << " == " << srhs << "\n"; rob@76: } rob@76: rob@76: void fail_equality( const char *slhs, const char *srhs, const char *file, int line ) rob@76: { rob@76: ++failCount_; rob@76: std::cout << file << "(" << line << "): FAILED : " << slhs << " != " << srhs << "\n"; rob@76: } rob@76: rob@76: template rob@76: void assertEqual_( const T& lhs, const T& rhs, const char *slhs, const char *srhs, const char *file, int line ) rob@76: { rob@76: if( lhs == rhs ) rob@76: pass_equality( slhs, srhs, file, line ); rob@76: else rob@76: fail_equality( slhs, srhs, file, line ); rob@76: } rob@76: rob@76: template rob@76: void assertEqual_( const T* lhs, const T* rhs, const char *slhs, const char *srhs, const char *file, int line ) rob@76: { rob@76: if( lhs == rhs ) rob@76: pass_equality( slhs, srhs, file, line ); rob@76: else rob@76: fail_equality( slhs, srhs, file, line ); rob@76: } rob@76: rob@76: template <> rob@76: void assertEqual_( const char* lhs, const char* rhs, const char *slhs, const char *srhs, const char *file, int line ) rob@76: { rob@76: if( std::strcmp( lhs, rhs ) == 0 ) rob@76: pass_equality( slhs, srhs, file, line ); rob@76: else rob@76: fail_equality( slhs, srhs, file, line ); rob@76: } rob@76: rob@76: rob@76: #define assertEqual( a, b ) assertEqual_( (a), (b), #a, #b, __FILE__, __LINE__ ) rob@76: rob@76: //--------------------------------------------------------------------------- rob@76: char * AllocateAligned4( unsigned long size ) rob@76: { rob@76: char *s = new char[ size + 4 ]; //allocate on stack to get 4 byte alignment rob@76: return (char*)((long)(s-1) & (~0x03L)) + 4; rob@76: } rob@76: rob@76: // allocate a 4 byte aligned copy of s rob@76: char * NewMessageBuffer( const char *s, unsigned long length ) rob@76: { rob@76: char *p = AllocateAligned4( length ); rob@76: std::memcpy( p, s, length ); rob@76: return p; rob@76: } rob@76: rob@76: void test1() rob@76: { rob@76: const char s[] = "/test\0\0\0,fiT\0\0\0\0\0\0\0\0\0\0\0A"; rob@76: char *buffer = NewMessageBuffer( s, sizeof(s)-1 ); rob@76: rob@76: // test argument iterator interface rob@76: bool unexpectedExceptionCaught = false; rob@76: try{ rob@76: ReceivedMessage m( ReceivedPacket(buffer, sizeof(s)-1) ); rob@76: rob@76: assertEqual( std::strcmp( m.AddressPattern(), "/test" ), 0 ); rob@76: assertEqual( std::strcmp( m.TypeTags(), "fiT" ), 0 ); rob@76: rob@76: ReceivedMessage::const_iterator i = m.ArgumentsBegin(); rob@76: ++i; rob@76: ++i; rob@76: ++i; rob@76: assertEqual( i, m.ArgumentsEnd() ); rob@76: rob@76: i = m.ArgumentsBegin(); rob@76: float f = (i++)->AsFloat(); rob@76: (void)f; rob@76: int n = (i++)->AsInt32(); rob@76: (void)n; rob@76: bool b = (i++)->AsBool(); rob@76: (void)b; rob@76: rob@76: i = m.ArgumentsBegin(); rob@76: bool exceptionThrown = false; rob@76: try{ rob@76: int n = (i++)->AsInt32(); rob@76: (void)n; rob@76: }catch( Exception& ){ rob@76: exceptionThrown = true; rob@76: } rob@76: assertEqual( exceptionThrown, true ); rob@76: rob@76: }catch( Exception& e ){ rob@76: std::cout << "unexpected exception: " << e.what() << "\n"; rob@76: unexpectedExceptionCaught = true; rob@76: } rob@76: assertEqual( unexpectedExceptionCaught, false ); rob@76: rob@76: rob@76: // test argument stream interface rob@76: unexpectedExceptionCaught = false; rob@76: try{ rob@76: ReceivedMessage m( ReceivedPacket(buffer, sizeof(s)-1) ); rob@76: ReceivedMessageArgumentStream args = m.ArgumentStream(); rob@76: assertEqual( args.Eos(), false ); rob@76: rob@76: float f; rob@76: int32 n; rob@76: bool b; rob@76: args >> f >> n >> b; rob@76: rob@76: (void) f; rob@76: (void) n; rob@76: (void) b; rob@76: rob@76: assertEqual( args.Eos(), true ); rob@76: rob@76: }catch( Exception& e ){ rob@76: std::cout << "unexpected exception: " << e.what() << "\n"; rob@76: unexpectedExceptionCaught = true; rob@76: } rob@76: assertEqual( unexpectedExceptionCaught, false ); rob@76: } rob@76: rob@76: //--------------------------------------------------------------------------- rob@76: rob@76: rob@76: #define TEST2_PRINT( ss )\ rob@76: {\ rob@76: const char s[] = ss;\ rob@76: ReceivedPacket p( NewMessageBuffer( s, sizeof(s)-1 ), sizeof(s)-1 ); \ rob@76: ReceivedMessage m( p );\ rob@76: std::cout << m << "\n";\ rob@76: } rob@76: rob@76: void test2() rob@76: { rob@76: bool unexpectedExceptionCaught = false; rob@76: try{ rob@76: // 012301230 1 2 3 rob@76: TEST2_PRINT( "/no_args\0\0\0\0" ); rob@76: rob@76: // 012301230 1 2 3 01 2 3 rob@76: TEST2_PRINT( "/no_args\0\0\0\0,\0\0\0" ); rob@76: rob@76: // 01230123 012 3 0 1 2 3 rob@76: TEST2_PRINT( "/an_int\0,i\0\0\0\0\0A" ); rob@76: // 012301230 1 2 3 012 3 0 1 2 3 rob@76: TEST2_PRINT( "/a_float\0\0\0\0,f\0\0\0\0\0\0" ); rob@76: // 0123012301 2 3 012 3 012301230123 rob@76: TEST2_PRINT( "/a_string\0\0\0,s\0\0hello world\0" ); rob@76: // 01230123 012 3 0 1 2 3 0 1 2 3 rob@76: TEST2_PRINT( "/a_blob\0,b\0\0\0\0\0\x4\x0\x1\x2\x3" ); rob@76: rob@76: // 0123012301 2 3 012 3 0 1 2 3 0 1 2 3 rob@76: TEST2_PRINT( "/an_int64\0\0\0,h\0\0\0\0\0\0\0\0\0\x1" ); rob@76: // 01230123012 3 012 3 0 1 2 3 0 1 2 3 rob@76: TEST2_PRINT( "/a_timetag\0\0,t\0\0\0\0\0\0\0\0\0\x1" ); rob@76: // 0123012301 2 3 012 3 0 1 2 3 0 1 2 3 rob@76: TEST2_PRINT( "/a_double\0\0\0,d\0\0\0\0\0\0\0\0\0\0" ); rob@76: // 0123012301 2 3 012 3 012301230123 rob@76: TEST2_PRINT( "/a_symbol\0\0\0,S\0\0hello world\0" ); rob@76: // 01230123 012 3 0 1 2 3 rob@76: TEST2_PRINT( "/a_char\0,c\0\0\0\0\0A" ); rob@76: // 012301230 1 2 3 012 3 0 1 2 3 rob@76: TEST2_PRINT( "/a_color\0\0\0\0,r\0\0\0\0\0\0" ); rob@76: // 012301230123012 3 012 3 0 1 2 3 rob@76: TEST2_PRINT( "/a_midimessage\0\0,m\0\0\0\0\0\0" ); rob@76: // 01230123 012 3 rob@76: TEST2_PRINT( "/a_bool\0,T\0\0" ); rob@76: // 01230123 012 3 rob@76: TEST2_PRINT( "/a_bool\0,F\0\0" ); rob@76: // 01230 1 2 3 012 3 rob@76: TEST2_PRINT( "/Nil\0\0\0\0,N\0\0" ); rob@76: // 01230 1 2 3 012 3 rob@76: TEST2_PRINT( "/Inf\0\0\0\0,I\0\0" ); rob@76: // 0123012 3 0123012 3 0 1 2 3 0 1 2 3 0 1 2 3 rob@76: TEST2_PRINT( "/Array\0\0,[iii]\0\0\0\0\0\x1\0\0\0\x2\0\0\0\x3" ); rob@76: rob@76: TEST2_PRINT( "/test\0\0\0,fiT\0\0\0\0\0\0\0\0\0\0\0A" ); rob@76: rob@76: bool exceptionThrown = false; rob@76: try{ rob@76: TEST2_PRINT( "/a_char\0,x\0\0\0\0\0A" ); // unknown type tag 'x' rob@76: }catch( Exception& ){ rob@76: exceptionThrown = true; rob@76: } rob@76: assertEqual( exceptionThrown, true ); rob@76: rob@76: }catch( Exception& e ){ rob@76: std::cout << "unexpected exception: " << e.what() << "\n"; rob@76: unexpectedExceptionCaught = true; rob@76: } rob@76: assertEqual( unexpectedExceptionCaught, false ); rob@76: } rob@76: rob@76: //----------------------------------------------------------------------- rob@76: rob@76: // pack a message and then unpack it and check that the result is the same rob@76: // also print each message rob@76: // repeat the process inside a bundle rob@76: rob@76: #define TEST_PACK_UNPACK0( addressPattern, argument, value, recieveGetter ) \ rob@76: { \ rob@76: std::memset( buffer, 0x74, bufferSize ); \ rob@76: OutboundPacketStream ps( buffer, bufferSize ); \ rob@76: ps << BeginMessage( addressPattern ) \ rob@76: << argument \ rob@76: << EndMessage;\ rob@76: assertEqual( ps.IsReady(), true );\ rob@76: ReceivedMessage m( ReceivedPacket(ps.Data(), ps.Size()) );\ rob@76: std::cout << m << "\n";\ rob@76: assertEqual( m.ArgumentsBegin()-> recieveGetter () , value );\ rob@76: } \ rob@76: { \ rob@76: std::memset( buffer, 0x74, bufferSize ); \ rob@76: OutboundPacketStream ps( buffer, bufferSize ); \ rob@76: ps << BeginBundle( 1234 ) \ rob@76: << BeginMessage( addressPattern ) \ rob@76: << argument \ rob@76: << EndMessage \ rob@76: << EndBundle;\ rob@76: assertEqual( ps.IsReady(), true );\ rob@76: ReceivedBundle b( ReceivedPacket(ps.Data(), ps.Size()) );\ rob@76: ReceivedMessage m( *b.ElementsBegin() );\ rob@76: std::cout << m << "\n";\ rob@76: assertEqual( m.ArgumentsBegin()-> recieveGetter () , value );\ rob@76: } rob@76: rob@76: #define TEST_PACK_UNPACK( addressPattern, argument, type, recieveGetter ) \ rob@76: { \ rob@76: std::memset( buffer, 0x74, bufferSize ); \ rob@76: OutboundPacketStream ps( buffer, bufferSize ); \ rob@76: ps << BeginMessage( addressPattern ) \ rob@76: << argument \ rob@76: << EndMessage;\ rob@76: assertEqual( ps.IsReady(), true );\ rob@76: ReceivedMessage m( ReceivedPacket(ps.Data(), ps.Size()) );\ rob@76: std::cout << m << "\n";\ rob@76: assertEqual( m.ArgumentsBegin()-> recieveGetter () , ( type ) argument );\ rob@76: } \ rob@76: { \ rob@76: std::memset( buffer, 0x74, bufferSize ); \ rob@76: OutboundPacketStream ps( buffer, bufferSize ); \ rob@76: ps << BeginBundle( 1234 ) \ rob@76: << BeginMessage( addressPattern ) \ rob@76: << argument \ rob@76: << EndMessage \ rob@76: << EndBundle;\ rob@76: assertEqual( ps.IsReady(), true );\ rob@76: ReceivedBundle b( ReceivedPacket(ps.Data(), ps.Size()) );\ rob@76: ReceivedMessage m( *b.ElementsBegin() );\ rob@76: std::cout << m << "\n";\ rob@76: assertEqual( m.ArgumentsBegin()-> recieveGetter () , ( type ) argument );\ rob@76: } rob@76: rob@76: void test3() rob@76: { rob@76: int bufferSize = 1000; rob@76: char *buffer = AllocateAligned4( bufferSize ); rob@76: rob@76: // single message tests rob@76: // empty message rob@76: { rob@76: std::memset( buffer, 0x74, bufferSize ); rob@76: OutboundPacketStream ps( buffer, bufferSize ); rob@76: ps << BeginMessage( "/no_arguments" ) rob@76: << EndMessage; rob@76: assertEqual( ps.IsReady(), true ); rob@76: ReceivedMessage m( ReceivedPacket(ps.Data(), ps.Size()) ); rob@76: std::cout << m << "\n";\ rob@76: } rob@76: rob@76: TEST_PACK_UNPACK( "/a_bool", true, bool, AsBool ); rob@76: TEST_PACK_UNPACK( "/a_bool", false, bool, AsBool ); rob@76: TEST_PACK_UNPACK( "/a_bool", (bool)1, bool, AsBool ); rob@76: rob@76: rob@76: #ifndef _OBJC_OBJC_H_ rob@76: TEST_PACK_UNPACK0( "/nil", Nil, true, IsNil ); rob@76: #endif rob@76: TEST_PACK_UNPACK0( "/nil", OscNil, true, IsNil ); rob@76: TEST_PACK_UNPACK0( "/inf", Infinitum, true, IsInfinitum ); rob@76: rob@76: TEST_PACK_UNPACK( "/an_int", (int32)1234, int32, AsInt32 ); rob@76: rob@76: TEST_PACK_UNPACK( "/a_float", 3.1415926f, float, AsFloat ); rob@76: rob@76: TEST_PACK_UNPACK( "/a_char", 'c', char, AsChar ); rob@76: rob@76: TEST_PACK_UNPACK( "/an_rgba_color", RgbaColor(0x22334455), uint32, AsRgbaColor ); rob@76: rob@76: TEST_PACK_UNPACK( "/a_midi_message", MidiMessage(0x7F), uint32, AsMidiMessage ); rob@76: rob@76: TEST_PACK_UNPACK( "/an_int64", (int64)(0xFFFFFFFF), int64, AsInt64 ); rob@76: rob@76: TEST_PACK_UNPACK( "/a_time_tag", TimeTag(0xFFFFFFFF), uint64, AsTimeTag ); rob@76: rob@76: TEST_PACK_UNPACK( "/a_double", (double)3.1415926, double, AsDouble ); rob@76: rob@76: // blob rob@76: { rob@76: char blobData[] = "abcd"; rob@76: std::memset( buffer, 0x74, bufferSize ); rob@76: OutboundPacketStream ps( buffer, bufferSize ); rob@76: ps << BeginMessage( "/a_blob" ) rob@76: << Blob( blobData, 4 ) rob@76: << EndMessage; rob@76: assertEqual( ps.IsReady(), true ); rob@76: ReceivedMessage m( ReceivedPacket(ps.Data(), ps.Size()) ); rob@76: std::cout << m << "\n"; rob@76: rob@76: const void *value; rob@76: osc_bundle_element_size_t size; rob@76: m.ArgumentsBegin()->AsBlob( value, size ); rob@76: assertEqual( size, (osc_bundle_element_size_t)4 ); rob@76: assertEqual( (memcmp( value, blobData, 4 ) == 0), true ); rob@76: } rob@76: rob@76: // array rob@76: { rob@76: int32 arrayData[] = {1,2,3,4}; rob@76: const std::size_t sourceArrayItemCount = 4; rob@76: std::memset( buffer, 0x74, bufferSize ); rob@76: OutboundPacketStream ps( buffer, bufferSize ); rob@76: ps << BeginMessage( "/an_array" ) rob@76: << BeginArray; rob@76: for( std::size_t j=0; j < sourceArrayItemCount; ++j ) rob@76: ps << arrayData[j]; rob@76: ps << EndArray << EndMessage; rob@76: assertEqual( ps.IsReady(), true ); rob@76: ReceivedMessage m( ReceivedPacket(ps.Data(), ps.Size()) ); rob@76: std::cout << m << "\n"; rob@76: rob@76: ReceivedMessageArgumentIterator i = m.ArgumentsBegin(); rob@76: assertEqual( i->IsArrayBegin(), true ); rob@76: assertEqual( i->ComputeArrayItemCount(), sourceArrayItemCount ); rob@76: std::size_t arrayItemCount = i->ComputeArrayItemCount(); rob@76: ++i; // move past array begin marker rob@76: for( std::size_t j=0; j < arrayItemCount; ++j ){ rob@76: assertEqual( true, i->IsInt32() ); rob@76: int32 k = i->AsInt32(); rob@76: assertEqual( k, arrayData[j] ); rob@76: ++i; rob@76: } rob@76: rob@76: assertEqual( i->IsArrayEnd(), true ); rob@76: } rob@76: rob@76: rob@76: rob@76: TEST_PACK_UNPACK( "/a_string", "hello world", const char*, AsString ); rob@76: rob@76: TEST_PACK_UNPACK( "/a_symbol", Symbol("foobar"), const char*, AsSymbol ); rob@76: rob@76: rob@76: // nested bundles, and multiple messages in bundles... rob@76: rob@76: { rob@76: std::memset( buffer, 0x74, bufferSize ); rob@76: OutboundPacketStream ps( buffer, bufferSize ); rob@76: ps << BeginBundle() rob@76: << BeginMessage( "/message_one" ) << 1 << 2 << 3 << 4 << EndMessage rob@76: << BeginMessage( "/message_two" ) << 1 << 2 << 3 << 4 << EndMessage rob@76: << BeginMessage( "/message_three" ) << 1 << 2 << 3 << 4 << EndMessage rob@76: << BeginMessage( "/message_four" ) << 1 << 2 << 3 << 4 << EndMessage rob@76: << EndBundle; rob@76: assertEqual( ps.IsReady(), true ); rob@76: ReceivedBundle b( ReceivedPacket(ps.Data(), ps.Size()) ); rob@76: std::cout << b << "\n"; rob@76: } rob@76: } rob@76: rob@76: rob@76: void RunUnitTests() rob@76: { rob@76: test1(); rob@76: test2(); rob@76: test3(); rob@76: PrintTestSummary(); rob@76: } rob@76: rob@76: } // namespace osc rob@76: rob@76: rob@76: #ifndef NO_OSC_TEST_MAIN rob@76: rob@76: int main(int argc, char* argv[]) rob@76: { rob@76: (void)argc; rob@76: (void)argv; rob@76: rob@76: osc::RunUnitTests(); rob@76: } rob@76: rob@76: #endif