Moved from popl to Poco for option parsing.
continuous-integration/drone/push Build is failing
Details
continuous-integration/drone/push Build is failing
Details
This commit is contained in:
parent
786912133b
commit
aedbebc6f6
12
.drone.yml
12
.drone.yml
|
@ -13,12 +13,6 @@ trigger:
|
|||
- tag
|
||||
|
||||
steps:
|
||||
- name: download
|
||||
image: plugins/download
|
||||
settings:
|
||||
source: https://raw.githubusercontent.com/badaix/popl/v1.2.0/include/popl.hpp
|
||||
destination: src/cli/popl.hpp
|
||||
|
||||
- name: gcc6
|
||||
image: debian:stretch-slim
|
||||
pull: always
|
||||
|
@ -167,12 +161,6 @@ trigger:
|
|||
- tag
|
||||
|
||||
steps:
|
||||
- name: download
|
||||
image: plugins/download
|
||||
settings:
|
||||
source: https://raw.githubusercontent.com/badaix/popl/v1.2.0/include/popl.hpp
|
||||
destination: src/cli/popl.hpp
|
||||
|
||||
- name: deb
|
||||
image: debian:stretch-slim
|
||||
pull: always
|
||||
|
|
|
@ -58,7 +58,6 @@ only.
|
|||
https://llvm.org/[clang] 3/7)
|
||||
* https://cmake.org/[cmake] (at least: 3.2)
|
||||
* https://pkgconfig.freedesktop.org/wiki/[pkgconfig] (tested: 0.29)
|
||||
* https://github.com/badaix/popl[popl] (tested: 1.2)
|
||||
* http://repo.or.cz/w/libxdg-basedir.git[libxdg-basedir] (tested: 1.2)
|
||||
* https://pocoproject.org/[POCO] (tested: 1.9 / 1.7)
|
||||
* http://vsqlite.virtuosic-bytes.com/[vsqlite++] (tested: 0.3)
|
||||
|
@ -75,8 +74,6 @@ only.
|
|||
apt-get update
|
||||
apt-get install g++-6 cmake pkg-config libpoco-dev libxdg-basedir-dev \
|
||||
libvsqlitepp-dev libboost-system-dev libboost-filesystem-dev asciidoc
|
||||
# Inside the source directory:
|
||||
wget -O src/cli/popl.hpp https://raw.githubusercontent.com/badaix/popl/v1.2.0/include/popl.hpp
|
||||
export CXX="g++-6"
|
||||
----
|
||||
====
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
include(GNUInstallDirs)
|
||||
|
||||
find_package(Poco COMPONENTS Util CONFIG)
|
||||
|
||||
file(GLOB sources_cli *.cpp)
|
||||
|
||||
add_executable(${PROJECT_NAME}-cli ${sources_cli})
|
||||
|
@ -11,7 +13,7 @@ target_include_directories(${PROJECT_NAME}-cli
|
|||
PRIVATE "${PROJECT_BINARY_DIR}" "${CMAKE_CURRENT_SOURCE_DIR}")
|
||||
|
||||
target_link_libraries(${PROJECT_NAME}-cli
|
||||
PRIVATE ${PROJECT_NAME})
|
||||
PRIVATE ${PROJECT_NAME} Poco::Util)
|
||||
|
||||
install(TARGETS ${PROJECT_NAME}-cli
|
||||
DESTINATION ${CMAKE_INSTALL_BINDIR})
|
||||
|
|
|
@ -18,10 +18,9 @@
|
|||
#include <string>
|
||||
#include <chrono>
|
||||
#include <fstream>
|
||||
#include <memory>
|
||||
#include <locale>
|
||||
#include "sqlite.hpp"
|
||||
#include "parse_options.hpp"
|
||||
#include "remwharead_cli.hpp"
|
||||
#include "uri.hpp"
|
||||
#include "types.hpp"
|
||||
#include "export/csv.hpp"
|
||||
|
@ -31,42 +30,60 @@
|
|||
#include "search.hpp"
|
||||
|
||||
using namespace remwharead;
|
||||
using std::cout;
|
||||
using std::cerr;
|
||||
using std::endl;
|
||||
using std::string;
|
||||
using std::chrono::system_clock;
|
||||
using std::ofstream;
|
||||
|
||||
int main(const int argc, const char *argv[])
|
||||
int App::main(const std::vector<std::string> &args)
|
||||
{
|
||||
std::locale::global(std::locale("")); // Set locale globally.
|
||||
|
||||
options opts = parse_options(argc, argv);
|
||||
if (opts.status_code != 0)
|
||||
if (_version_requested)
|
||||
{
|
||||
return opts.status_code;
|
||||
print_version();
|
||||
}
|
||||
else if (_help_requested)
|
||||
{
|
||||
print_help();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (_argument_error)
|
||||
{
|
||||
return Application::EXIT_USAGE;
|
||||
}
|
||||
if (args.size() > 0)
|
||||
{
|
||||
_uri = args[0];
|
||||
}
|
||||
if (_uri.empty() && _format == export_format::undefined)
|
||||
{
|
||||
cerr << "Error: You have to specify either URI or --export.\n";
|
||||
return Application::EXIT_USAGE;
|
||||
}
|
||||
}
|
||||
|
||||
Database db;
|
||||
|
||||
if (!db)
|
||||
{
|
||||
cerr << "Error: Database connection failed.\n";
|
||||
return 2;
|
||||
return Application::EXIT_IOERR;
|
||||
}
|
||||
|
||||
if (!opts.uri.empty())
|
||||
if (!_uri.empty())
|
||||
{
|
||||
URI uri(opts.uri);
|
||||
URI uri(_uri);
|
||||
html_extract page = uri.get();
|
||||
if (!page)
|
||||
{
|
||||
cerr << "Error: Could not fetch page.\n";
|
||||
cerr << page.error << endl;
|
||||
return 4;
|
||||
return Application::EXIT_UNAVAILABLE;
|
||||
}
|
||||
archive_answer archive;
|
||||
if (opts.archive)
|
||||
if (_archive)
|
||||
{
|
||||
archive = uri.archive();
|
||||
if (!archive)
|
||||
|
@ -74,35 +91,36 @@ int main(const int argc, const char *argv[])
|
|||
cerr << "Error archiving URL: " << archive.error << endl;
|
||||
}
|
||||
}
|
||||
db.store({opts.uri, archive.uri, system_clock::now(), opts.tags,
|
||||
db.store({_uri, archive.uri, system_clock::now(), _tags,
|
||||
page.title, page.description, page.fulltext});
|
||||
}
|
||||
|
||||
std::ofstream file;
|
||||
if (!opts.file.empty())
|
||||
ofstream file;
|
||||
if (!_file.empty())
|
||||
{
|
||||
file.open(opts.file);
|
||||
file.open(_file);
|
||||
if (!file.good())
|
||||
{
|
||||
cerr << "Error: Could not open file: " << opts.file << endl;
|
||||
return 3;
|
||||
cerr << "Error: Could not open file: " << _file << endl;
|
||||
return Application::EXIT_IOERR;
|
||||
}
|
||||
}
|
||||
if (opts.format != export_format::undefined)
|
||||
|
||||
if (_format != export_format::undefined)
|
||||
{
|
||||
vector<Database::entry> entries;
|
||||
Search search(db.retrieve(opts.span[0], opts.span[1]));
|
||||
Search search(db.retrieve(_timespan[0], _timespan[1]));
|
||||
|
||||
if (!opts.search_tags.empty())
|
||||
if (!_search_tags.empty())
|
||||
{
|
||||
entries = search.search_tags(opts.search_tags, opts.regex);
|
||||
entries = search.search_tags(_search_tags, _regex);
|
||||
}
|
||||
else if (!opts.search_all.empty())
|
||||
else if (!_search_all.empty())
|
||||
{
|
||||
entries = search.search_all(opts.search_all, opts.regex);
|
||||
entries = search.search_all(_search_all, _regex);
|
||||
}
|
||||
|
||||
switch (opts.format)
|
||||
switch (_format)
|
||||
{
|
||||
case export_format::csv:
|
||||
{
|
||||
|
@ -163,5 +181,7 @@ int main(const int argc, const char *argv[])
|
|||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
return Application::EXIT_OK;
|
||||
}
|
||||
|
||||
POCO_APP_MAIN(App)
|
||||
|
|
|
@ -15,168 +15,188 @@
|
|||
*/
|
||||
|
||||
#include <iostream>
|
||||
#include <exception>
|
||||
#include <popl.hpp>
|
||||
#include <Poco/Util/Option.h>
|
||||
#include <Poco/Util/HelpFormatter.h>
|
||||
#include "version.hpp"
|
||||
#include "parse_options.hpp"
|
||||
#include "remwharead_cli.hpp"
|
||||
|
||||
using std::cout;
|
||||
using std::cerr;
|
||||
using std::endl;
|
||||
using Poco::Util::Option;
|
||||
using Poco::Util::OptionCallback;
|
||||
using Poco::Util::HelpFormatter;
|
||||
|
||||
options::options()
|
||||
App::App()
|
||||
: _help_requested(false)
|
||||
, _version_requested(false)
|
||||
, _argument_error(false)
|
||||
, _uri()
|
||||
, _tags()
|
||||
, _format(export_format::undefined)
|
||||
, _timespan({ time_point(), system_clock::now() })
|
||||
, _archive(true)
|
||||
, _regex(false)
|
||||
{}
|
||||
|
||||
options::options(const uint8_t &status)
|
||||
: status_code(status)
|
||||
{}
|
||||
|
||||
const options parse_options(const int argc, const char *argv[])
|
||||
void App::defineOptions(OptionSet& options)
|
||||
{
|
||||
string tags;
|
||||
string format;
|
||||
string span;
|
||||
options opts;
|
||||
|
||||
try
|
||||
{
|
||||
popl::OptionParser op("Available options");
|
||||
op.add<popl::Value<string>>
|
||||
("t", "tags", "Add tags to URI, delimited by commas.", "", &tags);
|
||||
auto option_export = op.add<popl::Value<string>>
|
||||
("e", "export", "Export to format.", "simple", &format);
|
||||
op.add<popl::Value<string>>
|
||||
("f", "file", "Save output to file.", "", &opts.file);
|
||||
op.add<popl::Value<string>>
|
||||
("T", "time-span",
|
||||
"Only export entries between YYYY-MM-DD,YYYY-MM-DD.", "", &span);
|
||||
op.add<popl::Value<string>>
|
||||
("s", "search-tags",
|
||||
"Search in tags. Format: tag1 AND tag2 OR tag3.",
|
||||
"", &opts.search_tags);
|
||||
op.add<popl::Value<string>>
|
||||
("S", "search-all",
|
||||
"Search in tags, title, description and full text.",
|
||||
"", &opts.search_all);
|
||||
op.add<popl::Switch>
|
||||
("r", "regex", "Use regular expression for search.", &opts.regex);
|
||||
auto option_noarchive = op.add<popl::Switch>
|
||||
("N", "no-archive", "Do not archive URI.");
|
||||
auto option_help = op.add<popl::Switch>
|
||||
("h", "help", "Show this help message.");
|
||||
auto option_version = op.add<popl::Switch>
|
||||
("V", "version", "Print version, copyright and license.");
|
||||
op.parse(argc, argv);
|
||||
|
||||
if (option_help->is_set())
|
||||
{
|
||||
cout << "Usage: " << argv[0] << " [-t tags] [-N] URI\n"
|
||||
<< " " << argv[0]
|
||||
<< " -e format [-f file] [-T start,end] "
|
||||
<< "[[-s|-S] expression] [-r]\n";
|
||||
cout << op;
|
||||
return options(0);
|
||||
}
|
||||
|
||||
if (option_version->is_set())
|
||||
{
|
||||
cout << "remwharead " << global::version << endl <<
|
||||
"Copyright (C) 2019 tastytea <tastytea@tastytea.de>\n"
|
||||
"License GPLv3: GNU GPL version 3 "
|
||||
"<https://www.gnu.org/licenses/gpl-3.0.html>.\n"
|
||||
"This program comes with ABSOLUTELY NO WARRANTY. This is free software,\n"
|
||||
"and you are welcome to redistribute it under certain conditions.\n";
|
||||
return options(0);
|
||||
}
|
||||
|
||||
if (option_noarchive->is_set())
|
||||
{
|
||||
opts.archive = false;
|
||||
}
|
||||
|
||||
if (!tags.empty())
|
||||
{
|
||||
size_t pos_end = 0;
|
||||
size_t pos_start = 0;
|
||||
while (pos_end != std::string::npos)
|
||||
{
|
||||
pos_end = tags.find(',', pos_start);
|
||||
string buffer = tags.substr(pos_start, pos_end - pos_start);
|
||||
while (*buffer.begin() == ' ') // Remove leading spaces.
|
||||
{
|
||||
buffer.erase(buffer.begin());
|
||||
}
|
||||
while (*buffer.rbegin() == ' ') // Remove trailing spaces.
|
||||
{
|
||||
buffer.erase(buffer.end() - 1);
|
||||
}
|
||||
opts.tags.push_back(buffer);
|
||||
pos_start = pos_end + 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (option_export->is_set())
|
||||
{
|
||||
if (format == "csv")
|
||||
{
|
||||
opts.format = export_format::csv;
|
||||
}
|
||||
else if (format == "asciidoc" || format == "adoc")
|
||||
{
|
||||
opts.format = export_format::asciidoc;
|
||||
}
|
||||
else if (format == "bookmarks")
|
||||
{
|
||||
opts.format = export_format::bookmarks;
|
||||
}
|
||||
else if (format == "simple")
|
||||
{
|
||||
opts.format = export_format::simple;
|
||||
}
|
||||
else
|
||||
{
|
||||
opts.format = export_format::undefined;
|
||||
cerr << "Error: Export format must be "
|
||||
<< "csv, asciidoc, bookmarks or simple.\n";
|
||||
return options(1);
|
||||
}
|
||||
}
|
||||
|
||||
if (!span.empty())
|
||||
{
|
||||
size_t pos = span.find(',');
|
||||
if (pos != std::string::npos)
|
||||
{
|
||||
opts.span =
|
||||
{
|
||||
string_to_timepoint(span.substr(0, pos)),
|
||||
string_to_timepoint(span.substr(pos + 1))
|
||||
};
|
||||
}
|
||||
else
|
||||
{
|
||||
cerr << "Error: Time span must be in format: "
|
||||
"YYYY-MM-DD,YYYY-MM-DD.\n";
|
||||
return options(1);
|
||||
}
|
||||
}
|
||||
|
||||
if (op.non_option_args().size() > 0)
|
||||
{
|
||||
opts.uri = op.non_option_args().front();
|
||||
}
|
||||
|
||||
if (opts.uri == "" && opts.format == export_format::undefined)
|
||||
{
|
||||
cerr << "Error: You have to specify either URI or --export.\n";
|
||||
return options(1);
|
||||
}
|
||||
}
|
||||
catch (const std::exception &e)
|
||||
{
|
||||
cerr << "Error in " << __func__ << ": " << e.what() << endl;
|
||||
return options(1);
|
||||
}
|
||||
|
||||
return opts;
|
||||
options.addOption(
|
||||
Option("help", "h", "Show this help message.")
|
||||
.callback(OptionCallback<App>(this, &App::handle_info)));
|
||||
options.addOption(
|
||||
Option("version", "V", "Print version, copyright and license.")
|
||||
.callback(OptionCallback<App>(this, &App::handle_info)));
|
||||
options.addOption(
|
||||
Option("tags", "t", "Add tags to URI, delimited by commas.")
|
||||
.argument("Tags")
|
||||
.callback(OptionCallback<App>(this, &App::handle_options)));
|
||||
options.addOption(
|
||||
Option("export", "e", "Export to format.")
|
||||
.argument("Format")
|
||||
.callback(OptionCallback<App>(this, &App::handle_options)));
|
||||
options.addOption(
|
||||
Option("file", "f", "Save output to file.")
|
||||
.argument("File")
|
||||
.callback(OptionCallback<App>(this, &App::handle_options)));
|
||||
options.addOption(
|
||||
Option("time-span", "T",
|
||||
"Only export entries between YYYY-MM-DD,YYYY-MM-DD.")
|
||||
.argument("Times")
|
||||
.callback(OptionCallback<App>(this, &App::handle_options)));
|
||||
options.addOption(
|
||||
Option("search-tags", "s",
|
||||
"Search in tags. Format: tag1 AND tag2 OR tag3.")
|
||||
.argument("Expression")
|
||||
.callback(OptionCallback<App>(this, &App::handle_options)));
|
||||
options.addOption(
|
||||
Option("search-all", "S",
|
||||
"Search in tags, title, description and full text.")
|
||||
.argument("Expression")
|
||||
.callback(OptionCallback<App>(this, &App::handle_options)));
|
||||
options.addOption(
|
||||
Option("regex", "r", "Use regular expression for search."));
|
||||
options.addOption(
|
||||
Option("no-archive", "N", "Do not archive URI.")
|
||||
.callback(OptionCallback<App>(this, &App::handle_options)));
|
||||
}
|
||||
|
||||
void App::handle_info(const std::string &name, const std::string &)
|
||||
{
|
||||
if (name == "help")
|
||||
{
|
||||
_help_requested = true;
|
||||
}
|
||||
else if (name == "version")
|
||||
{
|
||||
_version_requested = true;
|
||||
}
|
||||
|
||||
stopOptionsProcessing();
|
||||
}
|
||||
|
||||
void App::handle_options(const std::string &name, const std::string &value)
|
||||
{
|
||||
if (name == "tags")
|
||||
{
|
||||
size_t pos_end = 0;
|
||||
size_t pos_start = 0;
|
||||
while (pos_end != std::string::npos)
|
||||
{
|
||||
pos_end = value.find(',', pos_start);
|
||||
string buffer = value.substr(pos_start, pos_end - pos_start);
|
||||
while (*buffer.begin() == ' ') // Remove leading spaces.
|
||||
{
|
||||
buffer.erase(buffer.begin());
|
||||
}
|
||||
while (*buffer.rbegin() == ' ') // Remove trailing spaces.
|
||||
{
|
||||
buffer.erase(buffer.end() - 1);
|
||||
}
|
||||
_tags.push_back(buffer);
|
||||
pos_start = pos_end + 1;
|
||||
}
|
||||
}
|
||||
else if (name == "export")
|
||||
{
|
||||
if (value == "csv")
|
||||
{
|
||||
_format = export_format::csv;
|
||||
}
|
||||
else if (value == "asciidoc" || value == "adoc")
|
||||
{
|
||||
_format = export_format::asciidoc;
|
||||
}
|
||||
else if (value == "bookmarks")
|
||||
{
|
||||
_format = export_format::bookmarks;
|
||||
}
|
||||
else if (value == "simple")
|
||||
{
|
||||
_format = export_format::simple;
|
||||
}
|
||||
else
|
||||
{
|
||||
cerr << "Error: Unknown format.\n";
|
||||
_argument_error = true;
|
||||
}
|
||||
}
|
||||
else if (name == "file")
|
||||
{
|
||||
_file = value;
|
||||
}
|
||||
else if (name == "time-span")
|
||||
{
|
||||
size_t pos = value.find(',');
|
||||
if (pos != std::string::npos)
|
||||
{
|
||||
_timespan =
|
||||
{
|
||||
string_to_timepoint(value.substr(0, pos)),
|
||||
string_to_timepoint(value.substr(pos + 1))
|
||||
};
|
||||
}
|
||||
else
|
||||
{
|
||||
cerr << "Error: Time span must be in format: "
|
||||
"YYYY-MM-DD,YYYY-MM-DD.\n";
|
||||
_argument_error = true;
|
||||
}
|
||||
}
|
||||
else if (name == "search-tags")
|
||||
{
|
||||
_search_tags = value;
|
||||
}
|
||||
else if (name == "search-all")
|
||||
{
|
||||
_search_all = value;
|
||||
}
|
||||
else if (name == "no-archive")
|
||||
{
|
||||
_archive = false;
|
||||
}
|
||||
else if (name == "regex")
|
||||
{
|
||||
_regex = true;
|
||||
}
|
||||
}
|
||||
|
||||
void App::print_help()
|
||||
{
|
||||
HelpFormatter helpFormatter(options());
|
||||
helpFormatter.setCommand(commandName());
|
||||
helpFormatter.setUsage("[-t tags] [-N] URI\n"
|
||||
"-e format [-f file] [-T start,end]\n"
|
||||
"[[-s|-S] expression] [-r]");
|
||||
helpFormatter.format(cout);
|
||||
}
|
||||
|
||||
void App::print_version()
|
||||
{
|
||||
cout << "remwharead " << global::version << endl <<
|
||||
"Copyright (C) 2019 tastytea <tastytea@tastytea.de>\n"
|
||||
"License GPLv3: GNU GPL version 3 "
|
||||
"<https://www.gnu.org/licenses/gpl-3.0.html>.\n"
|
||||
"This program comes with ABSOLUTELY NO WARRANTY. This is free software,"
|
||||
"\nand you are welcome to redistribute it under certain conditions.\n";
|
||||
}
|
||||
|
|
|
@ -21,7 +21,8 @@
|
|||
#include <vector>
|
||||
#include <array>
|
||||
#include <chrono>
|
||||
#include <cstdint>
|
||||
#include <Poco/Util/Application.h>
|
||||
#include <Poco/Util/OptionSet.h>
|
||||
#include "types.hpp"
|
||||
#include "time.hpp"
|
||||
|
||||
|
@ -31,26 +32,34 @@ using std::vector;
|
|||
using std::array;
|
||||
using std::chrono::system_clock;
|
||||
using time_point = system_clock::time_point;
|
||||
using std::uint8_t;
|
||||
using Poco::Util::OptionSet;
|
||||
|
||||
typedef struct options
|
||||
class App : public Poco::Util::Application
|
||||
{
|
||||
vector<string> tags;
|
||||
export_format format = export_format::undefined;
|
||||
string file;
|
||||
array<time_point, 2> span = {{ time_point(), system_clock::now() }};
|
||||
string uri;
|
||||
string search_tags;
|
||||
string search_all;
|
||||
bool regex = false;
|
||||
bool archive = true;
|
||||
uint8_t status_code = 0;
|
||||
public:
|
||||
App();
|
||||
|
||||
options();
|
||||
explicit options(const uint8_t &status);
|
||||
} options;
|
||||
protected:
|
||||
void defineOptions(OptionSet& options);
|
||||
void handle_info(const std::string &name, const std::string &value);
|
||||
void handle_options(const std::string &name, const std::string &value);
|
||||
void print_help();
|
||||
void print_version();
|
||||
int main(const std::vector<std::string> &args);
|
||||
|
||||
// Parse command-line options.
|
||||
const options parse_options(const int argc, const char *argv[]);
|
||||
private:
|
||||
bool _help_requested;
|
||||
bool _version_requested;
|
||||
bool _argument_error;
|
||||
string _uri;
|
||||
vector<string> _tags;
|
||||
export_format _format;
|
||||
string _file;
|
||||
array<time_point, 2> _timespan;
|
||||
string _search_tags;
|
||||
string _search_all;
|
||||
bool _archive;
|
||||
bool _regex;
|
||||
};
|
||||
|
||||
#endif // REMWHAREAD_PARSE_OPTIONS_HPP
|
|
@ -1,11 +1,5 @@
|
|||
include(CTest)
|
||||
|
||||
# I'm linking the library into the testlib to get the include directories.
|
||||
add_library(${PROJECT_NAME}_testlib ../src/cli/parse_options.cpp)
|
||||
target_include_directories(${PROJECT_NAME}_testlib
|
||||
PUBLIC "${PROJECT_BINARY_DIR}" "../src/cli")
|
||||
target_link_libraries(${PROJECT_NAME}_testlib PUBLIC ${PROJECT_NAME})
|
||||
|
||||
file(GLOB sources_tests test_*.cpp)
|
||||
|
||||
find_package(Catch2 CONFIG)
|
||||
|
@ -13,7 +7,7 @@ if(Catch2_FOUND) # Catch 2.x
|
|||
include(Catch)
|
||||
add_executable(all_tests main.cpp ${sources_tests})
|
||||
target_link_libraries(all_tests
|
||||
PRIVATE Catch2::Catch2 ${PROJECT_NAME}_testlib)
|
||||
PRIVATE Catch2::Catch2 ${PROJECT_NAME})
|
||||
target_include_directories(all_tests PRIVATE "/usr/include/catch2")
|
||||
catch_discover_tests(all_tests EXTRA_ARGS "${EXTRA_TEST_ARGS}")
|
||||
else() # Catch 1.x
|
||||
|
@ -23,7 +17,7 @@ else() # Catch 1.x
|
|||
get_filename_component(bin ${src} NAME_WE)
|
||||
add_executable(${bin} main.cpp ${src})
|
||||
target_link_libraries(${bin}
|
||||
PRIVATE ${PROJECT_NAME} ${PROJECT_NAME}_testlib)
|
||||
PRIVATE ${PROJECT_NAME} ${PROJECT_NAME})
|
||||
add_test(${bin} ${bin} "${EXTRA_TEST_ARGS}")
|
||||
endforeach()
|
||||
else()
|
||||
|
|
|
@ -1,138 +0,0 @@
|
|||
/* This file is part of remwharead.
|
||||
* Copyright © 2019 tastytea <tastytea@tastytea.de>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, version 3.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <exception>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <catch.hpp>
|
||||
#include "parse_options.hpp"
|
||||
|
||||
using namespace remwharead;
|
||||
using std::string;
|
||||
using std::vector;
|
||||
|
||||
SCENARIO ("The option parser works correctly")
|
||||
{
|
||||
bool exception = false;
|
||||
options opts;
|
||||
const string uri = "https://example.com/article.html";
|
||||
|
||||
WHEN ("The options are --help --file test")
|
||||
{
|
||||
try
|
||||
{
|
||||
const char *argv[]
|
||||
= { "remwharead", "--help", "--file", "test" };
|
||||
opts = parse_options(4, argv);
|
||||
}
|
||||
catch (const std::exception &e)
|
||||
{
|
||||
exception = true;
|
||||
}
|
||||
|
||||
THEN ("No exception is thrown")
|
||||
AND_THEN ("status code is 0")
|
||||
AND_THEN ("options.file is empty")
|
||||
{
|
||||
REQUIRE_FALSE(exception);
|
||||
REQUIRE(opts.status_code == 0);
|
||||
REQUIRE(opts.file == "");
|
||||
}
|
||||
}
|
||||
|
||||
WHEN ("The options are --version --file test")
|
||||
{
|
||||
try
|
||||
{
|
||||
const char *argv[]
|
||||
= { "remwharead", "--version", "--file", "test" };
|
||||
opts = parse_options(4, argv);
|
||||
}
|
||||
catch (const std::exception &e)
|
||||
{
|
||||
exception = true;
|
||||
}
|
||||
|
||||
THEN ("No exception is thrown")
|
||||
AND_THEN ("status code is 0")
|
||||
AND_THEN ("options.file is empty")
|
||||
{
|
||||
REQUIRE_FALSE(exception);
|
||||
REQUIRE(opts.status_code == 0);
|
||||
REQUIRE(opts.file == "");
|
||||
}
|
||||
}
|
||||
|
||||
WHEN ("The options are -t 💩 " + uri)
|
||||
{
|
||||
try
|
||||
{
|
||||
const char *argv[]
|
||||
= { "remwharead", "-t", "💩", uri.c_str() };
|
||||
opts = parse_options(4, argv);
|
||||
}
|
||||
catch (const std::exception &e)
|
||||
{
|
||||
exception = true;
|
||||
}
|
||||
|
||||
THEN ("No exception is thrown")
|
||||
AND_THEN ("status code is 0")
|
||||
AND_THEN ("Tag and URI are right")
|
||||
{
|
||||
REQUIRE_FALSE(exception);
|
||||
REQUIRE(opts.status_code == 0);
|
||||
REQUIRE(opts.tags == vector<string>{ "💩" });
|
||||
REQUIRE(opts.uri == uri);
|
||||
}
|
||||
}
|
||||
|
||||
WHEN ("A very long string is passed as a tag")
|
||||
{
|
||||
const string longstring = // 5 · 60 = 300
|
||||
"aw6hui6chieRo9aihai9un1aeke6oushoo2oRo4aeD6eiDeiSheek4ahGiel"
|
||||
"othaemeeyo4ievieV8kae9xiriejohD0aelah6oophaQueilohyaix3joo7O"
|
||||
"laiceeFePuetaeBe0aip3eemuaheer0aj8aij8ahchisi4eiperiechoopoo"
|
||||
"ohmie5doog5ohbahDoodah7daurah6haebeife2tah5Pheeweeb0eishooc4"
|
||||
"phohKu5Ha3HiCeedeoph1ocaingaHeedeepeesohmee6Equ4meirahk3aihe";
|
||||
const string tags = "tag1," + longstring + ",tag3";
|
||||
try
|
||||
{
|
||||
const char *argv[] =
|
||||
{
|
||||
"remwharead",
|
||||
"-t",
|
||||
tags.c_str(),
|
||||
uri.c_str()
|
||||
};
|
||||
opts = parse_options(4, argv);
|
||||
}
|
||||
catch (const std::exception &e)
|
||||
{
|
||||
exception = true;
|
||||
}
|
||||
|
||||
THEN ("No exception is thrown")
|
||||
AND_THEN ("status code is 0")
|
||||
AND_THEN ("Tag and URI are right")
|
||||
{
|
||||
REQUIRE_FALSE(exception);
|
||||
REQUIRE(opts.status_code == 0);
|
||||
REQUIRE((opts.tags == vector<string>{ "tag1", longstring, "tag3" }));
|
||||
REQUIRE(opts.uri == uri);
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue