|
From: <rus...@us...> - 2008-03-19 00:16:17
|
Revision: 103
http://gearbox.svn.sourceforge.net/gearbox/?rev=103&view=rev
Author: russo2503v
Date: 2008-03-18 17:16:15 -0700 (Tue, 18 Mar 2008)
Log Message:
-----------
added ctests and a few related classes
Modified Paths:
--------------
gearbox/trunk/cmake/internal/Setup.cmake
gearbox/trunk/cmake/internal/SetupDirectories.cmake
gearbox/trunk/cmake/internal/WriteConfigH.cmake
gearbox/trunk/src/gbxsickacfr/gbxiceutilacfr/CMakeLists.txt
gearbox/trunk/src/gbxsickacfr/gbxutilacfr/CMakeLists.txt
gearbox/trunk/src/gbxsickacfr/sickdefines.cpp
gearbox/trunk/src/gbxsickacfr/sickdefines.h
Added Paths:
-----------
gearbox/trunk/src/gbxsickacfr/gbxiceutilacfr/notify.h
gearbox/trunk/src/gbxsickacfr/gbxiceutilacfr/safethread.cpp
gearbox/trunk/src/gbxsickacfr/gbxiceutilacfr/safethread.h
gearbox/trunk/src/gbxsickacfr/gbxiceutilacfr/store.h
gearbox/trunk/src/gbxsickacfr/gbxiceutilacfr/test/
gearbox/trunk/src/gbxsickacfr/gbxiceutilacfr/test/CMakeLists.txt
gearbox/trunk/src/gbxsickacfr/gbxiceutilacfr/test/buffertest.cpp
gearbox/trunk/src/gbxsickacfr/gbxiceutilacfr/test/notifytest.cpp
gearbox/trunk/src/gbxsickacfr/gbxiceutilacfr/test/safethreadtest.cpp
gearbox/trunk/src/gbxsickacfr/gbxiceutilacfr/test/storetest.cpp
gearbox/trunk/src/gbxsickacfr/gbxiceutilacfr/test/subsystemthreadtest.cpp
gearbox/trunk/src/gbxsickacfr/gbxiceutilacfr/test/threadtest.cpp
gearbox/trunk/src/gbxsickacfr/gbxutilacfr/test/
gearbox/trunk/src/gbxsickacfr/gbxutilacfr/test/CMakeLists.txt
gearbox/trunk/src/gbxsickacfr/gbxutilacfr/test/mathtest.cpp
Modified: gearbox/trunk/cmake/internal/Setup.cmake
===================================================================
--- gearbox/trunk/cmake/internal/Setup.cmake 2008-03-18 06:43:26 UTC (rev 102)
+++ gearbox/trunk/cmake/internal/Setup.cmake 2008-03-19 00:16:15 UTC (rev 103)
@@ -6,7 +6,7 @@
-SET( GBX_CMAKE_DIR ${${PROJECT_NAME}_SOURCE_DIR}/cmake CACHE PATH "Location of CMake scripts" )
+SET( GBX_CMAKE_DIR ${${PROJECT_NAME}_SOURCE_DIR}/cmake CACHE INTERNAL "Location of CMake scripts" )
#
# Process version number
@@ -14,7 +14,7 @@
INCLUDE( ${GBX_CMAKE_DIR}/internal/SetupVersion.cmake )
#
-# Project directories
+# Project directories, including installation
#
INCLUDE( ${GBX_CMAKE_DIR}/internal/SetupDirectories.cmake )
Modified: gearbox/trunk/cmake/internal/SetupDirectories.cmake
===================================================================
--- gearbox/trunk/cmake/internal/SetupDirectories.cmake 2008-03-18 06:43:26 UTC (rev 102)
+++ gearbox/trunk/cmake/internal/SetupDirectories.cmake 2008-03-19 00:16:15 UTC (rev 103)
@@ -1,12 +1,33 @@
#
-# Default installation directory is OS-dependent.
+# This CMake variable may be provided by the user on the command line
+# e.g. $ cmake -DGEARBOX_INSTALL=/home/user .
#
-IF ( NOT GBX_OS_WIN )
- SET( CMAKE_INSTALL_PREFIX /usr/local CACHE PATH "Installation directory" )
-ELSE ( NOT GBX_OS_WIN )
- SET( CMAKE_INSTALL_PREFIX "C:\Program Files\Gearbox\Include" CACHE PATH "Installation directory" )
-ENDIF ( NOT GBX_OS_WIN )
+IF( CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT )
+ IF( DEFINED GEARBOX_INSTALL )
+
+ MESSAGE( STATUS GEARBOX_INSTALL=${GEARBOX_INSTALL} )
+
+ # using user-supplied installation directory
+ # SET( CMAKE_INSTALL_PREFIX ${GEARBOX_INSTALL} )
+ SET( CMAKE_INSTALL_PREFIX ${GEARBOX_INSTALL} CACHE PATH "Installation directory" FORCE )
+
+ MESSAGE( STATUS CMAKE_INSTALL_PREFIX=${CMAKE_INSTALL_PREFIX} )
+
+ ELSE( DEFINED GEARBOX_INSTALL )
+ #
+ # Default installation directory is OS-dependent.
+ #
+ IF ( NOT GBX_OS_WIN )
+ SET( CMAKE_INSTALL_PREFIX /usr/local CACHE PATH "Installation directory" FORCE )
+ ELSE ( NOT GBX_OS_WIN )
+ SET( CMAKE_INSTALL_PREFIX "C:\Program Files\Gearbox\Include" CACHE PATH "Installation directory" FORCE )
+ ENDIF ( NOT GBX_OS_WIN )
+
+ ENDIF( DEFINED GEARBOX_INSTALL )
+
+ENDIF( CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT )
+
MESSAGE( STATUS "Setting installation directory to ${CMAKE_INSTALL_PREFIX}" )
#
Modified: gearbox/trunk/cmake/internal/WriteConfigH.cmake
===================================================================
--- gearbox/trunk/cmake/internal/WriteConfigH.cmake 2008-03-18 06:43:26 UTC (rev 102)
+++ gearbox/trunk/cmake/internal/WriteConfigH.cmake 2008-03-19 00:16:15 UTC (rev 103)
@@ -14,7 +14,7 @@
MESSAGE( STATUS "Not writing config.h -- wrote it previously" )
ELSE ( WROTE_CONFIG_H )
MESSAGE( STATUS "Writing config.h" )
- SET( WROTE_CONFIG_H TRUE CACHE BOOL "Wrote config.h" )
+ SET( WROTE_CONFIG_H TRUE CACHE INTERNAL "Wrote config.h" )
FILE( WRITE ${CONFIG_H} "/* config.h. Generated by CMakeLists.txt */\n\n" )
Modified: gearbox/trunk/src/gbxsickacfr/gbxiceutilacfr/CMakeLists.txt
===================================================================
--- gearbox/trunk/src/gbxsickacfr/gbxiceutilacfr/CMakeLists.txt 2008-03-18 06:43:26 UTC (rev 102)
+++ gearbox/trunk/src/gbxsickacfr/gbxiceutilacfr/CMakeLists.txt 2008-03-19 00:16:15 UTC (rev 103)
@@ -33,8 +33,8 @@
GBX_ADD_HEADERS( gbxsickacfr/gbxiceutilacfr ${hdrs} )
-# IF ( GBX_BUILD_TESTS )
-# ADD_SUBDIRECTORY ( test )
-# ENDIF ( GBX_BUILD_TESTS )
+ IF ( GBX_BUILD_TESTS )
+ ADD_SUBDIRECTORY ( test )
+ ENDIF ( GBX_BUILD_TESTS )
ENDIF ( build )
Added: gearbox/trunk/src/gbxsickacfr/gbxiceutilacfr/notify.h
===================================================================
--- gearbox/trunk/src/gbxsickacfr/gbxiceutilacfr/notify.h (rev 0)
+++ gearbox/trunk/src/gbxsickacfr/gbxiceutilacfr/notify.h 2008-03-19 00:16:15 UTC (rev 103)
@@ -0,0 +1,114 @@
+/*
+ * GearBox Project: Peer-Reviewed Open-Source Libraries for Robotics
+ * http://gearbox.sf.net/
+ * Copyright (c) 2004-2008 Alex Brooks, Alexei Makarenko, Tobias Kaupp
+ *
+ * This distribution is licensed to you under the terms described in
+ * the LICENSE file included in this distribution.
+ *
+ */
+
+#ifndef GBXICEUTILACFR_NOTIFY_H
+#define GBXICEUTILACFR_NOTIFY_H
+
+#include <gbxsickacfr/gbxutilacfr/exceptions.h>
+#include <iostream>
+
+//
+// note: this class can be libGbxUtilAcfr but we keep it with the other "data pattern"
+// classes: Store and Buffer.
+//
+namespace gbxsickacfr {
+namespace gbxiceutilacfr {
+
+/*!
+ * @brief The object which implements the callback function.
+ *
+ * Derive from this class and implement the callback function NotifyHandler::handleData and
+ * register it with Notify by calline Notify::setNotifyHandler.
+ */
+template<class Type>
+class NotifyHandler
+{
+public:
+ virtual ~NotifyHandler() {};
+ //!
+ //! This function must be implemented by the component developer.
+ //!
+ virtual void handleData( const Type & obj )=0;
+};
+
+/*!
+ * @brief A data pipe with callback semantics.
+ *
+ * Write new data with Notify::set. The data is delivered to the data handler by
+ * calling NotifyHandler::handleData in the registered NotifyHandler.
+ *
+ * @see Buffer, Proxy
+ */
+template<class Type>
+class Notify
+{
+public:
+ Notify()
+ : hasNotifyHandler_(false)
+ {};
+
+ virtual ~Notify() {};
+
+ //! Sets internal link to the notify handler. If the provided pointer is NULL,
+ //! the internal link is quietly not set.
+ void setNotifyHandler( NotifyHandler<Type>* handler );
+
+ //! Returns TRUE is the notify handler has been set and FALSE otherwise.
+ bool hasNotifyHandler() { return hasNotifyHandler_; };
+
+ //! Forwards the @p obj to the data handler.
+ //! Raises gbxsickacfr::gbxutilacfr::Exception if the function is called when a notify handler has
+ //! not been set.
+ void set( const Type & obj );
+
+protected:
+ //! Reimplement this function for non-standard types.
+ virtual void internalSet( const Type & obj );
+
+ //! Interface to the object which is notified of incoming data.
+ NotifyHandler<Type>* handler_;
+
+private:
+
+ bool hasNotifyHandler_;
+};
+
+template<class Type>
+void Notify<Type>::setNotifyHandler( NotifyHandler<Type>* handler )
+{
+ if ( handler == 0 ) {
+ std::cout<<"TRACE(notify.h): no handler set. Ignoring data." << std::endl;
+ return;
+ }
+
+ handler_ = handler;
+ hasNotifyHandler_ = true;
+}
+
+template<class Type>
+void Notify<Type>::set( const Type & obj )
+{
+ if ( !hasNotifyHandler_ ) {
+ throw gbxsickacfr::gbxutilacfr::Exception( ERROR_INFO, "setting data when data handler has not been set" );
+ }
+
+ internalSet( obj );
+}
+
+template<class Type>
+void Notify<Type>::internalSet( const Type & obj )
+{
+ handler_->handleData( obj );
+}
+
+}
+} // end namespace
+
+#endif
Added: gearbox/trunk/src/gbxsickacfr/gbxiceutilacfr/safethread.cpp
===================================================================
--- gearbox/trunk/src/gbxsickacfr/gbxiceutilacfr/safethread.cpp (rev 0)
+++ gearbox/trunk/src/gbxsickacfr/gbxiceutilacfr/safethread.cpp 2008-03-19 00:16:15 UTC (rev 103)
@@ -0,0 +1,59 @@
+/*
+ * GearBox Project: Peer-Reviewed Open-Source Libraries for Robotics
+ * http://gearbox.sf.net/
+ * Copyright (c) 2004-2008 Alex Brooks, Alexei Makarenko, Tobias Kaupp
+ *
+ * This distribution is licensed to you under the terms described in
+ * the LICENSE file included in this distribution.
+ *
+ */
+
+#include <iostream>
+#include <sstream>
+
+#include "safethread.h"
+
+using namespace gbxsickacfr::gbxiceutilacfr;
+using namespace std;
+
+
+SafeThread::SafeThread( gbxsickacfr::gbxutilacfr::Tracer& tracer ) :
+ tracer_(tracer)
+{
+}
+
+void
+SafeThread::run()
+{
+ stringstream ss;
+ try
+ {
+ walk();
+ }
+ catch ( const IceUtil::Exception &e ) {
+ ss << "SafeThread::run(): Caught unexpected exception: " << e;
+ }
+ catch ( const std::exception &e ) {
+ ss << "SafeThread::run(): Caught unexpected exception: " << e.what();
+ }
+ catch ( const std::string &e ) {
+ ss << "SafeThread::run(): Caught unexpected string: " << e;
+ }
+ catch ( const char *e ) {
+ ss << "SafeThread::run(): Caught unexpected char *: " << e;
+ }
+ catch ( ... ) {
+ ss << "SafeThread::run(): Caught unexpected unknown exception.";
+ }
+
+ // only if there were exceptions
+ if ( !ss.str().empty() ) {
+ tracer_.error( ss.str() );
+ }
+ else {
+ tracer_.debug( "dropping out from run()", 4 );
+ }
+
+ // wait for the component to realize that we are quitting and tell us to stop.
+ waitForStop();
+}
Added: gearbox/trunk/src/gbxsickacfr/gbxiceutilacfr/safethread.h
===================================================================
--- gearbox/trunk/src/gbxsickacfr/gbxiceutilacfr/safethread.h (rev 0)
+++ gearbox/trunk/src/gbxsickacfr/gbxiceutilacfr/safethread.h 2008-03-19 00:16:15 UTC (rev 103)
@@ -0,0 +1,68 @@
+/*
+ * GearBox Project: Peer-Reviewed Open-Source Libraries for Robotics
+ * http://gearbox.sf.net/
+ * Copyright (c) 2004-2008 Alex Brooks, Alexei Makarenko, Tobias Kaupp
+ *
+ * This distribution is licensed to you under the terms described in
+ * the LICENSE file included in this distribution.
+ *
+ */
+
+#ifndef GBXICEUTILACFR_SAFE_THREAD_H
+#define GBXICEUTILACFR_SAFE_THREAD_H
+
+#include <gbxsickacfr/gbxiceutilacfr/thread.h>
+#include <gbxsickacfr/gbxutilacfr/tracer.h>
+
+namespace gbxsickacfr {
+namespace gbxiceutilacfr {
+
+/*!
+@brief A version of the Thread class which catches all possible exceptions.
+
+If a stray exception is caught, an error message will be printed
+(using cout), then we will wait for someone to call stop().
+
+To use this class, simply implement the pure virtual walk() function.
+@verbatim
+void MyThread::walk()
+{
+ // initialize
+
+ // main loop
+ while ( !isStopping() )
+ {
+ // do something
+ }
+
+ // clean up
+}
+@endverbatim
+
+@see Thread, SubsystemThread.
+ */
+class SafeThread : public Thread
+{
+public:
+ //! Needs an implementation of Tracer to report possible exceptions.
+ SafeThread( gbxsickacfr::gbxutilacfr::Tracer& tracer );
+
+ // from IceUtil::Thread (from which HydroUtil::Thread is derived)
+ //! This implementation calls walk(), catches all possible exceptions, prints out
+ //! errors and waits for someone to call stop().
+ virtual void run();
+
+ //! Implement this function in the derived class and put here all the stuff which your
+ //! thread needs to do.
+ virtual void walk()=0;
+
+private:
+ gbxsickacfr::gbxutilacfr::Tracer& tracer_;
+};
+//! A smart pointer to the SafeThread class.
+typedef IceUtil::Handle<SafeThread> SafeThreadPtr;
+
+}
+} // end namespace
+
+#endif
Added: gearbox/trunk/src/gbxsickacfr/gbxiceutilacfr/store.h
===================================================================
--- gearbox/trunk/src/gbxsickacfr/gbxiceutilacfr/store.h (rev 0)
+++ gearbox/trunk/src/gbxsickacfr/gbxiceutilacfr/store.h 2008-03-19 00:16:15 UTC (rev 103)
@@ -0,0 +1,246 @@
+/*
+ * GearBox Project: Peer-Reviewed Open-Source Libraries for Robotics
+ * http://gearbox.sf.net/
+ * Copyright (c) 2004-2008 Alex Brooks, Alexei Makarenko, Tobias Kaupp
+ *
+ * This distribution is licensed to you under the terms described in
+ * the LICENSE file included in this distribution.
+ *
+ */
+
+#ifndef GBXICEUTILACFR_STORE_H
+#define GBXICEUTILACFR_STORE_H
+
+#include <gbxsickacfr/gbxutilacfr/exceptions.h>
+
+#include <IceUtil/Monitor.h>
+#include <IceUtil/Mutex.h>
+#include <IceUtil/Time.h>
+
+namespace gbxsickacfr {
+namespace gbxiceutilacfr {
+
+/*!
+ * @brief Thread-safe storage for a single data objects.
+ *
+ * This container is similar to a circular Buffer of size one but with two
+ * differences:
+ * - a copy of the data is always available, yet the user knows when new
+ * data has arrived by calling @ref isNewData
+ * - @ref getNext returns the new data arrives (not when the buffer
+ * is non-empty.
+ *
+ * Write to it with @ref set. Read its contents with @ref get. Trying to read from
+ * an empty Store raises an gbxsickacfr::gbxutilacfr::Exception.
+ *
+ * @note Replaces the deprecated Proxy class.
+ * @see Buffer, Notify
+ */
+template<class Type>
+class Store : public IceUtil::Monitor<IceUtil::Mutex>
+{
+public:
+
+ Store();
+ virtual ~Store();
+
+ //! Returns TRUE if there's something in the Store. The Store starts its life empty
+ //! but after the object is set once, it will be non-empty again until @ref purge is
+ //! called.
+ bool isEmpty() const;
+
+ //! Returns TRUE if the data in the Store has not been accessed with @ref get yet.
+ bool isNewData() const;
+
+ //! Sets the contents of the Store.
+ void set( const Type & obj );
+
+ //! Returns the contents of the Store. This operation makes the data in the Store
+ //! "not new", i.e. @ref isNewData returns FALSE. Calls to @ref get when the Store is empty
+ //! raises an gbxsickacfr::gbxutilacfr::Exception exception.
+ void get( Type & obj ) const;
+
+ /*!
+ * @brief Waits until the next update and returns the new value.
+ * If the Store is empty, @ref getNext blocks until the Store is set and returns the new value.
+ * By default, there is no timeout (negative value). Returns 0 if successful.
+ *
+ * If timeout is set to a positive value (in milliseconds) and the wait times out, the function returns -1
+ * and the object argument itself is not touched. In the rare event of spurious wakeup,
+ * the return value is 1.
+ *
+ */
+ int getNext( Type & obj, int timeoutMs=-1 ) const;
+
+ //! Makes the Store empty.
+ //! @see isEmpty
+ void purge();
+
+protected:
+
+ // local copy of the object
+ Type obj_;
+
+ // Reimplement this function for non-standard types.
+ virtual void internalGet( Type & obj ) const ;
+
+ // Reimplement this function for non-standard types.
+ virtual void internalSet( const Type & obj );
+
+private:
+
+
+ bool isEmpty_;
+
+ // flag to keep track of new data. Make it mutable so that get() functions can be const.
+ mutable bool isNewData_;
+
+ // internal implementation of front( obj, -1 ); returns 0.
+ int getNextNoWait( Type & obj ) const;
+
+};
+
+
+//////////////////////////////////////////////////////////////////////
+
+template<class Type>
+Store<Type>::Store()
+ : isEmpty_(true),
+ isNewData_(false)
+{
+}
+
+template<class Type>
+Store<Type>::~Store()
+{
+}
+
+template<class Type>
+bool Store<Type>::isEmpty() const
+{
+ IceUtil::Monitor<IceUtil::Mutex>::Lock lock(*this);
+ return isEmpty_;
+}
+
+template<class Type>
+bool Store<Type>::isNewData() const
+{
+ IceUtil::Monitor<IceUtil::Mutex>::Lock lock(*this);
+ return isNewData_;
+}
+
+template<class Type>
+void Store<Type>::get( Type & obj ) const
+{
+ IceUtil::Monitor<IceUtil::Mutex>::Lock lock(*this);
+ if ( !isEmpty_ )
+ {
+ internalGet( obj );
+ isNewData_ = false;
+ }
+ else
+ {
+ throw gbxsickacfr::gbxutilacfr::Exception( ERROR_INFO, "trying to read from an empty Store." );
+ }
+}
+
+template<class Type>
+int Store<Type>::getNext( Type & obj, int timeoutMs ) const
+{
+ // special case: infinite wait time
+ if ( timeoutMs == -1 ) {
+ return getNextNoWait( obj );
+ }
+
+ // finite wait time
+ IceUtil::Monitor<IceUtil::Mutex>::Lock lock(*this);
+
+ // if already have data in the buffer, return it and get out
+ if ( isNewData_ )
+ {
+ internalGet( obj );
+ isNewData_ = false;
+ return 0;
+ }
+
+ // empty buffer: figure out when to wake up
+ // notice that we are still holding the lock, so it's ok to call timedWait()
+ if ( this->timedWait( IceUtil::Time::milliSeconds( timeoutMs ) ) )
+ {
+ // someone woke us up, we are holding the lock again
+ // check new data again (could be a spurious wakeup)
+ if ( isNewData_ )
+ {
+ internalGet( obj );
+ isNewData_ = false;
+ return 0;
+ }
+ else {
+ // spurious wakup, don't wait again, just return
+ return 1;
+ }
+ }
+ else {
+ // wait timedout, nobody woke us up
+ return -1;
+ }
+}
+
+template<class Type>
+int Store<Type>::getNextNoWait( Type & obj ) const
+{
+ IceUtil::Monitor<IceUtil::Mutex>::Lock lock(*this);
+
+ // check the condition before and after waiting to deal with spurious wakeups
+ // (see Ice manual sec. 28.9.2)
+ while ( !isNewData_ )
+ {
+ this->wait();
+ }
+
+ internalGet( obj );
+ isNewData_ = false;
+ return 0;
+}
+
+// NOTE: see notes on efficient notification in Ice sec. 28.9.3
+template<class Type>
+void Store<Type>::set( const Type &obj )
+{
+ IceUtil::Monitor<IceUtil::Mutex>::Lock lock(*this);
+
+ internalSet( obj );
+
+ // mark as having new data (nobody has looked at it yet)
+ isNewData_ = true;
+
+ // mark Store non-empty (only usefull the very first time)
+ isEmpty_ = false;
+
+ // wakeup someone who's waiting for an update
+ this->notify();
+}
+
+template<class Type>
+void Store<Type>::purge()
+{
+ IceUtil::Monitor<IceUtil::Mutex>::Lock lock(*this);
+ isEmpty_ = true;
+}
+
+template<class Type>
+void Store<Type>::internalGet( Type & obj ) const
+{
+ obj = obj_;
+}
+
+template<class Type>
+void Store<Type>::internalSet( const Type & obj )
+{
+ obj_ = obj;
+}
+
+}
+} // end namespace
+
+#endif
Added: gearbox/trunk/src/gbxsickacfr/gbxiceutilacfr/test/CMakeLists.txt
===================================================================
--- gearbox/trunk/src/gbxsickacfr/gbxiceutilacfr/test/CMakeLists.txt (rev 0)
+++ gearbox/trunk/src/gbxsickacfr/gbxiceutilacfr/test/CMakeLists.txt 2008-03-19 00:16:15 UTC (rev 103)
@@ -0,0 +1,21 @@
+# INCLUDE( ${HYDRO_CMAKE_DIR}/UseBasicRules.cmake )
+# INCLUDE( ${CMAKE_CURRENT_SOURCE_DIR}/../UseHydroIceUtil.cmake )
+LINK_LIBRARIES( GbxIceUtilAcfr )
+
+ADD_EXECUTABLE( buffertest buffertest.cpp )
+GBX_ADD_TEST( GbxIceUtilAcfrBufferTest buffertest )
+
+ADD_EXECUTABLE( storetest storetest.cpp )
+GBX_ADD_TEST( GbxIceUtilAcfrStoreTest storetest )
+
+ADD_EXECUTABLE( notifytest notifytest.cpp )
+GBX_ADD_TEST( GbxIceUtilAcfrNotifyTest notifytest )
+
+ADD_EXECUTABLE( threadtest threadtest.cpp )
+GBX_ADD_TEST( GbxIceUtilAcfrThreadTest threadtest )
+
+ADD_EXECUTABLE( safethreadtest safethreadtest.cpp )
+GBX_ADD_TEST( GbxIceUtilAcfrSafeThreadTest safethreadtest )
+
+ADD_EXECUTABLE( subsystemthreadtest subsystemthreadtest.cpp )
+GBX_ADD_TEST( GbxIceUtilAcfrSubsystemThreadTest subsystemthreadtest )
Added: gearbox/trunk/src/gbxsickacfr/gbxiceutilacfr/test/buffertest.cpp
===================================================================
--- gearbox/trunk/src/gbxsickacfr/gbxiceutilacfr/test/buffertest.cpp (rev 0)
+++ gearbox/trunk/src/gbxsickacfr/gbxiceutilacfr/test/buffertest.cpp 2008-03-19 00:16:15 UTC (rev 103)
@@ -0,0 +1,218 @@
+/*
+ * GearBox Project: Peer-Reviewed Open-Source Libraries for Robotics
+ * http://gearbox.sf.net/
+ * Copyright (c) 2004-2008 Alex Brooks, Alexei Makarenko, Tobias Kaupp
+ *
+ * This distribution is licensed to you under the terms described in
+ * the LICENSE file included in this distribution.
+ *
+ */
+
+#include <iostream>
+#include <cstdlib>
+#include <gbxsickacfr/gbxiceutilacfr/buffer.h>
+
+using namespace std;
+
+int main(int argc, char * argv[])
+{
+ gbxsickacfr::gbxiceutilacfr::Buffer<double> buffer(-1, gbxsickacfr::gbxiceutilacfr::BufferTypeCircular);
+ double data = 20.0;
+ double copy = -1.0;
+
+ cout<<"testing default constructor and depth() and type() ... ";
+ if ( buffer.depth()!=-1 || buffer.type()!=gbxsickacfr::gbxiceutilacfr::BufferTypeCircular ) {
+ cout<<"failed. depth: exp=-1 got="<<buffer.depth()<<" type: exp="<<(int)gbxsickacfr::gbxiceutilacfr::BufferTypeCircular<<" got="<<(int)buffer.type()<<endl;
+ return EXIT_FAILURE;
+ }
+ cout<<"ok"<<endl;
+
+ cout<<"testing get() with empty buffer ... ";
+ // call get on an empty stomach
+ try
+ {
+ buffer.get( copy );
+ cout<<"failed. empty buffer, should've caught exception"<<endl;
+ return EXIT_FAILURE;
+ }
+ catch ( const gbxsickacfr::gbxutilacfr::Exception & )
+ {
+ ; // ok
+ }
+ cout<<"ok"<<endl;
+
+ cout<<"testing getAndPop() with empty buffer ... ";
+ try
+ {
+ buffer.getAndPop( data );
+ cout<<"failed. empty buffer, should've caught exception"<<endl;
+ return EXIT_FAILURE;
+ }
+ catch ( const gbxsickacfr::gbxutilacfr::Exception & )
+ {
+ ; // ok
+ }
+ cout<<"ok"<<endl;
+
+ cout<<"testing getNext() with empty buffer ... ";
+ if ( buffer.getNext( data, 50 )==0 ) {
+ cout<<"failed. not expecting anybody setting the buffer"<<endl;
+ return EXIT_FAILURE;
+ }
+ cout<<"ok"<<endl;
+
+ cout<<"testing getAndPopNext() with empty buffer ... ";
+ if ( buffer.getAndPopNext( data, 50 )==0 ) {
+ cout<<"failed. not expecting anybody setting the proxy"<<endl;
+ return EXIT_FAILURE;
+ }
+ cout<<"ok"<<endl;
+
+ cout<<"testing isEmpty() and size() with empty buffer ... ";
+ if ( !buffer.isEmpty() || buffer.size()!=0 ) {
+ cout<<"failed. expecting an empty buffer."<<endl;
+ return EXIT_FAILURE;
+ }
+ cout<<"ok"<<endl;
+
+ cout<<"testing push() ... ";
+ for ( int i=0; i<3; ++i ) {
+ buffer.push( data );
+ }
+ cout<<"ok"<<endl;
+
+ cout<<"testing isEmpty() and size() ... ";
+ if ( buffer.isEmpty() || buffer.size()!=3 ) {
+ cout<<"failed on line "<<__LINE__<<": expecting an empty buffer of size 3."<<endl;
+ cout<<"TRACE(buffertest.cpp): buffer.size(): " << buffer.size() << endl;
+
+ return EXIT_FAILURE;
+ }
+ cout<<"ok"<<endl;
+
+ cout<<"testing get() ... ";
+ try
+ {
+ buffer.get( copy );
+ }
+ catch ( const gbxsickacfr::gbxutilacfr::Exception & )
+ {
+ cout<<"failed. should be a non-empty buffer."<<endl;
+ return EXIT_FAILURE;
+ }
+ if ( data!=copy )
+ {
+ cout<<"failed. expecting an exact copy of the data."<<endl;
+ cout<<"\tin="<<data<<" out="<<copy<<endl;
+ return EXIT_FAILURE;
+ }
+ if ( buffer.isEmpty() || buffer.size()!=3 ) {
+ cout<<"failed on line "<<__LINE__<<": expecting an empty buffer of size 3."<<endl;
+ return EXIT_FAILURE;
+ }
+ cout<<"ok, size="<<buffer.size()<<endl;
+
+ cout<<"testing getAndPop()... ";
+ try
+ {
+ int size = buffer.size();
+ for ( int i=0; i < size; i++ )
+ buffer.getAndPop( data );
+ }
+ catch ( const gbxsickacfr::gbxutilacfr::Exception & )
+ {
+ cout<<"failed. should be a non-empty buffer."<<endl;
+ return EXIT_FAILURE;
+ }
+ if ( !buffer.isEmpty() || buffer.size()!=0 ) {
+ cout<<"failed. expecting an empty buffer."<<endl;
+ return EXIT_FAILURE;
+ }
+ cout<<"ok"<<endl;
+
+ cout<<"testing circular buffer behavior ...";
+ buffer.configure( 1, gbxsickacfr::gbxiceutilacfr::BufferTypeCircular );
+ //this fills the buffer
+ buffer.push( 0 );
+ // this should over-write
+ buffer.push( 1 );
+ buffer.get( data );
+ if ( data != 1 ) {
+ cout<<"failed. second push should overwrite: expected=1, got="<<data<<endl;
+ return EXIT_FAILURE;
+ }
+ cout<<"ok"<<endl;
+
+ cout<<"testing queue buffer behavior ...";
+ buffer.configure( 1, gbxsickacfr::gbxiceutilacfr::BufferTypeQueue );
+ //this fills the buffer
+ buffer.push( 0 );
+ // this should be ignored
+ buffer.push( 1 );
+ buffer.get( data );
+ if ( data != 0 ) {
+ cout<<"failed. second push should not overwrite: expected=0, got="<<data<<endl;
+ return EXIT_FAILURE;
+ }
+ cout<<"ok"<<endl;
+
+ cout<<"testing configure() with gbxsickacfr::gbxiceutilacfr::BufferTypeCircular ... ";
+ buffer.configure( 300, gbxsickacfr::gbxiceutilacfr::BufferTypeCircular );
+ for ( int i=0; i<400; ++i ) {
+ buffer.push( data );
+ }
+ if ( buffer.isEmpty() || buffer.size()!=300 ) {
+ cout<<"failed. expecting a buffer of size 300."<<endl;
+ return EXIT_FAILURE;
+ }
+ // todo: test where the last data actually went.
+ cout<<"ok"<<endl;
+
+ cout<<"testing purge()... ";
+ buffer.purge();
+ if ( !buffer.isEmpty() || buffer.size()!=0 ) {
+ cout<<"failed. expecting an empty buffer."<<endl;
+ return EXIT_FAILURE;
+ }
+ cout<<"ok"<<endl;
+
+ cout<<"testing configure() with gbxsickacfr::gbxiceutilacfr::BufferTypeQueue ... ";
+ buffer.configure( 300, gbxsickacfr::gbxiceutilacfr::BufferTypeQueue );
+ for ( int i=0; i<400; ++i ) {
+ buffer.push( data );
+ }
+ if ( buffer.isEmpty() || buffer.size()!=300 ) {
+ cout<<"failed. expecting a buffer of size 300."<<endl;
+ return EXIT_FAILURE;
+ }
+ // todo: test where the last data actually went.
+ cout<<"ok"<<endl;
+
+ cout<<"testing getNext() ... ";
+ if ( buffer.getNext( data, 50 )!=0 ) {
+ cout<<"failed. expected to get data"<<endl;
+ return EXIT_FAILURE;
+ }
+ cout<<"ok"<<endl;
+
+ cout<<"testing getAndPopNext() ... ";
+ if ( buffer.getAndPopNext( data, 50 )!=0 ) {
+ cout<<"failed. expected to get data"<<endl;
+ return EXIT_FAILURE;
+ }
+ cout<<"ok"<<endl;
+
+ cout<<"testing pop() ... ";
+ for ( int i=0; i<400; ++i ) {
+ buffer.pop();
+ }
+ if ( !buffer.isEmpty() || buffer.size()!=0 ) {
+ cout<<"failed. expecting an empty buffer."<<endl;
+ return EXIT_FAILURE;
+ }
+ // todo: test where the last data actually went.
+ cout<<"ok"<<endl;
+
+
+ return EXIT_SUCCESS;
+}
Added: gearbox/trunk/src/gbxsickacfr/gbxiceutilacfr/test/notifytest.cpp
===================================================================
--- gearbox/trunk/src/gbxsickacfr/gbxiceutilacfr/test/notifytest.cpp (rev 0)
+++ gearbox/trunk/src/gbxsickacfr/gbxiceutilacfr/test/notifytest.cpp 2008-03-19 00:16:15 UTC (rev 103)
@@ -0,0 +1,88 @@
+/*
+ * GearBox Project: Peer-Reviewed Open-Source Libraries for Robotics
+ * http://gearbox.sf.net/
+ * Copyright (c) 2004-2008 Alex Brooks, Alexei Makarenko, Tobias Kaupp
+ *
+ * This distribution is licensed to you under the terms described in
+ * the LICENSE file included in this distribution.
+ *
+ */
+
+#include <iostream>
+#include <cstdlib>
+#include <gbxsickacfr/gbxiceutilacfr/notify.h>
+
+using namespace std;
+
+class TestNotifyHandler : public gbxsickacfr::gbxiceutilacfr::NotifyHandler<double>
+{
+public:
+ virtual void handleData( const double& obj )
+ {
+ copy_=obj;
+ };
+
+ double copy_;
+};
+
+int main(int argc, char * argv[])
+{
+ gbxsickacfr::gbxiceutilacfr::Notify<double> notify;
+ double data = 2.0;
+
+ gbxsickacfr::gbxiceutilacfr::NotifyHandler<double>* emptyHandler = 0;
+ TestNotifyHandler testHandler;
+
+ cout<<"testing set() ... ";
+ // call set on an empty stomach
+ try
+ {
+ notify.set( data );
+ cout<<"failed. empty notify handler, should've caught exception"<<endl;
+ return EXIT_FAILURE;
+ }
+ catch ( const gbxsickacfr::gbxutilacfr::Exception & )
+ {
+ ; // ok
+ }
+ cout<<"ok"<<endl;
+
+ cout<<"testing hasNotifyHandler() ... ";
+ if ( notify.hasNotifyHandler()!=0 ) {
+ cout<<"failed. not expecting to have a handler"<<endl;
+ return EXIT_FAILURE;
+ }
+ notify.setNotifyHandler( emptyHandler );
+ if ( notify.hasNotifyHandler()!=0 ) {
+ cout<<"failed. still not expecting to have a handler"<<endl;
+ return EXIT_FAILURE;
+ }
+ cout<<"ok"<<endl;
+
+ cout<<"testing setNotifyHandler() ... ";
+ notify.setNotifyHandler( &testHandler );
+ if ( notify.hasNotifyHandler()==0 ) {
+ cout<<"failed. expecting to have a handler"<<endl;
+ return EXIT_FAILURE;
+ }
+ cout<<"ok"<<endl;
+
+ cout<<"testing set() ... ";
+ try
+ {
+ notify.set( data );
+ }
+ catch ( const gbxsickacfr::gbxutilacfr::Exception & )
+ {
+ cout<<"failed. shouldn't have caught exception"<<endl;
+ return EXIT_FAILURE;
+ }
+ if ( data != testHandler.copy_ ) {
+ cout<<"failed. expecting an exact copy of the data."<<endl;
+ cout<<"\tin="<<data<<" out="<<testHandler.copy_<<endl;
+ return EXIT_FAILURE;
+ }
+ cout<<"ok"<<endl;
+
+ return EXIT_SUCCESS;
+}
Added: gearbox/trunk/src/gbxsickacfr/gbxiceutilacfr/test/safethreadtest.cpp
===================================================================
--- gearbox/trunk/src/gbxsickacfr/gbxiceutilacfr/test/safethreadtest.cpp (rev 0)
+++ gearbox/trunk/src/gbxsickacfr/gbxiceutilacfr/test/safethreadtest.cpp 2008-03-19 00:16:15 UTC (rev 103)
@@ -0,0 +1,91 @@
+/*
+ * GearBox Project: Peer-Reviewed Open-Source Libraries for Robotics
+ * http://gearbox.sf.net/
+ * Copyright (c) 2004-2008 Alex Brooks, Alexei Makarenko, Tobias Kaupp
+ *
+ * This distribution is licensed to you under the terms described in
+ * the LICENSE file included in this distribution.
+ *
+ */
+
+#include <iostream>
+
+#include <IceUtil/Time.h>
+
+#include <gbxsickacfr/gbxiceutilacfr/safethread.h>
+#include <gbxsickacfr/gbxutilacfr/trivialtracer.h>
+
+using namespace std;
+
+class TestThread : public gbxsickacfr::gbxiceutilacfr::SafeThread
+{
+public:
+ // it's safe to pass zero pointers
+ TestThread( gbxsickacfr::gbxutilacfr::Tracer& tracer ) :
+ SafeThread( tracer ) {};
+ virtual void walk()
+ {
+ while ( !isStopping() ) {
+ IceUtil::ThreadControl::sleep(IceUtil::Time::milliSeconds(50));
+ }
+ };
+};
+
+class TestThreadWithThrow : public gbxsickacfr::gbxiceutilacfr::SafeThread
+{
+public:
+ // it's safe to pass zero pointers
+ TestThreadWithThrow( gbxsickacfr::gbxutilacfr::Tracer& tracer ) :
+ SafeThread( tracer ) {};
+ virtual void walk()
+ {
+ throw "throwing from walk";
+ };
+};
+
+int main(int argc, char * argv[])
+{
+ gbxsickacfr::gbxutilacfr::TrivialTracer tracer;
+
+ cout<<"testing start() and stop()... ";
+ {
+ gbxsickacfr::gbxiceutilacfr::Thread* t=0;
+ try
+ {
+ t = new TestThread( tracer );
+ t->start();
+ }
+ catch (...)
+ {
+ cout<<"failed"<<endl<<"should be able to create thread"<<endl;
+ exit(EXIT_FAILURE);
+ }
+ IceUtil::ThreadControl tc = t->getThreadControl();
+ t->stop();
+ tc.join();
+ // do not delete t! it's already self-destructed.
+ }
+ cout<<"ok"<<endl;
+
+ cout<<"testing SafeThread() with exceptions... ";
+ {
+ gbxsickacfr::gbxiceutilacfr::Thread* t=0;
+ try
+ {
+ t = new TestThreadWithThrow( tracer );
+ t->start();
+ }
+ catch (...)
+ {
+ cout<<"failed"<<endl<<"all exception should've been caught."<<endl;
+ // ok
+ }
+ IceUtil::ThreadControl tc = t->getThreadControl();
+ t->stop();
+ tc.join();
+ // do not delete t! it's already self-destructed.
+ }
+ cout<<"ok"<<endl;
+
+ return EXIT_SUCCESS;
+}
Added: gearbox/trunk/src/gbxsickacfr/gbxiceutilacfr/test/storetest.cpp
===================================================================
--- gearbox/trunk/src/gbxsickacfr/gbxiceutilacfr/test/storetest.cpp (rev 0)
+++ gearbox/trunk/src/gbxsickacfr/gbxiceutilacfr/test/storetest.cpp 2008-03-19 00:16:15 UTC (rev 103)
@@ -0,0 +1,101 @@
+/*
+ * GearBox Project: Peer-Reviewed Open-Source Libraries for Robotics
+ * http://gearbox.sf.net/
+ * Copyright (c) 2004-2008 Alex Brooks, Alexei Makarenko, Tobias Kaupp
+ *
+ * This distribution is licensed to you under the terms described in
+ * the LICENSE file included in this distribution.
+ *
+ */
+
+#include <iostream>
+#include <cstdlib>
+#include <gbxsickacfr/gbxiceutilacfr/store.h>
+
+using namespace std;
+
+int main(int argc, char * argv[])
+{
+ gbxsickacfr::gbxiceutilacfr::Store<double> store;
+ double data = 20.0;
+ double copy = -1.0;
+
+ cout<<"testing get() ... ";
+ // call get on an empty stomach
+ try
+ {
+ store.get( data );
+ cout<<"failed. empty store, should've caught exception"<<endl;
+ return EXIT_FAILURE;
+ }
+ catch ( const gbxsickacfr::gbxutilacfr::Exception & )
+ {
+ ; // ok
+ }
+ cout<<"ok"<<endl;
+
+ cout<<"testing getNext() ... ";
+ if ( store.getNext( data, 50 )==0 ) {
+ cout<<"failed. not expecting anybody setting the store"<<endl;
+ return EXIT_FAILURE;
+ }
+ cout<<"ok"<<endl;
+
+ cout<<"testing isEmpty() and isNewData() ... ";
+ if ( !store.isEmpty() || store.isNewData() ) {
+ cout<<"failed. expecting an empty non-new store."<<endl;
+ return EXIT_FAILURE;
+ }
+ cout<<"ok"<<endl;
+
+ cout<<"testing set() ... ";
+ for ( int i=0; i<3; ++i ) {
+ store.set( data );
+ }
+ if ( store.isEmpty() || !store.isNewData() ) {
+ cout<<"failed. expecting a non-empty new store."<<endl;
+ return EXIT_FAILURE;
+ }
+ cout<<"ok"<<endl;
+
+ cout<<"testing get() ... ";
+ try
+ {
+ store.get( copy );
+ }
+ catch ( const gbxsickacfr::gbxutilacfr::Exception & )
+ {
+ cout<<"failed. should be a non-empty store."<<endl;
+ return EXIT_FAILURE;
+ }
+ if ( data!=copy )
+ {
+ cout<<"failed. expecting an exact copy of the data."<<endl;
+ cout<<"\tin="<<data<<" out="<<copy<<endl;
+ return EXIT_FAILURE;
+ }
+ if ( store.isEmpty() || store.isNewData() ) {
+ cout<<"failed. expecting a non-empty non-new store."<<endl;
+ return EXIT_FAILURE;
+ }
+ cout<<"ok"<<endl;
+
+ cout<<"testing getNext() ... ";
+ store.set( data );
+ if ( store.getNext( data, 50 )!=0 ) {
+ cout<<"failed. expected to get data"<<endl;
+ return EXIT_FAILURE;
+ }
+ cout<<"ok"<<endl;
+
+ cout<<"testing purge()... ";
+ store.purge();
+ if ( !store.isEmpty() || store.isNewData() ) {
+ cout<<"failed. expecting an empty non-new store."<<endl;
+ return EXIT_FAILURE;
+ }
+ cout<<"ok"<<endl;
+
+
+ return EXIT_SUCCESS;
+}
Added: gearbox/trunk/src/gbxsickacfr/gbxiceutilacfr/test/subsystemthreadtest.cpp
===================================================================
--- gearbox/trunk/src/gbxsickacfr/gbxiceutilacfr/test/subsystemthreadtest.cpp (rev 0)
+++ gearbox/trunk/src/gbxsickacfr/gbxiceutilacfr/test/subsystemthreadtest.cpp 2008-03-19 00:16:15 UTC (rev 103)
@@ -0,0 +1,106 @@
+/*
+ * GearBox Project: Peer-Reviewed Open-Source Libraries for Robotics
+ * http://gearbox.sf.net/
+ * Copyright (c) 2004-2008 Alex Brooks, Alexei Makarenko, Tobias Kaupp
+ *
+ * This distribution is licensed to you under the terms described in
+ * the LICENSE file included in this distribution.
+ *
+ */
+
+#include <iostream>
+
+#include <IceUtil/Time.h>
+
+#include <gbxsickacfr/gbxiceutilacfr/subsystemthread.h>
+#include <gbxsickacfr/gbxutilacfr/trivialtracer.h>
+#include <gbxsickacfr/gbxutilacfr/trivialstatus.h>
+
+using namespace std;
+
+class TestThread : public gbxsickacfr::gbxiceutilacfr::SubsystemThread
+{
+public:
+ // it's safe to pass zero pointers
+ TestThread( gbxsickacfr::gbxutilacfr::Tracer& tracer, gbxsickacfr::gbxutilacfr::Status& status ) :
+ SubsystemThread( tracer, status ) {};
+ virtual void walk()
+ {
+ while ( !isStopping() ) {
+ IceUtil::ThreadControl::sleep(IceUtil::Time::milliSeconds(50));
+ }
+ };
+};
+
+class TestThreadWithThrow : public gbxsickacfr::gbxiceutilacfr::SubsystemThread
+{
+public:
+ // it's safe to pass zero pointers
+ TestThreadWithThrow( gbxsickacfr::gbxutilacfr::Tracer& tracer, gbxsickacfr::gbxutilacfr::Status& status ) :
+ SubsystemThread( tracer, status ) {};
+ virtual void walk()
+ {
+ throw "throwing from walk";
+ };
+};
+
+class TestThreadWithTools : public gbxsickacfr::gbxiceutilacfr::SubsystemThread
+{
+public:
+ TestThreadWithTools( gbxsickacfr::gbxutilacfr::Tracer& tracer, gbxsickacfr::gbxutilacfr::Status& status ) :
+ SubsystemThread( tracer, status, "MyName" )
+ {
+ };
+ virtual void walk()
+ {
+ throw "throwing from walk";
+ };
+};
+
+int main(int argc, char * argv[])
+{
+ gbxsickacfr::gbxutilacfr::TrivialTracer tracer;
+ gbxsickacfr::gbxutilacfr::TrivialStatus status( tracer );
+
+ cout<<"testing start() and stop()... ";
+ {
+ gbxsickacfr::gbxiceutilacfr::Thread* t=0;
+ try
+ {
+ t = new TestThread( tracer, status );
+ t->start();
+ }
+ catch (...)
+ {
+ cout<<"failed"<<endl<<"should be able to create thread"<<endl;
+ exit(EXIT_FAILURE);
+ }
+ IceUtil::ThreadControl tc = t->getThreadControl();
+ t->stop();
+ tc.join();
+ // do not delete t! it's already self-destructed.
+ }
+ cout<<"ok"<<endl;
+
+ cout<<"testing SubsystemThread() with exceptions... ";
+ {
+ gbxsickacfr::gbxiceutilacfr::Thread* t=0;
+ try
+ {
+ t = new TestThreadWithThrow( tracer, status );
+ t->start();
+ }
+ catch (...)
+ {
+ cout<<"failed"<<endl<<"all exception should've been caught."<<endl;
+ // ok
+ }
+ IceUtil::ThreadControl tc = t->getThreadControl();
+ t->stop();
+ tc.join();
+ // do not delete t! it's already self-destructed.
+ }
+ cout<<"ok"<<endl;
+
+ return EXIT_SUCCESS;
+}
Added: gearbox/trunk/src/gbxsickacfr/gbxiceutilacfr/test/threadtest.cpp
===================================================================
--- gearbox/trunk/src/gbxsickacfr/gbxiceutilacfr/test/threadtest.cpp (rev 0)
+++ gearbox/trunk/src/gbxsickacfr/gbxiceutilacfr/test/threadtest.cpp 2008-03-19 00:16:15 UTC (rev 103)
@@ -0,0 +1,277 @@
+/*
+ * GearBox Project: Peer-Reviewed Open-Source Libraries for Robotics
+ * http://gearbox.sf.net/
+ * Copyright (c) 2004-2008 Alex Brooks, Alexei Makarenko, Tobias Kaupp
+ *
+ * This distribution is licensed to you under the terms described in
+ * the LICENSE file included in this distribution.
+ *
+ */
+
+#include <iostream>
+
+#include <IceUtil/Time.h>
+
+#include <gbxsickacfr/gbxiceutilacfr/thread.h>
+#include <gbxsickacfr/gbxutilacfr/exceptions.h>
+
+using namespace std;
+
+class TestThread : public gbxsickacfr::gbxiceutilacfr::Thread
+{
+public:
+ virtual void run()
+ {
+ while ( !isStopping() ) {
+ IceUtil::ThreadControl::sleep(IceUtil::Time::milliSeconds(50));
+ }
+ };
+};
+
+class TestThreadWithThrow : public gbxsickacfr::gbxiceutilacfr::Thread
+{
+public:
+ TestThreadWithThrow( bool shouldIThrow )
+ {
+ if ( shouldIThrow ) {
+ throw "throwing from constructor";
+ }
+ };
+
+ virtual void run()
+ {
+ while ( !isStopping() ) {
+ IceUtil::ThreadControl::sleep(IceUtil::Time::milliSeconds(50));
+ }
+ };
+};
+
+class TestThreadWithExit : public gbxsickacfr::gbxiceutilacfr::Thread
+{
+public:
+ TestThreadWithExit() :
+ isExiting_(false) {};
+
+ void exit()
+ {
+ IceUtil::Mutex::Lock lock(exitMutex_);
+ isExiting_ = true;
+ };
+
+ bool isExiting()
+ {
+ IceUtil::Mutex::Lock lock(exitMutex_);
+ return isExiting_;
+ };
+
+ virtual void run()
+ {
+ // this is the standard loop
+ while ( !isStopping() ) {
+ IceUtil::ThreadControl::sleep(IceUtil::Time::milliSeconds(50));
+ }
+
+ // this is a special loop for testing only
+ while ( !isExiting_ ) {
+ IceUtil::ThreadControl::sleep(IceUtil::Time::milliSeconds(50));
+ }
+ };
+
+private:
+ bool isExiting_;
+ IceUtil::Mutex exitMutex_;
+};
+
+class TestThreadWithWait : public gbxsickacfr::gbxiceutilacfr::Thread
+{
+public:
+ virtual void run()
+ {
+ waitForStop();
+ };
+};
+
+class TestThreadWithNap : public gbxsickacfr::gbxiceutilacfr::Thread
+{
+public:
+ virtual void run()
+ {
+ gbxsickacfr::gbxiceutilacfr::checkedSleep( this, IceUtil::Time::seconds(5), 100 );
+ };
+};
+
+int main(int argc, char * argv[])
+{
+ cout<<"testing start() and stop()... ";
+ {
+ gbxsickacfr::gbxiceutilacfr::Thread* t=0;
+ try
+ {
+ t = new TestThread;
+ t->start();
+ }
+ catch (...)
+ {
+ cout<<"failed"<<endl<<"should be able to create thread"<<endl;
+ exit(EXIT_FAILURE);
+ }
+ IceUtil::ThreadControl tc = t->getThreadControl();
+ t->stop();
+ tc.join();
+ // do not delete t! it's already self-destructed.
+ }
+ cout<<"ok"<<endl;
+
+ cout<<"testing start() and stop() with smart pointer ... ";
+ {
+ gbxsickacfr::gbxiceutilacfr::ThreadPtr t;
+ try
+ {
+ t = new TestThread;
+ t->start();
+ }
+ catch (...)
+ {
+ cout<<"failed"<<endl<<"should be able to create thread"<<endl;
+ exit(EXIT_FAILURE);
+ }
+ IceUtil::ThreadControl tc = t->getThreadControl();
+ t->stop();
+ tc.join();
+ }
+ cout<<"ok"<<endl;
+
+ // alexm: is this test still needed?
+ cout<<"testing Thread() with exceptions... ";
+ {
+ TestThreadWithThrow* t=0;
+ try
+ {
+ t = new TestThreadWithThrow( true );
+ cout<<"failed"<<endl<<"should not be able to create thread"<<endl;
+ exit(EXIT_FAILURE);
+ }
+ catch (...)
+ {
+ // ok
+ }
+ }
+ cout<<"ok"<<endl;
+
+ cout<<"testing state machine ... ";
+ {
+ // works only with smart pointers because with dumb ones the threads self-destruct
+ // and we can't examine their final state.
+ gbxsickacfr::gbxiceutilacfr::ThreadPtr t = new TestThreadWithExit;
+
+ if ( t->isStopping()!=false || t->isAlive()!=false || t->isStarted()!=false ) {
+ cout<<"failed"<<endl
+ <<"should be in Starting state but internal states do not match:"<<endl
+ <<"isStopping="<<(int)t->isStopping()<<" isAlive="<<(int)t->isAlive()<<" isStarted()="<<(int)t->isStarted()<<endl;
+ exit(EXIT_FAILURE);
+ }
+
+ t->start();
+ if ( t->isStopping()!=false || t->isAlive()!=true || t->isStarted()!=true ) {
+ cout<<"failed"<<endl
+ <<"should be in Started state but internal states do not match:"<<endl
+ <<"isStopping="<<(int)t->isStopping()<<" isAlive="<<(int)t->isAlive()<<" isStarted()="<<(int)t->isStarted()<<endl;
+ exit(EXIT_FAILURE);
+ }
+
+ t->stop();
+ if ( t->isStopping()!=true || t->isAlive()!=true || t->isStarted()!=true ) {
+ cout<<"failed"<<endl
+ <<"should be in Stopping state but internal states do not match:"<<endl
+ <<"isStopping="<<(int)t->isStopping()<<" isAlive="<<(int)t->isAlive()<<" isStarted()="<<(int)t->isStarted()<<endl;
+ exit(EXIT_FAILURE);
+ }
+
+ IceUtil::ThreadControl tc = t->getThreadControl();
+ // this ugly shit is to call one special function
+ TestThreadWithExit* dumb = (TestThreadWithExit*)&(*t);
+ dumb->exit();
+ IceUtil::ThreadControl::sleep(IceUtil::Time::milliSeconds(150));
+ // alexm: I think it self-destructs here. what can we tell about it?
+ if ( t->isStopping()!=true || t->isAlive()!=false || t->isStarted()!=true ) {
+ cout<<"failed"<<endl
+ <<"should be in Stopped state but internal states do not match:"<<endl
+ <<"isStopping="<<(int)t->isStopping()<<" isAlive="<<(int)t->isAlive()<<" isStarted()="<<(int)t->isStarted()<<endl;
+ exit(EXIT_FAILURE);
+ }
+ tc.join();
+ }
+ cout<<"ok"<<endl;
+
+ cout<<"testing waitForStop() ... ";
+ {
+ gbxsickacfr::gbxiceutilacfr::ThreadPtr t = new TestThreadWithWait;
+ t->start();
+ if ( t->isAlive()!=true ) {
+ cout<<"failed"<<endl
+ <<"should be in Started state but internal states do not match:"<<endl
+ <<"isStopping="<<(int)t->isStopping()<<" isAlive="<<(int)t->isAlive()<<" isStarted()="<<(int)t->isStarted()<<endl;
+ exit(EXIT_FAILURE);
+ }
+
+ t->stop();
+ IceUtil::ThreadControl tc = t->getThreadControl();
+ IceUtil::ThreadControl::sleep(IceUtil::Time::milliSeconds(150));
+ if ( t->isAlive()!=false ) {
+ cout<<"failed"<<endl
+ <<"should be in Stopped state but internal states do not match:"<<endl
+ <<"isStopping="<<(int)t->isStopping()<<" isAlive="<<(int)t->isAlive()<<" isStarted()="<<(int)t->isStarted()<<endl;
+ exit(EXIT_FAILURE);
+ }
+ tc.join();
+ }
+ cout<<"ok"<<endl;
+
+ // alexm: don't know how to test this, because of self-destruction
+// cout<<"testing stopAndJoin() ... ";
+// {
+// }
+// cout<<"ok"<<endl;
+
+ cout<<"testing stopAndJoin() with smart pointer ... ";
+ {
+ gbxsickacfr::gbxiceutilacfr::ThreadPtr t = new TestThread;
+ t->start();
+ if ( t->isAlive()!=true ) {
+ cout<<"failed"<<endl
+ <<"should be in Started state but internal states do not match:"<<endl
+ <<"isStopping="<<(int)t->isStopping()<<" isAlive="<<(int)t->isAlive()<<" isStarted()="<<(int)t->isStarted()<<endl;
+ exit(EXIT_FAILURE);
+ }
+
+ gbxsickacfr::gbxiceutilacfr::stopAndJoin( t );
+ IceUtil::ThreadControl::sleep(IceUtil::Time::milliSeconds(150));
+ if ( t->isAlive()!=false ) {
+ cout<<"failed"<<endl
+ <<"should be in Stopped state but internal states do not match:"<<endl
+ <<"isStopping="<<(int)t->isStopping()<<" isAlive="<<(int)t->isAlive()<<" isStarted()="<<(int)t->isStarted()<<endl;
+ exit(EXIT_FAILURE);
+ }
+ }
+ cout<<"ok"<<endl;
+
+ cout<<"testing checkedSleep() ... ";
+ {
+ gbxsickacfr::gbxiceutilacfr::ThreadPtr t = new TestThreadWithNap;
+ t->start();
+
+ IceUtil::Time stopTime = IceUtil::Time::now();
+ gbxsickacfr::gbxiceutilacfr::stopAndJoin( t );
+ IceUtil::Time joinTime = IceUtil::Time::now();
+ cout<<"time to stop = "<<(joinTime-stopTime).toDuration()<<endl;
+
+ if ( joinTime-stopTime > IceUtil::Time::seconds(1) ) {
+ cout<<"failed"<<endl
+ <<"should stop faster than in 1 second, time to stop ="<<(joinTime-stopTime).toDuration()<<endl;
+ exit(EXIT_FAILURE);
+ }
+ }
+ cout<<"ok"<<endl;
+
+ return EXIT_SUCCESS;
+}
Modified: gearbox/trunk/src/gbxsickacfr/gbxutilacfr/CMakeLists.txt
===================================================================
--- gearbox/trunk/src/gbxsickacfr/gbxutilacfr/CMakeLists.txt 2008-03-18 06:43:26 UTC (rev 102)
+++ gearbox/trunk/src/gbxsickacfr/gbxutilacfr/CMakeLists.txt 2008-03-19 00:16:15 UTC (rev 103)
@@ -19,8 +19,8 @@
GBX_ADD_HEADERS( gbxsickacfr/gbxutilacfr ${hdrs} )
-# IF ( GBX_BUILD_TESTS )
-# ADD_SUBDIRECTORY ( test )
-# ENDIF ( GBX_BUILD_TESTS )
+ IF ( GBX_BUILD_TESTS )
+ ADD_SUBDIRECTORY ( test )
+ ENDIF ( GBX_BUILD_TESTS )
ENDIF ( build )
Added: gearbox/trunk/src/gbxsickacfr/gbxutilacfr/test/CMakeLists.txt
===================================================================
--- gearbox/trunk/src/gbxsickacfr/gbxutilacfr/test/CMakeLists.txt (rev 0)
+++ gearbox/trunk/src/gbxsickacfr/gbxutilacfr/test/CMakeLists.txt 2008-03-19 00:16:15 UTC (rev 103)
@@ -0,0 +1,6 @@
+# INCLUDE( ${GBX_CMAKE_DIR}/UseBasicRules.cmake )
+
+LINK_LIBRARIES( GbxUtilAcfr )
+
+ADD_EXECUTABLE( mathtest mathtest.cpp )
+GBX_ADD_TEST( GbxUtilAcfrMathTest mathtest )
Added: gearbox/trunk/src/gbxsickacfr/gbxutilacfr/test/mathtest.cpp
===================================================================
--- gearbox/trunk/src/gbxsickacfr/gbxutilacfr/test/mathtest.cpp (rev 0)
+++ gearbox/trunk/src/gbxsickacfr/gbxutilacfr/test/mathtest.cpp 2008-03-19 00:16:15 UTC (rev 103)
@@ -0,0 +1,61 @@
+/*
+ * GearBox Project: Peer-Reviewed Open-Source Libraries for Robotics
+ * http://gearbox.sf.net/
+ * Copyright (c) 2004-2008 Alex Brooks, Alexei Makarenko, Tobias Kaupp
+ *
+ * This distribution is licensed to you under the terms described in
+ * the LICENSE file included in this distribution.
+ *
+ */
+
+#include <iostream>
+#include <gbxsickacfr/gbxutilacfr/mathdefs.h>
+#include <iomanip>
+#include <assert.h>
+
+#ifdef NDEBUG
+#undef NDEBUG
+#endif
+
+using namespace std;
+
+#define EPS 1e-8;
+
+template<typename T>
+void
+testNormalise()
+{
+ T angle;
+
+ angle = -M_PI;
+ NORMALISE_ANGLE(angle);
+ assert( angle >= -M_PI && angle < M_PI );
+
+ angle = -M_PI+EPS;
+ NORMALISE_ANGLE(angle);
+ assert( angle >= -M_PI && angle < M_PI );
+
+ angle = -M_PI-EPS;
+ NORMALISE_ANGLE(angle);
+ assert( angle >= -M_PI && angle < M_PI );
+
+ angle = M_PI;
+ NORMALISE_ANGLE(angle);
+ assert( angle >= -M_PI && angle < M_PI );
+
+ angle = M_PI+EPS;
+ NORMALISE_ANGLE(angle);
+ assert( angle >= -M_PI && angle < M_PI );
+
+ angle = M_PI-EPS;
+ NORMALISE_ANGLE(angle);
+ assert( angle >= -M_PI && angle < M_PI );
+}
+
+int main()
+{
+ testNormalise<float>();
+ testNormalise<double>();
+
+ cout << "Test PASSED" << endl;
+}
Modified: gearbox/trunk/src/gbxsickacfr/sickdefines.cpp
===================================================================
--- gearbox/trunk/src/gbxsickacfr/sickdefines.cpp 2008-03-18 06:43:26 UTC (rev 102)
+++ gearbox/trunk/src/gbxsickacfr/sickdefines.cpp 2008-03-19 00:16:15 UTC (rev 103)
@@ -1,6 +1,6 @@
/*
- * Orca-Robotics Project: Components for robotics
- * http://orca-robotics.sf.net/
+ * GearBox Project: Peer-Reviewed Open-Source Libraries for Robotics
+ * http://gearbox.sf.net/
* Copyright (c) 2004-2008 Alex Brooks
*
* This distribution is licensed to you under the terms described in
Modified: gearbox/trunk/src/gbxsickacfr/sickdefines.h
===================================================================
--- gearbox/trunk/src/gbxsickacfr/sickdefines.h 2008-03-18 06:43:26 UTC (rev 102)
+++ gearbox/trunk/src/gbxsickacfr/sickdefines.h 2008-03-19 00:16:15 UTC (rev 103)
@@ -1,6 +1,6 @@
/*
- * Orca-Robotics Project: Components for robotics
- * http://orca-robotics.sf.net/
+ * GearBox Project: Peer-Reviewed Open-Source Libraries for Robotics
+ * http://gearbox.sf.net/
* Copyright (c) 2004-2008 Alex Brooks
*
* This distribution is licensed to you under the terms described in
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|