mirror of
https://github.com/fmang/opustags.git
synced 2025-07-16 05:53:32 +02:00
Refactor Options to use TagsHandlers; add --stream
This commit is contained in:
@ -1,5 +1,8 @@
|
||||
#include <getopt.h>
|
||||
#include <regex>
|
||||
#include "tags_handlers/insertion_tags_handler.h"
|
||||
#include "tags_handlers/modification_tags_handler.h"
|
||||
#include "tags_handlers/removal_tags_handler.h"
|
||||
#include "options.h"
|
||||
|
||||
using namespace opustags;
|
||||
@ -12,7 +15,6 @@ ArgumentError::ArgumentError(const std::string &message)
|
||||
Options::Options() :
|
||||
show_help(false),
|
||||
overwrite(false),
|
||||
delete_all(false),
|
||||
set_all(false)
|
||||
{
|
||||
}
|
||||
@ -20,23 +22,32 @@ Options::Options() :
|
||||
Options opustags::parse_args(const int argc, char **argv)
|
||||
{
|
||||
static const auto short_def = "ho:i::yd:a:s:DS";
|
||||
|
||||
static const option long_def[] = {
|
||||
{"help", no_argument, 0, 'h'},
|
||||
{"output", required_argument, 0, 'o'},
|
||||
{"in-place", optional_argument, 0, 'i'},
|
||||
{"overwrite", no_argument, 0, 'y'},
|
||||
{"delete", required_argument, 0, 'd'},
|
||||
{"add", required_argument, 0, 'a'},
|
||||
{"set", required_argument, 0, 's'},
|
||||
{"delete-all", no_argument, 0, 'D'},
|
||||
{"set-all", no_argument, 0, 'S'},
|
||||
{"help", no_argument, 0, 'h'},
|
||||
{"output", required_argument, 0, 'o'},
|
||||
{"in-place", optional_argument, 0, 'i'},
|
||||
{"overwrite", no_argument, 0, 'y'},
|
||||
{"delete", required_argument, 0, 'd'},
|
||||
{"add", required_argument, 0, 'a'},
|
||||
{"stream", required_argument, 0, 0},
|
||||
{"set", required_argument, 0, 's'},
|
||||
{"delete-all", no_argument, 0, 'D'},
|
||||
{"set-all", no_argument, 0, 'S'},
|
||||
|
||||
{nullptr, 0, 0, 0}
|
||||
};
|
||||
|
||||
Options options;
|
||||
|
||||
int current_streamno = StreamTagsHandler::ALL_STREAMS;
|
||||
int option_index;
|
||||
char c;
|
||||
optind = 0;
|
||||
while ((c = getopt_long(argc, argv, short_def, long_def, nullptr)) != -1) {
|
||||
|
||||
while ((c = getopt_long(
|
||||
argc, argv, short_def, long_def, &option_index)) != -1) {
|
||||
|
||||
const std::string arg(optarg == nullptr ? "" : optarg);
|
||||
|
||||
switch (c) {
|
||||
@ -59,7 +70,9 @@ Options opustags::parse_args(const int argc, char **argv)
|
||||
case 'd':
|
||||
if (arg.find('=') != std::string::npos)
|
||||
throw ArgumentError("Invalid field: '" + arg + "'");
|
||||
options.to_delete.push_back(arg);
|
||||
options.tags_handler.add_handler(
|
||||
std::make_shared<RemovalTagsHandler>(
|
||||
current_streamno, arg));
|
||||
break;
|
||||
|
||||
case 'a':
|
||||
@ -69,9 +82,18 @@ Options opustags::parse_args(const int argc, char **argv)
|
||||
std::regex regex("^(\\w+)=(.*)$");
|
||||
if (!std::regex_match(arg, match, regex))
|
||||
throw ArgumentError("Invalid field: '" + arg + "'");
|
||||
options.to_add[match[1]] = match[2];
|
||||
if (c == 's')
|
||||
options.to_delete.push_back(match[1]);
|
||||
{
|
||||
options.tags_handler.add_handler(
|
||||
std::make_shared<ModificationTagsHandler>(
|
||||
current_streamno, match[1], match[2]));
|
||||
}
|
||||
else
|
||||
{
|
||||
options.tags_handler.add_handler(
|
||||
std::make_shared<InsertionTagsHandler>(
|
||||
current_streamno, match[1], match[2]));
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
@ -80,9 +102,18 @@ Options opustags::parse_args(const int argc, char **argv)
|
||||
break;
|
||||
|
||||
case 'D':
|
||||
options.delete_all = true;
|
||||
options.tags_handler.add_handler(
|
||||
std::make_shared<RemovalTagsHandler>(current_streamno));
|
||||
break;
|
||||
|
||||
case 0:
|
||||
{
|
||||
std::string long_arg = long_def[option_index].name;
|
||||
if (long_arg == "stream")
|
||||
current_streamno = atoi(optarg);
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
throw ArgumentError("Invalid flag");
|
||||
}
|
||||
|
@ -3,6 +3,7 @@
|
||||
#include <stdexcept>
|
||||
#include <map>
|
||||
#include <vector>
|
||||
#include "tags_handlers/composite_tags_handler.h"
|
||||
|
||||
namespace opustags
|
||||
{
|
||||
@ -12,13 +13,12 @@ namespace opustags
|
||||
|
||||
bool show_help;
|
||||
bool overwrite;
|
||||
bool delete_all;
|
||||
bool set_all;
|
||||
|
||||
std::string in_place; // string?
|
||||
std::string in_place;
|
||||
std::string path_out;
|
||||
std::map<std::string, std::string> to_add;
|
||||
std::vector<std::string> to_delete;
|
||||
|
||||
CompositeTagsHandler tags_handler;
|
||||
};
|
||||
|
||||
struct ArgumentError : std::runtime_error
|
||||
|
@ -1,6 +1,11 @@
|
||||
#include "options.h"
|
||||
#include <memory>
|
||||
#include "catch.h"
|
||||
#include "tags_handlers/modification_tags_handler.h"
|
||||
#include "tags_handlers/insertion_tags_handler.h"
|
||||
#include "tags_handlers/removal_tags_handler.h"
|
||||
|
||||
using namespace opustags;
|
||||
|
||||
static std::unique_ptr<char[]> string_to_uptr(const std::string &str)
|
||||
{
|
||||
@ -11,7 +16,7 @@ static std::unique_ptr<char[]> string_to_uptr(const std::string &str)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static opustags::Options retrieve_options(std::vector<std::string> args)
|
||||
static Options retrieve_options(std::vector<std::string> args)
|
||||
{
|
||||
// need to pass non-const char*, but we got const objects. make copies
|
||||
std::vector<std::unique_ptr<char[]>> arg_holders;
|
||||
@ -23,7 +28,17 @@ static opustags::Options retrieve_options(std::vector<std::string> args)
|
||||
for (size_t i = 0; i < arg_holders.size(); i++)
|
||||
plain_args[i] = arg_holders[i].get();
|
||||
|
||||
return opustags::parse_args(arg_holders.size(), plain_args.get());
|
||||
return parse_args(arg_holders.size(), plain_args.get());
|
||||
}
|
||||
|
||||
// retrieve a specific TagsHandler from the CompositeTagsHandler in options
|
||||
template<typename T> static T *get_handler(
|
||||
const Options &options, const size_t index)
|
||||
{
|
||||
const auto handlers = options.tags_handler.get_handlers();
|
||||
const auto handler = dynamic_cast<T*>(handlers.at(index).get());
|
||||
REQUIRE(handler);
|
||||
return handler;
|
||||
}
|
||||
|
||||
TEST_CASE("Options parsing test")
|
||||
@ -46,12 +61,6 @@ TEST_CASE("Options parsing test")
|
||||
REQUIRE(!retrieve_options({}).set_all);
|
||||
}
|
||||
|
||||
SECTION("--delete-all") {
|
||||
REQUIRE(retrieve_options({"--delete-all"}).delete_all);
|
||||
REQUIRE(retrieve_options({"-D"}).delete_all);
|
||||
REQUIRE(!retrieve_options({}).delete_all);
|
||||
}
|
||||
|
||||
SECTION("--in-place") {
|
||||
REQUIRE(retrieve_options({"-i"}).in_place == ".otmp");
|
||||
REQUIRE(retrieve_options({"--in-place"}).in_place == ".otmp");
|
||||
@ -68,52 +77,66 @@ TEST_CASE("Options parsing test")
|
||||
REQUIRE_THROWS(retrieve_options({"--delete", "invalid="}));
|
||||
}
|
||||
|
||||
SECTION("--delete-all") {
|
||||
REQUIRE(get_handler<RemovalTagsHandler>(
|
||||
retrieve_options({"--delete-all"}), 0)->get_tag_key().empty());
|
||||
|
||||
REQUIRE(get_handler<RemovalTagsHandler>(
|
||||
retrieve_options({"-D"}), 0)->get_tag_key().empty());
|
||||
}
|
||||
|
||||
SECTION("--delete") {
|
||||
REQUIRE(
|
||||
retrieve_options({"--delete", "ABC"}).to_delete
|
||||
== std::vector<std::string>{"ABC"});
|
||||
REQUIRE(
|
||||
retrieve_options({"-d", "ABC"}).to_delete
|
||||
== std::vector<std::string>{"ABC"});
|
||||
REQUIRE(
|
||||
retrieve_options({"-d", "ABC", "-d", "XYZ"}).to_delete
|
||||
== (std::vector<std::string>{"ABC", "XYZ"}));
|
||||
const auto opts = retrieve_options({"--delete", "A", "-d", "B"});
|
||||
REQUIRE(get_handler<RemovalTagsHandler>(opts, 0)->get_tag_key() == "A");
|
||||
REQUIRE(get_handler<RemovalTagsHandler>(opts, 1)->get_tag_key() == "B");
|
||||
REQUIRE_THROWS(retrieve_options({"--delete", "invalid="}));
|
||||
}
|
||||
|
||||
SECTION("--add") {
|
||||
const auto args1 = retrieve_options({"--add", "ABC=XYZ"});
|
||||
const auto args2 = retrieve_options({"-a", "ABC=XYZ"});
|
||||
REQUIRE(args1.to_add == args2.to_add);
|
||||
REQUIRE(args1.to_add
|
||||
== (std::map<std::string, std::string>{{"ABC", "XYZ"}}));
|
||||
REQUIRE(args1.to_delete.empty());
|
||||
REQUIRE(args2.to_delete.empty());
|
||||
|
||||
const auto args3 = retrieve_options({"-a", "ABC=XYZ", "-a", "1=2"});
|
||||
REQUIRE(args3.to_add == (std::map<std::string, std::string>{
|
||||
{"ABC", "XYZ"},
|
||||
{"1", "2"}}));
|
||||
REQUIRE(args3.to_delete.empty());
|
||||
|
||||
const auto opts = retrieve_options({"--add", "A=1", "-a", "B=2"});
|
||||
const auto handler1 = get_handler<InsertionTagsHandler>(opts, 0);
|
||||
const auto handler2 = get_handler<InsertionTagsHandler>(opts, 1);
|
||||
REQUIRE(handler1->get_tag_key() == "A");
|
||||
REQUIRE(handler1->get_tag_value() == "1");
|
||||
REQUIRE(handler2->get_tag_key() == "B");
|
||||
REQUIRE(handler2->get_tag_value() == "2");
|
||||
REQUIRE_THROWS(retrieve_options({"--add", "invalid"}));
|
||||
}
|
||||
|
||||
SECTION("--set") {
|
||||
const auto args1 = retrieve_options({"--set", "ABC=XYZ"});
|
||||
const auto args2 = retrieve_options({"-s", "ABC=XYZ"});
|
||||
REQUIRE(args1.to_add == args2.to_add);
|
||||
REQUIRE(args1.to_add
|
||||
== (std::map<std::string, std::string>{{"ABC", "XYZ"}}));
|
||||
REQUIRE(args1.to_delete == args2.to_delete);
|
||||
REQUIRE(args1.to_delete == std::vector<std::string>{"ABC"});
|
||||
|
||||
const auto args3 = retrieve_options({"-s", "ABC=XYZ", "-s", "1=2"});
|
||||
REQUIRE(args3.to_add == (std::map<std::string, std::string>{
|
||||
{"ABC", "XYZ"},
|
||||
{"1", "2"}}));
|
||||
REQUIRE(args3.to_delete == (std::vector<std::string>{"ABC", "1"}));
|
||||
|
||||
const auto opts = retrieve_options({"--set", "A=1", "-s", "B=2"});
|
||||
const auto handler1 = get_handler<ModificationTagsHandler>(opts, 0);
|
||||
const auto handler2 = get_handler<ModificationTagsHandler>(opts, 1);
|
||||
REQUIRE(handler1->get_tag_key() == "A");
|
||||
REQUIRE(handler1->get_tag_value() == "1");
|
||||
REQUIRE(handler2->get_tag_key() == "B");
|
||||
REQUIRE(handler2->get_tag_value() == "2");
|
||||
REQUIRE_THROWS(retrieve_options({"--set", "invalid"}));
|
||||
}
|
||||
|
||||
SECTION("--stream") {
|
||||
// by default, use all the streams
|
||||
REQUIRE(
|
||||
get_handler<RemovalTagsHandler>(retrieve_options({"-d", "xyz"}), 0)
|
||||
->get_streamno() == StreamTagsHandler::ALL_STREAMS);
|
||||
|
||||
// ...unless the user supplies an option to use a specific stream
|
||||
REQUIRE(
|
||||
get_handler<RemovalTagsHandler>(
|
||||
retrieve_options({"--stream", "1", "-d", "xyz"}), 0)
|
||||
->get_streamno() == 1);
|
||||
|
||||
// ...which can be combined multiple times
|
||||
{
|
||||
const auto opts = retrieve_options({
|
||||
"--stream", "1",
|
||||
"-d", "xyz",
|
||||
"--stream", "2",
|
||||
"-d", "abc"});
|
||||
const auto handler1 = get_handler<RemovalTagsHandler>(opts, 0);
|
||||
const auto handler2 = get_handler<RemovalTagsHandler>(opts, 1);
|
||||
REQUIRE(handler1->get_streamno() == 1);
|
||||
REQUIRE(handler2->get_streamno() == 2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user