diff --git a/docs/junit-output.rst b/docs/junit-output.rst index d74a87bf3..9540a1a18 100644 --- a/docs/junit-output.rst +++ b/docs/junit-output.rst @@ -42,11 +42,19 @@ Install the plugin via :cpp:class:`Registry ` before c int main(int argc, char** argv) { - mu::tiny::test::JUnitOutputPlugin junit; + // Pass the executable basename so that bare -pjunit writes + // .xml rather than mutiny.xml. + mu::tiny::test::JUnitOutputPlugin junit("my_suite"); mu::tiny::test::Registry::get_current_registry()->install_plugin(&junit); return mu::tiny::test::CommandLineRunner::run_all_tests(argc, argv); } +The string passed to the constructor is used as the package name when +``-pjunit`` is given without an explicit ``=`` suffix. It can be +overridden at runtime with ``-pjunit=``. Passing an empty string +(the default) makes bare ``-pjunit`` write to ``mutiny.xml`` with no +package prefix in classnames. + With the plugin installed, ``-pjunit`` on the command line enables the XML output. Without the flag, no XML is written and the console output is unchanged. @@ -60,7 +68,11 @@ When running the executable directly, a single file is produced for the entire run. The file is named ``.xml``, where ```` comes from: - the ``-pjunit=`` argument if given, or -- the executable basename (e.g. ``my_tests``) if only ``-pjunit`` is used. +- the default package name supplied to the :cpp:class:`JUnitOutputPlugin + ` constructor (the executable basename + when going through :cpp:func:`CommandLineRunner::run_all_tests + `), or +- ``mutiny`` if no default was provided. When using :cmake:variable:`MUTINY_JUNIT_REPORT` with :cmake:command:`mutiny_discover_tests`, CTest runs each test group as a separate process and gives each one a unique diff --git a/docs/plugins.rst b/docs/plugins.rst index b6ad6d172..c7abb7ff2 100644 --- a/docs/plugins.rst +++ b/docs/plugins.rst @@ -21,7 +21,7 @@ Subclass :cpp:class:`mu::tiny::test::Plugin` to intercept the test lifecycle. virtual void pre_test_action(Shell&, Result&) {} virtual void post_test_action(Shell&, Result&) {} - virtual bool parse_arguments(int argc, const char* const* argv, int index) + virtual bool parse_arguments(int argc, const char* const* argv) { return false; } virtual String get_help() const { return ""; } @@ -44,7 +44,7 @@ Override the methods you need: - Restore pointers, verify mock expectations * - :cpp:func:`parse_arguments() ` - During argument parsing - - Activate plugin via a :option:`-p\` argument + - Inspect ``argv[0]``; activate plugin via a :option:`-p\` argument * - :cpp:func:`get_help() ` - When :option:`-h` is printed - Show plugin's flag description diff --git a/examples/tests/TeamCityOutputPlugin.cpp b/examples/tests/TeamCityOutputPlugin.cpp index 179932aff..985dea169 100644 --- a/examples/tests/TeamCityOutputPlugin.cpp +++ b/examples/tests/TeamCityOutputPlugin.cpp @@ -112,11 +112,10 @@ TeamCityOutputPlugin::TeamCityOutputPlugin() bool TeamCityOutputPlugin::parse_arguments( int /*argc*/, - const char* const* argv, - int index + const char* const* argv ) { - mu::tiny::String arg = argv[index]; + mu::tiny::String arg = argv[0]; if (arg.size() > 2 && mu::tiny::String(arg.c_str() + 2) == "teamcity") { active_ = true; return true; diff --git a/examples/tests/TeamCityOutputPlugin.hpp b/examples/tests/TeamCityOutputPlugin.hpp index 2d8d495cb..8021fc384 100644 --- a/examples/tests/TeamCityOutputPlugin.hpp +++ b/examples/tests/TeamCityOutputPlugin.hpp @@ -28,7 +28,7 @@ class TeamCityOutputPlugin : public mu::tiny::test::Plugin public: TeamCityOutputPlugin(); - bool parse_arguments(int argc, const char* const* argv, int index) override; + bool parse_arguments(int argc, const char* const* argv) override; mu::tiny::String get_help() const override; mu::tiny::test::Output* create_output() override; diff --git a/include/mu/tiny/test/CommandLineArguments.hpp b/include/mu/tiny/test/CommandLineArguments.hpp index 113c6c3aa..252b2c5e6 100644 --- a/include/mu/tiny/test/CommandLineArguments.hpp +++ b/include/mu/tiny/test/CommandLineArguments.hpp @@ -116,41 +116,31 @@ class MUTINY_EXPORT CommandLineArguments unsigned int shuffle_seed_{ 0 }; Filter* group_filters_{ nullptr }; Filter* name_filters_{ nullptr }; - void set_repeat_count(int argc, const char* const* argv, int& index); - bool set_shuffle(int argc, const char* const* argv, int& index); - void add_group_filter(int argc, const char* const* argv, int& index); - bool add_group_dot_name_filter( + int set_repeat_count(int argc, const char* const* argv); + int set_shuffle(int argc, const char* const* argv); + int add_group_filter(int argc, const char* const* argv); + int add_group_dot_name_filter( int argc, const char* const* argv, - int& index, const String& parameter_name, bool strict, bool exclude ); - void add_strict_group_filter(int argc, const char* const* argv, int& index); - void add_exclude_group_filter(int argc, const char* const* argv, int& index); - void add_exclude_strict_group_filter( + int add_strict_group_filter(int argc, const char* const* argv); + int add_exclude_group_filter(int argc, const char* const* argv); + int add_exclude_strict_group_filter(int argc, const char* const* argv); + int add_name_filter(int argc, const char* const* argv); + int add_strict_name_filter(int argc, const char* const* argv); + int add_exclude_name_filter(int argc, const char* const* argv); + int add_exclude_strict_name_filter(int argc, const char* const* argv); + int add_test_to_run_based_on_verbose_output( int argc, const char* const* argv, - int& index - ); - void add_name_filter(int argc, const char* const* argv, int& index); - void add_strict_name_filter(int argc, const char* const* argv, int& index); - void add_exclude_name_filter(int argc, const char* const* argv, int& index); - void add_exclude_strict_name_filter( - int argc, - const char* const* argv, - int& index - ); - void add_test_to_run_based_on_verbose_output( - int argc, - const char* const* argv, - int& index, const char* parameter_name ); bool parse_simple_flag(const String& argument); - bool parse_prefix_arg(const String& argument, Plugin* plugin, int& index); - bool parse_argument(const String& argument, Plugin* plugin, int& index); + int parse_prefix_arg(int argc, const char* const* argv, Plugin* plugin); + int parse_argument(int argc, const char* const* argv, Plugin* plugin); }; } // namespace test diff --git a/include/mu/tiny/test/CommandLineRunner.hpp b/include/mu/tiny/test/CommandLineRunner.hpp index 1afb6575b..e4cac8f92 100644 --- a/include/mu/tiny/test/CommandLineRunner.hpp +++ b/include/mu/tiny/test/CommandLineRunner.hpp @@ -123,6 +123,7 @@ class MUTINY_EXPORT CommandLineRunner private: CommandLineArguments* arguments_{ nullptr }; Registry* registry_; + String program_name_; bool parse_arguments(Plugin* plugin); int run_all_tests(); diff --git a/include/mu/tiny/test/JUnitOutputPlugin.hpp b/include/mu/tiny/test/JUnitOutputPlugin.hpp index 37e014ac4..22558b56d 100644 --- a/include/mu/tiny/test/JUnitOutputPlugin.hpp +++ b/include/mu/tiny/test/JUnitOutputPlugin.hpp @@ -29,18 +29,24 @@ class Output; class MUTINY_EXPORT JUnitOutputPlugin : public Plugin { public: - /** @brief Construct and name the plugin. */ - JUnitOutputPlugin(); + /** + * @brief Construct the plugin with an optional default package name. + * + * @param default_package_name Used as the JUnit package name when + * @c -pjunit is given without an explicit @c =name suffix. + * Pass the executable basename to reproduce the standard behaviour. + * Defaults to empty, which leaves the package name unset. + */ + explicit JUnitOutputPlugin(const String& default_package_name = ""); /** * @brief Handle the `-pjunit[=]` command-line argument. * - * @param argc Argument count. - * @param argv Argument vector. - * @param index Current argument index. + * @param argc Remaining argument count (@p argv[0] through end). + * @param argv Pointer to the current argument. * @return true if the argument was consumed. */ - bool parse_arguments(int argc, const char* const* argv, int index) override; + bool parse_arguments(int argc, const char* const* argv) override; /** * @brief Return help text for the `-pjunit` option. @@ -56,6 +62,7 @@ class MUTINY_EXPORT JUnitOutputPlugin : public Plugin private: bool active_{ false }; + String default_package_name_; String package_name_; }; diff --git a/include/mu/tiny/test/Plugin.hpp b/include/mu/tiny/test/Plugin.hpp index 4d278a868..363a74589 100644 --- a/include/mu/tiny/test/Plugin.hpp +++ b/include/mu/tiny/test/Plugin.hpp @@ -67,15 +67,15 @@ class MUTINY_EXPORT Plugin /** * @brief Handle a custom command-line argument. * - * Called for each argument position @p index. Return true to indicate the - * argument was consumed (the runner will skip to the next one). + * Called with a pre-sliced view where @p argv[0] is the argument to inspect + * and @p argc is the number of remaining arguments (including @p argv[0]). + * Return true to indicate the argument was consumed. * - * @param argc Total argument count. - * @param argv Argument vector. - * @param index Current argument index to inspect. - * @return true if the argument at @p index was consumed. + * @param argc Remaining argument count (@p argv[0] through end). + * @param argv Pointer to the current argument. + * @return true if @p argv[0] was consumed. */ - virtual bool parse_arguments(int argc, const char* const* argv, int index); + virtual bool parse_arguments(int argc, const char* const* argv); /** * @brief Return a help string for this plugin's command-line arguments. @@ -110,24 +110,18 @@ class MUTINY_EXPORT Plugin /** * @brief Invoke parse_arguments() on each plugin in the chain. - * @param argc Argument count. - * @param argv Argument vector (const). - * @param index Current argument index. + * @param argc Remaining argument count (@p argv[0] through end). + * @param argv Pointer to the current argument. * @return true if any plugin consumed the argument. */ - virtual bool parse_all_arguments( - int argc, - const char* const* argv, - int index - ); + virtual bool parse_all_arguments(int argc, const char* const* argv); /** * @brief Overload accepting a non-const argv. - * @param argc Argument count. - * @param argv Argument vector. - * @param index Current argument index. + * @param argc Remaining argument count (@p argv[0] through end). + * @param argv Pointer to the current argument. * @return true if any plugin consumed the argument. */ - virtual bool parse_all_arguments(int argc, char** argv, int index); + virtual bool parse_all_arguments(int argc, char** argv); /** @return Concatenated help strings from all plugins in the chain. */ virtual String get_all_help() const; diff --git a/include/mu/tiny/test/TapOutputPlugin.hpp b/include/mu/tiny/test/TapOutputPlugin.hpp index ca960d4db..b1d59e057 100644 --- a/include/mu/tiny/test/TapOutputPlugin.hpp +++ b/include/mu/tiny/test/TapOutputPlugin.hpp @@ -35,12 +35,11 @@ class MUTINY_EXPORT TapOutputPlugin : public Plugin /** * @brief Handle the @c -ptap command-line argument. * - * @param argc Argument count. - * @param argv Argument vector. - * @param index Current argument index. + * @param argc Remaining argument count (@p argv[0] through end). + * @param argv Pointer to the current argument. * @return true if the argument was consumed. */ - bool parse_arguments(int argc, const char* const* argv, int index) override; + bool parse_arguments(int argc, const char* const* argv) override; /** * @brief Return help text for the @c -ptap option. diff --git a/src/test/CommandLineArguments.cpp b/src/test/CommandLineArguments.cpp index d1cdfa625..b9cafbf55 100644 --- a/src/test/CommandLineArguments.cpp +++ b/src/test/CommandLineArguments.cpp @@ -12,22 +12,31 @@ namespace tiny { namespace test { namespace { -String get_parameter_field( +class ParsedField +{ +public: + String value; + int extra; +}; + +ParsedField get_parameter_field( int argc, const char* const* argv, - int& i, const String& parameter_name ) { size_t parameter_length = parameter_name.size(); - String parameter(argv[i]); + String parameter(argv[0]); if (parameter.size() > parameter_length) { - return argv[i] + parameter_length; + ParsedField result = { String(argv[0] + parameter_length), 0 }; + return result; } - if (i + 1 < argc) { - return argv[++i]; + if (argc > 1) { + ParsedField result = { String(argv[1]), 1 }; + return result; } - return ""; + ParsedField result = { String(""), 0 }; + return result; } String sub_string_from_till( @@ -128,95 +137,87 @@ bool CommandLineArguments::parse_simple_flag(const String& argument) return false; } -bool CommandLineArguments::parse_prefix_arg( - const String& argument, - Plugin* plugin, - int& index +int CommandLineArguments::parse_prefix_arg( + int argc, + const char* const* argv, + Plugin* plugin ) { + String argument(argv[0]); if (string_starts_with(argument, "-r")) { - set_repeat_count(ac_, av_, index); - return true; + return set_repeat_count(argc, argv); } if (string_starts_with(argument, "-g")) { - add_group_filter(ac_, av_, index); - return true; + return add_group_filter(argc, argv); } if (string_starts_with(argument, "-t")) { - return add_group_dot_name_filter(ac_, av_, index, "-t", false, false); + return add_group_dot_name_filter(argc, argv, "-t", false, false); } if (string_starts_with(argument, "-st")) { - return add_group_dot_name_filter(ac_, av_, index, "-st", true, false); + return add_group_dot_name_filter(argc, argv, "-st", true, false); } if (string_starts_with(argument, "-xt")) { - return add_group_dot_name_filter(ac_, av_, index, "-xt", false, true); + return add_group_dot_name_filter(argc, argv, "-xt", false, true); } if (string_starts_with(argument, "-xst")) { - return add_group_dot_name_filter(ac_, av_, index, "-xst", true, true); + return add_group_dot_name_filter(argc, argv, "-xst", true, true); } if (string_starts_with(argument, "-sg")) { - add_strict_group_filter(ac_, av_, index); - return true; + return add_strict_group_filter(argc, argv); } if (string_starts_with(argument, "-xg")) { - add_exclude_group_filter(ac_, av_, index); - return true; + return add_exclude_group_filter(argc, argv); } if (string_starts_with(argument, "-xsg")) { - add_exclude_strict_group_filter(ac_, av_, index); - return true; + return add_exclude_strict_group_filter(argc, argv); } if (string_starts_with(argument, "-n")) { - add_name_filter(ac_, av_, index); - return true; + return add_name_filter(argc, argv); } if (string_starts_with(argument, "-sn")) { - add_strict_name_filter(ac_, av_, index); - return true; + return add_strict_name_filter(argc, argv); } if (string_starts_with(argument, "-xn")) { - add_exclude_name_filter(ac_, av_, index); - return true; + return add_exclude_name_filter(argc, argv); } if (string_starts_with(argument, "-xsn")) { - add_exclude_strict_name_filter(ac_, av_, index); - return true; + return add_exclude_strict_name_filter(argc, argv); } if (string_starts_with(argument, "-s")) { - return set_shuffle(ac_, av_, index); + return set_shuffle(argc, argv); } if (string_starts_with(argument, "TEST(")) { - add_test_to_run_based_on_verbose_output(ac_, av_, index, "TEST("); - return true; + return add_test_to_run_based_on_verbose_output(argc, argv, "TEST("); } if (string_starts_with(argument, "SKIPPED_TEST(")) { - add_test_to_run_based_on_verbose_output(ac_, av_, index, "SKIPPED_TEST("); - return true; + return add_test_to_run_based_on_verbose_output(argc, argv, "SKIPPED_TEST("); } if (string_starts_with(argument, "-p")) { - return plugin->parse_all_arguments(ac_, av_, index); + return plugin->parse_all_arguments(argc, argv) ? 0 : -1; } - return false; + return -1; } -bool CommandLineArguments::parse_argument( - const String& argument, - Plugin* plugin, - int& index +int CommandLineArguments::parse_argument( + int argc, + const char* const* argv, + Plugin* plugin ) { - if (parse_simple_flag(argument)) { - return true; + if (parse_simple_flag(String(argv[0]))) { + return 0; } - return parse_prefix_arg(argument, plugin, index); + return parse_prefix_arg(argc, argv, plugin); } bool CommandLineArguments::parse(Plugin* plugin) { for (int i = 1; i < ac_; i++) { - if (!parse_argument(av_[i], plugin, i)) { + int extra = parse_argument(ac_ - i, av_ + i, plugin); + if (extra < 0) { return false; } + i += extra; } return true; } @@ -388,34 +389,28 @@ const Filter* CommandLineArguments::get_name_filters() const return name_filters_; } -void CommandLineArguments::set_repeat_count( - int argc, - const char* const* argv, - int& i -) +int CommandLineArguments::set_repeat_count(int argc, const char* const* argv) { repeat_ = 0; + int extra = 0; - String repeat_parameter(argv[i]); + String repeat_parameter(argv[0]); if (repeat_parameter.size() > 2) { - repeat_ = static_cast(strtoul(argv[i] + 2)); - } else if (i + 1 < argc) { - repeat_ = static_cast(strtoul(argv[i + 1])); + repeat_ = static_cast(strtoul(argv[0] + 2)); + } else if (argc > 1) { + repeat_ = static_cast(strtoul(argv[1])); if (repeat_ != 0) { - i++; + extra = 1; } } if (0 == repeat_) { repeat_ = 2; } + return extra; } -bool CommandLineArguments::set_shuffle( - int argc, - const char* const* argv, - int& i -) +int CommandLineArguments::set_shuffle(int argc, const char* const* argv) { shuffling_ = true; shuffle_seed_ = static_cast(get_time_in_millis()); @@ -423,45 +418,43 @@ bool CommandLineArguments::set_shuffle( shuffle_seed_++; } - String shuffle_parameter = argv[i]; + int extra = 0; + String shuffle_parameter = argv[0]; if (shuffle_parameter.size() > 2) { shuffling_pre_seeded_ = true; - shuffle_seed_ = static_cast(strtoul(argv[i] + 2)); - } else if (i + 1 < argc) { - auto parsed_parameter = static_cast(strtoul(argv[i + 1])); + shuffle_seed_ = static_cast(strtoul(argv[0] + 2)); + } else if (argc > 1) { + auto parsed_parameter = static_cast(strtoul(argv[1])); if (parsed_parameter != 0) { shuffling_pre_seeded_ = true; shuffle_seed_ = parsed_parameter; - i++; + extra = 1; } } - return (shuffle_seed_ != 0); + return (shuffle_seed_ != 0) ? extra : -1; } -void CommandLineArguments::add_group_filter( - int argc, - const char* const* argv, - int& i -) +int CommandLineArguments::add_group_filter(int argc, const char* const* argv) { - auto* group_filter = new Filter(get_parameter_field(argc, argv, i, "-g")); + ParsedField field = get_parameter_field(argc, argv, "-g"); + auto* group_filter = new Filter(field.value); group_filters_ = group_filter->add(group_filters_); + return field.extra; } -bool CommandLineArguments::add_group_dot_name_filter( +int CommandLineArguments::add_group_dot_name_filter( int argc, const char* const* argv, - int& i, const String& parameter_name, bool strict, bool exclude ) { - String group_dot_name = get_parameter_field(argc, argv, i, parameter_name); - StringCollection collection(group_dot_name, '.'); + ParsedField field = get_parameter_field(argc, argv, parameter_name); + StringCollection collection(field.value, '.'); if (collection.size() != 2) { - return false; + return -1; } auto* group_filter = @@ -477,105 +470,108 @@ bool CommandLineArguments::add_group_dot_name_filter( } group_filters_ = group_filter->add(group_filters_); name_filters_ = name_filter->add(name_filters_); - return true; + return field.extra; } -void CommandLineArguments::add_strict_group_filter( +int CommandLineArguments::add_strict_group_filter( int argc, - const char* const* argv, - int& i + const char* const* argv ) { - auto* group_filter = new Filter(get_parameter_field(argc, argv, i, "-sg")); + ParsedField field = get_parameter_field(argc, argv, "-sg"); + auto* group_filter = new Filter(field.value); group_filter->strict_matching(); group_filters_ = group_filter->add(group_filters_); + return field.extra; } -void CommandLineArguments::add_exclude_group_filter( +int CommandLineArguments::add_exclude_group_filter( int argc, - const char* const* argv, - int& i + const char* const* argv ) { - auto* group_filter = new Filter(get_parameter_field(argc, argv, i, "-xg")); + ParsedField field = get_parameter_field(argc, argv, "-xg"); + auto* group_filter = new Filter(field.value); group_filter->invert_matching(); group_filters_ = group_filter->add(group_filters_); + return field.extra; } -void CommandLineArguments::add_exclude_strict_group_filter( +int CommandLineArguments::add_exclude_strict_group_filter( int argc, - const char* const* argv, - int& i + const char* const* argv ) { - auto* group_filter = new Filter(get_parameter_field(argc, argv, i, "-xsg")); + ParsedField field = get_parameter_field(argc, argv, "-xsg"); + auto* group_filter = new Filter(field.value); group_filter->strict_matching(); group_filter->invert_matching(); group_filters_ = group_filter->add(group_filters_); + return field.extra; } -void CommandLineArguments::add_name_filter( - int argc, - const char* const* argv, - int& i -) +int CommandLineArguments::add_name_filter(int argc, const char* const* argv) { - auto* name_filter = new Filter(get_parameter_field(argc, argv, i, "-n")); + ParsedField field = get_parameter_field(argc, argv, "-n"); + auto* name_filter = new Filter(field.value); name_filters_ = name_filter->add(name_filters_); + return field.extra; } -void CommandLineArguments::add_strict_name_filter( +int CommandLineArguments::add_strict_name_filter( int argc, - const char* const* argv, - int& index + const char* const* argv ) { - auto* name_filter = new Filter(get_parameter_field(argc, argv, index, "-sn")); + ParsedField field = get_parameter_field(argc, argv, "-sn"); + auto* name_filter = new Filter(field.value); name_filter->strict_matching(); name_filters_ = name_filter->add(name_filters_); + return field.extra; } -void CommandLineArguments::add_exclude_name_filter( +int CommandLineArguments::add_exclude_name_filter( int argc, - const char* const* argv, - int& index + const char* const* argv ) { - auto* name_filter = new Filter(get_parameter_field(argc, argv, index, "-xn")); + ParsedField field = get_parameter_field(argc, argv, "-xn"); + auto* name_filter = new Filter(field.value); name_filter->invert_matching(); name_filters_ = name_filter->add(name_filters_); + return field.extra; } -void CommandLineArguments::add_exclude_strict_name_filter( +int CommandLineArguments::add_exclude_strict_name_filter( int argc, - const char* const* argv, - int& index + const char* const* argv ) { - auto* name_filter = - new Filter(get_parameter_field(argc, argv, index, "-xsn")); + ParsedField field = get_parameter_field(argc, argv, "-xsn"); + auto* name_filter = new Filter(field.value); name_filter->invert_matching(); name_filter->strict_matching(); name_filters_ = name_filter->add(name_filters_); + return field.extra; } -void CommandLineArguments::add_test_to_run_based_on_verbose_output( +int CommandLineArguments::add_test_to_run_based_on_verbose_output( int argc, const char* const* argv, - int& index, const char* parameter_name ) { - String wholename = get_parameter_field(argc, argv, index, parameter_name); - String testname = sub_string_from_till(wholename, ',', ')'); + ParsedField field = get_parameter_field(argc, argv, parameter_name); + String testname = sub_string_from_till(field.value, ',', ')'); testname = testname.substr(2); auto* namefilter = new Filter(testname); auto* groupfilter = - new Filter(sub_string_from_till(wholename, wholename[0], ',')); + new Filter(sub_string_from_till(field.value, field.value[0], ',')); namefilter->strict_matching(); groupfilter->strict_matching(); group_filters_ = groupfilter->add(group_filters_); name_filters_ = namefilter->add(name_filters_); + return field.extra; } } // namespace test diff --git a/src/test/CommandLineRunner.cpp b/src/test/CommandLineRunner.cpp index 2a7992fbe..8d14d2996 100644 --- a/src/test/CommandLineRunner.cpp +++ b/src/test/CommandLineRunner.cpp @@ -14,6 +14,22 @@ namespace mu { namespace tiny { namespace test { +namespace { +String basename_from_path(const char* path) +{ + if ((path == nullptr) || (*path == 0)) { + return ""; + } + const char* base = path; + for (const char* p = path; *p != 0; ++p) { + if (*p == '/' || *p == '\\') { + base = p + 1; + } + } + return base; +} +} // namespace + int CommandLineRunner::run_all_tests(int argc, char** argv) { return run_all_tests(argc, reinterpret_cast(argv)); @@ -36,6 +52,7 @@ CommandLineRunner::CommandLineRunner( Registry* registry ) : registry_(registry) + , program_name_(argc > 0 ? basename_from_path(argv[0]) : "") { arguments_ = new CommandLineArguments(argc, argv); } @@ -53,7 +70,7 @@ int CommandLineRunner::run_all_tests_main() Plugin* const user_plugins = registry_->get_first_plugin(); SetPointerPlugin set_pointer_plugin; - JUnitOutputPlugin junit_plugin; + JUnitOutputPlugin junit_plugin(program_name_); TapOutputPlugin tap_plugin; registry_->install_plugin(&set_pointer_plugin); registry_->install_plugin(&junit_plugin); diff --git a/src/test/JUnitOutputPlugin.cpp b/src/test/JUnitOutputPlugin.cpp index f311250fb..c8478f9f7 100644 --- a/src/test/JUnitOutputPlugin.cpp +++ b/src/test/JUnitOutputPlugin.cpp @@ -8,36 +8,15 @@ namespace mu { namespace tiny { namespace test { -namespace { - -String basename_from_path(const char* path) -{ - if ((path == nullptr) || (*path == 0)) { - return ""; - } - const char* base = path; - for (const char* p = path; *p != 0; ++p) { - if (*p == '/' || *p == '\\') { - base = p + 1; - } - } - return base; -} - -} // namespace - -JUnitOutputPlugin::JUnitOutputPlugin() +JUnitOutputPlugin::JUnitOutputPlugin(const String& default_package_name) : Plugin("JUnitOutputPlugin") + , default_package_name_(default_package_name) { } -bool JUnitOutputPlugin::parse_arguments( - int /*argc*/, - const char* const* argv, - int index -) +bool JUnitOutputPlugin::parse_arguments(int /*argc*/, const char* const* argv) { - String arg = argv[index]; + String arg = argv[0]; constexpr char flag[] = "-pjunit"; constexpr size_t flag_len = sizeof(flag) / sizeof(flag[0]); @@ -50,7 +29,7 @@ bool JUnitOutputPlugin::parse_arguments( } package_name_ = arg.substr(flag_len); } else { - package_name_ = basename_from_path(argv[0]); + package_name_ = default_package_name_; } active_ = true; return true; diff --git a/src/test/Plugin.cpp b/src/test/Plugin.cpp index 6f7517f14..2038eeb54 100644 --- a/src/test/Plugin.cpp +++ b/src/test/Plugin.cpp @@ -47,24 +47,23 @@ void Plugin::run_all_post_test_action(Shell& test, Result& result) } } -bool Plugin:: - parse_arguments(int /*argc*/, const char* const* /*argv*/, int /*index*/) +bool Plugin::parse_arguments(int /*argc*/, const char* const* /*argv*/) { return false; } -bool Plugin::parse_all_arguments(int argc, char** argv, int index) +bool Plugin::parse_all_arguments(int argc, char** argv) { - return parse_all_arguments(argc, const_cast(argv), index); + return parse_all_arguments(argc, const_cast(argv)); } -bool Plugin::parse_all_arguments(int argc, const char* const* argv, int index) +bool Plugin::parse_all_arguments(int argc, const char* const* argv) { - if (parse_arguments(argc, argv, index)) { + if (parse_arguments(argc, argv)) { return true; } if (next_ != nullptr) { - return next_->parse_all_arguments(argc, argv, index); + return next_->parse_all_arguments(argc, argv); } return false; } diff --git a/src/test/TapOutputPlugin.cpp b/src/test/TapOutputPlugin.cpp index ec9f065ad..4685356df 100644 --- a/src/test/TapOutputPlugin.cpp +++ b/src/test/TapOutputPlugin.cpp @@ -11,13 +11,9 @@ TapOutputPlugin::TapOutputPlugin() { } -bool TapOutputPlugin::parse_arguments( - int /*argc*/, - const char* const* argv, - int index -) +bool TapOutputPlugin::parse_arguments(int /*argc*/, const char* const* argv) { - String arg = argv[index]; + String arg = argv[0]; if (arg != "-ptap") { return false; } diff --git a/tests/src/CommandLineArguments.test.cpp b/tests/src/CommandLineArguments.test.cpp index 151a872e8..59f3e3b7b 100644 --- a/tests/src/CommandLineArguments.test.cpp +++ b/tests/src/CommandLineArguments.test.cpp @@ -14,11 +14,7 @@ class OptionsPlugin : public mu::tiny::test::Plugin { } ~OptionsPlugin() override = default; - bool parse_arguments( - int /*argc*/, - const char* const* /*argv*/, - int /*index*/ - ) override + bool parse_arguments(int /*argc*/, const char* const* /*argv*/) override { return true; } @@ -183,6 +179,14 @@ TEST(CommandLineArguments, setGroupFilter) CHECK_EQUAL(mu::tiny::test::Filter("group"), *args->get_group_filters()); } +TEST(CommandLineArguments, setGroupFilterWithNoValueUsesEmptyFilter) +{ + int argc = 2; + const char* argv[] = { "tests.exe", "-g" }; + CHECK(new_argument_parser(argc, argv)); + CHECK_EQUAL(mu::tiny::test::Filter(""), *args->get_group_filters()); +} + TEST(CommandLineArguments, setCompleteGroupDotNameFilterInvalidArgument) { int argc = 3; diff --git a/tests/src/CommandLineTestRunner.test.cpp b/tests/src/CommandLineTestRunner.test.cpp index 8ae86b33a..8fc43d2aa 100644 --- a/tests/src/CommandLineTestRunner.test.cpp +++ b/tests/src/CommandLineTestRunner.test.cpp @@ -21,11 +21,7 @@ class DummyPluginWhichCountsThePlugins : public mu::tiny::test::Plugin { } - bool parse_arguments( - int /*argc*/, - const char* const* /*argv*/, - int /*index*/ - ) override + bool parse_arguments(int /*argc*/, const char* const* /*argv*/) override { /* Remove ourselves from the count */ amount_of_plugins = registry_->count_plugins() - 1; @@ -466,6 +462,27 @@ TEST(CommandLineRunner, realJunitOutputShouldBeCreatedAndWorkProperly) STRCMP_CONTAINS("TEST(group1, test1)", fake_output.console.c_str()); } +TEST(CommandLineRunner, junitPackageNameEmptyWhenArgvZeroIsEmpty) +{ + const char* argv[] = { + "", + "-pjunit", + }; + + FakeOutput fake_output; /* MUTINY_PTR_SET() is not reentrant */ + + mu::tiny::test::CommandLineRunner command_line_test_runner( + 2, argv, ®istry + ); + command_line_test_runner.run_all_tests_main(); + + fake_output.restore_originals(); + + STRCMP_CONTAINS( + "parse_arguments(2, argv, 1); + plugin = new mu::tiny::test::JUnitOutputPlugin(default_package_name); + const char* argv[] = { junit_arg }; + plugin->parse_arguments(1, argv); output = plugin->create_output(); result = new mu::tiny::test::Result(*output); test_case_runner = new JUnitTestOutputTestRunner(*result); @@ -838,6 +841,45 @@ TEST(JUnitOutput, TestCaseBlockWithAPackageName) STRCMP_EQUAL("\n", output_file->line(5)); } +TEST(JUnitOutput, defaultPackageName_usedWhenNoPjunitSuffix) +{ + init("-pjunit", "mypackage"); + test_case_runner->start().with_group("groupname").with_test("testname").end(); + + output_file = file_system.file("mypackage.xml"); + STRCMP_EQUAL( + "\n", + output_file->line(4) + ); +} + +TEST(JUnitOutput, defaultPackageName_overriddenByExplicitSuffix) +{ + init("-pjunit=explicit", "mydefault"); + test_case_runner->start().with_group("groupname").with_test("testname").end(); + + output_file = file_system.file("explicit.xml"); + STRCMP_EQUAL( + "\n", + output_file->line(4) + ); +} + +TEST(JUnitOutput, emptyDefaultPackageName_producesNoPrefix) +{ + init("-pjunit"); + test_case_runner->start().with_group("groupname").with_test("testname").end(); + + output_file = file_system.file("mutiny.xml"); + STRCMP_EQUAL( + "\n", + output_file->line(4) + ); +} + TEST(JUnitOutput, TestCaseBlockForSkippedTest) { init("-pjunit=packagename"); @@ -1179,16 +1221,16 @@ TEST(JUnitOutput, TestCaseBlockForSkippedTestEscapesXmlInMessage) ); } -TEST(JUnitOutput, parseArguments_derivesBasenameFromPathInArgv0) +TEST(JUnitOutput, parseArguments_pjunitWithoutName_succeeds) { mu::tiny::test::JUnitOutputPlugin p; - const char* argv[] = { "path/to/binary", "-pjunit" }; - CHECK(p.parse_arguments(2, argv, 1)); + const char* argv[] = { "-pjunit" }; + CHECK(p.parse_arguments(1, argv)); } TEST(JUnitOutput, parseArguments_pjunitWithInvalidSuffix_returnsFalse) { mu::tiny::test::JUnitOutputPlugin p; - const char* argv[] = { "", "-pjunitX" }; - CHECK(!p.parse_arguments(2, argv, 1)); + const char* argv[] = { "-pjunitX" }; + CHECK(!p.parse_arguments(1, argv)); } diff --git a/tests/src/TapOutput.test.cpp b/tests/src/TapOutput.test.cpp index d496cdf1c..b01aa0d26 100644 --- a/tests/src/TapOutput.test.cpp +++ b/tests/src/TapOutput.test.cpp @@ -210,8 +210,8 @@ TEST_GROUP(TapOutput) MUTINY_PTR_SET(mu::tiny::test::Output::fputs_, mock_tap_fputs); plugin = new mu::tiny::test::TapOutputPlugin(); - const char* argv[] = { "", "-ptap" }; - plugin->parse_arguments(2, argv, 1); + const char* argv[] = { "-ptap" }; + plugin->parse_arguments(1, argv); output = plugin->create_output(); result = new mu::tiny::test::Result(*output); test_case_runner = new TapTestOutputTestRunner(*result); @@ -382,8 +382,8 @@ TEST(TapOutput, secondRunResetsResults) TEST(TapOutput, parseArguments_ptapIsRecognised) { mu::tiny::test::TapOutputPlugin p; - const char* argv[] = { "", "-ptap" }; - CHECK(p.parse_arguments(2, argv, 1)); + const char* argv[] = { "-ptap" }; + CHECK(p.parse_arguments(1, argv)); auto* created = p.create_output(); CHECK(created != nullptr); delete created; @@ -392,8 +392,8 @@ TEST(TapOutput, parseArguments_ptapIsRecognised) TEST(TapOutput, parseArguments_otherArgReturnsFalse) { mu::tiny::test::TapOutputPlugin p; - const char* argv[] = { "", "-pjunit" }; - CHECK(!p.parse_arguments(2, argv, 1)); + const char* argv[] = { "-pjunit" }; + CHECK(!p.parse_arguments(1, argv)); CHECK(p.create_output() == nullptr); } diff --git a/tests/src/TestPlugin.test.cpp b/tests/src/TestPlugin.test.cpp index e2b5e17e7..f66b960f7 100644 --- a/tests/src/TestPlugin.test.cpp +++ b/tests/src/TestPlugin.test.cpp @@ -53,13 +53,13 @@ class DummyPluginWhichAcceptsParameters : public DummyPlugin { } - bool parse_arguments(int argc, const char* const* argv, int index) override + bool parse_arguments(int argc, const char* const* argv) override { - mu::tiny::String argument(argv[index]); + mu::tiny::String argument(argv[0]); if (argument == "-paccept") { return true; } - return Plugin::parse_arguments(argc, argv, index); + return Plugin::parse_arguments(argc, argv); } }; @@ -166,7 +166,7 @@ TEST(Plugin, ParseArgumentsForUnknownArgumentsFails) const char* cmd_line[] = { "nonsense", "andmorenonsense" }; CHECK( registry->get_first_plugin()->parse_all_arguments( - 2, const_cast(cmd_line), 0 + 2, const_cast(cmd_line) ) == false ); /* cover non-const wrapper, too */ } @@ -176,6 +176,6 @@ TEST(Plugin, ParseArgumentsContinuesAndSucceedsWhenAPluginCanParse) registry->install_plugin(second_plugin); const char* cmd_line[] = { "-paccept", "andmorenonsense" }; CHECK(registry->get_first_plugin()->parse_all_arguments( - 2, const_cast(cmd_line), 0 + 2, const_cast(cmd_line) )); /* cover non-const wrapper, too */ }