Improve argument parser tests

* Use auto
* Use `CPPUNIT_ASSERT_EQUAL` with `std::string_view` instead of `strcmp`
  for better error messages in case of a failure
* Avoid instantiating an `std::string` in checks using `std::string_view`
  instead
This commit is contained in:
Martchus 2022-06-26 11:18:36 +02:00
parent b1b811c57f
commit 3444e4bbb1
1 changed files with 48 additions and 48 deletions

View File

@ -119,34 +119,34 @@ void ArgumentParserTests::testArgument()
void ArgumentParserTests::testParsing() void ArgumentParserTests::testParsing()
{ {
// setup parser with some test argument definitions // setup parser with some test argument definitions
ArgumentParser parser; auto parser = ArgumentParser();
parser.setExitFunction(std::bind(&ArgumentParserTests::failOnExit, this, std::placeholders::_1)); parser.setExitFunction(std::bind(&ArgumentParserTests::failOnExit, this, std::placeholders::_1));
SET_APPLICATION_INFO; SET_APPLICATION_INFO;
QT_CONFIG_ARGUMENTS qtConfigArgs; auto qtConfigArgs = QT_CONFIG_ARGUMENTS();
Argument verboseArg("verbose", 'v', "be verbose"); auto verboseArg = Argument("verbose", 'v', "be verbose");
verboseArg.setCombinable(true); verboseArg.setCombinable(true);
Argument fileArg("file", 'f', "specifies the path of the file to be opened"); auto fileArg = Argument("file", 'f', "specifies the path of the file to be opened");
fileArg.setValueNames({ "path" }); fileArg.setValueNames({ "path" });
fileArg.setRequiredValueCount(1); fileArg.setRequiredValueCount(1);
fileArg.setEnvironmentVariable("PATH"); fileArg.setEnvironmentVariable("PATH");
Argument filesArg("files", 'f', "specifies the path of the file(s) to be opened"); auto filesArg = Argument("files", 'f', "specifies the path of the file(s) to be opened");
filesArg.setValueNames({ "path 1", "path 2" }); filesArg.setValueNames({ "path 1", "path 2" });
filesArg.setRequiredValueCount(Argument::varValueCount); filesArg.setRequiredValueCount(Argument::varValueCount);
Argument outputFileArg("output-file", 'o', "specifies the path of the output file"); auto outputFileArg = Argument("output-file", 'o', "specifies the path of the output file");
outputFileArg.setValueNames({ "path" }); outputFileArg.setValueNames({ "path" });
outputFileArg.setRequiredValueCount(1); outputFileArg.setRequiredValueCount(1);
outputFileArg.setRequired(true); outputFileArg.setRequired(true);
outputFileArg.setCombinable(true); outputFileArg.setCombinable(true);
Argument printFieldNamesArg("print-field-names", '\0', "prints available field names"); auto printFieldNamesArg = Argument("print-field-names", '\0', "prints available field names");
Argument displayFileInfoArg("display-file-info", 'i', "displays general file information"); auto displayFileInfoArg = Argument("display-file-info", 'i', "displays general file information");
Argument notAlbumArg("album", 'a', "should not be confused with album value"); auto notAlbumArg = Argument("album", 'a', "should not be confused with album value");
displayFileInfoArg.setDenotesOperation(true); displayFileInfoArg.setDenotesOperation(true);
displayFileInfoArg.setSubArguments({ &fileArg, &verboseArg, &notAlbumArg }); displayFileInfoArg.setSubArguments({ &fileArg, &verboseArg, &notAlbumArg });
Argument fieldsArg("fields", '\0', "specifies the fields"); auto fieldsArg = Argument("fields", '\0', "specifies the fields");
fieldsArg.setRequiredValueCount(Argument::varValueCount); fieldsArg.setRequiredValueCount(Argument::varValueCount);
fieldsArg.setValueNames({ "title", "album", "artist", "trackpos" }); fieldsArg.setValueNames({ "title", "album", "artist", "trackpos" });
fieldsArg.setImplicit(true); fieldsArg.setImplicit(true);
Argument displayTagInfoArg("get", 'p', "displays the values of all specified tag fields (displays all fields if none specified)"); auto displayTagInfoArg = Argument("get", 'p', "displays the values of all specified tag fields (displays all fields if none specified)");
displayTagInfoArg.setDenotesOperation(true); displayTagInfoArg.setDenotesOperation(true);
displayTagInfoArg.setSubArguments({ &fieldsArg, &filesArg, &verboseArg, &notAlbumArg }); displayTagInfoArg.setSubArguments({ &fieldsArg, &filesArg, &verboseArg, &notAlbumArg });
parser.setMainArguments( parser.setMainArguments(
@ -167,11 +167,11 @@ void ArgumentParserTests::testParsing()
} catch (const ParseError &e) { } catch (const ParseError &e) {
CPPUNIT_ASSERT_EQUAL("The argument \"files\" can not be combined with \"fields\"."s, string(e.what())); CPPUNIT_ASSERT_EQUAL("The argument \"files\" can not be combined with \"fields\"."s, string(e.what()));
// test printing btw // test printing btw
stringstream ss; auto ss = std::stringstream();
ss << e; ss << e;
CPPUNIT_ASSERT_EQUAL( CPPUNIT_ASSERT_EQUAL(
"Error: Unable to parse arguments: The argument \"files\" can not be combined with \"fields\".\nSee --help for available commands.\n"s, "Error: Unable to parse arguments: The argument \"files\" can not be combined with \"fields\".\nSee --help for available commands.\n"sv,
ss.str()); std::string_view(ss.str()));
} }
CPPUNIT_ASSERT(parser.isUncombinableMainArgPresent()); CPPUNIT_ASSERT(parser.isUncombinableMainArgPresent());
@ -182,14 +182,14 @@ void ArgumentParserTests::testParsing()
// check results // check results
CPPUNIT_ASSERT(!qtConfigArgs.qtWidgetsGuiArg().isPresent()); CPPUNIT_ASSERT(!qtConfigArgs.qtWidgetsGuiArg().isPresent());
CPPUNIT_ASSERT(!displayFileInfoArg.isPresent()); CPPUNIT_ASSERT(!displayFileInfoArg.isPresent());
CPPUNIT_ASSERT(!strcmp(parser.executable(), "tageditor")); CPPUNIT_ASSERT_EQUAL("tageditor"sv, std::string_view(parser.executable()));
CPPUNIT_ASSERT(!verboseArg.isPresent()); CPPUNIT_ASSERT(!verboseArg.isPresent());
CPPUNIT_ASSERT(displayTagInfoArg.isPresent()); CPPUNIT_ASSERT(displayTagInfoArg.isPresent());
CPPUNIT_ASSERT(fieldsArg.isPresent()); CPPUNIT_ASSERT(fieldsArg.isPresent());
CPPUNIT_ASSERT(!strcmp(fieldsArg.values().at(0), "album")); CPPUNIT_ASSERT_EQUAL("album"sv, std::string_view(fieldsArg.values().at(0)));
CPPUNIT_ASSERT(!strcmp(fieldsArg.values().at(1), "title")); CPPUNIT_ASSERT_EQUAL("title"sv, std::string_view(fieldsArg.values().at(1)));
CPPUNIT_ASSERT(!strcmp(fieldsArg.values().at(2), "diskpos")); CPPUNIT_ASSERT_EQUAL("diskpos"sv, std::string_view(fieldsArg.values().at(2)));
CPPUNIT_ASSERT_THROW(displayTagInfoArg.values().at(3), out_of_range); CPPUNIT_ASSERT_THROW(displayTagInfoArg.values().at(3), std::out_of_range);
CPPUNIT_ASSERT_EQUAL(&displayTagInfoArg, parser.specifiedOperation()); CPPUNIT_ASSERT_EQUAL(&displayTagInfoArg, parser.specifiedOperation());
// skip empty args // skip empty args
@ -203,13 +203,13 @@ void ArgumentParserTests::testParsing()
CPPUNIT_ASSERT(!verboseArg.isPresent()); CPPUNIT_ASSERT(!verboseArg.isPresent());
CPPUNIT_ASSERT(displayTagInfoArg.isPresent()); CPPUNIT_ASSERT(displayTagInfoArg.isPresent());
CPPUNIT_ASSERT(fieldsArg.isPresent()); CPPUNIT_ASSERT(fieldsArg.isPresent());
CPPUNIT_ASSERT(!strcmp(fieldsArg.values().at(0), "album")); CPPUNIT_ASSERT_EQUAL("album"sv, std::string_view(fieldsArg.values().at(0)));
CPPUNIT_ASSERT(!strcmp(fieldsArg.values().at(1), "title")); CPPUNIT_ASSERT_EQUAL("title"sv, std::string_view(fieldsArg.values().at(1)));
CPPUNIT_ASSERT(!strcmp(fieldsArg.values().at(2), "diskpos")); CPPUNIT_ASSERT_EQUAL("diskpos"sv, std::string_view(fieldsArg.values().at(2)));
CPPUNIT_ASSERT(!strcmp(fieldsArg.values().at(3), "")); CPPUNIT_ASSERT_EQUAL(""sv, std::string_view(fieldsArg.values().at(3)));
CPPUNIT_ASSERT_THROW(fieldsArg.values().at(4), out_of_range); CPPUNIT_ASSERT_THROW(fieldsArg.values().at(4), std::out_of_range);
CPPUNIT_ASSERT(filesArg.isPresent()); CPPUNIT_ASSERT(filesArg.isPresent());
CPPUNIT_ASSERT(!strcmp(filesArg.values().at(0), "somefile")); CPPUNIT_ASSERT_EQUAL("somefile"sv, std::string_view(filesArg.values().at(0)));
// error about unknown argument: forget get/-p // error about unknown argument: forget get/-p
const char *argv3[] = { "tageditor", "album", "title", "diskpos", "--files", "somefile" }; const char *argv3[] = { "tageditor", "album", "title", "diskpos", "--files", "somefile" };
@ -218,7 +218,7 @@ void ArgumentParserTests::testParsing()
parser.parseArgs(6, argv3, ParseArgumentBehavior::CheckConstraints | ParseArgumentBehavior::InvokeCallbacks); parser.parseArgs(6, argv3, ParseArgumentBehavior::CheckConstraints | ParseArgumentBehavior::InvokeCallbacks);
CPPUNIT_FAIL("Exception expected."); CPPUNIT_FAIL("Exception expected.");
} catch (const ParseError &e) { } catch (const ParseError &e) {
CPPUNIT_ASSERT_EQUAL("The specified argument \"album\" is unknown.\nDid you mean get or --help?"s, string(e.what())); CPPUNIT_ASSERT_EQUAL("The specified argument \"album\" is unknown.\nDid you mean get or --help?"sv, std::string_view(e.what()));
} }
// error about unknown argument: mistake in final argument // error about unknown argument: mistake in final argument
@ -228,7 +228,7 @@ void ArgumentParserTests::testParsing()
parser.parseArgs(7, argv18, ParseArgumentBehavior::CheckConstraints | ParseArgumentBehavior::InvokeCallbacks); parser.parseArgs(7, argv18, ParseArgumentBehavior::CheckConstraints | ParseArgumentBehavior::InvokeCallbacks);
CPPUNIT_FAIL("Exception expected."); CPPUNIT_FAIL("Exception expected.");
} catch (const ParseError &e) { } catch (const ParseError &e) {
CPPUNIT_ASSERT_EQUAL("The specified argument \"--fi\" is unknown.\nDid you mean --files or --no-color?"s, string(e.what())); CPPUNIT_ASSERT_EQUAL("The specified argument \"--fi\" is unknown.\nDid you mean --files or --no-color?"sv, std::string_view(e.what()));
} }
// warning about unknown argument // warning about unknown argument
@ -265,8 +265,8 @@ void ArgumentParserTests::testParsing()
CPPUNIT_ASSERT(!displayTagInfoArg.isPresent()); CPPUNIT_ASSERT(!displayTagInfoArg.isPresent());
CPPUNIT_ASSERT(!filesArg.isPresent()); CPPUNIT_ASSERT(!filesArg.isPresent());
CPPUNIT_ASSERT(fileArg.isPresent()); CPPUNIT_ASSERT(fileArg.isPresent());
CPPUNIT_ASSERT(!strcmp(fileArg.values().at(0), "test")); CPPUNIT_ASSERT_EQUAL("test"sv, std::string_view(fileArg.values().at(0)));
CPPUNIT_ASSERT_THROW(fileArg.values().at(1), out_of_range); CPPUNIT_ASSERT_THROW(fileArg.values().at(1), std::out_of_range);
// constraint checking: no multiple occurrences (not resetting verboseArg on purpose) // constraint checking: no multiple occurrences (not resetting verboseArg on purpose)
displayFileInfoArg.reset(); displayFileInfoArg.reset();
@ -276,7 +276,7 @@ void ArgumentParserTests::testParsing()
CPPUNIT_FAIL("Exception expected."); CPPUNIT_FAIL("Exception expected.");
} catch (const ParseError &e) { } catch (const ParseError &e) {
CPPUNIT_ASSERT(!qtConfigArgs.qtWidgetsGuiArg().isPresent()); CPPUNIT_ASSERT(!qtConfigArgs.qtWidgetsGuiArg().isPresent());
CPPUNIT_ASSERT(!strcmp(e.what(), "The argument \"verbose\" mustn't be specified more than 1 time.")); CPPUNIT_ASSERT_EQUAL("The argument \"verbose\" mustn't be specified more than 1 time."sv, std::string_view(e.what()));
} }
// constraint checking: no constraint (not resetting verboseArg on purpose) // constraint checking: no constraint (not resetting verboseArg on purpose)
@ -302,7 +302,7 @@ void ArgumentParserTests::testParsing()
CPPUNIT_FAIL("Exception expected."); CPPUNIT_FAIL("Exception expected.");
} catch (const ParseError &e) { } catch (const ParseError &e) {
CPPUNIT_ASSERT(!qtConfigArgs.qtWidgetsGuiArg().isPresent()); CPPUNIT_ASSERT(!qtConfigArgs.qtWidgetsGuiArg().isPresent());
CPPUNIT_ASSERT(!strcmp(e.what(), "The argument \"verbose\" must be specified at least 1 time.")); CPPUNIT_ASSERT_EQUAL("The argument \"verbose\" must be specified at least 1 time."sv, std::string_view(e.what()));
} }
verboseArg.setRequired(false); verboseArg.setRequired(false);
@ -315,7 +315,7 @@ void ArgumentParserTests::testParsing()
CPPUNIT_ASSERT(!fileArg.isPresent()); CPPUNIT_ASSERT(!fileArg.isPresent());
CPPUNIT_ASSERT(filesArg.isPresent()); CPPUNIT_ASSERT(filesArg.isPresent());
CPPUNIT_ASSERT_EQUAL(1_st, filesArg.values(0).size()); CPPUNIT_ASSERT_EQUAL(1_st, filesArg.values(0).size());
CPPUNIT_ASSERT(!strcmp(filesArg.values(0).front(), "test")); CPPUNIT_ASSERT_EQUAL("test"sv, std::string_view(filesArg.values(0).at(0)));
CPPUNIT_ASSERT(!qtConfigArgs.qtWidgetsGuiArg().isPresent()); CPPUNIT_ASSERT(!qtConfigArgs.qtWidgetsGuiArg().isPresent());
// constraint checking: no complains about missing -i // constraint checking: no complains about missing -i
@ -332,7 +332,7 @@ void ArgumentParserTests::testParsing()
CPPUNIT_FAIL("Exception expected."); CPPUNIT_FAIL("Exception expected.");
} catch (const ParseError &e) { } catch (const ParseError &e) {
CPPUNIT_ASSERT(!qtConfigArgs.qtWidgetsGuiArg().isPresent()); CPPUNIT_ASSERT(!qtConfigArgs.qtWidgetsGuiArg().isPresent());
CPPUNIT_ASSERT_EQUAL("The specified argument \"-f\" is unknown.\nDid you mean get or --help?"s, string(e.what())); CPPUNIT_ASSERT_EQUAL("The specified argument \"-f\" is unknown.\nDid you mean get or --help?"sv, std::string_view(e.what()));
} }
// equation sign syntax // equation sign syntax
@ -351,7 +351,7 @@ void ArgumentParserTests::testParsing()
CPPUNIT_ASSERT(fileArg.isPresent()); CPPUNIT_ASSERT(fileArg.isPresent());
CPPUNIT_ASSERT(verboseArg.isPresent()); CPPUNIT_ASSERT(verboseArg.isPresent());
CPPUNIT_ASSERT_EQUAL(1_st, fileArg.values(0).size()); CPPUNIT_ASSERT_EQUAL(1_st, fileArg.values(0).size());
CPPUNIT_ASSERT_EQUAL("test"s, string(fileArg.values(0).front())); CPPUNIT_ASSERT_EQUAL("test"sv, std::string_view(fileArg.values(0).front()));
// specifying value directly after abbreviation // specifying value directly after abbreviation
const char *argv12[] = { "tageditor", "-iftest" }; const char *argv12[] = { "tageditor", "-iftest" };
@ -360,7 +360,7 @@ void ArgumentParserTests::testParsing()
CPPUNIT_ASSERT(!filesArg.isPresent()); CPPUNIT_ASSERT(!filesArg.isPresent());
CPPUNIT_ASSERT(fileArg.isPresent()); CPPUNIT_ASSERT(fileArg.isPresent());
CPPUNIT_ASSERT_EQUAL(1_st, fileArg.values(0).size()); CPPUNIT_ASSERT_EQUAL(1_st, fileArg.values(0).size());
CPPUNIT_ASSERT(!strcmp(fileArg.values(0).front(), "test")); CPPUNIT_ASSERT_EQUAL("test"sv, std::string_view(fileArg.values().at(0)));
// specifying top-level argument after abbreviation // specifying top-level argument after abbreviation
const char *argv17[] = { "tageditor", "-if=test-v", "--no-color" }; const char *argv17[] = { "tageditor", "-if=test-v", "--no-color" };
@ -371,7 +371,7 @@ void ArgumentParserTests::testParsing()
CPPUNIT_ASSERT(!verboseArg.isPresent()); CPPUNIT_ASSERT(!verboseArg.isPresent());
CPPUNIT_ASSERT(parser.noColorArg().isPresent()); CPPUNIT_ASSERT(parser.noColorArg().isPresent());
CPPUNIT_ASSERT_EQUAL(1_st, fileArg.values(0).size()); CPPUNIT_ASSERT_EQUAL(1_st, fileArg.values(0).size());
CPPUNIT_ASSERT_EQUAL("test-v"s, string(fileArg.values(0).front())); CPPUNIT_ASSERT_EQUAL("test-v"sv, std::string_view(fileArg.values(0).front()));
// default argument // default argument
const char *argv8[] = { "tageditor" }; const char *argv8[] = { "tageditor" };
@ -383,9 +383,9 @@ void ArgumentParserTests::testParsing()
CPPUNIT_ASSERT(!displayTagInfoArg.isPresent()); CPPUNIT_ASSERT(!displayTagInfoArg.isPresent());
CPPUNIT_ASSERT(!filesArg.isPresent()); CPPUNIT_ASSERT(!filesArg.isPresent());
CPPUNIT_ASSERT(!fileArg.isPresent()); CPPUNIT_ASSERT(!fileArg.isPresent());
if (getenv("PATH")) { if (const auto path = std::getenv("PATH")) {
CPPUNIT_ASSERT(fileArg.firstValue()); CPPUNIT_ASSERT(fileArg.firstValue());
CPPUNIT_ASSERT(!strcmp(fileArg.firstValue(), getenv("PATH"))); CPPUNIT_ASSERT_EQUAL(std::string_view(path), std::string_view(fileArg.firstValue()));
} else { } else {
CPPUNIT_ASSERT(!fileArg.firstValue()); CPPUNIT_ASSERT(!fileArg.firstValue());
} }
@ -401,12 +401,12 @@ void ArgumentParserTests::testParsing()
CPPUNIT_ASSERT(!verboseArg.isPresent()); CPPUNIT_ASSERT(!verboseArg.isPresent());
CPPUNIT_ASSERT(displayTagInfoArg.isPresent()); CPPUNIT_ASSERT(displayTagInfoArg.isPresent());
CPPUNIT_ASSERT(fieldsArg.isPresent()); CPPUNIT_ASSERT(fieldsArg.isPresent());
CPPUNIT_ASSERT(!strcmp(fieldsArg.values().at(0), "album=test")); CPPUNIT_ASSERT_EQUAL("album=test"sv, std::string_view(fieldsArg.values().at(0)));
CPPUNIT_ASSERT(!strcmp(fieldsArg.values().at(1), "title")); CPPUNIT_ASSERT_EQUAL("title"sv, std::string_view(fieldsArg.values().at(1)));
CPPUNIT_ASSERT(!strcmp(fieldsArg.values().at(2), "diskpos")); CPPUNIT_ASSERT_EQUAL("diskpos"sv, std::string_view(fieldsArg.values().at(2)));
CPPUNIT_ASSERT_THROW(fieldsArg.values().at(3), out_of_range); CPPUNIT_ASSERT_THROW(fieldsArg.values().at(3), out_of_range);
CPPUNIT_ASSERT(filesArg.isPresent()); CPPUNIT_ASSERT(filesArg.isPresent());
CPPUNIT_ASSERT(!strcmp(filesArg.values().at(0), "somefile")); CPPUNIT_ASSERT_EQUAL("somefile"sv, std::string_view(filesArg.values().at(0)));
CPPUNIT_ASSERT(!notAlbumArg.isPresent()); CPPUNIT_ASSERT(!notAlbumArg.isPresent());
// constraint checking: required value count with insufficient number of provided parameters // constraint checking: required value count with insufficient number of provided parameters
@ -419,8 +419,8 @@ void ArgumentParserTests::testParsing()
} catch (const ParseError &e) { } catch (const ParseError &e) {
CPPUNIT_ASSERT(!qtConfigArgs.qtWidgetsGuiArg().isPresent()); CPPUNIT_ASSERT(!qtConfigArgs.qtWidgetsGuiArg().isPresent());
CPPUNIT_ASSERT_EQUAL( CPPUNIT_ASSERT_EQUAL(
"Not all parameters for argument \"fields\" provided. You have to provide the following parameters: title album artist trackpos"s, "Not all parameters for argument \"fields\" provided. You have to provide the following parameters: title album artist trackpos"sv,
string(e.what())); std::string_view(e.what()));
} }
// constraint checking: truncated argument not wrongly detected // constraint checking: truncated argument not wrongly detected
@ -432,7 +432,7 @@ void ArgumentParserTests::testParsing()
CPPUNIT_FAIL("Exception expected."); CPPUNIT_FAIL("Exception expected.");
} catch (const ParseError &e) { } catch (const ParseError &e) {
CPPUNIT_ASSERT(!qtConfigArgs.qtWidgetsGuiArg().isPresent()); CPPUNIT_ASSERT(!qtConfigArgs.qtWidgetsGuiArg().isPresent());
CPPUNIT_ASSERT_EQUAL("The specified argument \"--hel\" is unknown.\nDid you mean --help or get?"s, string(e.what())); CPPUNIT_ASSERT_EQUAL("The specified argument \"--hel\" is unknown.\nDid you mean --help or get?"sv, std::string_view(e.what()));
} }
// nested operations // nested operations
@ -442,7 +442,7 @@ void ArgumentParserTests::testParsing()
parser.parseArgs(6, argv14, ParseArgumentBehavior::CheckConstraints | ParseArgumentBehavior::InvokeCallbacks); parser.parseArgs(6, argv14, ParseArgumentBehavior::CheckConstraints | ParseArgumentBehavior::InvokeCallbacks);
CPPUNIT_ASSERT(displayTagInfoArg.isPresent()); CPPUNIT_ASSERT(displayTagInfoArg.isPresent());
CPPUNIT_ASSERT(fieldsArg.isPresent()); CPPUNIT_ASSERT(fieldsArg.isPresent());
CPPUNIT_ASSERT(!strcmp(fieldsArg.values().at(0), "album=test")); CPPUNIT_ASSERT_EQUAL("album=test"sv, std::string_view(fieldsArg.values().at(0)));
// implicit flag still works when argument doesn't denote operation // implicit flag still works when argument doesn't denote operation
parser.resetArgs(); parser.resetArgs();
@ -450,8 +450,8 @@ void ArgumentParserTests::testParsing()
parser.parseArgs(6, argv14, ParseArgumentBehavior::CheckConstraints | ParseArgumentBehavior::InvokeCallbacks); parser.parseArgs(6, argv14, ParseArgumentBehavior::CheckConstraints | ParseArgumentBehavior::InvokeCallbacks);
CPPUNIT_ASSERT(displayTagInfoArg.isPresent()); CPPUNIT_ASSERT(displayTagInfoArg.isPresent());
CPPUNIT_ASSERT(fieldsArg.isPresent()); CPPUNIT_ASSERT(fieldsArg.isPresent());
CPPUNIT_ASSERT(!strcmp(fieldsArg.values().at(0), "fields")); CPPUNIT_ASSERT_EQUAL("fields"sv, std::string_view(fieldsArg.values().at(0)));
CPPUNIT_ASSERT(!strcmp(fieldsArg.values().at(1), "album=test")); CPPUNIT_ASSERT_EQUAL("album=test"sv, std::string_view(fieldsArg.values().at(1)));
} }
/*! /*!