#include #include #include #include #define CLAP ::yycc::carton::clap namespace yycctest::carton::clap { using Token = CLAP::types::Token; namespace validator = CLAP::validator; #pragma region Clap Builder // YYC MARK: // GoogleTest do not allow use TEST and TEST_F in the same test suite // So I was forcely split following builder checker into independent test suit. TEST(CartonClapOption, BadOption) { // No short name and long name. EXPECT_ANY_THROW(auto opt = CLAP::option::Option(std::nullopt, std::nullopt, std::nullopt, u8"")); // Empty short name or long name. EXPECT_ANY_THROW(auto opt = CLAP::option::Option(u8"", std::nullopt, std::nullopt, u8"")); EXPECT_ANY_THROW(auto opt = CLAP::option::Option(std::nullopt, u8"", std::nullopt, u8"")); // Bad short name EXPECT_ANY_THROW(auto opt = CLAP::option::Option(u8"-", std::nullopt, std::nullopt, u8"")); } TEST(CartonClapOption, BadOptions) { // Duplicated. { auto options = CLAP::option::OptionCollection(); options.add_option(CLAP::option::Option(u8"a", std::nullopt, std::nullopt, u8"")); EXPECT_ANY_THROW(options.add_option(CLAP::option::Option(u8"a", std::nullopt, std::nullopt, u8""))); } // Duplicate between long name and short name. { auto options = CLAP::option::OptionCollection(); options.add_option(CLAP::option::Option(u8"a", std::nullopt, std::nullopt, u8"")); EXPECT_ANY_THROW(options.add_option(CLAP::option::Option(std::nullopt, u8"a", std::nullopt, u8""))); } } TEST(CartonClapVariable, BadVariable) { // Empty name EXPECT_ANY_THROW(auto var = CLAP::variable::Variable(u8"", u8"", true)); } TEST(CartonClapVariable, BadVariables) { // Duplicated. { auto variables = CLAP::variable::VariableCollection(); variables.add_variable(CLAP::variable::Variable(u8"a", u8"", true)); EXPECT_ANY_THROW(variables.add_variable(CLAP::variable::Variable(u8"a", u8"", true))); } } #pragma endregion #pragma region Clap Body class CartonClap : public ::testing::Test { protected: CartonClap() : // YYC MARK: // The fucking C++ must order I initialize this class which do not have default ctor in there. // So I forcely initialize it with dummy data and reset it in ctor body. // The reason why I do not use static function to intialize this is that I also need specify some class members when creating this. app(CLAP::summary::Summary(u8"", u8"", u8"", u8""), CLAP::option::OptionCollection(), CLAP::variable::VariableCollection()) { // Setup basic infos auto summary = CLAP::summary::Summary(u8"TestClap", u8"yyc12345", u8"1.0.0", u8"This is the test of clap."); // Add options auto options = CLAP::option::OptionCollection(); int_option = options.add_option(CLAP::option::Option(u8"i", u8"int", u8"", u8"integral argument")); float_option = options.add_option(CLAP::option::Option(u8"f", std::nullopt, u8"", u8"")); string_option = options.add_option(CLAP::option::Option(std::nullopt, u8"string", u8"", u8"")); clamped_float_option = options.add_option(CLAP::option::Option(std::nullopt, u8"clamped-float", u8"", u8"")); novalue_option = options.add_option(CLAP::option::Option(u8"b", std::nullopt, std::nullopt, u8"")); // Add variables auto variables = CLAP::variable::VariableCollection(); int_variable = variables.add_variable(CLAP::variable::Variable(u8"int", u8"", true)); clamped_int_variable = variables.add_variable(CLAP::variable::Variable(u8"clamped-int", u8"", true)); novalue_variable = variables.add_variable(CLAP::variable::Variable(u8"b", u8"", false)); // Create final application app = CLAP::application::Application(std::move(summary), std::move(options), std::move(variables)); } ~CartonClap() override = default; // Options Token int_option; using IntOptionValidator = validator::IntegralValidator; Token float_option; using FloatOptionValidator = validator::FloatingPointValidator; Token string_option; using StringOptionValidator = validator::StringValidator; Token clamped_float_option; using ClampedFloatOptionValidator = validator::FloatingPointValidator; Token novalue_option; // Variables Token int_variable; using IntVariableValidator = validator::IntegralValidator; Token clamped_int_variable; using ClampedFloatVariableValidator = validator::IntegralValidator; Token novalue_variable; // Application CLAP::application::Application app; }; TEST_F(CartonClap, Manual) { std::stringstream ss; auto manual = CLAP::manual::Manual(app); // TODO: It may be more precious check for this. // But I don't want to write it anymore. // Two manual output should not be empty. ss.str(""); manual.print_version(ss); EXPECT_FALSE(ss.view().empty()); ss.str(""); manual.print_help(ss); EXPECT_FALSE(ss.view().empty()); } #pragma region Parser Part TEST_F(CartonClap, ParserNormal) { const std::vector args = {u8"exec", u8"-i", u8"114514"}; auto result = CLAP::parser::Parser::from_user(app, args); ASSERT_TRUE(result.has_value()); auto parser = std::move(result.value()); // Check that int argument was captured with correct value { auto value = parser.get_value_option(int_option); ASSERT_TRUE(value.has_value()); EXPECT_EQ(value.value(), 114514); } // Check that other arguments were not captured { auto value = parser.get_value_option(float_option); EXPECT_FALSE(value.has_value()); } { auto value = parser.get_value_option(string_option); EXPECT_FALSE(value.has_value()); } { auto value = parser.get_value_option(clamped_float_option); EXPECT_FALSE(value.has_value()); } { auto value = parser.get_flag_option(novalue_option); ASSERT_TRUE(value.has_value()); EXPECT_EQ(value.value(), false); } } TEST_F(CartonClap, ParserNothing) { const std::vector args = {u8"exec"}; auto result = CLAP::parser::Parser::from_user(app, args); ASSERT_TRUE(result.has_value()); auto parser = std::move(result.value()); // Check that all arguments were not captured { auto value = parser.get_value_option(int_option); EXPECT_FALSE(value.has_value()); } { auto value = parser.get_value_option(float_option); EXPECT_FALSE(value.has_value()); } { auto value = parser.get_value_option(string_option); EXPECT_FALSE(value.has_value()); } { auto value = parser.get_value_option(clamped_float_option); EXPECT_FALSE(value.has_value()); } { auto value = parser.get_flag_option(novalue_option); ASSERT_TRUE(value.has_value()); EXPECT_EQ(value.value(), false); } } TEST_F(CartonClap, ParserFull) { const std::vector args = { u8"exec", // Program self. u8"-i", // Int option u8"114514", u8"-f", // Float option u8"2.0", u8"--string", // String option u8"fuck", u8"--clamped-float", // Clamped flpat option u8"0.5", u8"-b", // No value option }; auto result = CLAP::parser::Parser::from_user(app, args); ASSERT_TRUE(result.has_value()); auto parser = std::move(result.value()); // Check that all options were not captured { auto value = parser.get_value_option(int_option); ASSERT_TRUE(value.has_value()); EXPECT_EQ(value.value(), 114514); } { auto value = parser.get_value_option(float_option); ASSERT_TRUE(value.has_value()); EXPECT_EQ(value.value(), 2.0f); } { auto value = parser.get_value_option(string_option); ASSERT_TRUE(value.has_value()); EXPECT_EQ(value.value(), u8"fuck"); } { auto value = parser.get_value_option(clamped_float_option); ASSERT_TRUE(value.has_value()); EXPECT_EQ(value.value(), 0.5f); } { auto value = parser.get_flag_option(novalue_option); ASSERT_TRUE(value.has_value()); EXPECT_EQ(value.value(), true); } } TEST_F(CartonClap, ParserInvalidName) { const std::vector args = {u8"exec", u8"-?", u8"114514"}; auto result = CLAP::parser::Parser::from_user(app, args); ASSERT_FALSE(result.has_value()); } TEST_F(CartonClap, ParserDuplicatedAssign) { const std::vector args = {u8"exec", u8"-i", u8"114514", u8"--int", u8"114514"}; auto result = CLAP::parser::Parser::from_user(app, args); ASSERT_FALSE(result.has_value()); } TEST_F(CartonClap, ParserUnexpectedValue) { const std::vector args = {u8"exec", u8"-i", u8"114514", u8"1919810"}; auto result = CLAP::parser::Parser::from_user(app, args); ASSERT_FALSE(result.has_value()); } TEST_F(CartonClap, ParserLostValue) { const std::vector args = {u8"exec", u8"-i"}; auto result = CLAP::parser::Parser::from_user(app, args); ASSERT_FALSE(result.has_value()); } TEST_F(CartonClap, ParserBadCast) { const std::vector args = {u8"exec", u8"-i", u8"114514", u8"--clamped-float", u8"114.0"}; auto result = CLAP::parser::Parser::from_user(app, args); ASSERT_TRUE(result.has_value()); auto parser = std::move(result.value()); // Check okey cast { auto value = parser.get_value_option(int_option); ASSERT_TRUE(value.has_value()); EXPECT_EQ(value.value(), 114514); } // Check bad cast { auto value = parser.get_value_option(clamped_float_option); EXPECT_FALSE(value.has_value()); } } #pragma endregion #pragma region Resolver Part TEST_F(CartonClap, ResolverNormal) { const std::vector> vars = { {u8"int", u8"114514"}, // Integer variable }; auto result = CLAP::resolver::Resolver::from_user(app, vars); ASSERT_TRUE(result.has_value()); auto resolver = std::move(result.value()); // Check that int variable was captured with correct value { auto value = resolver.get_value_variable(int_variable); ASSERT_TRUE(value.has_value()); EXPECT_EQ(value.value(), 114514); } // Check that other variables were not captured { auto value = resolver.get_value_variable(clamped_int_variable); EXPECT_FALSE(value.has_value()); } { auto value = resolver.get_flag_variable(novalue_variable); ASSERT_TRUE(value.has_value()); EXPECT_EQ(value.value(), false); } } TEST_F(CartonClap, ResolverNothing) { const std::vector> vars = {}; auto result = CLAP::resolver::Resolver::from_user(app, vars); ASSERT_TRUE(result.has_value()); auto resolver = std::move(result.value()); // Check that all variables were not captured { auto value = resolver.get_value_variable(int_variable); EXPECT_FALSE(value.has_value()); } { auto value = resolver.get_value_variable(clamped_int_variable); EXPECT_FALSE(value.has_value()); } { auto value = resolver.get_flag_variable(novalue_variable); ASSERT_TRUE(value.has_value()); EXPECT_EQ(value.value(), false); } } TEST_F(CartonClap, ResolverFull) { const std::vector> vars = { {u8"int", u8"114514"}, // Integer variable {u8"clamped-int", u8"70"}, // Clamped int variable {u8"b", u8"some words"}, // Integer variable }; auto result = CLAP::resolver::Resolver::from_user(app, vars); ASSERT_TRUE(result.has_value()); auto resolver = std::move(result.value()); // Check that all variables were captured { auto value = resolver.get_value_variable(int_variable); ASSERT_TRUE(value.has_value()); EXPECT_EQ(value.value(), 114514); } { auto value = resolver.get_value_variable(clamped_int_variable); ASSERT_TRUE(value.has_value()); EXPECT_EQ(value.value(), 70); } { auto value = resolver.get_flag_variable(novalue_variable); ASSERT_TRUE(value.has_value()); EXPECT_EQ(value.value(), true); } } TEST_F(CartonClap, ResolverDuplicatedAssign) { const std::vector> vars = { {u8"int", u8"114514"}, // Integer variable {u8"int", u8"1919810"}, // Duplicated integer variable }; EXPECT_ANY_THROW(auto result = CLAP::resolver::Resolver::from_user(app, vars)); } TEST_F(CartonClap, ResolverBadCast) { const std::vector> vars = { {u8"int", u8"114514"}, // OK integer variable {u8"clamped-int", u8"11"}, // Bad clamped int variable }; auto result = CLAP::resolver::Resolver::from_user(app, vars); ASSERT_TRUE(result.has_value()); auto resolver = std::move(result.value()); // Check okey cast { auto value = resolver.get_value_variable(int_variable); ASSERT_TRUE(value.has_value()); EXPECT_EQ(value.value(), 114514); } // Check bad cast { auto value = resolver.get_value_variable(clamped_int_variable); EXPECT_FALSE(value.has_value()); } } #pragma endregion #pragma endregion } // namespace yycctest::carton::clap