diff --git a/.github/workflows/c-cpp.yml b/.github/workflows/c-cpp.yml new file mode 100644 index 0000000..fc221e9 --- /dev/null +++ b/.github/workflows/c-cpp.yml @@ -0,0 +1,32 @@ +name: C/C++ CI + +on: + push: + branches: [ "main" ] + pull_request: + branches: [ "main" ] + +jobs: + build: + + runs-on: ubuntu-latest + + steps: + - name: checkout + uses: actions/checkout@v4 + + + - name: get gcc + run: | + sudo apt-get update + sudo apt-get install -y build-essential gcc + + - name: tests + run: | + gcc -fsanitize=address 05_hw/tests.c -o tests.exe + ./tests.exe + + + + + diff --git a/05_hw/benchmarks.c b/05_hw/benchmarks.c new file mode 100644 index 0000000..555fa04 --- /dev/null +++ b/05_hw/benchmarks.c @@ -0,0 +1,73 @@ +#include +#include +#include + +#include "stack.h" +#include "stack.c" + +void benchmark_push(Stack* stack, int ITEMS){ + //Start the clock + clock_t start = clock(); + + //Push X elements + for (int i = 0; i < ITEMS; i++){ + push(stack, i); + } + + //Stop the clock + clock_t end = clock(); + + //Calculate the time + float benchmark_time = (float)(end - start) / CLOCKS_PER_SEC; + + printf("Time taken to complete push benchmark (%d elements): %.5f seconds\n", ITEMS, benchmark_time); + +} + +void benchmark_pop(Stack* stack, int ITEMS){ + + //Start the clock + clock_t start = clock(); + + + //Pop X elements + for (int i = 0; i < ITEMS; i++){ + pop(stack); + } + + //Stop the clock + clock_t end = clock(); + + //Calculate the time + float benchmark_time = (float)(end - start) / CLOCKS_PER_SEC; + + printf("Time taken to complete pop benchmark (%d elements): %.5f seconds\n", ITEMS, benchmark_time); + +} + +int main(){ + + //Test with different num of elements + int NUMBER_TESTS[] = {1000, 10000, 1000000}; + + + //Do 3 benchmarks + for (int i = 0; i < 3; i++){ + //Stack init + Stack stack; + initStack(&stack); + + benchmark_push(&stack, NUMBER_TESTS[i]); + + for (int i = 0; i < NUMBER_TESTS[i]; i++){ + push(&stack, i); + } + + benchmark_pop(&stack, NUMBER_TESTS[i]); + + destroyStack(&stack); + } + + return 0; + +} \ No newline at end of file diff --git a/05_hw/main.c b/05_hw/main.c index fded814..50168df 100644 --- a/05_hw/main.c +++ b/05_hw/main.c @@ -1,6 +1,7 @@ #include "stack.h" #include +#include "stack.c" int main() { Stack stack; @@ -18,14 +19,14 @@ int main() { printf("After popping an element:\n"); traverseStack(&stack); - Node* searchResult = searchByValue(&stack, 20); + const Node* searchResult = searchByValue(&stack, 20); if (searchResult != NULL) { printf("Element with value 20 found.\n"); } else { printf("Element with value 20 not found.\n"); } - Node* topElement = getTop(&stack); + const Node* topElement = getTop(&stack); if (topElement != NULL) { printf("Top element: %d\n", topElement->data); } diff --git a/05_hw/report.txt b/05_hw/report.txt new file mode 100644 index 0000000..aa38cd4 --- /dev/null +++ b/05_hw/report.txt @@ -0,0 +1,17 @@ +Running: cppcheck --enable=all --template={"file":"{file}","line":{line},"column":{column},"severity":"{severity}","message":"{message}","id":"{id}"}, c:\Users\User\Desktop\works\lecture-testing-task-main\05_hw\main.c +Checking c:\Users\User\Desktop\works\lecture-testing-task-main\05_hw\main.c ... + +{"file":"c:\Users\User\Desktop\works\lecture-testing-task-main\05_hw\stack.h","line":3,"column":0,"severity":"information","message":"Include file: not found. Please note: Cppcheck does not need standard library headers to get proper results.","id":"missingIncludeSystem"}, +{"file":"c:\Users\User\Desktop\works\lecture-testing-task-main\05_hw\main.c","line":3,"column":0,"severity":"information","message":"Include file: not found. Please note: Cppcheck does not need standard library headers to get proper results.","id":"missingIncludeSystem"}, +{"file":"c:\Users\User\Desktop\works\lecture-testing-task-main\05_hw\stack.c","line":1,"column":0,"severity":"information","message":"Include file: not found. Please note: Cppcheck does not need standard library headers to get proper results.","id":"missingIncludeSystem"}, +{"file":"c:\Users\User\Desktop\works\lecture-testing-task-main\05_hw\stack.c","line":2,"column":0,"severity":"information","message":"Include file: not found. Please note: Cppcheck does not need standard library headers to get proper results.","id":"missingIncludeSystem"}, + +{"file":"c:\Users\User\Desktop\works\lecture-testing-task-main\05_hw\main.c","line":22,"column":11,"severity":"style","message":"Variable 'searchResult' can be declared as pointer to const","id":"constVariablePointer"}, +{"file":"c:\Users\User\Desktop\works\lecture-testing-task-main\05_hw\main.c","line":29,"column":11,"severity":"style","message":"Variable 'topElement' can be declared as pointer to const","id":"constVariablePointer"}, +{"file":"c:\Users\User\Desktop\works\lecture-testing-task-main\05_hw\stack.c","line":71,"column":21,"severity":"style","message":"Parameter 'stack' can be declared as pointer to const","id":"constParameterPointer"}, +{"file":"c:\Users\User\Desktop\works\lecture-testing-task-main\05_hw\stack.c","line":85,"column":21,"severity":"style","message":"Parameter 'stack' can be declared as pointer to const","id":"constParameterPointer"}, + +{"file":"c:\Users\User\Desktop\works\lecture-testing-task-main\05_hw\stack.c","line":21,"column":6,"severity":"style","message":"The function 'destroyStack' is never used.","id":"unusedFunction"}, +{"file":"c:\Users\User\Desktop\works\lecture-testing-task-main\05_hw\stack.c","line":58,"column":7,"severity":"style","message":"The function 'searchByIndex' is never used.","id":"unusedFunction"}, +{"file":"c:\Users\User\Desktop\works\lecture-testing-task-main\05_hw\stack.c","line":85,"column":6,"severity":"style","message":"The function 'isEmpty' is never used.","id":"unusedFunction"}, +{"file":"c:\Users\User\Desktop\works\lecture-testing-task-main\05_hw\stack.c","line":6,"column":7,"severity":"style","message":"The function 'createNode' should have static linkage since it is not used outside of its translation unit.","id":"staticFunction"}, \ No newline at end of file diff --git a/05_hw/stack.c b/05_hw/stack.c index 0964440..32546f9 100644 --- a/05_hw/stack.c +++ b/05_hw/stack.c @@ -5,6 +5,10 @@ Node* createNode(int data) { Node* newNode = (Node*)malloc(sizeof(Node)); + if (newNode == NULL){ + printf("malloc failure"); + exit(EXIT_FAILURE); + } newNode->data = data; newNode->next = NULL; return newNode; @@ -17,10 +21,11 @@ void initStack(Stack* stack) { void destroyStack(Stack* stack) { Node* current = stack->top; while (current != NULL) { - Node *tmp = current; + Node* tmp = current; current = current->next; free(tmp); } + stack->top = NULL; } void push(Stack* stack, int data) { @@ -30,8 +35,13 @@ void push(Stack* stack, int data) { } void pop(Stack* stack) { + if (stack->top == NULL){ + printf("Attempting to pop an empty stack\n"); + return; + } Node* temp = stack->top; stack->top = stack->top->next; + free(temp); } Node* searchByValue(Stack* stack, int value) { @@ -40,6 +50,7 @@ Node* searchByValue(Stack* stack, int value) { if (current->data == value) { return current; } + current = current->next; } return NULL; } @@ -57,7 +68,7 @@ Node* searchByIndex(Stack* stack, int index) { return NULL; } -Node* getTop(Stack* stack) { +Node* getTop(Stack* const stack) { return stack->top; } @@ -71,8 +82,7 @@ void traverseStack(Stack* stack) { printf("\n"); } -bool isEmpty(Stack* stack) { - free(stack->top); +bool isEmpty(Stack* const stack) { return stack->top == NULL; } diff --git a/05_hw/stack.h b/05_hw/stack.h index ef0734e..8228d4b 100644 --- a/05_hw/stack.h +++ b/05_hw/stack.h @@ -19,7 +19,7 @@ Node* createNode(int data); void initStack(Stack* stack); -void destroyStack(Stack *stack); +void destroyStack(Stack* stack); void push(Stack* stack, int data); diff --git a/05_hw/tests.c b/05_hw/tests.c new file mode 100644 index 0000000..7822630 --- /dev/null +++ b/05_hw/tests.c @@ -0,0 +1,316 @@ +#include +#include +#include + +#include "stack.h" +#include "stack.c" + + +//Test destroyStack() +void test_destroyStack(){ + Stack stack; + initStack(&stack); + + push(&stack, 1); + push(&stack, 2); + + destroyStack(&stack); + assert(stack.top == NULL); + + printf("test_destroyStack() passed\n"); + +} + +void test_destroyStack_empty(){ + Stack stack; + initStack(&stack); + + destroyStack(&stack); + assert(stack.top == NULL); + + printf("test_destroyStack_empty() passed\n"); + +} + +//Test push() +void test_push(){ + + Stack stack; + initStack(&stack); + + push(&stack, 1); + assert(stack.top != NULL); + + destroyStack(&stack); + + printf("test_push() passed\n"); + +} + +//Test pop() +void test_pop(){ + + Stack stack; + initStack(&stack); + + push(&stack, 1); + pop(&stack); + assert(stack.top == NULL); + + destroyStack(&stack); + + printf("test_pop() passed\n"); + +} + +void test_pop_empty(){ + + Stack stack; + initStack(&stack); + + pop(&stack); + + destroyStack(&stack); + + printf("test_pop_empty() passed\n"); + +} + +//Test searchByValue() +void test_searchByValue_existing(){ + Stack stack; + initStack(&stack); + + push(&stack, 1); + push(&stack, 2); + push(&stack, 3); + push(&stack, 4); + push(&stack, 5); + + Node* result = searchByValue(&stack, 5); + assert(result != NULL && result->data == 5); + + destroyStack(&stack); + + printf("test_searchByValue_existing() passed\n"); + +} + +void test_searchByValue_nonexisting(){ + Stack stack; + initStack(&stack); + + push(&stack, 1); + push(&stack, 2); + push(&stack, 3); + push(&stack, 4); + push(&stack, 5); + + Node* result = searchByValue(&stack, 10); + assert(result == NULL); + + destroyStack(&stack); + + printf("test_searchByValue_nonexisting() passed\n"); + +} + +void test_searchByValue_empty(){ + Stack stack; + initStack(&stack); + + Node* result = searchByValue(&stack, 10); + assert(result == NULL); + + destroyStack(&stack); + + printf("test_searchByValue_empty() passed\n"); + +} + +//Test searchByIndex() +void test_searchByIndex_existing(){ + Stack stack; + initStack(&stack); + + push(&stack, 1); + push(&stack, 2); + push(&stack, 3); + push(&stack, 4); + push(&stack, 5); + + Node* result = searchByIndex(&stack, 2); + assert(result != NULL && result->data == 3); + + destroyStack(&stack); + + printf("test_searchByIndex_existing() passed\n"); + +} + +void test_searchByIndex_nonexisting(){ + Stack stack; + initStack(&stack); + + push(&stack, 1); + push(&stack, 2); + push(&stack, 3); + push(&stack, 4); + push(&stack, 5); + + Node* result = searchByIndex(&stack, 10); + assert(result == NULL); + + destroyStack(&stack); + + printf("test_searchByIndex_nonexisting() passed\n"); + +} + +void test_searchByIndex_empty(){ + Stack stack; + initStack(&stack); + + Node* result = searchByIndex(&stack, 10); + assert(result == NULL); + + destroyStack(&stack); + + printf("test_earchByIndex_empty() passed\n"); + +} + +//Test getTop() +void test_getTop(){ + Stack stack; + initStack(&stack); + + push(&stack, 1); + push(&stack, 2); + push(&stack, 3); + push(&stack, 4); + push(&stack, 5); + + Node* result = getTop(&stack); + assert(result != NULL && result->data == 5); + + destroyStack(&stack); + + printf("test_getTop() passed\n"); + +} + +void test_getTop_empty(){ + Stack stack; + initStack(&stack); + + Node* result = getTop(&stack); + assert(result == NULL); + + destroyStack(&stack); + + printf("test_getTop_empty() passed\n"); + +} + +//Test traverseStack() +void test_traverseStack(){ + Stack stack; + initStack(&stack); + + push(&stack, 1); + push(&stack, 2); + push(&stack, 3); + push(&stack, 4); + push(&stack, 5); + + printf("Expected result: 5 4 3 2 1\n"); + printf("Function output:"); + traverseStack(&stack); + + destroyStack(&stack); + + printf("test_traverseStack() passed\n"); + +} + +void test_traverseStack_empty(){ + Stack stack; + initStack(&stack); + + printf("Expected result: ' '\n"); + printf("Function output:"); + traverseStack(&stack); + + destroyStack(&stack); + + printf("test_traverseStack_empty() passed\n"); + +} + +//Test isEmpty() +void test_isEmpty(){ + Stack stack; + initStack(&stack); + + push(&stack, 1); + push(&stack, 2); + push(&stack, 3); + push(&stack, 4); + push(&stack, 5); + + assert(isEmpty(&stack) == false); + + destroyStack(&stack); + + printf("test_isEmpty() passed\n"); +} + +void test_isEmpty_empty(){ + Stack stack; + initStack(&stack); + + assert(isEmpty(&stack) == true); + + destroyStack(&stack); + + printf("test_isEmpty_empty() passed\n"); +} + +int main(){ + + printf("\n"); + test_destroyStack(); + test_destroyStack_empty(); + + printf("\n"); + test_push(); + test_pop(); + test_pop_empty(); + + printf("\n"); + test_searchByValue_existing(); + test_searchByValue_nonexisting(); + test_searchByValue_empty(); + + printf("\n"); + test_searchByIndex_existing(); + test_searchByIndex_nonexisting(); + test_searchByIndex_empty(); + + printf("\n"); + test_getTop(); + test_getTop_empty(); + + printf("\n"); + test_traverseStack(); + test_destroyStack_empty(); + + printf("\n"); + test_isEmpty(); + test_isEmpty_empty(); + + printf("\n"); + printf("All tests passed\n"); + +} \ No newline at end of file