From: hama Date: Mon, 6 Apr 2015 01:41:50 +0000 (+0200) Subject: allTests works, ReUnitParser works X-Git-Url: https://gitweb.hamatoma.de/?a=commitdiff_plain;h=90cca5179a1bd7b5a47c157093f2f168f43cd665;p=reqt allTests works, ReUnitParser works --- diff --git a/appl/qfilesearch b/appl/qfilesearch deleted file mode 160000 --- a/appl/qfilesearch +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 0000000000000000000000000000000000000000 diff --git a/appl/refind b/appl/refind new file mode 160000 --- /dev/null +++ b/appl/refind @@ -0,0 +1 @@ +Subproject commit 0000000000000000000000000000000000000000 diff --git a/base/ReContainer.cpp b/base/ReContainer.cpp index 6b7e5bf..67a439a 100644 --- a/base/ReContainer.cpp +++ b/base/ReContainer.cpp @@ -1,6 +1,6 @@ /* * ReContainer.cpp - * + * * License: Public Domain * You can use and modify this file without any restriction. * Do what you want. @@ -266,7 +266,8 @@ void ReContainer::nextItem(type_tag_t expected){ m_ixItem = 0; } if (m_ixItem >= m_typeList.length()) - throw ReException(LOG_ERROR, LOC_NEXT_ITEM_1, "no more items in the bag"); + throw ReException(LOG_ERROR, LOC_NEXT_ITEM_1, ReLogger::globalLogger(), + "no more items in the bag"); type_tag_t current = (type_tag_t) m_typeList.at(m_ixItem); // Unify all data types: if (current == TAG_DATA4G || current == TAG_DATA64K) diff --git a/base/ReQString.cpp b/base/ReQString.cpp deleted file mode 100644 index a57930b..0000000 --- a/base/ReQString.cpp +++ /dev/null @@ -1,180 +0,0 @@ -/* - * ReQString.cpp - * - * License: Public Domain - * You can use and modify this file without any restriction. - * Do what you want. - * No warranties and disclaimer of any damages. - * You also can use this license: http://www.wtfpl.net - * The latest sources: https://github.com/republib - */ - -/** @file - * @brief Missed operation for ReStrings. - */ -/** @file rplcore/rplqstring.hpp - * - * @brief Definitions for missed operation for ReStrings. - */ -#include "base/rebase.hpp" - -/** - * @brief Determines the length and vlaue of an integer. - * - * @param text the number as text - * @param start the first index to inspect - * @param radix the base of the number sytem: 8 (octal), 10 or 16 - * @param pValue OUT: the value of the integer. May be NULL - * - * @return <=0: no integer found - * otherwise: the length of the integer - */ -int ReQString::lengthOfUInt64(const ReString& text, int start, int radix, - quint64* pValue){ - int inputLength = text.size(); - int64_t value = 0; - int ix = start; - int cc; - if (radix == 10){ - while (ix < inputLength){ - if ((cc = text[ix].unicode()) >= '0' && cc <= '9') - value = value * 10 + cc - '0'; - else - break; - ix++; - } - }else if (radix == 16){ - while (ix < inputLength){ - if ((cc = text[ix].unicode()) >= '0' && cc <= '9') - value = value * 16 + cc - '0'; - else if (cc >= 'A' && cc <= 'F') - value = value * 16 + cc - 'A' + 10; - else if (cc >= 'a' && cc <= 'f') - value = value * 16 + cc - 'a' + 10; - else - break; - ix++; - } - }else if (radix == 8){ - while (ix < inputLength){ - if ((cc = text[ix].unicode()) >= '0' && cc <= '7') - value = value * 8 + cc - '0'; - else - break; - ix++; - } - }else{ - throw ReException("ReQString::lengthOfInt(): wrong radix: %d", radix); - } - if (pValue != NULL) - *pValue = value; - return ix - start; -} -/** - * @brief Determines the length and value of an unsigned integer. - * - * @param text the number as text - * @param start the first index to inspect - * @param radix the base of the number sytem: 8 (octal), 10 or 16 - * @param pValue OUT: the value of the integer. May be NULL - * - * @return 0: no integer found - * otherwise: the length of the integer - */ -int ReQString::lengthOfUInt(const ReString& text, int start, int radix, - uint* pValue){ - quint64 value; - int rc = lengthOfUInt64(text, start, radix, &value); - if (pValue != NULL) - *pValue = (uint) value; - return rc; -} - -/** - * @brief Determines the length and value of a floting point number. - * - * @param text the number as text - * @param start the first index to inspect - * @param pValue OUT: the value of the integer. May be NULL - * - * @return <=0: no real number found - * otherwise: the length of the floating point number - */ -int ReQString::lengthOfReal(const ReString& text, int start, qreal* pValue){ - int inputLength = text.size(); - qreal value = 0.0; - int cc; - int ix = start; - while (ix < inputLength){ - if ((cc = text[ix].unicode()) >= '0' && cc <= '9') - value = value * 10 + (cc - '0'); - else - break; - ix++; - } - // found: a digit has been found (in front of or behind the '.' - bool found = ix > start; - if (ix < inputLength && text[ix].unicode() == '.'){ - ix++; - } - if (ix < inputLength && text[ix].isDigit()){ - found = true; - qreal divisor = 1; - qreal precision = 0; - while (ix < inputLength && (cc = text[ix].unicode()) >= '0' && cc <= '9'){ - divisor *= 10; - precision = precision * 10 + cc - '0'; - ix++; - } - value += precision / divisor; - }else if (!found){ - ix = start; - } - if (found && ix + 1 < inputLength && toupper(text[ix].unicode()) == 'E'){ - int savePoint = ix; - ix++; - bool negative = false; - if ((cc = text[ix].unicode()) == '+') - ix++; - else if (cc == '-'){ - ix++; - negative = true; - } - if (ix >= inputLength || !text[ix].isDigit()) - ix = savePoint; - else{ - int exponent = 0; - while (ix < inputLength && text[ix].isDigit()){ - exponent = exponent * 10 + text[ix].unicode() - '0'; - ix++; - } - if (negative) - value /= qPow(10, exponent); - else - value *= qPow(10, exponent); - } - } - if (pValue) - *pValue = value; - return found ? ix - start : 0; -} - -/** - * @brief Converts a ReString into an utf-8 string - * - * The expression qstring.toUtf8().constData() is not allowed - * in a variable argument list like sprintf. This is a thread save workaround. - * - * @param source string to convert - * @param buffer OUT: target buffer - * @param bufferSize size of the target buffer - * @return buffer - */ -char*ReQString::utf8(const ReString& source, char buffer[], size_t bufferSize){ - QByteArray val = source.toUtf8(); - if (val.length() < (int) bufferSize) - bufferSize = val.length() + 1; - memcpy(buffer, val.constData(), bufferSize - 1); - buffer[bufferSize - 1] = '\0'; - return buffer; -} diff --git a/base/ReQStringUtil.cpp b/base/ReQStringUtil.cpp new file mode 100644 index 0000000..7dd4c06 --- /dev/null +++ b/base/ReQStringUtil.cpp @@ -0,0 +1,360 @@ +/* + * ReQStringUtil.cpp + * + * License: Public Domain + * You can use and modify this file without any restriction. + * Do what you want. + * No warranties and disclaimer of any damages. + * You also can use this license: http://www.wtfpl.net + * The latest sources: https://github.com/republib + */ + +/** @file + * @brief Missed operation for ReStrings. + */ +/** @file rplcore/rplqstring.hpp + * + * @brief Definitions for missed operation for ReStrings. + */ +#include "base/rebase.hpp" +#include +/** + * @brief Determines the length and vlaue of an integer. + * + * @param text the number as text + * @param start the first index to inspect + * @param radix the base of the number sytem: 8 (octal), 10 or 16 + * @param pValue OUT: the value of the integer. May be NULL + * + * @return <=0: no integer found + * otherwise: the length of the integer + */ +int ReQStringUtil::lengthOfUInt64(const ReString& text, int start, int radix, + quint64* pValue){ + int inputLength = text.size(); + int64_t value = 0; + int ix = start; + int cc; + if (radix == 10){ + while (ix < inputLength){ + if ((cc = text[ix].unicode()) >= '0' && cc <= '9') + value = value * 10 + cc - '0'; + else + break; + ix++; + } + }else if (radix == 16){ + while (ix < inputLength){ + if ((cc = text[ix].unicode()) >= '0' && cc <= '9') + value = value * 16 + cc - '0'; + else if (cc >= 'A' && cc <= 'F') + value = value * 16 + cc - 'A' + 10; + else if (cc >= 'a' && cc <= 'f') + value = value * 16 + cc - 'a' + 10; + else + break; + ix++; + } + }else if (radix == 8){ + while (ix < inputLength){ + if ((cc = text[ix].unicode()) >= '0' && cc <= '7') + value = value * 8 + cc - '0'; + else + break; + ix++; + } + }else{ + throw ReException("ReQStringUtil::lengthOfInt(): wrong radix: %d", radix); + } + if (pValue != NULL) + *pValue = value; + return ix - start; +} +/** + * @brief Determines the length and value of an unsigned integer. + * + * @param text the number as text + * @param start the first index to inspect + * @param radix the base of the number sytem: 8 (octal), 10 or 16 + * @param pValue OUT: the value of the integer. May be NULL + * + * @return 0: no integer found + * otherwise: the length of the integer + */ +int ReQStringUtil::lengthOfUInt(const ReString& text, int start, int radix, + uint* pValue){ + quint64 value; + int rc = lengthOfUInt64(text, start, radix, &value); + if (pValue != NULL) + *pValue = (uint) value; + return rc; +} + +/** + * @brief Determines the length and value of a floting point number. + * + * @param text the number as text + * @param start the first index to inspect + * @param pValue OUT: the value of the integer. May be NULL + * + * @return <=0: no real number found + * otherwise: the length of the floating point number + */ +int ReQStringUtil::lengthOfReal(const ReString& text, int start, qreal* pValue){ + int inputLength = text.size(); + qreal value = 0.0; + int cc; + int ix = start; + while (ix < inputLength){ + if ((cc = text[ix].unicode()) >= '0' && cc <= '9') + value = value * 10 + (cc - '0'); + else + break; + ix++; + } + // found: a digit has been found (in front of or behind the '.' + bool found = ix > start; + if (ix < inputLength && text[ix].unicode() == '.'){ + ix++; + } + if (ix < inputLength && text[ix].isDigit()){ + found = true; + qreal divisor = 1; + qreal precision = 0; + while (ix < inputLength && (cc = text[ix].unicode()) >= '0' && cc <= '9'){ + divisor *= 10; + precision = precision * 10 + cc - '0'; + ix++; + } + value += precision / divisor; + }else if (!found){ + ix = start; + } + if (found && ix + 1 < inputLength && toupper(text[ix].unicode()) == 'E'){ + int savePoint = ix; + ix++; + bool negative = false; + if ((cc = text[ix].unicode()) == '+') + ix++; + else if (cc == '-'){ + ix++; + negative = true; + } + if (ix >= inputLength || !text[ix].isDigit()) + ix = savePoint; + else{ + int exponent = 0; + while (ix < inputLength && text[ix].isDigit()){ + exponent = exponent * 10 + text[ix].unicode() - '0'; + ix++; + } + if (negative) + value /= qPow(10, exponent); + else + value *= qPow(10, exponent); + } + } + if (pValue) + *pValue = value; + return found ? ix - start : 0; +} + +/** + * @brief Converts a ReString into an utf-8 string + * + * The expression qstring.toUtf8().constData() is not allowed + * in a variable argument list like sprintf. This is a thread save workaround. + * + * @param source string to convert + * @param buffer OUT: target buffer + * @param bufferSize size of the target buffer + * @return buffer + */ +char*ReQStringUtil::utf8(const ReString& source, char buffer[], + size_t bufferSize){ + QByteArray val = source.toUtf8(); + if (val.length() < (int) bufferSize) + bufferSize = val.length() + 1; + memcpy(buffer, val.constData(), bufferSize - 1); + buffer[bufferSize - 1] = '\0'; + return buffer; +} + +class ReParserException : public ReException { +public: + ReParserException(const QString& message) : + ReException(), + m_message(message){ + } +public: + QString m_message; +}; +/** + * Constructor. + * + * @param expr an expression, e.g. "10*1024kByte+5MiByte" + * @param unitList description of the allowed units with its factor
+ * example: "kibyte:1024;kbyte:1000;mibyte:1048576;mbyte:1000000" + */ +ReUnitParser::ReUnitParser(const QString& expr, const char* unitList) : + m_result(0), m_expr(expr), m_message(), m_unitList(unitList){ + // Replace the '-' operator by '+' as operator and '-' as sign: + // This makes the syntax easier to parse: only one sum operator ('+'). + for (int ii = m_expr.length() - 1; ii > 0; ii--){ + if (m_expr[ii] == '-' && m_expr[ii -1] != '+' && m_expr[ii - 1] != '*'){ + m_expr.insert(ii, '+'); + } + } + parse(); +} +/** + * Returns whether the given expression is valid. + * + * @return true: the expression is valid, a result was calculated + */ +bool ReUnitParser::isValid() const{ + return m_message.isEmpty(); +} +/** + * Returns an empty string or the error message. + * + * @return "": no error occurred
+ * otherwise: the error message + */ +const QString& ReUnitParser::errorMessage() const{ + return m_message; +} +/** + * Returns the result of the expression as a 64 bit integer. + * + * @param defaultValue the result if the expression was not valid + * @return defaultValue: the result was not valid
+ * the result as a 64 bit integer + */ +int64_t ReUnitParser::asInt64(int64_t defaultValue){ + return m_message.isEmpty() ? m_result : defaultValue; +} +/** + * Returns the result of the expression as an integer. + * + * @param defaultValue the result if the expression was not valid + * @return defaultValue: the result was not valid
+ * the result as an integer + */ +int ReUnitParser::asInt(int defaultValue){ + return m_message.isEmpty() ? (int) m_result : defaultValue; +} +/** + * Returns the result of the expression as floating point number. + * + * @param defaultValue the result if the expression was not valid + * @return defaultValue: the result was not valid
+ * the result as a floating point + */ +real_t ReUnitParser::asReal(real_t defaultValue){ + return m_message.isEmpty() ? (real_t) m_result : defaultValue; +} + +/** + * Calculates the value of a number or a (number, unit) pair. + * + * @param value a non negative number or a number followed by a unit
+ * only units defined in m_unitList are allowed
+ * examples: "4kByte" returns 4000, "4kibyte" returns 4096 + * @return the value of the number multiplied by the factor given by the unit + * @throws ReParserException + */ +uint64_t ReUnitParser::valueOf(const QString& value) const{ + uint64_t rc = 0; + int ix = ReQStringUtil::lengthOfUInt64(value, 0, 10, &rc); + if (ix == 0) + throw ReParserException(QObject::tr("number expected: ") + value); + QString unit = value.mid(ix); + if (! unit.isEmpty()){ + QStringList units = QString(m_unitList).split(";"); + QStringList::const_iterator it; + bool found = false; + for (it = units.begin(); it != units.end(); ++it){ + QStringList pair = it->split(":"); + if (pair.count() == 0) + throw ReParserException(QObject::tr("missing ':' in unit definition, e.g. 'k:1000': ") + *it); + if (pair.count() > 2) + throw ReParserException(QObject::tr("too many ':' in unit definition: ") + *it); + bool ok = false; + QString unit2 = *pair.begin(); + QString factor = *++pair.begin(); + uint64_t nFactor = factor.toLongLong(&ok); + if (! ok) + throw ReParserException(QObject::tr("not a number: ") + factor); + if (unit2.startsWith(unit)){ + rc *= nFactor; + found = true; + break; + } + } + if (! found) + throw ReParserException(QObject::tr("unknown unit, allowed: ") + QString(m_unitList)); + } + return rc; +} +/** + * Evaluate the expression. + */ +void ReUnitParser::parse(){ + QStringList addends = m_expr.split("+"); + QStringList::const_iterator it; + try{ + m_result = 0; + for (it = addends.begin(); it != addends.end(); ++it){ + QStringList factors = it->split("*"); + QStringList::const_iterator it2; + int64_t product = 1; + for (it2 = factors.begin(); it2 != factors.end(); ++it2){ + QStringList powerOperands = it2->split("^"); + if (powerOperands.count() > 2) + throw ReParserException(QObject::tr("more than 2 power operators, e.g. '2^3^4'")); + QStringList::const_iterator it3 = powerOperands.begin(); + QString op = *it3; + bool isNeg = op.startsWith("-"); + if (isNeg) + op = op.mid(1); + uint64_t value = valueOf(op); + if (powerOperands.count() > 1){ + uint64_t fac = value; + uint64_t exponent = valueOf(*++it3); + if (qLn(value) * qLn(exponent) >= qLn(qPow(2.0, 64))) + throw ReParserException(QObject::tr("number overflow while power operation")); + for (int ii = 1; ii < (int) exponent; ii++) + value = value * fac; + } + product *= value; + if (isNeg) + product = -product; + } + m_result += product; + } + + } catch (ReParserException& e){ + m_message = e.m_message; + } +} + +/** + * Constructor. + * + * @param expr an expression, e.g. "10*1024kByte+5MiByte" + */ +ReSizeParser::ReSizeParser(const QString& expr) : + ReUnitParser(expr, "byte:1;kbyte:1000;kibyte:1024;" + "mbyte:1000000;mibyte:1048576;" + "gbyte:1000000000;gibyte:1073741824;" + "tbyte:1000000000000;tibyte:1099511627776"){ +} +/** + * Constructor. + * + * @param expr an expression, e.g. "3*3days-5min+3weeks" + */ +ReDateTimeParser::ReDateTimeParser(const QString& expr) : + ReUnitParser(expr, "minutes:60;hours:3600;days:86400;weeks:604800"){ +} diff --git a/base/ReQStringUtil.hpp b/base/ReQStringUtil.hpp new file mode 100644 index 0000000..7af38e9 --- /dev/null +++ b/base/ReQStringUtil.hpp @@ -0,0 +1,67 @@ +/* + * ReQtring.hpp + * + * License: Public Domain + * You can use and modify this file without any restriction. + * Do what you want. + * No warranties and disclaimer of any damages. + * You also can use this license: http://www.wtfpl.net + * The latest sources: https://github.com/republib + */ + +#ifndef RPLQSTRING_HPP +#define RPLQSTRING_HPP + +class ReQStringUtil { +public: + static int lengthOfUInt64(const ReString& text, int start = 0, + int radix = 10, uint64_t* value = NULL); + static int lengthOfUInt(const ReString& text, int start, int radix, + uint* pValue); + static int lengthOfReal(const ReString& text, int start = 0, qreal* value = + NULL); + /** + * @brief Returns the value of a hexadecimal digit. + * + * @param digit a (unicode) character + * @return -1: not a hexadecimal digit
+ * otherwise: the value, e.g. 10 for 'a' + */ + inline static int valueOfHexDigit(int digit){ + return digit >= '0' && digit <= '9' ? digit - '0' : + digit >= 'A' && digit <= 'F' ? digit - 'A' + 10 : + digit >= 'a' && digit <= 'f' ? digit - 'a' + 10 : -1; + } + static char* utf8(const ReString& source, char buffer[], size_t bufferSize); +}; + +class ReUnitParser { +public: + ReUnitParser(const QString& expr, const char* unitList); +public: + bool isValid() const; + const QString& errorMessage() const; + int64_t asInt64(int64_t defaultValue = -1ll); + int asInt(int defaultValue = -1); + real_t asReal(real_t defaultValue = -1.0); +private: + void parse(); + uint64_t valueOf(const QString& value) const; +private: + int64_t m_result; + QString m_expr; + QString m_message; + const char* m_unitList; +}; + +class ReSizeParser : public ReUnitParser { +public: + ReSizeParser(const QString& expr); +}; + +class ReDateTimeParser : public ReUnitParser { +public: + ReDateTimeParser(const QString& expr); +}; + +#endif // RPLQSTRING_HPP diff --git a/base/ReQtring.hpp b/base/ReQtring.hpp deleted file mode 100644 index 77e1e94..0000000 --- a/base/ReQtring.hpp +++ /dev/null @@ -1,38 +0,0 @@ -/* - * ReQtring.hpp - * - * License: Public Domain - * You can use and modify this file without any restriction. - * Do what you want. - * No warranties and disclaimer of any damages. - * You also can use this license: http://www.wtfpl.net - * The latest sources: https://github.com/republib - */ - -#ifndef RPLQSTRING_HPP -#define RPLQSTRING_HPP - -class ReQString { -public: - static int lengthOfUInt64(const ReString& text, int start = 0, - int radix = 10, quint64* value = NULL); - static int lengthOfUInt(const ReString& text, int start, int radix, - uint* pValue); - static int lengthOfReal(const ReString& text, int start = 0, qreal* value = - NULL); - /** - * @brief Returns the value of a hexadecimal digit. - * - * @param digit a (unicode) character - * @return -1: not a hexadecimal digit
- * otherwise: the value, e.g. 10 for 'a' - */ - inline static int valueOfHexDigit(int digit){ - return digit >= '0' && digit <= '9' ? digit - '0' : - digit >= 'A' && digit <= 'F' ? digit - 'A' + 10 : - digit >= 'a' && digit <= 'f' ? digit - 'a' + 10 : -1; - } - static char* utf8(const ReString& source, char buffer[], size_t bufferSize); -}; - -#endif // RPLQSTRING_HPP diff --git a/base/ReTerminator.hpp b/base/ReTerminator.hpp index d72d627..d8a193d 100644 --- a/base/ReTerminator.hpp +++ b/base/ReTerminator.hpp @@ -1,6 +1,6 @@ /* * ReTerminator.hpp - * + * * License: Public Domain * You can use and modify this file without any restriction. * Do what you want. diff --git a/base/ReTest.cpp b/base/ReTest.cpp index 22253b4..a8f9537 100644 --- a/base/ReTest.cpp +++ b/base/ReTest.cpp @@ -1,6 +1,6 @@ /* * ReTest.cpp - * + * * License: Public Domain * You can use and modify this file without any restriction. * Do what you want. @@ -42,19 +42,21 @@ ReTest::ReTest(const char* name) : m_logger.buildStandardAppender(getTempDir("rpltest")); log(QByteArray("Start of ") + m_name); m_memoryLogger.addAppender(&m_memoryAppender); - try{ - run(); - } catch (ReException e){ - error("unexpected RplException: %s", e.getMessage().constData()); - } catch (...){ - error("unknown Exception"); - } +} +void ReTest::doIt(){ + try{ + run(); + } catch (ReException e){ + error("unexpected RplException: %s", e.getMessage().constData()); + } catch (...){ + error("unknown Exception"); + } - if (m_errors > 0){ - error("Unit %s has %d error(s)", m_name.data(), m_errors); - // error() increments, we decrement: - m_errors--; - } + if (m_errors > 0){ + error("Unit %s has %d error(s)", m_name.data(), m_errors); + // error() increments, we decrement: + m_errors--; + } } /** diff --git a/base/ReTest.hpp b/base/ReTest.hpp index 9b27d01..0e85581 100644 --- a/base/ReTest.hpp +++ b/base/ReTest.hpp @@ -1,6 +1,6 @@ /* * ReTest.hpp - * + * * License: Public Domain * You can use and modify this file without any restriction. * Do what you want. @@ -21,6 +21,8 @@ private: ReTest(const ReTest& source); // Prohibits assignment operator: no implementation! ReTest& operator =(const ReTest& source); +protected: + void doIt(); public: bool assertEquals(int expected, int current, const char* file, int lineNo); bool assertEquals(int64_t expected, int64_t current, const char* file, diff --git a/base/rebase.hpp b/base/rebase.hpp index b7cb676..c8f0d85 100644 --- a/base/rebase.hpp +++ b/base/rebase.hpp @@ -8,8 +8,8 @@ * You also can use this license: http://www.wtfpl.net * The latest sources: https://github.com/republib */ -#ifndef RECORE_HPP -#define RECORE_HPP +#ifndef REBASE_HPP +#define REBASE_HPP #include #include @@ -20,9 +20,6 @@ #include #include -#include -#include -#include #include #include #include @@ -32,7 +29,7 @@ #include #include #include - +#include typedef unsigned char uint8_t; //typedef qint64 int64_t; typedef quint64 uint64_t; @@ -50,10 +47,10 @@ typedef QString ReString; #include "base/ReException.hpp" #include "base/ReContainer.hpp" #include "base/ReStringUtil.hpp" -#include "base/ReQtring.hpp" +#include "ReQStringUtil.hpp" #include "base/ReConfigurator.hpp" #include "base/ReConfig.hpp" #include "base/ReTerminator.hpp" #include "base/ReTest.hpp" -#endif // RECORE_HPP +#endif // REBASE_HPP diff --git a/base/testrplexample.cpp b/base/testrplexample.cpp index a220646..f4c53dc 100644 --- a/base/testrplexample.cpp +++ b/base/testrplexample.cpp @@ -1,6 +1,6 @@ /* * testrplexample.cpp - * + * * License: Public Domain * You can use and modify this file without any restriction. * Do what you want. @@ -10,7 +10,7 @@ */ include "project.hpp" -#include "base/base.hpp" +#include "base/rebase.hpp" // Code to test: int add(int a, int b){ return a+b; diff --git a/cunit/allTests.cpp b/cunit/allTests.cpp new file mode 100644 index 0000000..dea96b8 --- /dev/null +++ b/cunit/allTests.cpp @@ -0,0 +1,81 @@ +/* + * allTests.cpp + * + * License: Public Domain + * You can use and modify this file without any restriction. + * Do what you want. + * No warranties and disclaimer of any damages. + * You also can use the license from http://www.wtfpl.net/. + * The latest sources: https://github.com/republib + */ +#include "base/rebase.hpp" +#include "math/remath.hpp" +#include "net/renet.hpp" +//#include "os/reos.hpp" + +static bool s_allTest = true; + +static void testBase(){ + void testReByteStorage(); + void testReCharPtrMap(); + void testReConfig(); + void testReContainer(); + void testReException(); + void testReQStringUtil(); + void testReStringUtil(); + void testReWriter(); + + testReQStringUtil(); + if (s_allTest){ + testReByteStorage(); + testReCharPtrMap(); + testReConfig(); + testReContainer(); + testReException(); + testReQStringUtil(); + testReStringUtil(); + testReWriter(); + } +} +static void testMath(){ + +} +static void testExpr(){ + extern void testReMFParser(); + extern void testRplBenchmark(); + extern void testReVM(); + extern void testReSource(); + extern void testReLexer(); + extern void testReMFParser(); + extern void testReASTree(); + extern void testReVM(); + + //testRplBenchmark(); + if (s_allTest){ + testReVM(); + testReSource(); + testReLexer(); + testReMFParser(); + testReASTree(); + testReVM(); + } +} +static void testNet(){ + +} +static void testOs(){ + +} +void allTests(){ + testBase(); + if (s_allTest){ + testBase(); + testMath(); + testExpr(); + testNet(); + testOs(); + } +} + + + diff --git a/cunit/cuReASTree.cpp b/cunit/cuReASTree.cpp new file mode 100644 index 0000000..fde8699 --- /dev/null +++ b/cunit/cuReASTree.cpp @@ -0,0 +1,104 @@ +/* + * rplastree_test.cpp + * + * License: Public Domain + * You can use and modify this file without any restriction. + * Do what you want. + * No warranties and disclaimer of any damages. + * You also can use this license: http://www.wtfpl.net + * The latest sources: https://github.com/republib + */ + +/** @file + * @brief Unit test of the abstract syntax tree. + */ + + +#include "base/rebase.hpp" +#include "expr/reexpr.hpp" + +class TestReASTree : public ReTest{ +private: + ReSource m_source; + ReStringReader m_reader; + ReStringSourceUnit m_unit; + ReASTree m_tree; +public: + TestReASTree() : + ReTest("ReASTree"), + m_source(), + m_reader(m_source), + m_unit("
", "", &m_reader), + m_tree() + {} +public: + void testReASException() { + try{ + m_reader.addSource("
", "12"); + m_source.addReader(&m_reader); + m_source.addSourceUnit(m_reader.currentSourceUnit()); + const ReSourcePosition* pos = m_source.newPosition(2); + throw ReASException(pos, "simple string: %s", "Hi"); + checkF(true); + } catch (ReASException exc){ + checkEqu("
:0:2: simple string: Hi", exc.getMessage().constData()); + } + } + void testReASVariant(){ + ReASVariant val1; + val1.setFloat(2.5E-2); + checkEqu(2.5E-2, val1.asFloat()); + ReASVariant val2(val1); + checkEqu(2.5E-2, val2.asFloat()); + + val1.setInt(4321); + checkEqu(4321, val1.asInt()); + val2 = val1; + checkEqu(4321, val2.asInt()); + + val1.setBool(false); + checkF(val1.asBool()); + val2 = val1; + checkF(val2.asBool()); + + val1.setBool(true); + checkT(val1.asBool()); + val2 = val1; + checkT(val2.asBool()); + + val1.setString("High noon!"); + checkEqu("High noon!", *val1.asString()); + val2 = val1; + val1.setString("Bye"); + checkEqu("High noon!", *val2.asString()); + ReASVariant val3(val1); + checkEqu("Bye", *val3.asString()); + } + void testReASConstant(){ + ReASConstant constant; + //constant.value().setString("Jonny"); + ReASVariant value; + //constant.calc(value); + //checkEqu("Jonny", *value.asString()); + } + void testReASNamedValue(){ + ReASNamedValue value(NULL, m_tree.symbolSpaces()[0], "gugo", + ReASNamedValue::A_GLOBAL); + checkEqu("gugo", value.name()); + } + virtual void run() { + testReASNamedValue(); + testReASConstant(); + testReASException(); + testReASVariant(); + } +}; +void testReASTree() { + TestReASTree test; +} + + + + + + diff --git a/cunit/cuReBench.cpp b/cunit/cuReBench.cpp new file mode 100644 index 0000000..5a87df4 --- /dev/null +++ b/cunit/cuReBench.cpp @@ -0,0 +1,63 @@ +/* + * rplbench.cpp + * + * License: Public Domain + * You can use and modify this file without any restriction. + * Do what you want. + * No warranties and disclaimer of any damages. + * You also can use this license: http://www.wtfpl.net + * The latest sources: https://github.com/republib + */ + +/** @file + * @brief Unit test of the abstract syntax tree. + */ + + +#include "base/rebase.hpp" +#include "expr/reexpr.hpp" + +class TestRplBenchmark : public ReTest{ +private: + const char* m_filename; + ReSource m_source; + ReFileReader m_reader; + ReASTree m_tree; +public: + TestRplBenchmark() : + ReTest("RplBenchmark"), + m_filename("/home/ws/qt/rplqt/bench/mfbench.mf"), + m_source(), + m_reader(m_source), + m_tree() + { + m_source.addReader(&m_reader); + m_reader.addSource(m_filename); + } +public: + void benchmark() { + time_t start = time(NULL); + ReMFParser parser(m_source, m_tree); + parser.parse(); + time_t end = time(NULL); + printf("compilation: %d sec\n", int(end - start)); + } + virtual void run() { + try{ + ReFileSourceUnit* unit = dynamic_cast + (m_reader.currentSourceUnit()); + if (unit != NULL && ! unit->isOpen()) + throw ReException("file not found: %s", m_filename); + benchmark(); + } catch(ReException ex){ + printf("%s\n", ex.getMessage().constData()); + } + } +}; +void testRplBenchmark() { + TestRplBenchmark test; + test.run(); +} + + + diff --git a/cunit/cuReByteStorage.cpp b/cunit/cuReByteStorage.cpp new file mode 100644 index 0000000..fb8cf6d --- /dev/null +++ b/cunit/cuReByteStorage.cpp @@ -0,0 +1,78 @@ +/* + * rplbytestorage_test.cpp + * + * License: Public Domain + * You can use and modify this file without any restriction. + * Do what you want. + * No warranties and disclaimer of any damages. + * You also can use this license: http://www.wtfpl.net + * The latest sources: https://github.com/republib + */ +/** @file + * @brief Unit test of the byte and C string storage. + */ + +#include "base/rebase.hpp" + +class TestReByteStorage : public ReTest{ +public: + TestReByteStorage() : + ReTest("ReByteStorage") + { doIt(); } +private: + void testChars(){ + ReByteStorage store(100); + char* s1 = store.allocateChars(4); + memcpy((void*) s1, "123", 4); + const char* s2 = store.allocateChars("abc"); + const char* s3 = store.allocateChars("defghij", 3); + checkEqu(s1, "123"); + checkEqu(s2, "abc"); + checkEqu(s3, "def"); + const char* ptr = s1 + 4; + checkT(ptr == s2); + ptr += 4; + checkT(ptr == s3); + } + + void testBytes(){ + ReByteStorage store(100); + uint8_t* s1 = store.allocateBytes(4); + memcpy((void*) s1, "1234", 4); + uint8_t* s2 = store.allocateBytes((void*) "abcd", 4); + uint8_t* s3 = store.allocateBytes((void*) "efghij", 4); + uint8_t* s4 = store.allocateZeros(4); + + checkEqu("1234abcdefgh", (const char*) s1); + uint8_t* ptr = s1 + 4; + checkT(ptr == s2); + ptr += 4; + checkT(ptr == s3); + ptr += 4; + checkT(ptr == s4); + for (int ii = 0; ii < 4; ii++) + checkEqu(0, (int) s4[ii]); + } + void testBufferChange(){ + ReByteStorage store(10); + char buffer[2]; + buffer[1] = '\0'; + for (int ii = 0; ii < 10000; ii++){ + buffer[1] = 'A' + ii % 26; + store.allocateBytes(buffer, 1); + } + int a = 1; + } + +public: + virtual void run() { + testBufferChange(); + testChars(); + testBytes(); + } +}; +void testReByteStorage() { + TestReByteStorage test; +} + + diff --git a/cunit/cuReCharPtrMap.cpp b/cunit/cuReCharPtrMap.cpp new file mode 100644 index 0000000..2d5df72 --- /dev/null +++ b/cunit/cuReCharPtrMap.cpp @@ -0,0 +1,36 @@ +/* + * rplcharptrmap_test.cpp + * + * License: Public Domain + * You can use and modify this file without any restriction. + * Do what you want. + * No warranties and disclaimer of any damages. + * You also can use this license: http://www.wtfpl.net + * The latest sources: https://github.com/republib + */ + +#include "base/rebase.hpp" + +class TestReCharPtrMap : public ReTest{ +public: + TestReCharPtrMap() : + ReTest("ReCharPtrMap") + { + doIt(); + } +protected: + void testBasic(){ + ReCharPtrMap map; + map["x"] = "x1"; + checkT(map.contains("x")); + checkF(map.contains("y")); + checkEqu("x1", map["x"]); + } +public: + virtual void run(void) { + testBasic(); + } +}; +void testReCharPtrMap() { + TestReCharPtrMap test; +} diff --git a/cunit/cuReConfig.cpp b/cunit/cuReConfig.cpp index 535347d..01daeb5 100644 --- a/cunit/cuReConfig.cpp +++ b/cunit/cuReConfig.cpp @@ -17,6 +17,7 @@ class TestReConfig: public ReTest { public: TestReConfig() : ReTest("ReConfig") { + doIt(); } public: diff --git a/cunit/cuReContainer.cpp b/cunit/cuReContainer.cpp index e418b4e..ff368c6 100644 --- a/cunit/cuReContainer.cpp +++ b/cunit/cuReContainer.cpp @@ -1,6 +1,6 @@ /* * cuReContainer.cpp - * + * * License: Public Domain * You can use and modify this file without any restriction. * Do what you want. @@ -12,9 +12,9 @@ /** * @brief Unit test for ReContainer */ -class TestRplContainer : public ReTest { +class TestReContainer : public ReTest { public: - TestRplContainer() : ReTest("RplContainer") {} + TestReContainer() : ReTest("RplContainer") { doIt(); } public: void testBasic() { @@ -50,8 +50,8 @@ public: } }; -void testRplContainer() { - TestRplContainer test; +void testReContainer() { + TestReContainer test; } diff --git a/cunit/cuReEnigma.cpp b/cunit/cuReEnigma.cpp index 44912aa..bc07e17 100644 --- a/cunit/cuReEnigma.cpp +++ b/cunit/cuReEnigma.cpp @@ -1,6 +1,6 @@ /* * cuReEnigma.cpp - * + * * License: Public Domain * You can use and modify this file without any restriction. * Do what you want. @@ -9,12 +9,13 @@ * The latest sources: https://github.com/republib */ #include "base/rebase.hpp" +#include "math/remath.hpp" /** * @brief Unit test for ReEnigma. */ class TestReEnigma : public ReTest { public: - TestReEnigma() : ReTest("ReEnigma") {} + TestReEnigma() : ReTest("ReEnigma") { doIt(); } public: void testOneCharset(const char* value, const char* charSet, @@ -103,7 +104,7 @@ public: "850592651836811261879625929"); } - virtual void doIt() { + virtual void run() { testBytes(); testCharSet(); } @@ -111,5 +112,4 @@ public: void testReEnigma() { TestReEnigma test; - test.run(); } diff --git a/cunit/cuReException.cpp b/cunit/cuReException.cpp new file mode 100644 index 0000000..1230b73 --- /dev/null +++ b/cunit/cuReException.cpp @@ -0,0 +1,53 @@ +/* + * rplexception_test.cpp + * + * License: Public Domain + * You can use and modify this file without any restriction. + * Do what you want. + * No warranties and disclaimer of any damages. + * You also can use this license: http://www.wtfpl.net + * The latest sources: https://github.com/republib + */ +#include "base/rebase.hpp" + +/** @file + * @brief Unit test of the basic exceptions. + */ + +class TestReException : public ReTest{ +public: + TestReException() : ReTest("RplException") { doIt(); } + +public: + void testBasic() { + try{ + throw ReException("simple"); + checkF(true); + } catch (ReException exc){ + checkEqu("simple", exc.getMessage().constData()); + } + try{ + throw ReException("String: %s and int %d", "Hi", -333); + checkF(true); + } catch (ReException exc){ + checkEqu("String: Hi and int -333", exc.getMessage().constData()); + } + try{ + throw ReException(LOG_INFO, 1234, &m_memoryLogger, + "String: %s and int %d", "Hi", -333); + checkF(true); + } catch (ReException exc){ + checkT(logContains("^ .*\\(1234\\): String: Hi and int -333")); + } + log("ok"); + } + virtual void run() { + testBasic(); + } +}; +void testReException() { + TestReException test; +} + + + diff --git a/cunit/cuReLexer.cpp b/cunit/cuReLexer.cpp new file mode 100644 index 0000000..3cdb2ed --- /dev/null +++ b/cunit/cuReLexer.cpp @@ -0,0 +1,282 @@ +/* + * rpllexer_test.cpp + * + * License: Public Domain + * You can use and modify this file without any restriction. + * Do what you want. + * No warranties and disclaimer of any damages. + * You also can use this license: http://www.wtfpl.net + * The latest sources: https://github.com/republib + */ + +/** @file + * @brief Unit test of the syntax symbol extractor. + */ + +#include "base/rebase.hpp" +#include "expr/reexpr.hpp" + +class TestRplLexer : public ReTest, public ReToken{ +public: + TestRplLexer() : + ReTest("ReLexer"), + ReToken(TOKEN_ID) + {} + +public: + void testRplToken(){ + // test constructor values: + checkEqu(TOKEN_ID, tokenType()); + checkEqu(0, m_value.m_id); + checkT(m_string.isEmpty()); + checkT(m_printableString.isEmpty()); + + m_value.m_id = 7422; + checkEqu(7422, ReToken::id()); + m_string = "Wow!"; + checkEqu("Wow!", ReToken::toString()); + m_printableString = "GooGoo"; + checkEqu("GooGoo", rawString()); + m_tokenType = TOKEN_NUMBER; + checkEqu(TOKEN_NUMBER, tokenType()); + + clear(); + checkEqu(TOKEN_UNDEF, tokenType()); + checkEqu(0, m_value.m_id); + checkT(m_string.isEmpty()); + checkT(m_printableString.isEmpty()); + + m_value.m_integer = 773322; + checkEqu(773322, asInteger()); + m_value.m_real = 0.25; + checkEqu(0.25, asReal()); + } + + ReToken* checkToken(ReToken* token, RplTokenType type, int id = 0, + const char* string = NULL){ + checkEqu(type, token->tokenType()); + if (id != 0) + checkEqu(id, token->id()); + if (string != NULL) + checkEqu(string, token->toString()); + return token; + } + enum { KEY_UNDEF, KEY_IF, KEY_THEN, KEY_ELSE, KEY_FI + }; +# define KEYWORDS "if then else fi" + enum { OP_UNDEF, OP_PLUS, OP_TIMES, OP_DIV, OP_GT, + OP_LT, OP_GE, OP_LE, OP_EQ, OP_ASSIGN, OP_PLUS_ASSIGN, OP_DIV_ASSIGN, + OP_TIMES_ASSIGN + }; +# define OPERATORS "+\n* /\n> < >= <= ==\n= += /= *=" + enum { COMMENT_UNDEF, COMMENT_1, COMMENT_MULTILINE, COMMENT_2 + }; +# define COMMENTS "/* */ // \n" + void testSpace(){ + ReSource source; + ReStringReader reader(source); +# define BLANKS1 "\t\t \n" +# define BLANKS2 " \n" + reader.addSource("
", BLANKS1 BLANKS2); + source.addReader(&reader); + ReLexer lex(&source, KEYWORDS, OPERATORS, "=", COMMENTS, + "A-Za-z_", + "A-Za-z0-9_", + ReLexer::NUMTYPE_DECIMAL, + ReLexer::SF_TICK, ReLexer::STORE_ALL); + checkToken(lex.nextToken(), TOKEN_SPACE, 0, BLANKS1); + checkToken(lex.nextToken(), TOKEN_SPACE, 0, BLANKS2); + } + void testNumeric(){ + ReSource source; + ReStringReader reader(source); + const char* blanks = "321 0x73 7.8e+5"; + reader.addSource("
", blanks); + source.addReader(&reader); + ReLexer lex(&source, KEYWORDS, OPERATORS, "=", COMMENTS, + "A-Za-z_", + "A-Za-z0-9_", + ReLexer::NUMTYPE_ALL, + ReLexer::SF_TICK, ReLexer::STORE_ALL); + ReToken* token = checkToken(lex.nextToken(), TOKEN_NUMBER); + checkEqu(321, token->asInteger()); + token = checkToken(lex.nextNonSpaceToken(), TOKEN_NUMBER); + checkEqu(0x73, token->asInteger()); + token = checkToken(lex.nextNonSpaceToken(), TOKEN_REAL); + checkEqu(7.8e+5, token->asReal()); + } + + void testOperators(){ + ReSource source; + ReStringReader reader(source); + const char* ops = "<< < <<< <= == = ( ) [ ]"; + reader.addSource("
", ops); + source.addReader(&reader); + enum { UNDEF, SHIFT, LT, SHIFT2, LE, EQ, ASSIGN, + LPARENT, RPARENT, LBRACKET, RBRACKET }; + ReLexer lex(&source, KEYWORDS, ops, "=", COMMENTS, + "A-Za-z_", + "A-Za-z0-9_", + ReLexer::NUMTYPE_ALL, + ReLexer::SF_TICK, ReLexer::STORE_ALL); + checkToken(lex.nextNonSpaceToken(), TOKEN_OPERATOR, SHIFT); + checkToken(lex.nextNonSpaceToken(), TOKEN_OPERATOR, LT); + checkToken(lex.nextNonSpaceToken(), TOKEN_OPERATOR, SHIFT2); + checkToken(lex.nextNonSpaceToken(), TOKEN_OPERATOR, LE); + checkToken(lex.nextNonSpaceToken(), TOKEN_OPERATOR, EQ); + checkToken(lex.nextNonSpaceToken(), TOKEN_OPERATOR, ASSIGN); + checkToken(lex.nextNonSpaceToken(), TOKEN_OPERATOR, LPARENT); + checkToken(lex.nextNonSpaceToken(), TOKEN_OPERATOR, RPARENT); + checkToken(lex.nextNonSpaceToken(), TOKEN_OPERATOR, LBRACKET); + checkToken(lex.nextNonSpaceToken(), TOKEN_OPERATOR, RBRACKET); + checkToken(lex.nextNonSpaceToken(), TOKEN_END_OF_SOURCE); + reader.addSource("", "(([["); + lex.startUnit(""); + checkToken(lex.nextNonSpaceToken(), TOKEN_OPERATOR, LPARENT); + checkToken(lex.nextNonSpaceToken(), TOKEN_OPERATOR, LPARENT); + checkToken(lex.nextNonSpaceToken(), TOKEN_OPERATOR, LBRACKET); + checkToken(lex.nextNonSpaceToken(), TOKEN_OPERATOR, LBRACKET); + checkToken(lex.nextNonSpaceToken(), TOKEN_END_OF_SOURCE); + } + + void testComments(){ + ReSource source; + ReStringReader reader(source); + + reader.addSource("
", "/**/9//\n8/***/7// wow\n/*\n*\n*\n**/"); + source.addReader(&reader); + + enum { COMMENT_UNDEF, COMMENT_MULTILINE, COMMENT_1 + }; + ReLexer lex(&source, KEYWORDS, OPERATORS, "=", COMMENTS, + "A-Za-z_", + "A-Za-z0-9_", + ReLexer::NUMTYPE_ALL, + ReLexer::SF_LIKE_C, ReLexer::STORE_ALL); + checkToken(lex.nextToken(), TOKEN_COMMENT_START, COMMENT_MULTILINE, + "/**/"); + checkToken(lex.nextToken(), TOKEN_NUMBER); + checkToken(lex.nextToken(), TOKEN_COMMENT_START, COMMENT_1, + "//\n"); + checkToken(lex.nextToken(), TOKEN_NUMBER); + checkToken(lex.nextToken(), TOKEN_COMMENT_START, COMMENT_MULTILINE, + "/***/"); + checkToken(lex.nextToken(), TOKEN_NUMBER); + checkToken(lex.nextToken(), TOKEN_COMMENT_START, COMMENT_1, + "// wow\n"); + checkToken(lex.nextToken(), TOKEN_COMMENT_START, COMMENT_MULTILINE, + "/*\n*\n*\n**/"); + } + void testStrings(){ + ReSource source; + ReStringReader reader(source); + + reader.addSource("
", "\"abc\\t\\r\\n\\a\\v\"'1\\x9Z\\x21A\\X9'"); + source.addReader(&reader); + + ReLexer lex(&source, KEYWORDS, OPERATORS, "=", COMMENTS, + "A-Za-z_", + "A-Za-z0-9_", + ReLexer::NUMTYPE_ALL, + ReLexer::SF_LIKE_C, ReLexer::STORE_ALL); + checkToken(lex.nextToken(), TOKEN_STRING, '"', "abc\t\r\n\a\v"); + checkToken(lex.nextToken(), TOKEN_STRING, '\'', "1\tZ!A\t"); + } + void testKeywords(){ + ReSource source; + ReStringReader reader(source); + + reader.addSource("
", "if\n\tthen else\nfi"); + source.addReader(&reader); + + ReLexer lex(&source, KEYWORDS, OPERATORS, "=", COMMENTS, + "A-Za-z_", + "A-Za-z0-9_", + ReLexer::NUMTYPE_ALL, + ReLexer::SF_LIKE_C, ReLexer::STORE_ALL); + checkToken(lex.nextToken(), TOKEN_KEYWORD, KEY_IF); + checkToken(lex.nextNonSpaceToken(), TOKEN_KEYWORD, KEY_THEN); + checkToken(lex.nextNonSpaceToken(), TOKEN_KEYWORD, KEY_ELSE); + checkToken(lex.nextNonSpaceToken(), TOKEN_KEYWORD, KEY_FI); + checkToken(lex.nextNonSpaceToken(), TOKEN_END_OF_SOURCE); + } + + void testIds(){ + ReSource source; + ReStringReader reader(source); + + reader.addSource("
", "i\n\tifs\n" + "_ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"); + source.addReader(&reader); + + ReLexer lex(&source, KEYWORDS, OPERATORS, "=", COMMENTS, + "A-Za-z_", + "A-Za-z0-9_", + ReLexer::NUMTYPE_ALL, + ReLexer::SF_LIKE_C, ReLexer::STORE_ALL); + checkToken(lex.nextToken(), TOKEN_ID, 0, "i"); + checkToken(lex.nextNonSpaceToken(), TOKEN_ID, 0, + "ifs"); + checkToken(lex.nextNonSpaceToken(), TOKEN_ID, 0, + "_ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"); + } + + void testBasic(){ + ReSource source; + ReStringReader reader(source); + source.addReader(&reader); + reader.addSource("
", "if i>1 then i=1+2*_x9 fi"); + ReLexer lex(&source, KEYWORDS, OPERATORS, "=", COMMENTS, + "A-Za-z_", + "A-Za-z0-9_", + ReLexer::NUMTYPE_ALL, + ReLexer::SF_LIKE_C, ReLexer::STORE_ALL); + ReToken* token; + checkToken(lex.nextToken(), TOKEN_KEYWORD, KEY_IF); + checkToken(lex.nextToken(), TOKEN_SPACE, 0); + checkToken(lex.nextToken(), TOKEN_ID, 0, "i"); + checkToken(lex.nextToken(), TOKEN_OPERATOR, OP_GT); + token = checkToken(lex.nextToken(), TOKEN_NUMBER); + checkEqu(1, token->asInteger()); + checkToken(lex.nextToken(), TOKEN_SPACE, 0); + checkToken(lex.nextToken(), TOKEN_KEYWORD, KEY_THEN); + checkToken(lex.nextToken(), TOKEN_SPACE, 0); + + } + void testPrio(){ + ReSource source; + ReStringReader reader(source); + source.addReader(&reader); + reader.addSource("x", ""); + enum { O_UNDEF, O_ASSIGN, O_PLUS, O_MINUS, O_TIMES, O_DIV + }; + ReLexer lex(&source, KEYWORDS, + "=\n+ -\n* /", "=", + COMMENTS, + "A-Za-z_", + "A-Za-z0-9_", + ReLexer::NUMTYPE_ALL, + ReLexer::SF_LIKE_C, ReLexer::STORE_ALL); + checkT(lex.prioOfOp(O_ASSIGN) < lex.prioOfOp(O_PLUS)); + checkEqu(lex.prioOfOp(O_PLUS), lex.prioOfOp(O_MINUS)); + checkT(lex.prioOfOp(O_MINUS) < lex.prioOfOp(O_TIMES)); + checkEqu(lex.prioOfOp(O_TIMES), lex.prioOfOp(O_DIV)); + } + + virtual void run(void) { + testPrio(); + testBasic(); + testIds(); + testKeywords(); + testComments(); + testStrings(); + testOperators(); + testNumeric(); + testSpace(); + testRplToken(); + } +}; +void testReLexer() { + TestRplLexer test; + test.run(); +} diff --git a/cunit/cuReMFParser.cpp b/cunit/cuReMFParser.cpp new file mode 100644 index 0000000..04df740 --- /dev/null +++ b/cunit/cuReMFParser.cpp @@ -0,0 +1,228 @@ +/* + * rplmfparser_test.cpp + * + * License: Public Domain + * You can use and modify this file without any restriction. + * Do what you want. + * No warranties and disclaimer of any damages. + * You also can use this license: http://www.wtfpl.net + * The latest sources: https://github.com/republib + */ +/** @file + * @brief Unit test of the parser for the language "MF". + */ + +#include "base/rebase.hpp" +#include "expr/reexpr.hpp" + +class TestReMFParser : public ReTest{ +private: + ReSource m_source; + ReASTree m_tree; + ReStringReader m_reader; + ReFileReader m_fileReader; + QByteArray m_currentSource; +public: + TestReMFParser() : + ReTest("ReMFParser"), + m_source(), + m_tree(), + m_reader(m_source), + m_fileReader(m_source) + { + m_source.addReader(&m_reader); + doIt(); + } +protected: + void setSource(const char* content){ + ReASItem::reset(); + m_currentSource = content; + m_tree.clear(); + m_source.clear(); + m_reader.clear(); + m_reader.addSource("", content); + m_source.addReader(&m_reader); + m_source.addSourceUnit(m_reader.currentSourceUnit()); + } + void setFileSource(const char* filename){ + ReASItem::reset(); + m_currentSource = ReStringUtil::read(filename); + m_tree.clear(); + m_source.clear(); + m_fileReader.clear(); + m_fileReader.addSource(filename); + m_source.addReader(&m_fileReader); + m_source.addSourceUnit(m_fileReader.currentSourceUnit()); + } + +private: + void checkAST(const char* fileExpected, int lineNo){ + QByteArray fnExpected = "test"; + fnExpected += QDir::separator().toLatin1(); + fnExpected += "mfparser"; + fnExpected += (char) QDir::separator().toLatin1(); + fnExpected += fileExpected; + QByteArray fnCurrent = getTempFile(fileExpected, "rplmfparser"); + m_tree.dump(fnCurrent, ReASTree::DMP_NO_GLOBALS, m_currentSource); + assertEqualFiles(fnExpected.constData(), fnCurrent.constData(), + __FILE__, lineNo); + } + +public: + void fileClassTest(){ + setFileSource("test/rplmfparser/string1.mf"); + ReMFParser parser(m_source, m_tree); + parser.parse(); + checkAST("string1.txt", __LINE__); + } + + void baseTest(){ + setSource("2+3*4"); + ReMFParser parser(m_source, m_tree); + parser.parse(); + checkAST("baseTest.txt", __LINE__); + } + + void varDefTest(){ + setSource("const lazy Str s = 'Hi';\nconst List l;\nInt i = 3;"); + ReMFParser parser(m_source, m_tree); + parser.parse(); + checkAST("varDefTest.txt", __LINE__); + } + + void ifTest(){ + setSource("Int a;\nInt b;\na = b = 2;\nif 11 < 12\nthen a = 13 * 14\nelse a = 15 / 16\nfi"); + // setSource("Int a; if 11 < 12 then a = 13 * 14 else a = 15 / 16 fi"); + ReMFParser parser(m_source, m_tree); + parser.parse(); + checkAST("ifTest1.txt", __LINE__); + setSource("Str x;\nif 7 < 6\nthen x = '123';\nfi"); + parser.parse(); + checkAST("ifTest2.txt", __LINE__); + } + void whileTest(){ + setSource("Int a = 20;\nwhile 3 < 5 do\n a = 7\nod"); + ReMFParser parser(m_source, m_tree); + parser.parse(); + checkAST("whileTest.txt", __LINE__); + } + + void repeatTest(){ + setSource("Int a;\nrepeat\na++;\nuntil a != 2 * 3;"); + ReMFParser parser(m_source, m_tree); + parser.parse(); + checkAST("repeatTest.txt", __LINE__); + } + void forCTest(){ + setSource("Int a;\nfor b from 10 to 1 step -2 do\na += 1;\nod"); + ReMFParser parser(m_source, m_tree); + parser.parse(); + checkAST("forC1.txt", __LINE__); + setSource("Int a; for to 10 do a += 1 od"); + parser.parse(); + checkAST("forC2.txt", __LINE__); + } + void opTest(){ + checkEqu(25, ReMFParser::O_QUESTION); + checkEqu(37, ReMFParser::O_RSHIFT2); + checkEqu(41, ReMFParser::O_DEC); + checkEqu(48, ReMFParser::O_RBRACE); + setSource("Int a = 1;\nInt b = 100;\n--a;\nb++;\na--*++b**(8-3);\na=b=(a+(b-2)*3)"); + ReMFParser parser(m_source, m_tree); + parser.parse(); + checkAST("opTest1.txt", __LINE__); + } + void forItTest(){ + setSource("Map a;\nfor x in a do\na += 1;\nod"); + ReMFParser parser(m_source, m_tree); + parser.parse(); + checkAST("forIt1.txt", __LINE__); + } + void listTest(){ + ReMFParser parser(m_source, m_tree); + setSource("List b = [];"); + parser.parse(); + checkAST("list1.txt", __LINE__); + setSource("List a = [2+3, 3.14, 7, 'hi', a]; List b = [];"); + parser.parse(); + checkAST("list2.txt", __LINE__); + } + void mapTest(){ + setSource("Map a = {};"); + ReMFParser parser(m_source, m_tree); + parser.parse(); + checkAST("map1.txt", __LINE__); + setSource("Map a = {'a': 2+3,'bcd':3.14,'ccc':7, 'hi':'world'};\nMap b = {};"); + parser.parse(); + checkAST("map2.txt", __LINE__); + } + void methodCallTest(){ + //setSource("max(4,3.14);"); + setSource("rand();\nsin(a);\nmax(1+2*3,4**(5-4));"); + ReMFParser parser(m_source, m_tree); + parser.parse(); + checkAST("methc1.txt", __LINE__); + } + void fieldTest(){ + setSource("file.find('*.c')[0].name;\n[1,2,3].join(' ');\n3.14.trunc;"); + ReMFParser parser(m_source, m_tree); + parser.parse(); + checkAST("field1.txt", __LINE__); + } + + void methodTest(){ + setSource("func Float pi: 3.1415; endf func Str delim(): '/' endf;"); + ReMFParser parser(m_source, m_tree); + parser.parse(); + checkAST("meth1.txt", __LINE__); + setSource("func Int fac(const Int n):\n" + "Int rc; if rc <= 1 then rc = 1 else rc = n*fac(n-1) fi\n" + "rc endf"); + parser.parse(); + checkAST("meth2.txt", __LINE__); + setSource("func Int max(Int a, Int b):\n Int rc = a;\n" + "if a < b then rc = b; fi\nrc\n" + "endf\n" + "func Int max(const Int a, Int b, Int c):\n" + "max(a, max(b, c))\n" + "endf"); + parser.parse(); + checkAST("meth3.txt", __LINE__); + setSource("func Int max(const Int a, Int b, Int c):\n" + "func Int max(Int a, Int b):\n Int rc = a;\n" + "if a < b then rc = b; fi\nrc\n" + "endf\n" + "max(a, max(b, c))\n" + "endf"); + parser.parse(); + checkAST("meth4.txt", __LINE__); + } + void mainTest(){ + setSource("Int a=2+3*4;\nfunc Void main():\na;\nendf"); + ReMFParser parser(m_source, m_tree); + parser.parse(); + checkAST("main1.txt", __LINE__); + } + + virtual void run(void) { + mainTest(); + varDefTest(); + repeatTest(); + baseTest(); + whileTest(); + methodTest(); + fieldTest(); + methodCallTest(); + mapTest(); + forItTest(); + forCTest(); + listTest(); + opTest(); + fileClassTest(); + } +}; +void testReMFParser() { + TestReMFParser test; +} + + diff --git a/cunit/cuReMatrix.cpp b/cunit/cuReMatrix.cpp new file mode 100644 index 0000000..55b568e --- /dev/null +++ b/cunit/cuReMatrix.cpp @@ -0,0 +1,374 @@ +/* + * rplmatrix_test.cpp + * + * License: Public Domain + * You can use and modify this file without any restriction. + * Do what you want. + * No warranties and disclaimer of any damages. + * You also can use this license: http://www.wtfpl.net + * The latest sources: https://github.com/republib + */ + +/** @file + * @brief Unit test of the matrices. + */ + +#include "base/rebase.hpp" +#include "math/remath.hpp" + +class TestRplMatrix : public ReTest{ +public: + TestRplMatrix() : ReTest("RplMatrix") { doIt(); } + +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++){ + checkEqu(100.0*row + col + offset, mx.get(row, col)); + count++; + } + } + checkEqu(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++){ + checkEqu(value, mx.get(row, col)); + count++; + } + } + checkEqu(mx.getCols()*mx.getRows(), count); + } + + void testBasic() { + Tuple2 tuple(-2.0, 0.5); + checkEqu(-2.0, tuple.m_value1); + checkEqu(0.5, tuple.m_value2); + RplMatrix mat("mx"); + try{ + throw RplMatrixException(mat, "String: %s and int %d", "Hi", -333); + checkF(true); + } catch (RplMatrixException exc){ + checkEqu("mx: String: Hi and int -333", exc.getMessage()); + } + RplMatrix mat2; + try{ + throw RplMatrixException(mat2, "String: %s and int %d", "Hi", -333); + checkF(true); + } catch (RplMatrixException exc){ + checkEqu("String: Hi and int -333", exc.getMessage()); + } + checkEqu("mx", mat.getName()); + checkEqu("", mat2.getName()); + + RplMatrix m2x3(2, 3, "m2x3"); + checkEqu("m2x3", m2x3.getName()); + checkEqu(2, m2x3.getRows()); + checkEqu(3, m2x3.getCols()); + fillMatrix(m2x3); + checkMatrix(m2x3); + + RplMatrix mxCopy(m2x3); + checkEqu("m2x3-copy", mxCopy.getName()); + checkEqu(2, mxCopy.getRows()); + checkEqu(3, mxCopy.getCols()); + checkMatrix(mxCopy); + + RplMatrix mxCopy2("mxCopy2"); + mxCopy2 = m2x3; + checkEqu("mxCopy2", mxCopy2.getName()); + checkEqu(2, mxCopy2.getRows()); + checkEqu(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){ + checkEqu("m1: row number negative: -1", exc.getMessage()); + } + try { + m1.checkDefinition(1, -1); + checkT(false); + } catch(RplMatrixException exc){ + checkEqu("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){ + checkEqu("m1: invalid row: -1 not in [0,3[", exc.getMessage()); + } + try { + m1.check(3, 1); + checkT(false); + } catch(RplMatrixException exc){ + checkEqu("m1: invalid row: 3 not in [0,3[", exc.getMessage()); + } + try { + m1.check(1, -1); + checkT(false); + } catch(RplMatrixException exc){ + checkEqu("m1: invalid column: -1 not in [0,2[", exc.getMessage()); + } + try { + m1.check(1, 2); + checkT(false); + } catch(RplMatrixException exc){ + checkEqu("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){ + checkEqu("m1: m2 has a different row count: 3 / 2", exc.getMessage()); + } + m2.resize(3, 3); + try { + m1.checkSameDimension(m2); + checkT(false); + } catch(RplMatrixException exc){ + checkEqu("m1: m2 has a different column count: 2 / 3", exc.getMessage()); + } + } + void testResize(){ + RplMatrix m1(3, 2, "m1"); + fillMatrix(m1); + checkMatrix(m1); + RplMatrix m2(2, 4, "m2"); + fillConst(m2, 0); + checkConst(m2, 0); + + m1.resize(2, 4); + checkEqu(2, m1.getRows()); + checkEqu(4, m1.getCols()); + checkT(m1 == m2); + } + + void testMinMax(){ + RplMatrix m1(4, 5, "m1"); + fillMatrix(m1); + checkMatrix(m1); + m1.set(0, 0, -98); + m1.set(3, 4, 9999); + Tuple2 miniMax = m1.minMax(); + checkEqu(-98.0, miniMax.m_value1); + checkEqu(9999.0, miniMax.m_value2); + + fillMatrix(m1); + checkMatrix(m1); + m1.set(1, 1, 7777); + m1.set(3, 4, -987); + miniMax = m1.minMax(); + checkEqu(-987.0, miniMax.m_value1); + checkEqu(7777.0, miniMax.m_value2); + } + + void testTranspose() + { + RplMatrix m1(1, 5, "m1"); + fillMatrix(m1); + RplMatrix m2(m1.transpose()); + + checkEqu(5, m2.getRows()); + checkEqu(1, m2.getCols()); + + int row, col; + col = 0; + for (row = 0; row < 5; row++){ + checkEqu(qreal(col*100+row), m2.get(row, 0)); + } + + m1.resize(35, 73); + fillMatrix(m1); + m2 = m1.transpose(); + + checkEqu(73, m2.getRows()); + checkEqu(35, m2.getCols()); + + int count = 0; + for (row = 0; row < m2.getRows(); row++){ + for (col = 0; col < m2.getCols(); col++){ + checkEqu(qreal(col*100+row), m2.get(row, col)); + count++; + } + } + checkEqu(73*35, count); + } + void testToString(){ + RplMatrix m1(1, 1, "m1"); + m1.set(0, 0, 2.34); + checkEqu("[2.340000,\n]", m1.toString().constData()); + checkEqu("jonny[2.34000 |]", m1.toString("jonny", "%.5f", "|", " ").constData()); + + m1.resize(2, 1); + m1.set(0, 0, 2.34); + m1.set(1, 0, 55.5); + + checkEqu("[2.340000,\n55.500000,\n]", m1.toString().constData()); + checkEqu("jonny[2.34000 |55.50000 |]", m1.toString("jonny", "%.5f", "|", " ").constData()); + log(""); + } + void testReadCsv(){ + QByteArray fn = getTempFile("rplmatrixtest.csv"); + const char* content; + RplMatrix m1(1,1,"m1"); + + fillMatrix(m1); + content = ",Port0,Port1,Port2\n" + "element1,5, -3E-99 , 0.5\n" + "element2,7,-22.3,44\n" + "\n" + "2 Elements, 3, Ports"; + ReStringUtil::write(fn, content); + m1.readFromCvs(fn, 256); + checkEqu(2, m1.getRows()); + checkEqu(3, m1.getCols()); + + checkEqu(5.0, m1.get(0, 0)); + checkEqu(-3.0E-99, m1.get(0, 1)); + checkEqu(0.5, m1.get(0, 2)); + + checkEqu(7.0, m1.get(1, 0)); + checkEqu(-22.3, m1.get(1, 1)); + checkEqu(44.0, m1.get(1, 2)); + + fillMatrix(m1); + content = "Port0,Port1,Port2\n" + "5, -3E-99 , 0.5\n"; + ReStringUtil::write(fn, content); + m1.readFromCvs(fn, 256); + checkEqu(1, m1.getRows()); + checkEqu(3, m1.getCols()); + checkEqu(5.0, m1.get(0, 0)); + checkEqu(-3.0E-99, m1.get(0, 1)); + checkEqu(0.5, m1.get(0, 2)); + + +/* + void readFromCvs(const char* filename, int maxLineLength = 1024*1024); + void readFromXml(const char* filename, const char* tagCol, + const char* tagRow, const char* tagTable, + int maxLineLength = 1024*1024); +*/ + } + virtual void run(void) { + testBasic(); + testAddOperators(); + testCompareOperators(); + testCheckDefinition(); + testCheck(); + testCheckSameDimension(); + testResize(); + testMinMax(); + testTranspose(); + testToString(); + testReadCsv(); + } +}; +void testRplMatrix() { + TestRplMatrix test; +} diff --git a/cunit/cuReQStringUtil.cpp b/cunit/cuReQStringUtil.cpp new file mode 100644 index 0000000..c04145d --- /dev/null +++ b/cunit/cuReQStringUtil.cpp @@ -0,0 +1,151 @@ +/* + * rplqstring_test.cpp + * + * License: Public Domain + * You can use and modify this file without any restriction. + * Do what you want. + * No warranties and disclaimer of any damages. + * You also can use this license: http://www.wtfpl.net + * The latest sources: https://github.com/republib + */ +/** @file + * @brief Unit test of the ReString tools. + */ + +#include "base/rebase.hpp" + +class TestReQStringUtil : public ReTest { +public: + TestReQStringUtil() : + ReTest("ReQStringUtil") + { doIt(); } + +public: + void testLengthOfUInt64(){ + quint64 value = -3; + checkEqu(1, ReQStringUtil::lengthOfUInt64(ReString("0"), 0, 10, &value)); + checkEqu(int64_t(0), value); + checkEqu(3, ReQStringUtil::lengthOfUInt64("x432", 1, 10, &value)); + checkEqu(int64_t(432LL), value); + checkEqu(3, ReQStringUtil::lengthOfUInt64("x432 x", 1, 10, &value)); + checkEqu(int64_t(432LL), value); + checkEqu(3, ReQStringUtil::lengthOfUInt64("x432fabc x", 1, 10, &value)); + checkEqu(int64_t(432LL), value); + checkEqu(16, ReQStringUtil::lengthOfUInt64("a1234567890123567", 1, 10, &value)); + checkEqu(int64_t(1234567890123567LL), value); + checkEqu(10, ReQStringUtil::lengthOfUInt64("x1234abcdef", 1, 16, &value)); + checkEqu(int64_t(0x1234abcdefLL), value); + checkEqu(3, ReQStringUtil::lengthOfUInt64("432", 0, 8, &value)); + checkEqu(int64_t(0432LL), value); + checkEqu(6, ReQStringUtil::lengthOfUInt64(" 765432 ", 1, 8, &value)); + checkEqu(int64_t(0765432LL), value); + + checkEqu(0, ReQStringUtil::lengthOfUInt64("1 ", 1, 8, &value)); + checkEqu(0, ReQStringUtil::lengthOfUInt64("", 1, 8, &value)); + } + void testLengthOfUInt(){ + uint value = 3; + checkEqu(1, ReQStringUtil::lengthOfUInt(ReString("0"), 0, 10, &value)); + checkEqu(0, value); + checkEqu(3, ReQStringUtil::lengthOfUInt("x432", 1, 10, &value)); + checkEqu(432, value); + checkEqu(3, ReQStringUtil::lengthOfUInt("x432 x", 1, 10, &value)); + checkEqu(432, value); + checkEqu(3, ReQStringUtil::lengthOfUInt("x432fabc x", 1, 10, &value)); + checkEqu(432, value); + checkEqu(3, ReQStringUtil::lengthOfUInt("432", 0, 8, &value)); + checkEqu(0432, value); + checkEqu(6, ReQStringUtil::lengthOfUInt(" 765432 ", 1, 8, &value)); + checkEqu(0765432, value); + + checkEqu(0, ReQStringUtil::lengthOfUInt("1 ", 1, 8, &value)); + checkEqu(0, ReQStringUtil::lengthOfUInt("", 1, 8, &value)); + } + void testLengthOfReal(){ + qreal value; + checkEqu(4, ReQStringUtil::lengthOfReal(ReString("0.25"), 0, &value)); + checkEqu(0.25, value); + checkEqu(3, ReQStringUtil::lengthOfReal(ReString("X.25"), 1, &value)); + checkEqu(0.25, value); + checkEqu(1, ReQStringUtil::lengthOfReal(ReString(" 0"), 1, &value)); + checkEqu(0.0, value); + checkEqu(17, ReQStringUtil::lengthOfReal(ReString("X12345678901234567"), 1, &value)); + checkEqu(12345678901234567.0, value); + checkEqu(2, ReQStringUtil::lengthOfReal(ReString(".5"), 0, &value)); + checkEqu(0.5, value); + checkEqu(5, ReQStringUtil::lengthOfReal(ReString("2.5e2x"), 0, &value)); + checkEqu(250.0, value); + checkEqu(6, ReQStringUtil::lengthOfReal(ReString("2.5e+2"), 0, &value)); + checkEqu(250.0, value); + checkEqu(7, ReQStringUtil::lengthOfReal(ReString("2.5E-33"), 0, &value)); + checkEqu(2.5e-33, value); + + checkEqu(3, ReQStringUtil::lengthOfReal(ReString("2.5E"), 0, &value)); + checkEqu(2.5, value); + checkEqu(3, ReQStringUtil::lengthOfReal(ReString("2.5E+"), 0, &value)); + checkEqu(2.5, value); + checkEqu(3, ReQStringUtil::lengthOfReal(ReString("2.5E-a"), 0, &value)); + checkEqu(2.5, value); + } + + void testValueOfHexDigit(){ + checkEqu(0, ReQStringUtil::valueOfHexDigit('0')); + checkEqu(9, ReQStringUtil::valueOfHexDigit('9')); + checkEqu(10, ReQStringUtil::valueOfHexDigit('a')); + checkEqu(15, ReQStringUtil::valueOfHexDigit('f')); + checkEqu(10, ReQStringUtil::valueOfHexDigit('A')); + checkEqu(15, ReQStringUtil::valueOfHexDigit('F')); + + checkEqu(-1, ReQStringUtil::valueOfHexDigit('0' - 1)); + checkEqu(-1, ReQStringUtil::valueOfHexDigit('9' + 1)); + checkEqu(-1, ReQStringUtil::valueOfHexDigit('A' - 1)); + checkEqu(-1, ReQStringUtil::valueOfHexDigit('F' + 1)); + checkEqu(-1, ReQStringUtil::valueOfHexDigit('a' - 1)); + checkEqu(-1, ReQStringUtil::valueOfHexDigit('f' + 1)); + } + void testUtf8(){ + ReString name = "Heinz Müller"; + char buffer[32]; + checkEqu("Heinz Müller", ReQStringUtil::utf8(name, buffer, sizeof buffer)); + memset(buffer, 'x', sizeof buffer); + checkEqu("Heinz", ReQStringUtil::utf8(name, buffer, (size_t) (5+1))); + checkEqu(buffer[6], 'x'); + } + + void testUnitParser(){ + ReUnitParser parser("-1-2*3*4+2^3*4", NULL); + checkT(parser.isValid()); + checkEqu(7, parser.asInt()); + checkEqu(7LL, parser.asInt64()); + checkEqu(7.0, parser.asReal()); + } + void testSizeParser(){ + ReSizeParser parser("2^3byte+2*1k+1m+1g+1t"); + checkT(parser.isValid()); + checkEqu(1001001002008LL, parser.asInt64()); + + ReSizeParser parser2("1ki+1mi+1gi+1ti"); + checkT(parser2.isValid()); + checkEqu(1100586419200ll, parser2.asInt64()); + } + void testDateTimeParser(){ + ReDateTimeParser parser("1+1min+1h+1day+1week"); + checkT(parser.isValid()); + checkEqu(694861, parser.asInt()); + } + + virtual void run(void) { + testUnitParser(); + testSizeParser(); + testDateTimeParser(); + testUtf8(); + testLengthOfUInt64(); + testLengthOfUInt(); + testLengthOfReal(); + testValueOfHexDigit(); + } +}; +void testReQStringUtil() { + TestReQStringUtil test; +} + diff --git a/cunit/cuReSource.cpp b/cunit/cuReSource.cpp new file mode 100644 index 0000000..05b1b32 --- /dev/null +++ b/cunit/cuReSource.cpp @@ -0,0 +1,110 @@ +/* + * rplsource_test.cpp + * + * License: Public Domain + * You can use and modify this file without any restriction. + * Do what you want. + * No warranties and disclaimer of any damages. + * You also can use this license: http://www.wtfpl.net + * The latest sources: https://github.com/republib + */ + +/** @file + * @brief Unit test of the input media reader. + */ + +#include "base/rebase.hpp" +#include "expr/reexpr.hpp" + +class TestReSource : public ReTest{ +public: + TestReSource() : ReTest("TestReSource") { doIt(); } + +private: + QByteArray m_content1_1; + QByteArray m_content1_2; + QByteArray m_content2; + ReSource m_source; + +protected: + void init(){ + m_content1_1 = "# test\nimport source2\n"; + m_content1_2 = "a=1;\nveeeeeeeeery looooooooooooooong\n"; + m_content2 = "x=2"; + } + + void testReStringSourceUnit(){ + ReStringReader reader(m_source); + QByteArray content("a=1;\nveeeeeeeeery looooooooooooooong\n"); + ReStringSourceUnit unit("test", content, &reader); + unit.setLineNo(144); + checkEqu(144, unit.lineNo()); + checkEqu("test", unit.name()); + } + void checkOne(int maxSize, ReReader& reader){ + QByteArray total; + QByteArray buffer; + int lineNo = 0; + bool hasMore; + checkF(reader.openSourceUnit("unknownSource")); + checkT(reader.openSourceUnit("source1")); + while(reader.nextLine(maxSize, buffer, hasMore)){ + lineNo++; + total += buffer; + buffer.clear(); + while(hasMore && reader.fillBuffer(maxSize, buffer, hasMore)){ + total += buffer; + buffer.clear(); + } + bool isImport = total.endsWith("source2\n"); + if (isImport){ + reader.openSourceUnit("source2"); + checkEqu("source2", reader.currentSourceUnit()->name()); + while(reader.nextLine(maxSize, buffer, hasMore)){ + lineNo++; + while(hasMore && reader.fillBuffer(maxSize, buffer, hasMore)){ + total += buffer; + buffer.clear(); + } + } + checkEqu("source1", reader.currentSourceUnit()->name()); + } + } + checkEqu(5, lineNo); + checkEqu(m_content1_1 + m_content2 + m_content1_2, total); + + } + + void testReStringReader(){ + ReStringReader reader(m_source); + reader.addSource("source1", m_content1_1 + m_content1_2); + reader.addSource("source2", m_content2); + ReSourceUnit* unit = reader.openSourceUnit("source1"); + checkNN(unit); + checkEqu("source1", unit->name()); + checkEqu(0, unit->lineNo()); + checkOne(6, reader); + checkOne(100, reader); + reader.replaceSource("source2", "content2"); + + unit = reader.openSourceUnit("source2"); + QByteArray buffer; + bool hasMore; + checkT(reader.nextLine(50, buffer, hasMore)); + checkEqu("content2", buffer); + checkF(hasMore); + } + +public: + void run(void) { + init(); + testReStringSourceUnit(); + testReStringReader(); + } +}; +void testReSource() { + TestReSource test; +} + + + diff --git a/cunit/cuReStringUtil.cpp b/cunit/cuReStringUtil.cpp new file mode 100644 index 0000000..e107a24 --- /dev/null +++ b/cunit/cuReStringUtil.cpp @@ -0,0 +1,197 @@ +/* + * rplstring_test.cpp + * + * License: Public Domain + * You can use and modify this file without any restriction. + * Do what you want. + * No warranties and disclaimer of any damages. + * You also can use this license: http://www.wtfpl.net + * The latest sources: https://github.com/republib + */ + +/** @file + * @brief Unit test of the QByteArray tools. + */ +#include "base/rebase.hpp" +/** + * @brief Unit test for ReStringUtil. + */ +class TestReStringUtil : public ReTest { +public: + TestReStringUtil() : ReTest("ReStringUtil") { doIt(); } + +public: + void testCountChar(){ + checkEqu(1, ReStringUtil::countChar("x", 'x')); + checkEqu(0, ReStringUtil::countChar("X", 'x')); + checkEqu(2, ReStringUtil::countChar("xbxxbxx", 'b')); + } + + void testCount() { + checkEqu(0, ReStringUtil::count("abc", " ")); + checkEqu(1, ReStringUtil::count("abc", "b")); + checkEqu(2, ReStringUtil::count("axx", "x")); + + checkEqu(0, ReStringUtil::count("abbc", "bbb")); + checkEqu(1, ReStringUtil::count("\n\n", "\n\n")); + checkEqu(2, ReStringUtil::count(" a ", " ")); + } + + void testCutString() { + QByteArray source("123"); + QByteArray buffer; + checkEqu(QByteArray("123"), ReStringUtil::cutString(source, 4, buffer)); + checkEqu(QByteArray("123"), ReStringUtil::cutString(source, 3, buffer)); + checkEqu(QByteArray("12..."), ReStringUtil::cutString(source, 2, buffer)); + checkEqu(QByteArray("12"), ReStringUtil::cutString(source, 2, buffer, "")); + } + + void testHexDump() { + QByteArray data("abc123\nxyz"); + checkEqu(QByteArray("61 62 63 31 abc1\n" + "32 33 0a 78 23.x\n" + "79 7a yz\n"), + ReStringUtil::hexDump((uint8_t*) data.constData(), data.length(), 4)); + checkEqu(QByteArray("61 62 63 31 32 33 0a 78 79 7a abc123.xyz"), + ReStringUtil::hexDump((uint8_t*) data.constData(), data.length(), 10)); + checkEqu(QByteArray("61 62 63 31 32 33 0a 78 79 7a abc123.xyz"), + ReStringUtil::hexDump((uint8_t*) data.constData(), data.length(), 12)); + } + + void testReadWrite() { + QByteArray fn = getTempFile("test.dat"); + const char* content = "Hello world\nLine2\n"; + checkT(ReStringUtil::write(fn, content)); + checkEqu(content, ReStringUtil::read(fn, false)); + checkEqu(content, ReStringUtil::read(fn, true) + "\n"); + } + + void testToArray() { + QList array = ReStringUtil::toArray("1 abc 3", " "); + checkEqu(3, array.size()); + checkEqu("1", array.at(0)); + checkEqu("abc", array.at(1)); + checkEqu("3", array.at(2)); + } + + void testToNumber() { + checkEqu("3", ReStringUtil::toNumber(3)); + checkEqu("-33", ReStringUtil::toNumber(-33)); + checkEqu("003", ReStringUtil::toNumber(3, "%03d")); + } + + void testLengthOfNumber(){ + checkEqu(3, ReStringUtil::lengthOfNumber("0.3xxx")); + checkEqu(5, ReStringUtil::lengthOfNumber(" \t0.3xxx")); + checkEqu(3, ReStringUtil::lengthOfNumber("-.3xxx")); + checkEqu(2, ReStringUtil::lengthOfNumber(".3exxx")); + checkEqu(2, ReStringUtil::lengthOfNumber(".3e+xxx")); + checkEqu(16, ReStringUtil::lengthOfNumber("1234567.9012E+77")); + checkEqu(17, ReStringUtil::lengthOfNumber("-1234567.9012E+77 ")); + checkEqu(18, ReStringUtil::lengthOfNumber("-1234567.9012E+77 ", true)); + checkEqu(18, ReStringUtil::lengthOfNumber("-1234567.9012E+77 x", true)); + checkEqu(20, ReStringUtil::lengthOfNumber(" -1234567.9012E+77 x", true)); + } + + void checkCsv(const char* content, char expected){ + QByteArray fn = getTempFile("testrplstring.csv"); + ReStringUtil::write(fn, content); + FILE* fp = fopen(fn, "r"); + checkNN(fp); + char buffer[256]; + checkEqu(expected, ReStringUtil::findCsvSeparator(fp, buffer, sizeof buffer)); + fclose(fp); + } + + void testFindCsvSeparator(){ + const char* content = ",,,\t;;;||||"; + checkCsv(content, '\t'); + + content = "col1,col2\n1.5,3,5\n"; + checkCsv(content, ','); + + content = "col1;col2\n1,50;3.5\n" + "7;8\n10;12\n13;14"; + checkCsv(content, ';'); + + content = "0.3 7.8 8.9\n7.8 9.4 8.3"; + checkCsv(content, ' '); + + content = "0.3|7.8|8.9\n7.8| 9.4|8.3"; + checkCsv(content, '|'); + + content = "0,3;7.8;8.9"; + checkCsv(content, ';'); + } + void testLengthOfUInt64(){ + quint64 value = -3; + checkEqu(1, ReStringUtil::lengthOfUInt64("0", 10, &value)); + checkEqu((int64_t) 0LL, value); + checkEqu(3, ReStringUtil::lengthOfUInt64("432", 10, &value)); + checkEqu((int64_t) 432LL, value); + checkEqu(3, ReStringUtil::lengthOfUInt64("432 x", 10, &value)); + checkEqu((int64_t) 432LL, value); + checkEqu(3, ReStringUtil::lengthOfUInt64("432fabc x", 10, &value)); + checkEqu((int64_t) 432LL, value); + checkEqu(16, ReStringUtil::lengthOfUInt64("1234567890123567", 10, &value)); + checkEqu((int64_t) 1234567890123567LL, value); + checkEqu(10, ReStringUtil::lengthOfUInt64("1234abcdef", 16, &value)); + checkEqu((int64_t) 0x1234abcdefLL, value); + checkEqu(3, ReStringUtil::lengthOfUInt64("432", 8, &value)); + checkEqu((int64_t) 0432LL, value); + checkEqu(6, ReStringUtil::lengthOfUInt64("765432 ", 8, &value)); + checkEqu((int64_t) 0765432LL, value); + + checkEqu(0, ReStringUtil::lengthOfUInt64(" ", 8, &value)); + checkEqu(0, ReStringUtil::lengthOfUInt64("", 8, &value)); + } + void testLengthOfReal(){ + qreal value; + checkEqu(1, ReStringUtil::lengthOfReal("0", &value)); + checkEqu(0.0, value); + checkEqu(1, ReStringUtil::lengthOfReal("0%", &value)); + checkEqu(0.0, value); + checkEqu(4, ReStringUtil::lengthOfReal("0.25", &value)); + checkEqu(0.25, value); + checkEqu(3, ReStringUtil::lengthOfReal(".25", &value)); + checkEqu(0.25, value); + checkEqu(17, ReStringUtil::lengthOfReal("12345678901234567", &value)); + checkEqu(12345678901234567.0, value); + checkEqu(2, ReStringUtil::lengthOfReal(".5", &value)); + checkEqu(0.5, value); + checkEqu(5, ReStringUtil::lengthOfReal("2.5e2x", &value)); + checkEqu(250.0, value); + checkEqu(6, ReStringUtil::lengthOfReal("2.5e+2", &value)); + checkEqu(250.0, value); + checkEqu(7, ReStringUtil::lengthOfReal("2.5E-33", &value)); + checkEqu(2.5e-33, value); + + checkEqu(3, ReStringUtil::lengthOfReal("2.5E", &value)); + checkEqu(2.5, value); + checkEqu(3, ReStringUtil::lengthOfReal("2.5E+", &value)); + checkEqu(2.5, value); + checkEqu(3, ReStringUtil::lengthOfReal("2.5E-a", &value)); + checkEqu(2.5, value); + } + + virtual void run() { + testLengthOfReal(); + testLengthOfUInt64(); + testCountChar(); + testCount(); + testCutString(); + testToNumber(); + testToArray(); + testHexDump(); + testReadWrite(); + testLengthOfNumber(); + testFindCsvSeparator(); + } +}; + +void testReStringUtil() { + TestReStringUtil test; +} + + + diff --git a/cunit/cuReTraverser.cpp b/cunit/cuReTraverser.cpp new file mode 100644 index 0000000..90cc05c --- /dev/null +++ b/cunit/cuReTraverser.cpp @@ -0,0 +1,155 @@ +/* + * cuReTraverser.cpp + * + * License: Public Domain + * You can use and modify this file without any restriction. + * Do what you want. + * No warranties and disclaimer of any damages. + * You also can use this license: http://www.wtfpl.net + * The latest sources: https://github.com/republib + */ + +#include "base/rebase.hpp" +#include "os/reos.hpp" + +class TestReTraverser: public ReTestUnit { +public: + TestReTraverser() : + ReTestUnit("ReTraverser", __FILE__), + m_base(), + m_buffer(), + m_logger(ReLogger::globalLogger()) { + m_base = testDir(); + m_base.append("traverser"); + _mkdir(m_base.str(), ALLPERMS); + m_base.append(OS_SEPARATOR, -1); + run(); + ReDirectory::deleteTree(m_base.str(), true); + } +private: + ReByteBuffer m_base; + ReByteBuffer m_buffer; + ReLogger* m_logger; +private: + const char* makeDir(const char* relPath) { + m_buffer = m_base; + m_buffer.append(relPath); + m_buffer.replaceAll("/", 1, OS_SEPARATOR, -1); + _mkdir(m_buffer.str(), ALLPERMS); + struct stat info; + if (stat(m_buffer.str(), &info) != 0) { + logF(true, "cannot create dir %1$s", m_buffer.str()); + } + return m_buffer.str(); + } + void makeFile(const char* relPath) { + ReByteBuffer path(m_base); + path.append("/").append(relPath); + path.replaceAll("/", 1, OS_SEPARATOR, -1); + createFile(path.str(), relPath); + struct stat info; + if (stat(path.str(), &info) != 0) { + logF(true, "cannot create file %1$s", path.str()); + } + } + void initTree() { + makeFile("1.txt"); + makeDir("dir1"); + makeDir("dir2"); + makeDir("dir1/dir1_1"); + makeDir("dir1/dir1_2"); + makeDir("dir1/dir1_2/dir1_2_1"); + makeDir("dir1/cache"); + makeFile("dir1/dir1_2/dir1_2_1/x1.txt"); + makeFile("dir1/dir1_2/dir1_2_1/x2.txt"); + makeFile("dir2/2.x"); + makeFile("dir1/cache/cache.txt"); + } + void run() { + testFilter(); + initTree(); + + testBasic(); + testList(); + } + void testFilter() { + ReDirEntryFilter filter; + + } + void testList() { + const char* argv[] = { "list", m_base.str(), NULL }; + ReDirList(m_logger).run(2, argv); + } + void testCopyFile() { +#if defined __linux__ + ReByteBuffer src(m_base); + src.append("dir1/dir1_2/dir1_2_1/x1.txt"); + ReByteBuffer trg(testDir()); + trg.append("copy_x1.txt"); + ReByteBuffer buffer; + buffer.ensureSize(5); + ReDirSync::copyFile(src.str(), NULL, trg.str(), buffer, + ReLogger::globalLogger()); + checkFileEqu(src.str(), trg.str()); +#else + log(false, "testCopyFile not implemented"); +#endif + } + + void checkRelDate(time_t absTime, int relTime) { + int diff = int(time(NULL) - relTime - absTime); + if (diff < 0) + diff = -diff; + checkT(diff < 2); + } + + void checkOneFile(const char* node, const char* parent, + const ReHashList& hash) { + ReByteBuffer path, expected; + checkT(hash.get(ReByteBuffer(node), path)); + expected.set(parent, -1); + if (!expected.endsWith(OS_SEPARATOR)) + expected.append(OS_SEPARATOR); + if (!path.endsWith(expected.str(), -1)) + checkT(false); + } + void testBasic() { + ReTraverser traverser(m_base.str()); + RePatternList patterns; + // exclude */cache/* + ReByteBuffer buffer(";*;-cache"); + patterns.set(buffer.str()); + traverser.setDirPattern(&patterns); + int level = 0; + ReDirStatus_t* entry; + ReHashList hashPath; + ReSeqArray listChanged; + int state = 0; + while ((entry = traverser.rawNextFile(level)) != NULL) { + const char* node = entry->node(); + hashPath.put(ReByteBuffer(node, -1), entry->m_path); + if (traverser.hasChangedPath(state)) + listChanged.add(-1, node); + logF(false, "%d: %-12s %2d %s", level, node, int(entry->fileSize()), + entry->m_path.str()); + } + checkOneFile("x1.txt", "dir1_2_1", hashPath); + checkOneFile("x2.txt", "dir1_2_1", hashPath); + bool changed1 = listChanged.find("x1.txt") != (ReSeqArray::Index) -1; + bool changed2 = listChanged.find("x2.txt") != (ReSeqArray::Index) -1; + checkT(changed1 != changed2); + checkOneFile("dir1_2_1", "dir1_2", hashPath); + checkT(listChanged.find("dir1_2_1") >= 0); + checkOneFile("dir1_1", "dir1", hashPath); + checkOneFile("dir1_2", "dir1", hashPath); + changed1 = listChanged.find("dir1_1") != (ReSeqArray::Index) -1; + changed2 = listChanged.find("dir1_2") != (ReSeqArray::Index) -1; + checkT(changed1 != changed2); + checkF(hashPath.get("cache.txt", buffer)); + } +}; +extern void testReTraverser(void); + +void testReTraverser(void) { + TestReTraverser unit; +} diff --git a/cunit/cuReVM.cpp b/cunit/cuReVM.cpp new file mode 100644 index 0000000..9befa8c --- /dev/null +++ b/cunit/cuReVM.cpp @@ -0,0 +1,74 @@ +/* + * rplvm_test.cpp + * + * License: Public Domain + * You can use and modify this file without any restriction. + * Do what you want. + * No warranties and disclaimer of any damages. + * You also can use this license: http://www.wtfpl.net + * The latest sources: https://github.com/republib + */ + +#include "base/rebase.hpp" +#include "expr/reexpr.hpp" + +class TestReVM : public ReTest{ +private: + ReSource m_source; + ReASTree m_tree; + ReStringReader m_reader; + const char* m_currentSource; +public: + TestReVM() : + ReTest("ReVM"), + m_source(), + m_tree(), + m_reader(m_source) + { + m_source.addReader(&m_reader); + doIt(); + } +protected: + void setSource(const char* content){ + ReASItem::reset(); + m_currentSource = content; + m_tree.clear(); + m_source.clear(); + m_reader.clear(); + m_reader.addSource("", content); + m_source.addReader(&m_reader); + m_source.addSourceUnit(m_reader.currentSourceUnit()); + } + +private: + void checkAST(const char* fileExpected, int lineNo){ + QByteArray fnExpected = "test"; + fnExpected += QDir::separator().toLatin1(); + fnExpected += "ReVM"; + fnExpected += (char) QDir::separator().toLatin1(); + fnExpected += fileExpected; + QByteArray fnCurrent = getTempFile(fileExpected, "ReVM"); + ReMFParser parser(m_source, m_tree); + parser.parse(); + ReVirtualMachine vm(m_tree, m_source); + vm.setFlag(ReVirtualMachine::VF_TRACE_STATEMENTS); + ReFileWriter writer(fnCurrent); + vm.setTraceWriter(&writer); + writer.write(m_currentSource); + vm.executeModule(""); + assertEqualFiles(fnExpected.constData(), fnCurrent.constData(), + __FILE__, lineNo); + } +public: + void baseTest(){ + setSource("Int a=2+3*4;\nfunc Void main():\na;\nendf"); + checkAST("baseTest.txt", __LINE__); + } + virtual void run(void) { + baseTest(); + } +}; +void testReVM() { + TestReVM test; +} + diff --git a/cunit/cuReWriter.cpp b/cunit/cuReWriter.cpp new file mode 100644 index 0000000..67e2389 --- /dev/null +++ b/cunit/cuReWriter.cpp @@ -0,0 +1,50 @@ +/* + * rplwriter_test.cpp + * + * License: Public Domain + * You can use and modify this file without any restriction. + * Do what you want. + * No warranties and disclaimer of any damages. + * You also can use this license: http://www.wtfpl.net + * The latest sources: https://github.com/republib + */ + +/** @file + * @brief Unit test of the output media writers. + */ + +#include "base/rebase.hpp" +/** + * @brief Unit test for ReStringUtil. + */ +class TestReWriter : public ReTest { +public: + TestReWriter() : ReTest("ReWriter") { doIt(); } + +private: + void testFileWriter(){ + QByteArray fn = getTempFile("rplwriter.txt"); + ReFileWriter writer(fn); + writer.writeLine("abc"); + writer.formatLine("%04d", 42); + writer.writeIndented(3, "123"); + writer.indent(2); + writer.write("pi"); + writer.format("%3c%.2f", ':', 3.1415); + writer.writeLine(); + writer.close(); + QByteArray current = ReStringUtil::read(fn, false); + checkEqu("abc\n0042\n\t\t\t123\n\t\tpi :3.14\n", current); + } + +public: + virtual void run(void) { + testFileWriter(); + } +}; +void testReWriter() { + TestReWriter test; +} + + + diff --git a/cunit/main.cpp b/cunit/main.cpp deleted file mode 100644 index 0922b20..0000000 --- a/cunit/main.cpp +++ /dev/null @@ -1,85 +0,0 @@ -/* - * main.cpp - * - * License: Public Domain - * You can use and modify this file without any restriction. - * Do what you want. - * No warranties and disclaimer of any damages. - * You also can use this license: http://www.wtfpl.net - * The latest sources: https://github.com/republib - */ -#include "../rplcore/rplcore.hpp" -#include "../rplmath/rplmath.hpp" - -#include - -void testCore(){ - extern void testReString(); - testReString(); - - extern void testReCharPtrMap(); - testReCharPtrMap(); - - extern void testRplWriter(); - testRplWriter(); - - extern void testRplByteStorage(); - testRplByteStorage(); - - extern void testRplQString(); - testRplQString(); - - extern void testReString(); - testReString(); - - extern void testRplException(); - testRplException(); -} - -void testExpr(){ - extern void testRplMFParser(); - testRplMFParser(); - - extern void testRplBenchmark(); - //testRplBenchmark(); - - extern void testReVM(); - testReVM(); - - extern void testReSource(); - testReSource(); - - extern void testRplLexer(); - testRplLexer(); - - extern void testRplMFParser(); - testRplMFParser(); - - extern void testReASTree(); - testReASTree(); - - extern void testReVM(); - testReVM(); - -} - -void testStandard(){ - testExpr(); - testCore(); - extern void testRplMatrix(); - testRplMatrix(); - -} - -void labor(){ -} - -int main(int argc, char *argv[]) -{ - //labor(); - if (argc > 1) - printf("not used: %s\n", argv[1]); - - testStandard(); - -} diff --git a/cunit/rplastree_test.cpp b/cunit/rplastree_test.cpp deleted file mode 100644 index 0a98a23..0000000 --- a/cunit/rplastree_test.cpp +++ /dev/null @@ -1,106 +0,0 @@ -/* - * rplastree_test.cpp - * - * License: Public Domain - * You can use and modify this file without any restriction. - * Do what you want. - * No warranties and disclaimer of any damages. - * You also can use this license: http://www.wtfpl.net - * The latest sources: https://github.com/republib - */ - -/** @file - * @brief Unit test of the abstract syntax tree. - */ - - -#include "base/rebase.hpp" -#include "expr/reexpr.hpp" -#include "rplcore/rpltest.hpp" - -class TestReASTree : public ReTest{ -private: - ReSource m_source; - ReStringReader m_reader; - ReStringSourceUnit m_unit; - ReASTree m_tree; -public: - TestReASTree() : - ReTest("ReASTree"), - m_source(), - m_reader(m_source), - m_unit("
", "", &m_reader), - m_tree() - {} -public: - void testReASException() { - try{ - m_reader.addSource("
", "12"); - m_source.addReader(&m_reader); - m_source.addSourceUnit(m_reader.currentSourceUnit()); - const ReSourcePosition* pos = m_source.newPosition(2); - throw ReASException(pos, "simple string: %s", "Hi"); - checkF(true); - } catch (ReASException exc){ - checkEqu("
:0:2: simple string: Hi", exc.getMessage().constData()); - } - } - void testReASVariant(){ - ReASVariant val1; - val1.setFloat(2.5E-2); - checkEqu(2.5E-2, val1.asFloat()); - ReASVariant val2(val1); - checkEqu(2.5E-2, val2.asFloat()); - - val1.setInt(4321); - checkEqu(4321, val1.asInt()); - val2 = val1; - checkEqu(4321, val2.asInt()); - - val1.setBool(false); - checkF(val1.asBool()); - val2 = val1; - checkF(val2.asBool()); - - val1.setBool(true); - checkT(val1.asBool()); - val2 = val1; - checkT(val2.asBool()); - - val1.setString("High noon!"); - checkEqu("High noon!", *val1.asString()); - val2 = val1; - val1.setString("Bye"); - checkEqu("High noon!", *val2.asString()); - ReASVariant val3(val1); - checkEqu("Bye", *val3.asString()); - } - void testReASConstant(){ - ReASConstant constant; - //constant.value().setString("Jonny"); - ReASVariant value; - //constant.calc(value); - //checkEqu("Jonny", *value.asString()); - } - void testReASNamedValue(){ - ReASNamedValue value(NULL, m_tree.symbolSpaces()[0], "gugo", - ReASNamedValue::A_GLOBAL); - checkEqu("gugo", value.name()); - } - virtual void doIt() { - testReASNamedValue(); - testReASConstant(); - testReASException(); - testReASVariant(); - } -}; -void testReASTree() { - TestReASTree test; - test.run(); -} - - - - - - diff --git a/cunit/rplbench.cpp b/cunit/rplbench.cpp deleted file mode 100644 index 31f0e8a..0000000 --- a/cunit/rplbench.cpp +++ /dev/null @@ -1,64 +0,0 @@ -/* - * rplbench.cpp - * - * License: Public Domain - * You can use and modify this file without any restriction. - * Do what you want. - * No warranties and disclaimer of any damages. - * You also can use this license: http://www.wtfpl.net - * The latest sources: https://github.com/republib - */ - -/** @file - * @brief Unit test of the abstract syntax tree. - */ - - -#include "base/rebase.hpp" -#include "expr/reexpr.hpp" -#include "rplcore/rpltest.hpp" - -class TestRplBenchmark : public ReTest{ -private: - const char* m_filename; - ReSource m_source; - ReFileReader m_reader; - ReASTree m_tree; -public: - TestRplBenchmark() : - ReTest("RplBenchmark"), - m_filename("/home/ws/qt/rplqt/bench/mfbench.mf"), - m_source(), - m_reader(m_source), - m_tree() - { - m_source.addReader(&m_reader); - m_reader.addSource(m_filename); - } -public: - void benchmark() { - time_t start = time(NULL); - ReMFParser parser(m_source, m_tree); - parser.parse(); - time_t end = time(NULL); - printf("compilation: %d sec\n", int(end - start)); - } - virtual void doIt() { - try{ - ReFileSourceUnit* unit = dynamic_cast - (m_reader.currentSourceUnit()); - if (unit != NULL && ! unit->isOpen()) - throw ReException("file not found: %s", m_filename); - benchmark(); - } catch(ReException ex){ - printf("%s\n", ex.getMessage().constData()); - } - } -}; -void testRplBenchmark() { - TestRplBenchmark test; - test.run(); -} - - - diff --git a/cunit/rplbytestorage_test.cpp b/cunit/rplbytestorage_test.cpp deleted file mode 100644 index 0f40bc6..0000000 --- a/cunit/rplbytestorage_test.cpp +++ /dev/null @@ -1,80 +0,0 @@ -/* - * rplbytestorage_test.cpp - * - * License: Public Domain - * You can use and modify this file without any restriction. - * Do what you want. - * No warranties and disclaimer of any damages. - * You also can use this license: http://www.wtfpl.net - * The latest sources: https://github.com/republib - */ -/** @file - * @brief Unit test of the byte and C string storage. - */ - -#include "../base/rebase.hpp" -#include "../base/ReTest.hpp" - -class TestRplByteStorage : public ReTest{ -public: - TestRplByteStorage() : - ReTest("RplByteStorage") - {} -private: - void testChars(){ - ReByteStorage store(100); - char* s1 = store.allocateChars(4); - memcpy((void*) s1, "123", 4); - const char* s2 = store.allocateChars("abc"); - const char* s3 = store.allocateChars("defghij", 3); - checkEqu(s1, "123"); - checkEqu(s2, "abc"); - checkEqu(s3, "def"); - const char* ptr = s1 + 4; - checkT(ptr == s2); - ptr += 4; - checkT(ptr == s3); - } - - void testBytes(){ - ReByteStorage store(100); - uint8_t* s1 = store.allocateBytes(4); - memcpy((void*) s1, "1234", 4); - uint8_t* s2 = store.allocateBytes((void*) "abcd", 4); - uint8_t* s3 = store.allocateBytes((void*) "efghij", 4); - uint8_t* s4 = store.allocateZeros(4); - - checkEqu("1234abcdefgh", (const char*) s1); - uint8_t* ptr = s1 + 4; - checkT(ptr == s2); - ptr += 4; - checkT(ptr == s3); - ptr += 4; - checkT(ptr == s4); - for (int ii = 0; ii < 4; ii++) - checkEqu(0, (int) s4[ii]); - } - void testBufferChange(){ - ReByteStorage store(10); - char buffer[2]; - buffer[1] = '\0'; - for (int ii = 0; ii < 10000; ii++){ - buffer[1] = 'A' + ii % 26; - store.allocateBytes(buffer, 1); - } - int a = 1; - } - -public: - virtual void doIt() { - testBufferChange(); - testChars(); - testBytes(); - } -}; -void testRplByteStorage() { - TestRplByteStorage test; - test.run(); -} - - diff --git a/cunit/rplcharptrmap_test.cpp b/cunit/rplcharptrmap_test.cpp deleted file mode 100644 index 0643b9e..0000000 --- a/cunit/rplcharptrmap_test.cpp +++ /dev/null @@ -1,37 +0,0 @@ -/* - * rplcharptrmap_test.cpp - * - * License: Public Domain - * You can use and modify this file without any restriction. - * Do what you want. - * No warranties and disclaimer of any damages. - * You also can use this license: http://www.wtfpl.net - * The latest sources: https://github.com/republib - */ - -#include "base/rebase.hpp" -#include "rplcore/rpltest.hpp" - -class TestReCharPtrMap : public ReTest{ -public: - TestReCharPtrMap() : - ReTest("ReCharPtrMap") - { - } -protected: - void testBasic(){ - ReCharPtrMap map; - map["x"] = "x1"; - checkT(map.contains("x")); - checkF(map.contains("y")); - checkEqu("x1", map["x"]); - } - - virtual void doIt(void) { - testBasic(); - } -}; -void testReCharPtrMap() { - TestReCharPtrMap test; - test.run(); -} diff --git a/cunit/rplexception_test.cpp b/cunit/rplexception_test.cpp deleted file mode 100644 index f219850..0000000 --- a/cunit/rplexception_test.cpp +++ /dev/null @@ -1,54 +0,0 @@ -/* - * rplexception_test.cpp - * - * License: Public Domain - * You can use and modify this file without any restriction. - * Do what you want. - * No warranties and disclaimer of any damages. - * You also can use this license: http://www.wtfpl.net - * The latest sources: https://github.com/republib - */ -#include "base/rebase.hpp" -#include "rplcore/rpltest.hpp" -/** @file - * @brief Unit test of the basic exceptions. - */ - -class TestRplException : public ReTest{ -public: - TestRplException() : ReTest("RplException") {} - -public: - void testBasic() { - try{ - throw ReException("simple"); - checkF(true); - } catch (ReException exc){ - checkEqu("simple", exc.getMessage().constData()); - } - try{ - throw ReException("String: %s and int %d", "Hi", -333); - checkF(true); - } catch (ReException exc){ - checkEqu("String: Hi and int -333", exc.getMessage().constData()); - } - try{ - throw ReException(LOG_INFO, 1234, &m_memoryLogger, - "String: %s and int %d", "Hi", -333); - checkF(true); - } catch (ReException exc){ - checkT(logContains("^ .*\\(1234\\): String: Hi and int -333")); - } - log("ok"); - } - virtual void doIt() { - testBasic(); - } -}; -void testRplException() { - TestRplException test; - test.run(); -} - - - diff --git a/cunit/rpllexer_test.cpp b/cunit/rpllexer_test.cpp deleted file mode 100644 index 72f133e..0000000 --- a/cunit/rpllexer_test.cpp +++ /dev/null @@ -1,283 +0,0 @@ -/* - * rpllexer_test.cpp - * - * License: Public Domain - * You can use and modify this file without any restriction. - * Do what you want. - * No warranties and disclaimer of any damages. - * You also can use this license: http://www.wtfpl.net - * The latest sources: https://github.com/republib - */ - -/** @file - * @brief Unit test of the syntax symbol extractor. - */ - -#include "base/rebase.hpp" -#include "expr/reexpr.hpp" -#include "rplcore/rpltest.hpp" - -class TestRplLexer : public ReTest, public ReToken{ -public: - TestRplLexer() : - ReTest("ReLexer"), - ReToken(TOKEN_ID) - {} - -public: - void testRplToken(){ - // test constructor values: - checkEqu(TOKEN_ID, tokenType()); - checkEqu(0, m_value.m_id); - checkT(m_string.isEmpty()); - checkT(m_printableString.isEmpty()); - - m_value.m_id = 7422; - checkEqu(7422, ReToken::id()); - m_string = "Wow!"; - checkEqu("Wow!", ReToken::toString()); - m_printableString = "GooGoo"; - checkEqu("GooGoo", rawString()); - m_tokenType = TOKEN_NUMBER; - checkEqu(TOKEN_NUMBER, tokenType()); - - clear(); - checkEqu(TOKEN_UNDEF, tokenType()); - checkEqu(0, m_value.m_id); - checkT(m_string.isEmpty()); - checkT(m_printableString.isEmpty()); - - m_value.m_integer = 773322; - checkEqu(773322, asInteger()); - m_value.m_real = 0.25; - checkEqu(0.25, asReal()); - } - - ReToken* checkToken(ReToken* token, RplTokenType type, int id = 0, - const char* string = NULL){ - checkEqu(type, token->tokenType()); - if (id != 0) - checkEqu(id, token->id()); - if (string != NULL) - checkEqu(string, token->toString()); - return token; - } - enum { KEY_UNDEF, KEY_IF, KEY_THEN, KEY_ELSE, KEY_FI - }; -# define KEYWORDS "if then else fi" - enum { OP_UNDEF, OP_PLUS, OP_TIMES, OP_DIV, OP_GT, - OP_LT, OP_GE, OP_LE, OP_EQ, OP_ASSIGN, OP_PLUS_ASSIGN, OP_DIV_ASSIGN, - OP_TIMES_ASSIGN - }; -# define OPERATORS "+\n* /\n> < >= <= ==\n= += /= *=" - enum { COMMENT_UNDEF, COMMENT_1, COMMENT_MULTILINE, COMMENT_2 - }; -# define COMMENTS "/* */ // \n" - void testSpace(){ - ReSource source; - ReStringReader reader(source); -# define BLANKS1 "\t\t \n" -# define BLANKS2 " \n" - reader.addSource("
", BLANKS1 BLANKS2); - source.addReader(&reader); - ReLexer lex(&source, KEYWORDS, OPERATORS, "=", COMMENTS, - "A-Za-z_", - "A-Za-z0-9_", - ReLexer::NUMTYPE_DECIMAL, - ReLexer::SF_TICK, ReLexer::STORE_ALL); - checkToken(lex.nextToken(), TOKEN_SPACE, 0, BLANKS1); - checkToken(lex.nextToken(), TOKEN_SPACE, 0, BLANKS2); - } - void testNumeric(){ - ReSource source; - ReStringReader reader(source); - const char* blanks = "321 0x73 7.8e+5"; - reader.addSource("
", blanks); - source.addReader(&reader); - ReLexer lex(&source, KEYWORDS, OPERATORS, "=", COMMENTS, - "A-Za-z_", - "A-Za-z0-9_", - ReLexer::NUMTYPE_ALL, - ReLexer::SF_TICK, ReLexer::STORE_ALL); - ReToken* token = checkToken(lex.nextToken(), TOKEN_NUMBER); - checkEqu(321, token->asInteger()); - token = checkToken(lex.nextNonSpaceToken(), TOKEN_NUMBER); - checkEqu(0x73, token->asInteger()); - token = checkToken(lex.nextNonSpaceToken(), TOKEN_REAL); - checkEqu(7.8e+5, token->asReal()); - } - - void testOperators(){ - ReSource source; - ReStringReader reader(source); - const char* ops = "<< < <<< <= == = ( ) [ ]"; - reader.addSource("
", ops); - source.addReader(&reader); - enum { UNDEF, SHIFT, LT, SHIFT2, LE, EQ, ASSIGN, - LPARENT, RPARENT, LBRACKET, RBRACKET }; - ReLexer lex(&source, KEYWORDS, ops, "=", COMMENTS, - "A-Za-z_", - "A-Za-z0-9_", - ReLexer::NUMTYPE_ALL, - ReLexer::SF_TICK, ReLexer::STORE_ALL); - checkToken(lex.nextNonSpaceToken(), TOKEN_OPERATOR, SHIFT); - checkToken(lex.nextNonSpaceToken(), TOKEN_OPERATOR, LT); - checkToken(lex.nextNonSpaceToken(), TOKEN_OPERATOR, SHIFT2); - checkToken(lex.nextNonSpaceToken(), TOKEN_OPERATOR, LE); - checkToken(lex.nextNonSpaceToken(), TOKEN_OPERATOR, EQ); - checkToken(lex.nextNonSpaceToken(), TOKEN_OPERATOR, ASSIGN); - checkToken(lex.nextNonSpaceToken(), TOKEN_OPERATOR, LPARENT); - checkToken(lex.nextNonSpaceToken(), TOKEN_OPERATOR, RPARENT); - checkToken(lex.nextNonSpaceToken(), TOKEN_OPERATOR, LBRACKET); - checkToken(lex.nextNonSpaceToken(), TOKEN_OPERATOR, RBRACKET); - checkToken(lex.nextNonSpaceToken(), TOKEN_END_OF_SOURCE); - reader.addSource("", "(([["); - lex.startUnit(""); - checkToken(lex.nextNonSpaceToken(), TOKEN_OPERATOR, LPARENT); - checkToken(lex.nextNonSpaceToken(), TOKEN_OPERATOR, LPARENT); - checkToken(lex.nextNonSpaceToken(), TOKEN_OPERATOR, LBRACKET); - checkToken(lex.nextNonSpaceToken(), TOKEN_OPERATOR, LBRACKET); - checkToken(lex.nextNonSpaceToken(), TOKEN_END_OF_SOURCE); - } - - void testComments(){ - ReSource source; - ReStringReader reader(source); - - reader.addSource("
", "/**/9//\n8/***/7// wow\n/*\n*\n*\n**/"); - source.addReader(&reader); - - enum { COMMENT_UNDEF, COMMENT_MULTILINE, COMMENT_1 - }; - ReLexer lex(&source, KEYWORDS, OPERATORS, "=", COMMENTS, - "A-Za-z_", - "A-Za-z0-9_", - ReLexer::NUMTYPE_ALL, - ReLexer::SF_LIKE_C, ReLexer::STORE_ALL); - checkToken(lex.nextToken(), TOKEN_COMMENT_START, COMMENT_MULTILINE, - "/**/"); - checkToken(lex.nextToken(), TOKEN_NUMBER); - checkToken(lex.nextToken(), TOKEN_COMMENT_START, COMMENT_1, - "//\n"); - checkToken(lex.nextToken(), TOKEN_NUMBER); - checkToken(lex.nextToken(), TOKEN_COMMENT_START, COMMENT_MULTILINE, - "/***/"); - checkToken(lex.nextToken(), TOKEN_NUMBER); - checkToken(lex.nextToken(), TOKEN_COMMENT_START, COMMENT_1, - "// wow\n"); - checkToken(lex.nextToken(), TOKEN_COMMENT_START, COMMENT_MULTILINE, - "/*\n*\n*\n**/"); - } - void testStrings(){ - ReSource source; - ReStringReader reader(source); - - reader.addSource("
", "\"abc\\t\\r\\n\\a\\v\"'1\\x9Z\\x21A\\X9'"); - source.addReader(&reader); - - ReLexer lex(&source, KEYWORDS, OPERATORS, "=", COMMENTS, - "A-Za-z_", - "A-Za-z0-9_", - ReLexer::NUMTYPE_ALL, - ReLexer::SF_LIKE_C, ReLexer::STORE_ALL); - checkToken(lex.nextToken(), TOKEN_STRING, '"', "abc\t\r\n\a\v"); - checkToken(lex.nextToken(), TOKEN_STRING, '\'', "1\tZ!A\t"); - } - void testKeywords(){ - ReSource source; - ReStringReader reader(source); - - reader.addSource("
", "if\n\tthen else\nfi"); - source.addReader(&reader); - - ReLexer lex(&source, KEYWORDS, OPERATORS, "=", COMMENTS, - "A-Za-z_", - "A-Za-z0-9_", - ReLexer::NUMTYPE_ALL, - ReLexer::SF_LIKE_C, ReLexer::STORE_ALL); - checkToken(lex.nextToken(), TOKEN_KEYWORD, KEY_IF); - checkToken(lex.nextNonSpaceToken(), TOKEN_KEYWORD, KEY_THEN); - checkToken(lex.nextNonSpaceToken(), TOKEN_KEYWORD, KEY_ELSE); - checkToken(lex.nextNonSpaceToken(), TOKEN_KEYWORD, KEY_FI); - checkToken(lex.nextNonSpaceToken(), TOKEN_END_OF_SOURCE); - } - - void testIds(){ - ReSource source; - ReStringReader reader(source); - - reader.addSource("
", "i\n\tifs\n" - "_ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"); - source.addReader(&reader); - - ReLexer lex(&source, KEYWORDS, OPERATORS, "=", COMMENTS, - "A-Za-z_", - "A-Za-z0-9_", - ReLexer::NUMTYPE_ALL, - ReLexer::SF_LIKE_C, ReLexer::STORE_ALL); - checkToken(lex.nextToken(), TOKEN_ID, 0, "i"); - checkToken(lex.nextNonSpaceToken(), TOKEN_ID, 0, - "ifs"); - checkToken(lex.nextNonSpaceToken(), TOKEN_ID, 0, - "_ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"); - } - - void testBasic(){ - ReSource source; - ReStringReader reader(source); - source.addReader(&reader); - reader.addSource("
", "if i>1 then i=1+2*_x9 fi"); - ReLexer lex(&source, KEYWORDS, OPERATORS, "=", COMMENTS, - "A-Za-z_", - "A-Za-z0-9_", - ReLexer::NUMTYPE_ALL, - ReLexer::SF_LIKE_C, ReLexer::STORE_ALL); - ReToken* token; - checkToken(lex.nextToken(), TOKEN_KEYWORD, KEY_IF); - checkToken(lex.nextToken(), TOKEN_SPACE, 0); - checkToken(lex.nextToken(), TOKEN_ID, 0, "i"); - checkToken(lex.nextToken(), TOKEN_OPERATOR, OP_GT); - token = checkToken(lex.nextToken(), TOKEN_NUMBER); - checkEqu(1, token->asInteger()); - checkToken(lex.nextToken(), TOKEN_SPACE, 0); - checkToken(lex.nextToken(), TOKEN_KEYWORD, KEY_THEN); - checkToken(lex.nextToken(), TOKEN_SPACE, 0); - - } - void testPrio(){ - ReSource source; - ReStringReader reader(source); - source.addReader(&reader); - reader.addSource("x", ""); - enum { O_UNDEF, O_ASSIGN, O_PLUS, O_MINUS, O_TIMES, O_DIV - }; - ReLexer lex(&source, KEYWORDS, - "=\n+ -\n* /", "=", - COMMENTS, - "A-Za-z_", - "A-Za-z0-9_", - ReLexer::NUMTYPE_ALL, - ReLexer::SF_LIKE_C, ReLexer::STORE_ALL); - checkT(lex.prioOfOp(O_ASSIGN) < lex.prioOfOp(O_PLUS)); - checkEqu(lex.prioOfOp(O_PLUS), lex.prioOfOp(O_MINUS)); - checkT(lex.prioOfOp(O_MINUS) < lex.prioOfOp(O_TIMES)); - checkEqu(lex.prioOfOp(O_TIMES), lex.prioOfOp(O_DIV)); - } - - virtual void doIt(void) { - testPrio(); - testBasic(); - testIds(); - testKeywords(); - testComments(); - testStrings(); - testOperators(); - testNumeric(); - testSpace(); - testRplToken(); - } -}; -void testRplLexer() { - TestRplLexer test; - test.run(); -} diff --git a/cunit/rplmatrix_test.cpp b/cunit/rplmatrix_test.cpp deleted file mode 100644 index 2b30e7a..0000000 --- a/cunit/rplmatrix_test.cpp +++ /dev/null @@ -1,376 +0,0 @@ -/* - * rplmatrix_test.cpp - * - * License: Public Domain - * You can use and modify this file without any restriction. - * Do what you want. - * No warranties and disclaimer of any damages. - * You also can use this license: http://www.wtfpl.net - * The latest sources: https://github.com/republib - */ - -/** @file - * @brief Unit test of the matrices. - */ - -#include "base/rebase.hpp" -#include "rplmath/rplmath.hpp" -#include "rplcore/rpltest.hpp" - -class TestRplMatrix : public ReTest{ -public: - TestRplMatrix() : ReTest("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++){ - checkEqu(100.0*row + col + offset, mx.get(row, col)); - count++; - } - } - checkEqu(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++){ - checkEqu(value, mx.get(row, col)); - count++; - } - } - checkEqu(mx.getCols()*mx.getRows(), count); - } - - void testBasic() { - Tuple2 tuple(-2.0, 0.5); - checkEqu(-2.0, tuple.m_value1); - checkEqu(0.5, tuple.m_value2); - RplMatrix mat("mx"); - try{ - throw RplMatrixException(mat, "String: %s and int %d", "Hi", -333); - checkF(true); - } catch (RplMatrixException exc){ - checkEqu("mx: String: Hi and int -333", exc.getMessage()); - } - RplMatrix mat2; - try{ - throw RplMatrixException(mat2, "String: %s and int %d", "Hi", -333); - checkF(true); - } catch (RplMatrixException exc){ - checkEqu("String: Hi and int -333", exc.getMessage()); - } - checkEqu("mx", mat.getName()); - checkEqu("", mat2.getName()); - - RplMatrix m2x3(2, 3, "m2x3"); - checkEqu("m2x3", m2x3.getName()); - checkEqu(2, m2x3.getRows()); - checkEqu(3, m2x3.getCols()); - fillMatrix(m2x3); - checkMatrix(m2x3); - - RplMatrix mxCopy(m2x3); - checkEqu("m2x3-copy", mxCopy.getName()); - checkEqu(2, mxCopy.getRows()); - checkEqu(3, mxCopy.getCols()); - checkMatrix(mxCopy); - - RplMatrix mxCopy2("mxCopy2"); - mxCopy2 = m2x3; - checkEqu("mxCopy2", mxCopy2.getName()); - checkEqu(2, mxCopy2.getRows()); - checkEqu(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){ - checkEqu("m1: row number negative: -1", exc.getMessage()); - } - try { - m1.checkDefinition(1, -1); - checkT(false); - } catch(RplMatrixException exc){ - checkEqu("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){ - checkEqu("m1: invalid row: -1 not in [0,3[", exc.getMessage()); - } - try { - m1.check(3, 1); - checkT(false); - } catch(RplMatrixException exc){ - checkEqu("m1: invalid row: 3 not in [0,3[", exc.getMessage()); - } - try { - m1.check(1, -1); - checkT(false); - } catch(RplMatrixException exc){ - checkEqu("m1: invalid column: -1 not in [0,2[", exc.getMessage()); - } - try { - m1.check(1, 2); - checkT(false); - } catch(RplMatrixException exc){ - checkEqu("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){ - checkEqu("m1: m2 has a different row count: 3 / 2", exc.getMessage()); - } - m2.resize(3, 3); - try { - m1.checkSameDimension(m2); - checkT(false); - } catch(RplMatrixException exc){ - checkEqu("m1: m2 has a different column count: 2 / 3", exc.getMessage()); - } - } - void testResize(){ - RplMatrix m1(3, 2, "m1"); - fillMatrix(m1); - checkMatrix(m1); - RplMatrix m2(2, 4, "m2"); - fillConst(m2, 0); - checkConst(m2, 0); - - m1.resize(2, 4); - checkEqu(2, m1.getRows()); - checkEqu(4, m1.getCols()); - checkT(m1 == m2); - } - - void testMinMax(){ - RplMatrix m1(4, 5, "m1"); - fillMatrix(m1); - checkMatrix(m1); - m1.set(0, 0, -98); - m1.set(3, 4, 9999); - Tuple2 miniMax = m1.minMax(); - checkEqu(-98.0, miniMax.m_value1); - checkEqu(9999.0, miniMax.m_value2); - - fillMatrix(m1); - checkMatrix(m1); - m1.set(1, 1, 7777); - m1.set(3, 4, -987); - miniMax = m1.minMax(); - checkEqu(-987.0, miniMax.m_value1); - checkEqu(7777.0, miniMax.m_value2); - } - - void testTranspose() - { - RplMatrix m1(1, 5, "m1"); - fillMatrix(m1); - RplMatrix m2(m1.transpose()); - - checkEqu(5, m2.getRows()); - checkEqu(1, m2.getCols()); - - int row, col; - col = 0; - for (row = 0; row < 5; row++){ - checkEqu(qreal(col*100+row), m2.get(row, 0)); - } - - m1.resize(35, 73); - fillMatrix(m1); - m2 = m1.transpose(); - - checkEqu(73, m2.getRows()); - checkEqu(35, m2.getCols()); - - int count = 0; - for (row = 0; row < m2.getRows(); row++){ - for (col = 0; col < m2.getCols(); col++){ - checkEqu(qreal(col*100+row), m2.get(row, col)); - count++; - } - } - checkEqu(73*35, count); - } - void testToString(){ - RplMatrix m1(1, 1, "m1"); - m1.set(0, 0, 2.34); - checkEqu("[2.340000,\n]", m1.toString().constData()); - checkEqu("jonny[2.34000 |]", m1.toString("jonny", "%.5f", "|", " ").constData()); - - m1.resize(2, 1); - m1.set(0, 0, 2.34); - m1.set(1, 0, 55.5); - - checkEqu("[2.340000,\n55.500000,\n]", m1.toString().constData()); - checkEqu("jonny[2.34000 |55.50000 |]", m1.toString("jonny", "%.5f", "|", " ").constData()); - log(""); - } - void testReadCsv(){ - QByteArray fn = getTempFile("rplmatrixtest.csv"); - const char* content; - RplMatrix m1(1,1,"m1"); - - fillMatrix(m1); - content = ",Port0,Port1,Port2\n" - "element1,5, -3E-99 , 0.5\n" - "element2,7,-22.3,44\n" - "\n" - "2 Elements, 3, Ports"; - ReStringUtil::write(fn, content); - m1.readFromCvs(fn, 256); - checkEqu(2, m1.getRows()); - checkEqu(3, m1.getCols()); - - checkEqu(5.0, m1.get(0, 0)); - checkEqu(-3.0E-99, m1.get(0, 1)); - checkEqu(0.5, m1.get(0, 2)); - - checkEqu(7.0, m1.get(1, 0)); - checkEqu(-22.3, m1.get(1, 1)); - checkEqu(44.0, m1.get(1, 2)); - - fillMatrix(m1); - content = "Port0,Port1,Port2\n" - "5, -3E-99 , 0.5\n"; - ReStringUtil::write(fn, content); - m1.readFromCvs(fn, 256); - checkEqu(1, m1.getRows()); - checkEqu(3, m1.getCols()); - checkEqu(5.0, m1.get(0, 0)); - checkEqu(-3.0E-99, m1.get(0, 1)); - checkEqu(0.5, m1.get(0, 2)); - - -/* - void readFromCvs(const char* filename, int maxLineLength = 1024*1024); - void readFromXml(const char* filename, const char* tagCol, - const char* tagRow, const char* tagTable, - int maxLineLength = 1024*1024); -*/ - } - virtual void doIt(void) { - testBasic(); - testAddOperators(); - testCompareOperators(); - testCheckDefinition(); - testCheck(); - testCheckSameDimension(); - testResize(); - testMinMax(); - testTranspose(); - testToString(); - testReadCsv(); - } -}; -void testRplMatrix() { - TestRplMatrix test; - test.run(); -} diff --git a/cunit/rplmfparser_test.cpp b/cunit/rplmfparser_test.cpp deleted file mode 100644 index a234542..0000000 --- a/cunit/rplmfparser_test.cpp +++ /dev/null @@ -1,229 +0,0 @@ -/* - * rplmfparser_test.cpp - * - * License: Public Domain - * You can use and modify this file without any restriction. - * Do what you want. - * No warranties and disclaimer of any damages. - * You also can use this license: http://www.wtfpl.net - * The latest sources: https://github.com/republib - */ -/** @file - * @brief Unit test of the parser for the language "MF". - */ - -#include "base/rebase.hpp" -#include "expr/reexpr.hpp" -#include "rplcore/rpltest.hpp" - -class TestRplMFParser : public ReTest{ -private: - ReSource m_source; - ReASTree m_tree; - ReStringReader m_reader; - ReFileReader m_fileReader; - QByteArray m_currentSource; -public: - TestRplMFParser() : - ReTest("ReMFParser"), - m_source(), - m_tree(), - m_reader(m_source), - m_fileReader(m_source) - { - m_source.addReader(&m_reader); - } -protected: - void setSource(const char* content){ - ReASItem::reset(); - m_currentSource = content; - m_tree.clear(); - m_source.clear(); - m_reader.clear(); - m_reader.addSource("", content); - m_source.addReader(&m_reader); - m_source.addSourceUnit(m_reader.currentSourceUnit()); - } - void setFileSource(const char* filename){ - ReASItem::reset(); - m_currentSource = ReStringUtil::read(filename); - m_tree.clear(); - m_source.clear(); - m_fileReader.clear(); - m_fileReader.addSource(filename); - m_source.addReader(&m_fileReader); - m_source.addSourceUnit(m_fileReader.currentSourceUnit()); - } - -private: - void checkAST(const char* fileExpected, int lineNo){ - QByteArray fnExpected = "test"; - fnExpected += QDir::separator().toLatin1(); - fnExpected += "mfparser"; - fnExpected += (char) QDir::separator().toLatin1(); - fnExpected += fileExpected; - QByteArray fnCurrent = getTempFile(fileExpected, "rplmfparser"); - m_tree.dump(fnCurrent, ReASTree::DMP_NO_GLOBALS, m_currentSource); - assertEqualFiles(fnExpected.constData(), fnCurrent.constData(), - __FILE__, lineNo); - } - -public: - void fileClassTest(){ - setFileSource("test/rplmfparser/string1.mf"); - ReMFParser parser(m_source, m_tree); - parser.parse(); - checkAST("string1.txt", __LINE__); - } - - void baseTest(){ - setSource("2+3*4"); - ReMFParser parser(m_source, m_tree); - parser.parse(); - checkAST("baseTest.txt", __LINE__); - } - - void varDefTest(){ - setSource("const lazy Str s = 'Hi';\nconst List l;\nInt i = 3;"); - ReMFParser parser(m_source, m_tree); - parser.parse(); - checkAST("varDefTest.txt", __LINE__); - } - - void ifTest(){ - setSource("Int a;\nInt b;\na = b = 2;\nif 11 < 12\nthen a = 13 * 14\nelse a = 15 / 16\nfi"); - // setSource("Int a; if 11 < 12 then a = 13 * 14 else a = 15 / 16 fi"); - ReMFParser parser(m_source, m_tree); - parser.parse(); - checkAST("ifTest1.txt", __LINE__); - setSource("Str x;\nif 7 < 6\nthen x = '123';\nfi"); - parser.parse(); - checkAST("ifTest2.txt", __LINE__); - } - void whileTest(){ - setSource("Int a = 20;\nwhile 3 < 5 do\n a = 7\nod"); - ReMFParser parser(m_source, m_tree); - parser.parse(); - checkAST("whileTest.txt", __LINE__); - } - - void repeatTest(){ - setSource("Int a;\nrepeat\na++;\nuntil a != 2 * 3;"); - ReMFParser parser(m_source, m_tree); - parser.parse(); - checkAST("repeatTest.txt", __LINE__); - } - void forCTest(){ - setSource("Int a;\nfor b from 10 to 1 step -2 do\na += 1;\nod"); - ReMFParser parser(m_source, m_tree); - parser.parse(); - checkAST("forC1.txt", __LINE__); - setSource("Int a; for to 10 do a += 1 od"); - parser.parse(); - checkAST("forC2.txt", __LINE__); - } - void opTest(){ - checkEqu(25, ReMFParser::O_QUESTION); - checkEqu(37, ReMFParser::O_RSHIFT2); - checkEqu(41, ReMFParser::O_DEC); - checkEqu(48, ReMFParser::O_RBRACE); - setSource("Int a = 1;\nInt b = 100;\n--a;\nb++;\na--*++b**(8-3);\na=b=(a+(b-2)*3)"); - ReMFParser parser(m_source, m_tree); - parser.parse(); - checkAST("opTest1.txt", __LINE__); - } - void forItTest(){ - setSource("Map a;\nfor x in a do\na += 1;\nod"); - ReMFParser parser(m_source, m_tree); - parser.parse(); - checkAST("forIt1.txt", __LINE__); - } - void listTest(){ - ReMFParser parser(m_source, m_tree); - setSource("List b = [];"); - parser.parse(); - checkAST("list1.txt", __LINE__); - setSource("List a = [2+3, 3.14, 7, 'hi', a]; List b = [];"); - parser.parse(); - checkAST("list2.txt", __LINE__); - } - void mapTest(){ - setSource("Map a = {};"); - ReMFParser parser(m_source, m_tree); - parser.parse(); - checkAST("map1.txt", __LINE__); - setSource("Map a = {'a': 2+3,'bcd':3.14,'ccc':7, 'hi':'world'};\nMap b = {};"); - parser.parse(); - checkAST("map2.txt", __LINE__); - } - void methodCallTest(){ - //setSource("max(4,3.14);"); - setSource("rand();\nsin(a);\nmax(1+2*3,4**(5-4));"); - ReMFParser parser(m_source, m_tree); - parser.parse(); - checkAST("methc1.txt", __LINE__); - } - void fieldTest(){ - setSource("file.find('*.c')[0].name;\n[1,2,3].join(' ');\n3.14.trunc;"); - ReMFParser parser(m_source, m_tree); - parser.parse(); - checkAST("field1.txt", __LINE__); - } - - void methodTest(){ - setSource("func Float pi: 3.1415; endf func Str delim(): '/' endf;"); - ReMFParser parser(m_source, m_tree); - parser.parse(); - checkAST("meth1.txt", __LINE__); - setSource("func Int fac(const Int n):\n" - "Int rc; if rc <= 1 then rc = 1 else rc = n*fac(n-1) fi\n" - "rc endf"); - parser.parse(); - checkAST("meth2.txt", __LINE__); - setSource("func Int max(Int a, Int b):\n Int rc = a;\n" - "if a < b then rc = b; fi\nrc\n" - "endf\n" - "func Int max(const Int a, Int b, Int c):\n" - "max(a, max(b, c))\n" - "endf"); - parser.parse(); - checkAST("meth3.txt", __LINE__); - setSource("func Int max(const Int a, Int b, Int c):\n" - "func Int max(Int a, Int b):\n Int rc = a;\n" - "if a < b then rc = b; fi\nrc\n" - "endf\n" - "max(a, max(b, c))\n" - "endf"); - parser.parse(); - checkAST("meth4.txt", __LINE__); - } - void mainTest(){ - setSource("Int a=2+3*4;\nfunc Void main():\na;\nendf"); - ReMFParser parser(m_source, m_tree); - parser.parse(); - checkAST("main1.txt", __LINE__); - } - - virtual void doIt(void) { - mainTest(); - varDefTest(); - repeatTest(); - baseTest(); - whileTest(); - methodTest(); - fieldTest(); - methodCallTest(); - mapTest(); - forItTest(); - forCTest(); - listTest(); - opTest(); - fileClassTest(); - } -}; -void testRplMFParser() { - TestRplMFParser test; - test.run(); -} - - diff --git a/cunit/rplqstring_test.cpp b/cunit/rplqstring_test.cpp deleted file mode 100644 index d6116f5..0000000 --- a/cunit/rplqstring_test.cpp +++ /dev/null @@ -1,128 +0,0 @@ -/* - * rplqstring_test.cpp - * - * License: Public Domain - * You can use and modify this file without any restriction. - * Do what you want. - * No warranties and disclaimer of any damages. - * You also can use this license: http://www.wtfpl.net - * The latest sources: https://github.com/republib - */ -/** @file - * @brief Unit test of the ReString tools. - */ - -#include "base/rebase.hpp" -#include "rplcore/rpltest.hpp" - -class TestRplQString : public ReTest { -public: - TestRplQString() : - ReTest("ReQString") - {} - -public: - void testLengthOfUInt64(){ - quint64 value = -3; - checkEqu(1, ReQString::lengthOfUInt64(ReString("0"), 0, 10, &value)); - checkEqu(0LL, value); - checkEqu(3, ReQString::lengthOfUInt64("x432", 1, 10, &value)); - checkEqu(432LL, value); - checkEqu(3, ReQString::lengthOfUInt64("x432 x", 1, 10, &value)); - checkEqu(432LL, value); - checkEqu(3, ReQString::lengthOfUInt64("x432fabc x", 1, 10, &value)); - checkEqu(432LL, value); - checkEqu(16, ReQString::lengthOfUInt64("a1234567890123567", 1, 10, &value)); - checkEqu(1234567890123567LL, value); - checkEqu(10, ReQString::lengthOfUInt64("x1234abcdef", 1, 16, &value)); - checkEqu(0x1234abcdefLL, value); - checkEqu(3, ReQString::lengthOfUInt64("432", 0, 8, &value)); - checkEqu(0432LL, value); - checkEqu(6, ReQString::lengthOfUInt64(" 765432 ", 1, 8, &value)); - checkEqu(0765432LL, value); - - checkEqu(0, ReQString::lengthOfUInt64("1 ", 1, 8, &value)); - checkEqu(0, ReQString::lengthOfUInt64("", 1, 8, &value)); - } - void testLengthOfUInt(){ - uint value = 3; - checkEqu(1, ReQString::lengthOfUInt(ReString("0"), 0, 10, &value)); - checkEqu(0, value); - checkEqu(3, ReQString::lengthOfUInt("x432", 1, 10, &value)); - checkEqu(432, value); - checkEqu(3, ReQString::lengthOfUInt("x432 x", 1, 10, &value)); - checkEqu(432, value); - checkEqu(3, ReQString::lengthOfUInt("x432fabc x", 1, 10, &value)); - checkEqu(432, value); - checkEqu(3, ReQString::lengthOfUInt("432", 0, 8, &value)); - checkEqu(0432, value); - checkEqu(6, ReQString::lengthOfUInt(" 765432 ", 1, 8, &value)); - checkEqu(0765432, value); - - checkEqu(0, ReQString::lengthOfUInt("1 ", 1, 8, &value)); - checkEqu(0, ReQString::lengthOfUInt("", 1, 8, &value)); - } - void testLengthOfReal(){ - qreal value; - checkEqu(4, ReQString::lengthOfReal(ReString("0.25"), 0, &value)); - checkEqu(0.25, value); - checkEqu(3, ReQString::lengthOfReal(ReString("X.25"), 1, &value)); - checkEqu(0.25, value); - checkEqu(1, ReQString::lengthOfReal(ReString(" 0"), 1, &value)); - checkEqu(0.0, value); - checkEqu(17, ReQString::lengthOfReal(ReString("X12345678901234567"), 1, &value)); - checkEqu(12345678901234567.0, value); - checkEqu(2, ReQString::lengthOfReal(ReString(".5"), 0, &value)); - checkEqu(0.5, value); - checkEqu(5, ReQString::lengthOfReal(ReString("2.5e2x"), 0, &value)); - checkEqu(250.0, value); - checkEqu(6, ReQString::lengthOfReal(ReString("2.5e+2"), 0, &value)); - checkEqu(250.0, value); - checkEqu(7, ReQString::lengthOfReal(ReString("2.5E-33"), 0, &value)); - checkEqu(2.5e-33, value); - - checkEqu(3, ReQString::lengthOfReal(ReString("2.5E"), 0, &value)); - checkEqu(2.5, value); - checkEqu(3, ReQString::lengthOfReal(ReString("2.5E+"), 0, &value)); - checkEqu(2.5, value); - checkEqu(3, ReQString::lengthOfReal(ReString("2.5E-a"), 0, &value)); - checkEqu(2.5, value); - } - - void testValueOfHexDigit(){ - checkEqu(0, ReQString::valueOfHexDigit('0')); - checkEqu(9, ReQString::valueOfHexDigit('9')); - checkEqu(10, ReQString::valueOfHexDigit('a')); - checkEqu(15, ReQString::valueOfHexDigit('f')); - checkEqu(10, ReQString::valueOfHexDigit('A')); - checkEqu(15, ReQString::valueOfHexDigit('F')); - - checkEqu(-1, ReQString::valueOfHexDigit('0' - 1)); - checkEqu(-1, ReQString::valueOfHexDigit('9' + 1)); - checkEqu(-1, ReQString::valueOfHexDigit('A' - 1)); - checkEqu(-1, ReQString::valueOfHexDigit('F' + 1)); - checkEqu(-1, ReQString::valueOfHexDigit('a' - 1)); - checkEqu(-1, ReQString::valueOfHexDigit('f' + 1)); - } - void testUtf8(){ - ReString name = "Heinz Müller"; - char buffer[32]; - checkEqu("Heinz Müller", ReQString::utf8(name, buffer, sizeof buffer)); - memset(buffer, 'x', sizeof buffer); - checkEqu("Heinz", ReQString::utf8(name, buffer, (size_t) (5+1))); - checkEqu(buffer[6], 'x'); - } - - virtual void doIt(void) { - testUtf8(); - testLengthOfUInt64(); - testLengthOfUInt(); - testLengthOfReal(); - testValueOfHexDigit(); - } -}; -void testRplQString() { - TestRplQString test; - test.run(); -} - diff --git a/cunit/rplsource_test.cpp b/cunit/rplsource_test.cpp deleted file mode 100644 index 83fd0ec..0000000 --- a/cunit/rplsource_test.cpp +++ /dev/null @@ -1,112 +0,0 @@ -/* - * rplsource_test.cpp - * - * License: Public Domain - * You can use and modify this file without any restriction. - * Do what you want. - * No warranties and disclaimer of any damages. - * You also can use this license: http://www.wtfpl.net - * The latest sources: https://github.com/republib - */ - -/** @file - * @brief Unit test of the input media reader. - */ - -#include "base/rebase.hpp" -#include "expr/reexpr.hpp" -#include "rplcore/rpltest.hpp" - -class TestReSource : public ReTest{ -public: - TestReSource() : ReTest("TestReSource") {} - -private: - QByteArray m_content1_1; - QByteArray m_content1_2; - QByteArray m_content2; - ReSource m_source; - -protected: - void init(){ - m_content1_1 = "# test\nimport source2\n"; - m_content1_2 = "a=1;\nveeeeeeeeery looooooooooooooong\n"; - m_content2 = "x=2"; - } - - void testReStringSourceUnit(){ - ReStringReader reader(m_source); - QByteArray content("a=1;\nveeeeeeeeery looooooooooooooong\n"); - ReStringSourceUnit unit("test", content, &reader); - unit.setLineNo(144); - checkEqu(144, unit.lineNo()); - checkEqu("test", unit.name()); - } - void checkOne(int maxSize, ReReader& reader){ - QByteArray total; - QByteArray buffer; - int lineNo = 0; - bool hasMore; - checkF(reader.openSourceUnit("unknownSource")); - checkT(reader.openSourceUnit("source1")); - while(reader.nextLine(maxSize, buffer, hasMore)){ - lineNo++; - total += buffer; - buffer.clear(); - while(hasMore && reader.fillBuffer(maxSize, buffer, hasMore)){ - total += buffer; - buffer.clear(); - } - bool isImport = total.endsWith("source2\n"); - if (isImport){ - reader.openSourceUnit("source2"); - checkEqu("source2", reader.currentSourceUnit()->name()); - while(reader.nextLine(maxSize, buffer, hasMore)){ - lineNo++; - while(hasMore && reader.fillBuffer(maxSize, buffer, hasMore)){ - total += buffer; - buffer.clear(); - } - } - checkEqu("source1", reader.currentSourceUnit()->name()); - } - } - checkEqu(5, lineNo); - checkEqu(m_content1_1 + m_content2 + m_content1_2, total); - - } - - void testReStringReader(){ - ReStringReader reader(m_source); - reader.addSource("source1", m_content1_1 + m_content1_2); - reader.addSource("source2", m_content2); - ReSourceUnit* unit = reader.openSourceUnit("source1"); - checkNN(unit); - checkEqu("source1", unit->name()); - checkEqu(0, unit->lineNo()); - checkOne(6, reader); - checkOne(100, reader); - reader.replaceSource("source2", "content2"); - - unit = reader.openSourceUnit("source2"); - QByteArray buffer; - bool hasMore; - checkT(reader.nextLine(50, buffer, hasMore)); - checkEqu("content2", buffer); - checkF(hasMore); - } - -public: - virtual void doIt(void) { - init(); - testReStringSourceUnit(); - testReStringReader(); - } -}; -void testReSource() { - TestReSource test; - test.run(); -} - - - diff --git a/cunit/rplstring_test.cpp b/cunit/rplstring_test.cpp deleted file mode 100644 index c2e7dc8..0000000 --- a/cunit/rplstring_test.cpp +++ /dev/null @@ -1,199 +0,0 @@ -/* - * rplstring_test.cpp - * - * License: Public Domain - * You can use and modify this file without any restriction. - * Do what you want. - * No warranties and disclaimer of any damages. - * You also can use this license: http://www.wtfpl.net - * The latest sources: https://github.com/republib - */ - -/** @file - * @brief Unit test of the QByteArray tools. - */ -#include "base/rebase.hpp" -#include "rplcore/rpltest.hpp" -/** - * @brief Unit test for ReStringUtil. - */ -class TestReString : public ReTest { -public: - TestReString() : ReTest("ReStringUtil") {} - -public: - void testCountChar(){ - checkEqu(1, ReStringUtil::countChar("x", 'x')); - checkEqu(0, ReStringUtil::countChar("X", 'x')); - checkEqu(2, ReStringUtil::countChar("xbxxbxx", 'b')); - } - - void testCount() { - checkEqu(0, ReStringUtil::count("abc", " ")); - checkEqu(1, ReStringUtil::count("abc", "b")); - checkEqu(2, ReStringUtil::count("axx", "x")); - - checkEqu(0, ReStringUtil::count("abbc", "bbb")); - checkEqu(1, ReStringUtil::count("\n\n", "\n\n")); - checkEqu(2, ReStringUtil::count(" a ", " ")); - } - - void testCutString() { - QByteArray source("123"); - QByteArray buffer; - checkEqu(QByteArray("123"), ReStringUtil::cutString(source, 4, buffer)); - checkEqu(QByteArray("123"), ReStringUtil::cutString(source, 3, buffer)); - checkEqu(QByteArray("12..."), ReStringUtil::cutString(source, 2, buffer)); - checkEqu(QByteArray("12"), ReStringUtil::cutString(source, 2, buffer, "")); - } - - void testHexDump() { - QByteArray data("abc123\nxyz"); - checkEqu(QByteArray("61 62 63 31 abc1\n" - "32 33 0a 78 23.x\n" - "79 7a yz\n"), - ReStringUtil::hexDump((uint8_t*) data.constData(), data.length(), 4)); - checkEqu(QByteArray("61 62 63 31 32 33 0a 78 79 7a abc123.xyz"), - ReStringUtil::hexDump((uint8_t*) data.constData(), data.length(), 10)); - checkEqu(QByteArray("61 62 63 31 32 33 0a 78 79 7a abc123.xyz"), - ReStringUtil::hexDump((uint8_t*) data.constData(), data.length(), 12)); - } - - void testReadWrite() { - QByteArray fn = getTempFile("test.dat"); - const char* content = "Hello world\nLine2\n"; - checkT(ReStringUtil::write(fn, content)); - checkEqu(content, ReStringUtil::read(fn, false)); - checkEqu(content, ReStringUtil::read(fn, true) + "\n"); - } - - void testToArray() { - QList array = ReStringUtil::toArray("1 abc 3", " "); - checkEqu(3, array.size()); - checkEqu("1", array.at(0)); - checkEqu("abc", array.at(1)); - checkEqu("3", array.at(2)); - } - - void testToNumber() { - checkEqu("3", ReStringUtil::toNumber(3)); - checkEqu("-33", ReStringUtil::toNumber(-33)); - checkEqu("003", ReStringUtil::toNumber(3, "%03d")); - } - - void testLengthOfNumber(){ - checkEqu(3, ReStringUtil::lengthOfNumber("0.3xxx")); - checkEqu(5, ReStringUtil::lengthOfNumber(" \t0.3xxx")); - checkEqu(3, ReStringUtil::lengthOfNumber("-.3xxx")); - checkEqu(2, ReStringUtil::lengthOfNumber(".3exxx")); - checkEqu(2, ReStringUtil::lengthOfNumber(".3e+xxx")); - checkEqu(16, ReStringUtil::lengthOfNumber("1234567.9012E+77")); - checkEqu(17, ReStringUtil::lengthOfNumber("-1234567.9012E+77 ")); - checkEqu(18, ReStringUtil::lengthOfNumber("-1234567.9012E+77 ", true)); - checkEqu(18, ReStringUtil::lengthOfNumber("-1234567.9012E+77 x", true)); - checkEqu(20, ReStringUtil::lengthOfNumber(" -1234567.9012E+77 x", true)); - } - - void checkCsv(const char* content, char expected){ - QByteArray fn = getTempFile("testrplstring.csv"); - ReStringUtil::write(fn, content); - FILE* fp = fopen(fn, "r"); - checkNN(fp); - char buffer[256]; - checkEqu(expected, ReStringUtil::findCsvSeparator(fp, buffer, sizeof buffer)); - fclose(fp); - } - - void testFindCsvSeparator(){ - const char* content = ",,,\t;;;||||"; - checkCsv(content, '\t'); - - content = "col1,col2\n1.5,3,5\n"; - checkCsv(content, ','); - - content = "col1;col2\n1,50;3.5\n" - "7;8\n10;12\n13;14"; - checkCsv(content, ';'); - - content = "0.3 7.8 8.9\n7.8 9.4 8.3"; - checkCsv(content, ' '); - - content = "0.3|7.8|8.9\n7.8| 9.4|8.3"; - checkCsv(content, '|'); - - content = "0,3;7.8;8.9"; - checkCsv(content, ';'); - } - void testLengthOfUInt64(){ - quint64 value = -3; - checkEqu(1, ReStringUtil::lengthOfUInt64("0", 10, &value)); - checkEqu(0LL, value); - checkEqu(3, ReStringUtil::lengthOfUInt64("432", 10, &value)); - checkEqu(432LL, value); - checkEqu(3, ReStringUtil::lengthOfUInt64("432 x", 10, &value)); - checkEqu(432LL, value); - checkEqu(3, ReStringUtil::lengthOfUInt64("432fabc x", 10, &value)); - checkEqu(432LL, value); - checkEqu(16, ReStringUtil::lengthOfUInt64("1234567890123567", 10, &value)); - checkEqu(1234567890123567LL, value); - checkEqu(10, ReStringUtil::lengthOfUInt64("1234abcdef", 16, &value)); - checkEqu(0x1234abcdefLL, value); - checkEqu(3, ReStringUtil::lengthOfUInt64("432", 8, &value)); - checkEqu(0432LL, value); - checkEqu(6, ReStringUtil::lengthOfUInt64("765432 ", 8, &value)); - checkEqu(0765432LL, value); - - checkEqu(0, ReStringUtil::lengthOfUInt64(" ", 8, &value)); - checkEqu(0, ReStringUtil::lengthOfUInt64("", 8, &value)); - } - void testLengthOfReal(){ - qreal value; - checkEqu(1, ReStringUtil::lengthOfReal("0", &value)); - checkEqu(0.0, value); - checkEqu(1, ReStringUtil::lengthOfReal("0%", &value)); - checkEqu(0.0, value); - checkEqu(4, ReStringUtil::lengthOfReal("0.25", &value)); - checkEqu(0.25, value); - checkEqu(3, ReStringUtil::lengthOfReal(".25", &value)); - checkEqu(0.25, value); - checkEqu(17, ReStringUtil::lengthOfReal("12345678901234567", &value)); - checkEqu(12345678901234567.0, value); - checkEqu(2, ReStringUtil::lengthOfReal(".5", &value)); - checkEqu(0.5, value); - checkEqu(5, ReStringUtil::lengthOfReal("2.5e2x", &value)); - checkEqu(250.0, value); - checkEqu(6, ReStringUtil::lengthOfReal("2.5e+2", &value)); - checkEqu(250.0, value); - checkEqu(7, ReStringUtil::lengthOfReal("2.5E-33", &value)); - checkEqu(2.5e-33, value); - - checkEqu(3, ReStringUtil::lengthOfReal("2.5E", &value)); - checkEqu(2.5, value); - checkEqu(3, ReStringUtil::lengthOfReal("2.5E+", &value)); - checkEqu(2.5, value); - checkEqu(3, ReStringUtil::lengthOfReal("2.5E-a", &value)); - checkEqu(2.5, value); - } - - virtual void doIt() { - testLengthOfReal(); - testLengthOfUInt64(); - testCountChar(); - testCount(); - testCutString(); - testToNumber(); - testToArray(); - testHexDump(); - testReadWrite(); - testLengthOfNumber(); - testFindCsvSeparator(); - } -}; - -void testReString() { - TestReString test; - test.run(); -} - - - diff --git a/cunit/rplvm_test.cpp b/cunit/rplvm_test.cpp deleted file mode 100644 index 39df487..0000000 --- a/cunit/rplvm_test.cpp +++ /dev/null @@ -1,75 +0,0 @@ -/* - * rplvm_test.cpp - * - * License: Public Domain - * You can use and modify this file without any restriction. - * Do what you want. - * No warranties and disclaimer of any damages. - * You also can use this license: http://www.wtfpl.net - * The latest sources: https://github.com/republib - */ - -#include "base/rebase.hpp" -#include "expr/reexpr.hpp" -#include "rplcore/rpltest.hpp" - -class TestReVM : public ReTest{ -private: - ReSource m_source; - ReASTree m_tree; - ReStringReader m_reader; - const char* m_currentSource; -public: - TestReVM() : - ReTest("ReVM"), - m_source(), - m_tree(), - m_reader(m_source) - { - m_source.addReader(&m_reader); - } -protected: - void setSource(const char* content){ - ReASItem::reset(); - m_currentSource = content; - m_tree.clear(); - m_source.clear(); - m_reader.clear(); - m_reader.addSource("", content); - m_source.addReader(&m_reader); - m_source.addSourceUnit(m_reader.currentSourceUnit()); - } - -private: - void checkAST(const char* fileExpected, int lineNo){ - QByteArray fnExpected = "test"; - fnExpected += QDir::separator().toLatin1(); - fnExpected += "ReVM"; - fnExpected += (char) QDir::separator().toLatin1(); - fnExpected += fileExpected; - QByteArray fnCurrent = getTempFile(fileExpected, "ReVM"); - ReMFParser parser(m_source, m_tree); - parser.parse(); - ReVirtualMachine vm(m_tree, m_source); - vm.setFlag(ReVirtualMachine::VF_TRACE_STATEMENTS); - ReFileWriter writer(fnCurrent); - vm.setTraceWriter(&writer); - writer.write(m_currentSource); - vm.executeModule(""); - assertEqualFiles(fnExpected.constData(), fnCurrent.constData(), - __FILE__, lineNo); - } -public: - void baseTest(){ - setSource("Int a=2+3*4;\nfunc Void main():\na;\nendf"); - checkAST("baseTest.txt", __LINE__); - } - virtual void doIt(void) { - baseTest(); - } -}; -void testReVM() { - TestReVM test; - test.run(); -} - diff --git a/cunit/rplwriter_test.cpp b/cunit/rplwriter_test.cpp deleted file mode 100644 index 71de3b6..0000000 --- a/cunit/rplwriter_test.cpp +++ /dev/null @@ -1,52 +0,0 @@ -/* - * rplwriter_test.cpp - * - * License: Public Domain - * You can use and modify this file without any restriction. - * Do what you want. - * No warranties and disclaimer of any damages. - * You also can use this license: http://www.wtfpl.net - * The latest sources: https://github.com/republib - */ - -/** @file - * @brief Unit test of the output media writers. - */ - -#include "base/rebase.hpp" -#include "rplcore/rpltest.hpp" -/** - * @brief Unit test for ReStringUtil. - */ -class TestRplWriter : public ReTest { -public: - TestRplWriter() : ReTest("ReWriter") {} - -private: - void testFileWriter(){ - QByteArray fn = getTempFile("rplwriter.txt"); - ReFileWriter writer(fn); - writer.writeLine("abc"); - writer.formatLine("%04d", 42); - writer.writeIndented(3, "123"); - writer.indent(2); - writer.write("pi"); - writer.format("%3c%.2f", ':', 3.1415); - writer.writeLine(); - writer.close(); - QByteArray current = ReStringUtil::read(fn, false); - checkEqu("abc\n0042\n\t\t\t123\n\t\tpi :3.14\n", current); - } - -public: - virtual void doIt(void) { - testFileWriter(); - } -}; -void testRplWriter() { - TestRplWriter test; - test.run(); -} - - - diff --git a/expr/ReLexer.cpp b/expr/ReLexer.cpp index 3aab121..e9d814b 100644 --- a/expr/ReLexer.cpp +++ b/expr/ReLexer.cpp @@ -794,13 +794,13 @@ ReToken*ReLexer::scanString(){ throw ReLexException(*m_currentPosition, "missing hexadecimal digit behind \\x"); cc = m_input[length++]; - int hexVal = ReQString::valueOfHexDigit(cc); + int hexVal = ReQStringUtil::valueOfHexDigit(cc); if (hexVal < 0) throw ReLexException(*m_currentPosition, "not a hexadecimal digit behind \\x: %lc", QChar(cc)); if (length < inputLength){ cc = m_input[length]; - int nibble = ReQString::valueOfHexDigit(cc); + int nibble = ReQStringUtil::valueOfHexDigit(cc); if (nibble >= 0){ length++; hexVal = hexVal * 16 + nibble; diff --git a/net/ReTCPClient.hpp b/net/ReTCPClient.hpp index 7321dd3..1fabfe5 100644 --- a/net/ReTCPClient.hpp +++ b/net/ReTCPClient.hpp @@ -11,6 +11,13 @@ #ifndef RETCPCLIENT_HPP #define RETCPCLIENT_HPP +#ifndef REBASE_HPP +#include "base/rebase.hpp" +#include "math/remath.hpp" +#include "net/renet.hpp" +#endif + + class ReTCPPeer; class RplTcpClient: public QObject { diff --git a/net/ReTCPPeer.hpp b/net/ReTCPPeer.hpp index 578d196..c236037 100644 --- a/net/ReTCPPeer.hpp +++ b/net/ReTCPPeer.hpp @@ -11,6 +11,12 @@ #ifndef RPLTCPPEER_HPP #define RPLTCPPEER_HPP +#ifndef REBASE_HPP +#include "base/rebase.hpp" +#include "math/remath.hpp" +#include "net/renet.hpp" +#endif + class ReTCPPeer: public QObject { Q_OBJECT public: diff --git a/net/ReTCPServer.hpp b/net/ReTCPServer.hpp index 06c2fb8..4b9d149 100644 --- a/net/ReTCPServer.hpp +++ b/net/ReTCPServer.hpp @@ -1,6 +1,6 @@ /* * ReTCPServer.hpp - * + * * License: Public Domain * You can use and modify this file without any restriction. * Do what you want. @@ -11,6 +11,12 @@ #ifndef RPLTCPSERVER_HPP #define RPLTCPSERVER_HPP +#ifndef REBASE_HPP +#include "base/rebase.hpp" +#include "math/remath.hpp" +#include "net/renet.hpp" +#endif + // the sources generated from QT include this file directly: #ifndef RPLNET_HPP #include "renet.hpp" diff --git a/os/ReTraverser.cpp b/os/ReTraverser.cpp new file mode 100644 index 0000000..e9b4d39 --- /dev/null +++ b/os/ReTraverser.cpp @@ -0,0 +1,989 @@ +/* + * ReTraverser.cpp + * + * License: Public Domain + * You can use and modify this file without any restriction. + * Do what you want. + * No warranties and disclaimer of any damages. + * You also can use this license: http://www.wtfpl.net + * The latest sources: https://github.com/republib + */ + +#include "base/rebase.hpp" +#include "os/reos.hpp" +#if defined __WIN32__ +#include "accctrl.h" +#include "aclapi.h" +#pragma comment(lib, "advapi32.lib") +#endif + +enum { + LC_RIGHTS_AS_STRING_1 = LOC_FIRST_OF(LOC_TRAVERSER), // 50401 + LC_RIGHTS_AS_STRING_2, // 50402 + LC_RIGHTS_AS_STRING_3, // 50403 + LC_GET_PRIVILEGE_1, // 50404 + LC_GET_PRIVILEGE_2, // 50405 + LC_GET_PRIVILEGE_3, // 50406 + LC_GET_FILE_OWNER_1, // 50407 + LC_GET_FILE_OWNER_2, // 50408 +}; + +int ReDirEntryFilter::m_serialId = buildSerialId(CLASSID_DIR_ENTRY_FILTER, 1); + +/** + * Constructor. + */ +ReDirStatus_t::ReDirStatus_t(ReLogger* logger) : + m_path(), + m_fullName(), + m_passNo(0), + m_logger(logger), +#ifdef __linux__ + m_handle(NULL), + m_data(NULL) +//m_status; +#elif defined WIN32 +m_handle(INVALID_HANDLE_VALUE), +//m_data; +m_getPrivilege(true) +#endif +{ +#ifdef __linux__ + memset(&m_status, 0, sizeof m_status); +#elif defined WIN32 + memset(&m_data, 0, sizeof m_data); +#endif +} + +/** + * Returns the last access time. + * + * @return the last access time + */ +const ReFileTime_t* ReDirStatus_t::accessed() { +#ifdef __linux__ + return &(getStatus()->st_atim); +#elif defined __WIN32__ + return &m_data.ftLastAccessTime; +#endif +} + +/** + * Returns the filesize. + * + * @return the filesize + */ +ReFileSize_t ReDirStatus_t::fileSize() { +#ifdef __linux__ + return getStatus()->st_size; +#elif defined __WIN32__ + return ((int64_t) m_data.nFileSizeHigh << 32) + m_data.nFileSizeLow; +#endif +} + +/** + * Returns the file time as a string. + * + * @param buffer OUT: the file time + * @return buffer.str() (for chaining) + */ +const char* ReDirStatus_t::filetimeAsString(ReByteBuffer& buffer) { + return filetimeToString(modified(), buffer); +} + +/** + * Converts a filetime to a string. + * + * @param time the filetime to convert + * @param buffer OUT: the buffer for the string + * @return buffer.str(), e.g. "2014.01.07 02:59:43" + */ +const char* ReDirStatus_t::filetimeToString(const ReFileTime_t* time, + ReByteBuffer& buffer) { + time_t time1 = filetimeToTime(time); + struct tm* time2 = localtime(&time1); + buffer.setLength(4 + 2 * 2 + 2 * 2 + 1 + 3 * 2 + 2 * 1); + strftime(buffer.buffer(), buffer.length(), "%Y.%m.%d %H:%M:%S", time2); + return buffer.str(); +} + +/** + * Converts a filetime to a unix time (seconds since the Epoche). + * + * @param filetime the filetime to convert + * @return the count of seconds since 1.1.1970 + */ +time_t ReDirStatus_t::filetimeToTime(const ReFileTime_t* filetime) { +#ifdef __linux__ + return filetime->tv_sec; +#elif defined __WIN32__ + // 64-bit arithmetic: + LARGE_INTEGER date, adjust; + date.HighPart = filetime->dwHighDateTime; + date.LowPart = filetime->dwLowDateTime; + // 100-nanoseconds = milliseconds * 10000 + adjust.QuadPart = 11644473600000 * 10000; + // removes the diff between 1970 and 1601 + date.QuadPart -= adjust.QuadPart; + // converts back from 100-nanoseconds to seconds + time_t rc = (time_t) (date.QuadPart / 10000000); + return rc; +#endif +} + +/** + * Loads the info about the first file into the instance. + * + * @return true: success + */ +bool ReDirStatus_t::findFirst() { + bool rc = false; +#if defined __linux__ + if (m_handle != NULL) + closedir(m_handle); + m_handle = opendir(m_path.str()); + rc = m_handle != NULL && (m_data = readdir(m_handle)) != NULL; + m_status.st_ino = 0; +#elif defined __WIN32__ + if (m_handle != INVALID_HANDLE_VALUE) + FindClose(m_handle); + ReByteBuffer thePath(m_path); + thePath.append(m_path.lastChar() == '\\' ? "*" : "\\*"); + m_handle = FindFirstFileA(thePath.str(), &m_data); + rc = m_handle != INVALID_HANDLE_VALUE; +#endif + m_fullName.setLength(0); + return rc; +} + +/** + * Loads the info about the next file into the instance. + * + * @return true: success + */ +bool ReDirStatus_t::findNext() { +#if defined __linux__ + bool rc = m_handle != NULL && (m_data = readdir(m_handle)) != NULL; + m_status.st_ino = 0; +#elif defined __WIN32__ + bool rc = m_handle != INVALID_HANDLE_VALUE && FindNextFileA(m_handle, &m_data); +#endif + m_fullName.setLength(0); + return rc; +} + +/** + * Frees the resources of an instance. + */ +void ReDirStatus_t::freeEntry() { +#if defined __linux__ + if (m_handle != NULL) { + closedir(m_handle); + m_handle = NULL; + } +#elif defined __WIN32__ + if (m_handle != INVALID_HANDLE_VALUE) { + FindClose(m_handle); + m_handle = INVALID_HANDLE_VALUE; + } +#endif + m_path.setLength(0); + m_fullName.setLength(0); +} + +/** + * Returns the full filename (with path). + * + * @return the filename with path + */ +const char* ReDirStatus_t::fullName() { + if (m_fullName.length() == 0) + m_fullName.set(m_path).append(node(), -1); + return m_fullName.str(); +} + +#if defined __WIN32__ +/** Gets the name of the file owner. + * + * @param handle file handle (see CreateFile()) + * @param name OUT: the owner: [domain\\]name + * @return true: success + */ +bool ReDirStatus_t::getFileOwner(HANDLE handle, const char* file, + ReByteBuffer& name, ReLogger* logger) { + bool rc = false; + PSID pSidOwner = NULL; + PSECURITY_DESCRIPTOR pSD = NULL; + if (GetSecurityInfo(handle, SE_FILE_OBJECT, + OWNER_SECURITY_INFORMATION, &pSidOwner, NULL, NULL, NULL, &pSD) != ERROR_SUCCESS) { + if (logger != NULL) + logger->sayF(LOG_ERROR | CAT_FILE, LC_GET_FILE_OWNER_1, + "GetSecurityInfo($1): $2").arg(file).arg((int) GetLastError()).end(); + } else { + char accountName[128]; + char domainName[128]; + DWORD dwAcctName = sizeof accountName; + DWORD dwDomainName = sizeof domainName; + SID_NAME_USE eUse = SidTypeUnknown; + if (! LookupAccountSid(NULL, pSidOwner, accountName, &dwAcctName, domainName, + &dwDomainName, &eUse)) { + if (logger != NULL) + logger->sayF(LOG_ERROR | CAT_SECURITY, LC_GET_FILE_OWNER_2, + "LookupAccountSid(): $1").arg((int) GetLastError()).end(); + } else { + if (dwDomainName > 0) + name.append(domainName).appendChar('\\'); + name.append(accountName); + rc = true; + } + } + return rc; +} +#endif /* __WIN32__ */ + +#if defined __WIN32__ +/** Tries to get a privilege. + * + * @param privilege the name of the privilege, e.g. "SeBackup" + * @param logger logger for error logging + */ +bool ReDirStatus_t::getPrivilege(const char* privilege, ReLogger* logger) { + bool rc = false; + LUID luidPrivilege; + HANDLE hAccessToken; + if (! OpenProcessToken (GetCurrentProcess(), + TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hAccessToken)) { + if (logger != NULL) + logger->sayF(LOG_ERROR | CAT_FILE, LC_GET_PRIVILEGE_1, + "OpenProcessToken(): $1").arg((int) GetLastError()).end(); + } else if (! LookupPrivilegeValue (NULL, SE_BACKUP_NAME, &luidPrivilege)) { + if (logger != NULL) + logger->sayF(LOG_ERROR | CAT_FILE, LC_GET_PRIVILEGE_2, + "LookupPrivilegeValue(): $1").arg((int) GetLastError()).end(); + } else { + TOKEN_PRIVILEGES tpPrivileges; + tpPrivileges.PrivilegeCount = 1; + tpPrivileges.Privileges[0].Luid = luidPrivilege; + tpPrivileges.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; + if (AdjustTokenPrivileges (hAccessToken, FALSE, &tpPrivileges, + 0, NULL, NULL) == 0) + rc = true; + else { + int error = GetLastError(); + if (error != 1300 && logger != NULL) + logger->sayF(LOG_ERROR | CAT_FILE, LC_GET_PRIVILEGE_3, + "AdjustTokenPrivileges(): $1").arg((int) GetLastError()).end(); + } + } + return rc; +} +#endif /* __WIN32__ */ + +/** + * Tests whether the instance is a directory. + * + * @return true: instance contains the data of a directory + */ +bool ReDirStatus_t::isDirectory() { +#ifdef __linux__ + return m_data->d_type == DT_DIR + || (m_data->d_type == DT_UNKNOWN && S_ISDIR(getStatus()->st_mode)); +#elif defined __WIN32__ + return 0 != (m_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY); +#endif +} + +/** + * Tests whether the instance contains data about "." or "..". + * + * @return true: an ignorable entry has been found + */ +bool ReDirStatus_t::isDotDir() const { +#ifdef __linux__ + bool rc = m_data == NULL + || (m_data->d_name[0] == '.' + && (m_data->d_name[1] == '\0' + || (m_data->d_name[1] == '.' && m_data->d_name[2] == '\0'))); +#elif defined __WIN32__ + bool rc = m_data.cFileName[0] == '.' && (m_data.cFileName[1] == '\0' + || (m_data.cFileName[1] == '.' && m_data.cFileName[2] == '\0')); +#endif + return rc; +} + +/** + * Tests whether the instance is a symbolic link. + * + * Unter windows it tests whether the the instance is a reparse point. + * + * @return true: instance contains the data of a link + */ +bool ReDirStatus_t::isLink() { + bool rc; +#ifdef __linux__ + rc = m_data->d_type == DT_LNK + || (m_data->d_type == DT_UNKNOWN && S_ISLNK(getStatus()->st_mode)); +#elif defined __WIN32__ + rc = 0 != (m_data.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT); +#endif + return rc; +} +/** + * Tests whether the instance is a "normal" file. + * + * @return true: instance contains the data of a not special file + */ +bool ReDirStatus_t::isRegular() { +#ifdef __linux__ + return m_data->d_type == DT_REG + || (m_data->d_type == DT_UNKNOWN && S_ISREG(getStatus()->st_mode)); +#elif defined __WIN32__ + return 0 == (m_data.dwFileAttributes & (FILE_ATTRIBUTE_REPARSE_POINT | FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_DEVICE)); +#endif +} +/** + * Returns the modification time. + * + * @return the modification time + */ +const ReFileTime_t* ReDirStatus_t::modified() { +#ifdef __linux__ + return &(getStatus()->st_mtim); +#elif defined __WIN32__ + return &m_data.ftLastWriteTime; +#endif +} + +/** + * Returns the name of the current file (without path). + * + * @return the name of the current file. + */ +const char* ReDirStatus_t::node() const { +#ifdef __linux__ + return m_data->d_name; +#elif defined __WIN32__ + return m_data.cFileName; +#endif +} + +inline void addRight(int mode, ReByteBuffer& buffer) { + char right; + switch (mode & 7) { + case 1: + right = 'x'; + break; + case 2: + right = 'w'; + break; + case 3: + right = 'X'; + break; + case 4: + right = 'r'; + break; + case 5: + right = 'R'; + break; + case 6: + right = 'W'; + break; + case 7: + right = 'A'; + break; + default: + right = '-'; + break; + } + buffer.appendChar(right); +} +inline void addId(const char* id, int maxLength, ReByteBuffer& buffer) { + int length = strlen(id); + if (length == maxLength) + buffer.append(id, length); + else if (length < maxLength) + buffer.append(id, length).appendChar(' ', maxLength - length); + else { + buffer.append(id, 2); + buffer.append(id + length - maxLength - 2, maxLength - 2); + } +} +/** + * Returns the file rights as a string. + * + * @param buffer OUT: the file rights + * @param numerical true: the owner/group should be numerical (UID/GID) + * @param ownerWidth the width for group/owner + * @return buffer.str() (for chaining) + */ +const char* ReDirStatus_t::rightsAsString(ReByteBuffer& buffer, bool numerical, + int ownerWidth) { + buffer.setLength(0); +#if defined __linux__ + if (numerical) { + buffer.appendInt(getStatus()->st_mode & ALLPERMS, "%04o"); + buffer.appendInt(getStatus()->st_uid, " %4d"); + buffer.appendInt(getStatus()->st_gid, " %4d"); + } else { + int mode = getStatus()->st_mode & ALLPERMS; + addRight(mode >> 6, buffer); + addRight(mode >> 3, buffer); + addRight(mode, buffer); + buffer.appendChar(' '); + struct passwd* passwd = getpwuid(getStatus()->st_uid); + if (passwd == NULL) + buffer.appendInt(getStatus()->st_uid, "%4d"); + else + addId(passwd->pw_name, 5, buffer); + buffer.appendChar(' '); + struct group* group = getgrgid(getStatus()->st_gid); + if (group == NULL) + buffer.appendInt(getStatus()->st_gid, "%4d"); + else + addId(group->gr_name, 5, buffer); + buffer.appendChar(' '); + } +#elif defined __WIN32__ + const char* name = fullName(); + HANDLE handle = INVALID_HANDLE_VALUE; + if (! isDirectory()) { + if ( (handle = CreateFile(name, GENERIC_READ, FILE_SHARE_READ, NULL, + OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL)) == INVALID_HANDLE_VALUE) + m_logger->sayF(LOG_ERROR | CAT_FILE, LC_RIGHTS_AS_STRING_1, + "CreateFile($1): $2").arg(name).arg((int) GetLastError()).end(); + } else if (m_getPrivilege) { + // we try only one time: + m_getPrivilege = false; + if (getPrivilege(SE_BACKUP_NAME, m_logger)) { + if ( (handle = CreateFile(name, 0, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, + NULL)) != INVALID_HANDLE_VALUE) + m_logger->sayF(LOG_ERROR | CAT_FILE, LC_RIGHTS_AS_STRING_2, + "CreateFile($1): $2").arg(name).arg((int) GetLastError()).end(); + } + + } + ReByteBuffer owner; + if (handle != INVALID_HANDLE_VALUE) + getFileOwner(handle, name, owner, m_logger); + CloseHandle(handle); + buffer.appendFix(owner.str(), owner.length(), ownerWidth, ownerWidth); +#endif + return buffer.str(); +} + +/** + * Converts the unix time (time_t) to the file time. + * + * @param time the unix time (secondes since 1.1.1970) + * @param filetime OUT: the OS specific filetime + */ +void ReDirStatus_t::timeToFiletime(time_t time, ReFileTime_t& filetime) { +#ifdef __linux__ + filetime.tv_sec = time; + filetime.tv_nsec = 0; +#elif defined __WIN32__ + LONGLONG ll = Int32x32To64(time, 10000000) + 116444736000000000; + filetime.dwLowDateTime = (DWORD)ll; + filetime.dwHighDateTime = ll >> 32; +#endif +} +/** + * Returns the type of the entry. + * return the file type, e.g. TF_REGULAR + */ +ReDirStatus_t::Type_t ReDirStatus_t::type() { + Type_t rc = TF_UNDEF; +#if defined __linux__ + int flags = getStatus()->st_mode; + if (S_ISDIR(flags)) + rc = TF_SUBDIR; + else if (flags == 0 || S_ISREG(flags)) + rc = TF_REGULAR; + else if (S_ISLNK(flags)) + rc = TF_LINK; + else if (S_ISCHR(flags)) + rc = TF_CHAR; + else if (S_ISBLK(flags)) + rc = TF_BLOCK; + else if (S_ISFIFO(flags)) + rc = TF_PIPE; + else if (S_ISSOCK(flags)) + rc = TF_SOCKET; + else + rc = TF_OTHER; +#elif defined __WIN32__ + int flags = (m_data.dwFileAttributes & ~(FILE_ATTRIBUTE_READONLY + | FILE_ATTRIBUTE_HIDDEN + | FILE_ATTRIBUTE_SYSTEM + | FILE_ATTRIBUTE_ARCHIVE + | FILE_ATTRIBUTE_NORMAL + | FILE_ATTRIBUTE_TEMPORARY + | FILE_ATTRIBUTE_SPARSE_FILE + | FILE_ATTRIBUTE_COMPRESSED + | FILE_ATTRIBUTE_NOT_CONTENT_INDEXED + | FILE_ATTRIBUTE_ENCRYPTED + | FILE_ATTRIBUTE_HIDDEN)); + + if (0 == flags) + rc = TF_REGULAR; + else if (0 != (m_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) { + rc = (0 != (m_data.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT)) + ? TF_LINK_DIR : TF_SUBDIR; + } else if (0 != (m_data.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT)) + rc = TF_LINK; + else + rc = TF_OTHER; +#endif + return rc; +} + +/** + * Returns the filetype as a single character. + * + * @return the filetype, e.g. 'd' for a directory + */ +char ReDirStatus_t::typeAsChar() { + char rc = ' '; + switch (type()) { + case TF_REGULAR: + rc = ' '; + break; + case TF_LINK: + rc = 'l'; + break; + case TF_SUBDIR: + rc = 'd'; + break; + case TF_CHAR: + rc = 'c'; + break; + case TF_BLOCK: + rc = 'b'; + break; + case TF_PIPE: + rc = 'p'; + break; + case TF_SOCKET: + rc = 's'; + break; + default: + rc = 'o'; + break; + } + return rc; +} +/** + * Constructor. + */ +ReDirEntryFilter::ReDirEntryFilter() : + ReSerializable(m_serialId), + m_types(ReDirStatus_t::TC_ALL), + m_nodePatterns(NULL), + m_pathPatterns(NULL), + m_minSize(0), + m_maxSize(-1), + //m_minAge(0), + //m_maxAge(0), + m_minDepth(0), + m_maxDepth(512), + m_allDirectories(false) { + setFiletimeUndef(m_minAge); + setFiletimeUndef(m_maxAge); +} + +/** + * Destructor. + */ +ReDirEntryFilter::~ReDirEntryFilter() { +} + +/** + * Sets the members of the instance from a byte sequence. + * + * @param sequence IN/OUT: the serialized byte sequence + * @param length INT/OUT the length of sequence + */ +void ReDirEntryFilter::deserialize(const uint8_t*& sequence, size_t& length) { + int id; + unpackInt24(sequence, length, id); + if (id != m_serialId) + throw ReSerializeFormatException("wrong serialId", this); + ReByteBuffer buffer; + unpackString64k(sequence, length, buffer); + bool ignoreCase; + unpackBool(sequence, length, ignoreCase); + m_nodePatterns->set(buffer.str(), ignoreCase); + unpackString64k(sequence, length, buffer); + unpackBool(sequence, length, ignoreCase); + unpackString64k(sequence, length, buffer); + m_pathPatterns->set(buffer.str(), ignoreCase); + unpackInt64(sequence, length, m_minSize); + unpackInt64(sequence, length, m_maxSize); + int64_t value; + unpackInt64(sequence, length, value); + unpackBool(sequence, length, m_allDirectories); +} +/** + * Packs the members into a byte sequence. + * + * @param sequence IN/OUT: the place for the byte sequence + */ +ReByteBuffer& ReDirEntryFilter::serialize(ReByteBuffer& sequence) { + sequence.appendBits24(m_serialId); + packString64k(sequence, m_nodePatterns->patternString()); + packBool(sequence, m_nodePatterns->ignoreCase()); + packString64k(sequence, m_pathPatterns->patternString()); + packBool(sequence, m_pathPatterns->ignoreCase()); + sequence.appendBits64(m_minSize); + sequence.appendBits64(m_maxSize); + uint64_t value; +#if defined __linux__ + value = (m_minAge.tv_sec << 32) + m_minAge.tv_nsec; + sequence.appendBits64(int64_t(value)); + value = (m_minAge.tv_sec << 32) + m_minAge.tv_nsec; +#elif defined __WIN32__ +#error "missing impl" +#endif + sequence.appendBits64(int64_t(value)); + packBool(sequence, m_allDirectories); +} + +/** + * Tests whether an entry matches the conditions of the filter. + * + * @param entry entry to test + * @return : the entry matches the conditions of the filter
+ * : otherwise + */ +bool ReDirEntryFilter::match(ReDirStatus_t& entry) { + bool rc = false; + do { + if (m_allDirectories && entry.isDirectory()) { + rc = true; + break; + } + if (0 == (entry.type() & m_types)) + break; + int64_t size = entry.fileSize(); + if (m_minSize > 0 && size < m_minSize) + break; + if (m_maxSize >= 0 && size > m_maxSize) + break; + if (!filetimeIsUndefined(m_minAge) && *entry.modified() > m_minAge) + break; + if (!filetimeIsUndefined(m_maxAge) && m_maxAge > *entry.modified()) + break; + const char* node = entry.node(); + if (m_nodePatterns != NULL && !m_nodePatterns->match(node)) + break; + rc = true; + } while (false); + return rc; +} +; + +#ifdef __linux__ +/** + * Returns the status of the current file (lazy loading). + * + * @return the status of the current file + */ +struct stat* ReDirStatus_t::getStatus() { + if (m_status.st_ino == 0) { + if (stat(fullName(), &m_status) != 0) + m_status.st_ino = 0; + } + return &m_status; +} +#endif + +/** + * Constructor. + */ +ReDirTreeStatistic::ReDirTreeStatistic() : + m_directories(0), + m_files(0), + m_sizes(0ll) { +} +/** + * Builds a string describing the data. + * + * @param buffer IN/OUT: a buffer for the result + * @param append true: the string will be appended to the buffer
+ * false: the buffer will be cleared at the beginning + * @param formatFiles the sprintf format for the file count, e.g. "%8d" + * @param formatSized the sprintf format for the MByte format, e.g. "%12.6f" + * @param formatFiles the sprintf format for the directory count, e.g. "%6d" + * @return a human readable string + */ +const char* ReDirTreeStatistic::statisticAsString(ReByteBuffer& buffer, + bool append, const char* formatFiles, const char* formatSizes, + const char* formatDirs) { + if (!append) + buffer.setLength(0); + buffer.appendInt(m_files, formatFiles); + buffer.append(i18n("file(s)")).appendChar(' '); + buffer.append(m_sizes / 1000.0 / 1000, formatSizes); + buffer.append(" ", 1).append(i18n("MByte")).appendChar(' '); + buffer.appendInt(m_directories, formatDirs); + buffer.append(i18n("dirs(s)")); + return buffer.str(); +} + +/** + * Constructor. + * + * @param triggerCount efficiency: only every N calls a time check takes place + * @param interval the minimum number of seconds between two traces + */ +ReTraceUnit::ReTraceUnit(int triggerCount, int interval) : + m_count(0), + m_triggerCount(triggerCount), + m_lastTrace(0), + m_interval(interval), + m_startTime(time(NULL)) { + m_lastTrace = m_startTime; +} +/** + * Destructor. + */ +ReTraceUnit::~ReTraceUnit() { +} + +/** + * Prints a message. + * + * Often overwritten by a subclass. + * + * @param message message for the trace + * @return true (for chaining) + */ +bool ReTraceUnit::trace(const char* message) { + printf("%s\n", message); + return true; +} + +/** + * Constructor. + * + * @param base the base directory. The traversal starts at this point + */ +ReTraverser::ReTraverser(const char* base, ReTraceUnit* tracer, + ReLogger* logger) : + ReDirTreeStatistic(), + m_minLevel(0), + m_maxLevel(512), + m_level(-1), + m_base(base), + // m_dirs + m_passNoForDirSearch(2), + m_dirPatterns(NULL), + m_tracer(tracer), + m_logger(logger) { + memset(m_dirs, 0, sizeof m_dirs); + m_dirs[0] = new ReDirStatus_t(m_logger); + // remove a preceeding "./". This simplifies the pattern expressions: + if (m_base.startsWith( + ReByteBuffer(".").appendChar(OS_SEPARATOR_CHAR).str())) { + m_base.remove(0, 2); + } +} + +/** + * Destructor. + */ +ReTraverser::~ReTraverser() { + destroy(); +} + +/** + * Initializes the instance to process a new base. + * + * @param base the base directory to search + */ +void ReTraverser::changeBase(const char* base) { + destroy(); + m_base.setLength(0).append(base); + memset(m_dirs, 0, sizeof m_dirs); + m_dirs[0] = new ReDirStatus_t(m_logger); + // remove a preceeding "./". This simplifies the pattern expressions: + if (m_base.startsWith( + ReByteBuffer(".").appendChar(OS_SEPARATOR_CHAR).str())) { + m_base.remove(0, 2); + } +} + +/** + * Releases the resources. + */ +void ReTraverser::destroy() { + for (size_t ix = 0; ix < sizeof m_dirs / sizeof m_dirs[0]; ix++) { + if (m_dirs[ix] != NULL) { + m_dirs[ix]->freeEntry(); + delete m_dirs[ix]; + m_dirs[ix] = NULL; + } + } +} +/** + * Returns the info about the next file in the directory tree traversal. + * + * @param level OUT: the level relative to the base.
+ * 0 means the file is inside the base.
+ * Not defined if the result is NULL + * @return NULL no more files
+ * otherwise: the stack entry with the next file in the + * directory tree. May be a directory too + */ +ReDirStatus_t* ReTraverser::rawNextFile(int& level) { + ReDirStatus_t* rc = NULL; + bool alreadyRead = false; + bool again; + do { + again = false; + if (m_level < 0) { + // Not yet initialized? + if (m_dirs[0]->m_passNo == 2) + rc = NULL; + else { + // first call: + if (initEntry(m_base.str(), NULL, 0)) { + m_directories++; + if (1 != m_passNoForDirSearch) + rc = m_dirs[0]; + else + again = alreadyRead = true; + } + } + } else { + ReDirStatus_t* current = m_dirs[m_level]; + if (alreadyRead || current->findNext()) { + alreadyRead = false; + // a file or directory found: + if (m_tracer != NULL && m_tracer->isCountTriggered() + && m_tracer->isTimeTriggered()) + m_tracer->trace(current->fullName()); + if (current->m_passNo != m_passNoForDirSearch) { + // we search for any file: + rc = m_dirs[m_level]; + } else { + // we are interested only in true subdirectories: + again = true; + if (m_level < m_maxLevel && current->isDirectory() + && !current->isDotDir() && !current->isLink() + && (m_dirPatterns == NULL + || isAllowedDir(current->node()))) { + // open a new level + alreadyRead = initEntry(current->m_path, + current->node(), m_level + 1); + m_directories++; + } + } + } else { + // the current subdir does not have more files: + if (current->m_passNo == 1) { + // we start the second pass: + alreadyRead = initEntry(current->m_path, NULL, -1); + current->m_passNo = 2; + again = true; + } else { + // this subdirectory is complete. We continue in the parent directory: + current->freeEntry(); + if (--m_level >= 0) { + again = true; + } + } + } + } + if (rc != NULL && rc->isDotDir()) + again = true; + } while (again); + if (rc != NULL && !rc->isDirectory()) { + m_files++; + if (m_sizes >= 0) + m_sizes += rc->fileSize(); + } + level = m_level; + return rc; +} +/** + * Returns the info about the next file matching the filter options. + * + * @param level OUT: the level relative to the base.
+ * 0 means the file is inside the base.
+ * Not defined if the result is NULL + * @param filter NULL: every file matches
+ * otherwise: each found file must match this filter conditions + * @return NULL no more files
+ * otherwise: the info about the next file in the + * directory tree + */ +ReDirStatus_t* ReTraverser::nextFile(int& level, ReDirEntryFilter* filter) { + ReDirStatus_t* rc = rawNextFile(level); + while (rc != NULL) { + if (filter == NULL || filter->match(*rc)) { + break; + } + rc = rawNextFile(level); + } + return rc; +} + +/** + * Initializes an entry in the directory entry stack. + * + * @param parent the parent directory of the entry + * @param node the name of the directory belonging to the entry (without path) + * @param level the index of the entry in the stack.
+ * If < 0: m_levels and m_path will not be changed + * @return true: a new file is available
+ * false/code>: findFirstEntry() signals: no entry. + */ +bool ReTraverser::initEntry(const ReByteBuffer& parent, const char* node, + int level) { + bool rc = false; + if (level < MAX_ENTRY_STACK_DEPTH) { + if (level >= 0) + m_level = level; + if (m_dirs[m_level] == NULL) + m_dirs[m_level] = new ReDirStatus_t(m_logger); + ReDirStatus_t* current = m_dirs[m_level]; + current->m_passNo = 1; + if (level >= 0) { + current->m_path.set(parent.str(), parent.length()); + if (!parent.endsWith(OS_SEPARATOR)) + current->m_path.append(OS_SEPARATOR); + if (node != NULL) + current->m_path.append(node).append(OS_SEPARATOR); + } + rc = current->findFirst(); + } + return rc; +} + +/** + * Sets some properties from a filter. + * + * @param filter the filter with the properties to set + */ +void ReTraverser::setPropertiesFromFilter(ReDirEntryFilter* filter) { + m_minLevel = filter->m_minDepth; + m_maxLevel = filter->m_maxDepth; + setDirPattern(filter->m_pathPatterns); +} + +/** + * Returns the info of an entry the directory stack. + * + * @param offsetFromTop 0: return the top of stack
+ * 1: returns the entry one below the top
+ * 2: ... + * @return NULL: not available
+ * otherwise: the wanted entry + */ +ReDirStatus_t* ReTraverser::topOfStack(int offsetFromTop) { + ReDirStatus_t* rc = NULL; + if (offsetFromTop >= 0 && m_level - 1 - offsetFromTop >= 0) + rc = m_dirs[m_level - 1 - offsetFromTop]; + return rc; +} diff --git a/os/ReTraverser.hpp b/os/ReTraverser.hpp new file mode 100644 index 0000000..241b913 --- /dev/null +++ b/os/ReTraverser.hpp @@ -0,0 +1,290 @@ +/* + * ReTraverser.hpp + * + * License: Public Domain + * You can use and modify this file without any restriction. + * Do what you want. + * No warranties and disclaimer of any damages. + * You also can use this license: http://www.wtfpl.net + * The latest sources: https://github.com/republib + */ + +#ifndef OS_RETRAVERSER_HPP_ +#define OS_RETRAVERSER_HPP_ + +#include "string/ReMatcher.hpp" +#ifdef __linux__ +#include +#include + +typedef DIR* FindFileHandle_t; +#endif +/** Returns whether a filetime is undefined. + * @param time the filetime to test + * @return true: the given filetime is undefined + */ +inline bool filetimeIsUndefined(ReFileTime_t& time) { +#if defined __linux__ + return time.tv_sec == 0 && time.tv_nsec == 0; +#elif defined __WIN32__ + return time.dwHighDateTime == 0 && time.dwLowDateTime == 0; +#endif +} +/** Sets the filetime to undefined. + * @param time the filetime to clear + */ +inline void setFiletimeUndef(ReFileTime_t& time) { +#if defined __linux__ + time.tv_sec = time.tv_nsec = 0; +#elif defined __WIN32__ + time.dwHighDateTime = time.dwLowDateTime = 0; +#endif +} + +class ReDirStatus_t { +public: + enum Type_t { + TF_UNDEF = 0, + // single property flags: + TF_SUBDIR = 1 << 0, + TF_REGULAR = 1 << 1, + TF_LINK = 1 << 2, + TF_LINK_DIR = 1 << 3, + TF_BLOCK = 1 << 4, + TF_PIPE = 1 << 5, + TF_CHAR = 1 << 6, + TF_SOCKET = 1 << 7, + TF_OTHER = 1 << 8, + // collections: + TC_SPECIAL = (TF_BLOCK | TF_CHAR | TF_SOCKET | TF_PIPE | TF_OTHER), + TC_NON_DIR = (TC_SPECIAL | TF_LINK | TF_REGULAR), + TC_ALL = (TF_SUBDIR | TC_NON_DIR | TF_LINK_DIR) + }; + +public: + ReDirStatus_t(ReLogger* logger); +public: + const ReFileTime_t* accessed(); + ReFileSize_t fileSize(); + const char* filetimeAsString(ReByteBuffer& buffer); + bool findFirst(); + bool findNext(); + void freeEntry(); + const char* fullName(); + bool isDirectory(); + bool isDotDir() const; + bool isLink(); + bool isRegular(); + const ReFileTime_t* modified(); + const char* node() const; + const char* rightsAsString(ReByteBuffer& buffer, bool numerical, + int ownerWidth); + Type_t type(); + char typeAsChar(); +public: + static const char* filetimeToString(const ReFileTime_t* time, + ReByteBuffer& buffer); + static time_t filetimeToTime(const ReFileTime_t* time); +#if defined __WIN32__ + static bool getFileOwner(HANDLE handle, const char* file, ReByteBuffer& name, + ReLogger* logger = NULL); + static bool getPrivilege(const char* privilege, ReLogger* logger); +#endif + static void timeToFiletime(time_t time, ReFileTime_t& filetime); +public: + ReByteBuffer m_path; + ReByteBuffer m_fullName; + int m_passNo; + ReLogger* m_logger; +#ifdef __linux__ + DIR* m_handle; + struct dirent* m_data; + struct stat m_status; +public: + struct stat* getStatus(); +#elif defined WIN32 + HANDLE m_handle; + WIN32_FIND_DATAA m_data; + bool m_getPrivilege; +#endif +}; +class ReDirEntryFilter: public ReSerializable { +public: + ReDirEntryFilter(); + ~ReDirEntryFilter(); +public: + virtual void deserialize(const uint8_t*& sequence, size_t& length); + bool match(ReDirStatus_t& entry); + virtual ReByteBuffer& serialize(ReByteBuffer& sequence); +public: + ReDirStatus_t::Type_t m_types; + RePatternList* m_nodePatterns; + RePatternList* m_pathPatterns; + ReFileSize_t m_minSize; + ReFileSize_t m_maxSize; + ReFileTime_t m_minAge; + ReFileTime_t m_maxAge; + int m_minDepth; + int m_maxDepth; + bool m_allDirectories; +private: + static int m_serialId; +}; + +class ReTraceUnit { +public: + ReTraceUnit(int m_triggerCount = 10, int interval = 60); + virtual ~ReTraceUnit(); +public: + /** Returns whether the the instance is triggered. + * To avoid too the not cheap call of time() the trace unit uses a counter. + * If the counter reaches a given level the time check should be done. + * @return true: the counter has reached m_triggerCount + */ + inline bool isCountTriggered() { + bool rc = ++m_count % m_triggerCount == 0; + return rc; + } + /** Tests whether a given waiting time has been gone since the last trace. + * @return true: the last trace has been done after + * at least m_interval seconds + */ + inline bool isTimeTriggered() { + time_t now = time(NULL); + bool rc = now - m_lastTrace > m_interval; + if (rc) { + m_lastTrace = now; + } + return rc; + } + virtual bool trace(const char* message); +protected: + int m_count; + int m_triggerCount; + time_t m_lastTrace; + int m_interval; + time_t m_startTime; +}; + +class ReDirTreeStatistic { +public: + ReDirTreeStatistic(); +public: + const char* statisticAsString(ReByteBuffer& buffer, bool append = false, + const char* formatFiles = "%8d ", const char* formatSizes = "%12.6f", + const char* formatDirs = "%7d "); + /** + * Resets the counters. + */ + inline void clear() { + m_files = m_directories = 0; + m_sizes = 0ll; + } +public: + int m_directories; + int m_files; + int64_t m_sizes; +}; + +#define MAX_ENTRY_STACK_DEPTH 256 +class ReTraverser: public ReDirTreeStatistic { +public: + ReTraverser(const char* base, ReTraceUnit* tracer = NULL, ReLogger* logger = + NULL); + virtual ~ReTraverser(); +public: + void changeBase(const char* base); + /** + * Return the number of entered directories . + * @return the number of directories entered until now + */ + inline int directories() const { + return m_directories; + } + /** + * Return the number of found files. + * @return the number of files found until now + */ + inline int files() const { + return m_files; + } + /** Returns whether the current directory has changed since the last call. + * @param state IN/OUT: stored info about the current directory. + * The value has no interest for the caller + * @return true: the path has been changed + */ + inline bool hasChangedPath(int& state) { + bool rc = m_directories > state; + state = m_directories; + return rc; + } + ReDirStatus_t* rawNextFile(int& level); + ReDirStatus_t* nextFile(int& level, ReDirEntryFilter* filter = NULL); + /** Sets the tree traversal algorithm. + * @param depthFirst true: files of the subdirectories will + * be returned earlier + */ + void setDepthFirst(bool depthFirst) { + m_passNoForDirSearch = depthFirst ? 1 : 2; + } + /** Sets directory filter (pattern list). + * @param pattern pattern list for the subdirs to be entered + */ + inline void setDirPattern(RePatternList* pattern) { + m_dirPatterns = pattern; + if (pattern != NULL) + m_dirPatterns->setIgnoreCase(true); + } + /** Sets the maximal depth. + * @param value the value to set + */ + inline void setMaxLevel(int value) { + m_maxLevel = value; + } + /** Sets the minimal depth. + * @param value the value to set + */ + inline void setMinLevel(int value) { + m_minLevel = value; + } + void setPropertiesFromFilter(ReDirEntryFilter* filter); + /** + * Return the sum of file lengths of the found files. + * @return the sum of file lengths of the files found until now + */ + inline int64_t sizes() const { + return m_sizes; + } + ReDirStatus_t* topOfStack(int offset = 0); +protected: + void destroy(); + void freeEntry(int level); + bool initEntry(const ReByteBuffer& parent, const char* node, int level); + /** + * Tests whether a directory should be processed. + * @param node the base name of the subdir + * @return true: the subdir will be processed
+ * false: do not enter this subdir + */ + inline bool isAllowedDir(const char* node) { + bool rc = m_dirPatterns->match(node); + return rc; + } +protected: + int m_minLevel; + int m_maxLevel; + int m_level; + ReByteBuffer m_base; + ReDirStatus_t* m_dirs[MAX_ENTRY_STACK_DEPTH]; + /// each directory will be passed twice: for all files + for directories only + /// 1: depth first 2: breadth first + int m_passNoForDirSearch; + /// a subdirectory will be entered only if this pattern list matches + /// if NULL any directory will be entered + RePatternList* m_dirPatterns; + ReDirTreeStatistic m_statistic; + ReTraceUnit* m_tracer; + ReLogger* m_logger; +}; + +#endif /* OS_RETRAVERSER_HPP_ */ diff --git a/os/reos.hpp b/os/reos.hpp new file mode 100644 index 0000000..342a9f1 --- /dev/null +++ b/os/reos.hpp @@ -0,0 +1,48 @@ +/* + * reos.hpp + * + * License: Public Domain + * You can use and modify this file without any restriction. + * Do what you want. + * No warranties and disclaimer of any damages. + * You also can use this license: http://www.wtfpl.net + * The latest sources: https://github.com/republib + */ + +#ifndef OS_REOS_HPP_ +#define OS_REOS_HPP_ + +#if defined __linux__ +#include "unistd.h" +#include +#include +#include +#elif defined __WIN32__ +#include +#include "windows.h" +#include +#else +#error "unknown os" +#endif + +/** Returns whether a time is greater (younger) than another. + * @param time1 first operand + * @param time2 second operand + * @return true: time1 > time2 + */ +inline bool operator >(const ReFileTime_t& time1, const ReFileTime_t& time2) { +#if defined __linux__ + return time1.tv_sec > time2.tv_sec + || (time1.tv_sec == time2.tv_sec && time1.tv_nsec > time2.tv_nsec); +#else + return time1.dwHighDateTime > time2.dwHighDateTime + || (time1.dwHighDateTime == time2.dwHighDateTime + && time1.dwLowDateTime > time2.dwLowDateTime); +#endif +} +#include "os/ReTraverser.hpp" +#include "os/ReDirTools.hpp" +#include "net/renet.hpp" +#include "os/ReRemoteDir.hpp" + +#endif /* OS_REOS_HPP_ */ diff --git a/remodules.hpp b/remodules.hpp index ea53cad..ecc71cc 100644 --- a/remodules.hpp +++ b/remodules.hpp @@ -1,6 +1,6 @@ /* * remodules.hpp - * + * * License: Public Domain * You can use and modify this file without any restriction. * Do what you want. @@ -23,6 +23,7 @@ enum { LOC_SOURCE, LOC_VM, LOC_MFPARSER, // 115 + LOC_TRAVERSER, }; #define LOC_FIRST_OF(moduleNo) (moduleNo*100+1) class RplModules { diff --git a/static/ReStaticLib.cpp b/static/ReStaticLib.cpp new file mode 100644 index 0000000..487cb56 --- /dev/null +++ b/static/ReStaticLib.cpp @@ -0,0 +1,16 @@ +/* + * rplstaticlib.cpp + * + * License: Public Domain + * You can use and modify this file without any restriction. + * Do what you want. + * No warranties and disclaimer of any damages. + * You also can use this license: http://www.wtfpl.net + * The latest sources: https://github.com/republib + */ + + +int main(int argc, char** argv){ + void allTests(); + allTests(); +} diff --git a/static/rplstatic.pro b/static/rplstatic.pro index 82c9e9b..1ab5aa3 100644 --- a/static/rplstatic.pro +++ b/static/rplstatic.pro @@ -8,9 +8,9 @@ QT += network testlib QT -= gui -TARGET = rplstatic -TEMPLATE = lib -CONFIG += staticlib +TARGET = ReStaticLib +#TEMPLATE = lib +#CONFIG += staticlib INCLUDEPATH = .. /usr/include/c++/4.9 @@ -22,6 +22,9 @@ SOURCES += \ ../base/ReStringUtil.cpp \ ../base/ReTerminator.cpp \ ../base/ReTest.cpp \ + ../base/ReByteStorage.cpp \ + ../base/ReWriter.cpp \ + ../base/ReCharPtrMap.cpp \ ../math/ReEnigma.cpp \ ../math/ReMatrix.cpp \ ../math/ReRandom.cpp \ @@ -31,15 +34,31 @@ SOURCES += \ ../net/ReTCPServer.cpp \ ../expr/ReLexer.cpp \ ../expr/ReSource.cpp \ - ../base/ReQString.cpp \ + ../base/ReQStringUtil.cpp \ ../expr/ReASTree.cpp \ ../expr/ReASClasses.cpp \ ../expr/ReMFParser.cpp \ ../expr/ReVM.cpp \ ../expr/ReParser.cpp \ - ../base/ReByteStorage.cpp \ - ../base/ReWriter.cpp \ - ../base/ReCharPtrMap.cpp + ../bench/cppbench.cpp \ + ../cunit/cuReConfig.cpp \ + ../cunit/cuReContainer.cpp \ + ../cunit/cuReEnigma.cpp \ + ../cunit/cuReASTree.cpp \ + ../cunit/cuReBench.cpp \ + ../cunit/cuReByteStorage.cpp \ + ../cunit/cuReCharPtrMap.cpp \ + ../cunit/cuReException.cpp \ + ../cunit/cuReLexer.cpp \ + ../cunit/cuReMatrix.cpp \ + ../cunit/cuReQStringUtil.cpp \ + ../cunit/cuReSource.cpp \ + ../cunit/cuReStringUtil.cpp \ + ../cunit/cuReVM.cpp \ + ../cunit/cuReWriter.cpp \ + ../cunit/allTests.cpp \ + ReStaticLib.cpp \ + ../cunit/cuReMFParser.cpp HEADERS += ../remodules.hpp \ ../base/ReConfig.hpp \ @@ -63,7 +82,7 @@ HEADERS += ../remodules.hpp \ ../expr/ReLexer.hpp \ ../expr/reexpr.hpp \ ../expr/ReSource.hpp \ - ../base/ReQString.hpp \ + ../base/ReQStringUtil.hpp \ ../expr/ReASTree.hpp \ ../expr/ReASClasses.hpp \ ../expr/ReMFParser.hpp \ @@ -71,7 +90,8 @@ HEADERS += ../remodules.hpp \ ../expr/ReParser.hpp \ ../base/ReByteStorage.hpp \ ../base/ReWriter.hpp \ - ../base/ReCharPtrMap.hpp + ../base/ReCharPtrMap.hpp \ + ../base/ReQStringUtil.hpp unix:!symbian { maemo5 { diff --git a/static/rplstaticlib.cpp b/static/rplstaticlib.cpp deleted file mode 100644 index 0dc5255..0000000 --- a/static/rplstaticlib.cpp +++ /dev/null @@ -1,18 +0,0 @@ -/* - * rplstaticlib.cpp - * - * License: Public Domain - * You can use and modify this file without any restriction. - * Do what you want. - * No warranties and disclaimer of any damages. - * You also can use this license: http://www.wtfpl.net - * The latest sources: https://github.com/republib - */ - - -#include "../static/rplstaticlib.hpp" - - -RplStaticLib::RplStaticLib() -{ -} diff --git a/static/rplstaticlib.hpp b/static/rplstaticlib.hpp deleted file mode 100644 index ce4f2e3..0000000 --- a/static/rplstaticlib.hpp +++ /dev/null @@ -1,24 +0,0 @@ -/* - * rplstaticlib.hpp - * - * License: Public Domain - * You can use and modify this file without any restriction. - * Do what you want. - * No warranties and disclaimer of any damages. - * You also can use this license: http://www.wtfpl.net - * The latest sources: https://github.com/republib - */ - - -#ifndef RPLSTATICLIB_HPP -#define RPLSTATICLIB_HPP - - -class RplStaticLib -{ - -public: - RplStaticLib(); -}; - -#endif // RPLSTATICLIB_HPP