Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 11 additions & 7 deletions src/CommandLine.cc
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ using namespace std;

/// strict weak ordering by flag (lexicographic).
bool Option::operator<(const _Option &b) const {
return std::strcmp(flag, b.flag) < 0;
return (flag && b.flag) ? std::strcmp(flag, b.flag) < 0 : (flag < b.flag);
}

ostream &operator<<(ostream &a, const Option &b) {
Expand All @@ -50,8 +50,12 @@ ostream &operator<<(ostream &a, const Option &b) {

CommandLine::CommandLine(const set<Option> &a) : logger(LogConfig()), option_s(a) {
for (auto option : a) {
flag_m.insert(make_pair(option.flag, option));
longname_m.insert(make_pair(option.longname, option));
if (option.flag) {
flag_m.insert(make_pair(option.flag, option));
}
if (option.longname) {
longname_m.insert(make_pair(option.longname, option));
}
}
}

Expand Down Expand Up @@ -131,11 +135,11 @@ bool CommandLine::is_set_option(const Option &a) const {
}

bool CommandLine::is_set_flag(const char *a) const {
return flag_m.find(a) != flag_m.end() && is_set_option(flag_m.find(a)->second);
return a && flag_m.find(a) != flag_m.end() && is_set_option(flag_m.find(a)->second);
}

bool CommandLine::is_set_longname(const char *a) const {
return longname_m.find(a) != longname_m.end() && is_set_option(longname_m.find(a)->second);
return a && longname_m.find(a) != longname_m.end() && is_set_option(longname_m.find(a)->second);
}

vector<vector<const char*> > CommandLine::get_values_for_option(const Option &a) const {
Expand All @@ -146,11 +150,11 @@ vector<vector<const char*> > CommandLine::get_values_for_option(const Option &a)
}

vector<vector<const char*> > CommandLine::get_values_for_flag(const char *a) const {
return flag_m.find(a) != flag_m.end() ? get_values_for_option(flag_m.find(a)->second) : vector<vector<const char*> >();
return (a && flag_m.find(a) != flag_m.end()) ? get_values_for_option(flag_m.find(a)->second) : vector<vector<const char*> >();
}

vector<vector<const char*> > CommandLine::get_values_for_longname(const char *a) const {
return longname_m.find(a) != longname_m.end() ? get_values_for_option(longname_m.find(a)->second) : vector<vector<const char*> >();
return (a && longname_m.find(a) != longname_m.end()) ? get_values_for_option(longname_m.find(a)->second) : vector<vector<const char*> >();
}

const char* CommandLine::get_arg_for_option(const Option &a, int i) const {
Expand Down
9 changes: 5 additions & 4 deletions src/csvjoin.cc
Original file line number Diff line number Diff line change
Expand Up @@ -50,9 +50,9 @@ const int join_option_n = sizeof(join_option_a)/sizeof(Option);

/// Extension to DefaultCommandLine: JoinCommandLine can derive join parameters from options.
class JoinCommandLine : public DefaultCommandLine {
pair<ColIvalV,ColIvalV> join_columns=make_pair(false,false);
const char *right_fname = NULL;
JoinType join_type=JOIN_INNER;
pair<ColIvalV,ColIvalV> join_columns;
const char *right_fname;
JoinType join_type;

int set_join_columns() {
if (!is_set_flag("jc")){
Expand Down Expand Up @@ -80,7 +80,8 @@ class JoinCommandLine : public DefaultCommandLine {
};
public:
JoinCommandLine(const string &desc, const string &usage) :
DefaultCommandLine(desc, usage,set<Option>(join_option_a,join_option_a+join_option_n)){};
DefaultCommandLine(desc, usage,set<Option>(join_option_a,join_option_a+join_option_n)),
join_columns(make_pair(false,false)),right_fname(nullptr),join_type(JoinType::JOIN_INNER){};

int process() {
// join type
Expand Down
166 changes: 166 additions & 0 deletions tests/CommandLine_test.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,166 @@
#include "CommandLine.h"
#include <sstream>
#include <string>
#include <cassert>
#include "stl_out.h"

using namespace std;

bool test_Option_print(const Option &obj, const string &expected) {
bool retv = true;

stringstream ss;
ss << obj;
string actual = ss.str();

retv = (actual == expected);
if (!retv) {
cerr << "actual: " << actual << endl;
cerr << "expected: " << expected << endl;
}
return retv;
}

bool vvchrptr_eq(const vector<vector<const char*>> &a, const vector<vector<const char*>> &b) {
bool retv = true;
if (a.size()!=b.size()) return false;
for (unsigned int i = 0; i<a.size(); ++i) {
if (a[i].size()!=b[i].size()) return false;
for (unsigned int j =0; j< a[i].size(); ++j) {
if (strcmp(a[i][j],b[i][j])) return false;
}
}
return retv;
}

bool test_CommandLine_getopt(CommandLine *obj, const Option &check_option, bool expected_found, const vector<vector<const char*> > &expected_values) {
bool retv = true;

bool actual_found_flag = obj->is_set_flag(check_option.flag);
bool actual_found_longname = obj->is_set_longname(check_option.longname);
bool actual_found_option = obj->is_set_option(check_option);

auto actual_val_flag = obj->get_values_for_flag(check_option.flag);
auto actual_val_longname = obj->get_values_for_longname(check_option.longname);
auto actual_val_option = obj->get_values_for_option(check_option);

if (actual_found_flag != expected_found) {
cerr << "is_set_flag mismatch\tflag: " << check_option.flag << "\tactual: " << actual_found_flag << "\texpected: " << expected_found << endl;
retv = false;
}
if (actual_found_longname != expected_found) {
cerr << "is_set_longname mismatch\tlongname: " << check_option.longname << "\tactual: " << actual_found_longname << "\texpected: " << expected_found << endl;
retv = false;
}
if (actual_found_option != expected_found) {
cerr << "is_set_option mismatch\toption: " << check_option << "\tactual: " << actual_found_option << "\texpected: " << expected_found << endl;
retv = false;
}
if (!vvchrptr_eq(actual_val_flag,expected_values)) {
cerr<<"get_values_for_flag mismatch\tflag: "<<check_option.flag<<endl;
cerr<<"actual: "<<actual_val_flag<<" vs. expected: "<<expected_values<<endl;
retv = false;
}
if (!vvchrptr_eq(actual_val_longname,expected_values)) {
cerr<<"get_values_for_longname mismatch\tlongname: "<<check_option.longname<<endl;
retv = false;
}
if (!vvchrptr_eq(actual_val_option,expected_values)) {
cerr<<"get_values_for_option mismatch\toption: "<<check_option<<endl;
retv = false;
}
if (retv) {
for (unsigned int i = 0; i<check_option.arg_num; ++i) {
auto actual_flag_val_i = obj->get_arg_for_flag(check_option.flag,i);
auto actual_longname_val_i = obj->get_arg_for_longname(check_option.longname,i);
auto actual_option_val_i = obj->get_arg_for_option(check_option,i);
if (expected_values.empty() || (expected_values[0].size() <= i)) {
if (actual_flag_val_i!=nullptr) {
cerr<<"get_arg_for_flag should have return nullptr\tflag"<<check_option.flag<<" arg #"<<i<<"actual: "<<actual_flag_val_i<<endl;
retv = false;
}
if (actual_longname_val_i!=nullptr) {
cerr<<"get_arg_for_longname should have return nullptr\tlongname"<<check_option.longname<<" arg #"<<i<<"actual: "<<actual_longname_val_i<<endl;
retv = false;
}
if (actual_option_val_i!=nullptr) {
cerr<<"get_arg_for_option should have return nullptr\toption"<<check_option<<" arg #"<<i<<"actual: "<<actual_option_val_i<<endl;
retv = false;
}
} else {
if (strcmp(actual_flag_val_i, expected_values[0][i])) {
cerr<<"get_arg_for_flag mismatch\tflag "<<check_option.flag<<" arg #"<<i<<"\t actual: "<<actual_flag_val_i<<" vs. expected: "<<expected_values[0][i]<<endl;
retv = false;
}
if (strcmp(actual_longname_val_i, expected_values[0][i])) {
cerr<<"get_arg_for_longname mismatch\tlongname "<<check_option.longname<<" arg #"<<i<<"\t actual: "<<actual_longname_val_i<<" vs. expected: "<<expected_values[0][i]<<endl;
retv = false;
}
if (strcmp(actual_option_val_i, expected_values[0][i])) {
cerr<<"get_arg_for_option mismatch\toption "<<check_option<<" arg #"<<i<<"\t actual: "<<actual_option_val_i<<" vs. expected: "<<expected_values[0][i]<<endl;
retv = false;
}
}
}
}
return retv;
}

class TestCommandLine : public CommandLine {

int process() {
return 0;
}
public:

TestCommandLine(const set<Option> &_opts) : CommandLine(_opts) {
}

CommandLineExecuteResponse execute(int argc, const char *a[]) {
parse(argc, a);
return CommandLineExecuteResponse::CMDLINE_OK;
}
};

int main(int argc, const char *argv[]) {
Option opt1 = {"a", "append", 2, MultipleDefinition::APPEND, "This is opt1.\n"};
Option opt1_noflag = {nullptr, "append", 2, MultipleDefinition::APPEND, "This is opt1.\n"};
Option opt1_nolongname = {"a", nullptr, 2, MultipleDefinition::APPEND, "This is opt1.\n"};
Option opt1_nohelp = {"a", "append", 2, MultipleDefinition::APPEND, nullptr};
Option opt1_nothing = {nullptr, nullptr, 2, MultipleDefinition::APPEND, nullptr};

assert(test_Option_print(opt1, "-a\t--append=<arg1> <arg2>\tThis is opt1.\n"));
assert(test_Option_print(opt1_noflag, "\t--append=<arg1> <arg2>\tThis is opt1.\n"));
assert(test_Option_print(opt1_nolongname, "-a\tThis is opt1.\n"));
assert(test_Option_print(opt1_nohelp, "-a\t--append=<arg1> <arg2>"));
assert(test_Option_print(opt1_nothing, ""));

Option opts[] = {
{"a", "alpha", 0, MultipleDefinition::IGNORE, "This is option alpha."},
{"b", "bravo", 1, MultipleDefinition::IGNORE, "This is option bravo."},
{"c", "charlie", 2, MultipleDefinition::OVERRIDE, "This is option charlie."},
{"d", "delta", 1, MultipleDefinition::OVERRIDE, "This is option delta."}
};
TestCommandLine cmdline0(set<Option>(opts, opts + sizeof (opts) / sizeof (opts[0])));
TestCommandLine cmdline1=cmdline0;
const char *cmdline0args[] = {"progname", "-a", "-b", "1"};
cmdline0.execute(4, cmdline0args);
const char *cmdline1args[] = {"progname", "-b", "1", "-b", "2", "--charlie=a", "b", "--charlie=c", "d"};
cmdline1.execute(9, cmdline1args);

assert(test_CommandLine_getopt(&cmdline0, opts[0], true, {{}}));
assert(test_CommandLine_getopt(&cmdline0, opts[1], true, {{"1"}}));
assert(test_CommandLine_getopt(&cmdline0, opts[2], false, {}));
assert(test_CommandLine_getopt(&cmdline0, opts[3], false, {}));

assert(test_CommandLine_getopt(&cmdline0, opt1_noflag, false, {}));
assert(test_CommandLine_getopt(&cmdline0, opt1_nothing, false, {}));


assert(test_CommandLine_getopt(&cmdline1, opts[0], false, {}));
assert(test_CommandLine_getopt(&cmdline1, opts[1], true, {{"1"}}));
assert(test_CommandLine_getopt(&cmdline1, opts[2], true, {{"c","d"}}));
assert(test_CommandLine_getopt(&cmdline1, opts[3], false, {}));

return 0;
}
6 changes: 3 additions & 3 deletions tests/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ TESTS = \
ColIval_ctor_test \
ColIvalV_ctor_test \
ColIvalV_extract_ival_test \
CommandLine_test \
CsvCell_ctor_test \
CsvCell_decimal_test \
CsvCell_less_test \
Expand All @@ -19,6 +20,7 @@ check_PROGRAMS = \
ColIval_ctor_test \
ColIvalV_ctor_test \
ColIvalV_extract_ival_test \
CommandLine_test \
CsvCell_ctor_test \
CsvCell_decimal_test \
CsvCell_less_test \
Expand All @@ -37,9 +39,7 @@ BUILT_SOURCES =
AM_CXXFLAGS = -I${top_srcdir}/src
LDADD = ../src/libcsvtools.a

#strsplit_test_SOURCES=strsplit_test.cc ../src/CommandLine.cc
#stdrowfuncs_test_SOURCES=stdrowfuncs_test.cc ../src/Numeric.cc ../src/RowFunc.cc
#stdrowfuncs_test_OBJS=stdrowfuncs_test.cc src/Numeric.o src/RowFunc.o
CommandLine_test_LDADD=../src/CommandLine.o ../src/libcsvtools.a
strsplit_test_LDADD=../src/CommandLine.o ../src/libcsvtools.a
stdrowfuncs_test_LDADD= ../src/Numeric.o ../src/RowFunc.o

Expand Down
1 change: 1 addition & 0 deletions tests/app/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ dist_check_DATA= \
t1_filt01.csv t1_filt02.csv t1_filt1a.csv t1_filtne.csv \
t1_sort1e0d.csv t1_esc0.csv \
t1t2_natural.csv t1t2_outer.csv \
t1t4_natural.csv \
t2.csv t2esc.csv t2esch.csv t3.csv t2t3_cross.csv \
t3_rsx.csv t3_rstab.csv \
t4.csv \
Expand Down
1 change: 1 addition & 0 deletions tests/app/csvjoin_jtx_test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ CSVCONV="../../src/csvconv"
< "$WDIR/t1.csv" "$CSVJOIN" -jt natural -jf "$WDIR/t2.csv" | diff - "$WDIR/t1t2_natural.csv" || exit 1
< "$WDIR/t1.csv" "$CSVJOIN" -jt natural -jf "$WDIR/t2esc.csv" | "$CSVCONV" -esc remove | diff - "$WDIR/t1t2_natural.csv" || exit 1
< "$WDIR/t1.csv" "$CSVJOIN" -jt natural -jf "$WDIR/t2esch.csv" | "$CSVCONV" -esc remove | diff - "$WDIR/t1t2_natural.csv" || exit 1
< "$WDIR/t1.csv" "$CSVJOIN" -jt natural -jf "$WDIR/t4.csv" | "$CSVCONV" -esc remove | diff - "$WDIR/t1t4_natural.csv" || exit 1
< "$WDIR/t1.csv" "$CSVJOIN" -jt inner -jc 1:0 -jf "$WDIR/t2.csv" | diff - "$WDIR/t1t2_natural.csv" || exit 1
< "$WDIR/t1.csv" "$CSVJOIN" -jt outer -jc 1:0 -jf "$WDIR/t2.csv" | diff - "$WDIR/t1t2_outer.csv" || exit 1
< "$WDIR/t2.csv" "$CSVJOIN" -jt cross -jf "$WDIR/t3.csv" | diff - "$WDIR/t2t3_cross.csv" || exit 1
Expand Down
1 change: 1 addition & 0 deletions tests/app/t1t4_natural.csv
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
foo,bar,name,test_string