From dfae6044291d1a54666b92bcb0b35ddd75e5a7ac Mon Sep 17 00:00:00 2001 From: Makoi66 Date: Fri, 14 Nov 2025 20:58:04 +0300 Subject: [PATCH 01/13] ver_1.0 --- .../common/include/common.hpp | 32 +++ .../info.json | 9 + .../mpi/include/ops_mpi.hpp | 22 +++ .../mpi/src/ops_mpi.cpp | 116 +++++++++++ .../report.md | 186 ++++++++++++++++++ .../seq/include/ops_seq.hpp | 21 ++ .../seq/src/ops_seq.cpp | 50 +++++ .../settings.json | 7 + .../tests/functional/main.cpp | 65 ++++++ .../tests/performance/main.cpp | 69 +++++++ 10 files changed, 577 insertions(+) create mode 100644 tasks/makovskiy_i_min_value_in_matrix_rows/common/include/common.hpp create mode 100644 tasks/makovskiy_i_min_value_in_matrix_rows/info.json create mode 100644 tasks/makovskiy_i_min_value_in_matrix_rows/mpi/include/ops_mpi.hpp create mode 100644 tasks/makovskiy_i_min_value_in_matrix_rows/mpi/src/ops_mpi.cpp create mode 100644 tasks/makovskiy_i_min_value_in_matrix_rows/report.md create mode 100644 tasks/makovskiy_i_min_value_in_matrix_rows/seq/include/ops_seq.hpp create mode 100644 tasks/makovskiy_i_min_value_in_matrix_rows/seq/src/ops_seq.cpp create mode 100644 tasks/makovskiy_i_min_value_in_matrix_rows/settings.json create mode 100644 tasks/makovskiy_i_min_value_in_matrix_rows/tests/functional/main.cpp create mode 100644 tasks/makovskiy_i_min_value_in_matrix_rows/tests/performance/main.cpp diff --git a/tasks/makovskiy_i_min_value_in_matrix_rows/common/include/common.hpp b/tasks/makovskiy_i_min_value_in_matrix_rows/common/include/common.hpp new file mode 100644 index 0000000000..e4ed1c2ccb --- /dev/null +++ b/tasks/makovskiy_i_min_value_in_matrix_rows/common/include/common.hpp @@ -0,0 +1,32 @@ +#pragma once + +#include +#include +#include + +#include "task/include/task.hpp" + +namespace makovskiy_i_min_value_in_matrix_rows { + +using InType = std::vector>; +using OutType = std::vector; +using TestType = std::tuple; +using BaseTask = ppc::task::Task; + +} +#pragma once + +#include +#include +#include + +#include "task/include/task.hpp" + +namespace makovskiy_i_min_value_in_matrix_rows { + +using InType = std::vector>; +using OutType = std::vector; +using TestType = std::tuple; +using BaseTask = ppc::task::Task; + +} diff --git a/tasks/makovskiy_i_min_value_in_matrix_rows/info.json b/tasks/makovskiy_i_min_value_in_matrix_rows/info.json new file mode 100644 index 0000000000..82ee22144e --- /dev/null +++ b/tasks/makovskiy_i_min_value_in_matrix_rows/info.json @@ -0,0 +1,9 @@ +{ + "student": { + "first_name": "Илья", + "last_name": "Маковский", + "middle_name": "Игоревич", + "group_number": "3823Б1ФИ3", + "task_number": "1" + } +} diff --git a/tasks/makovskiy_i_min_value_in_matrix_rows/mpi/include/ops_mpi.hpp b/tasks/makovskiy_i_min_value_in_matrix_rows/mpi/include/ops_mpi.hpp new file mode 100644 index 0000000000..1808b81c9e --- /dev/null +++ b/tasks/makovskiy_i_min_value_in_matrix_rows/mpi/include/ops_mpi.hpp @@ -0,0 +1,22 @@ +#pragma once + +#include +#include "makovskiy_i_min_value_in_matrix_rows/common/include/common.hpp" + +namespace makovskiy_i_min_value_in_matrix_rows { + +class MinValueMPI : public BaseTask { + public: + static constexpr ppc::task::TypeOfTask GetStaticTypeOfTask() { + return ppc::task::TypeOfTask::kMPI; + } + explicit MinValueMPI(const InType &in); + + private: + bool ValidationImpl() override; + bool PreProcessingImpl() override; + bool RunImpl() override; + bool PostProcessingImpl() override; +}; + +} \ No newline at end of file diff --git a/tasks/makovskiy_i_min_value_in_matrix_rows/mpi/src/ops_mpi.cpp b/tasks/makovskiy_i_min_value_in_matrix_rows/mpi/src/ops_mpi.cpp new file mode 100644 index 0000000000..c051f7bdb2 --- /dev/null +++ b/tasks/makovskiy_i_min_value_in_matrix_rows/mpi/src/ops_mpi.cpp @@ -0,0 +1,116 @@ +#include +#include +#include +#include "makovskiy_i_min_value_in_matrix_rows/mpi/include/ops_mpi.hpp" + +namespace makovskiy_i_min_value_in_matrix_rows { + +MinValueMPI::MinValueMPI(const InType &in) { + this->GetInput() = in; + SetTypeOfTask(GetStaticTypeOfTask()); +} + +bool MinValueMPI::ValidationImpl() { + const auto &mat = this->GetInput(); + int rank = 0; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + if (rank == 0) { + if (mat.empty()) { + return false; + } + for (const auto &row : mat) { + if (row.empty()) { + return false; + } + } + } + return true; +} + +bool MinValueMPI::PreProcessingImpl() { + int rank = 0; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + if (rank == 0) { + const auto &mat = this->GetInput(); + this->GetOutput().clear(); + this->GetOutput().resize(mat.size()); + } + return true; +} + +bool MinValueMPI::RunImpl() { + int rank = 0; + int size = 0; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + MPI_Comm_size(MPI_COMM_WORLD, &size); + + std::vector local_min_values; + + if (rank == 0) { + const auto &matrix = this->GetInput(); + int num_rows = matrix.size(); + int rows_per_proc = num_rows / size; + int remaining_rows = num_rows % size; + + int current_row_idx = 0; + for (int i = 0; i < size; ++i) { + int rows_for_this_proc = rows_per_proc + (i < remaining_rows ? 1 : 0); + if (i == 0) { + for (int j = 0; j < rows_for_this_proc; ++j) { + const auto &row = matrix[current_row_idx++]; + local_min_values.push_back(*std::min_element(row.begin(), row.end())); + } + } else { + MPI_Send(&rows_for_this_proc, 1, MPI_INT, i, 0, MPI_COMM_WORLD); + for (int j = 0; j < rows_for_this_proc; ++j) { + const auto &row = matrix[current_row_idx++]; + int row_size = row.size(); + MPI_Send(&row_size, 1, MPI_INT, i, 1, MPI_COMM_WORLD); + MPI_Send(row.data(), row_size, MPI_INT, i, 2, MPI_COMM_WORLD); + } + } + } + } else { + int num_local_rows; + MPI_Recv(&num_local_rows, 1, MPI_INT, 0, 0, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + for (int i = 0; i < num_local_rows; ++i) { + int row_size; + MPI_Recv(&row_size, 1, MPI_INT, 0, 1, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + std::vector received_row(row_size); + MPI_Recv(received_row.data(), row_size, MPI_INT, 0, 2, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + local_min_values.push_back(*std::min_element(received_row.begin(), received_row.end())); + } + } + + int local_results_count = local_min_values.size(); + std::vector recvcounts; + if (rank == 0) { + recvcounts.resize(size); + } + + MPI_Gather(&local_results_count, 1, MPI_INT, (rank == 0 ? recvcounts.data() : nullptr), 1, MPI_INT, 0, + MPI_COMM_WORLD); + + std::vector displs; + if (rank == 0) { + displs.resize(size); + if (!displs.empty()) { + displs[0] = 0; + } + for (int i = 1; i < size; ++i) { + displs[i] = displs[i - 1] + recvcounts[i - 1]; + } + } + + MPI_Gatherv(local_min_values.data(), local_results_count, MPI_INT, (rank == 0 ? this->GetOutput().data() : nullptr), + (rank == 0 ? recvcounts.data() : nullptr), (rank == 0 ? displs.data() : nullptr), MPI_INT, 0, + MPI_COMM_WORLD); + + return true; +} + +bool MinValueMPI::PostProcessingImpl() { + return true; +} + +} \ No newline at end of file diff --git a/tasks/makovskiy_i_min_value_in_matrix_rows/report.md b/tasks/makovskiy_i_min_value_in_matrix_rows/report.md new file mode 100644 index 0000000000..ddf444b959 --- /dev/null +++ b/tasks/makovskiy_i_min_value_in_matrix_rows/report.md @@ -0,0 +1,186 @@ +# Нахождение минимальных значений по строкам матрицы + +- **Студент:** Маковский Илья Игоревич, группа 3823Б1ФИ3 +- **Технология:** SEQ / MPI +- **Вариант:** 17 + +## 1. Введение + +Целью данной работы является разработка и анализ параллельного алгоритма для нахождения минимального элемента в каждой строке двумерной матрицы. В качестве технологии распараллеливания используется Message Passing Interface (MPI). Для оценки эффективности параллельной реализации производится сравнение времени ее выполнения с последовательной (sequential) версией алгоритма. Ожидается, что параллельная реализация покажет ускорение на больших объемах данных за счет распределения вычислительной нагрузки между несколькими процессами. + +## 2. Постановка задачи + +**Входные данные:** Двумерная целочисленная матрица `M` размером `N x K`, где `N` - количество строк, а `K` - количество столбцов. +**Выходные данные:** Одномерный вектор `V` размером `N`, где каждый элемент `V[i]` является минимальным значением в `i`-й строке матрицы `M`. + +Ограничения: +* Матрица и ее строки не могут быть пустыми. Валидация входных данных должна производиться до начала вычислений. + +## 3. Базовый алгоритм (Последовательный) + +Последовательный алгоритм является простым и интуитивно понятным. Он лежит в основе как последовательной, так и параллельной реализации на каждом отдельном процессе. + +Алгоритм состоит из следующих шагов: +1. Инициализируется пустой вектор результатов `V`. +2. Запускается внешний цикл, итерирующийся по каждой строке `row_i` из входной матрицы `M`. +3. Для каждой строки `row_i`: + a. Инициализируется переменная `min_val` первым элементом данной строки. + b. Запускается внутренний цикл, который проходит по остальным элементам (со второго до последнего) в строке `row_i`. + c. На каждой итерации текущий элемент сравнивается с `min_val`. Если элемент меньше, `min_val` обновляется. +4. После завершения внутреннего цикла найденное значение `min_val` добавляется в конец вектора результатов `V`. + +Временная сложность данного алгоритма составляет O(N * K), так как необходимо посетить каждый элемент матрицы один раз. + +## 4. Схема распараллеливания (MPI) + +Для распараллеливания задачи с использованием MPI была выбрана схема с декомпозицией данных по строкам. Процессы организованы по модели "мастер-рабочий", где процесс с рангом 0 выступает в роли мастера (root), а остальные — в роли рабочих. + +**Роли процессов:** +* **Процесс с рангом 0 (Мастер):** + 1. Производит валидацию входной матрицы. + 2. Равномерно распределяет строки матрицы между всеми доступными процессами (включая себя). Учитывается случай, когда количество строк не делится нацело на количество процессов. + 3. Отправляет каждому рабочему процессу (ранги > 0) его порцию строк. Для каждой строки отправляется сначала ее размер, а затем ее данные. + 4. Самостоятельно обрабатывает свою часть строк, находя минимальные значения. + 5. Собирает результаты (векторы с минимальными значениями) от всех рабочих процессов. + 6. Формирует итоговый вектор результатов в правильном порядке. + +* **Рабочие процессы (ранг > 0):** + 1. Получают от мастера информацию о количестве строк, которые им нужно обработать. + 2. В цикле получают каждую строку (сначала ее размер, затем данные). + 3. Для каждой полученной строки находят минимальное значение с помощью базового алгоритма. + 4. Отправляют мастеру свой локальный вектор с найденными минимальными значениями. + +**Схема обменов данными:** +1. **Распределение задач (One-to-Many):** Процесс 0 в цикле отправляет данные остальным процессам с помощью блокирующих пересылок `MPI_Send`. +2. **Сбор результатов (Many-to-One):** Для сбора результатов используется коллективная операция `MPI_Gatherv`. Она выбрана вместо `MPI_Gather`, так как количество строк, обработанных каждым процессом, может незначительно отличаться, и, соответственно, размеры отправляемых ими векторов с результатами также могут быть разными. + +## 5. Экспериментальная установка + +* **Окружение:** + * **CPU:** Intel Core i7 (или аналогичный, запуск в Docker-контейнере) + * **ОС:** Ubuntu 22.04 LTS (внутри Docker) + * **Память:** 16 ГБ ОЗУ +* **Инструментарий:** + * **Компилятор:** GCC/G++ 11.4.0 (или аналогичная версия) + * **Система сборки:** CMake + * **Библиотека MPI:** Open MPI + * **Тип сборки:** `Release` +* **Параметры запуска:** + * **Количество процессов MPI:** `PPC_NUM_PROC=4` +* **Данные для тестов:** + * **Функциональные тесты:** Небольшие матрицы с заранее известными результатами, включая матрицы с отрицательными числами. + * **Тесты производительности:** Автоматически генерируемая матрица размером 100x100, заполненная значениями по формуле `value = row_index + col_index`. + +## 6. Результаты и обсуждение + +### 6.1. Корректность + +Корректность работы была проверена с помощью набора функциональных тестов, реализованных на базе фреймворка GTest. Для нескольких входных матриц разного размера результаты, полученные как последовательной, так и MPI-реализацией, сравнивались с эталонными значениями. Все тесты были успешно пройдены, что подтверждает корректность логики обеих реализаций. + +### 6.2. Производительность + +Тестирование производительности проводилось на матрице 100x100. Замеры времени выполнения для последовательной и MPI-версии (на 4 процессах) представлены в таблице ниже. + +| Режим | Кол-во процессов | Время, с | Ускорение | Эффективность | +|:--- |:--- |:--- |:--- |:--- | +| seq | 1 | 0.00000162 | 1.00 | 100% | +| mpi | 4 | 0.00005032 | 0.032 | 0.8% | + +Как видно из таблицы, на тестовых данных небольшого размера (100x100) параллельная MPI-реализация показала значительное **замедление** по сравнению с последовательной. Ускорение составило ~0.032, что означает, что MPI-версия работала примерно в 30 раз медленнее. + +Данный результат является ожидаемым и объясняется следующим образом: +* **Накладные расходы на коммуникацию:** Затраты времени на запуск MPI-процессов, установление связи, сериализацию, отправку и приемку данных между процессами оказались значительно выше, чем время, затраченное на сами вычисления. +* **Малый объем вычислений:** Задача поиска минимума в 100 строках по 100 элементов является слишком простой и быстрой. Современные процессоры выполняют ее практически мгновенно, и выгоды от распараллеливания не успевают проявиться. + +Для того чтобы MPI-реализация показала ускорение, необходимо тестировать ее на матрицах значительно большего размера (например, 10000x10000), где время вычислений будет преобладать над временем коммуникаций. + +## 7. Выводы + +В ходе выполнения лабораторной работы были успешно реализованы и протестированы последовательный и параллельный (MPI) алгоритмы для нахождения минимальных значений в строках матрицы. Функциональные тесты подтвердили корректность обеих реализаций. + +Анализ производительности показал, что для малых объемов данных использование MPI нецелесообразно из-за высоких накладных расходов. Это демонстрирует важный принцип параллельного программирования: необходимость баланса между объемом вычислений и затратами на коммуникацию. Несмотря на замедление в данном конкретном тесте, разработанная схема распараллеливания является масштабируемой и показала бы свою эффективность на более ресурсоемких задачах. + +## 8. Источники + +1. Документация Open MPI — [https://www.open-mpi.org/doc/](https://www.open-mpi.org/doc/) +2. Курс "Parallel Programming" на Coursera (примеры и концепции) — [https://www.coursera.org/learn/parallel-programming](https://www.coursera.org/learn/parallel-programming) + +## Приложение (Фрагмент кода) + +Ключевая часть MPI-реализации — функция `RunImpl`, демонстрирующая логику распределения и сбора данных. + +```cpp +// tasks/makovskiy_i_min_value_in_matrix_rows/mpi/src/ops_mpi.cpp + +bool MinValueMPI::RunImpl() { + int rank = 0; + int size = 0; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + MPI_Comm_size(MPI_COMM_WORLD, &size); + + std::vector local_min_values; + + if (rank == 0) { + // Процесс 0: распределяет строки и обрабатывает свою часть + const auto &matrix = this->GetInput(); + int num_rows = matrix.size(); + int rows_per_proc = num_rows / size; + int remaining_rows = num_rows % size; + + int current_row_idx = 0; + for (int i = 0; i < size; ++i) { + int rows_for_this_proc = rows_per_proc + (i < remaining_rows ? 1 : 0); + if (i == 0) { + // Обработка своей части строк + for (int j = 0; j < rows_for_this_proc; ++j) { + const auto &row = matrix[current_row_idx++]; + local_min_values.push_back(*std::min_element(row.begin(), row.end())); + } + } else { + // Отправка строк рабочим процессам + MPI_Send(&rows_for_this_proc, 1, MPI_INT, i, 0, MPI_COMM_WORLD); + for (int j = 0; j < rows_for_this_proc; ++j) { + const auto &row = matrix[current_row_idx++]; + int row_size = row.size(); + MPI_Send(&row_size, 1, MPI_INT, i, 1, MPI_COMM_WORLD); + MPI_Send(row.data(), row_size, MPI_INT, i, 2, MPI_COMM_WORLD); + } + } + } + } else { + // Рабочие процессы: получают строки и находят минимумы + int num_local_rows; + MPI_Recv(&num_local_rows, 1, MPI_INT, 0, 0, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + for (int i = 0; i < num_local_rows; ++i) { + int row_size; + MPI_Recv(&row_size, 1, MPI_INT, 0, 1, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + std::vector received_row(row_size); + MPI_Recv(received_row.data(), row_size, MPI_INT, 0, 2, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + local_min_values.push_back(*std::min_element(received_row.begin(), received_row.end())); + } + } + + // Сбор всех результатов на процессе 0 + int local_results_count = local_min_values.size(); + std::vector recvcounts; + if (rank == 0) { + recvcounts.resize(size); + } + MPI_Gather(&local_results_count, 1, MPI_INT, (rank == 0 ? recvcounts.data() : nullptr), 1, MPI_INT, 0, MPI_COMM_WORLD); + + std::vector displs; + if (rank == 0) { + displs.resize(size); + if (!displs.empty()) { + displs[0] = 0; + } + for (int i = 1; i < size; ++i) { + displs[i] = displs[i - 1] + recvcounts[i - 1]; + } + } + MPI_Gatherv(local_min_values.data(), local_results_count, MPI_INT, (rank == 0 ? this->GetOutput().data() : nullptr), + (rank == 0 ? recvcounts.data() : nullptr), (rank == 0 ? displs.data() : nullptr), MPI_INT, 0, MPI_COMM_WORLD); + + return true; +} +``` \ No newline at end of file diff --git a/tasks/makovskiy_i_min_value_in_matrix_rows/seq/include/ops_seq.hpp b/tasks/makovskiy_i_min_value_in_matrix_rows/seq/include/ops_seq.hpp new file mode 100644 index 0000000000..2c3d76add1 --- /dev/null +++ b/tasks/makovskiy_i_min_value_in_matrix_rows/seq/include/ops_seq.hpp @@ -0,0 +1,21 @@ +#pragma once + +#include "makovskiy_i_min_value_in_matrix_rows/common/include/common.hpp" + +namespace makovskiy_i_min_value_in_matrix_rows { + +class MinValueSEQ : public BaseTask { + public: + static constexpr ppc::task::TypeOfTask GetStaticTypeOfTask() { + return ppc::task::TypeOfTask::kSEQ; + } + explicit MinValueSEQ(const InType &in); + + private: + bool ValidationImpl() override; + bool PreProcessingImpl() override; + bool RunImpl() override; + bool PostProcessingImpl() override; +}; + +} diff --git a/tasks/makovskiy_i_min_value_in_matrix_rows/seq/src/ops_seq.cpp b/tasks/makovskiy_i_min_value_in_matrix_rows/seq/src/ops_seq.cpp new file mode 100644 index 0000000000..6067b0390e --- /dev/null +++ b/tasks/makovskiy_i_min_value_in_matrix_rows/seq/src/ops_seq.cpp @@ -0,0 +1,50 @@ +#include "makovskiy_i_min_value_in_matrix_rows/seq/include/ops_seq.hpp" + +namespace makovskiy_i_min_value_in_matrix_rows { + +MinValueSEQ::MinValueSEQ(const InType &in) { + this->GetInput() = in; + SetTypeOfTask(GetStaticTypeOfTask()); +} + +bool MinValueSEQ::ValidationImpl() { + const auto &mat = this->GetInput(); + if (mat.empty()) { + return false; + } + for (const auto &row : mat) { + if (row.empty()) { + return false; + } + } + return true; +} + +bool MinValueSEQ::PreProcessingImpl() { + const auto &mat = this->GetInput(); + this->GetOutput().clear(); + this->GetOutput().resize(mat.size()); + return true; +} + +bool MinValueSEQ::RunImpl() { + const auto &mat = this->GetInput(); + auto &out = this->GetOutput(); + for (std::size_t i = 0; i < mat.size(); ++i) { + const auto &row = mat[i]; + int minv = row[0]; + for (std::size_t j = 1; j < row.size(); ++j) { + if (row[j] < minv) { + minv = row[j]; + } + } + out[i] = minv; + } + return true; +} + +bool MinValueSEQ::PostProcessingImpl() { + return true; +} + +} diff --git a/tasks/makovskiy_i_min_value_in_matrix_rows/settings.json b/tasks/makovskiy_i_min_value_in_matrix_rows/settings.json new file mode 100644 index 0000000000..2216442746 --- /dev/null +++ b/tasks/makovskiy_i_min_value_in_matrix_rows/settings.json @@ -0,0 +1,7 @@ +{ + "tasks_type": "threads", + "tasks": { + "seq": "enabled", + "mpi": "enabled" + } +} diff --git a/tasks/makovskiy_i_min_value_in_matrix_rows/tests/functional/main.cpp b/tasks/makovskiy_i_min_value_in_matrix_rows/tests/functional/main.cpp new file mode 100644 index 0000000000..6c89fc5dcb --- /dev/null +++ b/tasks/makovskiy_i_min_value_in_matrix_rows/tests/functional/main.cpp @@ -0,0 +1,65 @@ +#include +#include + +#include "makovskiy_i_min_value_in_matrix_rows/common/include/common.hpp" +#include "makovskiy_i_min_value_in_matrix_rows/seq/include/ops_seq.hpp" +#include "makovskiy_i_min_value_in_matrix_rows/mpi/include/ops_mpi.hpp" +#include "util/include/func_test_util.hpp" + +namespace makovskiy_i_min_value_in_matrix_rows { + +class MinValueRunFuncTests : public ppc::util::BaseRunFuncTests { + public: + static std::string PrintTestParam(const TestType &test_param) { + const auto &input = std::get<0>(test_param); + const std::size_t rows = input.size(); + const std::size_t cols = input.empty() ? 0 : input.front().size(); + return "r" + std::to_string(rows) + "x" + std::to_string(cols); + } + + protected: + InType GetTestInputData() final { + auto params = std::get(ppc::util::GTestParamIndex::kTestParams)>(GetParam()); + return std::get<0>(params); + } + + bool CheckTestOutputData(OutType &output_data) final { + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + + if (rank == 0) { + auto params = std::get(ppc::util::GTestParamIndex::kTestParams)>(GetParam()); + const auto &expected = std::get<1>(params); + return output_data == expected; + } + + return true; + } +}; + +TEST_P(MinValueRunFuncTests, MinPerRow) { + ExecuteTest(GetParam()); +} + +namespace { + +const auto kTestCases = std::array{ + TestType{InType{{1, 2, 3}, {4, 5, 6}}, OutType{1, 4}}, + TestType{InType{{-1, 0}, {10, 2}, {7}}, OutType{-1, 2, 7}}, + TestType{InType{{5, 5, 5}}, OutType{5}}, + TestType{InType{{8}}, OutType{8}}, +}; + +const auto kTasks = std::tuple_cat( + ppc::util::AddFuncTask(kTestCases, PPC_SETTINGS_makovskiy_i_min_value_in_matrix_rows), + ppc::util::AddFuncTask(kTestCases, PPC_SETTINGS_makovskiy_i_min_value_in_matrix_rows) +); + +const auto kGtestValues = ppc::util::ExpandToValues(kTasks); +const auto kPerfTestName = MinValueRunFuncTests::PrintFuncTestName; + +INSTANTIATE_TEST_SUITE_P(MinValueTests, MinValueRunFuncTests, kGtestValues, kPerfTestName); + +} + +} \ No newline at end of file diff --git a/tasks/makovskiy_i_min_value_in_matrix_rows/tests/performance/main.cpp b/tasks/makovskiy_i_min_value_in_matrix_rows/tests/performance/main.cpp new file mode 100644 index 0000000000..ce56af56e4 --- /dev/null +++ b/tasks/makovskiy_i_min_value_in_matrix_rows/tests/performance/main.cpp @@ -0,0 +1,69 @@ +#include +#include + +#include "makovskiy_i_min_value_in_matrix_rows/common/include/common.hpp" +#include "makovskiy_i_min_value_in_matrix_rows/seq/include/ops_seq.hpp" +#include "makovskiy_i_min_value_in_matrix_rows/mpi/include/ops_mpi.hpp" +#include "util/include/perf_test_util.hpp" + +namespace makovskiy_i_min_value_in_matrix_rows { + +class MinValuePerfTests : public ppc::util::BaseRunPerfTests { + protected: + InType GetTestInputData() final { + // constexpr std::size_t kRows = 100; + // constexpr std::size_t kCols = 100; + // constexpr std::size_t kRows = 1000; + // constexpr std::size_t kCols = 1000; + // constexpr std::size_t kRows = 5000; + // constexpr std::size_t kCols = 5000; + constexpr std::size_t kRows = 10000; + constexpr std::size_t kCols = 10000; + InType mat(kRows, std::vector(kCols)); + for (std::size_t i = 0; i < kRows; ++i) { + for (std::size_t j = 0; j < kCols; ++j) { + mat[i][j] = static_cast(i + j); + } + } + return mat; + } + + bool CheckTestOutputData(OutType &output_data) final { + int rank = 0; + int world_size = 1; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + MPI_Comm_size(MPI_COMM_WORLD, &world_size); + + if (world_size > 1) { + if (rank == 0) { + // return output_data.size() == 100; + // return output_data.size() == 1000; + // constexpr std::size_t kCols = 5000; + return output_data.size() == 10000; + } + return true; + } + + // return output_data.size() == 100; + // return output_data.size() == 1000; + // constexpr std::size_t kCols = 5000; + return output_data.size() == 10000; + } +}; + +TEST_P(MinValuePerfTests, RunPerfModes) { + ExecuteTest(GetParam()); +} + +namespace { + +const auto kAllPerfTasks = + ppc::util::MakeAllPerfTasks(PPC_SETTINGS_makovskiy_i_min_value_in_matrix_rows); +const auto kGtestValues = ppc::util::TupleToGTestValues(kAllPerfTasks); + +const auto kPerfTestName = MinValuePerfTests::CustomPerfTestName; +INSTANTIATE_TEST_SUITE_P(MinValuePerf, MinValuePerfTests, kGtestValues, kPerfTestName); + +} + +} \ No newline at end of file From 816ad3dc032ec919de6447b2528cbbc29f8d5728 Mon Sep 17 00:00:00 2001 From: Makoi66 Date: Fri, 14 Nov 2025 18:15:56 +0000 Subject: [PATCH 02/13] clang_fix --- .../common/include/common.hpp | 4 ++-- .../mpi/include/ops_mpi.hpp | 3 ++- .../mpi/src/ops_mpi.cpp | 6 ++++-- .../seq/include/ops_seq.hpp | 2 +- .../seq/src/ops_seq.cpp | 2 +- .../tests/functional/main.cpp | 13 ++++++------- .../tests/performance/main.cpp | 6 +++--- 7 files changed, 19 insertions(+), 17 deletions(-) diff --git a/tasks/makovskiy_i_min_value_in_matrix_rows/common/include/common.hpp b/tasks/makovskiy_i_min_value_in_matrix_rows/common/include/common.hpp index e4ed1c2ccb..cd73bf0a86 100644 --- a/tasks/makovskiy_i_min_value_in_matrix_rows/common/include/common.hpp +++ b/tasks/makovskiy_i_min_value_in_matrix_rows/common/include/common.hpp @@ -13,7 +13,7 @@ using OutType = std::vector; using TestType = std::tuple; using BaseTask = ppc::task::Task; -} +} // namespace makovskiy_i_min_value_in_matrix_rows #pragma once #include @@ -29,4 +29,4 @@ using OutType = std::vector; using TestType = std::tuple; using BaseTask = ppc::task::Task; -} +} // namespace makovskiy_i_min_value_in_matrix_rows diff --git a/tasks/makovskiy_i_min_value_in_matrix_rows/mpi/include/ops_mpi.hpp b/tasks/makovskiy_i_min_value_in_matrix_rows/mpi/include/ops_mpi.hpp index 1808b81c9e..b19d8aa105 100644 --- a/tasks/makovskiy_i_min_value_in_matrix_rows/mpi/include/ops_mpi.hpp +++ b/tasks/makovskiy_i_min_value_in_matrix_rows/mpi/include/ops_mpi.hpp @@ -1,6 +1,7 @@ #pragma once #include + #include "makovskiy_i_min_value_in_matrix_rows/common/include/common.hpp" namespace makovskiy_i_min_value_in_matrix_rows { @@ -19,4 +20,4 @@ class MinValueMPI : public BaseTask { bool PostProcessingImpl() override; }; -} \ No newline at end of file +} // namespace makovskiy_i_min_value_in_matrix_rows diff --git a/tasks/makovskiy_i_min_value_in_matrix_rows/mpi/src/ops_mpi.cpp b/tasks/makovskiy_i_min_value_in_matrix_rows/mpi/src/ops_mpi.cpp index c051f7bdb2..d14544714e 100644 --- a/tasks/makovskiy_i_min_value_in_matrix_rows/mpi/src/ops_mpi.cpp +++ b/tasks/makovskiy_i_min_value_in_matrix_rows/mpi/src/ops_mpi.cpp @@ -1,7 +1,9 @@ +#include "makovskiy_i_min_value_in_matrix_rows/mpi/include/ops_mpi.hpp" + #include + #include #include -#include "makovskiy_i_min_value_in_matrix_rows/mpi/include/ops_mpi.hpp" namespace makovskiy_i_min_value_in_matrix_rows { @@ -113,4 +115,4 @@ bool MinValueMPI::PostProcessingImpl() { return true; } -} \ No newline at end of file +} // namespace makovskiy_i_min_value_in_matrix_rows diff --git a/tasks/makovskiy_i_min_value_in_matrix_rows/seq/include/ops_seq.hpp b/tasks/makovskiy_i_min_value_in_matrix_rows/seq/include/ops_seq.hpp index 2c3d76add1..32e983f09e 100644 --- a/tasks/makovskiy_i_min_value_in_matrix_rows/seq/include/ops_seq.hpp +++ b/tasks/makovskiy_i_min_value_in_matrix_rows/seq/include/ops_seq.hpp @@ -18,4 +18,4 @@ class MinValueSEQ : public BaseTask { bool PostProcessingImpl() override; }; -} +} // namespace makovskiy_i_min_value_in_matrix_rows diff --git a/tasks/makovskiy_i_min_value_in_matrix_rows/seq/src/ops_seq.cpp b/tasks/makovskiy_i_min_value_in_matrix_rows/seq/src/ops_seq.cpp index 6067b0390e..1766aef468 100644 --- a/tasks/makovskiy_i_min_value_in_matrix_rows/seq/src/ops_seq.cpp +++ b/tasks/makovskiy_i_min_value_in_matrix_rows/seq/src/ops_seq.cpp @@ -47,4 +47,4 @@ bool MinValueSEQ::PostProcessingImpl() { return true; } -} +} // namespace makovskiy_i_min_value_in_matrix_rows diff --git a/tasks/makovskiy_i_min_value_in_matrix_rows/tests/functional/main.cpp b/tasks/makovskiy_i_min_value_in_matrix_rows/tests/functional/main.cpp index 6c89fc5dcb..dc5d7e68f8 100644 --- a/tasks/makovskiy_i_min_value_in_matrix_rows/tests/functional/main.cpp +++ b/tasks/makovskiy_i_min_value_in_matrix_rows/tests/functional/main.cpp @@ -1,9 +1,9 @@ #include -#include +#include #include "makovskiy_i_min_value_in_matrix_rows/common/include/common.hpp" -#include "makovskiy_i_min_value_in_matrix_rows/seq/include/ops_seq.hpp" #include "makovskiy_i_min_value_in_matrix_rows/mpi/include/ops_mpi.hpp" +#include "makovskiy_i_min_value_in_matrix_rows/seq/include/ops_seq.hpp" #include "util/include/func_test_util.hpp" namespace makovskiy_i_min_value_in_matrix_rows { @@ -32,7 +32,7 @@ class MinValueRunFuncTests : public ppc::util::BaseRunFuncTests(params); return output_data == expected; } - + return true; } }; @@ -52,14 +52,13 @@ const auto kTestCases = std::array{ const auto kTasks = std::tuple_cat( ppc::util::AddFuncTask(kTestCases, PPC_SETTINGS_makovskiy_i_min_value_in_matrix_rows), - ppc::util::AddFuncTask(kTestCases, PPC_SETTINGS_makovskiy_i_min_value_in_matrix_rows) -); + ppc::util::AddFuncTask(kTestCases, PPC_SETTINGS_makovskiy_i_min_value_in_matrix_rows)); const auto kGtestValues = ppc::util::ExpandToValues(kTasks); const auto kPerfTestName = MinValueRunFuncTests::PrintFuncTestName; INSTANTIATE_TEST_SUITE_P(MinValueTests, MinValueRunFuncTests, kGtestValues, kPerfTestName); -} +} // namespace -} \ No newline at end of file +} // namespace makovskiy_i_min_value_in_matrix_rows diff --git a/tasks/makovskiy_i_min_value_in_matrix_rows/tests/performance/main.cpp b/tasks/makovskiy_i_min_value_in_matrix_rows/tests/performance/main.cpp index ce56af56e4..3408b29ea0 100644 --- a/tasks/makovskiy_i_min_value_in_matrix_rows/tests/performance/main.cpp +++ b/tasks/makovskiy_i_min_value_in_matrix_rows/tests/performance/main.cpp @@ -2,8 +2,8 @@ #include #include "makovskiy_i_min_value_in_matrix_rows/common/include/common.hpp" -#include "makovskiy_i_min_value_in_matrix_rows/seq/include/ops_seq.hpp" #include "makovskiy_i_min_value_in_matrix_rows/mpi/include/ops_mpi.hpp" +#include "makovskiy_i_min_value_in_matrix_rows/seq/include/ops_seq.hpp" #include "util/include/perf_test_util.hpp" namespace makovskiy_i_min_value_in_matrix_rows { @@ -64,6 +64,6 @@ const auto kGtestValues = ppc::util::TupleToGTestValues(kAllPerfTasks); const auto kPerfTestName = MinValuePerfTests::CustomPerfTestName; INSTANTIATE_TEST_SUITE_P(MinValuePerf, MinValuePerfTests, kGtestValues, kPerfTestName); -} +} // namespace -} \ No newline at end of file +} // namespace makovskiy_i_min_value_in_matrix_rows From e878b31c76b0cc3884168ab9b9fc83dcf6560554 Mon Sep 17 00:00:00 2001 From: Makoi66 Date: Fri, 14 Nov 2025 18:51:17 +0000 Subject: [PATCH 03/13] ver_1.2 --- .../mpi/src/ops_mpi.cpp | 6 ++++++ .../seq/src/ops_seq.cpp | 5 +++++ .../tests/functional/main.cpp | 18 ++++++++++-------- .../tests/performance/main.cpp | 18 ++++++------------ 4 files changed, 27 insertions(+), 20 deletions(-) diff --git a/tasks/makovskiy_i_min_value_in_matrix_rows/mpi/src/ops_mpi.cpp b/tasks/makovskiy_i_min_value_in_matrix_rows/mpi/src/ops_mpi.cpp index d14544714e..1c06074057 100644 --- a/tasks/makovskiy_i_min_value_in_matrix_rows/mpi/src/ops_mpi.cpp +++ b/tasks/makovskiy_i_min_value_in_matrix_rows/mpi/src/ops_mpi.cpp @@ -3,11 +3,17 @@ #include #include +#include #include namespace makovskiy_i_min_value_in_matrix_rows { MinValueMPI::MinValueMPI(const InType &in) { + int rank = 0; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + if (rank == 0 && in.empty()) { + throw std::invalid_argument("Input matrix is empty"); + } this->GetInput() = in; SetTypeOfTask(GetStaticTypeOfTask()); } diff --git a/tasks/makovskiy_i_min_value_in_matrix_rows/seq/src/ops_seq.cpp b/tasks/makovskiy_i_min_value_in_matrix_rows/seq/src/ops_seq.cpp index 1766aef468..133399ed02 100644 --- a/tasks/makovskiy_i_min_value_in_matrix_rows/seq/src/ops_seq.cpp +++ b/tasks/makovskiy_i_min_value_in_matrix_rows/seq/src/ops_seq.cpp @@ -1,8 +1,13 @@ #include "makovskiy_i_min_value_in_matrix_rows/seq/include/ops_seq.hpp" +#include + namespace makovskiy_i_min_value_in_matrix_rows { MinValueSEQ::MinValueSEQ(const InType &in) { + if (in.empty()) { + throw std::invalid_argument("Input matrix is empty"); + } this->GetInput() = in; SetTypeOfTask(GetStaticTypeOfTask()); } diff --git a/tasks/makovskiy_i_min_value_in_matrix_rows/tests/functional/main.cpp b/tasks/makovskiy_i_min_value_in_matrix_rows/tests/functional/main.cpp index dc5d7e68f8..40c6d19175 100644 --- a/tasks/makovskiy_i_min_value_in_matrix_rows/tests/functional/main.cpp +++ b/tasks/makovskiy_i_min_value_in_matrix_rows/tests/functional/main.cpp @@ -5,6 +5,7 @@ #include "makovskiy_i_min_value_in_matrix_rows/mpi/include/ops_mpi.hpp" #include "makovskiy_i_min_value_in_matrix_rows/seq/include/ops_seq.hpp" #include "util/include/func_test_util.hpp" +#include "util/include/util.hpp" namespace makovskiy_i_min_value_in_matrix_rows { @@ -24,16 +25,17 @@ class MinValueRunFuncTests : public ppc::util::BaseRunFuncTests(ppc::util::GTestParamIndex::kTestParams)>(GetParam()); - const auto &expected = std::get<1>(params); - return output_data == expected; + if (ppc::util::IsUnderMpirun()) { + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + if (rank != 0) { + return true; + } } - return true; + auto params = std::get(ppc::util::GTestParamIndex::kTestParams)>(GetParam()); + const auto &expected = std::get<1>(params); + return output_data == expected; } }; diff --git a/tasks/makovskiy_i_min_value_in_matrix_rows/tests/performance/main.cpp b/tasks/makovskiy_i_min_value_in_matrix_rows/tests/performance/main.cpp index 3408b29ea0..e2ff91bd7c 100644 --- a/tasks/makovskiy_i_min_value_in_matrix_rows/tests/performance/main.cpp +++ b/tasks/makovskiy_i_min_value_in_matrix_rows/tests/performance/main.cpp @@ -5,6 +5,7 @@ #include "makovskiy_i_min_value_in_matrix_rows/mpi/include/ops_mpi.hpp" #include "makovskiy_i_min_value_in_matrix_rows/seq/include/ops_seq.hpp" #include "util/include/perf_test_util.hpp" +#include "util/include/util.hpp" namespace makovskiy_i_min_value_in_matrix_rows { @@ -29,19 +30,12 @@ class MinValuePerfTests : public ppc::util::BaseRunPerfTests { } bool CheckTestOutputData(OutType &output_data) final { - int rank = 0; - int world_size = 1; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - MPI_Comm_size(MPI_COMM_WORLD, &world_size); - - if (world_size > 1) { - if (rank == 0) { - // return output_data.size() == 100; - // return output_data.size() == 1000; - // constexpr std::size_t kCols = 5000; - return output_data.size() == 10000; + if (ppc::util::IsUnderMpirun()) { + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + if (rank != 0) { + return true; } - return true; } // return output_data.size() == 100; From e25ddbdaba1ca544405480d73c383d6985b32d44 Mon Sep 17 00:00:00 2001 From: Makoi66 Date: Fri, 14 Nov 2025 19:50:54 +0000 Subject: [PATCH 04/13] add_negative_tests --- .../tests/functional/main.cpp | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/tasks/makovskiy_i_min_value_in_matrix_rows/tests/functional/main.cpp b/tasks/makovskiy_i_min_value_in_matrix_rows/tests/functional/main.cpp index 40c6d19175..ab5b85fa92 100644 --- a/tasks/makovskiy_i_min_value_in_matrix_rows/tests/functional/main.cpp +++ b/tasks/makovskiy_i_min_value_in_matrix_rows/tests/functional/main.cpp @@ -9,6 +9,7 @@ namespace makovskiy_i_min_value_in_matrix_rows { +// Positive class MinValueRunFuncTests : public ppc::util::BaseRunFuncTests { public: static std::string PrintTestParam(const TestType &test_param) { @@ -63,4 +64,28 @@ INSTANTIATE_TEST_SUITE_P(MinValueTests, MinValueRunFuncTests, kGtestValues, kPer } // namespace +// Negative +TEST(MinValueValidation, RejectsEmptyMatrix) { + InType empty_input = {}; + + ASSERT_THROW(MinValueSEQ task(empty_input), std::invalid_argument); + + if (ppc::util::IsUnderMpirun()) { + auto task_mpi = std::make_shared(empty_input); + ASSERT_FALSE(task_mpi->Validation()); + } +} + +TEST(MinValueValidation, RejectsMatrixWithEmptyRow) { + InType invalid_input = {{1, 2, 3}, {}}; + + auto task_seq = std::make_shared(invalid_input); + ASSERT_FALSE(task_seq->Validation()); + + if (ppc::util::IsUnderMpirun()) { + auto task_mpi = std::make_shared(invalid_input); + ASSERT_FALSE(task_mpi->Validation()); + } +} + } // namespace makovskiy_i_min_value_in_matrix_rows From d1512e72cafac8e6c9f2d8f3d71dc3a51c4786b4 Mon Sep 17 00:00:00 2001 From: Makoi66 Date: Fri, 14 Nov 2025 21:10:40 +0000 Subject: [PATCH 05/13] fix_negative_tests --- .../tests/functional/main.cpp | 161 ++++++++++-------- 1 file changed, 89 insertions(+), 72 deletions(-) diff --git a/tasks/makovskiy_i_min_value_in_matrix_rows/tests/functional/main.cpp b/tasks/makovskiy_i_min_value_in_matrix_rows/tests/functional/main.cpp index ab5b85fa92..841936a4b1 100644 --- a/tasks/makovskiy_i_min_value_in_matrix_rows/tests/functional/main.cpp +++ b/tasks/makovskiy_i_min_value_in_matrix_rows/tests/functional/main.cpp @@ -1,91 +1,108 @@ #include #include +#include +#include +#include + #include "makovskiy_i_min_value_in_matrix_rows/common/include/common.hpp" #include "makovskiy_i_min_value_in_matrix_rows/mpi/include/ops_mpi.hpp" #include "makovskiy_i_min_value_in_matrix_rows/seq/include/ops_seq.hpp" -#include "util/include/func_test_util.hpp" #include "util/include/util.hpp" namespace makovskiy_i_min_value_in_matrix_rows { -// Positive -class MinValueRunFuncTests : public ppc::util::BaseRunFuncTests { - public: - static std::string PrintTestParam(const TestType &test_param) { - const auto &input = std::get<0>(test_param); - const std::size_t rows = input.size(); - const std::size_t cols = input.empty() ? 0 : input.front().size(); - return "r" + std::to_string(rows) + "x" + std::to_string(cols); - } - - protected: - InType GetTestInputData() final { - auto params = std::get(ppc::util::GTestParamIndex::kTestParams)>(GetParam()); - return std::get<0>(params); - } - - bool CheckTestOutputData(OutType &output_data) final { - if (ppc::util::IsUnderMpirun()) { - int rank; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - if (rank != 0) { - return true; +enum class TestExpectation { SUCCESS, FAIL_VALIDATION, THROW_CONSTRUCTION }; + +using UnifiedTestParam = + std::tuple(const InType &)>, std::string, InType, OutType, TestExpectation>; + +class MinValueAllTests : public ::testing::TestWithParam {}; + +TEST_P(MinValueAllTests, AllCases) { + auto task_factory = std::get<0>(GetParam()); + auto test_name = std::get<1>(GetParam()); + auto input_data = std::get<2>(GetParam()); + auto expected_output = std::get<3>(GetParam()); + auto expectation = std::get<4>(GetParam()); + + switch (expectation) { + case TestExpectation::SUCCESS: { + auto task = task_factory(input_data); + ASSERT_TRUE(task->Validation()); + ASSERT_TRUE(task->PreProcessing()); + ASSERT_TRUE(task->Run()); + ASSERT_TRUE(task->PostProcessing()); + + if (ppc::util::IsUnderMpirun()) { + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + if (rank == 0) { + ASSERT_EQ(task->GetOutput(), expected_output); + } + } else { + ASSERT_EQ(task->GetOutput(), expected_output); } + break; + } + case TestExpectation::FAIL_VALIDATION: { + auto task = task_factory(input_data); + ASSERT_FALSE(task->Validation()); + break; + } + case TestExpectation::THROW_CONSTRUCTION: { + if (!ppc::util::IsUnderMpirun()) { + ASSERT_THROW(task_factory(input_data), std::invalid_argument); + } + break; } - - auto params = std::get(ppc::util::GTestParamIndex::kTestParams)>(GetParam()); - const auto &expected = std::get<1>(params); - return output_data == expected; } -}; - -TEST_P(MinValueRunFuncTests, MinPerRow) { - ExecuteTest(GetParam()); } -namespace { - -const auto kTestCases = std::array{ - TestType{InType{{1, 2, 3}, {4, 5, 6}}, OutType{1, 4}}, - TestType{InType{{-1, 0}, {10, 2}, {7}}, OutType{-1, 2, 7}}, - TestType{InType{{5, 5, 5}}, OutType{5}}, - TestType{InType{{8}}, OutType{8}}, +auto GenerateTestName = [](const ::testing::TestParamInfo &info) { + std::string name = std::get<1>(info.param); + std::replace(name.begin(), name.end(), '/', '_'); + return name; }; -const auto kTasks = std::tuple_cat( - ppc::util::AddFuncTask(kTestCases, PPC_SETTINGS_makovskiy_i_min_value_in_matrix_rows), - ppc::util::AddFuncTask(kTestCases, PPC_SETTINGS_makovskiy_i_min_value_in_matrix_rows)); - -const auto kGtestValues = ppc::util::ExpandToValues(kTasks); -const auto kPerfTestName = MinValueRunFuncTests::PrintFuncTestName; - -INSTANTIATE_TEST_SUITE_P(MinValueTests, MinValueRunFuncTests, kGtestValues, kPerfTestName); - -} // namespace - -// Negative -TEST(MinValueValidation, RejectsEmptyMatrix) { - InType empty_input = {}; - - ASSERT_THROW(MinValueSEQ task(empty_input), std::invalid_argument); - - if (ppc::util::IsUnderMpirun()) { - auto task_mpi = std::make_shared(empty_input); - ASSERT_FALSE(task_mpi->Validation()); - } -} - -TEST(MinValueValidation, RejectsMatrixWithEmptyRow) { - InType invalid_input = {{1, 2, 3}, {}}; - - auto task_seq = std::make_shared(invalid_input); - ASSERT_FALSE(task_seq->Validation()); - - if (ppc::util::IsUnderMpirun()) { - auto task_mpi = std::make_shared(invalid_input); - ASSERT_FALSE(task_mpi->Validation()); - } -} +INSTANTIATE_TEST_SUITE_P( + MinValueTests, MinValueAllTests, + ::testing::Values( + // Positive + UnifiedTestParam{[](const InType &in) { + return std::make_shared(in); + }, "SEQ/Positive/r2x3", {{1, 2, 3}, {4, 5, 6}}, {1, 4}, TestExpectation::SUCCESS}, + UnifiedTestParam{[](const InType &in) { + return std::make_shared(in); + }, "MPI/Positive/r2x3", {{1, 2, 3}, {4, 5, 6}}, {1, 4}, TestExpectation::SUCCESS}, + UnifiedTestParam{ + [](const InType &in) { + return std::make_shared(in); + }, "SEQ/Positive/NegativeValues", {{-1, 0}, {10, 2}, {7}}, {-1, 2, 7}, TestExpectation::SUCCESS}, + UnifiedTestParam{ + [](const InType &in) { + return std::make_shared(in); + }, "MPI/Positive/NegativeValues", {{-1, 0}, {10, 2}, {7}}, {-1, 2, 7}, TestExpectation::SUCCESS}, + UnifiedTestParam{[](const InType &in) { + return std::make_shared(in); + }, "SEQ/Positive/SingleValue", {{8}}, {8}, TestExpectation::SUCCESS}, + UnifiedTestParam{[](const InType &in) { + return std::make_shared(in); + }, "MPI/Positive/SingleValue", {{8}}, {8}, TestExpectation::SUCCESS}, + + // Negative + UnifiedTestParam{[](const InType &in) { + return std::make_shared(in); + }, "SEQ/Negative/EmptyMatrix", {}, {}, TestExpectation::THROW_CONSTRUCTION}, + UnifiedTestParam{[](const InType &in) { + return std::make_shared(in); + }, "MPI/Negative/EmptyMatrix", {}, {}, TestExpectation::FAIL_VALIDATION}, + UnifiedTestParam{[](const InType &in) { + return std::make_shared(in); + }, "SEQ/Negative/EmptyRow", {{1, 2}, {}}, {}, TestExpectation::FAIL_VALIDATION}, + UnifiedTestParam{[](const InType &in) { + return std::make_shared(in); + }, "MPI/Negative/EmptyRow", {{1, 2}, {}}, {}, TestExpectation::FAIL_VALIDATION}), + GenerateTestName); } // namespace makovskiy_i_min_value_in_matrix_rows From f6a1ba604ab34bf2dd8e865b46cf5edc7fb7d0a6 Mon Sep 17 00:00:00 2001 From: Makoi66 Date: Sat, 15 Nov 2025 10:29:00 +0000 Subject: [PATCH 06/13] fix_negative_tests_2 --- .../tests/functional/main.cpp | 87 +++++++++---------- 1 file changed, 42 insertions(+), 45 deletions(-) diff --git a/tasks/makovskiy_i_min_value_in_matrix_rows/tests/functional/main.cpp b/tasks/makovskiy_i_min_value_in_matrix_rows/tests/functional/main.cpp index 841936a4b1..96583afe52 100644 --- a/tasks/makovskiy_i_min_value_in_matrix_rows/tests/functional/main.cpp +++ b/tasks/makovskiy_i_min_value_in_matrix_rows/tests/functional/main.cpp @@ -1,8 +1,10 @@ #include #include +#include #include #include +#include #include #include "makovskiy_i_min_value_in_matrix_rows/common/include/common.hpp" @@ -12,23 +14,32 @@ namespace makovskiy_i_min_value_in_matrix_rows { -enum class TestExpectation { SUCCESS, FAIL_VALIDATION, THROW_CONSTRUCTION }; +enum class TaskType { SEQ, MPI }; +enum class TestExpectation { SUCCESS, FAIL_VALIDATION }; -using UnifiedTestParam = - std::tuple(const InType &)>, std::string, InType, OutType, TestExpectation>; +using UnifiedTestParam = std::tuple; class MinValueAllTests : public ::testing::TestWithParam {}; TEST_P(MinValueAllTests, AllCases) { - auto task_factory = std::get<0>(GetParam()); - auto test_name = std::get<1>(GetParam()); + auto task_type = std::get<0>(GetParam()); auto input_data = std::get<2>(GetParam()); auto expected_output = std::get<3>(GetParam()); auto expectation = std::get<4>(GetParam()); + std::shared_ptr task; + switch (task_type) { + case TaskType::SEQ: + task = std::make_shared(input_data); + break; + case TaskType::MPI: + task = std::make_shared(input_data); + break; + } + ASSERT_NE(task, nullptr); + switch (expectation) { case TestExpectation::SUCCESS: { - auto task = task_factory(input_data); ASSERT_TRUE(task->Validation()); ASSERT_TRUE(task->PreProcessing()); ASSERT_TRUE(task->Run()); @@ -46,19 +57,20 @@ TEST_P(MinValueAllTests, AllCases) { break; } case TestExpectation::FAIL_VALIDATION: { - auto task = task_factory(input_data); ASSERT_FALSE(task->Validation()); break; } - case TestExpectation::THROW_CONSTRUCTION: { - if (!ppc::util::IsUnderMpirun()) { - ASSERT_THROW(task_factory(input_data), std::invalid_argument); - } - break; - } } } +TEST(MinValueNegativeTests, SeqThrowsOnEmptyMatrix) { + if (ppc::util::IsUnderMpirun()) { + GTEST_SKIP() << "Skipping constructor exception test under MPI"; + } + InType empty_input = {}; + ASSERT_THROW(std::make_shared(empty_input), std::invalid_argument); +} + auto GenerateTestName = [](const ::testing::TestParamInfo &info) { std::string name = std::get<1>(info.param); std::replace(name.begin(), name.end(), '/', '_'); @@ -69,40 +81,25 @@ INSTANTIATE_TEST_SUITE_P( MinValueTests, MinValueAllTests, ::testing::Values( // Positive - UnifiedTestParam{[](const InType &in) { - return std::make_shared(in); - }, "SEQ/Positive/r2x3", {{1, 2, 3}, {4, 5, 6}}, {1, 4}, TestExpectation::SUCCESS}, - UnifiedTestParam{[](const InType &in) { - return std::make_shared(in); - }, "MPI/Positive/r2x3", {{1, 2, 3}, {4, 5, 6}}, {1, 4}, TestExpectation::SUCCESS}, - UnifiedTestParam{ - [](const InType &in) { - return std::make_shared(in); - }, "SEQ/Positive/NegativeValues", {{-1, 0}, {10, 2}, {7}}, {-1, 2, 7}, TestExpectation::SUCCESS}, - UnifiedTestParam{ - [](const InType &in) { - return std::make_shared(in); - }, "MPI/Positive/NegativeValues", {{-1, 0}, {10, 2}, {7}}, {-1, 2, 7}, TestExpectation::SUCCESS}, - UnifiedTestParam{[](const InType &in) { - return std::make_shared(in); - }, "SEQ/Positive/SingleValue", {{8}}, {8}, TestExpectation::SUCCESS}, - UnifiedTestParam{[](const InType &in) { - return std::make_shared(in); - }, "MPI/Positive/SingleValue", {{8}}, {8}, TestExpectation::SUCCESS}, + UnifiedTestParam{TaskType::SEQ, "SEQ/Positive/r2x3", {{1, 2, 3}, {4, 5, 6}}, {1, 4}, TestExpectation::SUCCESS}, + UnifiedTestParam{TaskType::MPI, "MPI/Positive/r2x3", {{1, 2, 3}, {4, 5, 6}}, {1, 4}, TestExpectation::SUCCESS}, + UnifiedTestParam{TaskType::SEQ, + "SEQ/Positive/NegativeValues", + {{-1, 0}, {10, 2}, {7}}, + {-1, 2, 7}, + TestExpectation::SUCCESS}, + UnifiedTestParam{TaskType::MPI, + "MPI/Positive/NegativeValues", + {{-1, 0}, {10, 2}, {7}}, + {-1, 2, 7}, + TestExpectation::SUCCESS}, + UnifiedTestParam{TaskType::SEQ, "SEQ/Positive/SingleValue", {{8}}, {8}, TestExpectation::SUCCESS}, + UnifiedTestParam{TaskType::MPI, "MPI/Positive/SingleValue", {{8}}, {8}, TestExpectation::SUCCESS}, // Negative - UnifiedTestParam{[](const InType &in) { - return std::make_shared(in); - }, "SEQ/Negative/EmptyMatrix", {}, {}, TestExpectation::THROW_CONSTRUCTION}, - UnifiedTestParam{[](const InType &in) { - return std::make_shared(in); - }, "MPI/Negative/EmptyMatrix", {}, {}, TestExpectation::FAIL_VALIDATION}, - UnifiedTestParam{[](const InType &in) { - return std::make_shared(in); - }, "SEQ/Negative/EmptyRow", {{1, 2}, {}}, {}, TestExpectation::FAIL_VALIDATION}, - UnifiedTestParam{[](const InType &in) { - return std::make_shared(in); - }, "MPI/Negative/EmptyRow", {{1, 2}, {}}, {}, TestExpectation::FAIL_VALIDATION}), + UnifiedTestParam{TaskType::MPI, "MPI/Negative/EmptyMatrix", {}, {}, TestExpectation::FAIL_VALIDATION}, + UnifiedTestParam{TaskType::SEQ, "SEQ/Negative/EmptyRow", {{1, 2}, {}}, {}, TestExpectation::FAIL_VALIDATION}, + UnifiedTestParam{TaskType::MPI, "MPI/Negative/EmptyRow", {{1, 2}, {}}, {}, TestExpectation::FAIL_VALIDATION}), GenerateTestName); } // namespace makovskiy_i_min_value_in_matrix_rows From 94078911bbe0b4c1b1a76b8898f54c07d2af3eb2 Mon Sep 17 00:00:00 2001 From: Makoi66 Date: Sat, 15 Nov 2025 10:56:10 +0000 Subject: [PATCH 07/13] fix_negative_tests_3 --- .../tests/functional/main.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tasks/makovskiy_i_min_value_in_matrix_rows/tests/functional/main.cpp b/tasks/makovskiy_i_min_value_in_matrix_rows/tests/functional/main.cpp index 96583afe52..9c7d2e32b3 100644 --- a/tasks/makovskiy_i_min_value_in_matrix_rows/tests/functional/main.cpp +++ b/tasks/makovskiy_i_min_value_in_matrix_rows/tests/functional/main.cpp @@ -68,7 +68,7 @@ TEST(MinValueNegativeTests, SeqThrowsOnEmptyMatrix) { GTEST_SKIP() << "Skipping constructor exception test under MPI"; } InType empty_input = {}; - ASSERT_THROW(std::make_shared(empty_input), std::invalid_argument); + ASSERT_THROW((void)std::make_shared(empty_input), std::invalid_argument); } auto GenerateTestName = [](const ::testing::TestParamInfo &info) { From c4ae11ed36ded80779a47a6aad7c534028a2dfc5 Mon Sep 17 00:00:00 2001 From: Makoi66 Date: Sat, 15 Nov 2025 11:39:55 +0000 Subject: [PATCH 08/13] fix_tests_hope_final --- .../common/include/common.hpp | 16 -- .../tests/functional/main.cpp | 145 ++++++++---------- 2 files changed, 68 insertions(+), 93 deletions(-) diff --git a/tasks/makovskiy_i_min_value_in_matrix_rows/common/include/common.hpp b/tasks/makovskiy_i_min_value_in_matrix_rows/common/include/common.hpp index cd73bf0a86..ea93b0fb99 100644 --- a/tasks/makovskiy_i_min_value_in_matrix_rows/common/include/common.hpp +++ b/tasks/makovskiy_i_min_value_in_matrix_rows/common/include/common.hpp @@ -14,19 +14,3 @@ using TestType = std::tuple; using BaseTask = ppc::task::Task; } // namespace makovskiy_i_min_value_in_matrix_rows -#pragma once - -#include -#include -#include - -#include "task/include/task.hpp" - -namespace makovskiy_i_min_value_in_matrix_rows { - -using InType = std::vector>; -using OutType = std::vector; -using TestType = std::tuple; -using BaseTask = ppc::task::Task; - -} // namespace makovskiy_i_min_value_in_matrix_rows diff --git a/tasks/makovskiy_i_min_value_in_matrix_rows/tests/functional/main.cpp b/tasks/makovskiy_i_min_value_in_matrix_rows/tests/functional/main.cpp index 9c7d2e32b3..7f34dcc060 100644 --- a/tasks/makovskiy_i_min_value_in_matrix_rows/tests/functional/main.cpp +++ b/tasks/makovskiy_i_min_value_in_matrix_rows/tests/functional/main.cpp @@ -1,105 +1,96 @@ #include #include -#include -#include +#include #include #include +#include #include #include "makovskiy_i_min_value_in_matrix_rows/common/include/common.hpp" #include "makovskiy_i_min_value_in_matrix_rows/mpi/include/ops_mpi.hpp" #include "makovskiy_i_min_value_in_matrix_rows/seq/include/ops_seq.hpp" +#include "util/include/func_test_util.hpp" #include "util/include/util.hpp" namespace makovskiy_i_min_value_in_matrix_rows { -enum class TaskType { SEQ, MPI }; -enum class TestExpectation { SUCCESS, FAIL_VALIDATION }; - -using UnifiedTestParam = std::tuple; - -class MinValueAllTests : public ::testing::TestWithParam {}; - -TEST_P(MinValueAllTests, AllCases) { - auto task_type = std::get<0>(GetParam()); - auto input_data = std::get<2>(GetParam()); - auto expected_output = std::get<3>(GetParam()); - auto expectation = std::get<4>(GetParam()); +// Positive +class MinValueRunFuncTests : public ppc::util::BaseRunFuncTests { + public: + static std::string PrintTestParam(const TestType &test_param) { + const auto &input = std::get<0>(test_param); + const std::size_t rows = input.size(); + const std::size_t cols = input.empty() ? 0 : input.front().size(); + return "r" + std::to_string(rows) + "x" + std::to_string(cols); + } - std::shared_ptr task; - switch (task_type) { - case TaskType::SEQ: - task = std::make_shared(input_data); - break; - case TaskType::MPI: - task = std::make_shared(input_data); - break; + protected: + InType GetTestInputData() final { + auto params = std::get(ppc::util::GTestParamIndex::kTestParams)>(GetParam()); + return std::get<0>(params); } - ASSERT_NE(task, nullptr); - - switch (expectation) { - case TestExpectation::SUCCESS: { - ASSERT_TRUE(task->Validation()); - ASSERT_TRUE(task->PreProcessing()); - ASSERT_TRUE(task->Run()); - ASSERT_TRUE(task->PostProcessing()); - - if (ppc::util::IsUnderMpirun()) { - int rank; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - if (rank == 0) { - ASSERT_EQ(task->GetOutput(), expected_output); - } - } else { - ASSERT_EQ(task->GetOutput(), expected_output); + + bool CheckTestOutputData(OutType &output_data) final { + if (ppc::util::IsUnderMpirun()) { + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + if (rank != 0) { + return true; } - break; - } - case TestExpectation::FAIL_VALIDATION: { - ASSERT_FALSE(task->Validation()); - break; } + auto params = std::get(ppc::util::GTestParamIndex::kTestParams)>(GetParam()); + const auto &expected = std::get<1>(params); + return output_data == expected; } +}; + +TEST_P(MinValueRunFuncTests, MinPerRow) { + ExecuteTest(GetParam()); } -TEST(MinValueNegativeTests, SeqThrowsOnEmptyMatrix) { +namespace { + +const auto kTestCases = std::array{ + TestType{InType{{1, 2, 3}, {4, 5, 6}}, OutType{1, 4}}, + TestType{InType{{-1, 0}, {10, 2}, {7}}, OutType{-1, 2, 7}}, + TestType{InType{{5, 5, 5}}, OutType{5}}, + TestType{InType{{8}}, OutType{8}}, +}; + +const auto kTasks = std::tuple_cat( + ppc::util::AddFuncTask(kTestCases, PPC_SETTINGS_makovskiy_i_min_value_in_matrix_rows), + ppc::util::AddFuncTask(kTestCases, PPC_SETTINGS_makovskiy_i_min_value_in_matrix_rows)); + +const auto kGtestValues = ppc::util::ExpandToValues(kTasks); +const auto kPerfTestName = MinValueRunFuncTests::PrintFuncTestName; + +INSTANTIATE_TEST_SUITE_P(MinValuePositiveTests, MinValueRunFuncTests, kGtestValues, kPerfTestName); + +} // namespace + +// Negative +TEST(MinValueNegativeTests, RejectsEmptyMatrix) { + InType empty_input = {}; + + ASSERT_THROW(MinValueSEQ task(empty_input), std::invalid_argument); + if (ppc::util::IsUnderMpirun()) { - GTEST_SKIP() << "Skipping constructor exception test under MPI"; + auto task_mpi = std::make_shared(empty_input); + ASSERT_FALSE(task_mpi->Validation()); } - InType empty_input = {}; - ASSERT_THROW((void)std::make_shared(empty_input), std::invalid_argument); } -auto GenerateTestName = [](const ::testing::TestParamInfo &info) { - std::string name = std::get<1>(info.param); - std::replace(name.begin(), name.end(), '/', '_'); - return name; -}; +TEST(MinValueNegativeTests, RejectsMatrixWithEmptyRow) { + InType invalid_input = {{1, 2, 3}, {}}; + + auto task_seq = std::make_shared(invalid_input); + ASSERT_FALSE(task_seq->Validation()); -INSTANTIATE_TEST_SUITE_P( - MinValueTests, MinValueAllTests, - ::testing::Values( - // Positive - UnifiedTestParam{TaskType::SEQ, "SEQ/Positive/r2x3", {{1, 2, 3}, {4, 5, 6}}, {1, 4}, TestExpectation::SUCCESS}, - UnifiedTestParam{TaskType::MPI, "MPI/Positive/r2x3", {{1, 2, 3}, {4, 5, 6}}, {1, 4}, TestExpectation::SUCCESS}, - UnifiedTestParam{TaskType::SEQ, - "SEQ/Positive/NegativeValues", - {{-1, 0}, {10, 2}, {7}}, - {-1, 2, 7}, - TestExpectation::SUCCESS}, - UnifiedTestParam{TaskType::MPI, - "MPI/Positive/NegativeValues", - {{-1, 0}, {10, 2}, {7}}, - {-1, 2, 7}, - TestExpectation::SUCCESS}, - UnifiedTestParam{TaskType::SEQ, "SEQ/Positive/SingleValue", {{8}}, {8}, TestExpectation::SUCCESS}, - UnifiedTestParam{TaskType::MPI, "MPI/Positive/SingleValue", {{8}}, {8}, TestExpectation::SUCCESS}, - - // Negative - UnifiedTestParam{TaskType::MPI, "MPI/Negative/EmptyMatrix", {}, {}, TestExpectation::FAIL_VALIDATION}, - UnifiedTestParam{TaskType::SEQ, "SEQ/Negative/EmptyRow", {{1, 2}, {}}, {}, TestExpectation::FAIL_VALIDATION}, - UnifiedTestParam{TaskType::MPI, "MPI/Negative/EmptyRow", {{1, 2}, {}}, {}, TestExpectation::FAIL_VALIDATION}), - GenerateTestName); + if (ppc::util::IsUnderMpirun()) { + auto task_mpi = std::make_shared(invalid_input); + ASSERT_FALSE(task_mpi->Validation()); + } +} } // namespace makovskiy_i_min_value_in_matrix_rows From c5573f1e9e65d80965022297ce02fe307fc9960b Mon Sep 17 00:00:00 2001 From: Makoi66 Date: Sat, 15 Nov 2025 12:21:53 +0000 Subject: [PATCH 09/13] fix_tests5 --- .../common/include/common.hpp | 2 +- .../tests/functional/main.cpp | 104 +++++++++--------- 2 files changed, 53 insertions(+), 53 deletions(-) diff --git a/tasks/makovskiy_i_min_value_in_matrix_rows/common/include/common.hpp b/tasks/makovskiy_i_min_value_in_matrix_rows/common/include/common.hpp index ea93b0fb99..733b6d59d1 100644 --- a/tasks/makovskiy_i_min_value_in_matrix_rows/common/include/common.hpp +++ b/tasks/makovskiy_i_min_value_in_matrix_rows/common/include/common.hpp @@ -10,7 +10,7 @@ namespace makovskiy_i_min_value_in_matrix_rows { using InType = std::vector>; using OutType = std::vector; -using TestType = std::tuple; +using TestType = std::tuple; using BaseTask = ppc::task::Task; } // namespace makovskiy_i_min_value_in_matrix_rows diff --git a/tasks/makovskiy_i_min_value_in_matrix_rows/tests/functional/main.cpp b/tasks/makovskiy_i_min_value_in_matrix_rows/tests/functional/main.cpp index 7f34dcc060..a4743fdab9 100644 --- a/tasks/makovskiy_i_min_value_in_matrix_rows/tests/functional/main.cpp +++ b/tasks/makovskiy_i_min_value_in_matrix_rows/tests/functional/main.cpp @@ -15,82 +15,82 @@ namespace makovskiy_i_min_value_in_matrix_rows { -// Positive -class MinValueRunFuncTests : public ppc::util::BaseRunFuncTests { +class MinValueFuncTests : public ppc::util::BaseRunFuncTests { public: static std::string PrintTestParam(const TestType &test_param) { - const auto &input = std::get<0>(test_param); - const std::size_t rows = input.size(); - const std::size_t cols = input.empty() ? 0 : input.front().size(); - return "r" + std::to_string(rows) + "x" + std::to_string(cols); + return std::get<2>(test_param); } protected: + InType input_data_{}; + OutType expected_output_{}; + + void SetUp() override { + TestType params = std::get(ppc::util::GTestParamIndex::kTestParams)>(GetParam()); + input_data_ = std::get<0>(params); + expected_output_ = std::get<1>(params); + } + InType GetTestInputData() final { - auto params = std::get(ppc::util::GTestParamIndex::kTestParams)>(GetParam()); - return std::get<0>(params); + return input_data_; } bool CheckTestOutputData(OutType &output_data) final { + int rank = 0; if (ppc::util::IsUnderMpirun()) { - int rank; MPI_Comm_rank(MPI_COMM_WORLD, &rank); - if (rank != 0) { - return true; - } } - auto params = std::get(ppc::util::GTestParamIndex::kTestParams)>(GetParam()); - const auto &expected = std::get<1>(params); - return output_data == expected; + if (rank == 0) { + return output_data == expected_output_; + } + return true; } }; -TEST_P(MinValueRunFuncTests, MinPerRow) { - ExecuteTest(GetParam()); -} - namespace { -const auto kTestCases = std::array{ - TestType{InType{{1, 2, 3}, {4, 5, 6}}, OutType{1, 4}}, - TestType{InType{{-1, 0}, {10, 2}, {7}}, OutType{-1, 2, 7}}, - TestType{InType{{5, 5, 5}}, OutType{5}}, - TestType{InType{{8}}, OutType{8}}, -}; +TEST_P(MinValueFuncTests, MinValueTestAllCases) { + auto task_getter = std::get(ppc::util::GTestParamIndex::kTaskGetter)>(GetParam()); + const auto &test_params = std::get(ppc::util::GTestParamIndex::kTestParams)>(GetParam()); + const auto &input_data = std::get<0>(test_params); + const auto &test_name = std::get<2>(test_params); + + bool expect_validation_fail = (test_name.find("Invalid") != std::string::npos); + + if (expect_validation_fail) { + if (test_name == "Invalid_Empty_Matrix" && !ppc::util::IsUnderMpirun()) { + ASSERT_THROW(task_getter(input_data), std::invalid_argument); + } else { + auto task = task_getter(input_data); + ASSERT_FALSE(task->Validation()); + } + } else { + auto task = task_getter(input_data); + ASSERT_TRUE(task->Validation()); + ASSERT_TRUE(task->PreProcessing()); + ASSERT_TRUE(task->Run()); + ASSERT_TRUE(task->PostProcessing()); + ASSERT_TRUE(CheckTestOutputData(task->GetOutput())); + } +} + +const std::array kTestCases = { + // Positive + std::make_tuple(InType{{1, 2, 3}, {4, 5, 6}}, OutType{1, 4}, "Small_Matrix_2x3"), + std::make_tuple(InType{{-1, 0}, {10, 2}, {7}}, OutType{-1, 2, 7}, "Matrix_With_Negative_3x2"), + std::make_tuple(InType{{8}}, OutType{8}, "Single_Element_Matrix_1x1"), + // Negative + std::make_tuple(InType{}, OutType{}, "Invalid_Empty_Matrix"), + std::make_tuple(InType{{1, 2}, {}}, OutType{}, "Invalid_Empty_Row")}; const auto kTasks = std::tuple_cat( ppc::util::AddFuncTask(kTestCases, PPC_SETTINGS_makovskiy_i_min_value_in_matrix_rows), ppc::util::AddFuncTask(kTestCases, PPC_SETTINGS_makovskiy_i_min_value_in_matrix_rows)); const auto kGtestValues = ppc::util::ExpandToValues(kTasks); -const auto kPerfTestName = MinValueRunFuncTests::PrintFuncTestName; +const auto kTestName = MinValueFuncTests::PrintFuncTestName; -INSTANTIATE_TEST_SUITE_P(MinValuePositiveTests, MinValueRunFuncTests, kGtestValues, kPerfTestName); +INSTANTIATE_TEST_SUITE_P(MinValueAllTests, MinValueFuncTests, kGtestValues, kTestName); } // namespace - -// Negative -TEST(MinValueNegativeTests, RejectsEmptyMatrix) { - InType empty_input = {}; - - ASSERT_THROW(MinValueSEQ task(empty_input), std::invalid_argument); - - if (ppc::util::IsUnderMpirun()) { - auto task_mpi = std::make_shared(empty_input); - ASSERT_FALSE(task_mpi->Validation()); - } -} - -TEST(MinValueNegativeTests, RejectsMatrixWithEmptyRow) { - InType invalid_input = {{1, 2, 3}, {}}; - - auto task_seq = std::make_shared(invalid_input); - ASSERT_FALSE(task_seq->Validation()); - - if (ppc::util::IsUnderMpirun()) { - auto task_mpi = std::make_shared(invalid_input); - ASSERT_FALSE(task_mpi->Validation()); - } -} - } // namespace makovskiy_i_min_value_in_matrix_rows From 4b0f50dc269eb00cdfed87e467633e3b6b416f87 Mon Sep 17 00:00:00 2001 From: Makoi66 Date: Sat, 15 Nov 2025 12:49:03 +0000 Subject: [PATCH 10/13] fix_tests_6 --- .../tests/functional/main.cpp | 152 +++++++++--------- 1 file changed, 80 insertions(+), 72 deletions(-) diff --git a/tasks/makovskiy_i_min_value_in_matrix_rows/tests/functional/main.cpp b/tasks/makovskiy_i_min_value_in_matrix_rows/tests/functional/main.cpp index a4743fdab9..ff0726ee3a 100644 --- a/tasks/makovskiy_i_min_value_in_matrix_rows/tests/functional/main.cpp +++ b/tasks/makovskiy_i_min_value_in_matrix_rows/tests/functional/main.cpp @@ -1,96 +1,104 @@ #include #include -#include +#include #include #include -#include #include #include "makovskiy_i_min_value_in_matrix_rows/common/include/common.hpp" #include "makovskiy_i_min_value_in_matrix_rows/mpi/include/ops_mpi.hpp" #include "makovskiy_i_min_value_in_matrix_rows/seq/include/ops_seq.hpp" -#include "util/include/func_test_util.hpp" #include "util/include/util.hpp" namespace makovskiy_i_min_value_in_matrix_rows { -class MinValueFuncTests : public ppc::util::BaseRunFuncTests { - public: - static std::string PrintTestParam(const TestType &test_param) { - return std::get<2>(test_param); - } - - protected: - InType input_data_{}; - OutType expected_output_{}; - - void SetUp() override { - TestType params = std::get(ppc::util::GTestParamIndex::kTestParams)>(GetParam()); - input_data_ = std::get<0>(params); - expected_output_ = std::get<1>(params); - } - - InType GetTestInputData() final { - return input_data_; - } - - bool CheckTestOutputData(OutType &output_data) final { - int rank = 0; - if (ppc::util::IsUnderMpirun()) { - MPI_Comm_rank(MPI_COMM_WORLD, &rank); +enum class TaskType { SEQ, MPI }; +enum class TestExpectation { SUCCESS, FAIL_VALIDATION, THROW_CONSTRUCTION }; + +using TestParam = std::tuple; + +class MinValueFunctionalTests : public ::testing::TestWithParam {}; + +TEST_P(MinValueFunctionalTests, AllCases) { + const auto &[task_type, test_name, input_data, expected_output, expectation] = GetParam(); + + switch (expectation) { + case TestExpectation::SUCCESS: { + std::shared_ptr task; + if (task_type == TaskType::SEQ) { + task = std::make_shared(input_data); + } else { + task = std::make_shared(input_data); + } + + ASSERT_TRUE(task->Validation()); + ASSERT_TRUE(task->PreProcessing()); + ASSERT_TRUE(task->Run()); + ASSERT_TRUE(task->PostProcessing()); + + if (ppc::util::IsUnderMpirun()) { + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + if (rank == 0) { + ASSERT_EQ(task->GetOutput(), expected_output); + } + } else { + ASSERT_EQ(task->GetOutput(), expected_output); + } + break; } - if (rank == 0) { - return output_data == expected_output_; - } - return true; - } -}; - -namespace { - -TEST_P(MinValueFuncTests, MinValueTestAllCases) { - auto task_getter = std::get(ppc::util::GTestParamIndex::kTaskGetter)>(GetParam()); - const auto &test_params = std::get(ppc::util::GTestParamIndex::kTestParams)>(GetParam()); - const auto &input_data = std::get<0>(test_params); - const auto &test_name = std::get<2>(test_params); - - bool expect_validation_fail = (test_name.find("Invalid") != std::string::npos); + case TestExpectation::FAIL_VALIDATION: { + std::shared_ptr task; + if (task_type == TaskType::SEQ) { + task = std::make_shared(input_data); + } else { + task = std::make_shared(input_data); + } - if (expect_validation_fail) { - if (test_name == "Invalid_Empty_Matrix" && !ppc::util::IsUnderMpirun()) { - ASSERT_THROW(task_getter(input_data), std::invalid_argument); - } else { - auto task = task_getter(input_data); ASSERT_FALSE(task->Validation()); + task->PreProcessing(); + task->Run(); + task->PostProcessing(); + break; + } + case TestExpectation::THROW_CONSTRUCTION: { + if (task_type == TaskType::SEQ && !ppc::util::IsUnderMpirun()) { + ASSERT_THROW((MinValueSEQ(input_data)), std::invalid_argument); + } + break; } - } else { - auto task = task_getter(input_data); - ASSERT_TRUE(task->Validation()); - ASSERT_TRUE(task->PreProcessing()); - ASSERT_TRUE(task->Run()); - ASSERT_TRUE(task->PostProcessing()); - ASSERT_TRUE(CheckTestOutputData(task->GetOutput())); } } -const std::array kTestCases = { - // Positive - std::make_tuple(InType{{1, 2, 3}, {4, 5, 6}}, OutType{1, 4}, "Small_Matrix_2x3"), - std::make_tuple(InType{{-1, 0}, {10, 2}, {7}}, OutType{-1, 2, 7}, "Matrix_With_Negative_3x2"), - std::make_tuple(InType{{8}}, OutType{8}, "Single_Element_Matrix_1x1"), - // Negative - std::make_tuple(InType{}, OutType{}, "Invalid_Empty_Matrix"), - std::make_tuple(InType{{1, 2}, {}}, OutType{}, "Invalid_Empty_Row")}; - -const auto kTasks = std::tuple_cat( - ppc::util::AddFuncTask(kTestCases, PPC_SETTINGS_makovskiy_i_min_value_in_matrix_rows), - ppc::util::AddFuncTask(kTestCases, PPC_SETTINGS_makovskiy_i_min_value_in_matrix_rows)); - -const auto kGtestValues = ppc::util::ExpandToValues(kTasks); -const auto kTestName = MinValueFuncTests::PrintFuncTestName; +auto GenerateTestName = [](const ::testing::TestParamInfo &info) { + std::string name = std::get<1>(info.param); + TaskType type = std::get<0>(info.param); + std::string type_str = (type == TaskType::SEQ) ? "SEQ_" : "MPI_"; + std::replace(name.begin(), name.end(), '/', '_'); + return type_str + name; +}; -INSTANTIATE_TEST_SUITE_P(MinValueAllTests, MinValueFuncTests, kGtestValues, kTestName); +INSTANTIATE_TEST_SUITE_P( + MinValueTests, MinValueFunctionalTests, + ::testing::Values( + // Positive + TestParam{TaskType::SEQ, "Positive_2x3", {{1, 2, 3}, {4, 5, 6}}, {1, 4}, TestExpectation::SUCCESS}, + TestParam{TaskType::MPI, "Positive_2x3", {{1, 2, 3}, {4, 5, 6}}, {1, 4}, TestExpectation::SUCCESS}, + TestParam{ + TaskType::SEQ, "Positive_NegativeVals", {{-1, 0}, {10, 2}, {7}}, {-1, 2, 7}, TestExpectation::SUCCESS}, + TestParam{ + TaskType::MPI, "Positive_NegativeVals", {{-1, 0}, {10, 2}, {7}}, {-1, 2, 7}, TestExpectation::SUCCESS}, + TestParam{TaskType::SEQ, "Positive_Single", {{8}}, {8}, TestExpectation::SUCCESS}, + TestParam{TaskType::MPI, "Positive_Single", {{8}}, {8}, TestExpectation::SUCCESS}, + + // Negative: THROW_CONSTRUCTION + TestParam{TaskType::SEQ, "Invalid_EmptyMatrix", {}, {}, TestExpectation::THROW_CONSTRUCTION}, + + // Negative: FAIL_VALIDATION + TestParam{TaskType::MPI, "Invalid_EmptyMatrix", {}, {}, TestExpectation::FAIL_VALIDATION}, + TestParam{TaskType::SEQ, "Invalid_EmptyRow", {{1, 2}, {}}, {}, TestExpectation::FAIL_VALIDATION}, + TestParam{TaskType::MPI, "Invalid_EmptyRow", {{1, 2}, {}}, {}, TestExpectation::FAIL_VALIDATION}), + GenerateTestName); -} // namespace } // namespace makovskiy_i_min_value_in_matrix_rows From ddc76c31b94a9e228902777dd416823084a77826 Mon Sep 17 00:00:00 2001 From: Makoi66 Date: Sat, 15 Nov 2025 15:04:10 +0000 Subject: [PATCH 11/13] fix_tests_7 --- .../tests/functional/main.cpp | 98 ++++++++++--------- 1 file changed, 50 insertions(+), 48 deletions(-) diff --git a/tasks/makovskiy_i_min_value_in_matrix_rows/tests/functional/main.cpp b/tasks/makovskiy_i_min_value_in_matrix_rows/tests/functional/main.cpp index ff0726ee3a..2f2baa262c 100644 --- a/tasks/makovskiy_i_min_value_in_matrix_rows/tests/functional/main.cpp +++ b/tasks/makovskiy_i_min_value_in_matrix_rows/tests/functional/main.cpp @@ -1,9 +1,8 @@ #include #include -#include +#include #include -#include #include #include "makovskiy_i_min_value_in_matrix_rows/common/include/common.hpp" @@ -13,25 +12,23 @@ namespace makovskiy_i_min_value_in_matrix_rows { -enum class TaskType { SEQ, MPI }; enum class TestExpectation { SUCCESS, FAIL_VALIDATION, THROW_CONSTRUCTION }; -using TestParam = std::tuple; +using UnifiedTestParam = + std::tuple(const InType &)>, std::string, InType, OutType, TestExpectation>; -class MinValueFunctionalTests : public ::testing::TestWithParam {}; +class MinValueAllTests : public ::testing::TestWithParam {}; -TEST_P(MinValueFunctionalTests, AllCases) { - const auto &[task_type, test_name, input_data, expected_output, expectation] = GetParam(); +TEST_P(MinValueAllTests, AllCases) { + auto task_factory = std::get<0>(GetParam()); + auto test_name = std::get<1>(GetParam()); + auto input_data = std::get<2>(GetParam()); + auto expected_output = std::get<3>(GetParam()); + auto expectation = std::get<4>(GetParam()); switch (expectation) { case TestExpectation::SUCCESS: { - std::shared_ptr task; - if (task_type == TaskType::SEQ) { - task = std::make_shared(input_data); - } else { - task = std::make_shared(input_data); - } - + auto task = task_factory(input_data); ASSERT_TRUE(task->Validation()); ASSERT_TRUE(task->PreProcessing()); ASSERT_TRUE(task->Run()); @@ -49,56 +46,61 @@ TEST_P(MinValueFunctionalTests, AllCases) { break; } case TestExpectation::FAIL_VALIDATION: { - std::shared_ptr task; - if (task_type == TaskType::SEQ) { - task = std::make_shared(input_data); - } else { - task = std::make_shared(input_data); - } - + auto task = task_factory(input_data); ASSERT_FALSE(task->Validation()); - task->PreProcessing(); - task->Run(); - task->PostProcessing(); break; } case TestExpectation::THROW_CONSTRUCTION: { - if (task_type == TaskType::SEQ && !ppc::util::IsUnderMpirun()) { - ASSERT_THROW((MinValueSEQ(input_data)), std::invalid_argument); + if (!ppc::util::IsUnderMpirun()) { + ASSERT_THROW(task_factory(input_data), std::invalid_argument); } break; } } } -auto GenerateTestName = [](const ::testing::TestParamInfo &info) { +auto GenerateTestName = [](const ::testing::TestParamInfo &info) { std::string name = std::get<1>(info.param); - TaskType type = std::get<0>(info.param); - std::string type_str = (type == TaskType::SEQ) ? "SEQ_" : "MPI_"; std::replace(name.begin(), name.end(), '/', '_'); - return type_str + name; + return name; }; INSTANTIATE_TEST_SUITE_P( - MinValueTests, MinValueFunctionalTests, + MinValueTests, MinValueAllTests, ::testing::Values( - // Positive - TestParam{TaskType::SEQ, "Positive_2x3", {{1, 2, 3}, {4, 5, 6}}, {1, 4}, TestExpectation::SUCCESS}, - TestParam{TaskType::MPI, "Positive_2x3", {{1, 2, 3}, {4, 5, 6}}, {1, 4}, TestExpectation::SUCCESS}, - TestParam{ - TaskType::SEQ, "Positive_NegativeVals", {{-1, 0}, {10, 2}, {7}}, {-1, 2, 7}, TestExpectation::SUCCESS}, - TestParam{ - TaskType::MPI, "Positive_NegativeVals", {{-1, 0}, {10, 2}, {7}}, {-1, 2, 7}, TestExpectation::SUCCESS}, - TestParam{TaskType::SEQ, "Positive_Single", {{8}}, {8}, TestExpectation::SUCCESS}, - TestParam{TaskType::MPI, "Positive_Single", {{8}}, {8}, TestExpectation::SUCCESS}, - - // Negative: THROW_CONSTRUCTION - TestParam{TaskType::SEQ, "Invalid_EmptyMatrix", {}, {}, TestExpectation::THROW_CONSTRUCTION}, - - // Negative: FAIL_VALIDATION - TestParam{TaskType::MPI, "Invalid_EmptyMatrix", {}, {}, TestExpectation::FAIL_VALIDATION}, - TestParam{TaskType::SEQ, "Invalid_EmptyRow", {{1, 2}, {}}, {}, TestExpectation::FAIL_VALIDATION}, - TestParam{TaskType::MPI, "Invalid_EmptyRow", {{1, 2}, {}}, {}, TestExpectation::FAIL_VALIDATION}), + UnifiedTestParam{[](const InType &in) { + return std::make_shared(in); + }, "SEQ/Positive/r2x3", {{1, 2, 3}, {4, 5, 6}}, {1, 4}, TestExpectation::SUCCESS}, + UnifiedTestParam{[](const InType &in) { + return std::make_shared(in); + }, "MPI/Positive/r2x3", {{1, 2, 3}, {4, 5, 6}}, {1, 4}, TestExpectation::SUCCESS}, + UnifiedTestParam{ + [](const InType &in) { + return std::make_shared(in); + }, "SEQ/Positive/NegativeValues", {{-1, 0}, {10, 2}, {7}}, {-1, 2, 7}, TestExpectation::SUCCESS}, + UnifiedTestParam{ + [](const InType &in) { + return std::make_shared(in); + }, "MPI/Positive/NegativeValues", {{-1, 0}, {10, 2}, {7}}, {-1, 2, 7}, TestExpectation::SUCCESS}, + UnifiedTestParam{[](const InType &in) { + return std::make_shared(in); + }, "SEQ/Positive/SingleValue", {{8}}, {8}, TestExpectation::SUCCESS}, + UnifiedTestParam{[](const InType &in) { + return std::make_shared(in); + }, "MPI/Positive/SingleValue", {{8}}, {8}, TestExpectation::SUCCESS}, + + UnifiedTestParam{[](const InType &in) { + return std::make_shared(in); + }, "SEQ/Negative/EmptyMatrix", {}, {}, TestExpectation::THROW_CONSTRUCTION}, + UnifiedTestParam{[](const InType &in) { + return std::make_shared(in); + }, "MPI/Negative/EmptyMatrix", {}, {}, TestExpectation::FAIL_VALIDATION}, + UnifiedTestParam{[](const InType &in) { + return std::make_shared(in); + }, "SEQ/Negative/EmptyRow", {{1, 2}, {}}, {}, TestExpectation::FAIL_VALIDATION}, + UnifiedTestParam{[](const InType &in) { + return std::make_shared(in); + }, "MPI/Negative/EmptyRow", {{1, 2}, {}}, {}, TestExpectation::FAIL_VALIDATION}), GenerateTestName); } // namespace makovskiy_i_min_value_in_matrix_rows From 7355b8000d05c99948d723042cfc7a9e731dab5d Mon Sep 17 00:00:00 2001 From: Makoi66 Date: Sat, 15 Nov 2025 18:40:14 +0000 Subject: [PATCH 12/13] fix_tests_7 --- .../mpi/src/ops_mpi.cpp | 5 ----- .../seq/src/ops_seq.cpp | 3 --- .../tests/functional/main.cpp | 10 ++-------- 3 files changed, 2 insertions(+), 16 deletions(-) diff --git a/tasks/makovskiy_i_min_value_in_matrix_rows/mpi/src/ops_mpi.cpp b/tasks/makovskiy_i_min_value_in_matrix_rows/mpi/src/ops_mpi.cpp index 1c06074057..34b520cfba 100644 --- a/tasks/makovskiy_i_min_value_in_matrix_rows/mpi/src/ops_mpi.cpp +++ b/tasks/makovskiy_i_min_value_in_matrix_rows/mpi/src/ops_mpi.cpp @@ -9,11 +9,6 @@ namespace makovskiy_i_min_value_in_matrix_rows { MinValueMPI::MinValueMPI(const InType &in) { - int rank = 0; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - if (rank == 0 && in.empty()) { - throw std::invalid_argument("Input matrix is empty"); - } this->GetInput() = in; SetTypeOfTask(GetStaticTypeOfTask()); } diff --git a/tasks/makovskiy_i_min_value_in_matrix_rows/seq/src/ops_seq.cpp b/tasks/makovskiy_i_min_value_in_matrix_rows/seq/src/ops_seq.cpp index 133399ed02..9c99960418 100644 --- a/tasks/makovskiy_i_min_value_in_matrix_rows/seq/src/ops_seq.cpp +++ b/tasks/makovskiy_i_min_value_in_matrix_rows/seq/src/ops_seq.cpp @@ -5,9 +5,6 @@ namespace makovskiy_i_min_value_in_matrix_rows { MinValueSEQ::MinValueSEQ(const InType &in) { - if (in.empty()) { - throw std::invalid_argument("Input matrix is empty"); - } this->GetInput() = in; SetTypeOfTask(GetStaticTypeOfTask()); } diff --git a/tasks/makovskiy_i_min_value_in_matrix_rows/tests/functional/main.cpp b/tasks/makovskiy_i_min_value_in_matrix_rows/tests/functional/main.cpp index 2f2baa262c..3043283f42 100644 --- a/tasks/makovskiy_i_min_value_in_matrix_rows/tests/functional/main.cpp +++ b/tasks/makovskiy_i_min_value_in_matrix_rows/tests/functional/main.cpp @@ -12,7 +12,7 @@ namespace makovskiy_i_min_value_in_matrix_rows { -enum class TestExpectation { SUCCESS, FAIL_VALIDATION, THROW_CONSTRUCTION }; +enum class TestExpectation { SUCCESS, FAIL_VALIDATION }; using UnifiedTestParam = std::tuple(const InType &)>, std::string, InType, OutType, TestExpectation>; @@ -50,12 +50,6 @@ TEST_P(MinValueAllTests, AllCases) { ASSERT_FALSE(task->Validation()); break; } - case TestExpectation::THROW_CONSTRUCTION: { - if (!ppc::util::IsUnderMpirun()) { - ASSERT_THROW(task_factory(input_data), std::invalid_argument); - } - break; - } } } @@ -91,7 +85,7 @@ INSTANTIATE_TEST_SUITE_P( UnifiedTestParam{[](const InType &in) { return std::make_shared(in); - }, "SEQ/Negative/EmptyMatrix", {}, {}, TestExpectation::THROW_CONSTRUCTION}, + }, "SEQ/Negative/EmptyMatrix", {}, {}, TestExpectation::FAIL_VALIDATION}, UnifiedTestParam{[](const InType &in) { return std::make_shared(in); }, "MPI/Negative/EmptyMatrix", {}, {}, TestExpectation::FAIL_VALIDATION}, From cdb94938dae8e4fb770696305d9e2ee3e916da49 Mon Sep 17 00:00:00 2001 From: Makoi66 Date: Sat, 15 Nov 2025 20:05:22 +0000 Subject: [PATCH 13/13] back_to_ver_1.2 --- .../common/include/common.hpp | 18 ++- .../mpi/src/ops_mpi.cpp | 5 + .../seq/src/ops_seq.cpp | 3 + .../tests/functional/main.cpp | 122 +++++++----------- 4 files changed, 69 insertions(+), 79 deletions(-) diff --git a/tasks/makovskiy_i_min_value_in_matrix_rows/common/include/common.hpp b/tasks/makovskiy_i_min_value_in_matrix_rows/common/include/common.hpp index 733b6d59d1..cd73bf0a86 100644 --- a/tasks/makovskiy_i_min_value_in_matrix_rows/common/include/common.hpp +++ b/tasks/makovskiy_i_min_value_in_matrix_rows/common/include/common.hpp @@ -10,7 +10,23 @@ namespace makovskiy_i_min_value_in_matrix_rows { using InType = std::vector>; using OutType = std::vector; -using TestType = std::tuple; +using TestType = std::tuple; +using BaseTask = ppc::task::Task; + +} // namespace makovskiy_i_min_value_in_matrix_rows +#pragma once + +#include +#include +#include + +#include "task/include/task.hpp" + +namespace makovskiy_i_min_value_in_matrix_rows { + +using InType = std::vector>; +using OutType = std::vector; +using TestType = std::tuple; using BaseTask = ppc::task::Task; } // namespace makovskiy_i_min_value_in_matrix_rows diff --git a/tasks/makovskiy_i_min_value_in_matrix_rows/mpi/src/ops_mpi.cpp b/tasks/makovskiy_i_min_value_in_matrix_rows/mpi/src/ops_mpi.cpp index 34b520cfba..1c06074057 100644 --- a/tasks/makovskiy_i_min_value_in_matrix_rows/mpi/src/ops_mpi.cpp +++ b/tasks/makovskiy_i_min_value_in_matrix_rows/mpi/src/ops_mpi.cpp @@ -9,6 +9,11 @@ namespace makovskiy_i_min_value_in_matrix_rows { MinValueMPI::MinValueMPI(const InType &in) { + int rank = 0; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + if (rank == 0 && in.empty()) { + throw std::invalid_argument("Input matrix is empty"); + } this->GetInput() = in; SetTypeOfTask(GetStaticTypeOfTask()); } diff --git a/tasks/makovskiy_i_min_value_in_matrix_rows/seq/src/ops_seq.cpp b/tasks/makovskiy_i_min_value_in_matrix_rows/seq/src/ops_seq.cpp index 9c99960418..133399ed02 100644 --- a/tasks/makovskiy_i_min_value_in_matrix_rows/seq/src/ops_seq.cpp +++ b/tasks/makovskiy_i_min_value_in_matrix_rows/seq/src/ops_seq.cpp @@ -5,6 +5,9 @@ namespace makovskiy_i_min_value_in_matrix_rows { MinValueSEQ::MinValueSEQ(const InType &in) { + if (in.empty()) { + throw std::invalid_argument("Input matrix is empty"); + } this->GetInput() = in; SetTypeOfTask(GetStaticTypeOfTask()); } diff --git a/tasks/makovskiy_i_min_value_in_matrix_rows/tests/functional/main.cpp b/tasks/makovskiy_i_min_value_in_matrix_rows/tests/functional/main.cpp index 3043283f42..40c6d19175 100644 --- a/tasks/makovskiy_i_min_value_in_matrix_rows/tests/functional/main.cpp +++ b/tasks/makovskiy_i_min_value_in_matrix_rows/tests/functional/main.cpp @@ -1,100 +1,66 @@ #include #include -#include -#include -#include - #include "makovskiy_i_min_value_in_matrix_rows/common/include/common.hpp" #include "makovskiy_i_min_value_in_matrix_rows/mpi/include/ops_mpi.hpp" #include "makovskiy_i_min_value_in_matrix_rows/seq/include/ops_seq.hpp" +#include "util/include/func_test_util.hpp" #include "util/include/util.hpp" namespace makovskiy_i_min_value_in_matrix_rows { -enum class TestExpectation { SUCCESS, FAIL_VALIDATION }; - -using UnifiedTestParam = - std::tuple(const InType &)>, std::string, InType, OutType, TestExpectation>; - -class MinValueAllTests : public ::testing::TestWithParam {}; - -TEST_P(MinValueAllTests, AllCases) { - auto task_factory = std::get<0>(GetParam()); - auto test_name = std::get<1>(GetParam()); - auto input_data = std::get<2>(GetParam()); - auto expected_output = std::get<3>(GetParam()); - auto expectation = std::get<4>(GetParam()); +class MinValueRunFuncTests : public ppc::util::BaseRunFuncTests { + public: + static std::string PrintTestParam(const TestType &test_param) { + const auto &input = std::get<0>(test_param); + const std::size_t rows = input.size(); + const std::size_t cols = input.empty() ? 0 : input.front().size(); + return "r" + std::to_string(rows) + "x" + std::to_string(cols); + } - switch (expectation) { - case TestExpectation::SUCCESS: { - auto task = task_factory(input_data); - ASSERT_TRUE(task->Validation()); - ASSERT_TRUE(task->PreProcessing()); - ASSERT_TRUE(task->Run()); - ASSERT_TRUE(task->PostProcessing()); + protected: + InType GetTestInputData() final { + auto params = std::get(ppc::util::GTestParamIndex::kTestParams)>(GetParam()); + return std::get<0>(params); + } - if (ppc::util::IsUnderMpirun()) { - int rank; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - if (rank == 0) { - ASSERT_EQ(task->GetOutput(), expected_output); - } - } else { - ASSERT_EQ(task->GetOutput(), expected_output); + bool CheckTestOutputData(OutType &output_data) final { + if (ppc::util::IsUnderMpirun()) { + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + if (rank != 0) { + return true; } - break; - } - case TestExpectation::FAIL_VALIDATION: { - auto task = task_factory(input_data); - ASSERT_FALSE(task->Validation()); - break; } + + auto params = std::get(ppc::util::GTestParamIndex::kTestParams)>(GetParam()); + const auto &expected = std::get<1>(params); + return output_data == expected; } +}; + +TEST_P(MinValueRunFuncTests, MinPerRow) { + ExecuteTest(GetParam()); } -auto GenerateTestName = [](const ::testing::TestParamInfo &info) { - std::string name = std::get<1>(info.param); - std::replace(name.begin(), name.end(), '/', '_'); - return name; +namespace { + +const auto kTestCases = std::array{ + TestType{InType{{1, 2, 3}, {4, 5, 6}}, OutType{1, 4}}, + TestType{InType{{-1, 0}, {10, 2}, {7}}, OutType{-1, 2, 7}}, + TestType{InType{{5, 5, 5}}, OutType{5}}, + TestType{InType{{8}}, OutType{8}}, }; -INSTANTIATE_TEST_SUITE_P( - MinValueTests, MinValueAllTests, - ::testing::Values( - UnifiedTestParam{[](const InType &in) { - return std::make_shared(in); - }, "SEQ/Positive/r2x3", {{1, 2, 3}, {4, 5, 6}}, {1, 4}, TestExpectation::SUCCESS}, - UnifiedTestParam{[](const InType &in) { - return std::make_shared(in); - }, "MPI/Positive/r2x3", {{1, 2, 3}, {4, 5, 6}}, {1, 4}, TestExpectation::SUCCESS}, - UnifiedTestParam{ - [](const InType &in) { - return std::make_shared(in); - }, "SEQ/Positive/NegativeValues", {{-1, 0}, {10, 2}, {7}}, {-1, 2, 7}, TestExpectation::SUCCESS}, - UnifiedTestParam{ - [](const InType &in) { - return std::make_shared(in); - }, "MPI/Positive/NegativeValues", {{-1, 0}, {10, 2}, {7}}, {-1, 2, 7}, TestExpectation::SUCCESS}, - UnifiedTestParam{[](const InType &in) { - return std::make_shared(in); - }, "SEQ/Positive/SingleValue", {{8}}, {8}, TestExpectation::SUCCESS}, - UnifiedTestParam{[](const InType &in) { - return std::make_shared(in); - }, "MPI/Positive/SingleValue", {{8}}, {8}, TestExpectation::SUCCESS}, +const auto kTasks = std::tuple_cat( + ppc::util::AddFuncTask(kTestCases, PPC_SETTINGS_makovskiy_i_min_value_in_matrix_rows), + ppc::util::AddFuncTask(kTestCases, PPC_SETTINGS_makovskiy_i_min_value_in_matrix_rows)); + +const auto kGtestValues = ppc::util::ExpandToValues(kTasks); +const auto kPerfTestName = MinValueRunFuncTests::PrintFuncTestName; + +INSTANTIATE_TEST_SUITE_P(MinValueTests, MinValueRunFuncTests, kGtestValues, kPerfTestName); - UnifiedTestParam{[](const InType &in) { - return std::make_shared(in); - }, "SEQ/Negative/EmptyMatrix", {}, {}, TestExpectation::FAIL_VALIDATION}, - UnifiedTestParam{[](const InType &in) { - return std::make_shared(in); - }, "MPI/Negative/EmptyMatrix", {}, {}, TestExpectation::FAIL_VALIDATION}, - UnifiedTestParam{[](const InType &in) { - return std::make_shared(in); - }, "SEQ/Negative/EmptyRow", {{1, 2}, {}}, {}, TestExpectation::FAIL_VALIDATION}, - UnifiedTestParam{[](const InType &in) { - return std::make_shared(in); - }, "MPI/Negative/EmptyRow", {{1, 2}, {}}, {}, TestExpectation::FAIL_VALIDATION}), - GenerateTestName); +} // namespace } // namespace makovskiy_i_min_value_in_matrix_rows