diff --git a/modules/util/include/func_test_util.hpp b/modules/util/include/func_test_util.hpp index 6af48e4cf..cc4965f4d 100644 --- a/modules/util/include/func_test_util.hpp +++ b/modules/util/include/func_test_util.hpp @@ -29,6 +29,9 @@ concept HasPrintTestParam = requires(TestType value) { { T::PrintTestParam(value) } -> std::same_as; }; +template +void RunTestCasesWithTag(const TestTasksList &test_tasks_list, std::string_view task_tag, RunTestCase run_test_case); + template /// @brief Base class for running functional tests on parallel tasks. /// @tparam InType Type of input data. @@ -56,6 +59,16 @@ class BaseRunFuncTests : public ::testing::TestWithParam &test_param) { + ExecuteTest(test_param); + } + + template + void RunTestCasesWithTag(const TestTasksList &test_tasks_list, std::string_view task_tag) { + ppc::util::RunTestCasesWithTag(test_tasks_list, task_tag, + [this](const auto &test_param) { RunTestCase(test_param); }); + } + void ExecuteTest(FuncTestParam test_param) { const std::string &test_name = std::get(GTestParamIndex::kNameTest)>(test_param); @@ -120,6 +133,43 @@ class BaseRunFuncTests : public ::testing::TestWithParam task_; }; +namespace detail { + +[[nodiscard]] inline std::string MakeFuncTestTaskTagPattern(std::string_view task_tag) { + std::string tag_pattern{task_tag}; + if (!tag_pattern.starts_with('_')) { + tag_pattern.insert(0, 1, '_'); + } + if (!tag_pattern.ends_with('_')) { + tag_pattern.push_back('_'); + } + return tag_pattern; +} + +} // namespace detail + +template +void RunTestCasesWithTag(const TestTasksList &test_tasks_list, std::string_view task_tag, RunTestCase run_test_case) { + if (task_tag.empty()) { + ADD_FAILURE() << "Functional test task tag must not be empty"; + return; + } + + const std::string task_tag_pattern = detail::MakeFuncTestTaskTagPattern(task_tag); + bool has_matching_task = false; + std::apply([&](const auto &...test_params) { + auto run_if_tagged = [&](const auto &test_param) { + const std::string &test_name = std::get(GTestParamIndex::kNameTest)>(test_param); + if (test_name.contains(task_tag_pattern)) { + has_matching_task = true; + std::invoke(run_test_case, test_param); + } + }; + (run_if_tagged(test_params), ...); + }, test_tasks_list); + EXPECT_TRUE(has_matching_task) << "No functional test cases matched tag: " << std::string(task_tag); +} + template auto ExpandToValuesImpl(const Tuple &t, std::index_sequence /*unused*/) { return ::testing::Values(std::get(t)...); diff --git a/modules/util/tests/util.cpp b/modules/util/tests/util.cpp index 6da563a9f..088ec37f0 100644 --- a/modules/util/tests/util.cpp +++ b/modules/util/tests/util.cpp @@ -1,12 +1,19 @@ #include "util/include/util.hpp" +#include #include +#include #include #include #include +#include +#include +#include #include "omp.h" +#include "task/include/task.hpp" +#include "util/include/func_test_util.hpp" namespace my::nested { struct Type {}; @@ -124,3 +131,49 @@ TEST(GetNumProc, ReadsFromEnvironment) { env::detail::set_scoped_environment_variable scoped("PPC_NUM_PROC", "4"); EXPECT_EQ(ppc::util::GetNumProc(), 4); } + +namespace { + +using FuncTestUtilParam = ppc::util::FuncTestParam; + +FuncTestUtilParam MakeFuncTestUtilParam(const std::string &test_name, int value) { + return FuncTestUtilParam{[](int) -> ppc::task::TaskPtr { return {}; }, test_name, value}; +} + +void ExpectSingleNonFatalFailureContains(const ::testing::TestPartResultArray &failures, std::string_view message) { + ASSERT_EQ(failures.size(), 1); + const ::testing::TestPartResult &failure = failures.GetTestPartResult(0); + EXPECT_EQ(failure.type(), ::testing::TestPartResult::kNonFatalFailure); + EXPECT_NE(std::string_view(failure.message()).find(message), std::string_view::npos); +} + +} // namespace + +TEST(FuncTestUtil, RunTestCasesWithTagAcceptsBareTags) { + const auto test_tasks = std::make_tuple(MakeFuncTestUtilParam("example_threads_seq_enabled", 1), + MakeFuncTestUtilParam("example_threads_tbb_enabled", 2), + MakeFuncTestUtilParam("example_threads_tbb_disabled", 3)); + + std::vector visited_params; + ppc::util::RunTestCasesWithTag(test_tasks, "tbb", [&](const auto &test_param) { + visited_params.push_back(std::get(ppc::util::GTestParamIndex::kTestParams)>(test_param)); + }); + + const std::vector expected_params{2, 3}; + EXPECT_EQ(visited_params, expected_params); +} + +TEST(FuncTestUtil, RunTestCasesWithTagFailsWhenTagIsMissing) { + const auto test_tasks = std::make_tuple(MakeFuncTestUtilParam("example_threads_seq_enabled", 1)); + + bool callback_was_called = false; + ::testing::TestPartResultArray failures; + { + ::testing::ScopedFakeTestPartResultReporter reporter( + ::testing::ScopedFakeTestPartResultReporter::INTERCEPT_ONLY_CURRENT_THREAD, &failures); + ppc::util::RunTestCasesWithTag(test_tasks, "omp", [&](const auto & /*test_param*/) { callback_was_called = true; }); + } + + ExpectSingleNonFatalFailureContains(failures, "No functional test cases matched tag: omp"); + EXPECT_FALSE(callback_was_called); +} diff --git a/scripts/run_tests.py b/scripts/run_tests.py index 482b30119..7c713f8bd 100755 --- a/scripts/run_tests.py +++ b/scripts/run_tests.py @@ -198,12 +198,21 @@ def __build_mpi_cmd(self, ppc_num_proc, additional_mpi_args): @staticmethod def __get_gtest_settings(repeats_count, type_task): + type_task_patterns = { + "_all_": ["_all_", "AllEnabled"], + "_mpi_": ["_mpi_", "MpiEnabled"], + "_omp_": ["_omp_", "OmpEnabled"], + "_seq_": ["_seq_", "SeqEnabled"], + "_stl_": ["_stl_", "StlEnabled"], + "_tbb_": ["_tbb_", "TbbEnabled"], + } + filter_patterns = type_task_patterns.get(type_task, [type_task]) command = [ f"--gtest_repeat={repeats_count}", "--gtest_recreate_environments_when_repeating", "--gtest_color=0", "--gtest_shuffle", - f"--gtest_filter=*{type_task}*", + "--gtest_filter=" + ":".join(f"*{pattern}*" for pattern in filter_patterns), ] return command diff --git a/tasks/example/processes/t1/tests/functional/main.cpp b/tasks/example/processes/t1/tests/functional/main.cpp index 1c32faa93..50b8c77de 100644 --- a/tasks/example/processes/t1/tests/functional/main.cpp +++ b/tasks/example/processes/t1/tests/functional/main.cpp @@ -27,7 +27,7 @@ class NesterovARunFuncTestsProcesses : public ppc::util::BaseRunFuncTests &test_param) { + void RunTestCase(const ppc::util::FuncTestParam &test_param) override { const std::string &test_name = std::get(ppc::util::GTestParamIndex::kNameTest)>(test_param); if (IsTestDisabled(test_name) || ShouldSkipNonMpiTask(test_name)) { @@ -83,8 +83,12 @@ const auto kTestTasksList = std::tuple_cat( } // namespace -TEST_F(NesterovARunFuncTestsProcesses, MatmulFromPic) { - std::apply([this](const auto &...test_params) { (RunTestCase(test_params), ...); }, kTestTasksList); +TEST_F(NesterovARunFuncTestsProcesses, MatmulFromPicMpiEnabled) { + RunTestCasesWithTag(kTestTasksList, "mpi"); +} + +TEST_F(NesterovARunFuncTestsProcesses, MatmulFromPicSeqEnabled) { + RunTestCasesWithTag(kTestTasksList, "seq"); } } // namespace example_processes_t1 diff --git a/tasks/example/processes/t2/tests/functional/main.cpp b/tasks/example/processes/t2/tests/functional/main.cpp index 0ea55456c..6e60e0f5b 100644 --- a/tasks/example/processes/t2/tests/functional/main.cpp +++ b/tasks/example/processes/t2/tests/functional/main.cpp @@ -27,7 +27,7 @@ class NesterovARunFuncTestsProcesses2 : public ppc::util::BaseRunFuncTests &test_param) { + void RunTestCase(const ppc::util::FuncTestParam &test_param) override { const std::string &test_name = std::get(ppc::util::GTestParamIndex::kNameTest)>(test_param); if (IsTestDisabled(test_name) || ShouldSkipNonMpiTask(test_name)) { @@ -83,8 +83,12 @@ const auto kTestTasksList = std::tuple_cat( } // namespace -TEST_F(NesterovARunFuncTestsProcesses2, MatmulFromPic) { - std::apply([this](const auto &...test_params) { (RunTestCase(test_params), ...); }, kTestTasksList); +TEST_F(NesterovARunFuncTestsProcesses2, MatmulFromPicMpiEnabled) { + RunTestCasesWithTag(kTestTasksList, "mpi"); +} + +TEST_F(NesterovARunFuncTestsProcesses2, MatmulFromPicSeqEnabled) { + RunTestCasesWithTag(kTestTasksList, "seq"); } } // namespace example_processes_t2 diff --git a/tasks/example/processes/t3/tests/functional/main.cpp b/tasks/example/processes/t3/tests/functional/main.cpp index 02672a54a..57bd3ebcf 100644 --- a/tasks/example/processes/t3/tests/functional/main.cpp +++ b/tasks/example/processes/t3/tests/functional/main.cpp @@ -27,7 +27,7 @@ class NesterovARunFuncTestsProcesses3 : public ppc::util::BaseRunFuncTests &test_param) { + void RunTestCase(const ppc::util::FuncTestParam &test_param) override { const std::string &test_name = std::get(ppc::util::GTestParamIndex::kNameTest)>(test_param); if (IsTestDisabled(test_name) || ShouldSkipNonMpiTask(test_name)) { @@ -83,8 +83,12 @@ const auto kTestTasksList = std::tuple_cat( } // namespace -TEST_F(NesterovARunFuncTestsProcesses3, MatmulFromPic) { - std::apply([this](const auto &...test_params) { (RunTestCase(test_params), ...); }, kTestTasksList); +TEST_F(NesterovARunFuncTestsProcesses3, MatmulFromPicMpiEnabled) { + RunTestCasesWithTag(kTestTasksList, "mpi"); +} + +TEST_F(NesterovARunFuncTestsProcesses3, MatmulFromPicSeqEnabled) { + RunTestCasesWithTag(kTestTasksList, "seq"); } } // namespace example_processes_t3 diff --git a/tasks/example/threads/tests/functional/main.cpp b/tasks/example/threads/tests/functional/main.cpp index 1ae1ff426..ff70a9993 100644 --- a/tasks/example/threads/tests/functional/main.cpp +++ b/tasks/example/threads/tests/functional/main.cpp @@ -30,7 +30,7 @@ class NesterovARunFuncTestsThreads : public ppc::util::BaseRunFuncTests &test_param) { + void RunTestCase(const ppc::util::FuncTestParam &test_param) override { const std::string &test_name = std::get(ppc::util::GTestParamIndex::kNameTest)>(test_param); if (IsTestDisabled(test_name) || ShouldSkipNonMpiTask(test_name)) { @@ -89,8 +89,24 @@ const auto kTestTasksList = } // namespace -TEST_F(NesterovARunFuncTestsThreads, MatmulFromPic) { - std::apply([this](const auto &...test_params) { (RunTestCase(test_params), ...); }, kTestTasksList); +TEST_F(NesterovARunFuncTestsThreads, MatmulFromPicAllEnabled) { + RunTestCasesWithTag(kTestTasksList, "all"); +} + +TEST_F(NesterovARunFuncTestsThreads, MatmulFromPicOmpEnabled) { + RunTestCasesWithTag(kTestTasksList, "omp"); +} + +TEST_F(NesterovARunFuncTestsThreads, MatmulFromPicSeqEnabled) { + RunTestCasesWithTag(kTestTasksList, "seq"); +} + +TEST_F(NesterovARunFuncTestsThreads, MatmulFromPicStlEnabled) { + RunTestCasesWithTag(kTestTasksList, "stl"); +} + +TEST_F(NesterovARunFuncTestsThreads, MatmulFromPicTbbEnabled) { + RunTestCasesWithTag(kTestTasksList, "tbb"); } } // namespace example_threads