diff --git a/05_hw/.gitignore b/05_hw/.gitignore new file mode 100644 index 0000000..00e3c77 --- /dev/null +++ b/05_hw/.gitignore @@ -0,0 +1,8 @@ +*.tmp +*.log + +/build/ +/dist/ + +config.ini +secret.txt diff --git a/05_hw/CMakeLists.txt b/05_hw/CMakeLists.txt index 6f5e398..f701846 100644 --- a/05_hw/CMakeLists.txt +++ b/05_hw/CMakeLists.txt @@ -1,7 +1,18 @@ cmake_minimum_required(VERSION 3.10) project(stack) +SET(GCC_COVERAGE_COMPILE_FLAGS "-g -O0 -coverage -fprofile-arcs -ftest-coverage") +SET(GCC_COVERAGE_LINK_FLAGS "-coverage -lgcov") + +set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize=address -g") +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=address -g") + add_library(stack stack.c) add_executable(main main.c) + target_link_libraries(main stack) +add_executable(tests tests.c stack.c) +target_link_libraries(tests stack gcov) +add_executable(benchmark benchmark.c stack.c) +target_link_libraries(benchmark stack gcov) diff --git a/05_hw/README.md b/05_hw/README.md index 8661b04..bed365f 100644 --- a/05_hw/README.md +++ b/05_hw/README.md @@ -1,22 +1,13 @@ # Домашнее задание +Данная работа над заданием была выполнена Дубковым Иваном, м23ИВТ-1 Файлы stack.c и stack.h являются простой реализацией стека, хранящего целые числа. -В коде есть баги и ошибки. - -Необходимо привести код в порядок. - - * Исправить ошибки; - * Покрыть код тестами; - * Проверить покрытие кода тестами (убедиться, что все функции и условия протестированы); - * Выбрать статический анализатор и запустить его (исправить ошибки, если будут); - * Запустить тесты с санитайзерами (исправить ошибки, если будут); - * Для базовых функций (push / pop) написать бенчмарки; - * Изучить возможности Github Actions и настроить CI для тестирования (*). - -Во время рефакторинга разрешается изменять не только код функций, но и их c сигнатуры, -если это будет оправдано с точки зрения использования/тестирования этих функций. - -Решение - Pull Request с исправлением. Желательно разбивать изменения на атомарные коммиты -с целью повышения качества ревью и ускорения получения фидбека. - -(*) - необязательное задание. +В коде были исправлены баги и ошибки, а также проведен ряд работ: + + * Код был покрыт тестами - при помощи файла tests.c; + * Проверить покрытие кода тестами (убедиться, что все функции и условия протестированы) - покрытие проверили при помощи модуля gcov; + * Был выбран статический анализатор Cppcheck, и при его помощи была проведена проверка на ошибки (существенных ошибок было не выявлено) + * Были запущены тесты с санитайзерами (Address Sanitiser) - при его помощи была обнаружена ошибка в работе кода, исправлено + * Для базовых функций (push / pop) были написаны бенчмарки - былва выявлена закономерность их поведения при различном количестве затраченных операций; + +В качестве решения предоставляется пулл-реквест с протестированным репозиторием. Результаты тестов прилагаются в подробном отчете формата .docx diff --git a/05_hw/benchmark.c b/05_hw/benchmark.c new file mode 100644 index 0000000..1033491 --- /dev/null +++ b/05_hw/benchmark.c @@ -0,0 +1,57 @@ +#include +#include +#include +#include "stack.h" + +void benchmark_push(Stack* stack, int num_operations) { + clock_t start = clock(); + + for (int i = 0; i < num_operations; i++) { + push(stack, i); + } + + clock_t end = clock(); + double time_spent = (double)(end - start) / CLOCKS_PER_SEC; + printf("Pushed %d times in %f seconds\n", num_operations, time_spent); +} + +void benchmark_pop(Stack* stack, int num_operations) { + clock_t start = clock(); + + for (int i = 0; i < num_operations; i++) { + pop(stack); + } + + clock_t end = clock(); + double time_spent = (double)(end - start) / CLOCKS_PER_SEC; + printf("Pushed %d times in %f seconds\n", num_operations, time_spent); +} + +int main() { + Stack stack; + initStack(&stack); + int iterations = 1000000; + + printf("Benchmarking push:\n"); + for (int i = 1000; i <= iterations; i *= 10) { + benchmark_push(&stack, i); + + while (!isEmpty(&stack)) { + pop(&stack); + } + } + + for (int i = 0; i < iterations; i++) { + push(&stack, i); + } + printf("\nBenchmarking pop:\n"); + + for (int i = 1000; i <= iterations; i *= 10) { + benchmark_pop(&stack, i); + for (int i = 0; i < iterations; i++) { + push(&stack, i); + } + } + destroyStack(&stack); + return 0; +} diff --git a/05_hw/stack.c b/05_hw/stack.c index 0964440..2af77d9 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) { @@ -31,7 +32,10 @@ void push(Stack* stack, int data) { void pop(Stack* stack) { Node* temp = stack->top; - stack->top = stack->top->next; + if (temp != NULL) { + stack->top = stack->top->next; + free(temp); + } } Node* searchByValue(Stack* stack, int value) { @@ -40,10 +44,12 @@ Node* searchByValue(Stack* stack, int value) { if (current->data == value) { return current; } + current = current->next; } return NULL; } + Node* searchByIndex(Stack* stack, int index) { Node* current = stack->top; int count = 0; @@ -72,7 +78,9 @@ void traverseStack(Stack* stack) { } bool isEmpty(Stack* stack) { - free(stack->top); - return stack->top == NULL; + bool temp = false; + if(stack->top == NULL){ + temp = true; + } + return temp; } - diff --git a/05_hw/tests.c b/05_hw/tests.c new file mode 100644 index 0000000..c016dcb --- /dev/null +++ b/05_hw/tests.c @@ -0,0 +1,177 @@ +#include "stack.h" +#include +#include + +void test_createNode() { + Node* node = createNode(123); + + assert(node != NULL); + assert(node->data == 123); + assert(node->next == NULL); + + free(node); + printf("test_createNode passed.\n"); +} + +void test_initStack() { + Stack stack; + initStack(&stack); + + assert(isEmpty(&stack) == true); + printf("test_initStack passed.\n"); +} + +void test_destroyStack() { + Stack stack; + initStack(&stack); + + push(&stack, 4); + push(&stack, 5); + + destroyStack(&stack); + + assert(isEmpty(&stack) == true); + printf("test_destroyStack passed.\n"); +} + +void test_push() { + Stack stack; + initStack(&stack); + + push(&stack, 3); + assert(getTop(&stack)->data == 3); + + push(&stack, -2); + assert(getTop(&stack)->data == -2); + + destroyStack(&stack); + printf("test_push passed.\n"); +} + +void test_pop() { + Stack stack; + initStack(&stack); + + push(&stack, 1); + push(&stack, 2); + + assert(getTop(&stack)->data == 2); + pop(&stack); + assert(getTop(&stack)->data == 1); + pop(&stack); + + assert(isEmpty(&stack) == true); + + destroyStack(&stack); + printf("test_pop passed.\n"); +} + +void test_searchByValue() { + Stack stack; + initStack(&stack); + + push(&stack, 15); + push(&stack, 2); + push(&stack, -12); + push(&stack, 14); + push(&stack, 12); + push(&stack, 5); + + Node* result = searchByValue(&stack, 12); + assert(result != NULL && result->data == 12); + + result = searchByValue(&stack, -12); + assert(result != NULL && result->data == -12); + + assert(searchByValue(&stack, 33) == NULL); + + destroyStack(&stack); + printf("test_searchByValue passed.\n"); +} + +void test_searchByIndex() { + Stack stack; + initStack(&stack); + + push(&stack, 1); + push(&stack, 2); + push(&stack, 3); + push(&stack, 4); + push(&stack, 5); + + Node* result = searchByIndex(&stack, 0); + assert(result != NULL && result->data == 5); + + result = searchByIndex(&stack, 2); + assert(result != NULL && result->data == 3); + + assert(searchByIndex(&stack, 12) == NULL); + + destroyStack(&stack); + printf("test_searchByIndex passed.\n"); +} + +void test_traverseStack() { + Stack stack; + initStack(&stack); + + push(&stack, 11); + push(&stack, 12); + push(&stack, 13); + + // Ожидаем, что будет выведено: 30 20 10 + printf("Expected values: Stack elements: 13 12 11\n"); + printf("Actual values: "); + + traverseStack(&stack); + + destroyStack(&stack); + printf("test_traverseStack passed.\n"); +} + +void test_isEmpty() { + Stack stack; + initStack(&stack); + + assert(isEmpty(&stack) == true); + + push(&stack, 42); + assert(isEmpty(&stack) == false); + + pop(&stack); + assert(isEmpty(&stack) == true); + destroyStack(&stack); + printf("test_isEmpty passed.\n"); +} + + +void test_getTop() { + Stack stack; + initStack(&stack); + + push(&stack, 100); + assert(getTop(&stack)->data == 100); + + push(&stack, 200); + assert(getTop(&stack)->data == 200); + + destroyStack(&stack); + printf("test_getTop passed.\n"); +} + +int main() { + test_createNode(); + test_initStack(); + test_destroyStack(); + test_push(); + test_pop(); + test_searchByValue(); + test_searchByIndex(); + test_traverseStack(); + test_isEmpty(); + test_getTop(); + + printf("All tests passed.\n"); + + return 0; +} diff --git "a/05_hw/\320\233\320\2401_\320\224\321\203\320\261\320\272\320\276\320\262_\320\23423\320\230\320\222\320\242-1.docx" "b/05_hw/\320\233\320\2401_\320\224\321\203\320\261\320\272\320\276\320\262_\320\23423\320\230\320\222\320\242-1.docx" new file mode 100644 index 0000000..0ba1a1c Binary files /dev/null and "b/05_hw/\320\233\320\2401_\320\224\321\203\320\261\320\272\320\276\320\262_\320\23423\320\230\320\222\320\242-1.docx" differ