iocsh: Add underline separator between help outputs
Also tweaks the overall format of the message a bit. Add tests for new help output format
This commit is contained in:
@@ -285,14 +285,16 @@ LIBCOM_API void errSymLookup(long status, char *pBuf, size_t bufLength);
|
||||
#define ANSI_ESC_MAGENTA "\033[35;1m"
|
||||
#define ANSI_ESC_CYAN "\033[36;1m"
|
||||
#define ANSI_ESC_BOLD "\033[1m"
|
||||
#define ANSI_ESC_UNDERLINE "\033[4m"
|
||||
#define ANSI_ESC_RESET "\033[0m"
|
||||
#define ANSI_RED(STR) ANSI_ESC_RED STR ANSI_ESC_RESET
|
||||
#define ANSI_GREEN(STR) ANSI_ESC_GREEN STR ANSI_ESC_RESET
|
||||
#define ANSI_YELLOW(STR) ANSI_ESC_YELLOW STR ANSI_ESC_RESET
|
||||
#define ANSI_BLUE(STR) ANSI_ESC_BLUE STR ANSI_ESC_RESET
|
||||
#define ANSI_MAGENTA(STR) ANSI_ESC_MAGENTA STR ANSI_ESC_RESET
|
||||
#define ANSI_CYAN(STR) ANSI_ESC_CYAN STR ANSI_ESC_RESET
|
||||
#define ANSI_BOLD(STR) ANSI_ESC_BOLD STR ANSI_ESC_RESET
|
||||
#define ANSI_RED(STR) ANSI_ESC_RED STR ANSI_ESC_RESET
|
||||
#define ANSI_GREEN(STR) ANSI_ESC_GREEN STR ANSI_ESC_RESET
|
||||
#define ANSI_YELLOW(STR) ANSI_ESC_YELLOW STR ANSI_ESC_RESET
|
||||
#define ANSI_BLUE(STR) ANSI_ESC_BLUE STR ANSI_ESC_RESET
|
||||
#define ANSI_MAGENTA(STR) ANSI_ESC_MAGENTA STR ANSI_ESC_RESET
|
||||
#define ANSI_CYAN(STR) ANSI_ESC_CYAN STR ANSI_ESC_RESET
|
||||
#define ANSI_BOLD(STR) ANSI_ESC_BOLD STR ANSI_ESC_RESET
|
||||
#define ANSI_UNDERLINE(STR) ANSI_ESC_UNDERLINE STR ANSI_ESC_RESET
|
||||
#define ERL_ERROR ANSI_RED("ERROR")
|
||||
#define ERL_WARNING ANSI_MAGENTA("WARNING")
|
||||
/** @} */
|
||||
|
||||
@@ -892,15 +892,19 @@ static void helpCallFunc(const iocshArgBuf *args)
|
||||
"Type 'help <command>' to see the arguments of <command>. eg. 'help db*'\n");
|
||||
}
|
||||
else {
|
||||
bool firstFunction = true;
|
||||
for (int iarg = 1 ; iarg < argc ; iarg++) {
|
||||
for (pcmd = iocshCommandHead ; pcmd != NULL ; pcmd = pcmd->next) {
|
||||
piocshFuncDef = pcmd->def.pFuncDef;
|
||||
if (epicsStrGlobMatch(piocshFuncDef->name, argv[iarg]) != 0) {
|
||||
if(piocshFuncDef->usage) {
|
||||
fputs("\nUsage: ", epicsGetStdout());
|
||||
|
||||
if (! firstFunction) {
|
||||
fprintf(epicsGetStdout(),
|
||||
ANSI_UNDERLINE(" \n"));
|
||||
}
|
||||
|
||||
fprintf(epicsGetStdout(),
|
||||
ANSI_BOLD("%s"),
|
||||
ANSI_BOLD("\n%s"),
|
||||
piocshFuncDef->name);
|
||||
|
||||
for (int a = 0 ; a < piocshFuncDef->nargs ; a++) {
|
||||
@@ -913,11 +917,14 @@ static void helpCallFunc(const iocshArgBuf *args)
|
||||
fprintf(epicsGetStdout(), " '%s'", cp);
|
||||
}
|
||||
}
|
||||
fprintf(epicsGetStdout(),"\n");;
|
||||
fprintf(epicsGetStdout(),"\n");
|
||||
if(piocshFuncDef->usage) {
|
||||
fprintf(epicsGetStdout(), "\n%s", piocshFuncDef->usage);
|
||||
}
|
||||
|
||||
firstFunction = false;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -269,6 +269,7 @@ TESTPROD_HOST += iocshTest
|
||||
iocshTest_SRCS += iocshTest.cpp
|
||||
TESTS += iocshTest
|
||||
TESTFILES += $(wildcard ../iocshTest*.cmd)
|
||||
TESTFILES += ../iocshTestHelpFunction1 ../iocshTestHelpFunctions
|
||||
|
||||
TESTPROD_HOST += epicsLoadTest
|
||||
epicsLoadTest_SRCS += epicsLoadTest.cpp
|
||||
|
||||
@@ -8,6 +8,8 @@
|
||||
#include <string>
|
||||
#include <fstream>
|
||||
#include <set>
|
||||
#include <sstream>
|
||||
#include <stdexcept>
|
||||
|
||||
#include <osiUnistd.h>
|
||||
#include <osiFileName.h>
|
||||
@@ -83,14 +85,117 @@ 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
|
||||
}
|
||||
|
||||
if (f1.tellg() != f2.tellg()) {
|
||||
testDiag("File sizes did not match");
|
||||
return false; // Size mismatch
|
||||
}
|
||||
|
||||
// Seek back to beginning and use std::equal to compare contents
|
||||
f1.seekg(0, std::ifstream::beg);
|
||||
f2.seekg(0, std::ifstream::beg);
|
||||
|
||||
bool are_equal = std::equal(
|
||||
std::istreambuf_iterator<char>(f1.rdbuf()),
|
||||
std::istreambuf_iterator<char>(),
|
||||
std::istreambuf_iterator<char>(f2.rdbuf())
|
||||
);
|
||||
|
||||
if (! are_equal) {
|
||||
testDiag("File contents did not match");
|
||||
|
||||
std::string line;
|
||||
f1.seekg(0, std::ifstream::beg);
|
||||
f2.seekg(0, std::ifstream::beg);
|
||||
|
||||
testDiag("File1 contents: ");
|
||||
while(std::getline(f1, line)) {
|
||||
testDiag("%s", line.c_str());
|
||||
}
|
||||
|
||||
testDiag("File2 contents: ");
|
||||
while(std::getline(f2, line)) {
|
||||
testDiag("%s", line.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
return are_equal;
|
||||
}
|
||||
|
||||
|
||||
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);
|
||||
testOk1(contents.find("help") != std::string::npos);
|
||||
testOk1(contents.find("testHelpFunction1") != std::string::npos);
|
||||
testOk1(contents.find("testHelpFunction2") != std::string::npos);
|
||||
testOk1(contents.find("testHelpFunction3") != std::string::npos);
|
||||
|
||||
// Confirm formatting of a single command
|
||||
iocshCmd(("help testHelpFunction1 > " + filename).c_str());
|
||||
testOk1(compareFiles(filename, "iocshTestHelpFunction1") == true);
|
||||
|
||||
// Confirm formatting of multiple commands
|
||||
iocshCmd(("help testHelp* > " + filename).c_str());
|
||||
testOk1(compareFiles(filename, "iocshTestHelpFunctions") == true);
|
||||
|
||||
remove(filename.c_str());
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
|
||||
|
||||
MAIN(iocshTest)
|
||||
{
|
||||
testPlan(19);
|
||||
testPlan(25);
|
||||
libComRegister();
|
||||
iocshRegister(&positionFuncDef, &positionCallFunc);
|
||||
iocshRegister(&assertFuncDef, &assertCallFunc);
|
||||
iocshRegister(&testHelpFunction1Def, &doNothing);
|
||||
iocshRegister(&testHelpFunction2Def, &doNothing);
|
||||
iocshRegister(&testHelpFunction3Def, &doNothing);
|
||||
findTestData();
|
||||
|
||||
testFile("iocshTestSuccess.cmd");
|
||||
@@ -129,6 +234,8 @@ MAIN(iocshTest)
|
||||
testPosition("after_error_1", false);
|
||||
reached.clear();
|
||||
|
||||
testHelp();
|
||||
|
||||
// cleanup after macLib to avoid valgrind false positives
|
||||
dbmfFreeChunks();
|
||||
return testDone();
|
||||
|
||||
4
modules/libcom/test/iocshTestHelpFunction1
Normal file
4
modules/libcom/test/iocshTestHelpFunction1
Normal file
@@ -0,0 +1,4 @@
|
||||
[1m
|
||||
testHelpFunction1[0m
|
||||
|
||||
Usage message of testHelpFunction1
|
||||
14
modules/libcom/test/iocshTestHelpFunctions
Normal file
14
modules/libcom/test/iocshTestHelpFunctions
Normal file
@@ -0,0 +1,14 @@
|
||||
[1m
|
||||
testHelpFunction1[0m
|
||||
|
||||
Usage message of testHelpFunction1
|
||||
[4m
|
||||
[0m[1m
|
||||
testHelpFunction2[0m
|
||||
|
||||
Usage message of testHelpFunction2
|
||||
[4m
|
||||
[0m[1m
|
||||
testHelpFunction3[0m
|
||||
|
||||
Usage message of testHelpFunction3
|
||||
Reference in New Issue
Block a user