You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
332 lines
16 KiB
332 lines
16 KiB
/* |
|
* This file is a part of PikoTools |
|
* and is distributed under the (new) BSD licence. |
|
* Author: Tomasz Sowa <t.sowa@ttmath.org> |
|
*/ |
|
|
|
/* |
|
* Copyright (c) 2021, Tomasz Sowa |
|
* All rights reserved. |
|
* |
|
* Redistribution and use in source and binary forms, with or without |
|
* modification, are permitted provided that the following conditions are met: |
|
* |
|
* * Redistributions of source code must retain the above copyright notice, |
|
* this list of conditions and the following disclaimer. |
|
* |
|
* * Redistributions in binary form must reproduce the above copyright |
|
* notice, this list of conditions and the following disclaimer in the |
|
* documentation and/or other materials provided with the distribution. |
|
* |
|
* * Neither the name Tomasz Sowa nor the names of contributors to this |
|
* project may be used to endorse or promote products derived |
|
* from this software without specific prior written permission. |
|
* |
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" |
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE |
|
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF |
|
* THE POSSIBILITY OF SUCH DAMAGE. |
|
*/ |
|
|
|
#include <iostream> |
|
#include "mainoptionsparser.h" |
|
#include "test.h" |
|
#include "mainoptions/mainoptionsparser.h" |
|
#include "utf8/utf8.h" |
|
#include "convert/convert.h" |
|
|
|
namespace pt |
|
{ |
|
|
|
namespace pt_mainoptions_tests |
|
{ |
|
|
|
|
|
struct MainOptionsParserOutputTest |
|
{ |
|
MainOptionsParser::Status status; |
|
const char * option_err; |
|
const char * json; |
|
}; |
|
|
|
|
|
void print_status(MainOptionsParser::Status status) |
|
{ |
|
if( status == MainOptionsParser::status_ok ) |
|
{ |
|
std::cout << "MainOptionsParser::status_ok"; |
|
} |
|
else |
|
if( status == MainOptionsParser::status_argument_not_provided ) |
|
{ |
|
std::cout << "MainOptionsParser::status_argument_not_provided"; |
|
} |
|
else |
|
if( status == MainOptionsParser::status_argument_provided ) |
|
{ |
|
std::cout << "MainOptionsParser::status_argument_provided"; |
|
} |
|
} |
|
|
|
|
|
bool has_space_in_str(const char * arg) |
|
{ |
|
while( *arg ) |
|
{ |
|
if( is_white((wchar_t)*arg) ) |
|
return true; |
|
|
|
arg += 1; |
|
} |
|
|
|
return false; |
|
} |
|
|
|
|
|
void print_args(int to_index, const char ** argv) |
|
{ |
|
for(int i=0 ; i <= to_index ; ++i) |
|
{ |
|
bool has_space = has_space_in_str(argv[i]); |
|
|
|
if( has_space ) |
|
std::cout << "\""; |
|
|
|
std::cout << argv[i]; |
|
|
|
if( has_space ) |
|
std::cout << "\""; |
|
|
|
std::cout << " "; |
|
} |
|
|
|
std::cout << std::endl; |
|
} |
|
|
|
|
|
|
|
void test_mainoptionsparser(size_t len, const char ** argv, const Space & arguments_required, MainOptionsParserOutputTest * output) |
|
{ |
|
reset_test_counter("mainoptionsparser"); |
|
std::cout << "Testing MainArgsParser" << std::endl; |
|
|
|
MainOptionsParser parser; |
|
Space space; |
|
|
|
/* |
|
* set to true when creating new tests (you can copy console output to the cpp file) |
|
*/ |
|
bool prepare_tests = false; |
|
|
|
for(size_t i = 0 ; i < len ; ++i) |
|
{ |
|
if( !prepare_tests ) |
|
print_args(i, argv); |
|
|
|
MainOptionsParser::Status status = parser.parse(i + 1, argv, space, arguments_required); |
|
|
|
std::wstring & err_wstr = parser.get_wrong_option(); |
|
std::string err_str; |
|
WideToUTF8(err_wstr, err_str); |
|
|
|
std::string json; |
|
space.serialize_to_json_to(json); |
|
|
|
std::cout << "{"; |
|
print_status(status); |
|
std::cout << ", " << "\"" << err_str << "\", " << "R\"json(" << json << ")json\"" << "}," << std::endl; |
|
|
|
if( !prepare_tests ) |
|
{ |
|
test("status", status, output[i].status); |
|
test("err_arg", err_str.c_str(), output[i].option_err); |
|
test("json", json.c_str(), output[i].json); |
|
} |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
void test_mainoptionsparser1() |
|
{ |
|
const char * argv[] = { |
|
"program_name", |
|
"-a", |
|
"-b", |
|
"-c", |
|
"-d", |
|
"argument for d", |
|
"-b", |
|
"--long", |
|
"--foo", |
|
"foo-one", |
|
"foo-two", |
|
"--long-option", |
|
"--bar", |
|
"bar1", |
|
"bar2", |
|
"bar3", |
|
"-x", |
|
"--piggy2=option_for_piggy2", |
|
"--piggy3", |
|
"--bar", |
|
"xbar1", |
|
"xbar2", |
|
"xbar3", |
|
"--piggy2 another_option_for_piggy2", |
|
"--", |
|
"non-option-argument1", |
|
"non-option-argument2", |
|
"non-option-argument3", |
|
}; |
|
|
|
MainOptionsParserOutputTest output[] = { |
|
{MainOptionsParser::status_ok, "", R"json({})json"}, |
|
{MainOptionsParser::status_ok, "", R"json({"a":[[]]})json"}, |
|
{MainOptionsParser::status_ok, "", R"json({"a":[[]],"b":[[]]})json"}, |
|
{MainOptionsParser::status_ok, "", R"json({"a":[[]],"b":[[]],"c":[[]]})json"}, |
|
{MainOptionsParser::status_argument_not_provided, "d", R"json({"a":[[]],"b":[[]],"c":[[]],"d":[[]]})json"}, |
|
{MainOptionsParser::status_ok, "", R"json({"a":[[]],"b":[[]],"c":[[]],"d":[["argument for d"]]})json"}, |
|
{MainOptionsParser::status_ok, "", R"json({"a":[[]],"b":[[],[]],"c":[[]],"d":[["argument for d"]]})json"}, |
|
{MainOptionsParser::status_ok, "", R"json({"a":[[]],"b":[[],[]],"c":[[]],"d":[["argument for d"]],"long":[[]]})json"}, |
|
{MainOptionsParser::status_argument_not_provided, "foo", R"json({"a":[[]],"b":[[],[]],"c":[[]],"d":[["argument for d"]],"foo":[[]],"long":[[]]})json"}, |
|
{MainOptionsParser::status_argument_not_provided, "foo", R"json({"a":[[]],"b":[[],[]],"c":[[]],"d":[["argument for d"]],"foo":[["foo-one"]],"long":[[]]})json"}, |
|
{MainOptionsParser::status_ok, "", R"json({"a":[[]],"b":[[],[]],"c":[[]],"d":[["argument for d"]],"foo":[["foo-one","foo-two"]],"long":[[]]})json"}, |
|
{MainOptionsParser::status_ok, "", R"json({"a":[[]],"b":[[],[]],"c":[[]],"d":[["argument for d"]],"foo":[["foo-one","foo-two"]],"long":[[]],"long-option":[[]]})json"}, |
|
{MainOptionsParser::status_argument_not_provided, "bar", R"json({"a":[[]],"b":[[],[]],"bar":[[]],"c":[[]],"d":[["argument for d"]],"foo":[["foo-one","foo-two"]],"long":[[]],"long-option":[[]]})json"}, |
|
{MainOptionsParser::status_argument_not_provided, "bar", R"json({"a":[[]],"b":[[],[]],"bar":[["bar1"]],"c":[[]],"d":[["argument for d"]],"foo":[["foo-one","foo-two"]],"long":[[]],"long-option":[[]]})json"}, |
|
{MainOptionsParser::status_argument_not_provided, "bar", R"json({"a":[[]],"b":[[],[]],"bar":[["bar1","bar2"]],"c":[[]],"d":[["argument for d"]],"foo":[["foo-one","foo-two"]],"long":[[]],"long-option":[[]]})json"}, |
|
{MainOptionsParser::status_ok, "", R"json({"a":[[]],"b":[[],[]],"bar":[["bar1","bar2","bar3"]],"c":[[]],"d":[["argument for d"]],"foo":[["foo-one","foo-two"]],"long":[[]],"long-option":[[]]})json"}, |
|
{MainOptionsParser::status_ok, "", R"json({"a":[[]],"b":[[],[]],"bar":[["bar1","bar2","bar3"]],"c":[[]],"d":[["argument for d"]],"foo":[["foo-one","foo-two"]],"long":[[]],"long-option":[[]],"x":[[]]})json"}, |
|
{MainOptionsParser::status_ok, "", R"json({"a":[[]],"b":[[],[]],"bar":[["bar1","bar2","bar3"]],"c":[[]],"d":[["argument for d"]],"foo":[["foo-one","foo-two"]],"long":[[]],"long-option":[[]],"piggy2":[["option_for_piggy2"]],"x":[[]]})json"}, |
|
{MainOptionsParser::status_ok, "", R"json({"a":[[]],"b":[[],[]],"bar":[["bar1","bar2","bar3"]],"c":[[]],"d":[["argument for d"]],"foo":[["foo-one","foo-two"]],"long":[[]],"long-option":[[]],"piggy2":[["option_for_piggy2"]],"piggy3":[[]],"x":[[]]})json"}, |
|
{MainOptionsParser::status_argument_not_provided, "bar", R"json({"a":[[]],"b":[[],[]],"bar":[["bar1","bar2","bar3"],[]],"c":[[]],"d":[["argument for d"]],"foo":[["foo-one","foo-two"]],"long":[[]],"long-option":[[]],"piggy2":[["option_for_piggy2"]],"piggy3":[[]],"x":[[]]})json"}, |
|
{MainOptionsParser::status_argument_not_provided, "bar", R"json({"a":[[]],"b":[[],[]],"bar":[["bar1","bar2","bar3"],["xbar1"]],"c":[[]],"d":[["argument for d"]],"foo":[["foo-one","foo-two"]],"long":[[]],"long-option":[[]],"piggy2":[["option_for_piggy2"]],"piggy3":[[]],"x":[[]]})json"}, |
|
{MainOptionsParser::status_argument_not_provided, "bar", R"json({"a":[[]],"b":[[],[]],"bar":[["bar1","bar2","bar3"],["xbar1","xbar2"]],"c":[[]],"d":[["argument for d"]],"foo":[["foo-one","foo-two"]],"long":[[]],"long-option":[[]],"piggy2":[["option_for_piggy2"]],"piggy3":[[]],"x":[[]]})json"}, |
|
{MainOptionsParser::status_ok, "", R"json({"a":[[]],"b":[[],[]],"bar":[["bar1","bar2","bar3"],["xbar1","xbar2","xbar3"]],"c":[[]],"d":[["argument for d"]],"foo":[["foo-one","foo-two"]],"long":[[]],"long-option":[[]],"piggy2":[["option_for_piggy2"]],"piggy3":[[]],"x":[[]]})json"}, |
|
{MainOptionsParser::status_ok, "", R"json({"a":[[]],"b":[[],[]],"bar":[["bar1","bar2","bar3"],["xbar1","xbar2","xbar3"]],"c":[[]],"d":[["argument for d"]],"foo":[["foo-one","foo-two"]],"long":[[]],"long-option":[[]],"piggy2":[["option_for_piggy2"]],"piggy2 another_option_for_piggy2":[[]],"piggy3":[[]],"x":[[]]})json"}, |
|
{MainOptionsParser::status_ok, "", R"json({"a":[[]],"args":[],"b":[[],[]],"bar":[["bar1","bar2","bar3"],["xbar1","xbar2","xbar3"]],"c":[[]],"d":[["argument for d"]],"foo":[["foo-one","foo-two"]],"long":[[]],"long-option":[[]],"piggy2":[["option_for_piggy2"]],"piggy2 another_option_for_piggy2":[[]],"piggy3":[[]],"x":[[]]})json"}, |
|
{MainOptionsParser::status_ok, "", R"json({"a":[[]],"args":["non-option-argument1"],"b":[[],[]],"bar":[["bar1","bar2","bar3"],["xbar1","xbar2","xbar3"]],"c":[[]],"d":[["argument for d"]],"foo":[["foo-one","foo-two"]],"long":[[]],"long-option":[[]],"piggy2":[["option_for_piggy2"]],"piggy2 another_option_for_piggy2":[[]],"piggy3":[[]],"x":[[]]})json"}, |
|
{MainOptionsParser::status_ok, "", R"json({"a":[[]],"args":["non-option-argument1","non-option-argument2"],"b":[[],[]],"bar":[["bar1","bar2","bar3"],["xbar1","xbar2","xbar3"]],"c":[[]],"d":[["argument for d"]],"foo":[["foo-one","foo-two"]],"long":[[]],"long-option":[[]],"piggy2":[["option_for_piggy2"]],"piggy2 another_option_for_piggy2":[[]],"piggy3":[[]],"x":[[]]})json"}, |
|
{MainOptionsParser::status_ok, "", R"json({"a":[[]],"args":["non-option-argument1","non-option-argument2","non-option-argument3"],"b":[[],[]],"bar":[["bar1","bar2","bar3"],["xbar1","xbar2","xbar3"]],"c":[[]],"d":[["argument for d"]],"foo":[["foo-one","foo-two"]],"long":[[]],"long-option":[[]],"piggy2":[["option_for_piggy2"]],"piggy2 another_option_for_piggy2":[[]],"piggy3":[[]],"x":[[]]})json"}, |
|
}; |
|
|
|
Space arguments_required; |
|
arguments_required.add(L"d", 1); |
|
arguments_required.add(L"foo", 2); |
|
arguments_required.add(L"bar", 3); |
|
arguments_required.add(L"piggy", 1); |
|
arguments_required.add(L"piggy2", 1); |
|
|
|
size_t len = sizeof(argv) / sizeof(const char *); |
|
test_mainoptionsparser(len, argv, arguments_required, output); |
|
} |
|
|
|
|
|
|
|
void test_mainoptionsparser2() |
|
{ |
|
const char * argv[] = { |
|
"program_name", |
|
"--long1", |
|
"--long2=with-argument", |
|
"--long3", |
|
"-a", |
|
"--=option-for-empty-argument", |
|
"-b", |
|
"arg b 1", |
|
"arg b 2", |
|
"-c", |
|
"-f file-name with spaces", |
|
"--xxx", |
|
"arg 1", |
|
"arg 2", |
|
"arg 3", |
|
"-", /* first non-option argument */ |
|
"non-option-argument2", |
|
"non-option-argument3", |
|
"non-option-argument4", |
|
}; |
|
|
|
MainOptionsParserOutputTest output[] = { |
|
{MainOptionsParser::status_ok, "", R"json({})json"}, |
|
{MainOptionsParser::status_ok, "", R"json({"long1":[[]]})json"}, |
|
{MainOptionsParser::status_ok, "", R"json({"long1":[[]],"long2":[["with-argument"]]})json"}, |
|
{MainOptionsParser::status_ok, "", R"json({"long1":[[]],"long2":[["with-argument"]],"long3":[[]]})json"}, |
|
{MainOptionsParser::status_ok, "", R"json({"a":[[]],"long1":[[]],"long2":[["with-argument"]],"long3":[[]]})json"}, |
|
{MainOptionsParser::status_ok, "", R"json({"":[["option-for-empty-argument"]],"a":[[]],"long1":[[]],"long2":[["with-argument"]],"long3":[[]]})json"}, |
|
{MainOptionsParser::status_argument_not_provided, "b", R"json({"":[["option-for-empty-argument"]],"a":[[]],"b":[[]],"long1":[[]],"long2":[["with-argument"]],"long3":[[]]})json"}, |
|
{MainOptionsParser::status_argument_not_provided, "b", R"json({"":[["option-for-empty-argument"]],"a":[[]],"b":[["arg b 1"]],"long1":[[]],"long2":[["with-argument"]],"long3":[[]]})json"}, |
|
{MainOptionsParser::status_ok, "", R"json({"":[["option-for-empty-argument"]],"a":[[]],"b":[["arg b 1","arg b 2"]],"long1":[[]],"long2":[["with-argument"]],"long3":[[]]})json"}, |
|
{MainOptionsParser::status_ok, "", R"json({"":[["option-for-empty-argument"]],"a":[[]],"b":[["arg b 1","arg b 2"]],"c":[[]],"long1":[[]],"long2":[["with-argument"]],"long3":[[]]})json"}, |
|
{MainOptionsParser::status_ok, "", R"json({"":[["option-for-empty-argument"]],"a":[[]],"b":[["arg b 1","arg b 2"]],"c":[[]],"f":[[" file-name with spaces"]],"long1":[[]],"long2":[["with-argument"]],"long3":[[]]})json"}, |
|
{MainOptionsParser::status_argument_not_provided, "xxx", R"json({"":[["option-for-empty-argument"]],"a":[[]],"b":[["arg b 1","arg b 2"]],"c":[[]],"f":[[" file-name with spaces"]],"long1":[[]],"long2":[["with-argument"]],"long3":[[]],"xxx":[[]]})json"}, |
|
{MainOptionsParser::status_argument_not_provided, "xxx", R"json({"":[["option-for-empty-argument"]],"a":[[]],"b":[["arg b 1","arg b 2"]],"c":[[]],"f":[[" file-name with spaces"]],"long1":[[]],"long2":[["with-argument"]],"long3":[[]],"xxx":[["arg 1"]]})json"}, |
|
{MainOptionsParser::status_argument_not_provided, "xxx", R"json({"":[["option-for-empty-argument"]],"a":[[]],"b":[["arg b 1","arg b 2"]],"c":[[]],"f":[[" file-name with spaces"]],"long1":[[]],"long2":[["with-argument"]],"long3":[[]],"xxx":[["arg 1","arg 2"]]})json"}, |
|
{MainOptionsParser::status_ok, "", R"json({"":[["option-for-empty-argument"]],"a":[[]],"b":[["arg b 1","arg b 2"]],"c":[[]],"f":[[" file-name with spaces"]],"long1":[[]],"long2":[["with-argument"]],"long3":[[]],"xxx":[["arg 1","arg 2","arg 3"]]})json"}, |
|
{MainOptionsParser::status_ok, "", R"json({"":[["option-for-empty-argument"]],"a":[[]],"args":["-"],"b":[["arg b 1","arg b 2"]],"c":[[]],"f":[[" file-name with spaces"]],"long1":[[]],"long2":[["with-argument"]],"long3":[[]],"xxx":[["arg 1","arg 2","arg 3"]]})json"}, |
|
{MainOptionsParser::status_ok, "", R"json({"":[["option-for-empty-argument"]],"a":[[]],"args":["-","non-option-argument2"],"b":[["arg b 1","arg b 2"]],"c":[[]],"f":[[" file-name with spaces"]],"long1":[[]],"long2":[["with-argument"]],"long3":[[]],"xxx":[["arg 1","arg 2","arg 3"]]})json"}, |
|
{MainOptionsParser::status_ok, "", R"json({"":[["option-for-empty-argument"]],"a":[[]],"args":["-","non-option-argument2","non-option-argument3"],"b":[["arg b 1","arg b 2"]],"c":[[]],"f":[[" file-name with spaces"]],"long1":[[]],"long2":[["with-argument"]],"long3":[[]],"xxx":[["arg 1","arg 2","arg 3"]]})json"}, |
|
{MainOptionsParser::status_ok, "", R"json({"":[["option-for-empty-argument"]],"a":[[]],"args":["-","non-option-argument2","non-option-argument3","non-option-argument4"],"b":[["arg b 1","arg b 2"]],"c":[[]],"f":[[" file-name with spaces"]],"long1":[[]],"long2":[["with-argument"]],"long3":[[]],"xxx":[["arg 1","arg 2","arg 3"]]})json"}, |
|
}; |
|
|
|
Space arguments_required; |
|
arguments_required.add(L"long2", 1); |
|
arguments_required.add(L"b", 2); |
|
arguments_required.add(L"f", 1); |
|
arguments_required.add(L"xxx", 3); |
|
arguments_required.add(L"", 1); |
|
|
|
size_t len = sizeof(argv) / sizeof(const char *); |
|
test_mainoptionsparser(len, argv, arguments_required, output); |
|
} |
|
|
|
|
|
|
|
void test_mainoptionsparser3() |
|
{ |
|
const char * argv[] = { |
|
"program_name", |
|
"--long1", |
|
"--long2=with-argument", |
|
"--long3", |
|
}; |
|
|
|
MainOptionsParserOutputTest output[] = { |
|
{MainOptionsParser::status_ok, "", R"json({})json"}, |
|
{MainOptionsParser::status_ok, "", R"json({"long1":[[]]})json"}, |
|
{MainOptionsParser::status_argument_provided, "long2", R"json({"long1":[[]]})json"}, |
|
{MainOptionsParser::status_argument_provided, "long2", R"json({"long1":[[]]})json"}, |
|
}; |
|
|
|
Space arguments_required; |
|
arguments_required.add(L"non-existing", 1); |
|
|
|
size_t len = sizeof(argv) / sizeof(const char *); |
|
test_mainoptionsparser(len, argv, arguments_required, output); |
|
} |
|
|
|
|
|
|
|
|
|
void make_tests() |
|
{ |
|
test_mainoptionsparser1(); |
|
test_mainoptionsparser2(); |
|
test_mainoptionsparser3(); |
|
} |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|