diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..93f2d9a --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +build/ +.vscode/ +googletest/ +benchmark/ \ No newline at end of file diff --git a/05_hw/CMakeLists.txt b/05_hw/CMakeLists.txt index 6f5e398..51c4093 100644 --- a/05_hw/CMakeLists.txt +++ b/05_hw/CMakeLists.txt @@ -1,7 +1,21 @@ cmake_minimum_required(VERSION 3.10) project(stack) -add_library(stack stack.c) +set(GOOGLETEST_VERSION 1.15.2) +enable_testing() +add_subdirectory(googletest) +include_directories(googletest/include) -add_executable(main main.c) -target_link_libraries(main stack) +add_library(stack stack.cpp) +add_executable(tests tests.cpp) +target_link_libraries(tests PRIVATE gtest stack) + +set(BENCHMARK_ENABLE_TESTING OFF) +add_subdirectory(benchmark) +include_directories(benchmark/include) + +add_executable(benchmark benchmark.cpp) +target_link_libraries(bench PRIVATE benchmark::benchmark stack) + +add_executable(main main.cpp) +target_link_libraries(main stack) \ No newline at end of file diff --git a/05_hw/benchmark.cpp b/05_hw/benchmark.cpp new file mode 100644 index 0000000..542a2b1 --- /dev/null +++ b/05_hw/benchmark.cpp @@ -0,0 +1,61 @@ +#include +#include "stack.h" + +class StackBench : public benchmark::Fixture +{ + // Метод, который выполняется перед каждым бенчмарком + void SetUp(::benchmark::State& state) + { + stack = new Stack(); // Создаем новый экземпляр стека + } + + // Метод, который выполняется после каждого бенчмарка + void TearDown(::benchmark::State& state) + { + delete stack; // Удаляем стек, освобождая память + } + +public: + Stack* stack; // Указатель на стек, который будет использоваться в бенчмарках +}; + +// Определяем бенчмарк для измерения времени выполнения операции добавления элементов в стек +BENCHMARK_DEFINE_F(StackBench, PushBench)(benchmark::State& st) +{ + for (auto _ : st) // Цикл для повторного выполнения теста + { + for(int i = 0; i < st.range(0); i++) // Внутренний цикл для добавления элементов в стек + push(stack, i); // Добавляем элемент i в стек + } +} + +// Определяем бенчмарк для измерения времени выполнения операции удаления элементов из стека +BENCHMARK_DEFINE_F(StackBench, PopBench)(benchmark::State& st) +{ + for(int i = 0; i < st.range(0); i++) // Сначала заполняем стек элементами + push(stack, i); // Добавляем элемент i в стек + + for (auto _ : st) // Цикл для повторного выполнения теста + { + for(int i = 0; i < st.range(0); i++) // Внутренний цикл для удаления элементов из стека + pop(stack); // Удаляем верхний элемент из стека + } +} + +// Регистрируем бенчмарки с различными аргументами (размером стека) +BENCHMARK_REGISTER_F(StackBench, PushBench) + ->Arg(100) // Размер стека 100 + ->Arg(1000) // Размер стека 1000 + ->Arg(10000) // Размер стека 10000 + ->Arg(100000) // Размер стека 100000 + ->Arg(1000000); // Размер стека 1000000 + +// Регистрируем бенчмарк для удаления элементов с теми же аргументами +BENCHMARK_REGISTER_F(StackBench, PopBench) + ->Arg(100) + ->Arg(1000) + ->Arg(10000) + ->Arg(100000) + ->Arg(1000000); + +BENCHMARK_MAIN(); \ No newline at end of file diff --git a/05_hw/stack.c b/05_hw/stack.c index 0964440..3f4a1cc 100644 --- a/05_hw/stack.c +++ b/05_hw/stack.c @@ -21,6 +21,7 @@ void destroyStack(Stack* stack) { current = current->next; free(tmp); } + stack->top = NULL; } void push(Stack* stack, int data) { @@ -30,8 +31,13 @@ void push(Stack* stack, int data) { } void pop(Stack* stack) { + if (stack->top == NULL) { + printf("Stack is empty, cannot pop.\n"); + return; + } Node* temp = stack->top; stack->top = stack->top->next; + free(temp); } Node* searchByValue(Stack* stack, int value) { @@ -40,6 +46,7 @@ Node* searchByValue(Stack* stack, int value) { if (current->data == value) { return current; } + current = current->next; } return NULL; } @@ -72,7 +79,6 @@ void traverseStack(Stack* stack) { } bool isEmpty(Stack* stack) { - free(stack->top); return stack->top == NULL; } diff --git a/05_hw/tests.cpp b/05_hw/tests.cpp new file mode 100644 index 0000000..0483875 --- /dev/null +++ b/05_hw/tests.cpp @@ -0,0 +1,131 @@ +#include +#include "stack.h" + +using namespace std; + +class StackTest : public testing::Test +{ + // Метод, который выполняется перед каждым тестом + void SetUp() override + { + stack = new Stack(); // Создаем новый экземпляр стека + } + + // Метод, который выполняется после каждого теста + void TearDown() override { + delete stack; // Удаляем стек, освобождая память + } + + public: + Stack* stack; // Указатель на стек, который будет использоваться в тестах +}; + +// Тест на проверку, что стек пустой +TEST_F(StackTest, isEmptyTest) +{ + ASSERT_EQ(isEmpty(stack), true); // Проверяем, что isEmpty возвращает true +} + +// Тест на получение верхнего элемента стека +TEST_F(StackTest, getTopTest) +{ + ASSERT_EQ(getTop(stack), nullptr); // Проверяем, что верхний элемент равен nullptr (стек пуст) +} + +// Тест на добавление элементов в стек +TEST_F(StackTest, PushTest) +{ + push(stack, 3); // Добавляем элемент 3 + push(stack, 5); // Добавляем элемент 5 + ASSERT_EQ(getTop(stack)->data, 5); // Проверяем, что верхний элемент равен 5 +} + +// Тест на удаление элемента из стека +TEST_F(StackTest, PopTest) +{ + push(stack, 3); // Добавляем элемент 3 + pop(stack); // Удаляем верхний элемент + ASSERT_EQ(getTop(stack), nullptr); // Проверяем, что стек пустой (nullptr) +} + +// Тест на попытку удалить элемент из пустого стека +TEST_F(StackTest, EmptyPopTest) +{ + pop(stack); // Пытаемся удалить элемент из пустого стека + ASSERT_EQ(getTop(stack), nullptr); // Проверяем, что стек все еще пустой +} + +// Тест на уничтожение стека +TEST_F(StackTest, destroyStackTest) +{ + push(stack, 3); // Добавляем элементы в стек + push(stack, 5); + push(stack, 15); + + destroyStack(stack); // Уничтожаем стек + + ASSERT_EQ(getTop(stack), nullptr); // Проверяем, что стек пустой (nullptr) +} + +// Тест на поиск элемента по значению +TEST_F(StackTest, searchByValueTest) +{ + push(stack, 3); + push(stack, 5); + push(stack, 15); + + ASSERT_EQ(searchByValue(stack, 5)->data, 5); // Проверяем, что найденный элемент равен 5 +} + +// Тест на поиск элемента по значению (не найдено) +TEST_F(StackTest, searchByValueInvTest) +{ + ASSERT_EQ(searchByValue(stack, 5), nullptr); // Проверяем, что поиск возвращает nullptr (не найдено) +} + +// Тест на поиск элемента по индексу +TEST_F(StackTest, searchByIndexTest) +{ + push(stack, 3); + push(stack, 5); + push(stack, 15); + + ASSERT_EQ(searchByIndex(stack, 1)->data, 5); // Проверяем, что элемент с индексом 1 равен 5 +} + +// Тест на поиск элемента по индексу (не найдено) +TEST_F(StackTest, searchByIndexInvTest) +{ + ASSERT_EQ(searchByIndex(stack, 1), nullptr); // Проверяем, что поиск возвращает nullptr (не найдено) +} + +// Тест на обход стека и вывод его элементов +TEST_F(StackTest, traverseStackTest) { + testing::internal::CaptureStdout(); // Захватываем стандартный вывод + + push(stack, 3); + push(stack, 5); + push(stack, 15); + + traverseStack(stack); // Обходим стек и выводим элементы + + std::string str = testing::internal::GetCapturedStdout(); // Получаем захваченный вывод + EXPECT_EQ("Stack elements: 15 5 3 \n", str); // Проверяем правильность вывода +} + +// Тест на обход пустого стека +TEST_F(StackTest, traverseStackEmptyTest) { + testing::internal::CaptureStdout(); // Захватываем стандартный вывод + + traverseStack(stack); // Обходим пустой стек + + std::string str = testing::internal::GetCapturedStdout(); // Получаем захваченный вывод + EXPECT_EQ("Stack elements: \n", str); // Проверяем правильность вывода для пустого стека +} + +int main(int argc, char **argv) +{ + ::testing::InitGoogleTest(&argc, argv); // Инициализируем Google Test + + return RUN_ALL_TESTS(); // Запускаем все тесты и возвращаем результат +} \ No newline at end of file