3 #include "../conversion/stringbuilder.h" 5 #include "../application/argumentparser.h" 6 #include "../application/argumentparserprivate.h" 7 #include "../application/failure.h" 8 #include "../application/fakeqtconfigarguments.h" 10 #include "../io/path.h" 12 #include "resources/config.h" 14 #include <cppunit/TestFixture.h> 15 #include <cppunit/extensions/HelperMacros.h> 31 CPPUNIT_TEST(testArgument);
32 CPPUNIT_TEST(testParsing);
33 CPPUNIT_TEST(testCallbacks);
34 CPPUNIT_TEST(testBashCompletion);
35 CPPUNIT_TEST_SUITE_END();
44 void testBashCompletion();
65 Argument argument(
"test",
't',
"some description");
66 CPPUNIT_ASSERT_EQUAL(argument.
isRequired(),
false);
68 CPPUNIT_ASSERT_EQUAL(argument.
isRequired(),
true);
69 Argument subArg(
"sub",
's',
"sub arg");
71 CPPUNIT_ASSERT_EQUAL(subArg.parents().at(0), &argument);
72 CPPUNIT_ASSERT(!subArg.conflictsWithArgument());
77 CPPUNIT_ASSERT(!strcmp(argument.
firstValue(), getenv(
"PATH")));
93 Argument verboseArg(
"verbose",
'v',
"be verbose");
95 Argument fileArg(
"file",
'f',
"specifies the path of the file to be opened");
99 Argument filesArg(
"files",
'f',
"specifies the path of the file(s) to be opened");
102 Argument outputFileArg(
"output-file",
'o',
"specifies the path of the output file");
107 Argument printFieldNamesArg(
"print-field-names",
'\0',
"prints available field names");
108 Argument displayFileInfoArg(
"display-file-info",
'i',
"displays general file information");
109 Argument notAlbumArg(
"album",
'a',
"should not be confused with album value");
111 displayFileInfoArg.
setSubArguments({ &fileArg, &verboseArg, ¬AlbumArg });
112 Argument fieldsArg(
"fields",
'\0',
"specifies the fields");
114 fieldsArg.
setValueNames({
"title",
"album",
"artist",
"trackpos" });
116 Argument displayTagInfoArg(
"get",
'p',
"displays the values of all specified tag fields (displays all fields if none specified)");
118 displayTagInfoArg.
setSubArguments({ &fieldsArg, &filesArg, &verboseArg, ¬AlbumArg });
119 parser.
setMainArguments({ &qtConfigArgs.qtWidgetsGuiArg(), &printFieldNamesArg, &displayTagInfoArg, &displayFileInfoArg, &helpArg });
122 const char *argv[] = {
"tageditor",
"get",
"album",
"title",
"diskpos",
"-f",
"somefile" };
126 CPPUNIT_FAIL(
"Exception expected.");
128 CPPUNIT_ASSERT(!strcmp(e.
what(),
"The argument \"files\" can not be combined with \"fields\"."));
136 CPPUNIT_ASSERT(!qtConfigArgs.qtWidgetsGuiArg().isPresent());
137 CPPUNIT_ASSERT(!displayFileInfoArg.
isPresent());
138 CPPUNIT_ASSERT(!strcmp(parser.
executable(),
"tageditor"));
140 CPPUNIT_ASSERT(displayTagInfoArg.
isPresent());
142 CPPUNIT_ASSERT(!strcmp(fieldsArg.
values().at(0),
"album"));
143 CPPUNIT_ASSERT(!strcmp(fieldsArg.
values().at(1),
"title"));
144 CPPUNIT_ASSERT(!strcmp(fieldsArg.
values().at(2),
"diskpos"));
145 CPPUNIT_ASSERT_THROW(displayTagInfoArg.
values().at(3), out_of_range);
148 const char *argv2[] = {
"tageditor",
"",
"-p",
"album",
"title",
"diskpos",
"",
"--files",
"somefile" };
153 CPPUNIT_ASSERT(!qtConfigArgs.qtWidgetsGuiArg().isPresent());
154 CPPUNIT_ASSERT(!displayFileInfoArg.
isPresent());
156 CPPUNIT_ASSERT(displayTagInfoArg.
isPresent());
158 CPPUNIT_ASSERT(!strcmp(fieldsArg.
values().at(0),
"album"));
159 CPPUNIT_ASSERT(!strcmp(fieldsArg.
values().at(1),
"title"));
160 CPPUNIT_ASSERT(!strcmp(fieldsArg.
values().at(2),
"diskpos"));
161 CPPUNIT_ASSERT(!strcmp(fieldsArg.
values().at(3),
""));
162 CPPUNIT_ASSERT_THROW(fieldsArg.
values().at(4), out_of_range);
164 CPPUNIT_ASSERT(!strcmp(filesArg.
values().at(0),
"somefile"));
167 const char *argv3[] = {
"tageditor",
"album",
"title",
"diskpos",
"--files",
"somefile" };
171 CPPUNIT_FAIL(
"Exception expected.");
173 CPPUNIT_ASSERT_EQUAL(
"The specified argument \"album\" is unknown."s,
string(e.
what()));
180 streambuf *regularCerrBuffer = cerr.rdbuf(buffer.rdbuf());
185 cerr.rdbuf(regularCerrBuffer);
188 cerr.rdbuf(regularCerrBuffer);
189 CPPUNIT_ASSERT_EQUAL(
"The specified argument \"album\" is unknown and will be ignored.\n"s
190 "The specified argument \"title\" is unknown and will be ignored.\n"s
191 "The specified argument \"diskpos\" is unknown and will be ignored.\n"s
192 "The specified argument \"--files\" is unknown and will be ignored.\n"s
193 "The specified argument \"somefile\" is unknown and will be ignored.\n"s,
196 CPPUNIT_ASSERT(!qtConfigArgs.qtWidgetsGuiArg().isPresent());
197 CPPUNIT_ASSERT(!displayFileInfoArg.
isPresent());
198 CPPUNIT_ASSERT(!displayTagInfoArg.
isPresent());
203 const char *argv4[] = {
"tageditor",
"-i",
"-vf",
"test" };
207 CPPUNIT_ASSERT(!qtConfigArgs.qtWidgetsGuiArg().isPresent());
208 CPPUNIT_ASSERT(displayFileInfoArg.
isPresent());
210 CPPUNIT_ASSERT(!displayTagInfoArg.
isPresent());
213 CPPUNIT_ASSERT(!strcmp(fileArg.
values().at(0),
"test"));
214 CPPUNIT_ASSERT_THROW(fileArg.
values().at(1), out_of_range);
220 CPPUNIT_FAIL(
"Exception expected.");
222 CPPUNIT_ASSERT(!qtConfigArgs.qtWidgetsGuiArg().isPresent());
223 CPPUNIT_ASSERT(!strcmp(e.
what(),
"The argument \"verbose\" mustn't be specified more than 1 time."));
230 CPPUNIT_ASSERT(!qtConfigArgs.qtWidgetsGuiArg().isPresent());
236 CPPUNIT_ASSERT(!qtConfigArgs.qtWidgetsGuiArg().isPresent());
239 const char *argv5[] = {
"tageditor",
"-i",
"-f",
"test" };
243 CPPUNIT_FAIL(
"Exception expected.");
245 CPPUNIT_ASSERT(!qtConfigArgs.qtWidgetsGuiArg().isPresent());
246 CPPUNIT_ASSERT(!strcmp(e.
what(),
"The argument \"verbose\" must be specified at least 1 time."));
251 const char *argv10[] = {
"tageditor",
"-pf",
"test" };
254 CPPUNIT_ASSERT(displayTagInfoArg.
isPresent());
255 CPPUNIT_ASSERT(!displayFileInfoArg.
isPresent());
258 CPPUNIT_ASSERT_EQUAL(filesArg.
values(0).size(),
static_cast<vector<const char *>::size_type
>(1));
259 CPPUNIT_ASSERT(!strcmp(filesArg.
values(0).front(),
"test"));
260 CPPUNIT_ASSERT(!qtConfigArgs.qtWidgetsGuiArg().isPresent());
263 const char *argv6[] = {
"tageditor",
"-g" };
266 CPPUNIT_ASSERT(qtConfigArgs.qtWidgetsGuiArg().isPresent());
269 const char *argv7[] = {
"tageditor",
"-f",
"test" };
273 CPPUNIT_FAIL(
"Exception expected.");
275 CPPUNIT_ASSERT(!qtConfigArgs.qtWidgetsGuiArg().isPresent());
276 CPPUNIT_ASSERT_EQUAL(
"The specified argument \"-f\" is unknown."s,
string(e.
what()));
280 const char *argv11[] = {
"tageditor",
"-if=test" };
285 CPPUNIT_ASSERT_EQUAL(fileArg.
values(0).size(),
static_cast<vector<const char *>::size_type
>(1));
286 CPPUNIT_ASSERT(!strcmp(fileArg.
values(0).front(),
"test"));
289 const char *argv12[] = {
"tageditor",
"-iftest" };
294 CPPUNIT_ASSERT_EQUAL(fileArg.
values(0).size(),
static_cast<vector<const char *>::size_type
>(1));
295 CPPUNIT_ASSERT(!strcmp(fileArg.
values(0).front(),
"test"));
298 const char *argv8[] = {
"tageditor" };
301 CPPUNIT_ASSERT(qtConfigArgs.qtWidgetsGuiArg().isPresent());
302 CPPUNIT_ASSERT(!displayFileInfoArg.
isPresent());
304 CPPUNIT_ASSERT(!displayTagInfoArg.
isPresent());
307 if (getenv(
"PATH")) {
309 CPPUNIT_ASSERT(!strcmp(fileArg.
firstValue(), getenv(
"PATH")));
315 const char *argv13[] = {
"tageditor",
"get",
"--fields",
"album=test",
"title",
"diskpos",
"--files",
"somefile" };
320 CPPUNIT_ASSERT(!qtConfigArgs.qtWidgetsGuiArg().isPresent());
321 CPPUNIT_ASSERT(!displayFileInfoArg.
isPresent());
323 CPPUNIT_ASSERT(displayTagInfoArg.
isPresent());
325 CPPUNIT_ASSERT(!strcmp(fieldsArg.
values().at(0),
"album=test"));
326 CPPUNIT_ASSERT(!strcmp(fieldsArg.
values().at(1),
"title"));
327 CPPUNIT_ASSERT(!strcmp(fieldsArg.
values().at(2),
"diskpos"));
328 CPPUNIT_ASSERT_THROW(fieldsArg.
values().at(3), out_of_range);
330 CPPUNIT_ASSERT(!strcmp(filesArg.
values().at(0),
"somefile"));
331 CPPUNIT_ASSERT(!notAlbumArg.
isPresent());
334 const char *argv9[] = {
"tageditor",
"-p",
"album",
"title",
"diskpos" };
339 CPPUNIT_FAIL(
"Exception expected.");
341 CPPUNIT_ASSERT(!qtConfigArgs.qtWidgetsGuiArg().isPresent());
342 CPPUNIT_ASSERT(!strcmp(e.
what(),
343 "Not all parameter for argument \"fields\" provided. You have to provide the following parameter: title album artist trackpos"));
347 const char *argv14[] = {
"tageditor",
"get",
"fields",
"album=test",
"-f",
"somefile" };
352 CPPUNIT_ASSERT(displayTagInfoArg.
isPresent());
354 CPPUNIT_ASSERT(!strcmp(fieldsArg.
values().at(0),
"album=test"));
360 CPPUNIT_ASSERT(displayTagInfoArg.
isPresent());
362 CPPUNIT_ASSERT(!strcmp(fieldsArg.
values().at(0),
"fields"));
363 CPPUNIT_ASSERT(!strcmp(fieldsArg.
values().at(1),
"album=test"));
372 Argument callbackArg(
"with-callback",
't',
"callback test");
375 CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(0), occurrence.
index);
376 CPPUNIT_ASSERT(occurrence.
path.empty());
377 CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(2), occurrence.
values.size());
378 CPPUNIT_ASSERT(!strcmp(occurrence.
values[0],
"val1"));
379 CPPUNIT_ASSERT(!strcmp(occurrence.
values[1],
"val2"));
382 Argument noCallbackArg(
"no-callback",
'l',
"callback test");
387 const char *argv[] = {
"test",
"-t",
"val1",
"val2" };
391 CPPUNIT_ASSERT_EQUAL(i, 42);
396 const char *argv2[] = {
"test",
"-l",
"val1",
"val2" };
409 Argument verboseArg(
"verbose",
'v',
"be verbose");
411 Argument filesArg(
"files",
'f',
"specifies the path of the file(s) to be opened");
414 Argument nestedSubArg(
"nested-sub",
'\0',
"nested sub arg");
415 Argument subArg(
"sub",
'\0',
"sub arg");
417 Argument displayFileInfoArg(
"display-file-info",
'i',
"displays general file information");
419 displayFileInfoArg.
setSubArguments({ &filesArg, &verboseArg, &subArg });
420 Argument fieldsArg(
"fields",
'\0',
"specifies the fields");
424 Argument valuesArg(
"values",
'\0',
"specifies the fields");
428 valuesArg.
setValueCompletionBehavior(ValueCompletionBehavior::PreDefinedValues | ValueCompletionBehavior::AppendEquationSign);
429 Argument getArg(
"get",
'g',
"gets tag values");
431 Argument setArg(
"set",
's',
"sets tag values");
434 parser.
setMainArguments({ &helpArg, &displayFileInfoArg, &getArg, &setArg });
438 streambuf *regularCoutBuffer = cout.rdbuf(buffer.rdbuf());
442 const char *
const argv1[] = {
"se" };
445 parser.printBashCompletion(1, argv1, 0, reader);
446 cout.rdbuf(regularCoutBuffer);
447 CPPUNIT_ASSERT_EQUAL(
"COMPREPLY=()\n"s, buffer.str());
450 buffer.str(
string());
451 cout.rdbuf(buffer.rdbuf());
454 parser.printBashCompletion(1, argv1, 0, reader);
455 cout.rdbuf(regularCoutBuffer);
456 CPPUNIT_ASSERT_EQUAL(
"COMPREPLY=('set' )\n"s, buffer.str());
459 const char *
const argv2[] = {
"set" };
460 buffer.str(
string());
461 cout.rdbuf(buffer.rdbuf());
464 parser.printBashCompletion(1, argv2, 0, reader);
465 cout.rdbuf(regularCoutBuffer);
466 CPPUNIT_ASSERT_EQUAL(
"COMPREPLY=('set' )\n"s, buffer.str());
469 buffer.str(
string());
470 cout.rdbuf(buffer.rdbuf());
473 parser.printBashCompletion(1, argv2, 1, reader);
474 cout.rdbuf(regularCoutBuffer);
475 CPPUNIT_ASSERT_EQUAL(
"COMPREPLY=('--files' '--values' )\n"s, buffer.str());
478 buffer.str(
string());
479 cout.rdbuf(buffer.rdbuf());
483 parser.printBashCompletion(1, argv2, 1, reader);
484 cout.rdbuf(regularCoutBuffer);
485 CPPUNIT_ASSERT_EQUAL(
"COMPREPLY=('files' '--values' )\n"s, buffer.str());
488 buffer.str(
string());
489 cout.rdbuf(buffer.rdbuf());
493 parser.printBashCompletion(0,
nullptr, 0, reader);
494 cout.rdbuf(regularCoutBuffer);
495 CPPUNIT_ASSERT_EQUAL(
"COMPREPLY=('display-file-info' 'get' 'set' '--help' )\n"s, buffer.str());
498 const char *
const argv3[] = {
"get",
"--fields" };
499 buffer.str(
string());
500 cout.rdbuf(buffer.rdbuf());
503 parser.printBashCompletion(2, argv3, 2, reader);
504 cout.rdbuf(regularCoutBuffer);
505 CPPUNIT_ASSERT_EQUAL(
"COMPREPLY=('title' 'album' 'artist' 'trackpos' '--files' )\n"s, buffer.str());
508 const char *
const argv4[] = {
"set",
"--values",
"a" };
509 buffer.str(
string());
510 cout.rdbuf(buffer.rdbuf());
513 parser.printBashCompletion(3, argv4, 2, reader);
514 cout.rdbuf(regularCoutBuffer);
515 CPPUNIT_ASSERT_EQUAL(
"COMPREPLY=('album=' 'artist=' ); compopt -o nospace\n"s, buffer.str());
519 iniFilePath.resize(iniFilePath.size() - 4);
521 mkvFilePath.resize(mkvFilePath.size() - 17);
523 const char *
const argv5[] = {
"get",
"--files", iniFilePath.c_str() };
524 buffer.str(
string());
525 cout.rdbuf(buffer.rdbuf());
528 parser.printBashCompletion(3, argv5, 2, reader);
529 cout.rdbuf(regularCoutBuffer);
531 const string res(buffer.str());
532 if (res.find(
".mkv") < res.find(
".ini")) {
533 CPPUNIT_ASSERT_EQUAL(
534 "COMPREPLY=('" % mkvFilePath %
" '\"'\"'with quote'\"'\"'.mkv' '" % iniFilePath +
".ini' ); compopt -o filenames\n", buffer.str());
536 CPPUNIT_ASSERT_EQUAL(
537 "COMPREPLY=('" % iniFilePath %
".ini' '" % mkvFilePath +
" '\"'\"'with quote'\"'\"'.mkv' ); compopt -o filenames\n", buffer.str());
541 const char *
const argv6[] = {
"set",
"--" };
542 buffer.str(
string());
543 cout.rdbuf(buffer.rdbuf());
546 parser.printBashCompletion(2, argv6, 1, reader);
547 cout.rdbuf(regularCoutBuffer);
548 CPPUNIT_ASSERT_EQUAL(
"COMPREPLY=('--files' '--values' )\n"s, buffer.str());
551 const char *
const argv7[] = {
"-i",
"--sub",
"--" };
552 buffer.str(
string());
553 cout.rdbuf(buffer.rdbuf());
556 parser.printBashCompletion(3, argv7, 2, reader);
557 cout.rdbuf(regularCoutBuffer);
558 CPPUNIT_ASSERT_EQUAL(
"COMPREPLY=('--files' '--nested-sub' '--verbose' )\n"s, buffer.str());
561 const char *
const argv8[] = {
"set",
"--values",
"t" };
562 buffer.str(
string());
563 cout.rdbuf(buffer.rdbuf());
566 parser.printBashCompletion(3, argv8, 2, reader);
567 cout.rdbuf(regularCoutBuffer);
568 CPPUNIT_ASSERT_EQUAL(
"COMPREPLY=('title=' 'trackpos=' ); compopt -o nospace\n"s, buffer.str());
571 const char *
const argv9[] = {
"-gf" };
572 buffer.str(
string());
573 cout.rdbuf(buffer.rdbuf());
576 parser.printBashCompletion(1, argv9, 0, reader);
577 cout.rdbuf(regularCoutBuffer);
578 CPPUNIT_ASSERT_EQUAL(
"COMPREPLY=('-gf' )\n"s, buffer.str());
580 buffer.str(
string());
581 cout.rdbuf(buffer.rdbuf());
584 parser.printBashCompletion(1, argv9, 1, reader);
585 cout.rdbuf(regularCoutBuffer);
586 CPPUNIT_ASSERT_EQUAL(static_cast<string::size_type>(0), buffer.str().find(
"COMPREPLY=('--fields' "));
589 cout.rdbuf(regularCoutBuffer);
void testBashCompletion()
Tests bash completion.
void resetArgs()
Resets all Argument instances assigned as mainArguments() and sub arguments.
#define QT_CONFIG_ARGUMENTS
void setImplicit(bool value)
Sets whether the argument is an implicit argument.
std::size_t index
The index of the occurrence.
void testParsing()
Tests parsing command line arguments.
void setCombinable(bool value)
Sets whether this argument can be combined.
void setUnknownArgumentBehavior(UnknownArgumentBehavior behavior)
Sets how unknown arguments are treated.
virtual const char * what() const USE_NOTHROW
Returns a C-style character string describing the cause of the Failure.
Contains currently only ArgumentParser and related classes.
void setMainArguments(const ArgumentInitializerList &mainArguments)
Sets the main arguments for the parser.
void testArgument()
Tests the behaviour of the argument class.
bool isRequired() const
Returns an indication whether the argument is mandatory.
void testCallbacks()
Tests whether callbacks are called correctly.
void setRequired(bool required)
Sets whether this argument is mandatory or not.
void parseArgs(int argc, const char *const *argv)
Parses the specified command line arguments.
const char * firstValue() const
Returns the first parameter value of the first occurrence of the argument.
The ArgumentParserTests class tests the ArgumentParser and Argument classes.
void setConstraints(std::size_t minOccurrences, std::size_t maxOccurrences)
Sets the allowed number of occurrences.
void setValueCompletionBehavior(ValueCompletionBehavior valueCompletionBehaviour)
Sets the items to be considered when generating completion for the values.
#define SET_APPLICATION_INFO
SET_APPLICATION_INFO
const std::vector< const char * > & values(std::size_t occurrence=0) const
Returns the parameter values for the specified occurrence of argument.
Contains several functions providing conversions between different data types.
const char * executable() const
Returns the name of the current executable.
void read()
Reads the commands line arguments specified when constructing the object.
The Argument class is a wrapper for command line argument information.
void setCallback(CallbackFunction callback)
Sets a callback function which will be called by the parser if the argument could be found and no par...
void setPreDefinedCompletionValues(const char *preDefinedCompletionValues)
Assignes the values to be used when generating completion for the values.
ApplicationUtilities::ArgumentReader & reset(const char *const *argv, const char *const *end)
Resets the ArgumentReader to continue reading new argv.
std::vector< Argument * > path
The "path" of the occurrence (the parent elements which have been specified before).
void addSubArgument(Argument *arg)
Adds arg as a secondary argument for this argument.
void setEnvironmentVariable(const char *environmentVariable)
Sets the environment variable queried when firstValue() is called.
The ArgumentOccurrence struct holds argument values for an occurrence of an argument.
bool isPresent() const
Returns an indication whether the argument could be detected when parsing.
The HelpArgument class prints help information for an argument parser when present (–help...
CPPUNIT_TEST_SUITE_REGISTRATION(ArgumentParserTests)
The Failure class is thrown by an ArgumentParser when a parsing error occurs.
void setDenotesOperation(bool denotesOperation)
Sets whether the argument denotes the operation.
void reset()
Resets occurrences (indices, values and paths).
void setRequiredValueCount(std::size_t requiredValueCount)
Sets the number of values which are required to be given for this argument.
void setSubArguments(const ArgumentInitializerList &subArguments)
Sets the secondary arguments for this arguments.
CPP_UTILITIES_EXPORT std::string testFilePath(const std::string &name)
Convenience function which returns the full path of the test file with the specified name...
The ArgumentParser class provides a means for handling command line arguments.
void setValueNames(std::initializer_list< const char *> valueNames)
Sets the names of the requried values.
std::vector< const char * > values
The parameter values which have been specified after the occurrence of the argument.