/* * ebusd - daemon for communication with eBUS heating systems. * Copyright (C) 2014-2021 John Baier * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include #include #include #include #include "lib/ebus/filereader.h" using namespace std; using namespace ebusd; static bool error = false; void verify(bool expectFailMatch, string type, string input, bool match, string expectStr, string gotStr) { match = match && expectStr == gotStr; if (expectFailMatch) { if (match) { cout << " failed " << type << " match >" << input << "< error: unexpectedly succeeded" << endl; error = true; } else { cout << " failed " << type << " match >" << input << "< OK" << endl; } } else if (match) { cout << " " << type << " match >" << input << "< OK" << endl; } else { cout << " " << type << " match >" << input << "< error: got >" << gotStr << "<, expected >" << expectStr << "<" << endl; error = true; } } string resultlines[][3] = { {"col 1", "col 2", "col 3"}, {"line 2 col 1 de", "line 2 col 2", "line 2 \"col 3\";default of col 3"}, {"", "", ""}, {"line 4 col 1 de", "line 4 col 2 part 1;line 4 col 2 part 2", "line 4 col 3;default of col 3"}, {"", "", ""}, {"line 6 col 1 de", "", "line 6 col 3;default of col 3"}, {"", "", ""}, {"line 8 col 1 de", "line 8 col 2 part 1;line 8 col 2 part 2", "line 8 col 3;default of col 3"}, }; string resultsublines[][2][4] = { {}, {{"subcol 1", "line 2 subcol 1", "subcol 2", "line 2 subcol 2;default of sub 0 subcol 2"},{"subcol 2", "line 2 subcol 2", "subcol 3", "line 2 subcol 3"}}, {}, {{"subcol 1", "line 4 subcol 1", "subcol 2", "line 4 subcol 2;default of sub 0 subcol 2"},{"subcol 2", "line 4 subcol 2", "subcol 3", "line 4 subcol 3"}}, {}, {{"subcol 1", "line 6 subcol 1", "subcol 2", "line 6 subcol 2;default of sub 0 subcol 2"},{"subcol 2", "line 6 subcol 2", "subcol 3", "line 6 subcol 3"}}, {}, {{"subcol 1", "line 8 subcol 1", "subcol 2", "line 8 subcol 2;default of sub 0 subcol 2"},{"subcol 2", "line 8 subcol 2", "subcol 3", "line 8 subcol 3"}}, }; static unsigned int baseLine = 0; class NoopReader : public FileReader { public: result_t addFromFile(const string& filename, unsigned int lineNo, vector* row, string* errorDescription, bool replace) override { return RESULT_OK; } }; class TestReader : public MappedFileReader { public: TestReader(size_t expectedCols, size_t langCols) : MappedFileReader::MappedFileReader(false, ""), m_expectedCols(expectedCols), m_langCols(langCols) {} result_t getFieldMap(const string& preferLanguage, vector* row, string* errorDescription) const override { if (row->size() == m_expectedCols+m_langCols) { cout << "get field map: split OK" << endl; if (m_langCols == 1) { (*row)[0] = SKIP_COLUMN; size_t pos = (*row)[1].find_last_of('.'); (*row)[1] = (*row)[1].substr(0, pos); } return RESULT_OK; } cout << "get field map: error got " << static_cast(row->size()) << " columns, expected " << static_cast(m_expectedCols+m_langCols) << endl; return RESULT_ERR_EOF; } result_t addFromFile(const string& filename, unsigned int lineNo, map* row, vector< map >* subRows, string* errorDescription, bool replace) override { if (row->empty() || (m_expectedCols == 3) != subRows->empty()) { cout << "read line " << static_cast(baseLine + lineNo) << ": read error: got " << static_cast(row->size()) << "/3 main, " << static_cast(subRows->size()) << (m_expectedCols == 3 ? "/0 sub" : "/>0 sub") << endl; return RESULT_ERR_EOF; } if (lineNo < 2 || lineNo >= 1+sizeof(resultlines)/sizeof(string[3])) { cout << "read line " << static_cast(baseLine + lineNo) << ": error invalid line" << endl; return RESULT_ERR_INVALID_ARG; } cout << "read line " << static_cast(baseLine + lineNo) << ": split OK" << endl; string* resultline = resultlines[lineNo - 1]; if (row->empty()) { cout << " result empty"; if (resultline[0] == "") { cout << ": OK" << endl; } else { cout << ": error" << endl; return RESULT_ERR_INVALID_ARG; } return RESULT_EMPTY; } bool error = false; string* colnames = resultlines[0]; map& defaults = getDefaults()[""]; for (size_t colIdx = 0; colIdx < 3; colIdx++) { string col = colnames[colIdx]; string got = (*row)[col] + defaults[col]; string expect = resultline[colIdx]; ostringstream type; type << "line " << static_cast(baseLine + lineNo) << " column \"" << col << "\""; bool match = got == expect; verify(false, type.str(), expect, match, expect, got); if (!match) { error = true; } } if (row->size() > 3) { ostringstream type; type << "line " << static_cast(baseLine + lineNo); verify(false, type.str(), "", false, "", "extra column"); error = true; } for (size_t subIdx = 0; subIdx < subRows->size(); subIdx++) { string* resultsubline = resultsublines[lineNo - 1][subIdx]; *row = (*subRows)[subIdx]; if (row->empty()) { cout << " sub " << subIdx << " result empty"; if (resultline[0] == "") { cout << ": OK" << endl; } else { cout << ": error" << endl; return RESULT_ERR_INVALID_ARG; } return RESULT_EMPTY; } vector< map >& subDefaults = getSubDefaults()[""]; for (size_t colIdx = 0; colIdx < 2; colIdx++) { string col = resultsubline[colIdx*2]; string got = (*row)[col]; if (subIdx < subDefaults.size()) { got += subDefaults[subIdx][col]; } string expect = resultsubline[colIdx*2+1]; ostringstream type; type << "line " << static_cast(baseLine + lineNo) << " sub " << subIdx << " column \"" << col << "\""; bool match = got == expect; verify(false, type.str(), expect, match, expect, got); if (!match) { error = true; } } if (row->size() > 2) { ostringstream type; type << "line " << static_cast(baseLine + lineNo) << " sub " << subIdx; verify(false, type.str(), "", false, "", "extra sub column"); error = true; } } return error ? RESULT_ERR_INVALID_ARG : RESULT_OK; } private: size_t m_expectedCols; size_t m_langCols; }; int main(int argc, char** argv) { if (argc > 1) { NoopReader reader; for (int argpos = 1; argpos < argc; argpos++) { size_t hash = 0, size = 0; time_t time = 0; string errorDescription; istream* stream = FileReader::openFile(argv[argpos], &errorDescription, &time); result_t result; if (!stream) { result = RESULT_ERR_NOTFOUND; } else { result = reader.readFromStream(stream, argv[argpos], time, false, nullptr, &errorDescription, false, &hash, &size); } cout << argv[argpos] << " "; if (result != RESULT_OK) { cout << getResultCode(result) << ", " << errorDescription << endl; error = true; continue; } FileReader::formatHash(hash, &cout); cout << " " << size << " " << time << endl; } return error ? 1 : 0; } baseLine = __LINE__+1; istringstream ifs( "col 1.en,col 1.de,col 2,col 3\n" "line 2 col 1 en,line 2 col 1 de,\"line 2 col 2\",\"line 2 \"\"col 3\"\";default of col 3\"\n" "line 4 col 1 en,line 4 col 1 de,\"line 4 col 2 part 1\n" "line 4 col 2 part 2\",line 4 col 3;default of col 3\n" ",,,\n" "line 6 col 1 en,line 6 col 1 de,,line 6 col 3;default of col 3\n" "line 8 col 1 en,line 8 col 1 de,\"line 8 col 2 part 1;\n" "line 8 col 2 part 2\",line 8 col 3;default of col 3\n" ); size_t hash = 0, size = 0, expectHash = 0xb958f1cb, expectSize = 389; TestReader reader{3, 1}; unsigned int lineNo = 0; vector row; string errorDescription; while (ifs.peek() != EOF) { result_t result = reader.readLineFromStream(&ifs, "", true, &lineNo, &row, &errorDescription, false, &hash, &size); if (result != RESULT_OK) { cout << " error " << getResultCode(result) << endl; error = true; } } if (hash == expectHash) { cout << "hash OK" << endl; } else { cout << "hash error: got 0x" << hex << hash << ", expected 0x" << expectHash << dec << endl; error = true; } if (size == expectSize) { cout << "size OK" << endl; } else { cout << "size error: got " << size << ", expected " << expectSize << endl; error = true; } ifs.clear(); baseLine = __LINE__+1; ifs.str( "col 1,col 2,col 3,*subcol 1,subcol 2,*subcol 2,subcol 3\n" "line 2 col 1 de,\"line 2 col 2\",\"line 2 \"\"col 3\"\"\",line 2 subcol 1,line 2 subcol 2,line 2 subcol 2,line 2 subcol 3\n" "line 4 col 1 de,\"line 4 col 2 part 1\n" "line 4 col 2 part 2\",line 4 col 3,line 4 subcol 1,line 4 subcol 2,line 4 subcol 2,line 4 subcol 3\n" ",,,\n" "line 6 col 1 de,,line 6 col 3,line 6 subcol 1,line 6 subcol 2,line 6 subcol 2,line 6 subcol 3\n" "line 8 col 1 de,\"line 8 col 2 part 1;\n" "line 8 col 2 part 2\",line 8 col 3,line 8 subcol 1,line 8 subcol 2,line 8 subcol 2,line 8 subcol 3\n" ); hash = 0, size = 0, expectHash = 0x2584e0f2, expectSize = 539; TestReader reader2{7, 0}; lineNo = 0; map defaults; reader2.getDefaults()[""]["col 3"] = ";default of col 3"; vector< map >& subDefaults = reader2.getSubDefaults()[""]; subDefaults.resize(1); subDefaults[0]["subcol 2"] = ";default of sub 0 subcol 2"; while (ifs.peek() != EOF) { result_t result = reader2.readLineFromStream(&ifs, "", true, &lineNo, &row, &errorDescription, false, &hash, &size); if (result != RESULT_OK) { cout << " error " << getResultCode(result) << endl; error = true; } } if (hash == expectHash) { cout << "hash OK" << endl; } else { cout << "hash error: got 0x" << hex << hash << ", expected 0x" << expectHash << dec << endl; error = true; } if (size == expectSize) { cout << "size OK" << endl; } else { cout << "size error: got " << size << ", expected " << expectSize << endl; error = true; } return error ? 1 : 0; }