#include <QVector>
#include <QDataStream>
#include <QMutex>
+#include <QRegularExpression>
typedef unsigned char uint8_t;
#include "rplmodules.hpp"
/**
* @brief Constructor.
*
- * @param message the reason of the exception
+ * For derived classes only!
*/
-RplException::RplException(const char* message) :
- m_message(message) {
+RplException::RplException() :
+ m_message("")
+{
}
/**
* @brief Constructor.
*
- * @param message the reason of the exception
+ * @param format the reason of the exception
+ * @param ... the values for the placeholders in the format.
*/
-RplException::RplException(const QByteArray& message) :
- m_message(message) {
-}
-
-/**
- * @brief Constructor.
- *
- * This constructor automatically logs the given data.
- *
- * @param level the logging level, e.g. LOG_ERROR
- * @param location an unique identifier for the location
- * where the exception was thrown
- * @param message the reason
- * @param logger if NULL the global logger will be used
- */
-RplException::RplException(RplLoggerLevel level, int location,
- const char* message, RplLogger* logger) :
- m_message(message) {
- if(logger == NULL)
- logger = RplLogger::globalLogger();
- logger->log(level, location, message);
-}
-
-/**
- * @brief Constructor.
- *
- * This constructor automatically logs the given data.
- *
- * @param level the logging level, e.g. LOG_ERROR
- * @param location an unique identifier for the location
- * where the exception was thrown
- * @param message the reason
- * @param logger Nif NULL the global logger will be used
- */
-RplException::RplException(RplLoggerLevel level, int location,
- const QByteArray& message, RplLogger* logger) :
- m_message(message) {
- if(logger == NULL)
- logger = RplLogger::globalLogger();
- logger->log(level, location, message);
-}
-
-/**
- * @brief Constructor.
- *
- * This constructor automatically logs the given data.
- *
- * @param level the logging level, e.g. LOG_ERROR
- * @param location an unique identifier for the location
- * where the exception was thrown
- * @param format the reason of the exception.
- * Can contain placeholders (@see
- * std::printf())
- * @param ... the values of the placeholders
- * in <code>format</code>
- * @param logger if NULL the global logger will be used
- */
-RplException::RplException(RplLoggerLevel level, int location,
- RplLogger* logger, const char* format, ...) :
+RplException::RplException(const char* format, ...) :
m_message("") {
char buffer[64000];
va_list ap;
vsnprintf(buffer, sizeof buffer, format, ap);
va_end(ap);
m_message = buffer;
- if(logger == NULL)
- logger = RplLogger::globalLogger();
- logger->log(level, location, buffer);
}
/**
* @param logger if NULL the global logger will be used
*/
RplException::RplException(RplLoggerLevel level, int location,
- RplLogger* logger,
- const QByteArray& format, ...) :
+ RplLogger* logger, const char* format, ...) :
m_message("") {
char buffer[64000];
va_list ap;
#ifndef RPLCORE_HPP
#include <QByteArray>
#endif
+
class RplException {
+protected:
+ RplException();
public:
- RplException(const char* message);
- RplException(const QByteArray& message);
+ RplException(const char* message, ...);
RplException(RplLoggerLevel level, int location, const char* message,
RplLogger* logger = NULL);
- RplException(RplLoggerLevel level, int location, const QByteArray& message,
- RplLogger* logger = NULL);
RplException(RplLoggerLevel level, int location, RplLogger* logger,
const char* message, ...);
- RplException(RplLoggerLevel level, int location, RplLogger* logger,
- const QByteArray& message, ...);
const QByteArray& getMessage() const {
return m_message;
}
class RplInvalidDataException : public RplException {
public:
RplInvalidDataException(RplLoggerLevel level, int location, const char* message,
- const void* data = NULL, size_t dataSize = 0, RplLogger* logger = NULL);
+ const void* data = NULL, size_t dataSize = 0, RplLogger* logger = NULL);
};
#endif // RPLEXCEPTION_HPP
RplFileAppender* fileAppender = new RplFileAppender(prefix, maxSize, maxCount);
fileAppender->setAutoDelete(true);
addAppender((RplAppender*) fileAppender);
-
}
/** @class RplStreamAppender rpllogger.hpp "rplcore/rpllogger.hpp"
RplMemoryAppender::RplMemoryAppender(int maxLines, const char* appenderName) :
RplAppender(appenderName),
m_lines(),
- m_maxLines(maxLines) {
+ m_maxLines(maxLines),
+ m_addPrefix(true)
+{
m_lines.reserve(maxLines);
}
RplLogger* logger) {
if(m_lines.size() >= m_maxLines)
m_lines.removeFirst();
- m_lines.append(message);
+ if (! m_addPrefix)
+ m_lines.append(message);
+ else {
+ QByteArray msg(logger->getStdPrefix(level, location));
+ msg += message;
+ m_lines.append(msg);
+ }
}
#pragma GCC diagnostic warning "-Wunused-parameter"
QVector<QByteArray> m_lines;
// maximum count of m_lines. If larger the oldest lines will be deleted.
int m_maxLines;
+ // true: standard prefix (level + datetime) will be stored too.
+ bool m_addPrefix;
};
#endif // RPLLOGGER_HPP
void testRplString() {
#ifdef RPL_TEST
TestRplString test;
- test.run();
#endif
}
RplTest::RplTest(const char* name) :
m_errors(0),
m_name(name),
- m_logger() {
+ m_logger(),
+ m_memoryAppender(1024),
+ m_memoryLogger()
+{
+ m_memoryAppender.setAutoDelete(false);
m_logger.buildStandardAppender(getTempDir("rpltest"));
log(QByteArray("Start of ") + m_name);
+ m_memoryLogger.addAppender(&m_memoryAppender);
}
/**
try {
doIt();
} catch(RplException e) {
- error("unexpected RplException: %s", e.getMessage().data());
+ error("unexpected RplException: %s", e.getMessage().constData());
+ } catch(...){
+ error("unknown Exception");
}
if(m_errors > 0) {
return false;
}
+/**
+ * @brief Tests whether the m_memoryLogger has a message containing a given pattern.
+ *
+ * @param pattern regular expression to search
+ * @return true: pattern has been found<br>
+ * false: otherwise
+ */
+bool RplTest::logContains(const char* pattern)
+{
+ const QVector<QByteArray>& lines = m_memoryAppender.getLines();
+ QRegularExpression rexpr(pattern);
+ bool rc = false;
+ QRegularExpressionMatch match;
+ for (int ii = 0; ii < lines.size(); ii++){
+ const QByteArray& line = lines.at(ii);
+ match = rexpr.match(line);
+ if (match.hasMatch()){
+ rc = true;
+ break;
+ }
+ }
+ return rc;
+}
+
/**
* @brief Returns the name of a directory in the temp dir.
*
bool withSeparator = true);
QByteArray getTempFile(const char* node, const char* parent = NULL,
bool deleteIfExists = true);
+ bool logContains(const char* pattern);
void run();
- virtual void doIt() = 0;
+protected:
+ virtual void doIt(void) = 0;
protected:
int m_errors;
QByteArray m_name;
RplLogger m_logger;
+ // for testing of logging code:
+ RplMemoryAppender m_memoryAppender;
+ RplLogger m_memoryLogger;
char m_separator;
};
#define checkE(expected, current) assertEquals(expected, current, __FILE__, __LINE__)
#include "rplmath/rplmath.hpp"
-RplMatrixException::RplMatrixException(int id, const RplMatrix& RplMatrix,
+RplMatrixException::RplMatrixException(const RplMatrix& RplMatrix,
const char* format, ...) :
- m_message()
+ RplException()
{
- if (! RplMatrix.getName().empty())
+ if (! RplMatrix.getName().isEmpty())
m_message = RplMatrix.getName() + ": ";
char buffer[16*1024];
va_end(args);
m_message += buffer;
}
-RplMatrixException::RplMatrixException(const char* format, ...)
-{
- char buffer[16*1024];
-
- va_list args;
- va_start(args, format);
- vsnprintf(buffer, sizeof buffer, format, args);
- va_end(args);
- m_message = buffer;
-}
/**
* Constructor.
*/
RplMatrix::RplMatrix(const RplMatrix& source) :
m_rows(0),
- m_cols(),
+ m_cols(0),
m_values(NULL),
- m_name(source.m_name + std::string("-copy"))
+ m_name(source.m_name + QByteArray("-copy"))
{
resize(source.m_rows, source.m_cols, source.m_values);
}
{
if (m_rows != operand.getRows())
throw RplMatrixException(*this,
- "RplMatrix %s has different row count: %d / %d",
- operand.getName().c_str(), m_rows, operand.getRows());
+ "%s has a different row count: %d / %d",
+ operand.getName().constData(), m_rows, operand.getRows());
if (m_cols != operand.getCols())
throw RplMatrixException(*this,
- "RplMatrix %s has different column count: %d / %d",
- operand.getName().c_str(), m_cols, operand.getCols());
+ "%s has a different column count: %d / %d",
+ operand.getName().constData(), m_cols, operand.getCols());
}
/**
if (rows != m_rows || cols != m_cols){
delete m_values;
m_values = new MatVal[rows * cols];
+ m_rows = rows;
+ m_cols = cols;
}
- int ix = -1;
if (values == NULL)
{
- for (int row = 0; row < m_rows; row++){
- for (int col = 0; row < m_cols; col++)
- m_values[++ix] = defaultValue;
+ for (int ix = rows*cols - 1; ix >= 0; ix--){
+ m_values[ix] = defaultValue;
}
} else {
- for (int row = 0; row < m_rows; row++){
- for (int col = 0; row < m_cols; col++){
- ix++;
- m_values[ix] = values[ix];
- }
- }
+ for (int ix = rows*cols - 1; ix >= 0; ix--){
+ m_values[ix] = values[ix];
+ }
}
return *this;
}
}
return rc;
}
-std::string RplMatrix::toString(const char* prefix, const char* format,
+QByteArray RplMatrix::toString(const char* prefix, const char* format,
const char* rowSeparator, const char* colSeparator) const
{
char buffer[128];
Tuple2 minMaxi(minMax());
- std::string rc;
+ QByteArray rc;
snprintf(buffer, sizeof buffer, format, minMaxi.m_value1);
int length = strlen(buffer);
snprintf(buffer, sizeof buffer, format, minMaxi.m_value2);
/**
* Implements a RplMatrix specific exception.
*/
-class RplMatrixException
+class RplMatrixException : public RplException
{
public:
- explicit RplMatrixException(int id, const char* format, ...);
- explicit RplMatrixException(const RplMatrix& RplMatrix, const char* format, ...);
-public:
- const std::string getMessage() const
- { return m_message; }
-private:
- std::string m_message;
+ RplMatrixException(const RplMatrix& RplMatrix, const char* format, ...);
};
/**
inline bool operator !=(MatVal operand)
{ return ! (*this == operand); }
public:
- inline const std::string& getName() const
+ inline const QByteArray& getName() const
{ return m_name; }
inline MatVal get(int row, int col) const
{ check(row, col); return m_values[row*m_cols + col]; }
MatVal defaultValue = 0.0);
Tuple2 minMax() const;
RplMatrix transpose() const;
- std::string toString(const char* prefix = NULL,
+ QByteArray toString(const char* prefix = NULL,
const char* format = "%f",
const char* rowSeparator = "\n",
const char* colSeparator = ",") const;
int m_rows;
int m_cols;
MatVal* m_values;
- std::string m_name;
+ QByteArray m_name;
};
#endif /* RplMatrix_HPP_ */
int main(int argc, char *argv[])
{
- //QCoreApplication a(argc, argv);
if (argc > 1)
printf("not used: %s\n", argv[1]);
- //return a.exec();
extern void testRplMatrix();
testRplMatrix();
+
+ extern void testRplException();
+ testRplException();
}
--- /dev/null
+/*
+ * Licence:
+ * You can use and modify this file without any restriction.
+ * There is no warranty.
+ * You also can use the licence from http://www.wtfpl.net/.
+ * The original sources can be found on https://github.com/republib.
+*/
+#include "rplcore/rplcore.hpp"
+#include "rplcore/rpltest.hpp"
+
+class TestRplException : public RplTest{
+public:
+ TestRplException() : RplTest("RplException") {}
+
+public:
+ void testBasic() {
+ try{
+ throw RplException("simple");
+ checkF(true);
+ } catch (RplException exc){
+ checkE("simple", exc.getMessage().constData());
+ }
+ try{
+ throw RplException("String: %s and int %d", "Hi", -333);
+ checkF(true);
+ } catch (RplException exc){
+ checkE("String: Hi and int -333", exc.getMessage().constData());
+ }
+ try{
+ throw RplException(LOG_INFO, 1234, &m_memoryLogger,
+ "String: %s and int %d", "Hi", -333);
+ checkF(true);
+ } catch (RplException exc){
+ checkT(logContains("^ .*\\(1234\\): String: Hi and int -333"));
+ }
+ log("ok");
+ }
+ virtual void doIt() {
+ testBasic();
+ }
+};
+void testRplException() {
+ TestRplException test;
+ test.run();
+}
+
+
+
TestRplMatrix() : RplTest("RplMatrix") {}
public:
+ void fillMatrix(RplMatrix& mx, MatVal offset = 0){
+ for(int row = 0; row < mx.getRows(); row++){
+ for (int col = 0; col < mx.getCols(); col++){
+ mx.set(row, col, 100.0*row + col + offset);
+ }
+ }
+ }
+ void checkMatrix(const RplMatrix& mx, MatVal offset = 0){
+ int count = 0;
+ for(int row = 0; row < mx.getRows(); row++){
+ for (int col = 0; col < mx.getCols(); col++){
+ checkE(100.0*row + col + offset, mx.get(row, col));
+ count++;
+ }
+ }
+ checkE(mx.getCols()*mx.getRows(), count);
+ }
+ void fillConst(RplMatrix& mx, MatVal value){
+ for(int row = 0; row < mx.getRows(); row++){
+ for (int col = 0; col < mx.getCols(); col++){
+ mx.set(row, col, value);
+ }
+ }
+ }
+ void checkConst(const RplMatrix& mx, MatVal value){
+ int count = 0;
+ for(int row = 0; row < mx.getRows(); row++){
+ for (int col = 0; col < mx.getCols(); col++){
+ checkE(value, mx.get(row, col));
+ count++;
+ }
+ }
+ checkE(mx.getCols()*mx.getRows(), count);
+ }
+
void testBasic() {
Tuple2 tuple(-2.0, 0.5);
checkE(-2.0, tuple.m_value1);
checkE(0.5, tuple.m_value2);
- try{
- throw RplMatrixException(1, "String: %s and int %d", "Hi", -333);
- checkF(true);
- } catch (RplMatrixException exc){
- checkE("String: Hi and int -333", exc.getMessage());
- }
RplMatrix mat("mx");
try{
throw RplMatrixException(mat, "String: %s and int %d", "Hi", -333);
} catch (RplMatrixException exc){
checkE("String: Hi and int -333", exc.getMessage());
}
+ checkE("mx", mat.getName());
+ checkE("", mat2.getName());
+
+ RplMatrix m2x3(2, 3, "m2x3");
+ checkE("m2x3", m2x3.getName());
+ checkE(2, m2x3.getRows());
+ checkE(3, m2x3.getCols());
+ fillMatrix(m2x3);
+ checkMatrix(m2x3);
+
+ RplMatrix mxCopy(m2x3);
+ checkE("m2x3-copy", mxCopy.getName());
+ checkE(2, mxCopy.getRows());
+ checkE(3, mxCopy.getCols());
+ checkMatrix(mxCopy);
+
+ RplMatrix mxCopy2("mxCopy2");
+ mxCopy2 = m2x3;
+ checkE("mxCopy2", mxCopy2.getName());
+ checkE(2, mxCopy2.getRows());
+ checkE(3, mxCopy2.getCols());
+ checkMatrix(mxCopy2);
+ }
+ void testAddOperators(){
+ RplMatrix m1(3, 2, "m1");
+ fillMatrix(m1);
+ checkMatrix(m1);
+ RplMatrix m2(3, 2, "m2");
+ fillMatrix(m2, 42);
+ checkMatrix(m2, 42);
+ RplMatrix m3(3, 2, "m3");
+ fillMatrix(m3, -42);
+ checkMatrix(m3, -42);
+
+ m1 += 42;
+ checkMatrix(m1, 42);
+
+ checkT(m1 == m2);
+ checkF(m1 == m3);
+
+ m1 -= 42;
+ checkMatrix(m1);
+ m1 -= m1;
+ checkConst(m1, 0);
+
+ fillMatrix(m1);
+ m1 -= m3;
+ checkConst(m1, 42);
+ m1 += m2;
+ checkMatrix(m1, 42*2);
+ }
+ void testCompareOperators(){
+ RplMatrix m1(3, 2, "m1");
+ fillMatrix(m1);
+ checkMatrix(m1);
+ RplMatrix m2(3, 2, "m2");
+ fillMatrix(m2);
+
+ checkT(m1 == m2);
+ checkF(m1 != m2);
+ // modify each element, comparism must return false:
+ int row, col;
+ for (row = 0; row < m2.getRows(); row++)
+ for (col = 0; col < m2.getCols(); col++){
+ fillMatrix(m2);
+ m2.set(row, col, -1);
+ checkF(m1 == m2);
+ checkT(m1 != m2);
+ }
+
+ fillConst(m1, 42);
+ checkT(m1 == 42);
+ checkF(m1 == 43);
+ checkT(m1 != 43);
+ for (row = 0; row < m1.getRows(); row++)
+ for (col = 0; col < m1.getCols(); col++){
+ fillMatrix(m1, 42);
+ m1.set(row, col, -1);
+ checkF(m1 == 42);
+ checkT(m1 != 42);
+ }
+ }
+
+ void testCheckDefinition(){
+ RplMatrix m1(3, 2, "m1");
+ fillMatrix(m1);
+ checkMatrix(m1);
+ RplMatrix m2(3, 2, "m2");
+ fillMatrix(m2);
+
+ m1.checkDefinition(1, 1);
+ m1.checkDefinition(1000, 1000);
+ m1.checkDefinition(0, 0);
+ try {
+ m1.checkDefinition(-1, 1);
+ checkT(false);
+ } catch(RplMatrixException exc){
+ checkE("m1: row number negative: -1", exc.getMessage());
+ }
+ try {
+ m1.checkDefinition(1, -1);
+ checkT(false);
+ } catch(RplMatrixException exc){
+ checkE("m1: column number negative: -1", exc.getMessage());
+ }
+
+ }
+ void testCheck(){
+ RplMatrix m1(3, 2, "m1");
+ fillMatrix(m1);
+ checkMatrix(m1);
+
+ m1.check(0, 0);
+ m1.check(3-1, 2-1);
+ try {
+ m1.check(-1, 1);
+ checkT(false);
+ } catch(RplMatrixException exc){
+ checkE("m1: invalid row: -1 not in [0,3[", exc.getMessage());
+ }
+ try {
+ m1.check(3, 1);
+ checkT(false);
+ } catch(RplMatrixException exc){
+ checkE("m1: invalid row: 3 not in [0,3[", exc.getMessage());
+ }
+ try {
+ m1.check(1, -1);
+ checkT(false);
+ } catch(RplMatrixException exc){
+ checkE("m1: invalid column: -1 not in [0,2[", exc.getMessage());
+ }
+ try {
+ m1.check(1, 2);
+ checkT(false);
+ } catch(RplMatrixException exc){
+ checkE("m1: invalid column: 2 not in [0,2[", exc.getMessage());
+ }
+ }
+ void testCheckSameDimension(){
+ RplMatrix m1(3, 2, "m1");
+ RplMatrix m2(3, 2, "m2");
+
+ m1.checkSameDimension(m2);
+
+ m2.resize(2, 2);
+ try {
+ m1.checkSameDimension(m2);
+ checkT(false);
+ } catch(RplMatrixException exc){
+ checkE("m1: m2 has a different row count: 3 / 2", exc.getMessage());
+ }
+ m2.resize(3, 3);
+ try {
+ m1.checkSameDimension(m2);
+ checkT(false);
+ } catch(RplMatrixException exc){
+ checkE("m1: m2 has a different column count: 2 / 3", exc.getMessage());
+ }
+ log("");
+/*
+ void checkDefinition(int rows, int cols) const;
+ void check(int row, int col) const;
+ void checkSameDimension(const RplMatrix& operand) const;
+*/
}
- virtual void doIt() {
+ virtual void doIt(void) {
testBasic();
+ testAddOperators();
+ testCompareOperators();
+ testCheckDefinition();
+ testCheck();
+ testCheckSameDimension();
}
};
void testRplMatrix() {
SOURCES += main.cpp \
rplmatrix_test.cpp \
- ../rplmath/rplmatrix.cpp
+ ../rplmath/rplmatrix.cpp \
+ ../rplcore/rpllogger.cpp \
+ ../rplcore/rpltest.cpp \
+ ../rplcore/rplstring.cpp \
+ ../rplcore/rplexception.cpp \
+ rplexception_test.cpp