* This is a class with static members only.
*/
+/**
+ * @brief Counts the occurrences of a given char in a string.
+ *
+ * @param line the text to inspect
+ * @param cc the char to count
+ * @return the number of <code>cc</code> in the text
+ */
+int RplString::countChar(const char* line, char cc)
+{
+ const char* ptr = line;
+ int rc = 0;
+ while( (ptr = strchr(ptr, cc)) != NULL){
+ rc++;
+ ptr++;
+ }
+ return rc;
+}
/**
* Counts the occurrences of a string in a string.
*
}
return fp != NULL;
}
-
-// ------------------
-#if ! defined RPL_TEST
-#define RPL_TEST
-#endif
-#ifdef RPL_TEST
-#include "rplcore/rpltest.hpp"
/**
- * @brief Unit test for <code>RplString</code>.
+ * @brief Returns the length of the number string.
+ *
+ * @param text a text to inspect
+ * @param skipTrailingSpaces true: if spaces are behind the number
+ * the result contains the length of these
+ * @return 0: not a number<br>
+ * otherwise: the length of the number string
*/
-class TestRplString : public RplTest {
-public:
- TestRplString() : RplTest("RplString") {}
-
-public:
- void testCount() {
- checkE(0, RplString::count("abc", " "));
- checkE(1, RplString::count("abc", "b"));
- checkE(2, RplString::count("axx", "x"));
-
- checkE(0, RplString::count("abbc", "bbb"));
- checkE(1, RplString::count("\n\n", "\n\n"));
- checkE(2, RplString::count(" a ", " "));
+int RplString::lengthOfNumber(const char* text, bool skipTrailingSpaces){
+ int rc = 0;
+ bool found = false;
+ const char* ptr = text;
+ while(isspace(*ptr))
+ ptr++;
+ if ( (*ptr == '+' || *ptr == '-'))
+ ptr++;
+ found = isdigit(*ptr);
+ while(isdigit(*ptr)){
+ ptr++;
}
-
- void testCutString() {
- QByteArray source("123");
- QByteArray buffer;
- checkE(QByteArray("123"), RplString::cutString(source, 4, buffer));
- checkE(QByteArray("123"), RplString::cutString(source, 3, buffer));
- checkE(QByteArray("12..."), RplString::cutString(source, 2, buffer));
- checkE(QByteArray("12"), RplString::cutString(source, 2, buffer, ""));
+ if (*ptr == '.'){
+ ptr++;
+ if (isdigit(*ptr)){
+ found = true;
+ while(isdigit(*ptr))
+ ptr++;
+ }
}
-
- void testHexDump() {
- QByteArray data("abc123\nxyz");
- checkE(QByteArray("61 62 63 31 abc1\n"
- "32 33 0a 78 23.x\n"
- "79 7a yz\n"),
- RplString::hexDump((uint8_t*) data.constData(), data.length(), 4));
- checkE(QByteArray("61 62 63 31 32 33 0a 78 79 7a abc123.xyz"),
- RplString::hexDump((uint8_t*) data.constData(), data.length(), 10));
- checkE(QByteArray("61 62 63 31 32 33 0a 78 79 7a abc123.xyz"),
- RplString::hexDump((uint8_t*) data.constData(), data.length(), 12));
+ if (found && toupper(*ptr) == 'E'){
+ const char* ptrToE = ptr;
+ ptr++;
+ if (*ptr == '+' || *ptr == '-')
+ ptr++;
+ if (! isdigit(*ptr))
+ ptr = ptrToE;
+ else {
+ while(isdigit(*ptr))
+ ptr++;
+ }
}
-
- void testReadWrite() {
- QByteArray fn = getTempFile("test.dat");
- const char* content = "Hello world\nLine2\n";
- checkT(RplString::write(fn, content));
- checkE(content, RplString::read(fn, false));
- checkE(content, RplString::read(fn, true) + "\n");
+ if (found && skipTrailingSpaces){
+ while(isspace(*ptr)){
+ ptr++;
+ }
}
+ rc = ! found ? 0 : ptr - text;
+ return rc;
+}
+/**
+ * @brief Adds the count of the possible separators.
+ *
+ * @param countCommas IN/OUT: number of ','
+ * @param countSemicolons IN/OUT: number of ';'
+ * @param countPipes IN/OUT: number of '|'
+ * @param countBlanks IN/OUT: number of ' '
+ */
+static void addSeparators(const char* line, int& commas, int& semicolons,
+ int& pipes, int& blanks)
+{
+ commas += RplString::countChar(line, ',');
+ semicolons += RplString::countChar(line, ';');
+ pipes += RplString::countChar(line, '|');
+ blanks += RplString::countChar(line, ' ');
+}
- void testToArray() {
- QVector<QByteArray> array = RplString::toArray("1 abc 3", " ");
- checkE(3, array.size());
- checkE("1", array.at(0));
- checkE("abc", array.at(1));
- checkE("3", array.at(2));
+/**
+ * @brief Finds the separator of the CSV file.
+ *
+ * If the file contain TABs the result is TAB.
+ * If not:
+ * Inspects the first 5 lines and counts the possible separators.
+ * The most found separator will be returned.
+ *
+ * @param fp CSV file
+ * @param buffer a line buffer
+ * @param bufferSize the size of <code>buffer[]</code>
+ */
+char RplString::findCsvSeparator(FILE* fp, char* buffer, size_t bufferSize){
+ char rc = '\0';
+ int lineNo = 0;
+ int maxLines = 5;
+ const char* line;
+ int commas = 0;
+ int semicolons = 0;
+ int pipes = 0;
+ int blanks = 0;
+ while(++lineNo < maxLines && (line = fgets(buffer, bufferSize, fp)) != NULL){
+ if (strchr(line, '\t') != NULL){
+ rc = '\t';
+ break;
+ }
+ addSeparators(line, commas, semicolons, pipes, blanks);
}
-
- void testToNumber() {
- checkE("3", RplString::toNumber(3));
- checkE("-33", RplString::toNumber(-33));
- checkE("003", RplString::toNumber(3, "%03d"));
+ fseek(fp, 0, SEEK_SET);
+ if (rc != '\t'){
+ if (semicolons > 0 && commas > 0){
+ // if ',' is decimal separator and ';' is the column separator:
+ // Add one semicolon per line because of number of values is
+ // 1 greater than the number of separators
+ semicolons += lineNo;
+ }
+ if (commas + semicolons + pipes == 0) {
+ rc = blanks > 0 ? ' ' : '\0';
+ } else if (semicolons >= commas && semicolons >= pipes)
+ rc = ';';
+ else if (commas > semicolons && commas > pipes)
+ rc = ',';
+ else if (pipes > commas && pipes > semicolons)
+ rc = '|';
}
+ return rc;
+}
- virtual void doIt() {
- testCount();
- testCutString();
- testToNumber();
- testToArray();
- testHexDump();
- testReadWrite();
- }
-};
-#endif
-void testRplString() {
-#ifdef RPL_TEST
- TestRplString test;
-#endif
-}
class RplString {
public:
+ static int countChar(const char* line, char cc);
static int count(const char* source, const char* item);
static const QByteArray& cutString(const QByteArray& source, int maxLength,
QByteArray& buffer, const char* appendix = "...");
static QVector<QByteArray> toArray(const char* source, const char* separator);
static QByteArray toCString(const char* source, int maxLength = -1);
static QByteArray toNumber(int value, const char* format = "%d");
+ static int lengthOfNumber(const char* text, bool skipTrailingSpaces = false);
+ static char findCsvSeparator(FILE* fp, char* buffer, size_t bufferSize);
+
};
#endif // RPLSTRING_HPP
rc += "]";
return rc;
}
-/**
- * Returns the length of the number string.
- *
- * @param text a text to inspect
- * @return 0: not a number<br>
- * otherwise: the length of the number string
- */
-static int lengthOfNumber(const char* text){
- int rc = 0;
- bool found = false;
- const char* ptr = text;
- while(isspace(*ptr))
- ptr++;
- if ( (*ptr == '+' || *ptr == '-'))
- ptr++;
- found = isdigit(*ptr);
- while(isdigit(*ptr))
- text++;
- if (*ptr == '.'){
- ptr++;
- found = isdigit(*ptr);
- if (found){
- while(isdigit(*ptr))
- ptr++;
- }
- }
- if (found && toupper(*ptr) == 'E'){
- ptr++;
- if (*ptr == '+' || *ptr == '-')
- ptr++;
- found = isdigit(*ptr);
- if (found){
- while(isdigit(*ptr))
- ptr++;
- }
- }
- if (found){
- while(isspace(*ptr)){
- ptr++;
- }
- }
- rc = found ? 0 : ptr - text;
- return rc;
-}
/**
* Finds the length of a column.
*
int rc = ptr - text;
return rc;
}
-/**
- * Counts the occurrences of a given char in a string.
- *
- * @param line the text to inspect
- * @param cc the char to count
- * @return the number of cc in the text
- */
-static int countChar(const char* line, char cc)
-{
- const char* ptr = line;
- int rc = 0;
- while( (ptr = strchr(ptr, cc)) != NULL){
- rc++;
- ptr++;
- }
- return rc;
-}
-/**
- * Adds the count of the possible separators.
- *
- * @param countTab IN/OUT: number of tabulators
- * @param countCommas IN/OUT: number of ','
- * @param countSemicolons IN/OUT: number of ';'
- * @param countPipes IN/OUT: number of '|'
- * @param countBlanks IN/OUT: number of ' '
- */
-static void addSeparators(const char* line, int& commas, int& semicolons,
- int& pipes, int& blanks)
-{
- commas += countChar(line, ',');
- semicolons += countChar(line, ';');
- pipes += countChar(line, '|');
- blanks += countChar(line, ' ');
-}
-/**
- * Finds the separator of the CSV file.
- *
- * Inspects the first 5 lines and counts the possible separators.
- * The most found separator will be returned.
- *
- * @param fp CSV file
- * @param buffer a line buffer
- * @param bufferSize the size of <code>buffer[]</code>
- */
-static char findSeparator(FILE* fp, char* buffer, size_t bufferSize){
- char rc = '\0';
- int ix = 0;
- int maxLines = 5;
- const char* line;
- int commas = 0;
- int semicolons = 0;
- int pipes = 0;
- int blanks = 0;
- while(++ix < maxLines && (line = fgets(buffer, bufferSize, fp)) != NULL){
- if (strchr(line, '\t') != NULL){
- rc = '\t';
- break;
- }
- addSeparators(line, commas, semicolons, pipes, blanks);
- }
- fseek(fp, 0, SEEK_SET);
- if (commas + semicolons + pipes == 0) {
- rc = blanks > 0 ? ' ' : '\0';
- } else if (semicolons > commas && semicolons > pipes)
- rc = ',';
- else if (commas > semicolons && commas > pipes)
- rc = ',';
- else if (pipes > commas && pipes > semicolons)
- rc = '|';
- return rc;
-}
/**
* Skips all columns with a content other than a numeric value.
*
{
int len1, len2 = 0;
- while ( (len1 = lengthOfNumber(line)) == 0
+ while ( (len1 = RplString::lengthOfNumber(line)) == 0
&& (len2 = lengthOfColumn(line, separator)) > 0)
line += len2;
+ if (*line == separator)
+ line++;
return line;
}
/**
* @return 0: not only numbers are in the line<br>
* otherwise: the count of numeric columns in the line
*/
-static int countNumbers(char* line, char separator){
- skipNonNumbers(line, separator);
+static int countNumbers(const char* line, char separator){
+ line = skipNonNumbers(line, separator);
bool again = true;
int rc = 0;
- while(again && *line != '\0'){
- int length = lengthOfNumber(line);
+ char cc;
+ while(again && (cc = *line) != '\0' && cc != '\n' && cc != '\r'){
+ int length = RplString::lengthOfNumber(line, true);
if (length == 0){
rc = 0;
again = false;
} else {
- line += lengthOfNumber(line);
+ line += length;
rc++;
if (*line == separator)
line++;
*/
void RplMatrix::readFromCvs(const char* filename, int maxLineLength)
{
- FILE* fp = fopen(filename, "r");
- if (fp == NULL)
+ FILE* fp = fopen(filename, "r");
+ if (fp == NULL)
throw RplMatrixException(*this, "Cannot open %s (%d)", filename, errno);
- char* buffer = new char[maxLineLength];
- char* line;
- char separator = findSeparator(fp, buffer, maxLineLength);
- int rows = 0;
- int cols = 0;
- // find the count of rows and columns:
- while( (line = fgets(buffer, sizeof buffer, fp)) != NULL)
- {
- int nCols;
- if ( (nCols = countNumbers(line, separator)) > 0){
- rows++;
- if (nCols > cols)
- cols = nCols;
- }
- }
- resize(rows, cols);
- // find the values
- fseek(fp, 0, SEEK_SET);
- int row = -1;
- while( (line = fgets(buffer, sizeof buffer, fp)) != NULL)
- {
- int nCols;
- if ( (nCols = countNumbers(line, separator)) > 0){
- row++;
- skipNonNumbers(line, separator);
- int col = -1;
- int length;
- char* ptr = line;
- while( (length = lengthOfNumber(ptr)) > 0){
- while(*ptr == ' ')
- ptr++;
- MatVal value = atof(ptr);
- m_values[m_cols*row + col] = value;
- ptr += length;
- if (*ptr)
- ptr++;
- }
- }
- }
+ char* buffer = new char[maxLineLength + 1];
+ const char* line;
+ char separator = RplString::findCsvSeparator(fp, buffer, maxLineLength);
+ int rows = 0;
+ int cols = 0;
+ int nCols;
+ // find the count of rows and columns:
+ while( (line = fgets(buffer, maxLineLength, fp)) != NULL)
+ {
+ if ( (nCols = countNumbers(line, separator)) > 0){
+ rows++;
+ if (nCols > cols)
+ cols = nCols;
+ }
+ }
+ resize(rows, cols);
+ // find the values
+ fseek(fp, 0, SEEK_SET);
+ int row = -1;
+ while( (line = fgets(buffer, maxLineLength, fp)) != NULL)
+ {
+ int nCols;
+ if ( (nCols = countNumbers(line, separator)) > 0){
+ row++;
+ line = skipNonNumbers(line, separator);
+ int col = -1;
+ int length;
+ const char* ptr;
+ while( (length = RplString::lengthOfNumber(line, true)) > 0){
+ col++;
+ ptr = line;
+ line += length;
+ while(*ptr == ' ')
+ ptr++;
+ MatVal value = atof(ptr);
+ m_values[m_cols*row + col] = value;
+ if (*line == separator)
+ line++;
+ else
+ break;
+ }
+ }
+ }
- fclose(fp);
- delete buffer;
+ fclose(fp);
+ delete buffer;
}
void RplMatrix::readFromXml(const char* filename, const char* tagCol,
const char* tagRow, const char* tagTable,
{
if (argc > 1)
printf("not used: %s\n", argv[1]);
+
extern void testRplMatrix();
testRplMatrix();
+ extern void testRplString();
+ testRplString();
+
extern void testRplException();
testRplException();
}
} catch(RplMatrixException exc){
checkE("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);
+ checkE(2, m1.getRows());
+ checkE(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();
+ checkE(-98.0, miniMax.m_value1);
+ checkE(9999.0, miniMax.m_value2);
+
+ fillMatrix(m1);
+ checkMatrix(m1);
+ m1.set(1, 1, 7777);
+ m1.set(3, 4, -987);
+ miniMax = m1.minMax();
+ checkE(-987.0, miniMax.m_value1);
+ checkE(7777.0, miniMax.m_value2);
+ }
+
+ void testTranspose()
+ {
+ RplMatrix m1(1, 5, "m1");
+ fillMatrix(m1);
+ RplMatrix m2(m1.transpose());
+
+ checkE(5, m2.getRows());
+ checkE(1, m2.getCols());
+
+ int row, col;
+ col = 0;
+ for (row = 0; row < 5; row++){
+ checkE(qreal(col*100+row), m2.get(row, 0));
+ }
+
+ m1.resize(35, 73);
+ fillMatrix(m1);
+ m2 = m1.transpose();
+
+ checkE(73, m2.getRows());
+ checkE(35, m2.getCols());
+
+ int count = 0;
+ for (row = 0; row < m2.getRows(); row++){
+ for (col = 0; col < m2.getCols(); col++){
+ checkE(qreal(col*100+row), m2.get(row, col));
+ count++;
+ }
+ }
+ checkE(73*35, count);
+ }
+ void testToString(){
+ RplMatrix m1(1, 1, "m1");
+ m1.set(0, 0, 2.34);
+ checkE("[2.340000,\n]", m1.toString().constData());
+ checkE("jonny[2.34000 |]", m1.toString("jonny", "%.5f", "|", " ").constData());
+
+ m1.resize(2, 1);
+ m1.set(0, 0, 2.34);
+ m1.set(1, 0, 55.5);
+
+ checkE("[2.340000,\n55.500000,\n]", m1.toString().constData());
+ checkE("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";
+ RplString::write(fn, content);
+ m1.readFromCvs(fn, 256);
+ checkE(2, m1.getRows());
+ checkE(3, m1.getCols());
+
+ checkE(5.0, m1.get(0, 0));
+ checkE(-3.0E-99, m1.get(0, 1));
+ checkE(0.5, m1.get(0, 2));
+
+ checkE(7.0, m1.get(1, 0));
+ checkE(-22.3, m1.get(1, 1));
+ checkE(44.0, m1.get(1, 2));
+
+ fillMatrix(m1);
+ content = "Port0,Port1,Port2\n"
+ "5, -3E-99 , 0.5\n";
+ RplString::write(fn, content);
+ m1.readFromCvs(fn, 256);
+ checkE(1, m1.getRows());
+ checkE(3, m1.getCols());
+ checkE(5.0, m1.get(0, 0));
+ checkE(-3.0E-99, m1.get(0, 1));
+ checkE(0.5, m1.get(0, 2));
+
+
/*
- void checkDefinition(int rows, int cols) const;
- void check(int row, int col) const;
- void checkSameDimension(const RplMatrix& operand) const;
+ 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) {
testCheckDefinition();
testCheck();
testCheckSameDimension();
+ testResize();
+ testMinMax();
+ testTranspose();
+ testToString();
+ testReadCsv();
}
};
void testRplMatrix() {
--- /dev/null
+/*
+ * Licence:
+ * You can use and modify this file without any restriction.
+ * There is no warranty.
+ * You also can use the licence from http://www.wtfpl.net/.
+ * The original sources can be found on https://github.com/republib.
+*/
+// ------------------
+#include "rplcore/rplcore.hpp"
+#include "rplcore/rpltest.hpp"
+/**
+ * @brief Unit test for <code>RplString</code>.
+ */
+class TestRplString : public RplTest {
+public:
+ TestRplString() : RplTest("RplString") {}
+
+public:
+ void testCountChar(){
+ checkE(1, RplString::countChar("x", 'x'));
+ checkE(0, RplString::countChar("X", 'x'));
+ checkE(2, RplString::countChar("xbxxbxx", 'b'));
+ }
+
+ void testCount() {
+ checkE(0, RplString::count("abc", " "));
+ checkE(1, RplString::count("abc", "b"));
+ checkE(2, RplString::count("axx", "x"));
+
+ checkE(0, RplString::count("abbc", "bbb"));
+ checkE(1, RplString::count("\n\n", "\n\n"));
+ checkE(2, RplString::count(" a ", " "));
+ }
+
+ void testCutString() {
+ QByteArray source("123");
+ QByteArray buffer;
+ checkE(QByteArray("123"), RplString::cutString(source, 4, buffer));
+ checkE(QByteArray("123"), RplString::cutString(source, 3, buffer));
+ checkE(QByteArray("12..."), RplString::cutString(source, 2, buffer));
+ checkE(QByteArray("12"), RplString::cutString(source, 2, buffer, ""));
+ }
+
+ void testHexDump() {
+ QByteArray data("abc123\nxyz");
+ checkE(QByteArray("61 62 63 31 abc1\n"
+ "32 33 0a 78 23.x\n"
+ "79 7a yz\n"),
+ RplString::hexDump((uint8_t*) data.constData(), data.length(), 4));
+ checkE(QByteArray("61 62 63 31 32 33 0a 78 79 7a abc123.xyz"),
+ RplString::hexDump((uint8_t*) data.constData(), data.length(), 10));
+ checkE(QByteArray("61 62 63 31 32 33 0a 78 79 7a abc123.xyz"),
+ RplString::hexDump((uint8_t*) data.constData(), data.length(), 12));
+ }
+
+ void testReadWrite() {
+ QByteArray fn = getTempFile("test.dat");
+ const char* content = "Hello world\nLine2\n";
+ checkT(RplString::write(fn, content));
+ checkE(content, RplString::read(fn, false));
+ checkE(content, RplString::read(fn, true) + "\n");
+ }
+
+ void testToArray() {
+ QVector<QByteArray> array = RplString::toArray("1 abc 3", " ");
+ checkE(3, array.size());
+ checkE("1", array.at(0));
+ checkE("abc", array.at(1));
+ checkE("3", array.at(2));
+ }
+
+ void testToNumber() {
+ checkE("3", RplString::toNumber(3));
+ checkE("-33", RplString::toNumber(-33));
+ checkE("003", RplString::toNumber(3, "%03d"));
+ }
+
+ void testLengthOfNumber(){
+ checkE(3, RplString::lengthOfNumber("0.3xxx"));
+ checkE(5, RplString::lengthOfNumber(" \t0.3xxx"));
+ checkE(3, RplString::lengthOfNumber("-.3xxx"));
+ checkE(2, RplString::lengthOfNumber(".3exxx"));
+ checkE(2, RplString::lengthOfNumber(".3e+xxx"));
+ checkE(16, RplString::lengthOfNumber("1234567.9012E+77"));
+ checkE(17, RplString::lengthOfNumber("-1234567.9012E+77 "));
+ checkE(18, RplString::lengthOfNumber("-1234567.9012E+77 ", true));
+ checkE(18, RplString::lengthOfNumber("-1234567.9012E+77 x", true));
+ checkE(20, RplString::lengthOfNumber(" -1234567.9012E+77 x", true));
+ }
+
+ void checkCsv(const char* content, char expected){
+ QByteArray fn = getTempFile("testrplstring.csv");
+ RplString::write(fn, content);
+ FILE* fp = fopen(fn, "r");
+ checkNN(fp);
+ char buffer[256];
+ checkE(expected, RplString::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, ';');
+ }
+
+ virtual void doIt() {
+ testCountChar();
+ testCount();
+ testCutString();
+ testToNumber();
+ testToArray();
+ testHexDump();
+ testReadWrite();
+ testLengthOfNumber();
+ testFindCsvSeparator();
+ }
+};
+
+void testRplString() {
+ TestRplString test;
+ test.run();
+}
+
+
+
../rplcore/rpltest.cpp \
../rplcore/rplstring.cpp \
../rplcore/rplexception.cpp \
- rplexception_test.cpp
+ rplexception_test.cpp \
+ rplstring_test.cpp