From 862b830879a2d100cc5e5ea1d77f009d03a74b64 Mon Sep 17 00:00:00 2001 From: Andrey Muminov Date: Sun, 15 Dec 2024 18:44:58 +0300 Subject: [PATCH 1/8] reorg lab dir --- 05_hw/.gitignore | 1 + 05_hw/CMakeLists.txt | 4 +- 05_hw/{ => src}/main.c | 19 +++++---- 05_hw/src/stack.c | 93 ++++++++++++++++++++++++++++++++++++++++++ 05_hw/src/stack.h | 43 +++++++++++++++++++ 05_hw/stack.c | 78 ----------------------------------- 05_hw/stack.h | 40 ------------------ 7 files changed, 150 insertions(+), 128 deletions(-) create mode 100644 05_hw/.gitignore rename 05_hw/{ => src}/main.c (71%) create mode 100644 05_hw/src/stack.c create mode 100644 05_hw/src/stack.h delete mode 100644 05_hw/stack.c delete mode 100644 05_hw/stack.h diff --git a/05_hw/.gitignore b/05_hw/.gitignore new file mode 100644 index 0000000..c795b05 --- /dev/null +++ b/05_hw/.gitignore @@ -0,0 +1 @@ +build \ No newline at end of file diff --git a/05_hw/CMakeLists.txt b/05_hw/CMakeLists.txt index 6f5e398..134e294 100644 --- a/05_hw/CMakeLists.txt +++ b/05_hw/CMakeLists.txt @@ -1,7 +1,7 @@ cmake_minimum_required(VERSION 3.10) project(stack) -add_library(stack stack.c) +add_library(stack src/stack.c) -add_executable(main main.c) +add_executable(main src/main.c) target_link_libraries(main stack) diff --git a/05_hw/main.c b/05_hw/src/main.c similarity index 71% rename from 05_hw/main.c rename to 05_hw/src/main.c index fded814..55f5658 100644 --- a/05_hw/main.c +++ b/05_hw/src/main.c @@ -2,7 +2,8 @@ #include -int main() { +int main() +{ Stack stack; initStack(&stack); @@ -18,19 +19,21 @@ int main() { printf("After popping an element:\n"); traverseStack(&stack); - Node* searchResult = searchByValue(&stack, 20); - if (searchResult != NULL) { + Node *searchResult = searchByValue(&stack, 20); + if (searchResult != NULL) + { printf("Element with value 20 found.\n"); - } else { + } + else + { printf("Element with value 20 not found.\n"); } - Node* topElement = getTop(&stack); - if (topElement != NULL) { + Node *topElement = getTop(&stack); + if (topElement != NULL) + { printf("Top element: %d\n", topElement->data); } return 0; } - - diff --git a/05_hw/src/stack.c b/05_hw/src/stack.c new file mode 100644 index 0000000..11f5f01 --- /dev/null +++ b/05_hw/src/stack.c @@ -0,0 +1,93 @@ +#include +#include + +#include "stack.h" + +Node *createNode(int data) +{ + Node *newNode = (Node *)malloc(sizeof(Node)); + newNode->data = data; + newNode->next = NULL; + return newNode; +} + +void initStack(Stack *stack) +{ + stack->top = NULL; +} + +void destroyStack(Stack *stack) +{ + Node *current = stack->top; + while (current != NULL) + { + Node *tmp = current; + current = current->next; + free(tmp); + } +} + +void push(Stack *stack, int data) +{ + Node *newNode = createNode(data); + newNode->next = stack->top; + stack->top = newNode; +} + +void pop(Stack *stack) +{ + Node *temp = stack->top; + stack->top = stack->top->next; +} + +Node *searchByValue(Stack *stack, int value) +{ + Node *current = stack->top; + while (current != NULL) + { + if (current->data == value) + { + return current; + } + } + return NULL; +} + +Node *searchByIndex(Stack *stack, int index) +{ + Node *current = stack->top; + int count = 0; + while (current != NULL) + { + if (count == index) + { + return current; + } + count++; + current = current->next; + } + return NULL; +} + +Node *getTop(Stack *stack) +{ + return stack->top; +} + +void traverseStack(Stack *stack) +{ + Node *current = stack->top; + printf("Stack elements: "); + while (current != NULL) + { + printf("%d ", current->data); + current = current->next; + } + printf("\n"); +} + +bool isEmpty(Stack *stack) +{ + free(stack->top); + return stack->top == NULL; +} diff --git a/05_hw/src/stack.h b/05_hw/src/stack.h new file mode 100644 index 0000000..423931f --- /dev/null +++ b/05_hw/src/stack.h @@ -0,0 +1,43 @@ +#pragma once + +#include + +typedef struct Node +{ + int data; + struct Node *next; +} Node; + +typedef struct Stack +{ + Node *top; +} Stack; + +#ifdef __cplusplus +extern "C" +{ +#endif + + Node *createNode(int data); + + void initStack(Stack *stack); + + void destroyStack(Stack *stack); + + void push(Stack *stack, int data); + + void pop(Stack *stack); + + Node *searchByValue(Stack *stack, int value); + + Node *searchByIndex(Stack *stack, int index); + + Node *getTop(Stack *stack); + + void traverseStack(Stack *stack); + + bool isEmpty(Stack *stack); + +#ifdef __cplusplus +} +#endif diff --git a/05_hw/stack.c b/05_hw/stack.c deleted file mode 100644 index 0964440..0000000 --- a/05_hw/stack.c +++ /dev/null @@ -1,78 +0,0 @@ -#include -#include - -#include "stack.h" - -Node* createNode(int data) { - Node* newNode = (Node*)malloc(sizeof(Node)); - newNode->data = data; - newNode->next = NULL; - return newNode; -} - -void initStack(Stack* stack) { - stack->top = NULL; -} - -void destroyStack(Stack* stack) { - Node* current = stack->top; - while (current != NULL) { - Node *tmp = current; - current = current->next; - free(tmp); - } -} - -void push(Stack* stack, int data) { - Node* newNode = createNode(data); - newNode->next = stack->top; - stack->top = newNode; -} - -void pop(Stack* stack) { - Node* temp = stack->top; - stack->top = stack->top->next; -} - -Node* searchByValue(Stack* stack, int value) { - Node* current = stack->top; - while (current != NULL) { - if (current->data == value) { - return current; - } - } - return NULL; -} - -Node* searchByIndex(Stack* stack, int index) { - Node* current = stack->top; - int count = 0; - while (current != NULL) { - if (count == index) { - return current; - } - count++; - current = current->next; - } - return NULL; -} - -Node* getTop(Stack* stack) { - return stack->top; -} - -void traverseStack(Stack* stack) { - Node* current = stack->top; - printf("Stack elements: "); - while (current != NULL) { - printf("%d ", current->data); - current = current->next; - } - printf("\n"); -} - -bool isEmpty(Stack* stack) { - free(stack->top); - return stack->top == NULL; -} - diff --git a/05_hw/stack.h b/05_hw/stack.h deleted file mode 100644 index ef0734e..0000000 --- a/05_hw/stack.h +++ /dev/null @@ -1,40 +0,0 @@ -#pragma once - -#include - -typedef struct Node { - int data; - struct Node* next; -} Node; - -typedef struct Stack { - Node* top; -} Stack; - -#ifdef __cplusplus -extern "C" { -#endif - -Node* createNode(int data); - -void initStack(Stack* stack); - -void destroyStack(Stack *stack); - -void push(Stack* stack, int data); - -void pop(Stack* stack); - -Node* searchByValue(Stack* stack, int value); - -Node* searchByIndex(Stack* stack, int index); - -Node* getTop(Stack* stack); - -void traverseStack(Stack* stack); - -bool isEmpty(Stack* stack); - -#ifdef __cplusplus -} -#endif From 9a844f555d069b3465929ec2f9beb6f27f537126 Mon Sep 17 00:00:00 2001 From: Andrey Muminov Date: Sun, 15 Dec 2024 18:52:34 +0300 Subject: [PATCH 2/8] fix bugs --- 05_hw/src/main.c | 11 +++++++---- 05_hw/src/stack.c | 3 ++- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/05_hw/src/main.c b/05_hw/src/main.c index 55f5658..2a4358d 100644 --- a/05_hw/src/main.c +++ b/05_hw/src/main.c @@ -7,9 +7,12 @@ int main() Stack stack; initStack(&stack); - push(&stack, 10); - push(&stack, 20); - push(&stack, 30); + const int first = 10; + const int second = 20; + const int third = 30; + push(&stack, first); + push(&stack, second); + push(&stack, third); printf("After pushing elements:\n"); traverseStack(&stack); @@ -19,7 +22,7 @@ int main() printf("After popping an element:\n"); traverseStack(&stack); - Node *searchResult = searchByValue(&stack, 20); + Node* searchResult = searchByValue(&stack, second); if (searchResult != NULL) { printf("Element with value 20 found.\n"); diff --git a/05_hw/src/stack.c b/05_hw/src/stack.c index 11f5f01..810daff 100644 --- a/05_hw/src/stack.c +++ b/05_hw/src/stack.c @@ -38,6 +38,7 @@ void pop(Stack *stack) { Node *temp = stack->top; stack->top = stack->top->next; + free(temp); } Node *searchByValue(Stack *stack, int value) @@ -49,6 +50,7 @@ Node *searchByValue(Stack *stack, int value) { return current; } + current = current->next; } return NULL; } @@ -88,6 +90,5 @@ void traverseStack(Stack *stack) bool isEmpty(Stack *stack) { - free(stack->top); return stack->top == NULL; } From c5b3f57c92225b6e9c6dbcf3627c3637dd766bd7 Mon Sep 17 00:00:00 2001 From: Andrey Muminov Date: Sun, 15 Dec 2024 23:33:17 +0300 Subject: [PATCH 3/8] add benchmark --- 05_hw/.gitignore | 3 +- 05_hw/benchmark/CMakeLists.txt | 12 ++++++ 05_hw/benchmark/benchmark.cpp | 67 ++++++++++++++++++++++++++++++++++ 3 files changed, 81 insertions(+), 1 deletion(-) create mode 100644 05_hw/benchmark/CMakeLists.txt create mode 100644 05_hw/benchmark/benchmark.cpp diff --git a/05_hw/.gitignore b/05_hw/.gitignore index c795b05..a0a00be 100644 --- a/05_hw/.gitignore +++ b/05_hw/.gitignore @@ -1 +1,2 @@ -build \ No newline at end of file +.vs +out \ No newline at end of file diff --git a/05_hw/benchmark/CMakeLists.txt b/05_hw/benchmark/CMakeLists.txt new file mode 100644 index 0000000..f3339c7 --- /dev/null +++ b/05_hw/benchmark/CMakeLists.txt @@ -0,0 +1,12 @@ +cmake_minimum_required(VERSION 3.10) + +add_executable(benchmark benchmark.cpp) + +target_link_libraries(benchmark PRIVATE stack::library) + +if(NOT CMAKE_BUILD_TYPE STREQUAL "Release") + target_compile_options(benchmark PRIVATE -fsanitize=address) + target_link_options(benchmark PRIVATE -fsanitize=address) +endif() + +target_include_directories(benchmark PRIVATE ${CMAKE_SOURCE_DIR}/src) diff --git a/05_hw/benchmark/benchmark.cpp b/05_hw/benchmark/benchmark.cpp new file mode 100644 index 0000000..81424cf --- /dev/null +++ b/05_hw/benchmark/benchmark.cpp @@ -0,0 +1,67 @@ +#include +#include +#include "../src/stack.h" + +class StackBenchmark +{ +public: + StackBenchmark(size_t limit) : limit(limit) + { + initStack(&stack); + } + + ~StackBenchmark() + { + destroyStack(&stack); + } + + void run() + { + benchmarkPush(); + benchmarkPop(); + } + +private: + Stack stack; + size_t limit; + + void benchmarkPush() + { + std::cout << "Pushing " << limit << " elements into the stack" << std::endl; + + auto start_time = std::chrono::steady_clock::now(); + for (size_t i = 0; i < limit; ++i) + { + push(&stack, 1); + } + auto end_time = std::chrono::steady_clock::now(); + + auto elapsed = std::chrono::duration_cast(end_time - start_time); + std::cout << "Push time: " << elapsed.count() << " ms" << std::endl; + } + + void benchmarkPop() + { + std::cout << "Popping " << limit << " elements from the stack" << std::endl; + + auto start_time = std::chrono::steady_clock::now(); + for (size_t i = 0; i < limit; ++i) + { + pop(&stack); + } + auto end_time = std::chrono::steady_clock::now(); + + auto elapsed = std::chrono::duration_cast(end_time - start_time); + std::cout << "Pop time: " << elapsed.count() << " ms" << std::endl; + } +}; + +int main() +{ + const size_t limit = 10000000; + + StackBenchmark benchmark(limit); + benchmark.run(); + + return 0; +} From 5de2989b0857a70a41feae9d6698f7b9e4a6d528 Mon Sep 17 00:00:00 2001 From: Andrey Muminov Date: Sun, 15 Dec 2024 23:34:44 +0300 Subject: [PATCH 4/8] update main code --- 05_hw/CMakeLists.txt | 16 +++++++++++++++- 05_hw/README.md | 16 ++++++++-------- 05_hw/src/main.c | 2 +- 3 files changed, 24 insertions(+), 10 deletions(-) diff --git a/05_hw/CMakeLists.txt b/05_hw/CMakeLists.txt index 134e294..eec59e8 100644 --- a/05_hw/CMakeLists.txt +++ b/05_hw/CMakeLists.txt @@ -2,6 +2,20 @@ cmake_minimum_required(VERSION 3.10) project(stack) add_library(stack src/stack.c) +add_library(stack::library ALIAS stack) add_executable(main src/main.c) -target_link_libraries(main stack) +target_link_libraries(main PRIVATE stack) + +if(NOT CMAKE_BUILD_TYPE STREQUAL "Release") + target_compile_options(stack PRIVATE -fsanitize=address) + target_link_options(stack PRIVATE -fsanitize=address) + + target_compile_options(main PRIVATE -fsanitize=address) + target_link_options(main PRIVATE -fsanitize=address) +endif() + +add_subdirectory(test) +enable_testing() + +add_subdirectory(benchmark) diff --git a/05_hw/README.md b/05_hw/README.md index 8661b04..d634921 100644 --- a/05_hw/README.md +++ b/05_hw/README.md @@ -5,13 +5,13 @@ Необходимо привести код в порядок. - * Исправить ошибки; - * Покрыть код тестами; - * Проверить покрытие кода тестами (убедиться, что все функции и условия протестированы); - * Выбрать статический анализатор и запустить его (исправить ошибки, если будут); - * Запустить тесты с санитайзерами (исправить ошибки, если будут); - * Для базовых функций (push / pop) написать бенчмарки; - * Изучить возможности Github Actions и настроить CI для тестирования (*). +- Исправить ошибки; +- Покрыть код тестами; +- Проверить покрытие кода тестами (убедиться, что все функции и условия протестированы); +- Выбрать статический анализатор и запустить его (исправить ошибки, если будут); +- Запустить тесты с санитайзерами (исправить ошибки, если будут); +- Для базовых функций (push / pop) написать бенчмарки; +- Изучить возможности Github Actions и настроить CI для тестирования (\*). Во время рефакторинга разрешается изменять не только код функций, но и их c сигнатуры, если это будет оправдано с точки зрения использования/тестирования этих функций. @@ -19,4 +19,4 @@ Решение - Pull Request с исправлением. Желательно разбивать изменения на атомарные коммиты с целью повышения качества ревью и ускорения получения фидбека. -(*) - необязательное задание. +(\*) - необязательное задание. diff --git a/05_hw/src/main.c b/05_hw/src/main.c index 2a4358d..2531658 100644 --- a/05_hw/src/main.c +++ b/05_hw/src/main.c @@ -22,7 +22,7 @@ int main() printf("After popping an element:\n"); traverseStack(&stack); - Node* searchResult = searchByValue(&stack, second); + Node *searchResult = searchByValue(&stack, second); if (searchResult != NULL) { printf("Element with value 20 found.\n"); From 4da88a1c599a1fe483e4f96c93fb614a325d92c0 Mon Sep 17 00:00:00 2001 From: Andrey Muminov Date: Sun, 15 Dec 2024 23:44:23 +0300 Subject: [PATCH 5/8] add tests --- 05_hw/test/CMakeLists.txt | 47 ++++++++++++++++ 05_hw/test/stack_fixture.h | 26 +++++++++ 05_hw/test/test_smoke.cpp | 54 +++++++++++++++++++ 05_hw/test/test_stack.cpp | 107 +++++++++++++++++++++++++++++++++++++ 4 files changed, 234 insertions(+) create mode 100644 05_hw/test/CMakeLists.txt create mode 100644 05_hw/test/stack_fixture.h create mode 100644 05_hw/test/test_smoke.cpp create mode 100644 05_hw/test/test_stack.cpp diff --git a/05_hw/test/CMakeLists.txt b/05_hw/test/CMakeLists.txt new file mode 100644 index 0000000..ad4cc54 --- /dev/null +++ b/05_hw/test/CMakeLists.txt @@ -0,0 +1,47 @@ +cmake_minimum_required(VERSION 3.12) # Минимальная версия CMake +project(tests) # Название проекта + +include(FetchContent) # Включаем поддержку загрузки контента + +# Загрузка и настройка googletest через FetchContent +FetchContent_Declare( + googletest + GIT_REPOSITORY https://github.com/google/googletest.git # Репозиторий googletest + GIT_TAG v1.15.2 # Тег версии googletest + OVERRIDE_FIND_PACKAGE # Ожидаем, что googletest не будет найден локально +) + +FetchContent_MakeAvailable(googletest) # Загружаем googletest + +# Для Windows: заставляем использовать общий CRT для библиотеки googletest +if(WIN32) + set(gtest_force_shared_crt ON CACHE BOOL "" FORCE) +endif() + +# Создаем исполнимый файл для тестов, добавляя тестовые файлы и исходники стека +add_executable(tests + test_stack.cpp # Тесты стека + test_smoke.cpp # Тесты для проверки работоспособности + ../src/stack.c # Исходный файл стека +) + +# Указываем директории с заголовочными файлами для тестов +target_include_directories(tests PRIVATE + ${CMAKE_SOURCE_DIR}/src # Директория с исходниками (stack.h и другие) + ${CMAKE_SOURCE_DIR}/test # Директория с тестами (например, stack_fixture.h) +) + +# Линкуем googletest к исполнимому файлу тестов +target_link_libraries(tests PRIVATE gtest gtest_main) + +# Настройка для покрытия кода в режиме Debug (если используется Clang) +if(CMAKE_BUILD_TYPE STREQUAL "Debug") + if(CMAKE_CXX_COMPILER_ID STREQUAL "Clang") + # Включаем опции для покрытия кода + target_compile_options(tests PRIVATE -coverage -fprofile-instr-generate -fcoverage-mapping) + target_link_options(tests PRIVATE -coverage) + + # Очищаем файлы gcda после выполнения тестов + execute_process(COMMAND rm -f *.gcda WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/tests.dir) + endif() +endif() diff --git a/05_hw/test/stack_fixture.h b/05_hw/test/stack_fixture.h new file mode 100644 index 0000000..e11345d --- /dev/null +++ b/05_hw/test/stack_fixture.h @@ -0,0 +1,26 @@ +#ifndef STACK_FIXTURE_H +#define STACK_FIXTURE_H + +#include // Для работы с Google Test +#include "../src/stack.h" // Подключаем заголовочный файл стека + +// Класс для создания тестового фикстуры для стека +class StackFixture : public ::testing::Test +{ +protected: + Stack stack; // Экземпляр стека + + // Конструктор инициализирует стек перед каждым тестом + StackFixture() + { + initStack(&stack); // Инициализация стека + } + + // Деструктор уничтожает стек после выполнения теста + ~StackFixture() override + { + destroyStack(&stack); // Уничтожение стека + } +}; + +#endif diff --git a/05_hw/test/test_smoke.cpp b/05_hw/test/test_smoke.cpp new file mode 100644 index 0000000..7851604 --- /dev/null +++ b/05_hw/test/test_smoke.cpp @@ -0,0 +1,54 @@ +#include +#include "../src/stack.h" +#include "stack_fixture.h" // Подключаем StackFixture + +// Тест для проверки, что стек пустой после инициализации +TEST_F(StackFixture, TestStackInitialization) +{ + // Проверяем, что стек пустой после инициализации + EXPECT_TRUE(isEmpty(&stack)) << "Stack should be empty after initialization"; +} + +// Тест для проверки добавления элемента в стек +TEST_F(StackFixture, TestPushElement) +{ + push(&stack, 10); // Добавляем элемент в стек + + // Проверяем, что стек не пустой после добавления элемента + EXPECT_FALSE(isEmpty(&stack)) << "Stack should not be empty after pushing an element"; +} + +// Тест для проверки удаления элемента из стека +TEST_F(StackFixture, TestPopElement) +{ + push(&stack, 10); // Добавляем элемент в стек + pop(&stack); // Удаляем элемент из стека + + // Проверяем, что стек пустой после удаления единственного элемента + EXPECT_TRUE(isEmpty(&stack)) << "Stack should be empty after popping the only element"; +} + +// Тест для проверки нескольких операций push/pop +TEST_F(StackFixture, TestMultiplePushPop) +{ + // Добавляем несколько элементов в стек + push(&stack, 10); + push(&stack, 20); + push(&stack, 30); + + // Проверяем, что стек не пустой после добавления элементов + EXPECT_FALSE(isEmpty(&stack)) << "Stack should not be empty after pushing multiple elements"; + + // Удаляем два элемента из стека + pop(&stack); + pop(&stack); + + // Проверяем, что стек не пустой после удаления двух элементов + EXPECT_FALSE(isEmpty(&stack)) << "Stack should not be empty after popping two elements"; + + // Удаляем последний элемент + pop(&stack); + + // Проверяем, что стек пустой после удаления всех элементов + EXPECT_TRUE(isEmpty(&stack)) << "Stack should be empty after popping all elements"; +} diff --git a/05_hw/test/test_stack.cpp b/05_hw/test/test_stack.cpp new file mode 100644 index 0000000..1afc1f7 --- /dev/null +++ b/05_hw/test/test_stack.cpp @@ -0,0 +1,107 @@ +#include +#include +#include +#include "stack_fixture.h" // Подключаем StackFixture + +// Тест для проверки корректности добавления элементов в стек +TEST_F(StackFixture, TestPush) +{ + push(&stack, 1); // Добавляем элемент в стек + push(&stack, 2); // Добавляем еще один элемент + + // Проверяем, что первый элемент в стеке - 2 + EXPECT_EQ(stack.top->data, 2); + // Проверяем, что второй элемент в стеке - 1 + EXPECT_EQ(stack.top->next->data, 1); +} + +// Тест для проверки корректности удаления элемента из стека +TEST_F(StackFixture, TestPop) +{ + push(&stack, 1); // Добавляем элемент в стек + push(&stack, 2); // Добавляем еще один элемент + pop(&stack); // Удаляем верхний элемент + + // Проверяем, что после удаления верхнего элемента стек имеет значение 1 + EXPECT_EQ(stack.top->data, 1); + // Проверяем, что следующий элемент в стеке равен nullptr (пусто) + EXPECT_EQ(stack.top->next, nullptr); +} + +// Тест для проверки правильности получения верхнего элемента стека +TEST_F(StackFixture, TestGetTop) +{ + push(&stack, 1); // Добавляем элемент в стек + push(&stack, 2); // Добавляем еще один элемент + + // Проверяем, что верхний элемент стека - это 2 + EXPECT_EQ(getTop(&stack)->data, 2); +} + +// Тест для проверки последовательности операций push и pop +TEST_F(StackFixture, TestPushPop) +{ + push(&stack, 1); // Добавляем элемент в стек + pop(&stack); // Удаляем элемент из стека + + // Проверяем, что после удаления элемента стек пустой + EXPECT_TRUE(isEmpty(&stack)); +} + +// Тест для проверки поиска элемента по значению в стеке +TEST_F(StackFixture, TestSearchByValue) +{ + push(&stack, 1); // Добавляем элемент в стек + push(&stack, -2); // Добавляем еще один элемент + push(&stack, 3); // Добавляем еще один элемент + + // Ищем элемент -2 в стеке + Node *current_found = searchByValue(&stack, -2); + // Ищем элемент 4, которого нет в стеке + Node *current_not_found = searchByValue(&stack, 4); + + // Проверяем, что элемент -2 найден и это второй элемент в стеке + EXPECT_EQ(current_found, stack.top->next); + // Проверяем, что элемент 4 не найден (возвращается nullptr) + EXPECT_EQ(current_not_found, nullptr); +} + +// Тест для проверки поиска элемента по индексу в стеке +TEST_F(StackFixture, TestSearchByIndex) +{ + push(&stack, 1); // Добавляем элемент в стек + push(&stack, -2); // Добавляем еще один элемент + push(&stack, 3); // Добавляем еще один элемент + + // Ищем элемент по индексу 1 + Node *current_found = searchByIndex(&stack, 1); + // Ищем элемент по индексу 3, который выходит за пределы стека + Node *current_not_found = searchByIndex(&stack, 3); + + // Проверяем, что элемент с индексом 1 найден (это второй элемент в стеке) + EXPECT_EQ(current_found, stack.top->next); + // Проверяем, что элемент с индексом 3 не найден (возвращается nullptr) + EXPECT_EQ(current_not_found, nullptr); +} + +// Тест для проверки корректности вывода всех элементов стека +TEST_F(StackFixture, TestTraverseStack) +{ + testing::internal::CaptureStdout(); // Перехватываем стандартный вывод + + push(&stack, 1); // Добавляем элементы в стек + push(&stack, -2); + push(&stack, 3); + push(&stack, -4); + push(&stack, 0); + + // Печатаем элементы стека + traverseStack(&stack); + + // Ожидаемый результат + std::string expected = "Stack elements: 0 -4 3 -2 1 \n"; + std::string output = testing::internal::GetCapturedStdout(); // Получаем перехваченный вывод + + // Проверяем, что вывод совпадает с ожидаемым + EXPECT_EQ(expected, output); +} From 2a1da0cc96b5864fac58de3871170468549b0422 Mon Sep 17 00:00:00 2001 From: Andrey Muminov Date: Sat, 21 Dec 2024 19:14:23 +0300 Subject: [PATCH 6/8] fix tests --- 05_hw/CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/05_hw/CMakeLists.txt b/05_hw/CMakeLists.txt index eec59e8..4551faa 100644 --- a/05_hw/CMakeLists.txt +++ b/05_hw/CMakeLists.txt @@ -17,5 +17,6 @@ endif() add_subdirectory(test) enable_testing() +add_test(tests test) add_subdirectory(benchmark) From f7f606ed824ebce83139dc6051c6cbaed5c9e3b3 Mon Sep 17 00:00:00 2001 From: Andrey Muminov Date: Sat, 21 Dec 2024 23:56:28 +0300 Subject: [PATCH 7/8] some fixes --- 05_hw/CMakeLists.txt | 8 +-- 05_hw/benchmark/benchmark.cpp | 91 ++++++++++++++++++----------------- 2 files changed, 50 insertions(+), 49 deletions(-) diff --git a/05_hw/CMakeLists.txt b/05_hw/CMakeLists.txt index 4551faa..b951c94 100644 --- a/05_hw/CMakeLists.txt +++ b/05_hw/CMakeLists.txt @@ -7,12 +7,8 @@ add_library(stack::library ALIAS stack) add_executable(main src/main.c) target_link_libraries(main PRIVATE stack) -if(NOT CMAKE_BUILD_TYPE STREQUAL "Release") - target_compile_options(stack PRIVATE -fsanitize=address) - target_link_options(stack PRIVATE -fsanitize=address) - - target_compile_options(main PRIVATE -fsanitize=address) - target_link_options(main PRIVATE -fsanitize=address) +if (NOT CMAKE_BUILD_TYPE STREQUAL "Release") + target_compile_options(main PRIVATE -fsanitize=address -MD) endif() add_subdirectory(test) diff --git a/05_hw/benchmark/benchmark.cpp b/05_hw/benchmark/benchmark.cpp index 81424cf..6e44c10 100644 --- a/05_hw/benchmark/benchmark.cpp +++ b/05_hw/benchmark/benchmark.cpp @@ -5,63 +5,68 @@ class StackBenchmark { public: - StackBenchmark(size_t limit) : limit(limit) - { - initStack(&stack); - } + StackBenchmark(size_t limit) : limit(limit) + { + initStack(&stack); + } - ~StackBenchmark() - { - destroyStack(&stack); - } + ~StackBenchmark() + { + destroyStack(&stack); + } - void run() - { - benchmarkPush(); - benchmarkPop(); - } + void run() + { + for (int i = 1; i <= 5; ++i) + { + std::cout << "Run " << i << ":" << std::endl; + benchmarkPush(); + benchmarkPop(); + std::cout << std::endl; + } + } private: - Stack stack; - size_t limit; + Stack stack; + size_t limit; - void benchmarkPush() - { - std::cout << "Pushing " << limit << " elements into the stack" << std::endl; + void benchmarkPush() + { + std::cout << " Pushing " << limit << " elements into the stack" << std::endl; - auto start_time = std::chrono::steady_clock::now(); - for (size_t i = 0; i < limit; ++i) - { - push(&stack, 1); - } - auto end_time = std::chrono::steady_clock::now(); + auto start_time = std::chrono::steady_clock::now(); + for (size_t i = 0; i < limit; ++i) + { + push(&stack, 1); + } + auto end_time = std::chrono::steady_clock::now(); - auto elapsed = std::chrono::duration_cast(end_time - start_time); - std::cout << "Push time: " << elapsed.count() << " ms" << std::endl; - } + auto elapsed = std::chrono::duration_cast(end_time - start_time); + std::cout << " Push time: " << elapsed.count() << " ms" << std::endl; + } - void benchmarkPop() - { - std::cout << "Popping " << limit << " elements from the stack" << std::endl; + void benchmarkPop() + { + std::cout << " Popping " << limit << " elements from the stack" << std::endl; - auto start_time = std::chrono::steady_clock::now(); - for (size_t i = 0; i < limit; ++i) - { - pop(&stack); - } - auto end_time = std::chrono::steady_clock::now(); + auto start_time = std::chrono::steady_clock::now(); + for (size_t i = 0; i < limit; ++i) + { + pop(&stack); + } + auto end_time = std::chrono::steady_clock::now(); - auto elapsed = std::chrono::duration_cast(end_time - start_time); - std::cout << "Pop time: " << elapsed.count() << " ms" << std::endl; - } + auto elapsed = std::chrono::duration_cast(end_time - start_time); + std::cout << " Pop time: " << elapsed.count() << " ms" << std::endl; + } }; int main() { - const size_t limit = 10000000; + const size_t limit = 10000000; - StackBenchmark benchmark(limit); - benchmark.run(); + StackBenchmark benchmark(limit); + benchmark.run(); - return 0; + return 0; } From e4b0fbd8dcc8fbc3e9603d0add26515167af218a Mon Sep 17 00:00:00 2001 From: Andrey Muminov Date: Sun, 22 Dec 2024 01:45:56 +0300 Subject: [PATCH 8/8] some fixes --- 05_hw/CMakeLists.txt | 15 ++++++++++----- 05_hw/CMakeSettings.json | 26 ++++++++++++++++++++++++++ 05_hw/benchmark/CMakeLists.txt | 11 ++--------- 05_hw/test/CMakeLists.txt | 21 ++++++++++++--------- 05_hw/test/{ => tests}/stack_fixture.h | 0 05_hw/test/{ => tests}/test_smoke.cpp | 0 05_hw/test/{ => tests}/test_stack.cpp | 0 7 files changed, 50 insertions(+), 23 deletions(-) create mode 100644 05_hw/CMakeSettings.json rename 05_hw/test/{ => tests}/stack_fixture.h (100%) rename 05_hw/test/{ => tests}/test_smoke.cpp (100%) rename 05_hw/test/{ => tests}/test_stack.cpp (100%) diff --git a/05_hw/CMakeLists.txt b/05_hw/CMakeLists.txt index b951c94..53144e7 100644 --- a/05_hw/CMakeLists.txt +++ b/05_hw/CMakeLists.txt @@ -1,18 +1,23 @@ -cmake_minimum_required(VERSION 3.10) +cmake_minimum_required(VERSION 3.12) project(stack) add_library(stack src/stack.c) add_library(stack::library ALIAS stack) -add_executable(main src/main.c) -target_link_libraries(main PRIVATE stack) +add_executable(main "src/main.c") +target_link_libraries(main stack) +# sanitizer setup if (NOT CMAKE_BUILD_TYPE STREQUAL "Release") - target_compile_options(main PRIVATE -fsanitize=address -MD) + target_compile_options(main PRIVATE -fsanitize=address -MD) + target_link_options(main PRIVATE) endif() + +# tests setup add_subdirectory(test) enable_testing() -add_test(tests test) +add_test(tests test/tests) +# benchmark setup add_subdirectory(benchmark) diff --git a/05_hw/CMakeSettings.json b/05_hw/CMakeSettings.json new file mode 100644 index 0000000..8901786 --- /dev/null +++ b/05_hw/CMakeSettings.json @@ -0,0 +1,26 @@ +{ + "configurations": [ + { + "name": "x64-Debug", + "generator": "Ninja", + "configurationType": "Debug", + "inheritEnvironments": [ "clang_cl_x86" ], + "buildRoot": "${projectDir}\\out\\build\\${name}", + "installRoot": "${projectDir}\\out\\install\\${name}", + "cmakeCommandArgs": "", + "buildCommandArgs": "", + "ctestCommandArgs": "" + }, + { + "name": "x64-Clang-Debug", + "generator": "Ninja", + "configurationType": "Debug", + "buildRoot": "${projectDir}\\out\\build\\${name}", + "installRoot": "${projectDir}\\out\\install\\${name}", + "cmakeCommandArgs": "", + "buildCommandArgs": "", + "ctestCommandArgs": "", + "inheritEnvironments": [ "clang_cl_x64" ] + } + ] +} \ No newline at end of file diff --git a/05_hw/benchmark/CMakeLists.txt b/05_hw/benchmark/CMakeLists.txt index f3339c7..40ef565 100644 --- a/05_hw/benchmark/CMakeLists.txt +++ b/05_hw/benchmark/CMakeLists.txt @@ -1,12 +1,5 @@ cmake_minimum_required(VERSION 3.10) +project(benchmark) add_executable(benchmark benchmark.cpp) - -target_link_libraries(benchmark PRIVATE stack::library) - -if(NOT CMAKE_BUILD_TYPE STREQUAL "Release") - target_compile_options(benchmark PRIVATE -fsanitize=address) - target_link_options(benchmark PRIVATE -fsanitize=address) -endif() - -target_include_directories(benchmark PRIVATE ${CMAKE_SOURCE_DIR}/src) +target_link_libraries(benchmark PRIVATE stack::library) \ No newline at end of file diff --git a/05_hw/test/CMakeLists.txt b/05_hw/test/CMakeLists.txt index ad4cc54..c21a073 100644 --- a/05_hw/test/CMakeLists.txt +++ b/05_hw/test/CMakeLists.txt @@ -20,28 +20,31 @@ endif() # Создаем исполнимый файл для тестов, добавляя тестовые файлы и исходники стека add_executable(tests - test_stack.cpp # Тесты стека - test_smoke.cpp # Тесты для проверки работоспособности - ../src/stack.c # Исходный файл стека -) + tests/test_stack.cpp + tests/test_smoke.cpp + ../src/stack.c) # Указываем директории с заголовочными файлами для тестов target_include_directories(tests PRIVATE ${CMAKE_SOURCE_DIR}/src # Директория с исходниками (stack.h и другие) ${CMAKE_SOURCE_DIR}/test # Директория с тестами (например, stack_fixture.h) + ${CMAKE_SOURCE_DIR}/test # Здесь добавляем ещё раз, так как stack_fixture.h находится в той же директории ) # Линкуем googletest к исполнимому файлу тестов target_link_libraries(tests PRIVATE gtest gtest_main) -# Настройка для покрытия кода в режиме Debug (если используется Clang) +message("C++ Compiler ID: ${CMAKE_CXX_COMPILER_ID}") + if(CMAKE_BUILD_TYPE STREQUAL "Debug") if(CMAKE_CXX_COMPILER_ID STREQUAL "Clang") - # Включаем опции для покрытия кода + message("Clang compiler detected: Enabling code coverage") target_compile_options(tests PRIVATE -coverage -fprofile-instr-generate -fcoverage-mapping) target_link_options(tests PRIVATE -coverage) - - # Очищаем файлы gcda после выполнения тестов - execute_process(COMMAND rm -f *.gcda WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/tests.dir) + execute_process(COMMAND rm -f *.gcda WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/tests.dir/tests) endif() +else() + message("Not a Debug build or unsupported compiler.") endif() + +target_link_libraries(tests PRIVATE gtest gtest_main) \ No newline at end of file diff --git a/05_hw/test/stack_fixture.h b/05_hw/test/tests/stack_fixture.h similarity index 100% rename from 05_hw/test/stack_fixture.h rename to 05_hw/test/tests/stack_fixture.h diff --git a/05_hw/test/test_smoke.cpp b/05_hw/test/tests/test_smoke.cpp similarity index 100% rename from 05_hw/test/test_smoke.cpp rename to 05_hw/test/tests/test_smoke.cpp diff --git a/05_hw/test/test_stack.cpp b/05_hw/test/tests/test_stack.cpp similarity index 100% rename from 05_hw/test/test_stack.cpp rename to 05_hw/test/tests/test_stack.cpp