/*************************************************************************\ * Copyright (c) 2019 Michael Davidsaver * SPDX-License-Identifier: EPICS * EPICS BASE is distributed subject to a Software License Agreement found * in file LICENSE that is included with this distribution. \*************************************************************************/ #include #include #include #include #include #include #include #include #include #include #include #include #include namespace { void findTestData() { const char *locations[] = { ".", "..", ".." OSI_PATH_LIST_SEPARATOR "O.Common", "O.Common", }; for(size_t i=0; i %d", expect ? "ran" : "expected error from", fname, err); } void testCmd(const char *cmd, bool expect=true) { testDiag("eval \"%s\"", cmd); int err = iocshCmd(cmd); testOk((err==0) ^ (!expect), "%s \"%s\" -> %d", expect ? "eval'd" : "expected error from", cmd, err); } std::set reached; const iocshArg positionArg0 = {"position", iocshArgString}; const iocshArg * const positionArgs[1] = { &positionArg0 }; const iocshFuncDef positionFuncDef = {"position",1,positionArgs}; void positionCallFunc(const iocshArgBuf *args) { testDiag("Reaching \"%s\"", args[0].sval); reached.insert(args[0].sval); } void testPosition(const std::string& pos, bool expect=true) { testOk((reached.find(pos)!=reached.end()) ^ !expect, "%sreached position %s", expect ? "" : "not ", pos.c_str()); } const iocshArg assertArg0 = {"condition", iocshArgInt}; const iocshArg * const assertArgs[1] = {&assertArg0}; const iocshFuncDef assertFuncDef = {"assert",1,assertArgs}; void assertCallFunc(const iocshArgBuf *args) { iocshSetError(args[0].ival); } const iocshFuncDef testHelpFunction1Def = {"testHelpFunction1",0,0, "Usage message of testHelpFunction1\n"}; const iocshFuncDef testHelpFunction2Def = {"testHelpFunction2",0,0, "Usage message of testHelpFunction2\n"}; const iocshFuncDef testHelpFunction3Def = {"testHelpFunction3",0,0, "Usage message of testHelpFunction3\n"}; void doNothing(const iocshArgBuf *args) { return; } std::string readFile(std::string filename) { std::ifstream t(filename.c_str()); std::stringstream buffer; if (!t.is_open()) { throw std::invalid_argument("Could not open filename " + filename); } buffer << t.rdbuf(); return buffer.str(); } bool compareFiles(const std::string& p1, const std::string& p2) { std::ifstream f1(p1.c_str(), std::ifstream::binary|std::ifstream::ate); std::ifstream f2(p2.c_str(), std::ifstream::binary|std::ifstream::ate); if (f1.fail() || f2.fail()) { testDiag("One or more files failed to open"); testDiag("f1.fail(): %d f2.fail(): %d", f1.fail(), f2.fail()); return false; // File problem } bool different = false; if (f1.tellg() != f2.tellg()) { testDiag("Help text size is different"); different = true; } else { // Seek back to beginning and use std::equal to compare contents f1.seekg(0, std::ifstream::beg); f2.seekg(0, std::ifstream::beg); different = !std::equal( std::istreambuf_iterator(f1.rdbuf()), std::istreambuf_iterator(), std::istreambuf_iterator(f2.rdbuf()) ); if (different) testDiag("Help text output is different"); } if (different) { std::string line; f1.seekg(0, std::ifstream::beg); f2.seekg(0, std::ifstream::beg); testDiag("Expected output:"); while(std::getline(f1, line)) { testDiag(" < %s", line.c_str()); } testDiag("Received output:"); while(std::getline(f2, line)) { testDiag(" > %s", line.c_str()); } } return !different; } void testHelp(void) { testDiag("iocshTest testHelp start"); // Filename to save help output to const std::string filename = "testHelpOutput"; // Verify help lists expected commands iocshCmd(("help > " + filename).c_str()); std::string contents = readFile(filename); testOk(contents.find("help") != std::string::npos, "Found 'help' in help output"); testOk(contents.find("testHelpFunction1") != std::string::npos, "Found 'testHelpFunction1' in help output"); testOk(contents.find("testHelpFunction2") != std::string::npos, "Found 'testHelpFunction2' in help output"); testOk(contents.find("testHelpFunction3") != std::string::npos, "Found 'testHelpFunction3' in help output"); // Confirm formatting of a single command iocshCmd(("help testHelpFunction1 > " + filename).c_str()); testOk(compareFiles(filename, "iocshTestHelpFunction1"), "'help testHelpFunction1' matches file iocshTestHelpFunction1"); // Confirm formatting of multiple commands iocshCmd(("help testHelp* > " + filename).c_str()); testOk(compareFiles(filename, "iocshTestHelpFunctions"), "'help testHelp*' matches file iocshTestHelpFunctions"); remove(filename.c_str()); } } // namespace MAIN(iocshTest) { testPlan(25); libComRegister(); iocshRegister(&positionFuncDef, &positionCallFunc); iocshRegister(&assertFuncDef, &assertCallFunc); iocshRegister(&testHelpFunction1Def, &doNothing); iocshRegister(&testHelpFunction2Def, &doNothing); iocshRegister(&testHelpFunction3Def, &doNothing); findTestData(); testFile("iocshTestSuccess.cmd"); testPosition("success"); reached.clear(); testPosition("success", false); testCmd("