mirror of https://github.com/JAJames/jessilib.git
Jessica James
5 years ago
5 changed files with 464 additions and 4 deletions
@ -0,0 +1,136 @@ |
|||
/**
|
|||
* Copyright (C) 2019 Jessica James. |
|||
* |
|||
* Permission to use, copy, modify, and/or distribute this software for any |
|||
* purpose with or without fee is hereby granted, provided that the above |
|||
* copyright notice and this permission notice appear in all copies. |
|||
* |
|||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
|||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
|||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY |
|||
* SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
|||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION |
|||
* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN |
|||
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
|||
* |
|||
* Written by Jessica James <jessica.aj@outlook.com> |
|||
*/ |
|||
|
|||
#include "app_parameters.hpp" |
|||
|
|||
namespace jessilib { |
|||
|
|||
app_parameters::app_parameters(int in_argc, char** in_argv) |
|||
: app_parameters{ in_argc, const_cast<const char**>(in_argv) } { |
|||
// Empty ctor body
|
|||
} |
|||
|
|||
app_parameters::app_parameters(int in_argc, const char** in_argv) { |
|||
// Sanity safety check; should never happen
|
|||
if (in_argc <= 0 || in_argv == nullptr) { |
|||
return; |
|||
} |
|||
|
|||
// Populate path
|
|||
m_path = in_argv[0]; |
|||
|
|||
// Process args
|
|||
std::string_view key{ nullptr }; |
|||
std::string value; |
|||
auto flush_value = [&key, &value, this]() { |
|||
// This is the start of a key; flush what we were previously processing
|
|||
if (!key.empty()) { |
|||
if (value.empty()) { |
|||
m_switches.emplace_back(key); |
|||
} |
|||
else { |
|||
m_values.emplace(key, std::move(value)); |
|||
value.clear(); |
|||
} |
|||
} |
|||
}; |
|||
|
|||
for (int index = 1; index < in_argc; ++index) { |
|||
const char* arg = in_argv[index]; |
|||
if (arg != nullptr && *arg != '\0') { |
|||
// Check if this is a key or value
|
|||
if (*arg == '-') { |
|||
// Flush pending value (if any)
|
|||
flush_value(); |
|||
|
|||
// Strip any leading '-' or '--' and set key
|
|||
key = arg + 1; |
|||
if (key[0] == '-') { |
|||
key.remove_prefix(1); |
|||
} |
|||
|
|||
// Parse key for any value denominator ('=')
|
|||
size_t key_end = key.find('='); |
|||
if (key_end != std::string_view::npos) { |
|||
// arg contains start of a value
|
|||
value = key.substr(key_end + 1); |
|||
key = key.substr(0, key_end); |
|||
} |
|||
} |
|||
else { |
|||
// This is part of a value; add it
|
|||
if (!value.empty()) { |
|||
value += ' '; |
|||
} |
|||
|
|||
value += arg; |
|||
} |
|||
} |
|||
// else // empty string encountered
|
|||
|
|||
// Push arg
|
|||
m_args.emplace_back(arg); |
|||
} |
|||
|
|||
// Flush any pending switch/value
|
|||
flush_value(); |
|||
} |
|||
|
|||
std::string_view app_parameters::path() const { |
|||
return m_path; |
|||
} |
|||
|
|||
const std::vector<std::string_view>& app_parameters::arguments() const { |
|||
return m_args; |
|||
} |
|||
|
|||
const std::vector<std::string_view>& app_parameters::switches() const { |
|||
return m_switches; |
|||
} |
|||
|
|||
std::unordered_set<std::string_view> app_parameters::switches_set() const { |
|||
return { m_switches.begin(), m_switches.end() }; |
|||
} |
|||
|
|||
const std::unordered_map<std::string_view, std::string>& app_parameters::values() const { |
|||
return m_values; |
|||
} |
|||
|
|||
object app_parameters::as_object() const { |
|||
// Null check
|
|||
if (m_path.empty() |
|||
&& m_args.empty()) { |
|||
// app_parameters is null; return a null object
|
|||
return object{}; |
|||
} |
|||
|
|||
// Transform m_values into appropriate map type; TODO: add helper to object for this
|
|||
std::map<std::string, object> values_map; |
|||
for (auto& value : m_values) { |
|||
values_map.emplace(value.first, value.second); |
|||
} |
|||
|
|||
return std::map<std::string, object>{ |
|||
{ "Path", m_path }, |
|||
{ "Args", m_args }, |
|||
{ "Switches", m_switches }, |
|||
{ "Values", values_map } |
|||
}; |
|||
} |
|||
|
|||
} // namespace jessilib
|
@ -0,0 +1,44 @@ |
|||
/**
|
|||
* Copyright (C) 2019 Jessica James. |
|||
* |
|||
* Permission to use, copy, modify, and/or distribute this software for any |
|||
* purpose with or without fee is hereby granted, provided that the above |
|||
* copyright notice and this permission notice appear in all copies. |
|||
* |
|||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
|||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
|||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY |
|||
* SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
|||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION |
|||
* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN |
|||
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
|||
* |
|||
* Written by Jessica James <jessica.aj@outlook.com> |
|||
*/ |
|||
|
|||
#include "object.hpp" |
|||
|
|||
namespace jessilib { |
|||
|
|||
class app_parameters { |
|||
public: |
|||
app_parameters(int in_argc, char** in_argv); |
|||
app_parameters(int in_argc, const char** in_argv); |
|||
|
|||
std::string_view path() const; |
|||
const std::vector<std::string_view>& arguments() const; |
|||
const std::vector<std::string_view>& switches() const; |
|||
std::unordered_set<std::string_view> switches_set() const; |
|||
const std::unordered_map<std::string_view, std::string>& values() const; |
|||
jessilib::object as_object() const; |
|||
|
|||
operator jessilib::object() const { return as_object(); } |
|||
|
|||
private: |
|||
std::string_view m_path; |
|||
std::vector<std::string_view> m_args; |
|||
std::vector<std::string_view> m_switches; |
|||
std::unordered_map<std::string_view, std::string> m_values; |
|||
}; |
|||
|
|||
} // namespace jessilib
|
@ -0,0 +1,277 @@ |
|||
/**
|
|||
* Copyright (C) 2020 Jessica James. |
|||
* |
|||
* Permission to use, copy, modify, and/or distribute this software for any |
|||
* purpose with or without fee is hereby granted, provided that the above |
|||
* copyright notice and this permission notice appear in all copies. |
|||
* |
|||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
|||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
|||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY |
|||
* SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
|||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION |
|||
* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN |
|||
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
|||
* |
|||
* Written by Jessica James <jessica.aj@outlook.com> |
|||
*/ |
|||
|
|||
#include "test.hpp" |
|||
#include "app_parameters.hpp" |
|||
|
|||
using namespace jessilib; |
|||
using namespace std::literals; |
|||
|
|||
class ArgWrapper { |
|||
public: |
|||
template<typename... Args> |
|||
ArgWrapper(Args... in_args) |
|||
: ArgWrapper{ std::vector<std::string>{ in_args... } } { |
|||
// Empty ctor body
|
|||
} |
|||
|
|||
ArgWrapper(std::vector<std::string> in_args) |
|||
: m_args{ in_args }, |
|||
m_argv{ new const char*[in_args.size()] } { |
|||
// Populate m_argv
|
|||
for (size_t index = 0; index != m_args.size(); ++index) { |
|||
m_argv[index] = m_args[index].c_str(); |
|||
} |
|||
} |
|||
|
|||
const char** argv() const { |
|||
return m_argv.get(); |
|||
} |
|||
|
|||
int argc() const { |
|||
return m_args.size(); |
|||
} |
|||
|
|||
private: |
|||
std::vector<std::string> m_args; |
|||
std::unique_ptr<const char*[]> m_argv; |
|||
}; |
|||
|
|||
TEST(AppParametersTest, null) { |
|||
app_parameters parameters{ 0, static_cast<const char**>(nullptr) }; |
|||
app_parameters parameters2{ 1234, static_cast<const char**>(nullptr) }; |
|||
|
|||
EXPECT_TRUE(parameters.path().empty()); |
|||
EXPECT_TRUE(parameters.arguments().empty()); |
|||
EXPECT_TRUE(parameters.switches().empty()); |
|||
EXPECT_TRUE(parameters.switches_set().empty()); |
|||
EXPECT_TRUE(parameters.values().empty()); |
|||
EXPECT_TRUE(parameters.as_object().null()); |
|||
|
|||
EXPECT_TRUE(parameters2.path().empty()); |
|||
EXPECT_TRUE(parameters2.arguments().empty()); |
|||
EXPECT_TRUE(parameters2.switches().empty()); |
|||
EXPECT_TRUE(parameters2.switches_set().empty()); |
|||
EXPECT_TRUE(parameters2.values().empty()); |
|||
EXPECT_TRUE(parameters2.as_object().null()); |
|||
} |
|||
|
|||
TEST(AppParametersTest, path_only) { |
|||
ArgWrapper args{ "/path/to/exe" }; |
|||
app_parameters parameters{ args.argc(), args.argv() }; |
|||
|
|||
EXPECT_EQ(parameters.path(), "/path/to/exe"); |
|||
EXPECT_TRUE(parameters.arguments().empty()); |
|||
EXPECT_TRUE(parameters.switches().empty()); |
|||
EXPECT_TRUE(parameters.switches_set().empty()); |
|||
EXPECT_TRUE(parameters.values().empty()); |
|||
|
|||
auto obj = parameters.as_object(); |
|||
EXPECT_FALSE(obj.null()); |
|||
EXPECT_EQ(obj["Path"], "/path/to/exe"); |
|||
} |
|||
|
|||
TEST(AppParametersTest, single_switch) { |
|||
ArgWrapper args{ "/path/to/exe", "-switch" }; |
|||
app_parameters parameters{ args.argc(), args.argv() }; |
|||
|
|||
EXPECT_FALSE(parameters.path().empty()); |
|||
EXPECT_EQ(parameters.arguments().size(), 1U); |
|||
EXPECT_EQ(parameters.switches().size(), 1U); |
|||
EXPECT_EQ(parameters.switches_set().size(), 1U); |
|||
EXPECT_TRUE(parameters.values().empty()); |
|||
|
|||
auto obj = parameters.as_object(); |
|||
EXPECT_FALSE(obj.null()); |
|||
EXPECT_EQ(obj["Path"], "/path/to/exe"); |
|||
EXPECT_EQ(obj["Args"], object{ std::vector<std::string>{ "-switch" } }); |
|||
EXPECT_EQ(obj["Switches"], object{ std::vector<std::string>{ "switch" } }); |
|||
} |
|||
|
|||
TEST(AppParametersTest, double_switch) { |
|||
ArgWrapper args{ "/path/to/exe", "-switch1", "--switch2" }; |
|||
app_parameters parameters{ args.argc(), args.argv() }; |
|||
|
|||
EXPECT_FALSE(parameters.path().empty()); |
|||
EXPECT_EQ(parameters.arguments().size(), 2U); |
|||
EXPECT_EQ(parameters.switches().size(), 2U); |
|||
EXPECT_EQ(parameters.switches_set().size(), 2U); |
|||
EXPECT_TRUE(parameters.values().empty()); |
|||
|
|||
auto obj = parameters.as_object(); |
|||
std::vector<std::string> expected_args{ "-switch1", "--switch2" }; |
|||
std::vector<std::string> expected_switches{ "switch1", "switch2" }; |
|||
EXPECT_FALSE(obj.null()); |
|||
EXPECT_EQ(obj["Path"], "/path/to/exe"); |
|||
EXPECT_EQ(obj["Args"], expected_args); |
|||
EXPECT_EQ(obj["Switches"], expected_switches); |
|||
} |
|||
|
|||
TEST(AppParametersTest, duplicate_switch) { |
|||
ArgWrapper args{ "/path/to/exe", "-switch", "--switch" }; |
|||
app_parameters parameters{ args.argc(), args.argv() }; |
|||
|
|||
EXPECT_FALSE(parameters.path().empty()); |
|||
EXPECT_EQ(parameters.arguments().size(), 2U); |
|||
EXPECT_EQ(parameters.switches().size(), 2U); |
|||
EXPECT_EQ(parameters.switches_set().size(), 1U); |
|||
EXPECT_TRUE(parameters.values().empty()); |
|||
|
|||
auto obj = parameters.as_object(); |
|||
std::vector<std::string> expected_args{ "-switch", "--switch" }; |
|||
std::vector<std::string> expected_switches{ "switch", "switch" }; |
|||
EXPECT_FALSE(obj.null()); |
|||
EXPECT_EQ(obj["Path"], "/path/to/exe"); |
|||
EXPECT_EQ(obj["Args"], expected_args); |
|||
EXPECT_EQ(obj["Switches"], expected_switches); |
|||
} |
|||
|
|||
TEST(AppParametersTest, single_value) { |
|||
ArgWrapper args{ "/path/to/exe", "-key", "value" }; |
|||
app_parameters parameters{ args.argc(), args.argv() }; |
|||
|
|||
EXPECT_FALSE(parameters.path().empty()); |
|||
EXPECT_EQ(parameters.arguments().size(), 2U); |
|||
EXPECT_EQ(parameters.switches().size(), 0U); |
|||
EXPECT_EQ(parameters.switches_set().size(), 0U); |
|||
EXPECT_EQ(parameters.values().size(), 1U); |
|||
|
|||
auto obj = parameters.as_object(); |
|||
std::vector<std::string> expected_args{ "-key", "value" }; |
|||
std::map<std::string, object> expected_values{ { "key", "value" } }; |
|||
EXPECT_FALSE(obj.null()); |
|||
EXPECT_EQ(obj["Path"], "/path/to/exe"); |
|||
EXPECT_EQ(obj["Args"], expected_args); |
|||
EXPECT_EQ(obj["Values"], expected_values); |
|||
} |
|||
|
|||
TEST(AppParametersTest, single_value_eq) { |
|||
ArgWrapper args{ "/path/to/exe", "-key=value" }; |
|||
app_parameters parameters{ args.argc(), args.argv() }; |
|||
|
|||
EXPECT_FALSE(parameters.path().empty()); |
|||
EXPECT_EQ(parameters.arguments().size(), 1U); |
|||
EXPECT_EQ(parameters.switches().size(), 0U); |
|||
EXPECT_EQ(parameters.switches_set().size(), 0U); |
|||
EXPECT_EQ(parameters.values().size(), 1U); |
|||
|
|||
auto obj = parameters.as_object(); |
|||
std::vector<std::string> expected_args{ "-key=value" }; |
|||
std::map<std::string, object> expected_values{ { "key", "value" } }; |
|||
EXPECT_FALSE(obj.null()); |
|||
EXPECT_EQ(obj["Path"], "/path/to/exe"); |
|||
EXPECT_EQ(obj["Args"], expected_args); |
|||
EXPECT_EQ(obj["Values"], expected_values); |
|||
} |
|||
|
|||
TEST(AppParametersTest, multiword_value) { |
|||
ArgWrapper args{ "/path/to/exe", "-key", "valuePart1", "valuePart2" }; |
|||
app_parameters parameters{ args.argc(), args.argv() }; |
|||
|
|||
EXPECT_FALSE(parameters.path().empty()); |
|||
EXPECT_EQ(parameters.arguments().size(), 3U); |
|||
EXPECT_EQ(parameters.switches().size(), 0U); |
|||
EXPECT_EQ(parameters.switches_set().size(), 0U); |
|||
EXPECT_EQ(parameters.values().size(), 1U); |
|||
|
|||
auto obj = parameters.as_object(); |
|||
std::vector<std::string> expected_args{ "-key", "valuePart1", "valuePart2" }; |
|||
std::map<std::string, object> expected_values{ { "key", "valuePart1 valuePart2" } }; |
|||
EXPECT_FALSE(obj.null()); |
|||
EXPECT_EQ(obj["Path"], "/path/to/exe"); |
|||
EXPECT_EQ(obj["Args"], expected_args); |
|||
EXPECT_EQ(obj["Values"], expected_values); |
|||
} |
|||
|
|||
TEST(AppParametersTest, multiword_value_eq) { |
|||
ArgWrapper args{ "/path/to/exe", "-key=valuePart1", "valuePart2" }; |
|||
app_parameters parameters{ args.argc(), args.argv() }; |
|||
|
|||
EXPECT_FALSE(parameters.path().empty()); |
|||
EXPECT_EQ(parameters.arguments().size(), 2U); |
|||
EXPECT_EQ(parameters.switches().size(), 0U); |
|||
EXPECT_EQ(parameters.switches_set().size(), 0U); |
|||
EXPECT_EQ(parameters.values().size(), 1U); |
|||
|
|||
auto obj = parameters.as_object(); |
|||
std::vector<std::string> expected_args{ "-key=valuePart1", "valuePart2" }; |
|||
std::map<std::string, object> expected_values{ { "key", "valuePart1 valuePart2" } }; |
|||
EXPECT_FALSE(obj.null()); |
|||
EXPECT_EQ(obj["Path"], "/path/to/exe"); |
|||
EXPECT_EQ(obj["Args"], expected_args); |
|||
EXPECT_EQ(obj["Values"], expected_values); |
|||
} |
|||
|
|||
TEST(AppParametersTest, double_value) { |
|||
ArgWrapper args{ "/path/to/exe", "-key", "value", "--key2", "value2" }; |
|||
app_parameters parameters{ args.argc(), args.argv() }; |
|||
|
|||
EXPECT_FALSE(parameters.path().empty()); |
|||
EXPECT_EQ(parameters.arguments().size(), 4U); |
|||
EXPECT_EQ(parameters.switches().size(), 0U); |
|||
EXPECT_EQ(parameters.switches_set().size(), 0U); |
|||
EXPECT_EQ(parameters.values().size(), 2U); |
|||
|
|||
auto obj = parameters.as_object(); |
|||
std::vector<std::string> expected_args{ "-key", "value", "--key2", "value2" }; |
|||
std::map<std::string, object> expected_values{ { "key", "value" }, { "key2", "value2" } }; |
|||
EXPECT_FALSE(obj.null()); |
|||
EXPECT_EQ(obj["Path"], "/path/to/exe"); |
|||
EXPECT_EQ(obj["Args"], expected_args); |
|||
EXPECT_EQ(obj["Values"], expected_values); |
|||
} |
|||
|
|||
TEST(AppParametersTest, double_value_eq) { |
|||
ArgWrapper args{ "/path/to/exe", "-key=value", "--key2=value2" }; |
|||
app_parameters parameters{ args.argc(), args.argv() }; |
|||
|
|||
EXPECT_FALSE(parameters.path().empty()); |
|||
EXPECT_EQ(parameters.arguments().size(), 2U); |
|||
EXPECT_EQ(parameters.switches().size(), 0U); |
|||
EXPECT_EQ(parameters.switches_set().size(), 0U); |
|||
EXPECT_EQ(parameters.values().size(), 2U); |
|||
|
|||
auto obj = parameters.as_object(); |
|||
std::vector<std::string> expected_args{ "-key=value", "--key2=value2" }; |
|||
std::map<std::string, object> expected_values{ { "key", "value" }, { "key2", "value2" } }; |
|||
EXPECT_FALSE(obj.null()); |
|||
EXPECT_EQ(obj["Path"], "/path/to/exe"); |
|||
EXPECT_EQ(obj["Args"], expected_args); |
|||
EXPECT_EQ(obj["Values"], expected_values); |
|||
} |
|||
|
|||
TEST(AppParametersTest, switch_and_value) { |
|||
ArgWrapper args{ "/path/to/exe", "--switch", "-key", "value" }; |
|||
app_parameters parameters{ args.argc(), args.argv() }; |
|||
|
|||
EXPECT_FALSE(parameters.path().empty()); |
|||
EXPECT_EQ(parameters.arguments().size(), 3U); |
|||
EXPECT_EQ(parameters.switches().size(), 1U); |
|||
EXPECT_EQ(parameters.switches_set().size(), 1U); |
|||
EXPECT_EQ(parameters.values().size(), 1U); |
|||
|
|||
auto obj = parameters.as_object(); |
|||
std::vector<std::string> expected_args{ "--switch", "-key", "value" }; |
|||
std::vector<std::string> expected_switches{ "switch" }; |
|||
std::map<std::string, object> expected_values{ { "key", "value" } }; |
|||
EXPECT_FALSE(obj.null()); |
|||
EXPECT_EQ(obj["Path"], "/path/to/exe"); |
|||
EXPECT_EQ(obj["Args"], expected_args); |
|||
EXPECT_EQ(obj["Switches"], expected_switches); |
|||
EXPECT_EQ(obj["Values"], expected_values); |
|||
} |
Loading…
Reference in new issue