mirror of
https://github.com/introlab/rtabmap.git
synced 2026-10-03 16:47:47 +08:00
Added utilite tests
This commit is contained in:
@@ -1168,6 +1168,17 @@ TEST(Util3dFiltering, cropBoxIncludesPointsInBox)
|
||||
EXPECT_LE(x, 6.0f);
|
||||
}
|
||||
|
||||
// Point included in the box, with z min=max (2D case)
|
||||
min[2] = max[2] = 0.0f;
|
||||
output = util3d::cropBox(cloud, indices, min, max, transform, negative);
|
||||
|
||||
ASSERT_EQ(output->size(), 4);
|
||||
for (int idx : *output) {
|
||||
float x = cloud->points[idx].x;
|
||||
EXPECT_GE(x, 3.0f);
|
||||
EXPECT_LE(x, 6.0f);
|
||||
}
|
||||
|
||||
// Point excluded from the box
|
||||
negative = true;
|
||||
output = util3d::cropBox(cloud, indices, min, max, transform, negative);
|
||||
@@ -1197,6 +1208,7 @@ TEST(Util3dFiltering, cropBoxInvalidBoundsTriggerAssertion)
|
||||
using PointT = pcl::PointXYZ;
|
||||
pcl::PointCloud<PointT>::Ptr cloud(new pcl::PointCloud<PointT>);
|
||||
cloud->points.emplace_back(0.0f, 0.0f, 0.0f);
|
||||
cloud->points.emplace_back(0.0f, 1.0f, 0.0f);
|
||||
pcl::IndicesPtr indices = nullptr;
|
||||
|
||||
Eigen::Vector4f min(5.0f, 0.0f, 0.0f, 1.0f);
|
||||
|
||||
@@ -8,3 +8,7 @@ ENDIF(UNIX AND NOT ANDROID)
|
||||
ADD_SUBDIRECTORY( src )
|
||||
|
||||
ADD_SUBDIRECTORY( resource_generator )
|
||||
|
||||
if(BUILD_TESTING)
|
||||
ADD_SUBDIRECTORY( test )
|
||||
endif()
|
||||
|
||||
@@ -93,27 +93,80 @@ std::string UTILITE_EXPORT uToUpperCase(const std::string & str);
|
||||
std::string UTILITE_EXPORT uToLowerCase(const std::string & str);
|
||||
|
||||
/**
|
||||
* Convert a number (unsigned int) to a string.
|
||||
* @param number the number to convert in a string
|
||||
* @return the string
|
||||
* Convert an unsigned integer to a string.
|
||||
*
|
||||
* This function converts an unsigned integer value to its string representation.
|
||||
* The conversion uses standard decimal notation.
|
||||
*
|
||||
* Example:
|
||||
* @code
|
||||
* std::string str = uNumber2Str(42u);
|
||||
* // str contains "42"
|
||||
* @endcode
|
||||
*
|
||||
* @param number the unsigned integer number to convert to a string
|
||||
* @return the string representation of the number
|
||||
*/
|
||||
std::string UTILITE_EXPORT uNumber2Str(unsigned int number);
|
||||
|
||||
/**
|
||||
* Convert a number (int) to a string.
|
||||
* @param number the number to convert in a string
|
||||
* @return the string
|
||||
* Convert a signed integer to a string.
|
||||
*
|
||||
* This function converts a signed integer value to its string representation.
|
||||
* Negative numbers will include a minus sign prefix.
|
||||
*
|
||||
* Example:
|
||||
* @code
|
||||
* std::string str = uNumber2Str(-42);
|
||||
* // str contains "-42"
|
||||
* @endcode
|
||||
*
|
||||
* @param number the integer number to convert to a string
|
||||
* @return the string representation of the number (includes minus sign for negative values)
|
||||
*/
|
||||
std::string UTILITE_EXPORT uNumber2Str(int number);
|
||||
|
||||
/**
|
||||
* Convert a number (float) to a string.
|
||||
* @param number the number to convert in a string
|
||||
* @return the string
|
||||
* Convert a float to a string.
|
||||
*
|
||||
* This function converts a floating-point value to its string representation
|
||||
* with configurable precision and format.
|
||||
*
|
||||
* Example:
|
||||
* @code
|
||||
* std::string str1 = uNumber2Str(3.14159f, 2, false);
|
||||
* // str1 contains "3.14" (scientific notation if needed)
|
||||
*
|
||||
* std::string str2 = uNumber2Str(3.14159f, 2, true);
|
||||
* // str2 contains "3.14" (fixed decimal notation)
|
||||
* @endcode
|
||||
*
|
||||
* @param number the float number to convert to a string
|
||||
* @param precision the number of decimal places to display (default: 6)
|
||||
* @param fixed if true, use fixed decimal notation; if false, use scientific notation when appropriate (default: false)
|
||||
* @return the string representation of the number
|
||||
*/
|
||||
std::string UTILITE_EXPORT uNumber2Str(float number, int precision=6, bool fixed = false);
|
||||
|
||||
/**
|
||||
* Convert a number (double) to a string.
|
||||
* @param number the number to convert in a string
|
||||
* @return the string
|
||||
* Convert a double to a string.
|
||||
*
|
||||
* This function converts a double-precision floating-point value to its string
|
||||
* representation with configurable precision and format.
|
||||
*
|
||||
* Example:
|
||||
* @code
|
||||
* std::string str1 = uNumber2Str(3.141592653589793, 4, false);
|
||||
* // str1 contains "3.1416" (scientific notation if needed)
|
||||
*
|
||||
* std::string str2 = uNumber2Str(3.141592653589793, 4, true);
|
||||
* // str2 contains "3.1416" (fixed decimal notation)
|
||||
* @endcode
|
||||
*
|
||||
* @param number the double number to convert to a string
|
||||
* @param precision the number of decimal places to display (default: 6)
|
||||
* @param fixed if true, use fixed decimal notation; if false, use scientific notation when appropriate (default: false)
|
||||
* @return the string representation of the number
|
||||
*/
|
||||
std::string UTILITE_EXPORT uNumber2Str(double number, int precision=6, bool fixed = false);
|
||||
|
||||
|
||||
@@ -318,7 +318,11 @@ public:
|
||||
|
||||
/**
|
||||
* Set is the logger buffers messages, default false. When true, the messages are
|
||||
* buffered until the application is closed or ULogger::flush() is called.
|
||||
* buffered until the application is closed or ULogger::flush() is called.
|
||||
*
|
||||
* Note that if logging to a file, flush doesn't mean that messages are written to file right
|
||||
* away. To write everything on disk, set logger type to kTypeNoLog.
|
||||
*
|
||||
* @see ULogger::flush()
|
||||
* @param buffered true to buffer messages, otherwise set to false.
|
||||
*/
|
||||
@@ -374,14 +378,6 @@ public:
|
||||
*/
|
||||
static void flush();
|
||||
|
||||
/**
|
||||
* Write a message directly to logger without level handling.
|
||||
* @param msg the message to write.
|
||||
* @param ... the variable arguments
|
||||
* @deprecated use UDEBUG(), UINFO(), UWARN(), UERROR() or UFATAL()
|
||||
*/
|
||||
static void write(const char* msg, ...);
|
||||
|
||||
/*
|
||||
* Write a message to logger: use UDEBUG(), UINFO(), UWARN(), UERROR() or UFATAL() instead.
|
||||
* @param level the log level of this message
|
||||
|
||||
@@ -119,7 +119,7 @@ inline T uMax(const T * v, unsigned int size, unsigned int & index)
|
||||
template<class T>
|
||||
inline T uMax(const std::vector<T> & v, unsigned int & index)
|
||||
{
|
||||
return uMax(v.data(), v->size(), index);
|
||||
return uMax(v.data(), v.size(), index);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -82,40 +82,46 @@ public:
|
||||
}
|
||||
|
||||
/**
|
||||
* Lock the mutex.
|
||||
* Lock the mutex.
|
||||
* @return true on success, false if error.
|
||||
*/
|
||||
int lock() const
|
||||
bool lock() const
|
||||
{
|
||||
#ifdef _WIN32
|
||||
EnterCriticalSection(&C); return 0;
|
||||
EnterCriticalSection(&C); return true;
|
||||
#else
|
||||
return pthread_mutex_lock(&M);
|
||||
return pthread_mutex_lock(&M) == 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* Try locking the mutex.
|
||||
* @return true if mutex has been locked by this call, false otherwise.
|
||||
*/
|
||||
#ifdef _WIN32
|
||||
#if(_WIN32_WINNT >= 0x0400)
|
||||
int lockTry() const
|
||||
bool lockTry() const
|
||||
{
|
||||
return (TryEnterCriticalSection(&C)?0:EBUSY);
|
||||
return (TryEnterCriticalSection(&C)?true:false);
|
||||
}
|
||||
#endif
|
||||
#else
|
||||
int lockTry() const
|
||||
bool lockTry() const
|
||||
{
|
||||
return pthread_mutex_trylock(&M);
|
||||
return pthread_mutex_trylock(&M) == 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Unlock the mutex.
|
||||
* @return true on success, false if error.
|
||||
*/
|
||||
int unlock() const
|
||||
bool unlock() const
|
||||
{
|
||||
#ifdef _WIN32
|
||||
LeaveCriticalSection(&C); return 0;
|
||||
LeaveCriticalSection(&C); return true;
|
||||
#else
|
||||
return pthread_mutex_unlock(&M);
|
||||
return pthread_mutex_unlock(&M) == 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@@ -23,17 +23,46 @@
|
||||
#include "rtabmap/utilite/utilite_export.h" // DLL export/import defines
|
||||
|
||||
/**
|
||||
* This class is used to get some informations
|
||||
* about the current process.
|
||||
* \file UProcessInfo.h
|
||||
* \brief UProcessInfo class for getting process information
|
||||
*
|
||||
* This class provides methods to retrieve information about the current process,
|
||||
* such as memory usage.
|
||||
*/
|
||||
|
||||
/**
|
||||
* \class UProcessInfo
|
||||
* \brief Class for getting information about the current process
|
||||
*
|
||||
* This class provides static methods to retrieve information about the current
|
||||
* process, such as memory usage. The information is retrieved from the operating
|
||||
* system.
|
||||
*
|
||||
* Example:
|
||||
* @code
|
||||
* long int memory = UProcessInfo::getMemoryUsage();
|
||||
* std::cout << "Memory usage: " << memory << " bytes" << std::endl;
|
||||
* @endcode
|
||||
*/
|
||||
class UTILITE_EXPORT UProcessInfo {
|
||||
public:
|
||||
/**
|
||||
* \brief Constructor
|
||||
*/
|
||||
UProcessInfo();
|
||||
|
||||
/**
|
||||
* \brief Virtual destructor
|
||||
*/
|
||||
virtual ~UProcessInfo();
|
||||
|
||||
/**
|
||||
* Get the memory used by the current process.
|
||||
* @return the number of bytes used by the current process.
|
||||
* \brief Get the memory used by the current process
|
||||
*
|
||||
* This method returns the amount of memory currently used by the process.
|
||||
* The exact meaning of "memory used" may vary between operating systems.
|
||||
*
|
||||
* @return the number of bytes used by the current process, or -1 on error
|
||||
*/
|
||||
static long int getMemoryUsage();
|
||||
};
|
||||
|
||||
@@ -133,15 +133,15 @@ public:
|
||||
|
||||
/*
|
||||
* Try to acquire the semaphore, not a blocking call.
|
||||
* @return false if the semaphore can't be taken without waiting (value <= 0), true otherwise
|
||||
* @return true if the semaphore could be acquired with the number specified, false otherwise
|
||||
*/
|
||||
#ifdef _WIN32
|
||||
int acquireTry() const
|
||||
bool acquireTry() const
|
||||
{
|
||||
return ((WaitForSingleObject((HANDLE)S,INFINITE)==WAIT_OBJECT_0)?0:EAGAIN);
|
||||
return ((WaitForSingleObject((HANDLE)S,INFINITE)==WAIT_OBJECT_0)?true:false);
|
||||
}
|
||||
#else
|
||||
int acquireTry(int n)
|
||||
bool acquireTry(int n)
|
||||
{
|
||||
pthread_mutex_lock(&_waitMutex);
|
||||
if(n > _available)
|
||||
@@ -158,19 +158,21 @@ public:
|
||||
/**
|
||||
* Release the semaphore, increasing its value by 1 and
|
||||
* signaling waiting threads (which called acquire()).
|
||||
* @return true on success, false otherwise
|
||||
*/
|
||||
#ifdef _WIN32
|
||||
int release(int n = 1) const
|
||||
bool release(int n = 1) const
|
||||
{
|
||||
return (ReleaseSemaphore((HANDLE)S,n,0)?0:ERANGE);
|
||||
return (ReleaseSemaphore((HANDLE)S,n,0)?true:false);
|
||||
}
|
||||
#else
|
||||
void release(int n = 1)
|
||||
bool release(int n = 1)
|
||||
{
|
||||
pthread_mutex_lock(&_waitMutex);
|
||||
_available += n;
|
||||
pthread_cond_broadcast(&_cond);
|
||||
pthread_mutex_unlock(&_waitMutex);
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
@@ -75,14 +75,6 @@ public:
|
||||
double elapsed() {return getElapsedTime();}
|
||||
double getElapsedTime();
|
||||
|
||||
/**
|
||||
* This method is used to get the interval time
|
||||
* between stop() and the start().
|
||||
* @return double the interval in seconds.
|
||||
* @deprecated use elapsed() instead.
|
||||
*/
|
||||
UTILITE_DEPRECATED double getInterval();
|
||||
|
||||
/**
|
||||
* This method is used to get the interval of
|
||||
* the timer while it is running. It's automatically
|
||||
|
||||
@@ -25,100 +25,433 @@
|
||||
#include <vector>
|
||||
|
||||
/**
|
||||
* Experimental class...
|
||||
* \file UVariant.h
|
||||
* \brief UVariant class for storing and converting between different data types
|
||||
*
|
||||
* This class provides a type-safe way to store values of different types
|
||||
* and convert between them. It supports basic types (bool, char, int, float, etc.)
|
||||
* and arrays of these types.
|
||||
*
|
||||
* Example:
|
||||
* @code
|
||||
* UVariant v(42);
|
||||
* if(v.isInt())
|
||||
* {
|
||||
* int value = v.toInt();
|
||||
* }
|
||||
* @endcode
|
||||
*/
|
||||
|
||||
/**
|
||||
* \class UVariant
|
||||
* \brief A variant type that can hold values of different types
|
||||
*
|
||||
* UVariant is a type-safe container that can store values of various types
|
||||
* including booleans, integers, floats, strings, and arrays. It provides
|
||||
* methods to check the stored type and convert to other types.
|
||||
*/
|
||||
class UTILITE_EXPORT UVariant
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* \enum Type
|
||||
* \brief Enumeration of supported data types
|
||||
*/
|
||||
enum Type{
|
||||
kBool,
|
||||
kChar,
|
||||
kUChar,
|
||||
kShort,
|
||||
kUShort,
|
||||
kInt,
|
||||
kUInt,
|
||||
kFloat,
|
||||
kDouble,
|
||||
kStr,
|
||||
kCharArray,
|
||||
kUCharArray,
|
||||
kShortArray,
|
||||
kUShortArray,
|
||||
kIntArray,
|
||||
kUIntArray,
|
||||
kFloatArray,
|
||||
kDoubleArray,
|
||||
kUndef
|
||||
kBool, /**< Boolean type */
|
||||
kChar, /**< Signed char type */
|
||||
kUChar, /**< Unsigned char type */
|
||||
kShort, /**< Short integer type */
|
||||
kUShort, /**< Unsigned short integer type */
|
||||
kInt, /**< Integer type */
|
||||
kUInt, /**< Unsigned integer type */
|
||||
kFloat, /**< Float type */
|
||||
kDouble, /**< Double type */
|
||||
kStr, /**< String type */
|
||||
kCharArray, /**< Array of signed char */
|
||||
kUCharArray, /**< Array of unsigned char */
|
||||
kShortArray, /**< Array of short */
|
||||
kUShortArray, /**< Array of unsigned short */
|
||||
kIntArray, /**< Array of int */
|
||||
kUIntArray, /**< Array of unsigned int */
|
||||
kFloatArray, /**< Array of float */
|
||||
kDoubleArray, /**< Array of double */
|
||||
kUndef /**< Undefined type (default) */
|
||||
};
|
||||
public:
|
||||
/**
|
||||
* \brief Default constructor
|
||||
* Creates an undefined variant
|
||||
*/
|
||||
UVariant();
|
||||
|
||||
/**
|
||||
* \brief Constructor from bool
|
||||
* @param value the boolean value
|
||||
*/
|
||||
UVariant(const bool & value);
|
||||
|
||||
/**
|
||||
* \brief Constructor from signed char
|
||||
* @param value the signed char value
|
||||
*/
|
||||
UVariant(const signed char & value);
|
||||
|
||||
/**
|
||||
* \brief Constructor from unsigned char
|
||||
* @param value the unsigned char value
|
||||
*/
|
||||
UVariant(const unsigned char & value);
|
||||
|
||||
/**
|
||||
* \brief Constructor from short
|
||||
* @param value the short value
|
||||
*/
|
||||
UVariant(const short & value);
|
||||
|
||||
/**
|
||||
* \brief Constructor from unsigned short
|
||||
* @param value the unsigned short value
|
||||
*/
|
||||
UVariant(const unsigned short & value);
|
||||
|
||||
/**
|
||||
* \brief Constructor from int
|
||||
* @param value the integer value
|
||||
*/
|
||||
UVariant(const int & value);
|
||||
|
||||
/**
|
||||
* \brief Constructor from unsigned int
|
||||
* @param value the unsigned integer value
|
||||
*/
|
||||
UVariant(const unsigned int & value);
|
||||
|
||||
/**
|
||||
* \brief Constructor from float
|
||||
* @param value the float value
|
||||
*/
|
||||
UVariant(const float & value);
|
||||
|
||||
/**
|
||||
* \brief Constructor from double
|
||||
* @param value the double value
|
||||
*/
|
||||
UVariant(const double & value);
|
||||
|
||||
/**
|
||||
* \brief Constructor from C string
|
||||
* @param value the C string value
|
||||
*/
|
||||
UVariant(const char * value);
|
||||
|
||||
/**
|
||||
* \brief Constructor from std::string
|
||||
* @param value the string value
|
||||
*/
|
||||
UVariant(const std::string & value);
|
||||
|
||||
/**
|
||||
* \brief Constructor from array of signed char
|
||||
* @param value the array of signed char
|
||||
*/
|
||||
UVariant(const std::vector<signed char> & value);
|
||||
|
||||
/**
|
||||
* \brief Constructor from array of unsigned char
|
||||
* @param value the array of unsigned char
|
||||
*/
|
||||
UVariant(const std::vector<unsigned char> & value);
|
||||
|
||||
/**
|
||||
* \brief Constructor from array of short
|
||||
* @param value the array of short
|
||||
*/
|
||||
UVariant(const std::vector<short> & value);
|
||||
|
||||
/**
|
||||
* \brief Constructor from array of unsigned short
|
||||
* @param value the array of unsigned short
|
||||
*/
|
||||
UVariant(const std::vector<unsigned short> & value);
|
||||
|
||||
/**
|
||||
* \brief Constructor from array of int
|
||||
* @param value the array of int
|
||||
*/
|
||||
UVariant(const std::vector<int> & value);
|
||||
|
||||
/**
|
||||
* \brief Constructor from array of unsigned int
|
||||
* @param value the array of unsigned int
|
||||
*/
|
||||
UVariant(const std::vector<unsigned int> & value);
|
||||
|
||||
/**
|
||||
* \brief Constructor from array of float
|
||||
* @param value the array of float
|
||||
*/
|
||||
UVariant(const std::vector<float> & value);
|
||||
|
||||
/**
|
||||
* \brief Constructor from array of double
|
||||
* @param value the array of double
|
||||
*/
|
||||
UVariant(const std::vector<double> & value);
|
||||
|
||||
/**
|
||||
* \brief Get the type of the stored value
|
||||
* @return the Type enum value
|
||||
*/
|
||||
Type type() const {return type_;}
|
||||
|
||||
/**
|
||||
* \brief Check if the variant is undefined
|
||||
* @return true if type is kUndef
|
||||
*/
|
||||
bool isUndef() const {return type_ == kUndef;}
|
||||
|
||||
/**
|
||||
* \brief Check if the variant is a bool
|
||||
* @return true if type is kBool
|
||||
*/
|
||||
bool isBool() const {return type_ == kBool;}
|
||||
|
||||
/**
|
||||
* \brief Check if the variant is a signed char
|
||||
* @return true if type is kChar
|
||||
*/
|
||||
bool isChar() const {return type_ == kChar;}
|
||||
|
||||
/**
|
||||
* \brief Check if the variant is an unsigned char
|
||||
* @return true if type is kUChar
|
||||
*/
|
||||
bool isUChar() const {return type_ == kUChar;}
|
||||
|
||||
/**
|
||||
* \brief Check if the variant is a short
|
||||
* @return true if type is kShort
|
||||
*/
|
||||
bool isShort() const {return type_ == kShort;}
|
||||
|
||||
/**
|
||||
* \brief Check if the variant is an unsigned short
|
||||
* @return true if type is kUShort
|
||||
*/
|
||||
bool isUShort() const {return type_ == kUShort;}
|
||||
|
||||
/**
|
||||
* \brief Check if the variant is an int
|
||||
* @return true if type is kInt
|
||||
*/
|
||||
bool isInt() const {return type_ == kInt;}
|
||||
|
||||
/**
|
||||
* \brief Check if the variant is an unsigned int
|
||||
* @return true if type is kUInt
|
||||
*/
|
||||
bool isUInt() const {return type_ == kUInt;}
|
||||
|
||||
/**
|
||||
* \brief Check if the variant is a float
|
||||
* @return true if type is kFloat
|
||||
*/
|
||||
bool isFloat() const {return type_ == kFloat;}
|
||||
|
||||
/**
|
||||
* \brief Check if the variant is a double
|
||||
* @return true if type is kDouble
|
||||
*/
|
||||
bool isDouble() const {return type_ == kDouble;}
|
||||
|
||||
/**
|
||||
* \brief Check if the variant is a string
|
||||
* @return true if type is kStr
|
||||
*/
|
||||
bool isStr() const {return type_ == kStr;}
|
||||
|
||||
/**
|
||||
* \brief Check if the variant is an array of signed char
|
||||
* @return true if type is kCharArray
|
||||
*/
|
||||
bool isCharArray() const {return type_ == kCharArray;}
|
||||
|
||||
/**
|
||||
* \brief Check if the variant is an array of unsigned char
|
||||
* @return true if type is kUCharArray
|
||||
*/
|
||||
bool isUCharArray() const {return type_ == kUCharArray;}
|
||||
|
||||
/**
|
||||
* \brief Check if the variant is an array of short
|
||||
* @return true if type is kShortArray
|
||||
*/
|
||||
bool isShortArray() const {return type_ == kShortArray;}
|
||||
|
||||
/**
|
||||
* \brief Check if the variant is an array of unsigned short
|
||||
* @return true if type is kUShortArray
|
||||
*/
|
||||
bool isUShortArray() const {return type_ == kUShortArray;}
|
||||
|
||||
/**
|
||||
* \brief Check if the variant is an array of int
|
||||
* @return true if type is kIntArray
|
||||
*/
|
||||
bool isIntArray() const {return type_ == kIntArray;}
|
||||
|
||||
/**
|
||||
* \brief Check if the variant is an array of unsigned int
|
||||
* @return true if type is kUIntArray
|
||||
*/
|
||||
bool isUIntArray() const {return type_ == kUIntArray;}
|
||||
|
||||
/**
|
||||
* \brief Check if the variant is an array of float
|
||||
* @return true if type is kFloatArray
|
||||
*/
|
||||
bool isFloatArray() const {return type_ == kFloatArray;}
|
||||
|
||||
/**
|
||||
* \brief Check if the variant is an array of double
|
||||
* @return true if type is kDoubleArray
|
||||
*/
|
||||
bool isDoubleArray() const {return type_ == kDoubleArray;}
|
||||
|
||||
/**
|
||||
* \brief Convert the variant to bool
|
||||
* @return the boolean value
|
||||
*/
|
||||
bool toBool() const;
|
||||
|
||||
/**
|
||||
* \brief Convert the variant to signed char
|
||||
* @param ok pointer to bool to indicate success (optional)
|
||||
* @return the signed char value
|
||||
*/
|
||||
signed char toChar(bool * ok = 0) const;
|
||||
|
||||
/**
|
||||
* \brief Convert the variant to unsigned char
|
||||
* @param ok pointer to bool to indicate success (optional)
|
||||
* @return the unsigned char value
|
||||
*/
|
||||
unsigned char toUChar(bool * ok = 0) const;
|
||||
|
||||
/**
|
||||
* \brief Convert the variant to short
|
||||
* @param ok pointer to bool to indicate success (optional)
|
||||
* @return the short value
|
||||
*/
|
||||
short toShort(bool * ok = 0) const;
|
||||
|
||||
/**
|
||||
* \brief Convert the variant to unsigned short
|
||||
* @param ok pointer to bool to indicate success (optional)
|
||||
* @return the unsigned short value
|
||||
*/
|
||||
unsigned short toUShort(bool * ok = 0) const;
|
||||
|
||||
/**
|
||||
* \brief Convert the variant to int
|
||||
* @param ok pointer to bool to indicate success (optional)
|
||||
* @return the integer value
|
||||
*/
|
||||
int toInt(bool * ok = 0) const;
|
||||
|
||||
/**
|
||||
* \brief Convert the variant to unsigned int
|
||||
* @param ok pointer to bool to indicate success (optional)
|
||||
* @return the unsigned integer value
|
||||
*/
|
||||
unsigned int toUInt(bool * ok = 0) const;
|
||||
|
||||
/**
|
||||
* \brief Convert the variant to float
|
||||
* @param ok pointer to bool to indicate success (optional)
|
||||
* @return the float value
|
||||
*/
|
||||
float toFloat(bool * ok = 0) const;
|
||||
|
||||
/**
|
||||
* \brief Convert the variant to double
|
||||
* @param ok pointer to bool to indicate success (optional)
|
||||
* @return the double value
|
||||
*/
|
||||
double toDouble(bool * ok = 0) const;
|
||||
|
||||
/**
|
||||
* \brief Convert the variant to string
|
||||
* @param ok pointer to bool to indicate success (optional)
|
||||
* @return the string value
|
||||
*/
|
||||
std::string toStr(bool * ok = 0) const;
|
||||
|
||||
/**
|
||||
* \brief Convert the variant to array of signed char
|
||||
* @param ok pointer to bool to indicate success (optional)
|
||||
* @return the array of signed char
|
||||
*/
|
||||
std::vector<signed char> toCharArray(bool * ok = 0) const;
|
||||
|
||||
/**
|
||||
* \brief Convert the variant to array of unsigned char
|
||||
* @param ok pointer to bool to indicate success (optional)
|
||||
* @return the array of unsigned char
|
||||
*/
|
||||
std::vector<unsigned char> toUCharArray(bool * ok = 0) const;
|
||||
|
||||
/**
|
||||
* \brief Convert the variant to array of short
|
||||
* @param ok pointer to bool to indicate success (optional)
|
||||
* @return the array of short
|
||||
*/
|
||||
std::vector<short> toShortArray(bool * ok = 0) const;
|
||||
|
||||
/**
|
||||
* \brief Convert the variant to array of unsigned short
|
||||
* @param ok pointer to bool to indicate success (optional)
|
||||
* @return the array of unsigned short
|
||||
*/
|
||||
std::vector<unsigned short> toUShortArray(bool * ok = 0) const;
|
||||
|
||||
/**
|
||||
* \brief Convert the variant to array of int
|
||||
* @param ok pointer to bool to indicate success (optional)
|
||||
* @return the array of int
|
||||
*/
|
||||
std::vector<int> toIntArray(bool * ok = 0) const;
|
||||
|
||||
/**
|
||||
* \brief Convert the variant to array of unsigned int
|
||||
* @param ok pointer to bool to indicate success (optional)
|
||||
* @return the array of unsigned int
|
||||
*/
|
||||
std::vector<unsigned int> toUIntArray(bool * ok = 0) const;
|
||||
|
||||
/**
|
||||
* \brief Convert the variant to array of float
|
||||
* @param ok pointer to bool to indicate success (optional)
|
||||
* @return the array of float
|
||||
*/
|
||||
std::vector<float> toFloatArray(bool * ok = 0) const;
|
||||
|
||||
/**
|
||||
* \brief Convert the variant to array of double
|
||||
* @param ok pointer to bool to indicate success (optional)
|
||||
* @return the array of double
|
||||
*/
|
||||
std::vector<double> toDoubleArray(bool * ok = 0) const;
|
||||
|
||||
/**
|
||||
* \brief Virtual destructor
|
||||
*/
|
||||
virtual ~UVariant() {}
|
||||
|
||||
private:
|
||||
Type type_;
|
||||
std::vector<unsigned char> data_;
|
||||
Type type_; /**< The type of the stored value */
|
||||
std::vector<unsigned char> data_; /**< The stored data */
|
||||
};
|
||||
|
||||
#endif /* UVARIANT_H */
|
||||
|
||||
@@ -278,6 +278,11 @@ std::string UDirectory::getDir(const std::string & filePath)
|
||||
{
|
||||
if(dir[i] == '/' || dir[i] == '\\')
|
||||
{
|
||||
if(i == 0)
|
||||
{
|
||||
// leading /
|
||||
break;
|
||||
}
|
||||
//remove separators...
|
||||
dir[i] = 0;
|
||||
--i;
|
||||
|
||||
@@ -87,7 +87,7 @@ std::string UFile::getName(const std::string & filePath)
|
||||
std::string UFile::getExtension(const std::string &filePath)
|
||||
{
|
||||
std::list<std::string> list = uSplit(filePath, '.');
|
||||
if(list.size())
|
||||
if(list.size()>1)
|
||||
{
|
||||
return list.back();
|
||||
}
|
||||
|
||||
+4
-60
@@ -254,6 +254,8 @@ std::map<std::string, unsigned long> ULogger::getRegisteredThreads()
|
||||
|
||||
void ULogger::reset()
|
||||
{
|
||||
UScopeMutex lock(loggerMutex_);
|
||||
flush();
|
||||
ULogger::setType(ULogger::kTypeNoLog);
|
||||
append_ = true;
|
||||
printTime_ = true;
|
||||
@@ -263,9 +265,11 @@ void ULogger::reset()
|
||||
printWhere_ = true;
|
||||
printWhereFullPath_ = false;
|
||||
printThreadID_ = false;
|
||||
buffered_ = false;
|
||||
limitWhereLength_ = false;
|
||||
level_ = kInfo; // By default, we show all info msgs + upper level (Warning, Error)
|
||||
logFileName_ = ULogger::kDefaultLogFileName;
|
||||
registeredThreads_.clear();
|
||||
}
|
||||
|
||||
void ULogger::setBuffered(bool buffered)
|
||||
@@ -297,66 +301,6 @@ void ULogger::_flush()
|
||||
bufferedMsgs_.clear();
|
||||
}
|
||||
|
||||
void ULogger::write(const char* msg, ...)
|
||||
{
|
||||
loggerMutex_.lock();
|
||||
if(!instance_)
|
||||
{
|
||||
loggerMutex_.unlock();
|
||||
return;
|
||||
}
|
||||
|
||||
std::string endline = "";
|
||||
if(printEndline_) {
|
||||
endline = "\r\n";
|
||||
}
|
||||
|
||||
std::string time = "";
|
||||
if(printTime_)
|
||||
{
|
||||
getTime(time);
|
||||
time.append(" - ");
|
||||
}
|
||||
|
||||
|
||||
if(printTime_)
|
||||
{
|
||||
if(buffered_)
|
||||
{
|
||||
bufferedMsgs_.append(time.c_str());
|
||||
}
|
||||
else
|
||||
{
|
||||
ULogger::getInstance()->_writeStr(time.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
va_list args;
|
||||
va_start(args, msg);
|
||||
if(buffered_)
|
||||
{
|
||||
bufferedMsgs_.append(uFormatv(msg, args));
|
||||
}
|
||||
else
|
||||
{
|
||||
ULogger::getInstance()->_write(msg, args);
|
||||
}
|
||||
va_end(args);
|
||||
if(printEndline_)
|
||||
{
|
||||
if(buffered_)
|
||||
{
|
||||
bufferedMsgs_.append(endline.c_str());
|
||||
}
|
||||
else
|
||||
{
|
||||
ULogger::getInstance()->_writeStr(endline.c_str());
|
||||
}
|
||||
}
|
||||
loggerMutex_.unlock();
|
||||
|
||||
}
|
||||
|
||||
void ULogger::write(ULogger::Level level,
|
||||
const char * file,
|
||||
int line,
|
||||
|
||||
@@ -65,17 +65,6 @@ double UTimer::getElapsedTime()
|
||||
QueryPerformanceCounter(&now);
|
||||
return double(now.QuadPart - startTimeRecorded_.QuadPart) / frequency_.QuadPart;
|
||||
}
|
||||
double UTimer::getInterval()
|
||||
{
|
||||
if(stopTimeRecorded_.QuadPart == startTimeRecorded_.QuadPart)
|
||||
{
|
||||
return getElapsedTime();
|
||||
}
|
||||
else
|
||||
{
|
||||
return double(stopTimeRecorded_.QuadPart - startTimeRecorded_.QuadPart) / frequency_.QuadPart;
|
||||
}
|
||||
}
|
||||
#else
|
||||
double UTimer::now()
|
||||
{
|
||||
@@ -99,19 +88,6 @@ double UTimer::getElapsedTime()
|
||||
return UTimer::now() - (double(startTimeRecorded_.tv_sec) + double(startTimeRecorded_.tv_usec) / 1000000.0);
|
||||
|
||||
}
|
||||
double UTimer::getInterval()
|
||||
{
|
||||
if(startTimeRecorded_.tv_sec == stopTimeRecorded_.tv_sec && startTimeRecorded_.tv_usec == stopTimeRecorded_.tv_usec)
|
||||
{
|
||||
return getElapsedTime();
|
||||
}
|
||||
else
|
||||
{
|
||||
double start = double(startTimeRecorded_.tv_sec) + double(startTimeRecorded_.tv_usec) / 1000000.0;
|
||||
double stop = double(stopTimeRecorded_.tv_sec) + double(stopTimeRecorded_.tv_usec) / 1000000.0;
|
||||
return stop - start;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
double UTimer::ticks() // Stop->start and return Interval
|
||||
|
||||
@@ -0,0 +1,67 @@
|
||||
# UConversion.h
|
||||
add_executable(test_uconversion test_uconversion.cpp)
|
||||
target_link_libraries(test_uconversion gtest_main rtabmap::utilite)
|
||||
gtest_discover_tests(test_uconversion)
|
||||
|
||||
# UTimer.h
|
||||
add_executable(test_utimer test_utimer.cpp)
|
||||
target_link_libraries(test_utimer gtest_main rtabmap::utilite)
|
||||
gtest_discover_tests(test_utimer)
|
||||
|
||||
# UVariant.h
|
||||
add_executable(test_uvariant test_uvariant.cpp)
|
||||
target_link_libraries(test_uvariant gtest_main rtabmap::utilite)
|
||||
gtest_discover_tests(test_uvariant)
|
||||
|
||||
# UFile.h
|
||||
add_executable(test_ufile test_ufile.cpp)
|
||||
target_link_libraries(test_ufile gtest_main rtabmap::utilite)
|
||||
gtest_discover_tests(test_ufile)
|
||||
|
||||
# UDirectory.h
|
||||
add_executable(test_udirectory test_udirectory.cpp)
|
||||
target_link_libraries(test_udirectory gtest_main rtabmap::utilite)
|
||||
gtest_discover_tests(test_udirectory)
|
||||
|
||||
# UProcessInfo.h
|
||||
add_executable(test_uprocessinfo test_uprocessinfo.cpp)
|
||||
target_link_libraries(test_uprocessinfo gtest_main rtabmap::utilite)
|
||||
gtest_discover_tests(test_uprocessinfo)
|
||||
|
||||
# UMath.h
|
||||
add_executable(test_umath test_umath.cpp)
|
||||
target_link_libraries(test_umath gtest_main rtabmap::utilite)
|
||||
gtest_discover_tests(test_umath)
|
||||
|
||||
# UStl.h
|
||||
add_executable(test_ustl test_ustl.cpp)
|
||||
target_link_libraries(test_ustl gtest_main rtabmap::utilite)
|
||||
gtest_discover_tests(test_ustl)
|
||||
|
||||
# UEventsHandler.h, UEventsManager.h, UEventsSender.h
|
||||
add_executable(test_uevents test_uevents.cpp)
|
||||
target_link_libraries(test_uevents gtest_main rtabmap::utilite)
|
||||
gtest_discover_tests(test_uevents)
|
||||
|
||||
# UMutex.h
|
||||
add_executable(test_umutex test_umutex.cpp)
|
||||
target_link_libraries(test_umutex gtest_main rtabmap::utilite)
|
||||
gtest_discover_tests(test_umutex)
|
||||
|
||||
# UThread.h
|
||||
add_executable(test_uthread test_uthread.cpp)
|
||||
target_link_libraries(test_uthread gtest_main rtabmap::utilite)
|
||||
gtest_discover_tests(test_uthread)
|
||||
|
||||
# USemaphore.h
|
||||
add_executable(test_usemaphore test_usemaphore.cpp)
|
||||
target_link_libraries(test_usemaphore gtest_main rtabmap::utilite)
|
||||
gtest_discover_tests(test_usemaphore)
|
||||
|
||||
# ULogger.h
|
||||
add_executable(test_ulogger test_ulogger.cpp)
|
||||
target_link_libraries(test_ulogger gtest_main rtabmap::utilite)
|
||||
gtest_discover_tests(test_ulogger
|
||||
PROPERTIES RUN_SERIAL TRUE
|
||||
)
|
||||
|
||||
@@ -0,0 +1,203 @@
|
||||
#include "gtest/gtest.h"
|
||||
#include "rtabmap/utilite/UConversion.h"
|
||||
|
||||
TEST(UConversionTest, uReplaceCharChar)
|
||||
{
|
||||
std::string str = "Hello";
|
||||
std::string result = uReplaceChar(str, 'l', 'p');
|
||||
EXPECT_EQ(result, "Heppo");
|
||||
}
|
||||
|
||||
TEST(UConversionTest, uReplaceCharString)
|
||||
{
|
||||
std::string str = "Hello";
|
||||
std::string result = uReplaceChar(str, 'o', "oween");
|
||||
EXPECT_EQ(result, "Helloween");
|
||||
}
|
||||
|
||||
TEST(UConversionTest, uToUpperCase)
|
||||
{
|
||||
std::string str = "hello!";
|
||||
std::string result = uToUpperCase(str);
|
||||
EXPECT_EQ(result, "HELLO!");
|
||||
}
|
||||
|
||||
TEST(UConversionTest, uToLowerCase)
|
||||
{
|
||||
std::string str = "HELLO!";
|
||||
std::string result = uToLowerCase(str);
|
||||
EXPECT_EQ(result, "hello!");
|
||||
}
|
||||
|
||||
TEST(UConversionTest, uNumber2StrUnsignedInt)
|
||||
{
|
||||
unsigned int number = 42;
|
||||
std::string result = uNumber2Str(number);
|
||||
EXPECT_EQ(result, "42");
|
||||
}
|
||||
|
||||
TEST(UConversionTest, uNumber2StrInt)
|
||||
{
|
||||
int number = -42;
|
||||
std::string result = uNumber2Str(number);
|
||||
EXPECT_EQ(result, "-42");
|
||||
}
|
||||
|
||||
TEST(UConversionTest, uNumber2StrFloat)
|
||||
{
|
||||
float number = 0.14159f;
|
||||
std::string result = uNumber2Str(number, 2, false);
|
||||
EXPECT_STREQ(result.c_str(), "0.14");
|
||||
|
||||
number = 3.14159f;
|
||||
result = uNumber2Str(number, 2, false);
|
||||
EXPECT_STREQ(result.c_str(), "3.1");
|
||||
}
|
||||
|
||||
TEST(UConversionTest, uNumber2StrDouble)
|
||||
{
|
||||
double number = 0.14159;
|
||||
std::string result = uNumber2Str(number, 2, false);
|
||||
EXPECT_STREQ(result.c_str(), "0.14");
|
||||
|
||||
number = 3.14159;
|
||||
result = uNumber2Str(number, 2, false);
|
||||
EXPECT_STREQ(result.c_str(), "3.1");
|
||||
}
|
||||
|
||||
TEST(UConversionTest, uStr2Int)
|
||||
{
|
||||
std::string str = "42";
|
||||
int result = uStr2Int(str);
|
||||
EXPECT_EQ(result, 42);
|
||||
}
|
||||
|
||||
TEST(UConversionTest, uStr2IntNegative)
|
||||
{
|
||||
std::string str = "-42";
|
||||
int result = uStr2Int(str);
|
||||
EXPECT_EQ(result, -42);
|
||||
}
|
||||
|
||||
TEST(UConversionTest, uStr2Float)
|
||||
{
|
||||
std::string str = "3.14";
|
||||
float result = uStr2Float(str);
|
||||
EXPECT_NEAR(result, 3.14f, 0.001f);
|
||||
}
|
||||
|
||||
TEST(UConversionTest, uStr2FloatComma)
|
||||
{
|
||||
std::string str = "3,14";
|
||||
float result = uStr2Float(str);
|
||||
EXPECT_NEAR(result, 3.14f, 0.001f);
|
||||
}
|
||||
|
||||
TEST(UConversionTest, uStr2Double)
|
||||
{
|
||||
std::string str = "3.14159";
|
||||
double result = uStr2Double(str);
|
||||
EXPECT_NEAR(result, 3.14159, 0.00001);
|
||||
}
|
||||
|
||||
TEST(UConversionTest, uStr2DoubleComma)
|
||||
{
|
||||
std::string str = "3,14159";
|
||||
double result = uStr2Double(str);
|
||||
EXPECT_NEAR(result, 3.14159, 0.00001);
|
||||
}
|
||||
|
||||
TEST(UConversionTest, uBool2Str)
|
||||
{
|
||||
std::string resultTrue = uBool2Str(true);
|
||||
std::string resultFalse = uBool2Str(false);
|
||||
EXPECT_EQ(resultTrue, "true");
|
||||
EXPECT_EQ(resultFalse, "false");
|
||||
}
|
||||
|
||||
TEST(UConversionTest, uStr2Bool)
|
||||
{
|
||||
EXPECT_TRUE(uStr2Bool("true"));
|
||||
EXPECT_TRUE(uStr2Bool("TRUE"));
|
||||
EXPECT_TRUE(uStr2Bool("True"));
|
||||
EXPECT_FALSE(uStr2Bool("false"));
|
||||
EXPECT_FALSE(uStr2Bool("FALSE"));
|
||||
EXPECT_FALSE(uStr2Bool("0"));
|
||||
EXPECT_TRUE(uStr2Bool("1"));
|
||||
EXPECT_TRUE(uStr2Bool("anything"));
|
||||
}
|
||||
|
||||
TEST(UConversionTest, uStr2Bytes)
|
||||
{
|
||||
std::string str = "Hello";
|
||||
std::vector<unsigned char> bytes = uStr2Bytes(str);
|
||||
EXPECT_EQ(bytes.size(), 6); // "Hello" + null terminator
|
||||
EXPECT_EQ(bytes[0], 'H');
|
||||
EXPECT_EQ(bytes[4], 'o');
|
||||
EXPECT_EQ(bytes[5], '\0');
|
||||
}
|
||||
|
||||
TEST(UConversionTest, uBytes2Str)
|
||||
{
|
||||
std::vector<unsigned char> bytes = {'H', 'e', 'l', 'l', 'o', '\0'};
|
||||
std::string result = uBytes2Str(bytes);
|
||||
EXPECT_EQ(result, "Hello");
|
||||
}
|
||||
|
||||
TEST(UConversionTest, uBytes2Hex)
|
||||
{
|
||||
char bytes[] = {0x3F, 0x1A};
|
||||
std::string result = uBytes2Hex(bytes, 2);
|
||||
EXPECT_EQ(result, "3F1A");
|
||||
}
|
||||
|
||||
TEST(UConversionTest, uHex2Bytes)
|
||||
{
|
||||
std::string hex = "1f3B";
|
||||
std::vector<char> bytes = uHex2Bytes(hex);
|
||||
EXPECT_EQ(bytes.size(), 2);
|
||||
EXPECT_EQ(bytes[0], 0x1F);
|
||||
EXPECT_EQ(bytes[1], 0x3B);
|
||||
}
|
||||
|
||||
TEST(UConversionTest, uHex2BytesWithLength)
|
||||
{
|
||||
std::string hex = "1f3B";
|
||||
std::vector<char> bytes = uHex2Bytes(hex.c_str(), 4);
|
||||
EXPECT_EQ(bytes.size(), 2);
|
||||
EXPECT_EQ(bytes[0], 0x1F);
|
||||
EXPECT_EQ(bytes[1], 0x3B);
|
||||
}
|
||||
|
||||
TEST(UConversionTest, uHex2Str)
|
||||
{
|
||||
std::string hex = "48656C6C6F21";
|
||||
std::string result = uHex2Str(hex);
|
||||
EXPECT_EQ(result, "Hello!");
|
||||
}
|
||||
|
||||
TEST(UConversionTest, uHex2Ascii)
|
||||
{
|
||||
unsigned char c = 0xFA;
|
||||
unsigned char left = uHex2Ascii(c, false);
|
||||
unsigned char right = uHex2Ascii(c, true);
|
||||
EXPECT_EQ(left, 'F');
|
||||
EXPECT_EQ(right, 'A');
|
||||
}
|
||||
|
||||
TEST(UConversionTest, uAscii2Hex)
|
||||
{
|
||||
unsigned char result = uAscii2Hex('F');
|
||||
EXPECT_EQ(result, 0x0F);
|
||||
result = uAscii2Hex('a');
|
||||
EXPECT_EQ(result, 0x0A);
|
||||
}
|
||||
|
||||
TEST(UConversionTest, uFormat)
|
||||
{
|
||||
std::string result = uFormat("Hello %s %d", "world", 42);
|
||||
EXPECT_NE(result.find("Hello"), std::string::npos);
|
||||
EXPECT_NE(result.find("world"), std::string::npos);
|
||||
EXPECT_NE(result.find("42"), std::string::npos);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,242 @@
|
||||
#include "gtest/gtest.h"
|
||||
#include "rtabmap/utilite/UDirectory.h"
|
||||
#include "rtabmap/utilite/UFile.h"
|
||||
#include <cstdio>
|
||||
#include <fstream>
|
||||
|
||||
TEST(UDirectoryTest, Exists)
|
||||
{
|
||||
// Test with current directory (should exist)
|
||||
EXPECT_TRUE(UDirectory::exists("."));
|
||||
|
||||
// Test with nonexistent directory
|
||||
EXPECT_FALSE(UDirectory::exists("nonexistent_directory_xyz123"));
|
||||
}
|
||||
|
||||
TEST(UDirectoryTest, GetDir)
|
||||
{
|
||||
std::string filePath = "/path/to/file.txt";
|
||||
std::string dir = UDirectory::getDir(filePath);
|
||||
EXPECT_EQ(dir, "/path/to");
|
||||
|
||||
std::string filePath2 = "/path";
|
||||
std::string dir2 = UDirectory::getDir(filePath2);
|
||||
EXPECT_EQ(dir2, "/");
|
||||
|
||||
std::string filePath3 = "file.txt";
|
||||
std::string dir3 = UDirectory::getDir(filePath3);
|
||||
EXPECT_EQ(dir3, ".");
|
||||
|
||||
std::string filePath4 = "./file.txt";
|
||||
std::string dir4 = UDirectory::getDir(filePath4);
|
||||
EXPECT_EQ(dir4, ".");
|
||||
}
|
||||
|
||||
TEST(UDirectoryTest, CurrentDir)
|
||||
{
|
||||
std::string current = UDirectory::currentDir(false);
|
||||
EXPECT_GT(current.size(), 0);
|
||||
|
||||
std::string currentWithSep = UDirectory::currentDir(true);
|
||||
EXPECT_GT(currentWithSep.size(), 0);
|
||||
// Should end with separator if trailingSeparator is true
|
||||
std::string sep = UDirectory::separator();
|
||||
if(currentWithSep.size() > 0)
|
||||
{
|
||||
EXPECT_EQ(currentWithSep.back(), sep[0]);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(UDirectoryTest, MakeDir)
|
||||
{
|
||||
std::string testDir = "test_make_dir";
|
||||
// Remove if exists
|
||||
if(UDirectory::exists(testDir))
|
||||
{
|
||||
UDirectory::removeDir(testDir);
|
||||
}
|
||||
|
||||
bool result = UDirectory::makeDir(testDir);
|
||||
EXPECT_TRUE(result);
|
||||
EXPECT_TRUE(UDirectory::exists(testDir));
|
||||
|
||||
// Cleanup
|
||||
UDirectory::removeDir(testDir);
|
||||
}
|
||||
|
||||
TEST(UDirectoryTest, RemoveDir)
|
||||
{
|
||||
std::string testDir = "test_remove_dir";
|
||||
// Create if doesn't exist
|
||||
if(!UDirectory::exists(testDir))
|
||||
{
|
||||
UDirectory::makeDir(testDir);
|
||||
}
|
||||
|
||||
bool result = UDirectory::removeDir(testDir);
|
||||
EXPECT_TRUE(result);
|
||||
EXPECT_FALSE(UDirectory::exists(testDir));
|
||||
}
|
||||
|
||||
TEST(UDirectoryTest, HomeDir)
|
||||
{
|
||||
std::string home = UDirectory::homeDir();
|
||||
EXPECT_GT(home.size(), 0);
|
||||
}
|
||||
|
||||
TEST(UDirectoryTest, Separator)
|
||||
{
|
||||
std::string sep = UDirectory::separator();
|
||||
EXPECT_EQ(sep.size(), 1);
|
||||
#ifdef _WIN32
|
||||
EXPECT_EQ(sep, "\\");
|
||||
#else
|
||||
EXPECT_EQ(sep, "/");
|
||||
#endif
|
||||
}
|
||||
|
||||
TEST(UDirectoryTest, Constructor)
|
||||
{
|
||||
std::string testDir = ".";
|
||||
UDirectory dir(testDir);
|
||||
EXPECT_TRUE(dir.isValid());
|
||||
}
|
||||
|
||||
TEST(UDirectoryTest, SetPath)
|
||||
{
|
||||
UDirectory dir;
|
||||
dir.setPath(".");
|
||||
EXPECT_TRUE(dir.isValid());
|
||||
}
|
||||
|
||||
TEST(UDirectoryTest, GetNextFileName)
|
||||
{
|
||||
// Create a test directory with files
|
||||
std::string testDir = "test_dir_files";
|
||||
if(!UDirectory::exists(testDir))
|
||||
{
|
||||
UDirectory::makeDir(testDir);
|
||||
}
|
||||
|
||||
// Create some test files
|
||||
std::ofstream file1(testDir + UDirectory::separator() + "file1.txt");
|
||||
file1 << "content1";
|
||||
file1.close();
|
||||
|
||||
std::ofstream file2(testDir + UDirectory::separator() + "file2.txt");
|
||||
file2 << "content2";
|
||||
file2.close();
|
||||
|
||||
UDirectory dir(testDir);
|
||||
std::string name1 = dir.getNextFileName();
|
||||
std::string name2 = dir.getNextFileName();
|
||||
|
||||
EXPECT_STREQ(name1.c_str(), "file1.txt");
|
||||
EXPECT_STREQ(name2.c_str(), "file2.txt");
|
||||
|
||||
// Cleanup
|
||||
UFile::erase(testDir + UDirectory::separator() + "file1.txt");
|
||||
UFile::erase(testDir + UDirectory::separator() + "file2.txt");
|
||||
UDirectory::removeDir(testDir);
|
||||
}
|
||||
|
||||
TEST(UDirectoryTest, GetNextFilePath)
|
||||
{
|
||||
std::string testDir = "test_dir_paths";
|
||||
if(!UDirectory::exists(testDir))
|
||||
{
|
||||
UDirectory::makeDir(testDir);
|
||||
}
|
||||
|
||||
std::ofstream file(testDir + UDirectory::separator() + "test.txt");
|
||||
file << "content";
|
||||
file.close();
|
||||
|
||||
UDirectory dir(testDir);
|
||||
std::string path = dir.getNextFilePath();
|
||||
EXPECT_GT(path.size(), 0);
|
||||
EXPECT_NE(path.find("test.txt"), std::string::npos);
|
||||
|
||||
// Cleanup
|
||||
UFile::erase(testDir + UDirectory::separator() + "test.txt");
|
||||
UDirectory::removeDir(testDir);
|
||||
}
|
||||
|
||||
TEST(UDirectoryTest, GetFileNames)
|
||||
{
|
||||
std::string testDir = "test_dir_list";
|
||||
if(!UDirectory::exists(testDir))
|
||||
{
|
||||
UDirectory::makeDir(testDir);
|
||||
}
|
||||
|
||||
std::ofstream file1(testDir + UDirectory::separator() + "file1.txt");
|
||||
file1 << "content1";
|
||||
file1.close();
|
||||
|
||||
std::ofstream file2(testDir + UDirectory::separator() + "file2.txt");
|
||||
file2 << "content2";
|
||||
file2.close();
|
||||
|
||||
UDirectory dir(testDir);
|
||||
const std::list<std::string>& fileNames = dir.getFileNames();
|
||||
EXPECT_GE(fileNames.size(), 2);
|
||||
EXPECT_STREQ(fileNames.front().c_str(), "file1.txt");
|
||||
EXPECT_STREQ(fileNames.back().c_str(), "file2.txt");
|
||||
|
||||
// Cleanup
|
||||
UFile::erase(testDir + UDirectory::separator() + "file1.txt");
|
||||
UFile::erase(testDir + UDirectory::separator() + "file2.txt");
|
||||
UDirectory::removeDir(testDir);
|
||||
}
|
||||
|
||||
TEST(UDirectoryTest, Rewind)
|
||||
{
|
||||
std::string testDir = "test_dir_rewind";
|
||||
if(UDirectory::exists(testDir))
|
||||
{
|
||||
UDirectory::removeDir(testDir);
|
||||
}
|
||||
UDirectory::makeDir(testDir);
|
||||
std::ofstream file1(testDir + UDirectory::separator() + "file1.txt");
|
||||
file1 << "content1";
|
||||
file1.close();
|
||||
UDirectory dir(testDir);
|
||||
std::string name1 = dir.getNextFileName();
|
||||
EXPECT_FALSE(name1.empty());
|
||||
dir.rewind();
|
||||
std::string name2 = dir.getNextFileName();
|
||||
// Should get the same file name after rewind
|
||||
EXPECT_EQ(name1, name2);
|
||||
}
|
||||
|
||||
TEST(UDirectoryTest, ExtensionsFilter)
|
||||
{
|
||||
std::string testDir = "test_dir_ext";
|
||||
if(!UDirectory::exists(testDir))
|
||||
{
|
||||
UDirectory::makeDir(testDir);
|
||||
}
|
||||
|
||||
std::ofstream file1(testDir + UDirectory::separator() + "file1.txt");
|
||||
file1 << "content1";
|
||||
file1.close();
|
||||
|
||||
std::ofstream file2(testDir + UDirectory::separator() + "file2.jpg");
|
||||
file2 << "content2";
|
||||
file2.close();
|
||||
|
||||
UDirectory dir(testDir, "txt");
|
||||
const std::list<std::string>& fileNames = dir.getFileNames();
|
||||
// Should only get .txt files
|
||||
for(const std::string& name : fileNames)
|
||||
{
|
||||
EXPECT_NE(name.find(".txt"), std::string::npos);
|
||||
}
|
||||
|
||||
// Cleanup
|
||||
UFile::erase(testDir + UDirectory::separator() + "file1.txt");
|
||||
UFile::erase(testDir + UDirectory::separator() + "file2.jpg");
|
||||
UDirectory::removeDir(testDir);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,478 @@
|
||||
#include "gtest/gtest.h"
|
||||
#include "rtabmap/utilite/UEvent.h"
|
||||
#include "rtabmap/utilite/UEventsHandler.h"
|
||||
#include "rtabmap/utilite/UEventsManager.h"
|
||||
#include "rtabmap/utilite/UEventsSender.h"
|
||||
#include "rtabmap/utilite/UTimer.h"
|
||||
#include <thread>
|
||||
#include <chrono>
|
||||
#include <atomic>
|
||||
|
||||
// Test event classes
|
||||
class TestEvent : public UEvent
|
||||
{
|
||||
public:
|
||||
TestEvent(int code = 0) : UEvent(code) {}
|
||||
virtual ~TestEvent() {}
|
||||
virtual std::string getClassName() const {return "TestEvent";}
|
||||
};
|
||||
|
||||
class AnotherEvent : public UEvent
|
||||
{
|
||||
public:
|
||||
AnotherEvent() : UEvent(0) {}
|
||||
virtual ~AnotherEvent() {}
|
||||
virtual std::string getClassName() const {return "AnotherEvent";}
|
||||
};
|
||||
|
||||
// Test handler class
|
||||
class TestHandler : public UEventsHandler
|
||||
{
|
||||
public:
|
||||
TestHandler() : eventCount_(0), lastEventCode_(0){}
|
||||
|
||||
int getEventCount() const { return eventCount_; }
|
||||
int getLastEventCode() const { return lastEventCode_; }
|
||||
const std::string & getLastEventClassName() const { return lastEventClassName_; }
|
||||
void reset() { eventCount_ = 0; lastEventCode_ = 0; lastEventClassName_.clear(); }
|
||||
|
||||
protected:
|
||||
virtual bool handleEvent(UEvent * event)
|
||||
{
|
||||
eventCount_++;
|
||||
lastEventCode_ = event->getCode();
|
||||
lastEventClassName_ = event->getClassName();
|
||||
return false;
|
||||
}
|
||||
|
||||
private:
|
||||
int eventCount_;
|
||||
int lastEventCode_;
|
||||
std::string lastEventClassName_;
|
||||
bool ownershipTaken_;
|
||||
};
|
||||
|
||||
// Handler that takes ownership
|
||||
class OwnershipHandler : public UEventsHandler
|
||||
{
|
||||
public:
|
||||
OwnershipHandler() : event_(nullptr) {}
|
||||
~OwnershipHandler() {delete event_;}
|
||||
const UEvent * getEvent() const {return event_;}
|
||||
void reset() { delete event_; event_ = nullptr;}
|
||||
|
||||
protected:
|
||||
virtual bool handleEvent(UEvent * event)
|
||||
{
|
||||
event_ = event; // Take ownership
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
UEvent * event_;
|
||||
};
|
||||
|
||||
// Handler that filters events
|
||||
class FilteringHandler : public UEventsHandler
|
||||
{
|
||||
public:
|
||||
FilteringHandler() : testEventCount_(0), anotherEventCount_(0) {}
|
||||
int getTestEventCount() const { return testEventCount_; }
|
||||
int getAnotherEventCount() const { return anotherEventCount_; }
|
||||
void reset() { testEventCount_ = 0; anotherEventCount_ = 0; }
|
||||
|
||||
protected:
|
||||
virtual bool handleEvent(UEvent * event)
|
||||
{
|
||||
if(event->getClassName() == "TestEvent")
|
||||
{
|
||||
testEventCount_++;
|
||||
}
|
||||
else if(event->getClassName() == "AnotherEvent")
|
||||
{
|
||||
anotherEventCount_++;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private:
|
||||
int testEventCount_;
|
||||
int anotherEventCount_;
|
||||
};
|
||||
|
||||
// Test sender class that can post events
|
||||
class TestSender : public UEventsSender
|
||||
{
|
||||
public:
|
||||
TestSender() {}
|
||||
|
||||
// Public method to test protected post() method
|
||||
void testPost(UEvent* event, bool async = true) const
|
||||
{
|
||||
post(event, async);
|
||||
}
|
||||
};
|
||||
|
||||
TEST(UEventsTest, UEventGetClassName)
|
||||
{
|
||||
TestEvent event;
|
||||
EXPECT_EQ(event.getClassName(), "TestEvent");
|
||||
EXPECT_EQ(event.getCode(), 0);
|
||||
}
|
||||
|
||||
TEST(UEventsTest, UEventGetCode)
|
||||
{
|
||||
TestEvent event(42);
|
||||
EXPECT_EQ(event.getCode(), 42);
|
||||
}
|
||||
|
||||
TEST(UEventsTest, UEventsHandlerRegisterUnregister)
|
||||
{
|
||||
TestHandler handler;
|
||||
|
||||
// Register handler
|
||||
handler.registerToEventsManager();
|
||||
|
||||
// Post an event
|
||||
UEventsManager::post(new TestEvent(), true);
|
||||
|
||||
// Give time for event to be processed
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(50));
|
||||
|
||||
EXPECT_GT(handler.getEventCount(), 0);
|
||||
|
||||
// Unregister handler
|
||||
handler.unregisterFromEventsManager();
|
||||
|
||||
// Post another event
|
||||
int countBefore = handler.getEventCount();
|
||||
UEventsManager::post(new TestEvent(), true);
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(50));
|
||||
|
||||
// Should not receive event after unregister
|
||||
EXPECT_EQ(handler.getEventCount(), countBefore);
|
||||
}
|
||||
|
||||
TEST(UEventsTest, UEventsHandlerDestructorUnregisters)
|
||||
{
|
||||
TestHandler* handler = new TestHandler();
|
||||
handler->registerToEventsManager();
|
||||
|
||||
// Post an event
|
||||
UEventsManager::post(new TestEvent(), true);
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(50));
|
||||
|
||||
EXPECT_EQ(handler->getEventCount(), 1);
|
||||
|
||||
// Delete handler (should unregister automatically)
|
||||
handler->unregisterFromEventsManager();
|
||||
|
||||
// Post another event
|
||||
UEventsManager::post(new TestEvent(), true);
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(50));
|
||||
|
||||
EXPECT_EQ(handler->getEventCount(), 1);
|
||||
}
|
||||
|
||||
TEST(UEventsTest, UEventsManagerAddRemoveHandler)
|
||||
{
|
||||
TestHandler handler1;
|
||||
TestHandler handler2;
|
||||
|
||||
UEventsManager::addHandler(&handler1);
|
||||
UEventsManager::addHandler(&handler2);
|
||||
|
||||
UEventsManager::post(new TestEvent(), true);
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(50));
|
||||
|
||||
EXPECT_GT(handler1.getEventCount(), 0);
|
||||
EXPECT_GT(handler2.getEventCount(), 0);
|
||||
|
||||
UEventsManager::removeHandler(&handler1);
|
||||
|
||||
int count1Before = handler1.getEventCount();
|
||||
int count2Before = handler2.getEventCount();
|
||||
|
||||
UEventsManager::post(new TestEvent(), true);
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(50));
|
||||
|
||||
EXPECT_EQ(handler1.getEventCount(), count1Before);
|
||||
EXPECT_GT(handler2.getEventCount(), count2Before);
|
||||
|
||||
UEventsManager::removeHandler(&handler2);
|
||||
}
|
||||
|
||||
TEST(UEventsTest, UEventsManagerPostAsync)
|
||||
{
|
||||
TestHandler handler;
|
||||
UEventsManager::addHandler(&handler);
|
||||
|
||||
handler.reset();
|
||||
|
||||
UEventsManager::post(new TestEvent(), true);
|
||||
|
||||
// Give time for async processing
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(100));
|
||||
|
||||
EXPECT_GT(handler.getEventCount(), 0);
|
||||
|
||||
UEventsManager::removeHandler(&handler);
|
||||
}
|
||||
|
||||
TEST(UEventsTest, UEventsManagerPostSync)
|
||||
{
|
||||
TestHandler handler;
|
||||
UEventsManager::addHandler(&handler);
|
||||
|
||||
handler.reset();
|
||||
|
||||
UEventsManager::post(new TestEvent(), false);
|
||||
|
||||
// Sync should be immediate
|
||||
EXPECT_GT(handler.getEventCount(), 0);
|
||||
|
||||
UEventsManager::removeHandler(&handler);
|
||||
}
|
||||
|
||||
TEST(UEventsTest, UEventsManagerMultipleHandlers)
|
||||
{
|
||||
TestHandler handler1;
|
||||
TestHandler handler2;
|
||||
TestHandler handler3;
|
||||
|
||||
UEventsManager::addHandler(&handler1);
|
||||
UEventsManager::addHandler(&handler2);
|
||||
UEventsManager::addHandler(&handler3);
|
||||
|
||||
handler1.reset();
|
||||
handler2.reset();
|
||||
handler3.reset();
|
||||
|
||||
UEventsManager::post(new TestEvent(), true);
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(50));
|
||||
|
||||
EXPECT_GT(handler1.getEventCount(), 0);
|
||||
EXPECT_GT(handler2.getEventCount(), 0);
|
||||
EXPECT_GT(handler3.getEventCount(), 0);
|
||||
|
||||
UEventsManager::removeHandler(&handler1);
|
||||
UEventsManager::removeHandler(&handler2);
|
||||
UEventsManager::removeHandler(&handler3);
|
||||
}
|
||||
|
||||
TEST(UEventsTest, UEventsManagerEventOrdering)
|
||||
{
|
||||
TestHandler handler;
|
||||
UEventsManager::addHandler(&handler);
|
||||
|
||||
handler.reset();
|
||||
|
||||
// Post multiple events
|
||||
UEventsManager::post(new TestEvent(1), true);
|
||||
UEventsManager::post(new TestEvent(2), true);
|
||||
UEventsManager::post(new TestEvent(3), true);
|
||||
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(100));
|
||||
|
||||
// Should receive all events (order may vary in async mode)
|
||||
EXPECT_GE(handler.getEventCount(), 3);
|
||||
|
||||
UEventsManager::removeHandler(&handler);
|
||||
}
|
||||
|
||||
TEST(UEventsTest, UEventsHandlerOwnership)
|
||||
{
|
||||
OwnershipHandler handler;
|
||||
TestHandler handler0;
|
||||
TestHandler handler2;
|
||||
UEventsManager::addHandler(&handler0);
|
||||
UEventsManager::addHandler(&handler);
|
||||
UEventsManager::addHandler(&handler2);
|
||||
|
||||
UEventsManager::post(new TestEvent(42), true);
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(50));
|
||||
|
||||
EXPECT_NE(handler.getEvent(), nullptr);
|
||||
EXPECT_EQ(handler.getEvent()->getCode(), 42);
|
||||
|
||||
// Should have received the event
|
||||
EXPECT_GT(handler0.getEventCount(), 0);
|
||||
|
||||
// Should not have received the event
|
||||
EXPECT_EQ(handler2.getEventCount(), 0);
|
||||
|
||||
UEventsManager::removeHandler(&handler0);
|
||||
UEventsManager::removeHandler(&handler);
|
||||
UEventsManager::removeHandler(&handler2);
|
||||
}
|
||||
|
||||
TEST(UEventsTest, UEventsHandlerFiltering)
|
||||
{
|
||||
FilteringHandler handler;
|
||||
UEventsManager::addHandler(&handler);
|
||||
|
||||
handler.reset();
|
||||
|
||||
UEventsManager::post(new TestEvent(), true);
|
||||
UEventsManager::post(new AnotherEvent(), true);
|
||||
UEventsManager::post(new TestEvent(), true);
|
||||
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(100));
|
||||
|
||||
EXPECT_EQ(handler.getTestEventCount(), 2);
|
||||
EXPECT_EQ(handler.getAnotherEventCount(), 1);
|
||||
|
||||
UEventsManager::removeHandler(&handler);
|
||||
}
|
||||
|
||||
TEST(UEventsTest, UEventsSenderPost)
|
||||
{
|
||||
TestSender sender;
|
||||
TestHandler handler;
|
||||
|
||||
UEventsManager::addHandler(&handler);
|
||||
|
||||
handler.reset();
|
||||
|
||||
// Test protected post() method through TestSender
|
||||
sender.testPost(new TestEvent(), true);
|
||||
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(50));
|
||||
|
||||
EXPECT_GT(handler.getEventCount(), 0);
|
||||
|
||||
UEventsManager::removeHandler(&handler);
|
||||
}
|
||||
|
||||
TEST(UEventsTest, UEventsSenderDestructorRemovesPipes)
|
||||
{
|
||||
TestSender* sender = new TestSender();
|
||||
TestHandler handler;
|
||||
|
||||
UEventsManager::addHandler(&handler);
|
||||
UEventsManager::createPipe(sender, &handler, "TestEvent");
|
||||
|
||||
// Delete sender - should remove pipes automatically
|
||||
delete sender;
|
||||
|
||||
// Should not crash and pipes should be removed
|
||||
SUCCEED();
|
||||
|
||||
UEventsManager::removeHandler(&handler);
|
||||
}
|
||||
|
||||
TEST(UEventsTest, UEventsManagerCreateRemovePipe)
|
||||
{
|
||||
TestSender sender;
|
||||
TestHandler handler;
|
||||
TestHandler handler2;
|
||||
|
||||
UEventsManager::addHandler(&handler);
|
||||
UEventsManager::addHandler(&handler2);
|
||||
|
||||
// Create a pipe
|
||||
UEventsManager::createPipe(&sender, &handler, "TestEvent");
|
||||
|
||||
handler.reset();
|
||||
|
||||
// Post event with sender
|
||||
sender.testPost(new TestEvent());
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(50));
|
||||
EXPECT_EQ(handler.getEventCount(), 1);
|
||||
EXPECT_EQ(handler2.getEventCount(), 0);
|
||||
|
||||
// Post event with sender using UEventsManager
|
||||
UEventsManager::post(new TestEvent(), true, &sender);
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(50));
|
||||
EXPECT_EQ(handler.getEventCount(), 2);
|
||||
EXPECT_EQ(handler2.getEventCount(), 0);
|
||||
|
||||
// Post global event
|
||||
UEventsManager::post(new TestEvent(), true);
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(50));
|
||||
EXPECT_EQ(handler.getEventCount(), 3);
|
||||
EXPECT_EQ(handler2.getEventCount(), 1);
|
||||
|
||||
// Remove pipe
|
||||
UEventsManager::removePipe(&sender, &handler, "TestEvent");
|
||||
|
||||
|
||||
// Post another event
|
||||
UEventsManager::post(new TestEvent(), true, &sender);
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(50));
|
||||
|
||||
// Should still receive events, no pipe filtering
|
||||
EXPECT_EQ(handler.getEventCount(), 4);
|
||||
EXPECT_EQ(handler2.getEventCount(), 2);
|
||||
|
||||
UEventsManager::removeHandler(&handler);
|
||||
UEventsManager::removeHandler(&handler2);
|
||||
}
|
||||
|
||||
TEST(UEventsTest, UEventsManagerRemoveAllPipes)
|
||||
{
|
||||
TestSender sender;
|
||||
TestHandler handler1;
|
||||
TestHandler handler2;
|
||||
|
||||
UEventsManager::addHandler(&handler1);
|
||||
UEventsManager::addHandler(&handler2);
|
||||
|
||||
UEventsManager::createPipe(&sender, &handler1, "TestEvent");
|
||||
UEventsManager::createPipe(&sender, &handler2, "AnotherEvent");
|
||||
|
||||
sender.testPost(new TestEvent());
|
||||
sender.testPost(new AnotherEvent());
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(50));
|
||||
EXPECT_EQ(handler1.getEventCount(), 1);
|
||||
EXPECT_EQ(handler2.getEventCount(), 1);
|
||||
|
||||
UEventsManager::removeAllPipes(&sender);
|
||||
|
||||
sender.testPost(new TestEvent());
|
||||
sender.testPost(new AnotherEvent());
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(50));
|
||||
EXPECT_EQ(handler1.getEventCount(), 3);
|
||||
EXPECT_EQ(handler2.getEventCount(), 3);
|
||||
|
||||
UEventsManager::removeHandler(&handler1);
|
||||
UEventsManager::removeHandler(&handler2);
|
||||
}
|
||||
|
||||
TEST(UEventsTest, MultipleEventTypes)
|
||||
{
|
||||
FilteringHandler handler;
|
||||
UEventsManager::addHandler(&handler);
|
||||
|
||||
handler.reset();
|
||||
|
||||
UEventsManager::post(new TestEvent(), true);
|
||||
UEventsManager::post(new AnotherEvent(), true);
|
||||
UEventsManager::post(new TestEvent(), true);
|
||||
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(100));
|
||||
|
||||
EXPECT_EQ(handler.getTestEventCount(), 2);
|
||||
EXPECT_EQ(handler.getAnotherEventCount(), 1);
|
||||
|
||||
UEventsManager::removeHandler(&handler);
|
||||
}
|
||||
|
||||
TEST(UEventsTest, HandlerReceivesCorrectEvent)
|
||||
{
|
||||
TestHandler handler;
|
||||
UEventsManager::addHandler(&handler);
|
||||
|
||||
handler.reset();
|
||||
|
||||
TestEvent* event = new TestEvent(42);
|
||||
UEventsManager::post(event, true);
|
||||
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(50));
|
||||
|
||||
EXPECT_EQ(handler.getLastEventCode(), 42);
|
||||
EXPECT_STREQ(handler.getLastEventClassName().c_str(), "TestEvent");
|
||||
|
||||
UEventsManager::removeHandler(&handler);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,145 @@
|
||||
#include "gtest/gtest.h"
|
||||
#include "rtabmap/utilite/UFile.h"
|
||||
#include "rtabmap/utilite/UDirectory.h"
|
||||
#include <fstream>
|
||||
#include <cstdio>
|
||||
|
||||
TEST(UFileTest, Exists)
|
||||
{
|
||||
// Create a temporary file
|
||||
std::string testFile = "test_file_exists.txt";
|
||||
std::ofstream file(testFile);
|
||||
file << "test content";
|
||||
file.close();
|
||||
|
||||
EXPECT_TRUE(UFile::exists(testFile));
|
||||
EXPECT_FALSE(UFile::exists("nonexistent_file.txt"));
|
||||
|
||||
// Cleanup
|
||||
std::remove(testFile.c_str());
|
||||
}
|
||||
|
||||
TEST(UFileTest, Length)
|
||||
{
|
||||
std::string testFile = "test_file_length.txt";
|
||||
std::string content = "test content";
|
||||
std::ofstream file(testFile);
|
||||
file << content;
|
||||
file.close();
|
||||
|
||||
long length = UFile::length(testFile);
|
||||
EXPECT_EQ(length, static_cast<long>(content.size()));
|
||||
|
||||
long lengthNonexistent = UFile::length("nonexistent_file.txt");
|
||||
EXPECT_EQ(lengthNonexistent, 0);
|
||||
|
||||
// Cleanup
|
||||
std::remove(testFile.c_str());
|
||||
}
|
||||
|
||||
TEST(UFileTest, Erase)
|
||||
{
|
||||
std::string testFile = "test_file_erase.txt";
|
||||
std::ofstream file(testFile);
|
||||
file << "test content";
|
||||
file.close();
|
||||
|
||||
EXPECT_TRUE(UFile::exists(testFile));
|
||||
int result = UFile::erase(testFile);
|
||||
EXPECT_EQ(result, 0);
|
||||
EXPECT_FALSE(UFile::exists(testFile));
|
||||
}
|
||||
|
||||
TEST(UFileTest, Rename)
|
||||
{
|
||||
std::string oldFile = "test_file_old.txt";
|
||||
std::string newFile = "test_file_new.txt";
|
||||
std::ofstream file(oldFile);
|
||||
file << "test content";
|
||||
file.close();
|
||||
|
||||
int result = UFile::rename(oldFile, newFile);
|
||||
EXPECT_EQ(result, 0);
|
||||
EXPECT_FALSE(UFile::exists(oldFile));
|
||||
EXPECT_TRUE(UFile::exists(newFile));
|
||||
|
||||
// Cleanup
|
||||
std::remove(newFile.c_str());
|
||||
}
|
||||
|
||||
TEST(UFileTest, GetName)
|
||||
{
|
||||
std::string path = "/path/to/file.txt";
|
||||
std::string name = UFile::getName(path);
|
||||
EXPECT_EQ(name, "file.txt");
|
||||
|
||||
std::string path2 = "file.txt";
|
||||
std::string name2 = UFile::getName(path2);
|
||||
EXPECT_EQ(name2, "file.txt");
|
||||
}
|
||||
|
||||
TEST(UFileTest, GetExtension)
|
||||
{
|
||||
std::string path = "/path/to/file.txt";
|
||||
std::string ext = UFile::getExtension(path);
|
||||
EXPECT_EQ(ext, "txt");
|
||||
|
||||
std::string path2 = "file";
|
||||
std::string ext2 = UFile::getExtension(path2);
|
||||
EXPECT_STREQ(ext2.c_str(), "");
|
||||
}
|
||||
|
||||
TEST(UFileTest, Copy)
|
||||
{
|
||||
std::string sourceFile = "test_file_source.txt";
|
||||
std::string destFile = "test_file_dest.txt";
|
||||
std::string content = "test content";
|
||||
|
||||
std::ofstream file(sourceFile);
|
||||
file << content;
|
||||
file.close();
|
||||
|
||||
UFile::copy(sourceFile, destFile);
|
||||
EXPECT_TRUE(UFile::exists(destFile));
|
||||
EXPECT_EQ(UFile::length(destFile), static_cast<long>(content.size()));
|
||||
|
||||
// Cleanup
|
||||
std::remove(sourceFile.c_str());
|
||||
std::remove(destFile.c_str());
|
||||
}
|
||||
|
||||
TEST(UFileTest, InstanceMethods)
|
||||
{
|
||||
std::string testFile = "test_file_instance.txt";
|
||||
std::ofstream file(testFile);
|
||||
file << "test content";
|
||||
file.close();
|
||||
|
||||
UFile ufile(testFile);
|
||||
EXPECT_TRUE(ufile.isValid());
|
||||
EXPECT_TRUE(ufile.exists());
|
||||
EXPECT_GT(ufile.length(), 0);
|
||||
EXPECT_EQ(ufile.getName(), "test_file_instance.txt");
|
||||
EXPECT_EQ(ufile.getExtension(), "txt");
|
||||
|
||||
// Cleanup
|
||||
std::remove(testFile.c_str());
|
||||
}
|
||||
|
||||
TEST(UFileTest, InstanceRename)
|
||||
{
|
||||
std::string testFile = "test_file_rename_old.txt";
|
||||
std::ofstream file(testFile);
|
||||
file << "test content";
|
||||
file.close();
|
||||
|
||||
UFile ufile(testFile);
|
||||
int result = ufile.rename("test_file_rename_new");
|
||||
EXPECT_EQ(result, 0);
|
||||
EXPECT_FALSE(UFile::exists(testFile));
|
||||
EXPECT_TRUE(UFile::exists("test_file_rename_new.txt"));
|
||||
|
||||
// Cleanup
|
||||
std::remove("test_file_rename_new.txt");
|
||||
}
|
||||
|
||||
@@ -0,0 +1,774 @@
|
||||
#include "gtest/gtest.h"
|
||||
#include "rtabmap/utilite/ULogger.h"
|
||||
#include "rtabmap/utilite/UFile.h"
|
||||
#include "rtabmap/utilite/UThread.h"
|
||||
#include "rtabmap/utilite/UStl.h"
|
||||
#include <fstream>
|
||||
#include <sstream>
|
||||
#include <thread>
|
||||
|
||||
TEST(ULoggerTest, DefaultState)
|
||||
{
|
||||
ULogger::reset();
|
||||
|
||||
EXPECT_EQ(ULogger::type(), ULogger::kTypeNoLog);
|
||||
EXPECT_EQ(ULogger::level(), ULogger::kInfo);
|
||||
EXPECT_TRUE(ULogger::isPrintTime());
|
||||
EXPECT_TRUE(ULogger::isPrintLevel());
|
||||
EXPECT_TRUE(ULogger::isPrintEndLine());
|
||||
EXPECT_TRUE(ULogger::isPrintColored());
|
||||
EXPECT_TRUE(ULogger::isPrintWhere());
|
||||
EXPECT_FALSE(ULogger::isPrintWhereFullPath());
|
||||
EXPECT_FALSE(ULogger::isPrintThreadId());
|
||||
EXPECT_FALSE(ULogger::isBuffered());
|
||||
}
|
||||
|
||||
TEST(ULoggerTest, SetType)
|
||||
{
|
||||
ULogger::setType(ULogger::kTypeConsole);
|
||||
EXPECT_EQ(ULogger::type(), ULogger::kTypeConsole);
|
||||
|
||||
ULogger::setType(ULogger::kTypeNoLog);
|
||||
EXPECT_EQ(ULogger::type(), ULogger::kTypeNoLog);
|
||||
|
||||
ULogger::setType(ULogger::kTypeFile, "test_log.txt", false);
|
||||
EXPECT_EQ(ULogger::type(), ULogger::kTypeFile);
|
||||
|
||||
// Cleanup
|
||||
UFile::erase("test_log.txt");
|
||||
}
|
||||
|
||||
TEST(ULoggerTest, SetLevel)
|
||||
{
|
||||
ULogger::setLevel(ULogger::kDebug);
|
||||
EXPECT_EQ(ULogger::level(), ULogger::kDebug);
|
||||
|
||||
ULogger::setLevel(ULogger::kInfo);
|
||||
EXPECT_EQ(ULogger::level(), ULogger::kInfo);
|
||||
|
||||
ULogger::setLevel(ULogger::kWarning);
|
||||
EXPECT_EQ(ULogger::level(), ULogger::kWarning);
|
||||
|
||||
ULogger::setLevel(ULogger::kError);
|
||||
EXPECT_EQ(ULogger::level(), ULogger::kError);
|
||||
|
||||
ULogger::setLevel(ULogger::kFatal);
|
||||
EXPECT_EQ(ULogger::level(), ULogger::kFatal);
|
||||
}
|
||||
|
||||
TEST(ULoggerTest, LevelFiltering)
|
||||
{
|
||||
ULogger::reset();
|
||||
std::string testFile = "logger_level_filtering_test.txt";
|
||||
ULogger::setType(ULogger::kTypeFile, testFile, false);
|
||||
|
||||
ULogger::setLevel(ULogger::kInfo);
|
||||
|
||||
// Debug should not be logged
|
||||
UDEBUG("This debug message should not appear");
|
||||
|
||||
// Info and above should be logged
|
||||
UINFO("This info message should appear");
|
||||
UWARN("This warning message should appear");
|
||||
UERROR("This error message should appear");
|
||||
|
||||
// Make sure the log file is closed
|
||||
ULogger::setType(ULogger::kTypeNoLog);
|
||||
|
||||
std::ifstream file(testFile);
|
||||
std::string fileContent(
|
||||
(std::istreambuf_iterator<char>(file)), // Start iterator
|
||||
std::istreambuf_iterator<char>() // End iterator
|
||||
);
|
||||
file.close();
|
||||
|
||||
EXPECT_FALSE(uStrContains(fileContent, "DEBUG"));
|
||||
EXPECT_TRUE(uStrContains(fileContent, "INFO"));
|
||||
EXPECT_TRUE(uStrContains(fileContent, "WARN"));
|
||||
EXPECT_TRUE(uStrContains(fileContent, "ERROR"));
|
||||
}
|
||||
|
||||
TEST(ULoggerTest, SetPrintTime)
|
||||
{
|
||||
ULogger::reset();
|
||||
|
||||
std::string testFile = "logger_print_time_test.txt";
|
||||
ULogger::setType(ULogger::kTypeFile, testFile, false);
|
||||
|
||||
ULogger::setPrintTime(false);
|
||||
EXPECT_FALSE(ULogger::isPrintTime());
|
||||
UINFO("This info message should appear without time");
|
||||
|
||||
ULogger::setPrintTime(true);
|
||||
EXPECT_TRUE(ULogger::isPrintTime());
|
||||
UINFO("This info message should appear with time");
|
||||
|
||||
// Make sure the log file is closed
|
||||
ULogger::setType(ULogger::kTypeNoLog);
|
||||
|
||||
std::ifstream file(testFile);
|
||||
std::string line;
|
||||
EXPECT_TRUE(file.is_open());
|
||||
|
||||
// First line should not have date
|
||||
std::getline(file, line);
|
||||
EXPECT_EQ(uSplit(line, '-').size(), 1);
|
||||
// Time is format YYYY-MM-DD HH:MM:SS
|
||||
std::getline(file, line);
|
||||
EXPECT_EQ(uSplit(line, '-').size(), 3);
|
||||
file.close();
|
||||
}
|
||||
|
||||
TEST(ULoggerTest, SetPrintLevel)
|
||||
{
|
||||
ULogger::reset();
|
||||
|
||||
std::string testFile = "logger_print_level_test.txt";
|
||||
ULogger::setType(ULogger::kTypeFile, testFile, false);
|
||||
|
||||
ULogger::setPrintLevel(false);
|
||||
EXPECT_FALSE(ULogger::isPrintLevel());
|
||||
UINFO("This info message should appear without level");
|
||||
|
||||
ULogger::setPrintLevel(true);
|
||||
EXPECT_TRUE(ULogger::isPrintLevel());
|
||||
UINFO("This info message should appear with level");
|
||||
|
||||
// Make sure the log file is closed
|
||||
ULogger::setType(ULogger::kTypeNoLog);
|
||||
|
||||
std::ifstream file(testFile);
|
||||
std::string line;
|
||||
EXPECT_TRUE(file.is_open());
|
||||
|
||||
// First line should not have level
|
||||
std::getline(file, line);
|
||||
EXPECT_EQ(uSplit(line, ']').size(), 1);
|
||||
// Level format: [INFO] msg...
|
||||
std::getline(file, line);
|
||||
EXPECT_EQ(uSplit(line, ']').size(), 2);
|
||||
file.close();
|
||||
}
|
||||
|
||||
TEST(ULoggerTest, SetPrintEndline)
|
||||
{
|
||||
ULogger::reset();
|
||||
std::string testFile = "logger_print_endline_test.txt";
|
||||
ULogger::setType(ULogger::kTypeFile, testFile, false);
|
||||
|
||||
ULogger::setPrintEndline(false);
|
||||
EXPECT_FALSE(ULogger::isPrintEndLine());
|
||||
UINFO("This info message should appear first. ");
|
||||
|
||||
ULogger::setPrintEndline(true);
|
||||
EXPECT_TRUE(ULogger::isPrintEndLine());
|
||||
UINFO("This info message should appear on same line than previous msg.");
|
||||
|
||||
// Make sure the log file is closed
|
||||
ULogger::setType(ULogger::kTypeNoLog);
|
||||
|
||||
std::ifstream file(testFile);
|
||||
std::string line;
|
||||
EXPECT_TRUE(file.is_open());
|
||||
|
||||
// First line should not have level
|
||||
std::getline(file, line);
|
||||
EXPECT_FALSE(line.empty());
|
||||
std::getline(file, line);
|
||||
EXPECT_TRUE(line.empty());
|
||||
file.close();
|
||||
}
|
||||
|
||||
TEST(ULoggerTest, SetPrintColored)
|
||||
{
|
||||
ULogger::reset();
|
||||
|
||||
ULogger::setPrintColored(false);
|
||||
EXPECT_FALSE(ULogger::isPrintColored());
|
||||
|
||||
ULogger::setPrintColored(true);
|
||||
EXPECT_TRUE(ULogger::isPrintColored());
|
||||
}
|
||||
|
||||
TEST(ULoggerTest, SetPrintWhere)
|
||||
{
|
||||
ULogger::reset();
|
||||
std::string testFile = "logger_print_where_test.txt";
|
||||
ULogger::setType(ULogger::kTypeFile, testFile, false);
|
||||
|
||||
ULogger::setPrintWhere(false);
|
||||
EXPECT_FALSE(ULogger::isPrintWhere());
|
||||
UINFO("This info message should appear without where");
|
||||
|
||||
ULogger::setPrintWhere(true);
|
||||
EXPECT_TRUE(ULogger::isPrintWhere());
|
||||
UINFO("This info message should appear with where");
|
||||
|
||||
// Make sure the log file is closed
|
||||
ULogger::setType(ULogger::kTypeNoLog);
|
||||
|
||||
std::ifstream file(testFile);
|
||||
std::string line;
|
||||
EXPECT_TRUE(file.is_open());
|
||||
|
||||
// First line should not have where (no test_ulogger.cpp)
|
||||
std::getline(file, line);
|
||||
EXPECT_FALSE(uStrContains(line, "test_ulogger.cpp"));
|
||||
std::getline(file, line);
|
||||
EXPECT_TRUE(uStrContains(line, "test_ulogger.cpp"));
|
||||
file.close();
|
||||
}
|
||||
|
||||
TEST(ULoggerTest, SetPrintWhereFullPath)
|
||||
{
|
||||
ULogger::reset();
|
||||
std::string testFile = "logger_print_where_full_test.txt";
|
||||
ULogger::setType(ULogger::kTypeFile, testFile, false);
|
||||
|
||||
ULogger::setPrintWhereFullPath(false);
|
||||
EXPECT_FALSE(ULogger::isPrintWhereFullPath());
|
||||
UINFO("This info message should appear without full path");
|
||||
|
||||
ULogger::setPrintWhereFullPath(true);
|
||||
EXPECT_TRUE(ULogger::isPrintWhereFullPath());
|
||||
UINFO("This info message should appear with full path");
|
||||
|
||||
// Make sure the log file is closed
|
||||
ULogger::setType(ULogger::kTypeNoLog);
|
||||
|
||||
std::ifstream file(testFile);
|
||||
std::string line;
|
||||
EXPECT_TRUE(file.is_open());
|
||||
|
||||
// First line should not have full path (without / or \\)
|
||||
std::getline(file, line);
|
||||
EXPECT_TRUE(!uStrContains(line, "/") && !uStrContains(line, "\\"));
|
||||
std::getline(file, line);
|
||||
EXPECT_TRUE(uStrContains(line, "/") || uStrContains(line, "\\"));
|
||||
file.close();
|
||||
}
|
||||
|
||||
TEST(ULoggerTest, SetPrintThreadId)
|
||||
{
|
||||
ULogger::reset();
|
||||
std::string testFile = "logger_print_thread_id_test.txt";
|
||||
ULogger::setType(ULogger::kTypeFile, testFile, false);
|
||||
|
||||
ULogger::setPrintThreadId(false);
|
||||
EXPECT_FALSE(ULogger::isPrintThreadId());
|
||||
UINFO("This info message should appear without thread ID");
|
||||
|
||||
ULogger::setPrintThreadId(true);
|
||||
EXPECT_TRUE(ULogger::isPrintThreadId());
|
||||
UINFO("This info message should appear with thread ID");
|
||||
|
||||
// Make sure the log file is closed
|
||||
ULogger::setType(ULogger::kTypeNoLog);
|
||||
|
||||
std::ifstream file(testFile);
|
||||
std::string line;
|
||||
EXPECT_TRUE(file.is_open());
|
||||
|
||||
// First line should not have thread ID (without {})
|
||||
std::getline(file, line);
|
||||
EXPECT_TRUE(!uStrContains(line, "{") && !uStrContains(line, "}"));
|
||||
std::getline(file, line);
|
||||
EXPECT_TRUE(uStrContains(line, "{") && uStrContains(line, "}"));
|
||||
file.close();
|
||||
}
|
||||
|
||||
TEST(ULoggerTest, SetBuffered)
|
||||
{
|
||||
ULogger::reset();
|
||||
ULogger::setBuffered(true);
|
||||
EXPECT_TRUE(ULogger::isBuffered());
|
||||
|
||||
ULogger::setBuffered(false);
|
||||
EXPECT_FALSE(ULogger::isBuffered());
|
||||
}
|
||||
|
||||
TEST(ULoggerTest, FileLogging)
|
||||
{
|
||||
ULogger::reset();
|
||||
std::string testFile = "test_ulogger_file.txt";
|
||||
|
||||
// Remove file if exists
|
||||
if(UFile::exists(testFile))
|
||||
{
|
||||
UFile::erase(testFile);
|
||||
}
|
||||
|
||||
ULogger::setType(ULogger::kTypeFile, testFile, false);
|
||||
ULogger::setLevel(ULogger::kDebug);
|
||||
|
||||
UINFO("Test message 1");
|
||||
UWARN("Test message 2");
|
||||
UERROR("Test message 3");
|
||||
|
||||
// Make sure everything is written to file
|
||||
ULogger::setType(ULogger::kTypeNoLog);
|
||||
|
||||
// Check file exists and has content
|
||||
EXPECT_TRUE(UFile::exists(testFile));
|
||||
EXPECT_GT(UFile::length(testFile), 0);
|
||||
}
|
||||
|
||||
TEST(ULoggerTest, FileLoggingAppend)
|
||||
{
|
||||
ULogger::reset();
|
||||
std::string testFile = "test_ulogger_append.txt";
|
||||
|
||||
// Remove file if exists
|
||||
if(UFile::exists(testFile))
|
||||
{
|
||||
UFile::erase(testFile);
|
||||
}
|
||||
|
||||
ULogger::setType(ULogger::kTypeFile, testFile, false);
|
||||
ULogger::setLevel(ULogger::kInfo);
|
||||
|
||||
UINFO("First message");
|
||||
// Make sure everything is written to file
|
||||
ULogger::setType(ULogger::kTypeNoLog);
|
||||
|
||||
long length1 = UFile::length(testFile);
|
||||
|
||||
// Append mode
|
||||
ULogger::setType(ULogger::kTypeFile, testFile, true);
|
||||
UINFO("Second message");
|
||||
// Make sure everything is written to file
|
||||
ULogger::setType(ULogger::kTypeNoLog);
|
||||
|
||||
long length2 = UFile::length(testFile);
|
||||
EXPECT_GT(length2, length1);
|
||||
}
|
||||
|
||||
TEST(ULoggerTest, BufferedLogging)
|
||||
{
|
||||
ULogger::reset();
|
||||
std::string testFile = "test_ulogger_buffered.txt";
|
||||
|
||||
// Remove file if exists
|
||||
if(UFile::exists(testFile))
|
||||
{
|
||||
UFile::erase(testFile);
|
||||
}
|
||||
|
||||
ULogger::setType(ULogger::kTypeFile, testFile, false);
|
||||
ULogger::setBuffered(true);
|
||||
ULogger::setLevel(ULogger::kInfo);
|
||||
|
||||
UINFO("Buffered message 1");
|
||||
UINFO("Buffered message 2");
|
||||
|
||||
// File should be empty before flush
|
||||
EXPECT_EQ(UFile::length(testFile), 0);
|
||||
|
||||
// Make sure everything is written to file
|
||||
ULogger::setType(ULogger::kTypeNoLog);
|
||||
|
||||
// File should have content after flush
|
||||
EXPECT_GT(UFile::length(testFile), 0);
|
||||
}
|
||||
|
||||
TEST(ULoggerTest, GetTime)
|
||||
{
|
||||
std::string timeStr;
|
||||
int result = ULogger::getTime(timeStr);
|
||||
|
||||
EXPECT_GT(result, 0);
|
||||
EXPECT_GT(timeStr.size(), 0u);
|
||||
|
||||
// Time string should contain date/time format
|
||||
// Format is typically "YYYY-MM-DD HH:MM:SS" or similar
|
||||
EXPECT_NE(timeStr.find("-"), std::string::npos);
|
||||
}
|
||||
|
||||
TEST(ULoggerTest, SetEventLevel)
|
||||
{
|
||||
ULogger::reset();
|
||||
|
||||
ULogger::setEventLevel(ULogger::kDebug);
|
||||
EXPECT_EQ(ULogger::eventLevel(), ULogger::kDebug);
|
||||
|
||||
ULogger::setEventLevel(ULogger::kInfo);
|
||||
EXPECT_EQ(ULogger::eventLevel(), ULogger::kInfo);
|
||||
|
||||
ULogger::setEventLevel(ULogger::kWarning);
|
||||
EXPECT_EQ(ULogger::eventLevel(), ULogger::kWarning);
|
||||
|
||||
ULogger::setEventLevel(ULogger::kError);
|
||||
EXPECT_EQ(ULogger::eventLevel(), ULogger::kError);
|
||||
}
|
||||
|
||||
TEST(ULoggerTest, RegisterCurrentThread)
|
||||
{
|
||||
ULogger::reset();
|
||||
ULogger::registerCurrentThread("TestThread");
|
||||
|
||||
std::map<std::string, unsigned long> threads = ULogger::getRegisteredThreads();
|
||||
EXPECT_GT(threads.size(), 0u);
|
||||
EXPECT_NE(threads.find("TestThread"), threads.end());
|
||||
|
||||
ULogger::unregisterCurrentThread();
|
||||
|
||||
threads = ULogger::getRegisteredThreads();
|
||||
EXPECT_EQ(threads.find("TestThread"), threads.end());
|
||||
}
|
||||
|
||||
TEST(ULoggerTest, ThreadIdFilter)
|
||||
{
|
||||
ULogger::reset();
|
||||
|
||||
unsigned long currentId = UThread::currentThreadId();
|
||||
std::set<unsigned long> filter;
|
||||
filter.insert(currentId);
|
||||
|
||||
ULogger::setTreadIdFilter(filter);
|
||||
|
||||
const std::set<unsigned long>& retrieved = ULogger::getTreadIdFilter();
|
||||
EXPECT_EQ(retrieved.size(), 1u);
|
||||
EXPECT_NE(retrieved.find(currentId), retrieved.end());
|
||||
}
|
||||
|
||||
class OtherThread : public UThread
|
||||
{
|
||||
public:
|
||||
OtherThread() : logOnce_(false) {}
|
||||
std::string name() {return "OtherThread";}
|
||||
void logOnce() {logOnce_ = true;}
|
||||
protected:
|
||||
virtual void mainLoopBegin() {ULogger::registerCurrentThread(name());}
|
||||
virtual void mainLoopEnd() {ULogger::unregisterCurrentThread();}
|
||||
virtual void mainLoop() {
|
||||
uSleep(10);
|
||||
if(logOnce_)
|
||||
{
|
||||
UINFO("Logging from OtherThread");
|
||||
logOnce_ = false;
|
||||
}
|
||||
}
|
||||
private:
|
||||
bool logOnce_;
|
||||
};
|
||||
|
||||
TEST(ULoggerTest, ThreadIdFilterVector)
|
||||
{
|
||||
ULogger::reset();
|
||||
|
||||
// Both threads are registering to logger
|
||||
ULogger::registerCurrentThread("FilterThread");
|
||||
OtherThread otherThread;
|
||||
otherThread.start();
|
||||
|
||||
std::vector<std::string> threadNames;
|
||||
threadNames.push_back(otherThread.name());
|
||||
threadNames.push_back("FilterThread");
|
||||
|
||||
ULogger::setTreadIdFilter(threadNames);
|
||||
|
||||
const std::set<unsigned long>& retrieved = ULogger::getTreadIdFilter();
|
||||
EXPECT_EQ(retrieved.size(), 2u);
|
||||
|
||||
std::string testFile = "logger_thread_log_filtering_test.txt";
|
||||
ULogger::setType(ULogger::kTypeFile, testFile, false);
|
||||
UINFO("This log should appear");
|
||||
|
||||
threadNames.pop_back();
|
||||
ULogger::setTreadIdFilter(threadNames);
|
||||
UINFO("This log should not appear");
|
||||
|
||||
otherThread.logOnce();
|
||||
otherThread.join(true);
|
||||
|
||||
// Make sure the log file is closed
|
||||
ULogger::setType(ULogger::kTypeNoLog);
|
||||
|
||||
std::ifstream file(testFile);
|
||||
std::string line;
|
||||
EXPECT_TRUE(file.is_open());
|
||||
|
||||
std::getline(file, line);
|
||||
EXPECT_TRUE(uStrContains(line, "This log should appear"));
|
||||
std::getline(file, line);
|
||||
EXPECT_TRUE(uStrContains(line, "Logging from OtherThread"));
|
||||
file.close();
|
||||
|
||||
ULogger::unregisterCurrentThread();
|
||||
}
|
||||
|
||||
TEST(ULoggerTest, WriteWithLevel)
|
||||
{
|
||||
ULogger::reset();
|
||||
|
||||
std::string testFile = "logger_write_level_test.txt";
|
||||
ULogger::setType(ULogger::kTypeFile, testFile, false);
|
||||
|
||||
ULogger::setLevel(ULogger::kDebug);
|
||||
|
||||
// Test write with different levels
|
||||
ULogger::write(ULogger::kDebug, __FILE__, __LINE__, __FUNCTION__, "Debug message %d", 42);
|
||||
ULogger::write(ULogger::kInfo, __FILE__, __LINE__, __FUNCTION__, "Info message %s", "test");
|
||||
ULogger::write(ULogger::kWarning, __FILE__, __LINE__, __FUNCTION__, "Warning message");
|
||||
ULogger::write(ULogger::kError, __FILE__, __LINE__, __FUNCTION__, "Error message");
|
||||
|
||||
// Make sure the log file is closed
|
||||
ULogger::setType(ULogger::kTypeNoLog);
|
||||
|
||||
std::ifstream file(testFile);
|
||||
std::string line;
|
||||
EXPECT_TRUE(file.is_open());
|
||||
|
||||
std::getline(file, line);
|
||||
EXPECT_TRUE(uStrContains(line, "[DEBUG]"));
|
||||
EXPECT_TRUE(uStrContains(line, "Debug message 42"));
|
||||
std::getline(file, line);
|
||||
EXPECT_TRUE(uStrContains(line, "[ INFO]"));
|
||||
EXPECT_TRUE(uStrContains(line, "Info message test"));
|
||||
std::getline(file, line);
|
||||
EXPECT_TRUE(uStrContains(line, "[ WARN]"));
|
||||
EXPECT_TRUE(uStrContains(line, "Warning message"));
|
||||
std::getline(file, line);
|
||||
EXPECT_TRUE(uStrContains(line, "[ERROR]"));
|
||||
EXPECT_TRUE(uStrContains(line, "Error message"));
|
||||
file.close();
|
||||
}
|
||||
|
||||
TEST(ULoggerTest, Macros)
|
||||
{
|
||||
ULogger::reset();
|
||||
std::string testFile = "logger_macros_test.txt";
|
||||
ULogger::setType(ULogger::kTypeFile, testFile, false);
|
||||
|
||||
ULogger::setLevel(ULogger::kDebug);
|
||||
|
||||
UDEBUG("Debug macro message");
|
||||
UINFO("Info macro message");
|
||||
UWARN("Warning macro message");
|
||||
UERROR("Error macro message");
|
||||
|
||||
// Make sure the log file is closed
|
||||
ULogger::setType(ULogger::kTypeNoLog);
|
||||
|
||||
std::ifstream file(testFile);
|
||||
std::string line;
|
||||
EXPECT_TRUE(file.is_open());
|
||||
|
||||
std::getline(file, line);
|
||||
EXPECT_TRUE(uStrContains(line, "[DEBUG]"));
|
||||
EXPECT_TRUE(uStrContains(line, "Debug macro message"));
|
||||
std::getline(file, line);
|
||||
EXPECT_TRUE(uStrContains(line, "[ INFO]"));
|
||||
EXPECT_TRUE(uStrContains(line, "Info macro message"));
|
||||
std::getline(file, line);
|
||||
EXPECT_TRUE(uStrContains(line, "[ WARN]"));
|
||||
EXPECT_TRUE(uStrContains(line, "Warning macro message"));
|
||||
std::getline(file, line);
|
||||
EXPECT_TRUE(uStrContains(line, "[ERROR]"));
|
||||
EXPECT_TRUE(uStrContains(line, "Error macro message"));
|
||||
file.close();
|
||||
}
|
||||
|
||||
TEST(ULoggerTest, Reset)
|
||||
{
|
||||
ULogger::reset();
|
||||
// Change some settings
|
||||
ULogger::setType(ULogger::kTypeConsole);
|
||||
ULogger::setLevel(ULogger::kDebug);
|
||||
ULogger::setPrintTime(false);
|
||||
ULogger::setPrintLevel(false);
|
||||
ULogger::setBuffered(true);
|
||||
|
||||
// Reset
|
||||
ULogger::reset();
|
||||
|
||||
// Should be back to defaults
|
||||
EXPECT_EQ(ULogger::type(), ULogger::kTypeNoLog);
|
||||
EXPECT_EQ(ULogger::level(), ULogger::kInfo);
|
||||
EXPECT_TRUE(ULogger::isPrintTime());
|
||||
EXPECT_TRUE(ULogger::isPrintLevel());
|
||||
EXPECT_FALSE(ULogger::isBuffered());
|
||||
}
|
||||
|
||||
TEST(ULoggerTest, MultipleLogLevels)
|
||||
{
|
||||
ULogger::reset();
|
||||
std::string testFile = "logger_multiple_levels_test.txt";
|
||||
ULogger::setType(ULogger::kTypeFile, testFile, false);
|
||||
|
||||
// Test all levels
|
||||
ULogger::setLevel(ULogger::kDebug);
|
||||
UDEBUG("Debug");
|
||||
UINFO("Info");
|
||||
UWARN("Warning");
|
||||
UERROR("Error");
|
||||
|
||||
ULogger::setLevel(ULogger::kInfo);
|
||||
UDEBUG("Debug - should not appear");
|
||||
UINFO("Info");
|
||||
UWARN("Warning");
|
||||
UERROR("Error");
|
||||
|
||||
ULogger::setLevel(ULogger::kWarning);
|
||||
UDEBUG("Debug - should not appear");
|
||||
UINFO("Info - should not appear");
|
||||
UWARN("Warning");
|
||||
UERROR("Error");
|
||||
|
||||
ULogger::setLevel(ULogger::kError);
|
||||
UDEBUG("Debug - should not appear");
|
||||
UINFO("Info - should not appear");
|
||||
UWARN("Warning - should not appear");
|
||||
UERROR("Error");
|
||||
|
||||
// Make sure the log file is closed
|
||||
ULogger::setType(ULogger::kTypeNoLog);
|
||||
|
||||
std::ifstream file(testFile);
|
||||
std::string line;
|
||||
EXPECT_TRUE(file.is_open());
|
||||
|
||||
int count = 0;
|
||||
std::getline(file, line);
|
||||
while(!line.empty())
|
||||
{
|
||||
EXPECT_TRUE(!uStrContains(line, "should not appear"));
|
||||
++count;
|
||||
std::getline(file, line);
|
||||
}
|
||||
EXPECT_EQ(count, 10);
|
||||
file.close();
|
||||
}
|
||||
|
||||
TEST(ULoggerTest, FileContent)
|
||||
{
|
||||
ULogger::reset();
|
||||
std::string testFile = "test_ulogger_content.txt";
|
||||
|
||||
ULogger::setType(ULogger::kTypeFile, testFile, false);
|
||||
ULogger::setLevel(ULogger::kInfo);
|
||||
ULogger::setPrintTime(false);
|
||||
ULogger::setPrintLevel(true);
|
||||
ULogger::setPrintWhere(false);
|
||||
|
||||
UINFO("Test content message");
|
||||
ULogger::setType(ULogger::kTypeNoLog);
|
||||
|
||||
// Read file and check content
|
||||
std::ifstream file(testFile);
|
||||
std::string content((std::istreambuf_iterator<char>(file)),
|
||||
std::istreambuf_iterator<char>());
|
||||
file.close();
|
||||
|
||||
EXPECT_NE(content.find("Test content message"), std::string::npos);
|
||||
}
|
||||
|
||||
TEST(ULoggerTest, ThreadSafety)
|
||||
{
|
||||
ULogger::reset();
|
||||
std::string testFile = "logger_thread_safety_test.txt";
|
||||
ULogger::setType(ULogger::kTypeFile, testFile, false);
|
||||
|
||||
// Disable all printing to easyly test results below
|
||||
ULogger::setPrintTime(false);
|
||||
ULogger::setPrintLevel(false);
|
||||
ULogger::setPrintWhere(false);
|
||||
ULogger::setPrintWhereFullPath(false);
|
||||
ULogger::setPrintColored(false);
|
||||
ULogger::setPrintThreadId(false);
|
||||
|
||||
const int numThreads = 5;
|
||||
const int messagesPerThread = 9;
|
||||
|
||||
std::vector<std::thread> threads;
|
||||
|
||||
for(int i = 0; i < numThreads; ++i)
|
||||
{
|
||||
threads.emplace_back([i, messagesPerThread]() {
|
||||
for(int j = 0; j < messagesPerThread; ++j)
|
||||
{
|
||||
UINFO("Thread %d message %d", i, j);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
for(auto& t : threads)
|
||||
{
|
||||
t.join();
|
||||
}
|
||||
|
||||
// Make sure the log file is closed
|
||||
ULogger::setType(ULogger::kTypeNoLog);
|
||||
|
||||
std::ifstream file(testFile);
|
||||
std::string line;
|
||||
EXPECT_TRUE(file.is_open());
|
||||
|
||||
int count = 0;
|
||||
std::getline(file, line);
|
||||
while(!line.empty())
|
||||
{
|
||||
// Expect all messages on single line, no interleaved, format: "Thread X message X"
|
||||
EXPECT_EQ(line.length(), 19);
|
||||
++count;
|
||||
std::getline(file, line);
|
||||
}
|
||||
EXPECT_EQ(count, 45);
|
||||
file.close();
|
||||
}
|
||||
|
||||
TEST(ULoggerTest, DefaultLogFileName)
|
||||
{
|
||||
EXPECT_EQ(ULogger::kDefaultLogFileName, "./ULog.txt");
|
||||
}
|
||||
|
||||
TEST(ULoggerTest, AllPrintOptions)
|
||||
{
|
||||
ULogger::reset();
|
||||
std::string testFile = "logger_all_print_options_test.txt";
|
||||
ULogger::setType(ULogger::kTypeFile, testFile, false);
|
||||
|
||||
// Test with all print options enabled
|
||||
ULogger::setPrintTime(true);
|
||||
ULogger::setPrintLevel(true);
|
||||
ULogger::setPrintWhereFullPath(true);
|
||||
ULogger::setPrintColored(true);
|
||||
ULogger::setPrintThreadId(true);
|
||||
|
||||
UINFO("Message with all options");
|
||||
|
||||
// Test with all print options disabled
|
||||
ULogger::setPrintTime(false);
|
||||
ULogger::setPrintLevel(false);
|
||||
ULogger::setPrintWhere(false);
|
||||
ULogger::setPrintWhereFullPath(false);
|
||||
ULogger::setPrintColored(false);
|
||||
ULogger::setPrintThreadId(false);
|
||||
|
||||
UINFO("Message with no options");
|
||||
|
||||
// Make sure the log file is closed
|
||||
ULogger::setType(ULogger::kTypeNoLog);
|
||||
|
||||
std::ifstream file(testFile);
|
||||
std::string line;
|
||||
EXPECT_TRUE(file.is_open());
|
||||
|
||||
std::getline(file, line);
|
||||
EXPECT_TRUE(uStrContains(line, "["));
|
||||
EXPECT_TRUE(uStrContains(line, "{"));
|
||||
EXPECT_TRUE(uStrContains(line, "-"));
|
||||
EXPECT_TRUE(uStrContains(line, ".cpp"));
|
||||
EXPECT_TRUE(uStrContains(line, "/") || uStrContains(line, "\\"));
|
||||
|
||||
std::getline(file, line);
|
||||
EXPECT_FALSE(uStrContains(line, "["));
|
||||
EXPECT_FALSE(uStrContains(line, "{"));
|
||||
EXPECT_FALSE(uStrContains(line, "-"));
|
||||
EXPECT_FALSE(uStrContains(line, ".cpp"));
|
||||
EXPECT_FALSE(uStrContains(line, "\\"));
|
||||
EXPECT_FALSE(uStrContains(line, "/"));
|
||||
|
||||
file.close();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,284 @@
|
||||
#include "gtest/gtest.h"
|
||||
#include "rtabmap/utilite/UMath.h"
|
||||
#include <cmath>
|
||||
#include <limits>
|
||||
|
||||
TEST(UMathTest, uIsNan)
|
||||
{
|
||||
float nanValue = std::numeric_limits<float>::quiet_NaN();
|
||||
float normalValue = 3.14f;
|
||||
|
||||
EXPECT_TRUE(uIsNan(nanValue));
|
||||
EXPECT_FALSE(uIsNan(normalValue));
|
||||
|
||||
double nanDouble = std::numeric_limits<double>::quiet_NaN();
|
||||
double normalDouble = 3.14;
|
||||
EXPECT_TRUE(uIsNan(nanDouble));
|
||||
EXPECT_FALSE(uIsNan(normalDouble));
|
||||
}
|
||||
|
||||
TEST(UMathTest, uIsFinite)
|
||||
{
|
||||
float infValue = std::numeric_limits<float>::infinity();
|
||||
float normalValue = 3.14f;
|
||||
float nanValue = std::numeric_limits<float>::quiet_NaN();
|
||||
|
||||
EXPECT_FALSE(uIsFinite(infValue));
|
||||
EXPECT_TRUE(uIsFinite(normalValue));
|
||||
EXPECT_FALSE(uIsFinite(nanValue));
|
||||
}
|
||||
|
||||
TEST(UMathTest, uMin3)
|
||||
{
|
||||
EXPECT_EQ(uMin3(3, 1, 2), 1);
|
||||
EXPECT_EQ(uMin3(1, 2, 3), 1);
|
||||
EXPECT_EQ(uMin3(2, 3, 1), 1);
|
||||
EXPECT_EQ(uMin3(1.5f, 2.5f, 0.5f), 0.5f);
|
||||
}
|
||||
|
||||
TEST(UMathTest, uMax3)
|
||||
{
|
||||
EXPECT_EQ(uMax3(3, 1, 2), 3);
|
||||
EXPECT_EQ(uMax3(1, 2, 3), 3);
|
||||
EXPECT_EQ(uMax3(2, 3, 1), 3);
|
||||
EXPECT_EQ(uMax3(1.5f, 2.5f, 0.5f), 2.5f);
|
||||
}
|
||||
|
||||
TEST(UMathTest, uMaxArray)
|
||||
{
|
||||
int arr[] = {1, 5, 3, 9, 2};
|
||||
unsigned int index;
|
||||
int max = uMax(arr, 5, index);
|
||||
EXPECT_EQ(max, 9);
|
||||
EXPECT_EQ(index, 3u);
|
||||
|
||||
int max2 = uMax(arr, 5);
|
||||
EXPECT_EQ(max2, 9);
|
||||
}
|
||||
|
||||
TEST(UMathTest, uMaxVector)
|
||||
{
|
||||
std::vector<int> v = {1, 5, 3, 9, 2};
|
||||
unsigned int index;
|
||||
int max = uMax(v, index);
|
||||
EXPECT_EQ(max, 9);
|
||||
EXPECT_EQ(index, 3u);
|
||||
|
||||
int max2 = uMax(v);
|
||||
EXPECT_EQ(max2, 9);
|
||||
}
|
||||
|
||||
TEST(UMathTest, uMinArray)
|
||||
{
|
||||
int arr[] = {5, 1, 3, 9, 2};
|
||||
unsigned int index;
|
||||
int min = uMin(arr, 5, index);
|
||||
EXPECT_EQ(min, 1);
|
||||
EXPECT_EQ(index, 1u);
|
||||
|
||||
int min2 = uMin(arr, 5);
|
||||
EXPECT_EQ(min2, 1);
|
||||
}
|
||||
|
||||
TEST(UMathTest, uMinVector)
|
||||
{
|
||||
std::vector<int> v = {5, 1, 3, 9, 2};
|
||||
unsigned int index;
|
||||
int min = uMin(v, index);
|
||||
EXPECT_EQ(min, 1);
|
||||
EXPECT_EQ(index, 1u);
|
||||
|
||||
int min2 = uMin(v);
|
||||
EXPECT_EQ(min2, 1);
|
||||
}
|
||||
|
||||
TEST(UMathTest, uMinMaxArray)
|
||||
{
|
||||
int arr[] = {5, 1, 3, 9, 2};
|
||||
int min, max;
|
||||
unsigned int indexMin, indexMax;
|
||||
uMinMax(arr, 5, min, max, indexMin, indexMax);
|
||||
EXPECT_EQ(min, 1);
|
||||
EXPECT_EQ(max, 9);
|
||||
EXPECT_EQ(indexMin, 1u);
|
||||
EXPECT_EQ(indexMax, 3u);
|
||||
}
|
||||
|
||||
TEST(UMathTest, uMinMaxVector)
|
||||
{
|
||||
std::vector<int> v = {5, 1, 3, 9, 2};
|
||||
int min, max;
|
||||
unsigned int indexMin, indexMax;
|
||||
uMinMax(v, min, max, indexMin, indexMax);
|
||||
EXPECT_EQ(min, 1);
|
||||
EXPECT_EQ(max, 9);
|
||||
EXPECT_EQ(indexMin, 1u);
|
||||
EXPECT_EQ(indexMax, 3u);
|
||||
}
|
||||
|
||||
TEST(UMathTest, uMinMaxWithoutIndices)
|
||||
{
|
||||
int arr[] = {5, 1, 3, 9, 2};
|
||||
int min, max;
|
||||
uMinMax(arr, 5, min, max);
|
||||
EXPECT_EQ(min, 1);
|
||||
EXPECT_EQ(max, 9);
|
||||
|
||||
std::vector<int> v = {5, 1, 3, 9, 2};
|
||||
uMinMax(v, min, max);
|
||||
EXPECT_EQ(min, 1);
|
||||
EXPECT_EQ(max, 9);
|
||||
}
|
||||
|
||||
TEST(UMathTest, uSign)
|
||||
{
|
||||
EXPECT_EQ(uSign(5), 1);
|
||||
EXPECT_EQ(uSign(-5), -1);
|
||||
EXPECT_EQ(uSign(0), 1);
|
||||
EXPECT_EQ(uSign(3.14f), 1);
|
||||
EXPECT_EQ(uSign(-3.14f), -1);
|
||||
}
|
||||
|
||||
TEST(UMathTest, uSumList)
|
||||
{
|
||||
std::list<int> list = {1, 2, 3, 4, 5};
|
||||
int sum = uSum(list);
|
||||
EXPECT_EQ(sum, 15);
|
||||
}
|
||||
|
||||
TEST(UMathTest, uSumArray)
|
||||
{
|
||||
int arr[] = {1, 2, 3, 4, 5};
|
||||
int sum = uSum(arr, 5);
|
||||
EXPECT_EQ(sum, 15);
|
||||
}
|
||||
|
||||
TEST(UMathTest, uSumVector)
|
||||
{
|
||||
std::vector<int> v = {1, 2, 3, 4, 5};
|
||||
int sum = uSum(v);
|
||||
EXPECT_EQ(sum, 15);
|
||||
}
|
||||
|
||||
TEST(UMathTest, uSumSquared)
|
||||
{
|
||||
int arr[] = {1, 2, 3};
|
||||
int sum = uSumSquared(arr, 3);
|
||||
EXPECT_EQ(sum, 14); // 1*1 + 2*2 + 3*3 = 1 + 4 + 9 = 14
|
||||
|
||||
int sum2 = uSumSquared(arr, 3, 2); // subtract 2
|
||||
EXPECT_EQ(sum2, 2); // (-1)*(-1) + 0*0 + 1*1 = 1 + 0 + 1 = 2
|
||||
}
|
||||
|
||||
TEST(UMathTest, uMean)
|
||||
{
|
||||
int arr[] = {1, 2, 3, 4, 5};
|
||||
float mean = uMean(arr, 5);
|
||||
EXPECT_FLOAT_EQ(mean, 3.0f);
|
||||
|
||||
std::vector<int> v = {1, 2, 3, 4, 5};
|
||||
float mean2 = uMean(v);
|
||||
EXPECT_FLOAT_EQ(mean2, 3.0f);
|
||||
|
||||
std::list<int> list = {1, 2, 3, 4, 5};
|
||||
float mean3 = uMean(list);
|
||||
EXPECT_FLOAT_EQ(mean3, 3.0f);
|
||||
}
|
||||
|
||||
TEST(UMathTest, uMeanSquaredError)
|
||||
{
|
||||
float x[] = {1.0f, 2.0f, 3.0f};
|
||||
float y[] = {1.1f, 2.1f, 3.1f};
|
||||
float mse = uMeanSquaredError(x, 3, y, 3);
|
||||
EXPECT_NEAR(mse, 0.01f, 0.001f); // (0.1^2 + 0.1^2 + 0.1^2) / 3 = 0.01
|
||||
|
||||
std::vector<float> vx = {1.0f, 2.0f, 3.0f};
|
||||
std::vector<float> vy = {1.1f, 2.1f, 3.1f};
|
||||
float mse2 = uMeanSquaredError(vx, vy);
|
||||
EXPECT_NEAR(mse2, 0.01f, 0.001f);
|
||||
}
|
||||
|
||||
TEST(UMathTest, uVariance)
|
||||
{
|
||||
float arr[] = {1.0f, 2.0f, 3.0f, 4.0f, 5.0f};
|
||||
float mean = uMean(arr, 5);
|
||||
float variance = uVariance(arr, 5, mean);
|
||||
EXPECT_NEAR(variance, 2.5f, 0.1f); // Variance of 1,2,3,4,5 is 2.5
|
||||
|
||||
float variance2 = uVariance(arr, 5);
|
||||
EXPECT_NEAR(variance2, 2.5f, 0.1f);
|
||||
}
|
||||
|
||||
TEST(UMathTest, uNormSquared)
|
||||
{
|
||||
std::vector<float> v = {3.0f, 4.0f};
|
||||
float normSq = uNormSquared(v);
|
||||
EXPECT_FLOAT_EQ(normSq, 25.0f); // 3*3 + 4*4 = 9 + 16 = 25
|
||||
|
||||
float normSq2 = uNormSquared(3.0f, 4.0f);
|
||||
EXPECT_FLOAT_EQ(normSq2, 25.0f);
|
||||
|
||||
float normSq3 = uNormSquared(1.0f, 2.0f, 3.0f);
|
||||
EXPECT_FLOAT_EQ(normSq3, 14.0f); // 1*1 + 2*2 + 3*3 = 1 + 4 + 9 = 14
|
||||
}
|
||||
|
||||
TEST(UMathTest, uNorm)
|
||||
{
|
||||
std::vector<float> v = {3.0f, 4.0f};
|
||||
float norm = uNorm(v);
|
||||
EXPECT_FLOAT_EQ(norm, 5.0f); // sqrt(3*3 + 4*4) = sqrt(25) = 5
|
||||
|
||||
float norm2 = uNorm(3.0f, 4.0f);
|
||||
EXPECT_FLOAT_EQ(norm2, 5.0f);
|
||||
|
||||
float norm3 = uNorm(1.0f, 2.0f, 3.0f);
|
||||
EXPECT_NEAR(norm3, 3.741657f, 0.001f); // sqrt(14)
|
||||
}
|
||||
|
||||
TEST(UMathTest, uNormalize)
|
||||
{
|
||||
std::vector<float> v = {3.0f, 4.0f};
|
||||
std::vector<float> normalized = uNormalize(v);
|
||||
float norm = uNorm(normalized);
|
||||
EXPECT_NEAR(norm, 1.0f, 0.001f);
|
||||
|
||||
std::vector<float> zero = {0.0f, 0.0f};
|
||||
std::vector<float> normalizedZero = uNormalize(zero);
|
||||
EXPECT_EQ(normalizedZero.size(), 2u);
|
||||
EXPECT_FLOAT_EQ(normalizedZero[0], 0.0f);
|
||||
EXPECT_FLOAT_EQ(normalizedZero[1], 0.0f);
|
||||
}
|
||||
|
||||
TEST(UMathTest, uLocalMaxima)
|
||||
{
|
||||
float arr[] = {1.0f, 3.0f, 2.0f, 5.0f, 4.0f, 6.0f, 3.0f};
|
||||
std::list<unsigned int> maxima = uLocalMaxima(arr, 7);
|
||||
// Should find maxima at indices 1, 3, 5
|
||||
EXPECT_GT(maxima.size(), 0u);
|
||||
|
||||
std::vector<float> v = {1.0f, 3.0f, 2.0f, 5.0f, 4.0f};
|
||||
std::list<unsigned int> maxima2 = uLocalMaxima(v);
|
||||
EXPECT_GT(maxima2.size(), 0u);
|
||||
}
|
||||
|
||||
TEST(UMathTest, uHamming)
|
||||
{
|
||||
std::vector<float> window = uHamming(10);
|
||||
EXPECT_EQ(window.size(), 10u);
|
||||
// Hamming window values should be between 0 and 1
|
||||
for(float w : window)
|
||||
{
|
||||
EXPECT_GE(w, 0.0f);
|
||||
EXPECT_LE(w, 1.0f);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(UMathTest, uIsInBounds)
|
||||
{
|
||||
EXPECT_TRUE(uIsInBounds(5, 0, 10));
|
||||
EXPECT_FALSE(uIsInBounds(10, 0, 10));
|
||||
EXPECT_FALSE(uIsInBounds(-1, 0, 10));
|
||||
EXPECT_FALSE(uIsInBounds(std::numeric_limits<float>::quiet_NaN(), 0.0f, 10.0f));
|
||||
EXPECT_FALSE(uIsInBounds(std::numeric_limits<float>::infinity(), 0.0f, 10.0f));
|
||||
}
|
||||
|
||||
@@ -0,0 +1,172 @@
|
||||
#include "gtest/gtest.h"
|
||||
#include "rtabmap/utilite/UMutex.h"
|
||||
#include <thread>
|
||||
#include <chrono>
|
||||
#include <atomic>
|
||||
#include <vector>
|
||||
|
||||
TEST(UMutexTest, Constructor)
|
||||
{
|
||||
UMutex mutex;
|
||||
// Should be constructible
|
||||
SUCCEED();
|
||||
}
|
||||
|
||||
TEST(UMutexTest, LockUnlock)
|
||||
{
|
||||
UMutex mutex;
|
||||
EXPECT_TRUE(mutex.lock());
|
||||
EXPECT_TRUE(mutex.unlock());
|
||||
}
|
||||
|
||||
TEST(UMutexTest, LockTry)
|
||||
{
|
||||
UMutex mutex;
|
||||
|
||||
// Try to lock when not locked
|
||||
EXPECT_TRUE(mutex.lockTry());
|
||||
|
||||
// Unlock
|
||||
mutex.unlock();
|
||||
}
|
||||
|
||||
TEST(UMutexTest, LockTryWhenLocked)
|
||||
{
|
||||
UMutex mutex;
|
||||
|
||||
// Lock the mutex
|
||||
mutex.lock();
|
||||
|
||||
// Try to lock from another thread
|
||||
std::atomic<bool> tryResult(false);
|
||||
std::thread t([&mutex, &tryResult]() {
|
||||
tryResult = mutex.lockTry(); // Should fail (busy or similar)
|
||||
});
|
||||
|
||||
t.join();
|
||||
|
||||
EXPECT_FALSE(tryResult);
|
||||
|
||||
mutex.unlock();
|
||||
}
|
||||
|
||||
TEST(UMutexTest, ThreadSafety)
|
||||
{
|
||||
UMutex mutex;
|
||||
std::atomic<int> counter(0);
|
||||
const int numThreads = 4;
|
||||
const int iterations = 1000;
|
||||
|
||||
std::vector<std::thread> threads;
|
||||
|
||||
for(int i = 0; i < numThreads; ++i)
|
||||
{
|
||||
threads.emplace_back([&mutex, &counter, iterations]() {
|
||||
for(int j = 0; j < iterations; ++j)
|
||||
{
|
||||
mutex.lock();
|
||||
int val = counter.load();
|
||||
std::this_thread::sleep_for(std::chrono::microseconds(1));
|
||||
counter.store(val + 1);
|
||||
mutex.unlock();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
for(auto& t : threads)
|
||||
{
|
||||
t.join();
|
||||
}
|
||||
|
||||
EXPECT_EQ(counter.load(), numThreads * iterations);
|
||||
}
|
||||
|
||||
TEST(UMutexTest, RecursiveLock)
|
||||
{
|
||||
UMutex mutex;
|
||||
|
||||
// Lock multiple times from same thread (should work on Unix)
|
||||
EXPECT_TRUE(mutex.lock());
|
||||
EXPECT_TRUE(mutex.lock());
|
||||
EXPECT_TRUE(mutex.lock());
|
||||
|
||||
// Unlock multiple times
|
||||
EXPECT_TRUE(mutex.unlock());
|
||||
EXPECT_TRUE(mutex.unlock());
|
||||
EXPECT_TRUE(mutex.unlock());
|
||||
}
|
||||
|
||||
TEST(UMutexTest, UScopeMutex)
|
||||
{
|
||||
UMutex mutex;
|
||||
{
|
||||
UScopeMutex scopeMutex(mutex);
|
||||
// Mutex should be locked here
|
||||
|
||||
// Try to lock from another thread
|
||||
std::thread t([&mutex]() {
|
||||
EXPECT_FALSE(mutex.lockTry()); // Should fail
|
||||
});
|
||||
t.join();
|
||||
}
|
||||
// Mutex should be unlocked here
|
||||
|
||||
// Try to lock from another thread
|
||||
std::thread t([&mutex]() {
|
||||
EXPECT_TRUE(mutex.lockTry()); // Should succeed
|
||||
mutex.unlock();
|
||||
});
|
||||
t.join();
|
||||
}
|
||||
|
||||
TEST(UMutexTest, UScopeMutexWithPointer)
|
||||
{
|
||||
UMutex mutex;
|
||||
|
||||
{
|
||||
UScopeMutex scopeMutex(&mutex);
|
||||
// Mutex should be locked here
|
||||
|
||||
// Try to lock from another thread
|
||||
std::thread t([&mutex]() {
|
||||
EXPECT_FALSE(mutex.lockTry()); // Should fail
|
||||
});
|
||||
t.join();
|
||||
}
|
||||
// Mutex should be unlocked here
|
||||
|
||||
// Try to lock from another thread
|
||||
std::thread t([&mutex]() {
|
||||
EXPECT_TRUE(mutex.lockTry()); // Should succeed
|
||||
mutex.unlock();
|
||||
});
|
||||
t.join();
|
||||
}
|
||||
|
||||
TEST(UMutexTest, MultipleMutexes)
|
||||
{
|
||||
UMutex mutex1;
|
||||
UMutex mutex2;
|
||||
|
||||
mutex1.lock();
|
||||
mutex2.lock();
|
||||
|
||||
mutex1.unlock();
|
||||
mutex2.unlock();
|
||||
|
||||
SUCCEED();
|
||||
}
|
||||
|
||||
TEST(UMutexTest, LockUnlockSequence)
|
||||
{
|
||||
UMutex mutex;
|
||||
|
||||
for(int i = 0; i < 10; ++i)
|
||||
{
|
||||
mutex.lock();
|
||||
mutex.unlock();
|
||||
}
|
||||
|
||||
SUCCEED();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
#include "gtest/gtest.h"
|
||||
#include "rtabmap/utilite/UProcessInfo.h"
|
||||
|
||||
TEST(UProcessInfoTest, Constructor)
|
||||
{
|
||||
UProcessInfo info;
|
||||
// Should be constructible
|
||||
SUCCEED();
|
||||
}
|
||||
|
||||
TEST(UProcessInfoTest, GetMemoryUsage)
|
||||
{
|
||||
long int memory = UProcessInfo::getMemoryUsage();
|
||||
// Memory usage should be positive
|
||||
EXPECT_GT(memory, 0);
|
||||
// Should be reasonable (less than 1TB)
|
||||
EXPECT_LT(memory, 1024LL * 1024 * 1024 * 1024);
|
||||
}
|
||||
|
||||
TEST(UProcessInfoTest, GetMemoryUsageMultipleCalls)
|
||||
{
|
||||
long int memory1 = UProcessInfo::getMemoryUsage();
|
||||
long int memory2 = UProcessInfo::getMemoryUsage();
|
||||
// Both calls should return valid values
|
||||
EXPECT_GT(memory1, 0);
|
||||
EXPECT_GT(memory2, 0);
|
||||
// Values should be similar (might vary slightly)
|
||||
EXPECT_NEAR(memory1, memory2, memory1 * 0.1); // Allow 10% variation
|
||||
}
|
||||
|
||||
@@ -0,0 +1,333 @@
|
||||
#include "gtest/gtest.h"
|
||||
#include "rtabmap/utilite/USemaphore.h"
|
||||
#include "rtabmap/utilite/UMutex.h"
|
||||
#include "rtabmap/utilite/UTimer.h"
|
||||
#include <thread>
|
||||
#include <chrono>
|
||||
#include <atomic>
|
||||
#include <vector>
|
||||
|
||||
TEST(USemaphoreTest, ConstructorDefault)
|
||||
{
|
||||
USemaphore sem;
|
||||
// Should be constructible with default value (0)
|
||||
EXPECT_EQ(sem.value(), 0);
|
||||
}
|
||||
|
||||
TEST(USemaphoreTest, ConstructorWithValue)
|
||||
{
|
||||
USemaphore sem(5);
|
||||
EXPECT_EQ(sem.value(), 5);
|
||||
}
|
||||
|
||||
TEST(USemaphoreTest, Release)
|
||||
{
|
||||
USemaphore sem(0);
|
||||
|
||||
sem.release();
|
||||
EXPECT_EQ(sem.value(), 1);
|
||||
|
||||
sem.release(3);
|
||||
EXPECT_EQ(sem.value(), 4);
|
||||
}
|
||||
|
||||
TEST(USemaphoreTest, Acquire)
|
||||
{
|
||||
USemaphore sem(2);
|
||||
|
||||
bool result = sem.acquire();
|
||||
EXPECT_TRUE(result);
|
||||
EXPECT_EQ(sem.value(), 1);
|
||||
|
||||
result = sem.acquire();
|
||||
EXPECT_TRUE(result);
|
||||
EXPECT_EQ(sem.value(), 0);
|
||||
}
|
||||
|
||||
TEST(USemaphoreTest, AcquireMultiple)
|
||||
{
|
||||
USemaphore sem(5);
|
||||
|
||||
bool result = sem.acquire(3);
|
||||
EXPECT_TRUE(result);
|
||||
EXPECT_EQ(sem.value(), 2);
|
||||
|
||||
result = sem.acquire(2);
|
||||
EXPECT_TRUE(result);
|
||||
EXPECT_EQ(sem.value(), 0);
|
||||
}
|
||||
|
||||
TEST(USemaphoreTest, AcquireBlocks)
|
||||
{
|
||||
USemaphore sem(0);
|
||||
std::atomic<bool> acquired(false);
|
||||
std::atomic<bool> threadStarted(false);
|
||||
|
||||
std::thread t([&sem, &acquired, &threadStarted]() {
|
||||
threadStarted = true;
|
||||
bool result = sem.acquire();
|
||||
acquired = result;
|
||||
});
|
||||
|
||||
// Wait for thread to start and try to acquire
|
||||
while(!threadStarted)
|
||||
{
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(1));
|
||||
}
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(10));
|
||||
|
||||
// Thread should be blocked
|
||||
EXPECT_FALSE(acquired);
|
||||
|
||||
// Release to unblock
|
||||
sem.release();
|
||||
|
||||
t.join();
|
||||
|
||||
EXPECT_TRUE(acquired);
|
||||
}
|
||||
|
||||
TEST(USemaphoreTest, AcquireWithTimeout)
|
||||
{
|
||||
USemaphore sem(0);
|
||||
|
||||
// Try to acquire with timeout
|
||||
bool result = sem.acquire(1, 50); // 50ms timeout
|
||||
EXPECT_FALSE(result); // Should timeout
|
||||
|
||||
// Release and try again
|
||||
sem.release();
|
||||
result = sem.acquire(1, 50);
|
||||
EXPECT_TRUE(result);
|
||||
}
|
||||
|
||||
TEST(USemaphoreTest, AcquireTry)
|
||||
{
|
||||
USemaphore sem(3);
|
||||
|
||||
// Try to acquire when available
|
||||
#ifdef _WIN32
|
||||
bool result = sem.acquireTry();
|
||||
EXPECT_TRUE(result);
|
||||
EXPECT_EQ(sem.value(), 2);
|
||||
result = sem.acquireTry();
|
||||
EXPECT_TRUE(result);
|
||||
EXPECT_EQ(sem.value(), 1);
|
||||
result = sem.acquireTry();
|
||||
EXPECT_TRUE(result);
|
||||
EXPECT_EQ(sem.value(), 0);
|
||||
result = sem.acquireTry();
|
||||
EXPECT_TRUE(result);
|
||||
#else
|
||||
int result = sem.acquireTry(1);
|
||||
EXPECT_TRUE(result);
|
||||
EXPECT_EQ(sem.value(), 2);
|
||||
|
||||
result = sem.acquireTry(2);
|
||||
EXPECT_TRUE(result);
|
||||
EXPECT_EQ(sem.value(), 0);
|
||||
|
||||
// Try to acquire when not available
|
||||
result = sem.acquireTry(1);
|
||||
EXPECT_FALSE(result);
|
||||
#endif
|
||||
}
|
||||
|
||||
TEST(USemaphoreTest, Value)
|
||||
{
|
||||
USemaphore sem(10);
|
||||
|
||||
int value = sem.value();
|
||||
EXPECT_EQ(value, 10);
|
||||
|
||||
sem.acquire(3);
|
||||
value = sem.value();
|
||||
EXPECT_EQ(value, 7);
|
||||
|
||||
sem.release(2);
|
||||
value = sem.value();
|
||||
EXPECT_EQ(value, 9);
|
||||
}
|
||||
|
||||
TEST(USemaphoreTest, ThreadSafety)
|
||||
{
|
||||
USemaphore sem(0);
|
||||
std::atomic<int> counter(0);
|
||||
const int numThreads = 4;
|
||||
const int iterations = 100;
|
||||
|
||||
std::vector<std::thread> threads;
|
||||
|
||||
// Create threads that will wait on semaphore
|
||||
for(int i = 0; i < numThreads; ++i)
|
||||
{
|
||||
threads.emplace_back([&sem, &counter, iterations]() {
|
||||
for(int j = 0; j < iterations; ++j)
|
||||
{
|
||||
sem.acquire();
|
||||
counter++;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Release semaphore to allow threads to proceed
|
||||
std::thread releaseThread([&sem, numThreads, iterations]() {
|
||||
for(int i = 0; i < numThreads * iterations; ++i)
|
||||
{
|
||||
sem.release();
|
||||
std::this_thread::sleep_for(std::chrono::microseconds(10));
|
||||
}
|
||||
});
|
||||
|
||||
for(auto& t : threads)
|
||||
{
|
||||
t.join();
|
||||
}
|
||||
|
||||
releaseThread.join();
|
||||
|
||||
EXPECT_EQ(counter.load(), numThreads * iterations);
|
||||
}
|
||||
|
||||
TEST(USemaphoreTest, ProducerConsumer)
|
||||
{
|
||||
USemaphore full(0);
|
||||
USemaphore empty(10);
|
||||
std::vector<int> buffer;
|
||||
UMutex bufferMutex;
|
||||
const int items = 20;
|
||||
std::atomic<int> produced(0);
|
||||
std::atomic<int> consumed(0);
|
||||
|
||||
// Producer thread
|
||||
std::thread producer([&full, &empty, &buffer, &bufferMutex, &produced, items]() {
|
||||
for(int i = 0; i < items; ++i)
|
||||
{
|
||||
empty.acquire();
|
||||
{
|
||||
UScopeMutex lock(bufferMutex);
|
||||
buffer.push_back(i);
|
||||
}
|
||||
full.release();
|
||||
produced++;
|
||||
}
|
||||
});
|
||||
|
||||
// Consumer thread
|
||||
std::thread consumer([&full, &empty, &buffer, &bufferMutex, &consumed, items]() {
|
||||
for(int i = 0; i < items; ++i)
|
||||
{
|
||||
full.acquire();
|
||||
{
|
||||
UScopeMutex lock(bufferMutex);
|
||||
if(!buffer.empty())
|
||||
{
|
||||
buffer.pop_back();
|
||||
}
|
||||
}
|
||||
empty.release();
|
||||
consumed++;
|
||||
}
|
||||
});
|
||||
|
||||
producer.join();
|
||||
consumer.join();
|
||||
|
||||
EXPECT_EQ(produced.load(), items);
|
||||
EXPECT_EQ(consumed.load(), items);
|
||||
}
|
||||
|
||||
TEST(USemaphoreTest, MultipleAcquireRelease)
|
||||
{
|
||||
USemaphore sem(0);
|
||||
|
||||
// Release multiple times
|
||||
sem.release(5);
|
||||
EXPECT_EQ(sem.value(), 5);
|
||||
|
||||
// Acquire multiple times
|
||||
bool result = sem.acquire(3);
|
||||
EXPECT_TRUE(result);
|
||||
EXPECT_EQ(sem.value(), 2);
|
||||
|
||||
result = sem.acquire(2);
|
||||
EXPECT_TRUE(result);
|
||||
EXPECT_EQ(sem.value(), 0);
|
||||
}
|
||||
|
||||
TEST(USemaphoreTest, AcquireZero)
|
||||
{
|
||||
USemaphore sem(5);
|
||||
|
||||
// Acquire 0 should not block
|
||||
bool result = sem.acquire(0);
|
||||
EXPECT_TRUE(result);
|
||||
EXPECT_EQ(sem.value(), 5);
|
||||
}
|
||||
|
||||
TEST(USemaphoreTest, ReleaseZero)
|
||||
{
|
||||
USemaphore sem(5);
|
||||
|
||||
// Release 0 should not change value
|
||||
sem.release(0);
|
||||
EXPECT_EQ(sem.value(), 5);
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
TEST(USemaphoreTest, Reset)
|
||||
{
|
||||
USemaphore sem(5);
|
||||
EXPECT_EQ(sem.value(), 5);
|
||||
|
||||
sem.reset(10);
|
||||
EXPECT_EQ(sem.value(), 10);
|
||||
|
||||
sem.reset(0);
|
||||
EXPECT_EQ(sem.value(), 0);
|
||||
}
|
||||
#endif
|
||||
|
||||
TEST(USemaphoreTest, ConcurrentAcquireRelease)
|
||||
{
|
||||
USemaphore sem(0);
|
||||
std::atomic<int> acquiredCount(0);
|
||||
const int numThreads = 5;
|
||||
|
||||
std::vector<std::thread> acquireThreads;
|
||||
std::vector<std::thread> releaseThreads;
|
||||
|
||||
// Create threads that acquire
|
||||
for(int i = 0; i < numThreads; ++i)
|
||||
{
|
||||
acquireThreads.emplace_back([&sem, &acquiredCount]() {
|
||||
sem.acquire();
|
||||
acquiredCount++;
|
||||
});
|
||||
}
|
||||
|
||||
// Wait a bit
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(50));
|
||||
|
||||
// Create threads that release
|
||||
for(int i = 0; i < numThreads; ++i)
|
||||
{
|
||||
releaseThreads.emplace_back([&sem]() {
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(10));
|
||||
sem.release();
|
||||
});
|
||||
}
|
||||
|
||||
for(auto& t : acquireThreads)
|
||||
{
|
||||
t.join();
|
||||
}
|
||||
|
||||
for(auto& t : releaseThreads)
|
||||
{
|
||||
t.join();
|
||||
}
|
||||
|
||||
EXPECT_EQ(acquiredCount.load(), numThreads);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,347 @@
|
||||
#include "gtest/gtest.h"
|
||||
#include "rtabmap/utilite/UStl.h"
|
||||
#include <map>
|
||||
|
||||
TEST(UStlTest, uUniqueKeys)
|
||||
{
|
||||
std::multimap<int, std::string> mm;
|
||||
mm.insert({1, "a"});
|
||||
mm.insert({1, "b"});
|
||||
mm.insert({2, "c"});
|
||||
mm.insert({3, "d"});
|
||||
mm.insert({3, "e"});
|
||||
|
||||
std::list<int> uniqueKeys = uUniqueKeys(mm);
|
||||
EXPECT_EQ(uniqueKeys.size(), 3u);
|
||||
EXPECT_EQ(uniqueKeys.front(), 1);
|
||||
EXPECT_EQ(uniqueKeys.back(), 3);
|
||||
}
|
||||
|
||||
TEST(UStlTest, uKeysMultimap)
|
||||
{
|
||||
std::multimap<int, std::string> mm;
|
||||
mm.insert({1, "a"});
|
||||
mm.insert({2, "b"});
|
||||
mm.insert({3, "c"});
|
||||
|
||||
std::vector<int> keys = uKeys(mm);
|
||||
EXPECT_EQ(keys.size(), 3u);
|
||||
|
||||
std::list<int> keysList = uKeysList(mm);
|
||||
EXPECT_EQ(keysList.size(), 3u);
|
||||
}
|
||||
|
||||
TEST(UStlTest, uValuesMultimap)
|
||||
{
|
||||
std::multimap<int, std::string> mm;
|
||||
mm.insert({1, "a"});
|
||||
mm.insert({1, "b"});
|
||||
mm.insert({2, "c"});
|
||||
|
||||
std::vector<std::string> values = uValues(mm);
|
||||
EXPECT_EQ(values.size(), 3u);
|
||||
|
||||
std::list<std::string> valuesList = uValuesList(mm);
|
||||
EXPECT_EQ(valuesList.size(), 3u);
|
||||
}
|
||||
|
||||
TEST(UStlTest, uValuesMultimapForKey)
|
||||
{
|
||||
std::multimap<int, std::string> mm;
|
||||
mm.insert({1, "a"});
|
||||
mm.insert({1, "b"});
|
||||
mm.insert({2, "c"});
|
||||
|
||||
std::list<std::string> values = uValues(mm, 1);
|
||||
EXPECT_EQ(values.size(), 2u);
|
||||
EXPECT_EQ(values.front(), "a");
|
||||
EXPECT_EQ(values.back(), "b");
|
||||
}
|
||||
|
||||
TEST(UStlTest, uKeysMap)
|
||||
{
|
||||
std::map<int, std::string> m;
|
||||
m[1] = "a";
|
||||
m[2] = "b";
|
||||
m[3] = "c";
|
||||
|
||||
std::vector<int> keys = uKeys(m);
|
||||
EXPECT_EQ(keys.size(), 3u);
|
||||
|
||||
std::list<int> keysList = uKeysList(m);
|
||||
EXPECT_EQ(keysList.size(), 3u);
|
||||
|
||||
std::set<int> keysSet = uKeysSet(m);
|
||||
EXPECT_EQ(keysSet.size(), 3u);
|
||||
}
|
||||
|
||||
TEST(UStlTest, uValuesMap)
|
||||
{
|
||||
std::map<int, std::string> m;
|
||||
m[1] = "a";
|
||||
m[2] = "b";
|
||||
m[3] = "c";
|
||||
|
||||
std::vector<std::string> values = uValues(m);
|
||||
EXPECT_EQ(values.size(), 3u);
|
||||
|
||||
std::list<std::string> valuesList = uValuesList(m);
|
||||
EXPECT_EQ(valuesList.size(), 3u);
|
||||
}
|
||||
|
||||
TEST(UStlTest, uValueMap)
|
||||
{
|
||||
std::map<int, std::string> m;
|
||||
m[1] = "a";
|
||||
m[2] = "b";
|
||||
|
||||
std::string value = uValue(m, 1, std::string("default"));
|
||||
EXPECT_EQ(value, "a");
|
||||
|
||||
std::string defaultValue = uValue(m, 99, std::string("default"));
|
||||
EXPECT_EQ(defaultValue, "default");
|
||||
}
|
||||
|
||||
TEST(UStlTest, uTake)
|
||||
{
|
||||
std::map<int, std::string> m;
|
||||
m[1] = "a";
|
||||
m[2] = "b";
|
||||
|
||||
std::string value = uTake(m, 1, std::string("default"));
|
||||
EXPECT_EQ(value, "a");
|
||||
EXPECT_EQ(m.size(), 1u);
|
||||
EXPECT_EQ(m.find(1), m.end());
|
||||
}
|
||||
|
||||
TEST(UStlTest, uIteratorAtList)
|
||||
{
|
||||
std::list<int> list = {1, 2, 3, 4, 5};
|
||||
auto iter = uIteratorAt(list, 2);
|
||||
EXPECT_EQ(*iter, 3);
|
||||
|
||||
const std::list<int>& constList = list;
|
||||
auto constIter = uIteratorAt(constList, 2);
|
||||
EXPECT_EQ(*constIter, 3);
|
||||
}
|
||||
|
||||
TEST(UStlTest, uIteratorAtSet)
|
||||
{
|
||||
std::set<int> s = {1, 2, 3, 4, 5};
|
||||
auto iter = uIteratorAt(s, 2);
|
||||
EXPECT_NE(iter, s.end());
|
||||
}
|
||||
|
||||
TEST(UStlTest, uIteratorAtVector)
|
||||
{
|
||||
std::vector<int> v = {1, 2, 3, 4, 5};
|
||||
auto iter = uIteratorAt(v, 2);
|
||||
EXPECT_EQ(*iter, 3);
|
||||
|
||||
const std::vector<int>& constV = v;
|
||||
auto constIter = uIteratorAt(constV, 2);
|
||||
EXPECT_EQ(*constIter, 3);
|
||||
}
|
||||
|
||||
TEST(UStlTest, uValueAtList)
|
||||
{
|
||||
std::list<int> list = {1, 2, 3, 4, 5};
|
||||
int& value = uValueAt(list, 2);
|
||||
EXPECT_EQ(value, 3);
|
||||
value = 10;
|
||||
EXPECT_EQ(uValueAt(list, 2), 10);
|
||||
|
||||
const std::list<int>& constList = list;
|
||||
const int& constValue = uValueAt(constList, 2);
|
||||
EXPECT_EQ(constValue, 10);
|
||||
}
|
||||
|
||||
TEST(UStlTest, uContainsList)
|
||||
{
|
||||
std::list<int> list = {1, 2, 3, 4, 5};
|
||||
EXPECT_TRUE(uContains(list, 3));
|
||||
EXPECT_FALSE(uContains(list, 10));
|
||||
}
|
||||
|
||||
TEST(UStlTest, uContainsMap)
|
||||
{
|
||||
std::map<int, std::string> m;
|
||||
m[1] = "a";
|
||||
m[2] = "b";
|
||||
EXPECT_TRUE(uContains(m, 1));
|
||||
EXPECT_FALSE(uContains(m, 10));
|
||||
}
|
||||
|
||||
TEST(UStlTest, uContainsMultimap)
|
||||
{
|
||||
std::multimap<int, std::string> mm;
|
||||
mm.insert({1, "a"});
|
||||
mm.insert({2, "b"});
|
||||
EXPECT_TRUE(uContains(mm, 1));
|
||||
EXPECT_FALSE(uContains(mm, 10));
|
||||
}
|
||||
|
||||
TEST(UStlTest, uInsert)
|
||||
{
|
||||
std::map<int, std::string> m;
|
||||
uInsert(m, std::make_pair(1, std::string("a")));
|
||||
EXPECT_EQ(m[1], "a");
|
||||
|
||||
uInsert(m, std::make_pair(1, std::string("b")));
|
||||
EXPECT_EQ(m[1], "b"); // Should replace
|
||||
|
||||
std::map<int, std::string> m2;
|
||||
m2[2] = "c";
|
||||
m2[3] = "d";
|
||||
uInsert(m, m2);
|
||||
EXPECT_EQ(m.size(), 3u);
|
||||
}
|
||||
|
||||
TEST(UStlTest, uListToVector)
|
||||
{
|
||||
std::list<int> list = {1, 2, 3, 4, 5};
|
||||
std::vector<int> v = uListToVector(list);
|
||||
EXPECT_EQ(v.size(), 5u);
|
||||
EXPECT_EQ(v[0], 1);
|
||||
EXPECT_EQ(v[4], 5);
|
||||
}
|
||||
|
||||
TEST(UStlTest, uVectorToList)
|
||||
{
|
||||
std::vector<int> v = {1, 2, 3, 4, 5};
|
||||
std::list<int> list = uVectorToList(v);
|
||||
EXPECT_EQ(list.size(), 5u);
|
||||
EXPECT_EQ(list.front(), 1);
|
||||
EXPECT_EQ(list.back(), 5);
|
||||
}
|
||||
|
||||
TEST(UStlTest, uMultimapToMap)
|
||||
{
|
||||
std::multimap<int, std::string> mm;
|
||||
mm.insert({1, "a"});
|
||||
mm.insert({1, "b"});
|
||||
mm.insert({2, "c"});
|
||||
|
||||
std::map<int, std::string> m = uMultimapToMap(mm);
|
||||
EXPECT_EQ(m.size(), 2u); // All entries
|
||||
}
|
||||
|
||||
TEST(UStlTest, uMultimapToMapUnique)
|
||||
{
|
||||
std::multimap<int, std::string> mm;
|
||||
mm.insert({1, "a"});
|
||||
mm.insert({1, "b"});
|
||||
mm.insert({2, "c"});
|
||||
|
||||
std::map<int, std::string> m = uMultimapToMapUnique(mm);
|
||||
EXPECT_EQ(m.size(), 1u); // Only unique keys with single value
|
||||
EXPECT_EQ(m[2], "c");
|
||||
}
|
||||
|
||||
TEST(UStlTest, uAppend)
|
||||
{
|
||||
std::list<int> list1 = {1, 2, 3};
|
||||
std::list<int> list2 = {4, 5, 6};
|
||||
uAppend(list1, list2);
|
||||
EXPECT_EQ(list1.size(), 6u);
|
||||
EXPECT_EQ(list1.back(), 6);
|
||||
}
|
||||
|
||||
TEST(UStlTest, uIndexOf)
|
||||
{
|
||||
std::vector<int> v = {1, 2, 3, 4, 5};
|
||||
EXPECT_EQ(uIndexOf(v, 3), 2);
|
||||
EXPECT_EQ(uIndexOf(v, 10), -1);
|
||||
}
|
||||
|
||||
TEST(UStlTest, uSplit)
|
||||
{
|
||||
std::list<std::string> result = uSplit("Hello the world!", ' ');
|
||||
EXPECT_EQ(result.size(), 3u);
|
||||
EXPECT_EQ(result.front(), "Hello");
|
||||
EXPECT_EQ(result.back(), "world!");
|
||||
|
||||
std::list<std::string> result2 = uSplit("a,b,c", ',');
|
||||
EXPECT_EQ(result2.size(), 3u);
|
||||
}
|
||||
|
||||
TEST(UStlTest, uJoin)
|
||||
{
|
||||
std::list<std::string> strings;
|
||||
strings.push_back("Hello");
|
||||
strings.push_back("world!");
|
||||
std::string joined = uJoin(strings, " ");
|
||||
EXPECT_EQ(joined, "Hello world!");
|
||||
|
||||
std::string joined2 = uJoin(strings, "");
|
||||
EXPECT_EQ(joined2, "Helloworld!");
|
||||
}
|
||||
|
||||
TEST(UStlTest, uIsDigit)
|
||||
{
|
||||
EXPECT_TRUE(uIsDigit('0'));
|
||||
EXPECT_TRUE(uIsDigit('5'));
|
||||
EXPECT_TRUE(uIsDigit('9'));
|
||||
EXPECT_FALSE(uIsDigit('a'));
|
||||
EXPECT_FALSE(uIsDigit('A'));
|
||||
}
|
||||
|
||||
TEST(UStlTest, uIsInteger)
|
||||
{
|
||||
EXPECT_TRUE(uIsInteger("123"));
|
||||
EXPECT_TRUE(uIsInteger("-123"));
|
||||
EXPECT_FALSE(uIsInteger("12.3"));
|
||||
EXPECT_FALSE(uIsInteger("abc"));
|
||||
|
||||
EXPECT_TRUE(uIsInteger("123", true));
|
||||
EXPECT_TRUE(uIsInteger("123", false));
|
||||
EXPECT_FALSE(uIsInteger("-123", false));
|
||||
}
|
||||
|
||||
TEST(UStlTest, uIsNumber)
|
||||
{
|
||||
EXPECT_TRUE(uIsNumber("123"));
|
||||
EXPECT_TRUE(uIsNumber("12.3"));
|
||||
EXPECT_TRUE(uIsNumber("-12.3"));
|
||||
EXPECT_FALSE(uIsNumber("abc"));
|
||||
EXPECT_FALSE(uIsNumber("12.3.4"));
|
||||
}
|
||||
|
||||
TEST(UStlTest, uSplitNumChar)
|
||||
{
|
||||
std::list<std::string> result = uSplitNumChar("Hello 03 my 65 world!");
|
||||
EXPECT_GT(result.size(), 0u);
|
||||
// Should contain numbers and characters separately
|
||||
}
|
||||
|
||||
TEST(UStlTest, uStrNumCmp)
|
||||
{
|
||||
EXPECT_LT(uStrNumCmp("Image9.jpg", "Image10.jpg"), 0);
|
||||
EXPECT_GT(uStrNumCmp("Image10.jpg", "Image9.jpg"), 0);
|
||||
EXPECT_EQ(uStrNumCmp("Image10.jpg", "Image10.jpg"), 0);
|
||||
}
|
||||
|
||||
TEST(UStlTest, uStrContains)
|
||||
{
|
||||
EXPECT_TRUE(uStrContains("Hello World", "World"));
|
||||
EXPECT_TRUE(uStrContains("Hello World", "Hello"));
|
||||
EXPECT_FALSE(uStrContains("Hello World", "xyz"));
|
||||
}
|
||||
|
||||
TEST(UStlTest, uCompareVersion)
|
||||
{
|
||||
EXPECT_GT(uCompareVersion("2.0.0", 1, 0, 0), 0);
|
||||
EXPECT_EQ(uCompareVersion("1.0.0", 1, 0, 0), 0);
|
||||
EXPECT_LT(uCompareVersion("0.9.0", 1, 0, 0), 0);
|
||||
}
|
||||
|
||||
TEST(UStlTest, uPad)
|
||||
{
|
||||
std::string result = uPad("Hello", 10);
|
||||
EXPECT_GE(result.size(), 10u);
|
||||
EXPECT_EQ(result.substr(0, 5), "Hello");
|
||||
|
||||
std::string result2 = uPad("Hello", 3);
|
||||
EXPECT_EQ(result2, "Hello"); // Should not truncate
|
||||
}
|
||||
|
||||
@@ -0,0 +1,352 @@
|
||||
#include "gtest/gtest.h"
|
||||
#include "rtabmap/utilite/UThread.h"
|
||||
#include "rtabmap/utilite/UTimer.h"
|
||||
#include <thread>
|
||||
#include <chrono>
|
||||
#include <atomic>
|
||||
|
||||
// Simple test thread
|
||||
class SimpleThread : public UThread
|
||||
{
|
||||
public:
|
||||
SimpleThread() : UThread(), counter_(0), started_(false) {}
|
||||
virtual ~SimpleThread() {join(true);}
|
||||
int getCounter() const { return counter_; }
|
||||
bool hasStarted() const { return started_; }
|
||||
void reset() { counter_ = 0; started_ = false; }
|
||||
|
||||
protected:
|
||||
virtual void mainLoop()
|
||||
{
|
||||
started_ = true;
|
||||
counter_++;
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(10));
|
||||
kill(); // Stop after one iteration
|
||||
}
|
||||
|
||||
private:
|
||||
int counter_;
|
||||
bool started_;
|
||||
};
|
||||
|
||||
// Thread that runs multiple iterations
|
||||
class CountingThread : public UThread
|
||||
{
|
||||
public:
|
||||
CountingThread() : UThread(), counter_(0), maxIterations_(10) {}
|
||||
virtual ~CountingThread() {join(true);}
|
||||
void setMaxIterations(int max) { maxIterations_ = max; }
|
||||
int getCounter() const { return counter_; }
|
||||
|
||||
protected:
|
||||
virtual void mainLoop()
|
||||
{
|
||||
counter_++;
|
||||
if(counter_ >= maxIterations_)
|
||||
{
|
||||
kill();
|
||||
}
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(5));
|
||||
}
|
||||
|
||||
private:
|
||||
int counter_;
|
||||
int maxIterations_;
|
||||
};
|
||||
|
||||
// Thread with initialization
|
||||
class InitThread : public UThread
|
||||
{
|
||||
public:
|
||||
InitThread() : UThread(), initialized_(false), counter_(0) {}
|
||||
virtual ~InitThread() {join(true);}
|
||||
bool isInitialized() const { return initialized_; }
|
||||
int getCounter() const { return counter_; }
|
||||
|
||||
protected:
|
||||
virtual void mainLoopBegin()
|
||||
{
|
||||
initialized_ = true;
|
||||
}
|
||||
|
||||
virtual void mainLoop()
|
||||
{
|
||||
counter_++;
|
||||
if(counter_ >= 5)
|
||||
{
|
||||
kill();
|
||||
}
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(5));
|
||||
}
|
||||
|
||||
private:
|
||||
bool initialized_;
|
||||
int counter_;
|
||||
};
|
||||
|
||||
// Thread with cleanup
|
||||
class CleanupThread : public UThread
|
||||
{
|
||||
public:
|
||||
CleanupThread() : UThread(), cleanedUp_(false), counter_(0) {}
|
||||
virtual ~CleanupThread() {join(true);}
|
||||
bool isCleanedUp() const { return cleanedUp_; }
|
||||
int getCounter() const { return counter_; }
|
||||
|
||||
protected:
|
||||
virtual void mainLoop()
|
||||
{
|
||||
counter_++;
|
||||
if(counter_ >= 3)
|
||||
{
|
||||
kill();
|
||||
}
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(5));
|
||||
}
|
||||
|
||||
virtual void mainLoopEnd()
|
||||
{
|
||||
cleanedUp_ = true;
|
||||
}
|
||||
|
||||
private:
|
||||
bool cleanedUp_;
|
||||
int counter_;
|
||||
};
|
||||
|
||||
TEST(UThreadTest, Constructor)
|
||||
{
|
||||
SimpleThread thread;
|
||||
EXPECT_TRUE(thread.isIdle());
|
||||
EXPECT_FALSE(thread.isRunning());
|
||||
EXPECT_FALSE(thread.isCreating());
|
||||
EXPECT_FALSE(thread.isKilled());
|
||||
}
|
||||
|
||||
TEST(UThreadTest, Start)
|
||||
{
|
||||
SimpleThread thread;
|
||||
thread.start();
|
||||
|
||||
EXPECT_TRUE(thread.isRunning() || thread.isCreating());
|
||||
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(5));
|
||||
EXPECT_TRUE(thread.isRunning());
|
||||
|
||||
// Give thread time to stop
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(10));
|
||||
|
||||
// Thread should be running or killed (if it finished quickly)
|
||||
EXPECT_TRUE(thread.isKilled() || thread.isIdle());
|
||||
|
||||
thread.join();
|
||||
}
|
||||
|
||||
TEST(UThreadTest, Join)
|
||||
{
|
||||
SimpleThread thread;
|
||||
UTimer timer;
|
||||
thread.start();
|
||||
thread.join();
|
||||
|
||||
EXPECT_GT(timer.elapsed(), 0.01);
|
||||
EXPECT_TRUE(thread.isIdle());
|
||||
EXPECT_GT(thread.getCounter(), 0);
|
||||
}
|
||||
|
||||
TEST(UThreadTest, JoinWait)
|
||||
{
|
||||
CountingThread thread;
|
||||
thread.setMaxIterations(10);
|
||||
thread.start();
|
||||
|
||||
// Join wait
|
||||
thread.join(false);
|
||||
|
||||
EXPECT_TRUE(thread.isIdle());
|
||||
EXPECT_EQ(thread.getCounter(), 10); // Should have processed all iterations
|
||||
}
|
||||
|
||||
TEST(UThreadTest, JoinKillFirst)
|
||||
{
|
||||
CountingThread thread;
|
||||
thread.setMaxIterations(1000);
|
||||
thread.start();
|
||||
|
||||
// Wait a bit
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(50));
|
||||
|
||||
// Join with kill
|
||||
thread.join(true);
|
||||
|
||||
EXPECT_TRUE(thread.isIdle());
|
||||
EXPECT_LT(thread.getCounter(), 1000); // Should have stopped early
|
||||
}
|
||||
|
||||
TEST(UThreadTest, Kill)
|
||||
{
|
||||
CountingThread thread;
|
||||
thread.setMaxIterations(1000);
|
||||
thread.start();
|
||||
|
||||
// Wait a bit
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(50));
|
||||
|
||||
// Kill the thread
|
||||
thread.kill();
|
||||
|
||||
EXPECT_TRUE(thread.isKilled());
|
||||
|
||||
// Wait for it to finish
|
||||
thread.join();
|
||||
|
||||
EXPECT_TRUE(thread.isIdle());
|
||||
EXPECT_LT(thread.getCounter(), 1000); // Should have stopped early
|
||||
}
|
||||
|
||||
TEST(UThreadTest, MultipleStart)
|
||||
{
|
||||
SimpleThread thread;
|
||||
thread.start();
|
||||
|
||||
// Try to start again (should be ignored)
|
||||
thread.start();
|
||||
|
||||
thread.join();
|
||||
|
||||
EXPECT_TRUE(thread.isIdle());
|
||||
}
|
||||
|
||||
TEST(UThreadTest, MainLoopBegin)
|
||||
{
|
||||
InitThread thread;
|
||||
thread.start();
|
||||
thread.join();
|
||||
|
||||
EXPECT_TRUE(thread.isInitialized());
|
||||
EXPECT_GT(thread.getCounter(), 0);
|
||||
}
|
||||
|
||||
TEST(UThreadTest, MainLoopEnd)
|
||||
{
|
||||
CleanupThread thread;
|
||||
thread.start();
|
||||
thread.join();
|
||||
|
||||
EXPECT_TRUE(thread.isCleanedUp());
|
||||
EXPECT_GT(thread.getCounter(), 0);
|
||||
}
|
||||
|
||||
TEST(UThreadTest, ThreadId)
|
||||
{
|
||||
SimpleThread thread;
|
||||
unsigned long mainThreadId = UThread::currentThreadId();
|
||||
|
||||
thread.start();
|
||||
unsigned long threadId = thread.getThreadId();
|
||||
|
||||
EXPECT_NE(threadId, 0u);
|
||||
EXPECT_NE(threadId, mainThreadId);
|
||||
|
||||
thread.join();
|
||||
}
|
||||
|
||||
TEST(UThreadTest, CurrentThreadId)
|
||||
{
|
||||
unsigned long id1 = UThread::currentThreadId();
|
||||
unsigned long id2 = UThread::currentThreadId();
|
||||
|
||||
EXPECT_EQ(id1, id2);
|
||||
EXPECT_NE(id1, 0u);
|
||||
}
|
||||
|
||||
TEST(UThreadTest, SetPriority)
|
||||
{
|
||||
SimpleThread thread;
|
||||
thread.setPriority(UThread::kPLow);
|
||||
thread.setPriority(UThread::kPNormal);
|
||||
thread.setPriority(UThread::kPAboveNormal);
|
||||
|
||||
thread.start();
|
||||
thread.join();
|
||||
|
||||
SUCCEED();
|
||||
}
|
||||
|
||||
TEST(UThreadTest, SetAffinity)
|
||||
{
|
||||
SimpleThread thread;
|
||||
thread.setAffinity(0); // No affinity
|
||||
thread.setAffinity(1); // CPU 1
|
||||
|
||||
thread.start();
|
||||
thread.join();
|
||||
|
||||
SUCCEED();
|
||||
}
|
||||
|
||||
TEST(UThreadTest, ThreadHandle)
|
||||
{
|
||||
SimpleThread thread;
|
||||
thread.start();
|
||||
|
||||
UThread::Handle handle = thread.getThreadHandle();
|
||||
EXPECT_NE(handle, 0);
|
||||
|
||||
thread.join();
|
||||
}
|
||||
|
||||
TEST(UThreadTest, MultipleThreads)
|
||||
{
|
||||
std::vector<SimpleThread*> threads;
|
||||
const int numThreads = 5;
|
||||
|
||||
for(int i = 0; i < numThreads; ++i)
|
||||
{
|
||||
threads.push_back(new SimpleThread());
|
||||
threads[i]->start();
|
||||
}
|
||||
|
||||
for(int i = 0; i < numThreads; ++i)
|
||||
{
|
||||
threads[i]->join();
|
||||
EXPECT_GT(threads[i]->getCounter(), 0);
|
||||
delete threads[i];
|
||||
}
|
||||
}
|
||||
|
||||
TEST(UThreadTest, DestructorJoin)
|
||||
{
|
||||
// Test that destructor properly cleans up
|
||||
{
|
||||
SimpleThread thread;
|
||||
thread.start();
|
||||
// Destructor should call join(true) if implemented
|
||||
}
|
||||
|
||||
SUCCEED();
|
||||
}
|
||||
|
||||
TEST(UThreadTest, KillBeforeStart)
|
||||
{
|
||||
SimpleThread thread;
|
||||
thread.kill(); // Kill before start
|
||||
|
||||
thread.start();
|
||||
thread.join();
|
||||
|
||||
// Should still work
|
||||
SUCCEED();
|
||||
}
|
||||
|
||||
TEST(UThreadTest, JoinBeforeStart)
|
||||
{
|
||||
SimpleThread thread;
|
||||
thread.join(); // Join before start
|
||||
|
||||
thread.start();
|
||||
thread.join();
|
||||
|
||||
SUCCEED();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,115 @@
|
||||
#include "gtest/gtest.h"
|
||||
#include "rtabmap/utilite/UTimer.h"
|
||||
#include <thread>
|
||||
#include <chrono>
|
||||
|
||||
TEST(UTimerTest, Constructor)
|
||||
{
|
||||
UTimer timer;
|
||||
// Timer should be constructible
|
||||
SUCCEED();
|
||||
}
|
||||
|
||||
TEST(UTimerTest, StartStop)
|
||||
{
|
||||
UTimer timer;
|
||||
timer.start();
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(10));
|
||||
timer.stop();
|
||||
double elapsed = timer.getElapsedTime();
|
||||
EXPECT_GE(elapsed, 0.01); // Should be at least 10 ms
|
||||
EXPECT_LT(elapsed, 0.015); // Should be less than 15 ms
|
||||
}
|
||||
|
||||
TEST(UTimerTest, Elapsed)
|
||||
{
|
||||
UTimer timer;
|
||||
timer.start();
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(10));
|
||||
double elapsed = timer.elapsed();
|
||||
EXPECT_GE(elapsed, 0.01);
|
||||
EXPECT_LT(elapsed, 0.015);
|
||||
|
||||
// Timer should still be running after elapsed()
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(10));
|
||||
double ticks2 = timer.ticks();
|
||||
EXPECT_GE(ticks2, 0.02);
|
||||
EXPECT_LT(ticks2, 0.025);
|
||||
}
|
||||
|
||||
TEST(UTimerTest, GetElapsedTime)
|
||||
{
|
||||
UTimer timer;
|
||||
timer.start();
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(10));
|
||||
double elapsed = timer.getElapsedTime();
|
||||
EXPECT_GE(elapsed, 0.01);
|
||||
EXPECT_LT(elapsed, 0.015);
|
||||
|
||||
// Timer should still be running after getElapsedTime()
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(10));
|
||||
double ticks2 = timer.ticks();
|
||||
EXPECT_GE(ticks2, 0.02);
|
||||
EXPECT_LT(ticks2, 0.025);
|
||||
}
|
||||
|
||||
TEST(UTimerTest, Ticks)
|
||||
{
|
||||
UTimer timer;
|
||||
timer.start();
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(10));
|
||||
double ticks1 = timer.ticks();
|
||||
EXPECT_GE(ticks1, 0.01);
|
||||
EXPECT_LT(ticks1, 0.015);
|
||||
|
||||
// Timer should have retarted and still be running after ticks()
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(10));
|
||||
double ticks2 = timer.ticks();
|
||||
EXPECT_GE(ticks2, 0.01);
|
||||
EXPECT_LT(ticks2, 0.015);
|
||||
}
|
||||
|
||||
TEST(UTimerTest, Restart)
|
||||
{
|
||||
UTimer timer;
|
||||
timer.start();
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(10));
|
||||
double elapsed1 = timer.restart();
|
||||
EXPECT_GE(elapsed1, 0.01);
|
||||
EXPECT_LT(elapsed1, 0.02);
|
||||
|
||||
// After restart, timer should be running again
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(10));
|
||||
double elapsed2 = timer.elapsed();
|
||||
EXPECT_GE(elapsed2, 0.01);
|
||||
EXPECT_LT(elapsed2, 0.02);
|
||||
}
|
||||
|
||||
TEST(UTimerTest, Now)
|
||||
{
|
||||
double time1 = UTimer::now();
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(10));
|
||||
double time2 = UTimer::now();
|
||||
EXPECT_GE(time2-time1, 0.01);
|
||||
EXPECT_LT(time2-time1, 0.015);
|
||||
}
|
||||
|
||||
TEST(UTimerTest, MultipleStartStop)
|
||||
{
|
||||
UTimer timer;
|
||||
timer.start();
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(5));
|
||||
timer.stop();
|
||||
double elapsed1 = timer.getElapsedTime();
|
||||
|
||||
timer.start();
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(5));
|
||||
timer.stop();
|
||||
double elapsed2 = timer.getElapsedTime();
|
||||
|
||||
EXPECT_GE(elapsed1, 0.005);
|
||||
EXPECT_LT(elapsed1, 0.01);
|
||||
EXPECT_GE(elapsed2, 0.005);
|
||||
EXPECT_LT(elapsed2, 0.01);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,213 @@
|
||||
#include "gtest/gtest.h"
|
||||
#include "rtabmap/utilite/UVariant.h"
|
||||
|
||||
TEST(UVariantTest, DefaultConstructor)
|
||||
{
|
||||
UVariant v;
|
||||
EXPECT_TRUE(v.isUndef());
|
||||
EXPECT_EQ(v.type(), UVariant::kUndef);
|
||||
}
|
||||
|
||||
TEST(UVariantTest, BoolConstructor)
|
||||
{
|
||||
UVariant v(true);
|
||||
EXPECT_TRUE(v.isBool());
|
||||
EXPECT_EQ(v.type(), UVariant::kBool);
|
||||
EXPECT_TRUE(v.toBool());
|
||||
|
||||
UVariant v2(false);
|
||||
EXPECT_FALSE(v2.toBool());
|
||||
}
|
||||
|
||||
TEST(UVariantTest, CharConstructor)
|
||||
{
|
||||
signed char value = 42;
|
||||
UVariant v(value);
|
||||
EXPECT_TRUE(v.isChar());
|
||||
EXPECT_EQ(v.type(), UVariant::kChar);
|
||||
bool ok = false;
|
||||
EXPECT_EQ(v.toChar(&ok), value);
|
||||
EXPECT_TRUE(ok);
|
||||
}
|
||||
|
||||
TEST(UVariantTest, UCharConstructor)
|
||||
{
|
||||
unsigned char value = 200;
|
||||
UVariant v(value);
|
||||
EXPECT_TRUE(v.isUChar());
|
||||
EXPECT_EQ(v.type(), UVariant::kUChar);
|
||||
bool ok = false;
|
||||
EXPECT_EQ(v.toUChar(&ok), value);
|
||||
EXPECT_TRUE(ok);
|
||||
}
|
||||
|
||||
TEST(UVariantTest, ShortConstructor)
|
||||
{
|
||||
short value = -100;
|
||||
UVariant v(value);
|
||||
EXPECT_TRUE(v.isShort());
|
||||
EXPECT_EQ(v.type(), UVariant::kShort);
|
||||
bool ok = false;
|
||||
EXPECT_EQ(v.toShort(&ok), value);
|
||||
EXPECT_TRUE(ok);
|
||||
}
|
||||
|
||||
TEST(UVariantTest, UShortConstructor)
|
||||
{
|
||||
unsigned short value = 500;
|
||||
UVariant v(value);
|
||||
EXPECT_TRUE(v.isUShort());
|
||||
EXPECT_EQ(v.type(), UVariant::kUShort);
|
||||
bool ok = false;
|
||||
EXPECT_EQ(v.toUShort(&ok), value);
|
||||
EXPECT_TRUE(ok);
|
||||
}
|
||||
|
||||
TEST(UVariantTest, IntConstructor)
|
||||
{
|
||||
int value = -1000;
|
||||
UVariant v(value);
|
||||
EXPECT_TRUE(v.isInt());
|
||||
EXPECT_EQ(v.type(), UVariant::kInt);
|
||||
bool ok = false;
|
||||
EXPECT_EQ(v.toInt(&ok), value);
|
||||
EXPECT_TRUE(ok);
|
||||
}
|
||||
|
||||
TEST(UVariantTest, UIntConstructor)
|
||||
{
|
||||
unsigned int value = 100000;
|
||||
UVariant v(value);
|
||||
EXPECT_TRUE(v.isUInt());
|
||||
EXPECT_EQ(v.type(), UVariant::kUInt);
|
||||
bool ok = false;
|
||||
EXPECT_EQ(v.toUInt(&ok), value);
|
||||
EXPECT_TRUE(ok);
|
||||
}
|
||||
|
||||
TEST(UVariantTest, FloatConstructor)
|
||||
{
|
||||
float value = 3.14f;
|
||||
UVariant v(value);
|
||||
EXPECT_TRUE(v.isFloat());
|
||||
EXPECT_EQ(v.type(), UVariant::kFloat);
|
||||
bool ok = false;
|
||||
EXPECT_NEAR(v.toFloat(&ok), value, 0.001f);
|
||||
EXPECT_TRUE(ok);
|
||||
}
|
||||
|
||||
TEST(UVariantTest, DoubleConstructor)
|
||||
{
|
||||
double value = 3.14159;
|
||||
UVariant v(value);
|
||||
EXPECT_TRUE(v.isDouble());
|
||||
EXPECT_EQ(v.type(), UVariant::kDouble);
|
||||
bool ok = false;
|
||||
EXPECT_NEAR(v.toDouble(&ok), value, 0.00001);
|
||||
EXPECT_TRUE(ok);
|
||||
}
|
||||
|
||||
TEST(UVariantTest, StringConstructor)
|
||||
{
|
||||
std::string value = "Hello World";
|
||||
UVariant v(value);
|
||||
EXPECT_TRUE(v.isStr());
|
||||
EXPECT_EQ(v.type(), UVariant::kStr);
|
||||
bool ok = false;
|
||||
EXPECT_EQ(v.toStr(&ok), value);
|
||||
EXPECT_TRUE(ok);
|
||||
}
|
||||
|
||||
TEST(UVariantTest, CStringConstructor)
|
||||
{
|
||||
const char* value = "Hello World";
|
||||
UVariant v(value);
|
||||
EXPECT_TRUE(v.isStr());
|
||||
EXPECT_EQ(v.type(), UVariant::kStr);
|
||||
bool ok = false;
|
||||
EXPECT_EQ(v.toStr(&ok), std::string(value));
|
||||
EXPECT_TRUE(ok);
|
||||
}
|
||||
|
||||
TEST(UVariantTest, CharArrayConstructor)
|
||||
{
|
||||
std::vector<signed char> value = {1, 2, 3, -4};
|
||||
UVariant v(value);
|
||||
EXPECT_TRUE(v.isCharArray());
|
||||
EXPECT_EQ(v.type(), UVariant::kCharArray);
|
||||
bool ok = false;
|
||||
std::vector<signed char> result = v.toCharArray(&ok);
|
||||
EXPECT_TRUE(ok);
|
||||
EXPECT_EQ(result.size(), value.size());
|
||||
for(size_t i = 0; i < value.size(); ++i)
|
||||
{
|
||||
EXPECT_EQ(result[i], value[i]);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(UVariantTest, UCharArrayConstructor)
|
||||
{
|
||||
std::vector<unsigned char> value = {1, 2, 3, 4};
|
||||
UVariant v(value);
|
||||
EXPECT_TRUE(v.isUCharArray());
|
||||
EXPECT_EQ(v.type(), UVariant::kUCharArray);
|
||||
bool ok = false;
|
||||
std::vector<unsigned char> result = v.toUCharArray(&ok);
|
||||
EXPECT_TRUE(ok);
|
||||
EXPECT_EQ(result.size(), value.size());
|
||||
for(size_t i = 0; i < value.size(); ++i)
|
||||
{
|
||||
EXPECT_EQ(result[i], value[i]);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(UVariantTest, IntArrayConstructor)
|
||||
{
|
||||
std::vector<int> value = {1, -2, 3, -4, 5};
|
||||
UVariant v(value);
|
||||
EXPECT_TRUE(v.isIntArray());
|
||||
EXPECT_EQ(v.type(), UVariant::kIntArray);
|
||||
bool ok = false;
|
||||
std::vector<int> result = v.toIntArray(&ok);
|
||||
EXPECT_TRUE(ok);
|
||||
EXPECT_EQ(result.size(), value.size());
|
||||
for(size_t i = 0; i < value.size(); ++i)
|
||||
{
|
||||
EXPECT_EQ(result[i], value[i]);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(UVariantTest, FloatArrayConstructor)
|
||||
{
|
||||
std::vector<float> value = {1.1f, 2.2f, 3.3f};
|
||||
UVariant v(value);
|
||||
EXPECT_TRUE(v.isFloatArray());
|
||||
EXPECT_EQ(v.type(), UVariant::kFloatArray);
|
||||
bool ok = false;
|
||||
std::vector<float> result = v.toFloatArray(&ok);
|
||||
EXPECT_TRUE(ok);
|
||||
EXPECT_EQ(result.size(), value.size());
|
||||
for(size_t i = 0; i < value.size(); ++i)
|
||||
{
|
||||
EXPECT_NEAR(result[i], value[i], 0.001f);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(UVariantTest, TypeChecks)
|
||||
{
|
||||
UVariant v(42);
|
||||
EXPECT_TRUE(v.isInt());
|
||||
EXPECT_FALSE(v.isBool());
|
||||
EXPECT_FALSE(v.isFloat());
|
||||
EXPECT_FALSE(v.isStr());
|
||||
EXPECT_FALSE(v.isUndef());
|
||||
}
|
||||
|
||||
TEST(UVariantTest, ConversionFailure)
|
||||
{
|
||||
UVariant v(42); // int
|
||||
bool ok = true;
|
||||
v.toFloat(&ok);
|
||||
EXPECT_FALSE(ok); // Should fail to convert int to float
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user