diff --git a/.github/workflows/parafeed_CI.yaml b/.github/workflows/parafeed_CI.yaml index d4505bc..293544b 100644 --- a/.github/workflows/parafeed_CI.yaml +++ b/.github/workflows/parafeed_CI.yaml @@ -5,6 +5,10 @@ on: branches: [ main, master ] pull_request: branches: [ main, master ] + workflow_dispatch: + inputs: + reason: + description: 'Reason for manual run' jobs: build-and-test: diff --git a/code/CMakeLists.txt b/code/CMakeLists.txt index 5d737a1..b9f5721 100644 --- a/code/CMakeLists.txt +++ b/code/CMakeLists.txt @@ -176,11 +176,11 @@ set(shccl_sources ParseCmdLine.cc clparseVal.cc InstallSymb.cc - clgetSVal.cc - clgetNSVal.cc +# clgetSVal.cc +# clgetNSVal.cc clgetFullVal.cc - clgetValp.cc +# clgetValp.cc clStartInteractive.cc clRestartShell.cc clfInteractive.cc diff --git a/code/ParseCmdLine.cc b/code/ParseCmdLine.cc index 167737b..4805169 100644 --- a/code/ParseCmdLine.cc +++ b/code/ParseCmdLine.cc @@ -28,7 +28,7 @@ #include #include #include -//#include +#include /*#include */ #ifdef __cplusplus #ifdef _GNU_SOURCE @@ -385,7 +385,7 @@ int startShell() { loadDefaults(1); cl_defaultsLoaded=1; } - if (doInp) + if (doInp && !cl_NoPrompt) { // // Why is this required? This gets called anyway via @@ -454,8 +454,9 @@ int EndCL() cl_RegistrationMode=0; // i = clgetSVal("help",val,&i); - i = clgetSValp("help",strVal,i); - DeleteVar("help",&cl_SymbTab,&cl_TabTail); + string help("help"); + i = clgetSValp(help,strVal,i); + DeleteVar((char *)help.c_str(),&cl_SymbTab,&cl_TabTail); // if (!cl_NoPrompt) loadDefaults(0); // if (!strcmp(val,"doc")) @@ -476,6 +477,7 @@ int EndCL() if (!cl_defaultsLoaded) {loadDefaults(1);cl_defaultsLoaded=1;} } // DeleteVar("help",&cl_SymbTab,&cl_TabTail); + cl_NoPrompt=1; if (strVal=="doc") doprintdoc(strVal.c_str()); else doprintparams(strVal.c_str()); } @@ -495,7 +497,7 @@ int EndCL() if (arg[strlen(arg)-1]==')') arg[strlen(arg)-1] = '\0'; doexplain(arg); free(val_t); - exit(0); + throw(clExit("Exiting due to explain mode", "###Informational", CL_INFORMATIONAL)); } else if (strVal=="def") { @@ -511,8 +513,7 @@ int EndCL() if (cl_DOCLEANUP) clCleanUp(); if (cl_DryRun==1) { - clThrowUp("Exiting in EndCL() due to dryrun mode", "###Informational", CL_INFORMATIONAL); - exit(0); + throw(clExit("Exiting in EndCL() due to dryrun mode", "###Informational", CL_INFORMATIONAL)); } return i; } @@ -529,9 +530,8 @@ int EndCL() save_hist(var,(char *)CL_HIST_DEFAULT); #endif if (cl_DryRun==1) - { - exit(0); - } + throw(clExit("Exiting in EndCL() due to dryrun mode", "###Informational", CL_INFORMATIONAL)); + return 1; } /*------------------------------------------------------------------------ diff --git a/code/callbacks.cc b/code/callbacks.cc index a9012bf..ae99819 100644 --- a/code/callbacks.cc +++ b/code/callbacks.cc @@ -37,6 +37,7 @@ #ifdef GNUREADLINE #include #endif +extern unsigned short cl_NoPrompt; #ifdef __cplusplus using namespace std; @@ -108,6 +109,7 @@ END{ \ /*----------------------------------------------------------------------*/ int doinp(char *arg) { + if (cl_NoPrompt) return 0; auto printer = [](FILE *fd, Symbol *t) { PrintKey(stderr, t); @@ -702,7 +704,7 @@ int dosavefd(FILE *fd, const std::vector& opts) if (S->Class==CL_DBGCLASS) cout << "\t***This keyword is exposed with a command-line argument of \"help=dbg\"***" << endl; } - exit(0); + // exit(0); return 1; } /*----------------------------------------------------------------------*/ @@ -729,7 +731,7 @@ int dosavefd(FILE *fd, const std::vector& opts) cout << endl; } } - exit(0); + // exit(0); return 1; } /*----------------------------------------------------------------------*/ diff --git a/code/clCleanUp.cc b/code/clCleanUp.cc index 3ecee1e..47471ca 100644 --- a/code/clCleanUp.cc +++ b/code/clCleanUp.cc @@ -37,6 +37,8 @@ void clCleanUp() cl_RegistrationMode=1; cl_Pass = 0; cl_SymbLoaded= 0; + cl_InteractiveShell=0; + cl_NoPrompt=0; } #ifdef __cplusplus diff --git a/code/clError.h b/code/clError.h index 2a7a174..0702f3e 100644 --- a/code/clError.h +++ b/code/clError.h @@ -69,6 +69,16 @@ class clNumParsingError: public clError clNumParsingError(const clNumParsingError& that) : clError(that) {}; ~clNumParsingError() {}; }; + +class clExit: public clError +{ +public: + clExit():clError() {}; + clExit(const char *m, const char *i, int l=0): clError(m,i,l) {}; + clExit(const string& m, const string& i, int l=0): clError(m,i,l) {}; + clExit(const clExit& that) : clError(that) {}; + ~clExit() {}; +}; /*--------------------------------------------------------------------- In the entire library, the following routine is used always when an exception is to be thrown. diff --git a/code/clgetFullVal.cc b/code/clgetFullVal.cc index 2281532..c07976a 100644 --- a/code/clgetFullVal.cc +++ b/code/clgetFullVal.cc @@ -21,6 +21,7 @@ #include #include #include +#include #ifdef __cplusplus extern "C" { #endif @@ -30,27 +31,28 @@ extern "C" { int clgetFullVal(char *Name, char **val) { int n,i,len=0; - char tmp[FILENAME_MAX]; + // char tmp[FILENAME_MAX]; + std::string tmp; if (!*val) free(*val); *val=NULL; if ((n=clgetNVals(Name))>0) { for (i=1;i<=n;i++) { - clgetSVal(Name,tmp,&i); - len += strlen(tmp)+1; + clgetSValp(string(Name),tmp,i); + len += strlen(tmp.c_str())+1; } *val = (char *)getmem(len,"clgetFullVal"); for (i=0;i +#include +//#include // // //---------------------------------------------------------------------- @@ -145,46 +142,47 @@ int dbgclgetValp(const std::string& Name, std::vector& val, int& n, SMap smap // template -int cldbggetValp(const std::string& Name, T& val, int& n) {return dbgclgetValp(Name,val,n);} +inline int cldbggetValp(const std::string& Name, T& val, int& n) {return dbgclgetValp(Name,val,n);} -int clgetFValp(const std::string& Name, float &val, int &n) {return clgetValp(Name,val,n);} -int clgetFValp(const std::string& Name, float& val, int& n, SMap &smap) {return clgetValp(Name,val,n,smap);} -int clgetNFValp(const std::string& Name, std::vector& val, int& n) {return clgetValp(Name,val,n);} -int clgetNFValp(const std::string& Name, std::vector& val, int& n, SMap &smap) {return clgetValp(Name,val,n,smap);} +inline int clgetFValp(const std::string& Name, float& val, int& n) {return clgetValp(Name,val,n);} +inline int clgetFValp(const std::string& Name, float& val, int& n, SMap &smap) {return clgetValp(Name,val,n,smap);} +inline int clgetNFValp(const std::string& Name, std::vector& val, int& n) {return clgetValp(Name,val,n);} +inline int clgetNFValp(const std::string& Name, std::vector& val, int& n, SMap &smap) {return clgetValp(Name,val,n,smap);} -int clgetIValp(const std::string& Name, int &val, int &n) {return clgetValp(Name,val,n);} -int clgetIValp(const std::string& Name, int& val, int& n, SMap &smap) {return clgetValp(Name,val,n,smap);} -int clgetNIValp(const std::string& Name, std::vector& val, int& n) {return clgetValp(Name,val,n);} -int clgetNIValp(const std::string& Name, std::vector& val, int& n, SMap &smap) {return clgetValp(Name,val,n,smap);} +inline int clgetIValp(const std::string& Name, int &val, int &n) {return clgetValp(Name,val,n);} +inline int clgetIValp(const std::string& Name, int& val, int& n, SMap &smap) {return clgetValp(Name,val,n,smap);} +inline int clgetNIValp(const std::string& Name, std::vector& val, int& n) {return clgetValp(Name,val,n);} +inline int clgetNIValp(const std::string& Name, std::vector& val, int& n, SMap &smap) {return clgetValp(Name,val,n,smap);} -int clgetBValp(const std::string& Name, bool& val, int &n) {return clgetValp(Name,val,n);} -int clgetBValp(const std::string& Name, bool& val, int& n, SMap &smap) {return clgetValp(Name,val,n,smap);} -int clgetNBValp(const std::string& Name, std::vector& val, int& n) {return clgetValp(Name,val,n);} -int clgetNBValp(const std::string& Name, std::vector& val, int& n, SMap &smap){return clgetValp(Name,val,n,smap);} +inline int clgetBValp(const std::string& Name, bool& val, int &n) {return clgetValp(Name,val,n);} +inline int clgetBValp(const std::string& Name, bool& val, int& n, SMap &smap) {return clgetValp(Name,val,n,smap);} +inline int clgetNBValp(const std::string& Name, std::vector& val, int& n) {return clgetValp(Name,val,n);} +inline int clgetNBValp(const std::string& Name, std::vector& val, int& n, SMap &smap){return clgetValp(Name,val,n,smap);} -int clgetSValp(const std::string& Name, std::string& val, int &n) {return clgetValp(Name,val,n);} -int clgetSValp(const std::string& Name, std::string& val, int& n, SMap &smap) {return clgetValp(Name,val,n,smap);} -int clgetNSValp(const std::string& Name, std::vector& val, int& n) {return clgetValp(Name,val,n);} -int clgetNSValp(const std::string& Name, std::vector& val, int& n, SMap &smap) {return clgetValp(Name,val,n,smap);} -int clgetNSValp(const std::string& Name, std::vector& val, int& n, const SMap smap) {return clgetValp(Name,val,n,smap);} +//inline int clgetSVal(const char *Name, char *val, int *n) {return clgetValp(std::string(Name), *val, *n);} +inline int clgetSValp(const std::string& Name, std::string& val, int &n) {return clgetValp(Name,val,n);} +inline int clgetSValp(const std::string& Name, std::string& val, int& n, SMap &smap) {return clgetValp(Name,val,n,smap);} +inline int clgetNSValp(const std::string& Name, std::vector& val, int& n) {return clgetValp(Name,val,n);} +inline int clgetNSValp(const std::string& Name, std::vector& val, int& n, SMap &smap) {return clgetValp(Name,val,n,smap);} +inline int clgetNSValp(const std::string& Name, std::vector& val, int& n, const SMap smap) {return clgetValp(Name,val,n,smap);} -int cldbggetIValp(const std::string& Name, int& val, int& n) {return dbgclgetValp(Name,val,n);} -int cldbggetFValp(const std::string& Name, float& val, int& n) {return dbgclgetValp(Name,val,n);} -int cldbggetBValp(const std::string& Name, bool& val, int& n) {return dbgclgetValp(Name,val,n);} -int cldbggetSValp(const std::string& Name, std::string& val, int& n) {return dbgclgetValp(Name,val,n);} +inline int cldbggetIValp(const std::string& Name, int& val, int& n) {return dbgclgetValp(Name,val,n);} +inline int cldbggetFValp(const std::string& Name, float& val, int& n) {return dbgclgetValp(Name,val,n);} +inline int cldbggetBValp(const std::string& Name, bool& val, int& n) {return dbgclgetValp(Name,val,n);} +inline int cldbggetSValp(const std::string& Name, std::string& val, int& n) {return dbgclgetValp(Name,val,n);} -int cldbggetIValp(const std::string& Name, int& val, int& n, SMap& smap) {return dbgclgetValp(Name,val,n,smap);} -int cldbggetFValp(const std::string& Name, float& val, int& n, SMap& smap) {return dbgclgetValp(Name,val,n,smap);} -int cldbggetBValp(const std::string& Name, bool& val, int& n, SMap& smap) {return dbgclgetValp(Name,val,n, smap);} -int cldbggetSValp(const std::string& Name, std::string& val, int& n, SMap& smap) {return dbgclgetValp(Name,val,n,smap);} +inline int cldbggetIValp(const std::string& Name, int& val, int& n, SMap& smap) {return dbgclgetValp(Name,val,n,smap);} +inline int cldbggetFValp(const std::string& Name, float& val, int& n, SMap& smap) {return dbgclgetValp(Name,val,n,smap);} +inline int cldbggetBValp(const std::string& Name, bool& val, int& n, SMap& smap) {return dbgclgetValp(Name,val,n, smap);} +inline int cldbggetSValp(const std::string& Name, std::string& val, int& n, SMap& smap) {return dbgclgetValp(Name,val,n,smap);} -int cldbggetNIValp(const std::string& Key, std::vector& val, int& m) {return dbgclgetValp(Key, val, m);} -int cldbggetNFValp(const std::string& Key, std::vector& val, int& m) {return dbgclgetValp(Key, val, m);} -int cldbggetNBValp(const std::string& Key, std::vector& val, int& m) {return dbgclgetValp(Key, val, m);} -int cldbggetNSValp(const std::string& Key, std::vector& val, int& m) {return dbgclgetValp(Key, val, m);} +inline int cldbggetNIValp(const std::string& Key, std::vector& val, int& m) {return dbgclgetValp(Key, val, m);} +inline int cldbggetNFValp(const std::string& Key, std::vector& val, int& m) {return dbgclgetValp(Key, val, m);} +inline int cldbggetNBValp(const std::string& Key, std::vector& val, int& m) {return dbgclgetValp(Key, val, m);} +inline int cldbggetNSValp(const std::string& Key, std::vector& val, int& m) {return dbgclgetValp(Key, val, m);} -int cldbggetNIValp(const std::string& Key, std::vector& val, int& m, SMap& smap) {return dbgclgetValp(Key, val, m,smap);} -int cldbggetNFValp(const std::string& Key, std::vector& val, int& m, SMap& smap) {return dbgclgetValp(Key, val, m,smap);} -int cldbggetNBValp(const std::string& Key, std::vector& val, int& m, SMap& smap) {return dbgclgetValp(Key, val, m,smap);} -int cldbggetNSValp(const std::string& Key, std::vector& val, int& m, SMap& smap){return dbgclgetValp(Key, val, m,smap);} +inline int cldbggetNIValp(const std::string& Key, std::vector& val, int& m, SMap& smap) {return dbgclgetValp(Key, val, m,smap);} +inline int cldbggetNFValp(const std::string& Key, std::vector& val, int& m, SMap& smap) {return dbgclgetValp(Key, val, m,smap);} +inline int cldbggetNBValp(const std::string& Key, std::vector& val, int& m, SMap& smap) {return dbgclgetValp(Key, val, m,smap);} +inline int cldbggetNSValp(const std::string& Key, std::vector& val, int& m, SMap& smap){return dbgclgetValp(Key, val, m,smap);} #endif diff --git a/code/clgetValp.h b/code/clgetValp.h index acaef64..e11c489 100644 --- a/code/clgetValp.h +++ b/code/clgetValp.h @@ -17,15 +17,8 @@ * */ // -// Generic baseclass type functions that are called in clget?Valp() -// functions. -// -// The code is separated into clgetBaseCode() and clgetGenericValp() -// functions since the code to return the value from the Symbol is -// differen, at least for T=string. clgetGenericValp() function has -// this code for T=int,float,bool and is therefore usable for -// realizing clget{I,F,B}Valp() functions. clgetSValp() calls -// clgetBaseCode() directly. +// API level include file to use clgetValp() style, or +// clget[N][IFBS]Val() style function. // #ifndef CLGETVALP_H #define CLGETVALP_H @@ -33,5 +26,9 @@ #include #include #include -#include +// +//---------------------------------------------------------------------- +// Templated code and wrapper functions +// +#include #endif diff --git a/code/support.cc b/code/support.cc index be13dc0..86df2f4 100644 --- a/code/support.cc +++ b/code/support.cc @@ -238,11 +238,6 @@ extern "C" { if ((fd1=creat(err,0644))<0) { perror(out); - /* - if (clThrowUp("In STDERR redirection.","###Error", - CL_SEVERE)==CL_SEVERE) - exit(-1); - */ clThrowUp("In STDERR redirection.","###Error", CL_SEVERE); } diff --git a/code/test/testing.text b/code/test/testing.text index 4328390..078210f 100644 --- a/code/test/testing.text +++ b/code/test/testing.text @@ -1,24 +1,24 @@ -1. Run the app in the help=noprompt mode without app.def and no +[DONE] 1. Run the app in the help=noprompt mode without app.def and no settings. The printed values should be the factory defaults. -2. app help=noprompt = should print for corresponding +[DONE] 2. app help=noprompt = should print for corresponding on commandline and factory defaults for everything else. -3. app help=def should return an error. +[DONE] 3. app help=def should return an error. -4. Setup app.def. Run app. Should return the settings for keys found +[DONE] 4. Setup app.def. Run app. Should return the settings for keys found in app.def and factory defaults for everything else. -5. app help=def should work as if app help=prompt and the "go" command +[DONE] 5. app help=def should work as if app help=prompt and the "go" command is used. -6. app help=def,tt.def should return error +[DONE] 6. app help=def,tt.def should return error -7. Setup tt.def with some key settings missing. app help=def,tt.def +[DONE] 7. Setup tt.def with some key settings missing. app help=def,tt.def should return the settings of keys found in tt.def and factory defaults for everything else. -8. app followed by "load !" should set all keys found in +[DONE] 8. app followed by "load !" should set all keys found in that were not already set (complement load). "keys that were not already set" really means keys that take string values and are currently blank. All other keys would be set one way or another -- @@ -26,6 +26,6 @@ 9. Test for app help=defdbg -10. Test for app help=params. Verify the output format and the +[DONE] 10. Test for app help=params. Verify the output format and the various tokens. diff --git a/code/test/unittest/ParafeedTest.h b/code/test/unittest/ParafeedTest.h index dcbb362..c2ebbae 100644 --- a/code/test/unittest/ParafeedTest.h +++ b/code/test/unittest/ParafeedTest.h @@ -8,35 +8,201 @@ #include #include #include +#include +#include string cmd_g; -bool firstPass=true; +bool firstPass_g=true; size_t cmd_pos_g=0; -class ParafeedTest : public ::testing::Test { +// +//-------------------------------------------------------------------- +// Factored out re-usable code into global functions +// +auto makeDefFile=[](std::vector& args, + std::string defFile=std::string(), + std::string help=std::string()) +{ + if (!defFile.empty()) + { + std::ofstream ofs(defFile); + for(int i=1;i args + { + "test2", + "bool=true", + "bool1=false", + "int=42", + "dbgint=77", + "float=2.71", + "oneint=atan(1)*4/PI*100+23", + "string=showstrarr", + "strarr=val1,val2", + "fullval=custom_value", + "dbgfullval=debug_value", + "farray=9.9,8.8,7.7" + }; + + return args; +}; +// +//-------------------------------------------------------------------- +// +auto makeCanonicalArgs=[](std::string defFile=std::string(), + std::string help=std::string()) +{ + auto args=canonicalArgs(); + makeDefFile(args,defFile,help); + + return args; +}; +// +//-------------------------------------------------------------------- +// +auto canonicalTest=[]() +{ + int i; + + // bool + bool b = false; + SMap watchPoints; + VString exposedKeys = {"bool1"}; + watchPoints["1"] = exposedKeys; + i = 1; + clgetValp("bool", b, i, watchPoints); + EXPECT_TRUE(b); + + // bool1 + bool b1 = true; + ClearMap(watchPoints); + exposedKeys = {"int"}; + watchPoints["0"] = exposedKeys; + i = 1; + clgetValp("bool1", b1, i, watchPoints); + EXPECT_FALSE(b1); + + // int + int intVal = 0; + ClearMap(watchPoints); + exposedKeys = {"float"}; + watchPoints["1"] = exposedKeys; + i = 1; + clgetValp("int", intVal, i, watchPoints); + EXPECT_EQ(intVal, 42); + + // dbgint + int dbgInt = 0; + i = 1; + cldbggetValp("dbgint", dbgInt, i); + EXPECT_EQ(dbgInt, 77); + + // float + float fVal = 0.0f; + i = 1; + clgetValp("float", fVal, i); + EXPECT_FLOAT_EQ(fVal, 2.71f); + + // oneint + int oneintVal = 0; + i = 1; + clgetValp("oneint", oneintVal, i); + EXPECT_EQ(oneintVal, 123); + + // string + std::string str; + ClearMap(watchPoints); + exposedKeys = {"strarr"}; + watchPoints["showstrarr"] = exposedKeys; + exposedKeys = {"fullval"}; + watchPoints["showfullval"] = exposedKeys; + str = "showstrarr"; + i = 1; + clgetValp("string", str, i, watchPoints); + EXPECT_EQ(str, "showstrarr"); + + // { + // char sstr[100]; + // clgetSVal("string", sstr, &i, watchPoints); + // //EXPECT_EQ(sstr, "showstrarr");// DOES NOT WORK! + // EXPECT_EQ(sstr, str); + + // clgetSVal("string", sstr, &i); + // //EXPECT_EQ(sstr, "showstrarr");// DOES NOT WORK! + // EXPECT_EQ(sstr, str); + // } + + // fullval + std::string fullVal; + i = 0; + clgetFullValp("fullval", fullVal); + EXPECT_EQ(fullVal, "custom_value"); + + // dbgfullval + std::string dbgFullVal; + i = 0; + dbgclgetFullValp("dbgfullval", dbgFullVal); + EXPECT_EQ(dbgFullVal, "debug_value"); + + // strarr + VString strarr; + i = 0; + clgetValp("strarr", strarr, i); + ASSERT_EQ(strarr.size(), 2u); + EXPECT_EQ(strarr[0], "val1"); + EXPECT_EQ(strarr[1], "val2"); + + // farray + std::vector fv(3); + int N = 3; + int count = clgetValp("farray", fv, N); + EXPECT_EQ(count, 3); + EXPECT_FLOAT_EQ(fv[0], 9.9f); + EXPECT_FLOAT_EQ(fv[1], 8.8f); + EXPECT_FLOAT_EQ(fv[2], 7.7f); +}; +// +//-------------------------------------------------------------------- +// +class ParafeedTest : public ::testing::Test +{ public: ~ParafeedTest() { clCleanUp(); // Reset the input mechanism for the scanner/parser set_shell_input(backup_cl_shell_input_g); - firstPass=true; + firstPass_g=true; cmd_pos_g=0; } - + // //------------------------------------------------------------------ // Function that can supply the input to the scanner/parser from a // string (here the global cmd_g variable). static int test_shell_inp(char *buf, size_t max_size) { - if (!firstPass || cmd_pos_g >= cmd_g.size()) return 0; + if (!firstPass_g || cmd_pos_g >= cmd_g.size()) return 0; const size_t n_to_copy = std::min(max_size, cmd_g.size() - cmd_pos_g); std::memcpy(buf, cmd_g.data() + cmd_pos_g, n_to_copy); cmd_pos_g += n_to_copy; - if (cmd_pos_g >= cmd_g.size()) firstPass=false; + if (cmd_pos_g >= cmd_g.size()) firstPass_g=false; + + // Show the buffer passed to the caller (shell.l::YYINPUT). + cerr << "< "; + for(uint i=0;i(n_to_copy); } - + // //------------------------------------------------------------------ // Set the string for the scanner in test_shell_inp(). Save the // current input function for the scanner before resetting the @@ -44,7 +210,7 @@ class ParafeedTest : public ::testing::Test { void sendCmd(const string& cmd) { cmd_g=cmd; - firstPass=true; + firstPass_g=true; cmd_pos_g=0; backup_cl_shell_input_g=get_shell_input(); set_shell_input(test_shell_inp); @@ -53,19 +219,60 @@ class ParafeedTest : public ::testing::Test { std::function backup_cl_shell_input_g; protected: - std::pair MakeArgv(const std::vector& args) { - char** argv = new char*[args.size()]; - for (size_t i = 0; i < args.size(); ++i) { - argv[i] = new char[args[i].size() + 1]; - std::strcpy(argv[i], args[i].c_str()); - } - return {static_cast(args.size()), argv}; - } + // C-style argv array + std::vector argv_p; - void FreeArgv(int argc, char** argv) { - for (int i = 0; i < argc; ++i) { - delete[] argv[i]; - } - delete[] argv; - } + // + // Code inspired from an example on Stackoverflow. This does not + // need explicit memory allocation, and therefore is leak-free. + // However, the generated argc,argv pair is not available outside + // the scope if the argv_p variable (which currently is the class + // scope). + // + std::pair MakeArgv(std::vector& string_args) + { + argv_p.resize(0); + // .data() provides the char* pointer needed for C-style arrays + // push these into the class data member, available for the life + // of the class instance. + for (auto& s : string_args) +#if __cplusplus == 199711L + // Code specific to C++98 + argv_p.push_back((char *)(s.c_str())); +#else + argv_p.push_back(s.data()); +#endif + + // The following was in the original example, but seems not necessary + // argv.push_back(nullptr); + + return std::pair(static_cast(argv_p.size()), argv_p.data()); + } + + // Dummy method. + inline void FreeArgv(int argc, char **argv) {}; + + // + // The code below generates the argc,argv pair that is usable + // outside the class scope, but it requires explicity freeing the + // allocate memory without which there will be a memory leak. + // + // std::pair MakeArgv(const std::vector& args) + // { + // char** argv = new char*[args.size()]; + // for (size_t i = 0; i < args.size(); ++i) + // { + // argv[i] = new char[args[i].size() + 1]; + // std::strcpy(argv[i], args[i].c_str()); + // } + // return {static_cast(args.size()), argv}; + // } + // void FreeArgv(int argc, char** argv) + // { + // for (int i = 0; i < argc; ++i) + // { + // delete[] argv[i]; + // } + // delete[] argv; + // } }; diff --git a/code/test/unittest/test_parafeed_interactive.cpp b/code/test/unittest/test_parafeed_interactive.cpp index f8ef97e..1c90b2c 100644 --- a/code/test/unittest/test_parafeed_interactive.cpp +++ b/code/test/unittest/test_parafeed_interactive.cpp @@ -1,112 +1,206 @@ #include // +// Test the canonical Args setting in the interactive mode. This has +// "bool1=false int=42" setting. Check that bool1=false exposes +// "int", and "int=42" keeps "float" hidden. +// +TEST_F(ParafeedTest, InteractiveCanonical) +{ + std::vector args=makeCanonicalArgs("","help=dbg"); + auto [argc, argv] = MakeArgv(args); + sendCmd("go\n"); + BeginCL(argc, argv); + { + clInteractive(0); + + canonicalTest(); + + // Get a pointer to the named symbol from the internal symbol + // table. + // + // The following keys should be of the CL_DBGCLASS class and + // CL_DBG_ON==true. In the interactive shell, these keys will be + // visible. + // + Symbol *S; + S=SearchVSymb("dbgint"); + EXPECT_EQ(CL_DBG_ON && S->Class==CL_DBGCLASS, true); + + S=SearchVSymb("dbgfullval"); + EXPECT_EQ(CL_DBG_ON && S->Class==CL_DBGCLASS, true); + + if (cl_Pass > 0) + { + S=SearchVSymb("int"); + EXPECT_NE(S,nullptr); EXPECT_EQ(S->Exposed,1); + + S=SearchVSymb("float"); + EXPECT_NE(S,nullptr); EXPECT_EQ(S->Exposed,0); + } + } + EndCL(); + FreeArgv(argc, argv); +} +// //-------------------------------------------------------------------- +// Test for incorrect values in argv. Here, oneint=x, instead of a +// valid number. In the first pass (cl_Pass==0), an exception should +// be thrown. The second pass, after the correct input to the parser +// ("oneint=100"), no exception should be thrown. // -TEST_F(ParafeedTest, Interactive) { - std::vector args = { - "test2", - //"help=noprompt", - "bool=1", - "oneint=x", - "string=showstrarr", - "strarr=foo,bar", - "farray=1,3,4,5,6,7,8,9,10" +TEST_F(ParafeedTest, InteractiveWrongArgv) +{ + std::vector args = + { + "test2", + //"help=noprompt", + "bool=1", + "oneint=x", + "string=showstrarr", + "strarr=foo,bar", + "farray=1,3,4,5,6,7,8,9,10" }; - auto [argc, argv] = MakeArgv(args); + auto [argc, argv] = MakeArgv(args); - clCleanUp(); - // sendCmd() sets the parser input stream to be the given string. - // The parser scans this string in the interactive shell (started - // in the EndCL() call below). - sendCmd("bool=true\noneint=100\ninp\ngo\n"); + // sendCmd() sets the parser input stream to be the given string. + // The parser scans this string in the interactive shell (started + // in the EndCL() call below). + sendCmd("bool=true\n oneint=100\n fullval=this is full val\n inp\n go\n"); - BeginCL(argc, argv); - clInteractive(1); + BeginCL(argc, argv); + clInteractive(1); - bool b = false; - int oneint = 0; - int N = 10; - int i = 1; + bool b = false; + int oneint = 0; + int N = 10; + int i = 1; - std::string s; - std::vector strarr; - std::vector farray(N); + std::string s; + std::vector strarr; + std::vector farray(N); + string fullVal="this is the default value"; - i=1;clgetValp("bool", b, i); - - i=1; + i=1;clgetValp("bool", b, i); - // - // The setting from argv is used in the first pass - // (a.k.a. "registeration pass"). Without the "help=noprompt" - // detected in this first pass, the EndCL() call starts the - // interactive shell, which triggers the second pass on the "go" - // command (setjmp() called in EndCL() to restart execution from - // the location of the clInteractive() call). In this second pass - // the interactive settings (here, vis the sendCmd() call) - // replaces the values which are then available in the clgetValp() - // calls. - // - if (cl_Pass == 0) // cl_Pass is a global parafeed lib. control - // variable - EXPECT_THROW(clgetValp("oneint", oneint, i),clError); - else - clgetValp("oneint", oneint, i); - - i=1;clgetValp("string", s, i); + i=1; - i=0;clgetValp("strarr", strarr, i); + // + // The setting from argv is used in the first pass + // (a.k.a. "registeration pass"). Without the "help=noprompt" + // detected in this first pass, the EndCL() call starts the + // interactive shell, which triggers the second pass on the "go" + // command (setjmp() called in EndCL() to restart execution from + // the location of the clInteractive() call). In this second pass + // the interactive settings (here, vis the sendCmd() call) + // replaces the values which are then available in the clgetValp() + // calls. + // + if (cl_Pass == 0) // cl_Pass is a global parafeed lib. control + // variable + EXPECT_THROW(clgetValp("oneint", oneint, i),clError); + else + clgetValp("oneint", oneint, i); - clgetValp("farray", farray, N); - - EndCL(); + i=1;clgetValp("string", s, i); - // Expect the value as set interactively vis sendCmd() - EXPECT_EQ(oneint,100); + i=0;clgetValp("strarr", strarr, i); - FreeArgv(argc, argv); -} + clgetValp("farray", farray, N); + + i=0;clgetFullValp("fullval",fullVal); + + EndCL(); -TEST_F(ParafeedTest, InteractiveWrongType) { - std::vector args = { - "test2", - //"help=noprompt", - "bool=1", - "oneint=1", - "string=showstrarr", - "strarr=foo,bar", - "farray=1,3,4,5,6,7,8,9,10" + // Expect the value as set interactively vis sendCmd() + EXPECT_EQ(oneint,100); + EXPECT_EQ(fullVal,"this is full val"); + + FreeArgv(argc, argv); +} +// +//-------------------------------------------------------------------- +// Test for incorrect values set in the interactive shell (here, +// bool=xtrue). The interactive shell, started in EndCL(), should +// throw and exception. +// +TEST_F(ParafeedTest, InteractiveWrongType) +{ + std::vector args = + { + "test2", + //"help=noprompt", + "bool=1", + "oneint=1", + "string=showstrarr", + "strarr=foo,bar", + "farray=1,3,4,5,6,7,8,9,10" }; - auto [argc, argv] = MakeArgv(args); + auto [argc, argv] = MakeArgv(args); + + // Interactively set the wrong type for bool + sendCmd("oneint=100\n bool=xtrue\n inp\n go\n"); + + BeginCL(argc, argv); + clInteractive(1); + + bool b = false; + int oneint = 0; + int N = 10; + int i = 1; + std::string s; + std::vector strarr; + std::vector farray(N); + + i=1;clgetValp("bool", b, i); + + i=1;clgetValp("oneint", oneint, i); - clCleanUp(); - // Interactively set the wrong type for bool - sendCmd("oneint=100\nbool=xtrue\ninp\ngo\n"); + i=1;clgetValp("string", s, i); - BeginCL(argc, argv); - clInteractive(1); + i=0;clgetValp("strarr", strarr, i); - bool b = false; - int oneint = 0; - int N = 10; - int i = 1; - std::string s; - std::vector strarr; - std::vector farray(N); + clgetValp("farray", farray, N); + + // Exception thrown in the interactive shell due to illegal + // keyword setting (bool=xtrue) via sendCmd() + EXPECT_THROW(EndCL(),clError); + + FreeArgv(argc, argv); +} +// +//-------------------------------------------------------------------- +// Test Complementary load: Load defFile with a "!" at the end to set +// only those variables from the defFile which aren't already set. In +// practice this applies only to keys that take string values and are +// currently blank. All other keys would be set one way or another -- +// either as factory defaults, or via app.def or via user interaction. +// +TEST_F(ParafeedTest, InteractiveComplementaryLoad) +{ + std::string defFile="tt.def"; + std::remove(defFile.c_str()); + std::vector args=makeCanonicalArgs(defFile,""); + // + // defFile sets strarr=val1,val2. Set strarr to something else + // interactively, do a complementary load and test that it has the + // values set interactively (and not val1,val2). + // + sendCmd("strarr=blah1,blah2\n load "+defFile+"!\n inp\n go\n"); - i=1;clgetValp("bool", b, i); + auto [argc, argv] = MakeArgv(args); + std::vector strarr; - i=1;clgetValp("oneint", oneint, i); + BeginCL(argc, argv); - i=1;clgetValp("string", s, i); + clInteractive(1); - i=0;clgetValp("strarr", strarr, i); + int i=0;clgetValp("strarr", strarr, i); - clgetValp("farray", farray, N); + EndCL(); - // Exception thrown in the interactive shell due to illegal - // keyword setting (bool=xtrue) via sendCmd() - EXPECT_THROW(EndCL(),clError); + ASSERT_EQ(strarr.size(), 2u); + EXPECT_EQ(strarr[0], "blah1"); + EXPECT_EQ(strarr[1], "blah2"); - FreeArgv(argc, argv); + std::remove(defFile.c_str()); } diff --git a/code/test/unittest/test_parafeed_noninteractive.cpp b/code/test/unittest/test_parafeed_noninteractive.cpp index 1659328..db39764 100644 --- a/code/test/unittest/test_parafeed_noninteractive.cpp +++ b/code/test/unittest/test_parafeed_noninteractive.cpp @@ -1,296 +1,467 @@ #include -#include - // // --------------------------------------------------------------------------------- // -TEST_F(ParafeedTest, ParsesClgetValpParametersCorrectly) { - std::vector args = { - "test2", - "help=noprompt", - "bool=true", - "bool1=false", - "int=42", - "dbgint=77", - "float=2.71", - "oneint=123", - "string=showstrarr", - "strarr=val1,val2", - "fullval=custom_value", - "dbgfullval=debug_value", - "farray=9.9,8.8,7.7" - }; - auto [argc, argv] = MakeArgv(args); +TEST_F(ParafeedTest, ParsesClgetValpParametersCorrectly) +{ + std::vector args=makeCanonicalArgs("","help=noprompt"); + auto [argc, argv] = MakeArgv(args); - BeginCL(argc, argv); + BeginCL(argc, argv); + { clInteractive(0); - int i; - - // bool - bool b = false; - SMap watchPoints; - VString exposedKeys = {"bool1"}; - watchPoints["1"] = exposedKeys; - i = 1; - clgetValp("bool", b, i, watchPoints); - EXPECT_TRUE(b); - - // bool1 - bool b1 = true; - ClearMap(watchPoints); - exposedKeys = {"int"}; - watchPoints["0"] = exposedKeys; - i = 1; - clgetValp("bool1", b1, i, watchPoints); - EXPECT_FALSE(b1); - - // int - int intVal = 0; - ClearMap(watchPoints); - exposedKeys = {"float"}; - watchPoints["1"] = exposedKeys; - i = 1; - clgetValp("int", intVal, i, watchPoints); - EXPECT_EQ(intVal, 42); - - // dbgint - int dbgInt = 0; - i = 1; - cldbggetValp("dbgint", dbgInt, i); - EXPECT_EQ(dbgInt, 77); - - // float - float fVal = 0.0f; - i = 1; - clgetValp("float", fVal, i); - EXPECT_FLOAT_EQ(fVal, 2.71f); - - // oneint - int oneintVal = 0; - i = 1; - clgetValp("oneint", oneintVal, i); - EXPECT_EQ(oneintVal, 123); - - // string - std::string str; - ClearMap(watchPoints); - exposedKeys = {"strarr"}; - watchPoints["showstrarr"] = exposedKeys; - exposedKeys = {"fullval"}; - watchPoints["showfullval"] = exposedKeys; - str = "showstrarr"; - i = 1; - clgetValp("string", str, i, watchPoints); - EXPECT_EQ(str, "showstrarr"); - - // fullval - std::string fullVal; - i = 0; - clgetFullValp("fullval", fullVal); - EXPECT_EQ(fullVal, "custom_value"); - - // dbgfullval - std::string dbgFullVal; - i = 0; - dbgclgetFullValp("dbgfullval", dbgFullVal); - EXPECT_EQ(dbgFullVal, "debug_value"); - - // strarr - VString strarr; - i = 0; - clgetValp("strarr", strarr, i); - ASSERT_EQ(strarr.size(), 2u); - EXPECT_EQ(strarr[0], "val1"); - EXPECT_EQ(strarr[1], "val2"); - - // farray - std::vector fv(3); - int N = 3; - int count = clgetValp("farray", fv, N); - EXPECT_EQ(count, 3); - EXPECT_FLOAT_EQ(fv[0], 9.9f); - EXPECT_FLOAT_EQ(fv[1], 8.8f); - EXPECT_FLOAT_EQ(fv[2], 7.7f); - - EndCL(); - FreeArgv(argc, argv); + canonicalTest(); + // + // The following keys should be of the CL_DBGCLASS class and + // CL_DBG_ON==false. + // + Symbol *S; + S=SearchVSymb("dbgint"); + EXPECT_EQ(!CL_DBG_ON && S->Class==CL_DBGCLASS, true); + + S=SearchVSymb("dbgfullval"); + EXPECT_EQ(!CL_DBG_ON && S->Class==CL_DBGCLASS, true); + + } + EndCL(); + FreeArgv(argc, argv); } -TEST_F(ParafeedTest, TextColouringHandlesMissingTermEnvironment) { - const char* originalTerm = std::getenv("TERM"); - std::string originalTermValue = originalTerm ? originalTerm : ""; +TEST_F(ParafeedTest, TextColouringHandlesMissingTermEnvironment) +{ + const char* originalTerm = std::getenv("TERM"); + std::string originalTermValue = originalTerm ? originalTerm : ""; - unsetenv("TERM"); + unsetenv("TERM"); - std::string startSeq; - std::string endSeq; - EXPECT_NO_THROW(clTextColouring("keyword", CL_HIDDENKEYWORD, startSeq, endSeq)); + std::string startSeq; + std::string endSeq; + EXPECT_NO_THROW(clTextColouring("keyword", CL_HIDDENKEYWORD, startSeq, endSeq)); - if (originalTerm) { - setenv("TERM", originalTermValue.c_str(), 1); - } else { - unsetenv("TERM"); - } + if (originalTerm) + setenv("TERM", originalTermValue.c_str(), 1); + else + unsetenv("TERM"); } // below tests can be included when parafeed throws on these wrong usage. -TEST_F(ParafeedTest, PrintsErrorOnUnknownParameter) { - std::vector args = { - "test2", - "help=noprompt", - "bool=true" - // "unknownparam=badvalue" // This will add the named parameter to the symbol table. - // The library allows user-defined symbols. +TEST_F(ParafeedTest, PrintsErrorOnUnknownParameter) +{ + std::vector args = + { + "test2", + "help=noprompt", + "bool=true" + // "unknownparam=badvalue" // This will add the named parameter to the symbol table. + // The library allows user-defined symbols. }; - auto [argc, argv] = MakeArgv(args); + auto [argc, argv] = MakeArgv(args); - BeginCL(argc, argv); - clInteractive(0); + BeginCL(argc, argv); + clInteractive(0); - // Try accessing only the known parameter - bool b = false; - int i = 1; - clgetValp("bool", b, i); + // Try accessing only the known parameter + bool b = false; + int i = 1; + clgetValp("bool", b, i); - std::string unused; - i = 1; - clgetValp("unknownparam", unused, i); - EndCL(); + std::string unused; + i = 1; + clgetValp("unknownparam", unused, i); + EndCL(); - FreeArgv(argc, argv); + FreeArgv(argc, argv); } /*TEST_F(ParafeedTest, MissingRequiredParam) { - std::vector args = { - "test2", - "help=noprompt", - "bool=true", - "oneint=5", - "string=showstrarr", - // missing "strarr=" - "farray=1.0,2.0,3.0,4.0,5.0,6.0,7.0,8.0,9.0,10.0" + std::vector args = { + "test2", + "help=noprompt", + "bool=true", + "oneint=5", + "string=showstrarr", + // missing "strarr=" + "farray=1.0,2.0,3.0,4.0,5.0,6.0,7.0,8.0,9.0,10.0" + }; + auto [argc, argv] = MakeArgv(args); + + ::testing::internal::CaptureStdout(); + + BeginCL(argc, argv); + clInteractive(0); + + bool b = false; + int oneint = 0; + std::string s; + std::vector strarr; + std::vector farray(10); + int i = 1; + + clgetValp("bool", b, i); + clgetValp("oneint", oneint, i); + clgetValp("string", s, i); + + // attempt to access the missing "strarr" + int index = 0; + clgetValp("strarr", strarr, index); // Should produce error + + EndCL(); + + std::string output = ::testing::internal::GetCapturedStdout(); + FreeArgv(argc, argv); + + + EXPECT_NE(output.find("###Error"), std::string::npos) + << "Expected error message for missing 'strarr' not found in stdout:\n" << output; + } +*/ + +TEST_F(ParafeedTest, WrongDataType) +{ + std::vector args = + { + "test2", + "help=noprompt", + "bool=not_true", // Wrong data type + "oneint=not_int", // Wrong data type + "string=showstrarr", + "strarr=foo,bar", + "farray=1,x,3,4,5,6,7,8,9,10" // One wrong data type }; - auto [argc, argv] = MakeArgv(args); + auto [argc, argv] = MakeArgv(args); - ::testing::internal::CaptureStdout(); + BeginCL(argc, argv); + // clInteractive(0); - BeginCL(argc, argv); - clInteractive(0); + bool b = false; + int oneint = 0; + std::string s; + std::vector strarr; + std::vector farray(10); + int i = 1; + + EXPECT_THROW(clgetValp("bool", b, i),clError); + + // Should fail due to wrong type + EXPECT_THROW(clgetValp("oneint", oneint, i),clError); - bool b = false; - int oneint = 0; - std::string s; - std::vector strarr; - std::vector farray(10); - int i = 1; + clgetValp("string", s, i); + int idx = 0; + clgetValp("strarr", strarr, idx); + int N = 10; - clgetValp("bool", b, i); + EXPECT_THROW(clgetValp("farray", farray, N),clError); + + EndCL(); + + FreeArgv(argc, argv); +} + +// +//-------------------------------------------------------------------- +// This interactive test after non-interactive ones above tests if the +// internal state of the library is properly reset (in clCleanUp()). +// +TEST_F(ParafeedTest, Interactive) +{ + std::vector args = + { + "test2", + //"help=noprompt", + "bool=1", + "oneint=x", + "string=showstrarr", + "strarr=foo,bar", + "farray=1,3,4,5,6,7,8,9,10" + }; + auto [argc, argv] = MakeArgv(args); + + // sendCmd() sets the parser input stream to be the given string. + // The parser scans this string in the interactive shell (started + // in the EndCL() call below). + sendCmd("bool=true\noneint=100\ninp\ngo\n"); + + BeginCL(argc, argv); + clInteractive(1); + + bool b = false; + int oneint = 0; + int N = 10; + int i = 1; + + std::string s; + std::vector strarr; + std::vector farray(N); + + i=1;clgetValp("bool", b, i); + + i=1; + + // + // The setting from argv is used in the first pass + // (a.k.a. "registeration pass"). Without the "help=noprompt" + // detected in this first pass, the EndCL() call starts the + // interactive shell, which triggers the second pass on the "go" + // command (setjmp() called in EndCL() to restart execution from + // the location of the clInteractive() call). In this second pass + // the interactive settings (here, vis the sendCmd() call) + // replaces the values which are then available in the clgetValp() + // calls. + // + if (cl_Pass == 0) // cl_Pass is a global parafeed lib. control + // variable + EXPECT_THROW(clgetValp("oneint", oneint, i),clError); + else clgetValp("oneint", oneint, i); - clgetValp("string", s, i); - // attempt to access the missing "strarr" - int index = 0; - clgetValp("strarr", strarr, index); // Should produce error + i=1;clgetValp("string", s, i); - EndCL(); + i=0;clgetValp("strarr", strarr, i); - std::string output = ::testing::internal::GetCapturedStdout(); - FreeArgv(argc, argv); + clgetValp("farray", farray, N); + EndCL(); - EXPECT_NE(output.find("###Error"), std::string::npos) - << "Expected error message for missing 'strarr' not found in stdout:\n" << output; + // Expect the value as set interactively vis sendCmd() + EXPECT_EQ(oneint,100); + + FreeArgv(argc, argv); } -*/ -TEST_F(ParafeedTest, WrongDataType) { - std::vector args = { - "test2", - "help=noprompt", - "bool=not_true", // Wrong data type - "oneint=not_int", // Wrong data type - "string=showstrarr", - "strarr=foo,bar", - "farray=1,x,3,4,5,6,7,8,9,10" // One wrong data type +// +//-------------------------------------------------------------------- +// Test help=params mode +// +TEST_F(ParafeedTest, ParamsMode) +{ + std::vector args = + { + "test2", + "help=params" }; - auto [argc, argv] = MakeArgv(args); + auto [argc, argv] = MakeArgv(args); - BeginCL(argc, argv); - // clInteractive(0); + ::testing::internal::CaptureStdout(); - bool b = false; - int oneint = 0; - std::string s; - std::vector strarr; - std::vector farray(10); - int i = 1; + BeginCL(argc, argv); - EXPECT_THROW(clgetValp("bool", b, i),clError); - - // Should fail due to wrong type - EXPECT_THROW(clgetValp("oneint", oneint, i),clError); - - clgetValp("string", s, i); - int idx = 0; - clgetValp("strarr", strarr, idx); - int N = 10; + clInteractive(0); + + bool b = false; + int oneint = 0; + int N = 10; + int i = 1; + + std::string s; + std::vector strarr; + std::vector farray(N); + + i=1;clgetValp("bool", b, i); + + i=1;clgetValp("oneint", oneint, i); + + i=1;clgetValp("string", s, i); + + i=0;clgetValp("strarr", strarr, i); + + clgetValp("farray", farray, N); + + EndCL(); + std::string expected_output= + "%%N:test2\n" + "%%P:bool:bool:0:\n" + "%%P:oneint:int:0:\n" + "%%P:string:string::\n" + "%%P:strarr:string[]::\n" + "%%P:farray:float[10]:0,0,0,0,0,0,0,0,0,0:\n"; + + std::string output = ::testing::internal::GetCapturedStdout(); + EXPECT_EQ(output,expected_output); + + FreeArgv(argc, argv); +} +// +//-------------------------------------------------------------------- +// Test help=def[,Name] mode +// +TEST_F(ParafeedTest, DefMode) +{ + std::vector args = + { + "test2", + "help=def" + }; + auto [argc, argv] = MakeArgv(args); + + // help=def will look for test2.def file to load the parameters + // and throw an exception since test2.def does not exist + EXPECT_THROW(BeginCL(argc, argv),clError); + + clInteractive(0); + + bool b = false; + int oneint = 0; + int N = 10; + int i = 1; + + std::string s; + std::vector strarr; + std::vector farray(N); + + i=1;clgetValp("bool", b, i); + + i=1;clgetValp("oneint", oneint, i); + + i=1;clgetValp("string", s, i); + + i=0;clgetValp("strarr", strarr, i); + + clgetValp("farray", farray, N); + + EndCL(); + + FreeArgv(argc, argv); +} +// +//-------------------------------------------------------------------- +// +TEST_F(ParafeedTest, DefModeWithDefFile) +{ + std::string defFile0="test2.def", defFile1="tt.def"; + std::vector args; + + cerr << "[INFO]: With help=def," << defFile0 + << " BeginCL() will look for test2.def " + << "file to load the parameters and find it." + << endl; + + std::remove(defFile0.c_str()); + std::remove(defFile1.c_str()); - EXPECT_THROW(clgetValp("farray", farray, N),clError); - - EndCL(); + args=makeCanonicalArgs(defFile0,"help=def,"+defFile0); - FreeArgv(argc, argv); + for(auto s : args) cerr << s << " "; cerr << endl; + auto [argc, argv] = MakeArgv(args); + + BeginCL(argc, argv); + FreeArgv(argc, argv); + + canonicalTest(); + + EndCL(); + + std::remove(defFile0.c_str()); + std::remove(defFile1.c_str()); } +// +//-------------------------------------------------------------------- +// +TEST_F(ParafeedTest, DefModeWithoutDefFileError) +{ + std::string defFile0="test2.def", defFile1="tt.def"; + std::vector args; + + cerr << "[INFO]: With help=def" + << " by default BeginCL() will look for " << defFile0 + << "file to load the parameters and find it." + << endl; + + std::remove(defFile0.c_str()); + std::remove(defFile1.c_str()); + // + // With help="def" by default BeginCL() will look for + // test2.def file to load the parameters and find it. + // + args=makeCanonicalArgs(defFile0,"help=def"); + + for(auto s : args) cerr << s << " "; cerr << endl; + auto [argc, argv] = MakeArgv(args); + BeginCL(argc, argv); + FreeArgv(argc, argv); + + canonicalTest(); + + EndCL(); + + std::remove(defFile0.c_str()); + std::remove(defFile1.c_str()); +} // //-------------------------------------------------------------------- -// This does not yet work as expected. // -// TEST_F(ParafeedTest, Interactive) { -// std::vector args = { -// "test2", -// //"help=noprompt", -// "bool=1", // Wrong data type -// "oneint=1", // Wrong data type -// "string=showstrarr", -// "strarr=foo,bar", -// "farray=1,3,4,5,6,7,8,9,10" // One wrong data type -// }; -// auto [argc, argv] = MakeArgv(args); - -// clCleanUp(); -// sendCmd("bool=true\noneint=100\ninp\ngo\n"); -// //sendCmd("go\n"); -// BeginCL(argc, argv); -// clInteractive(1); - -// bool b = false; -// int oneint = 0; -// std::string s; -// std::vector strarr; -// std::vector farray(10); -// int i = 1; - -// // EXPECT_THROW(clgetValp("bool", b, i),clError); -// clgetValp("bool", b, i); - -// // Should fail due to wrong type -// clgetValp("oneint", oneint, i); - -// clgetValp("string", s, i); -// int idx = 0; -// clgetValp("strarr", strarr, idx); -// int N = 10; - -// clgetValp("farray", farray, N); - -// EndCL(); - -// EXPECT_EQ(oneint,100); - -// FreeArgv(argc, argv); -// } +TEST_F(ParafeedTest, DefModeWithDefFileError) +{ + std::string defFile0="test2.def", defFile1="tt.def"; + std::vector args; + + cerr << "[INFO]: With help=def" + << " by default BeginCL() will look for " << defFile0 + << " file to load the parameters and not find it (since, " + << defFile1 << " is saved)" + << " and throw an exception." + << endl; + + std::remove(defFile0.c_str()); + std::remove(defFile1.c_str()); + // + // With help="def" BeginCL() will look for + // test2.def file to load the parameters and not find it, + // and throw an exception + // + args=makeCanonicalArgs(defFile1,"help=def"); + + for(auto s : args) cerr << s << " "; cerr << endl; + auto [argc, argv] = MakeArgv(args); + + EXPECT_THROW(BeginCL(argc, argv),clError); + FreeArgv(argc, argv); + + canonicalTest(); + + EndCL(); + + std::remove(defFile0.c_str()); + std::remove(defFile1.c_str()); +} +// +//-------------------------------------------------------------------- +// +TEST_F(ParafeedTest, DefModeWithWrongDefFile) +{ + std::string defFile0="test2.def", defFile1="tt.def"; + std::vector args; + + cerr << "[INFO]: With help=def,"+defFile1 + << " BeginCL() will look for " << defFile1 + << " file to load the parameters and not find it (since " + << defFile0 << " is saved)" + << " and throw an exception." + << endl; + + std::remove(defFile0.c_str()); + std::remove(defFile1.c_str()); + // + // With help="def,+defFile1 BeginCL() will look for + // tt.def file to load the parameters and not find it, + // and throw an exception + // + args=makeCanonicalArgs(defFile0,"help=def,"+defFile1); + + for(auto s : args) cerr << s << " "; cerr << endl; + auto [argc, argv] = MakeArgv(args); + + EXPECT_THROW(BeginCL(argc, argv),clError); + FreeArgv(argc, argv); + + canonicalTest(); + + EndCL(); + + std::remove(defFile0.c_str()); + std::remove(defFile1.c_str()); +} diff --git a/code/tstcpp.cc b/code/tstcpp.cc index c9ceb15..828fb80 100644 --- a/code/tstcpp.cc +++ b/code/tstcpp.cc @@ -114,6 +114,10 @@ void UI(bool restart, int argc, char **argv) } EndCL(); } + catch (clExit& x) + { + exit(0); + } catch (clError& x) { x << x << endl;