diff --git a/.github/workflows/cicd_workflow.yml b/.github/workflows/cicd_workflow.yml new file mode 100644 index 0000000..7cf8e67 --- /dev/null +++ b/.github/workflows/cicd_workflow.yml @@ -0,0 +1,47 @@ +name: CI + +on: + push: + branches: [ "hw1" ] + pull_request: + branches: [ "main" ] + + +jobs: + build: + + runs-on: ubuntu-latest + container: leshiy1295/gcc_linters_valgrind_cmake_gtest + + steps: + - uses: actions/checkout@v3 + + - name: build + run: cmake ./hw1 -B ./hw1/build + + - name: make & run + # Build your program with the given configuration + working-directory: ./hw1/build + run: | + make + ./solution + + - name: test + working-directory: ./hw1/build/tests + run: ./test_solution + + - name: test coverage + working-directory: ./hw1/build + run: | + apt install lcov -y + lcov -t "tests/test_solution" -o coverage.info -c -d src + genhtml -o report coverage.info + + - name: valgrind + working-directory: ./hw1/build/ + run: valgrind --tool=memcheck --leak-check=yes ./solution + + - name: valgrind test + working-directory: ./hw1/build/tests + run: valgrind --tool=memcheck --leak-check=yes ./test_solution + diff --git a/hw1/CMakeLists.txt b/hw1/CMakeLists.txt new file mode 100644 index 0000000..9931089 --- /dev/null +++ b/hw1/CMakeLists.txt @@ -0,0 +1,18 @@ +cmake_minimum_required(VERSION 3.14) +project(solution) + +set(CMAKE_C_FLAGS ${CMAKE_C_FLAGS} "-lm -Wall -Wpedantic -Wextra -Werror -fprofile-arcs -ftest-coverage -O0") + +add_subdirectory(src) + +message("PRINTER_LIB_INCLUDE_DIRS = ${SRC_LIB_INCLUDE_DIR}") +message("PRINTER_LIB_LIBRARIES = ${SRC_LIB_LIBRARIES}") + +add_executable(${PROJECT_NAME} main.c) + +#set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -coverage -lgcov" ) + +target_include_directories(${PROJECT_NAME} PUBLIC ${SRC_LIB_INCLUDE_DIR}) +target_link_libraries(${PROJECT_NAME} PRIVATE ${SRC_LIB_LIBRARIES}) + +add_subdirectory(tests) \ No newline at end of file diff --git a/hw1/README.md b/hw1/README.md new file mode 100644 index 0000000..fff95b9 --- /dev/null +++ b/hw1/README.md @@ -0,0 +1 @@ +Составить программу нахождения минимальной площади грани тетраэдра, заданного 4 вершинами. Оформить решение в виде функции, принимающей на вход указатели на координаты вершин тетраэдра. На выходе функция должна возвращать указатель на значение площади наименьшей грани. \ No newline at end of file diff --git a/hw1/main.c b/hw1/main.c new file mode 100644 index 0000000..498c7d5 --- /dev/null +++ b/hw1/main.c @@ -0,0 +1,37 @@ +#include +#include"solution.h" +#include + +int main(){ + FILE* fp = fopen("../test.txt","r"); + if (!fp){ + return -1; + } + Point* a = malloc(sizeof(Point)); + Point* b = malloc(sizeof(Point)); + Point* c = malloc(sizeof(Point)); + Point* d = malloc(sizeof(Point)); + + if (fscanf(fp, "%f %f %f", &a->x, &a->y, &a->z) != 3){ + return -1; + } + if (fscanf(fp, "%f %f %f", &b->x, &b->y, &b->z) != 3){ + return -1; + }; + if (fscanf(fp, "%f %f %f", &c->x, &c->y, &c->z) != 3){ + return -1; + }; + if (fscanf(fp, "%f %f %f", &d->x, &d->y, &d->z) != 3){ + return -1; + }; + fclose(fp); + + float* result = min_area_tetrahedron(a, b, c, d); + printf("result %f, %p \n", *result, (void *) result); + + free(a); + free(b); + free(c); + free(d); + return 0; +} diff --git a/hw1/src/CMakeLists.txt b/hw1/src/CMakeLists.txt new file mode 100644 index 0000000..3d3c7df --- /dev/null +++ b/hw1/src/CMakeLists.txt @@ -0,0 +1,12 @@ +cmake_minimum_required(VERSION 3.0.0) +project(solution_lib) + +set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fprofile-arcs -ftest-coverage -O0") + +file(GLOB SOURCES *.c) +file(GLOB INCLUDE_DIRS ${CMAKE_CURRENT_SOURCE_DIR}) + +add_library(${PROJECT_NAME} STATIC ${SOURCES}) + +set(SRC_LIB_LIBRARIES ${PROJECT_NAME} PARENT_SCOPE) +set(SRC_LIB_INCLUDE_DIR ${INCLUDE_DIRS} PARENT_SCOPE) \ No newline at end of file diff --git a/hw1/src/solution.c b/hw1/src/solution.c new file mode 100644 index 0000000..0deb259 --- /dev/null +++ b/hw1/src/solution.c @@ -0,0 +1,73 @@ +#include"solution.h" +#include +#include +#include + +Vector* cross_product(Vector* a, Vector* b){ + if (!a || !b){ + return NULL; + } + Vector* v = malloc(sizeof(Vector)); + v->i = a->k * b->j - a->j * b->k; + v->j = a->i * b->k - a->k * b->i; + v->k = a->j * b->i - a->i * b->j; + return v; +} + +float vector_norm(Vector* v){ + if (!v){ + return -1; + } + return sqrt((v->i * v->i + v->j * v->j + v->k * v->k)); +} + +float area_triangle(Point* a, Point* b, Point* c){ + if (!a || !b || !c){ + return -1; + } + Vector* v = malloc(sizeof(Vector)); + v->i = c->x - a->x; + v->j = c->y - a->y; + v->k = c->z - a->z; + + Vector* u = malloc(sizeof(Vector)); + u->i = b->x - a->x; + u->j = b->y - a->y; + u->k = b->z - a->z; + + Vector* w = cross_product(v, u); + w->i = w->i / 2; + w->j = w->j / 2; + w->k = w->k / 2; + free(v); + free(u); + + float area = vector_norm(w); + free(w); + + return area; +} + +float* min_area_tetrahedron(Point* a, Point* b, Point* c, Point* d){ + if (!a || !b || !c || !d){ + return NULL; + } + static float min_area; + + const float s0 = area_triangle(a, b, c); + const float s1 = area_triangle(a, b, d); + const float s2 = area_triangle(a, c, d); + const float s3 = area_triangle(b, c, d); + min_area = s0; + + if (min_area > s1){ + min_area = s1; + } + if (min_area > s2){ + min_area = s2; + } + if (min_area > s3){ + min_area = s3; + } + return &min_area; +} diff --git a/hw1/src/solution.h b/hw1/src/solution.h new file mode 100644 index 0000000..880f7a8 --- /dev/null +++ b/hw1/src/solution.h @@ -0,0 +1,19 @@ +typedef struct Point{ + float x; + float y; + float z; +} Point; + +typedef struct Vector{ + float i; + float j; + float k; +} Vector; + +Vector* cross_product(Vector* a, Vector* b); + +float vector_norm(Vector* v); + +float area_triangle(Point* a, Point* b, Point* c); + +float* min_area_tetrahedron(Point* a, Point* b, Point* c, Point* d); diff --git a/hw1/test.txt b/hw1/test.txt new file mode 100644 index 0000000..1a0340c --- /dev/null +++ b/hw1/test.txt @@ -0,0 +1,4 @@ +0 0 0 +0 0 3 +0 1 0 +2 0 0 \ No newline at end of file diff --git a/hw1/tests/CMakeLists.txt b/hw1/tests/CMakeLists.txt new file mode 100644 index 0000000..fdd1da6 --- /dev/null +++ b/hw1/tests/CMakeLists.txt @@ -0,0 +1,14 @@ +cmake_minimum_required(VERSION 3.14) +project(test_solution) + +set(CMAKE_CXX_STANDARD 14) +set(CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS} "-fprofile-arcs -ftest-coverage -O0 -fsanitize=address,undefined -fno-sanitize-recover=all -fsanitize-undefined-trap-on-error") +set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -coverage -lgcov" ) + +file(GLOB SOURCES *.cpp) + +find_package(GTest REQUIRED) + +add_executable(${PROJECT_NAME} ${SOURCES}) +target_include_directories(${PROJECT_NAME} PUBLIC ${SRC_LIB_INCLUDE_DIR}) +target_link_libraries(${PROJECT_NAME} ${SRC_LIB_LIBRARIES} GTest::gtest_main) \ No newline at end of file diff --git a/hw1/tests/solution_test.cpp b/hw1/tests/solution_test.cpp new file mode 100644 index 0000000..b8fb907 --- /dev/null +++ b/hw1/tests/solution_test.cpp @@ -0,0 +1,77 @@ +#include +#include +#include + +extern "C" { + #include +} + +TEST(Src, TestBasics) { + FILE* fp = fopen("../../test.txt","r"); + Point *a = (Point*) malloc(sizeof(Point)); + Point *b = (Point*) malloc(sizeof(Point)); + Point *c = (Point*) malloc(sizeof(Point)); + Point *d = (Point*) malloc(sizeof(Point)); + + fscanf(fp, "%f %f %f", &a->x, &a->y, &a->z); + fscanf(fp, "%f %f %f", &b->x, &b->y, &b->z); + fscanf(fp, "%f %f %f", &c->x, &c->y, &c->z); + fscanf(fp, "%f %f %f", &d->x, &d->y, &d->z); + fclose(fp); + + float * result; + result = min_area_tetrahedron(a, b, c, d); + + EXPECT_FLOAT_EQ(1, *result); + free(a); + free(b); + free(c); + free(d); +} + +TEST(Src, TestBasicsPermute1) { + FILE* fp = fopen("../../test.txt","r"); + Point *a = (Point*) malloc(sizeof(Point)); + Point *b = (Point*) malloc(sizeof(Point)); + Point *c = (Point*) malloc(sizeof(Point)); + Point *d = (Point*) malloc(sizeof(Point)); + + fscanf(fp, "%f %f %f", &b->x, &b->y, &b->z); + fscanf(fp, "%f %f %f", &a->x, &a->y, &a->z); + fscanf(fp, "%f %f %f", &c->x, &c->y, &c->z); + fscanf(fp, "%f %f %f", &d->x, &d->y, &d->z); + fclose(fp); + + float * result; + result = min_area_tetrahedron(a, b, c, d); + + EXPECT_FLOAT_EQ(1, *result); + free(a); + free(b); + free(c); + free(d); +} + +TEST(Src, TestBasicsPermute2) { + FILE* fp = fopen("../../test.txt","r"); + + Point *a = (Point*) malloc(sizeof(Point)); + Point *b = (Point*) malloc(sizeof(Point)); + Point *c = (Point*) malloc(sizeof(Point)); + Point *d = (Point*) malloc(sizeof(Point)); + + fscanf(fp, "%f %f %f", &b->x, &b->y, &b->z); + fscanf(fp, "%f %f %f", &c->x, &c->y, &c->z); + fscanf(fp, "%f %f %f", &a->x, &a->y, &a->z); + fscanf(fp, "%f %f %f", &d->x, &d->y, &d->z); + fclose(fp); + + float * result; + result = min_area_tetrahedron(a, b, c, d); + + EXPECT_FLOAT_EQ(1, *result); + free(a); + free(b); + free(c); + free(d); +}