diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..42f47ad --- /dev/null +++ b/.travis.yml @@ -0,0 +1,66 @@ +#Лучший гайд: https://habr.com/ru/post/329264/ + +dist: focal # используем Ubuntu 20.04 Focal Fossa +sudo: required # используем Virtual Machine (а не Docker container) + +language: c # на практике разницы между специфичным для C++ окружением + # и, скажем, python -- никакой. Но пусть будет cpp. + +os: + # будем прогонять CI и на Linux, и на Mac OS X... + - linux + #- osx + +compiler: + # ... и с помощью GCC, и Clang + - gcc + #- clang + +env: + # список переменных окружения, влияющих на матрицу сборки: + - BUILD_CONFIGURATION=Debug + - BUILD_CONFIGURATION=Release + #- TARGET_CPU=amd64 + +matrix: + exclude: + # вручную исключим ненужные элементы из матрицы сборки: + - os: osx + compiler: gcc + +install: + # скрипт настройки среды и установки зависимостей: + - source testing/ci-install-$TRAVIS_OS_NAME.sh + +script: + + #accuracy: + - cppcheck --error-exitcode=1 --suppress=missingIncludeSystem --enable=style,performance,portability,warning project/ + + # скрипт сборки и тестирования проекта: + - mkdir build + - cd build + - cmake .. -DCMAKE_BUILD_TYPE=$BUILD_CONFIGURATION -DCMAKE_CXX_FLAGS="--coverage" + # -DTARGET_CPU=$TARGET_CPU + - cmake --build . + + - ctest --output-on-failure + #- gcovr -r .. + - lcov --directory . --capture --output-file coverage.info + - lcov --remove coverage.info '/usr/*' "${HOME}"'/.cache/*' --output-file coverage.info + - lcov --list coverage.info + #- codecov + - curl -s https://codecov.io/bash > .codecov + - chmod +x .codecov + - ./.codecov + + #safety: + - valgrind --error-exitcode=1 --tool=memcheck --leak-check=full ./program ../testing/logic/cases/17.txt + +after_success: + # public: + - bash <(curl -s https://codecov.io/bash) + + + #private + #- bash <(curl -s https://codecov.io/bash) -t your-repository-upload-token diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..d58d386 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,24 @@ +cmake_minimum_required(VERSION 3.16) +project(hw1) +set(CMAKE_C_STANDARD 11) + +set(CMAKE_C_FLAGS "-g -coverage -O0 -Wall -fprofile-arcs -ftest-coverage -fPIC") +set(CMAKE_CXX_FLAGS "-g -coverage -O0 -Wall -fprofile-arcs -ftest-coverage -fPIC") +set(CMAKE_CXX_OUTPUT_EXTENSION_REPLACE 1) + +include_directories(project/include/) +add_executable(program project/src/program.c project/src/hw-1.c) + +enable_testing() +find_package(GTest REQUIRED) + +include_directories(${GTEST_INCLUDE_DIRS}) +message(${GTEST_LIBRARIES}) +message(${GTEST_INCLUDE_DIRS}) + +add_executable(tests testing/tests.cpp) +target_link_libraries(tests ${GTEST_LIBRARIES} -lpthread) + +add_test(program_and_functions_test ./tests) +add_definitions(-fprofile-arcs -ftest-coverage) +target_link_libraries(tests -fprofile-arcs) diff --git a/README.md b/README.md index 657ccef..4060c09 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,6 @@ # [Techno] CPP -Домашки Турчина Дениса +Домашки Дениса Турчина +АПО-13 Вар 74 + +# Вариант #74 +Разработать программу, которая на вход принимает исходный код на языке C, находит в нём все комментарии (однострочные и многострочные) и для каждого из них заполняет структуру, содержащую информацию о тексте комментария, его типе и о номерах строк, на которых он расположен. В результате должен получиться список таких структур, который нужно вывести на экран. diff --git a/project/include/hw-1.h b/project/include/hw-1.h new file mode 100644 index 0000000..3aa300b --- /dev/null +++ b/project/include/hw-1.h @@ -0,0 +1,44 @@ +// +// Created by denactive on 12.03.2021. +// +#ifndef PROJECT_HW_1_H +#define PROJECT_HW_1_H + +#include +#include +#include +#include +#include +#include +#include +#include + +#define BUFFER_SIZE 1024 +#define SYNTAX_ERROR 1 + +enum { + single, + multiline +}; + +typedef struct { + char* beg; + char* end; + size_t line; + unsigned int type; +} comment; + +int parse_comments(const char* str, size_t *line_cnt, comment **res, size_t *comments_amount); + +char* execute_line_comment(const char *str, size_t *line_cnt, comment **res, size_t *comments_amount); +char* execute_multiline_comment(const char *str, size_t *line_cnt, comment **res, size_t *comments_amount); + +int res_exp(comment **res, size_t *comments_amount); +int free_res(comment **res); +void print_res(const comment *res, size_t *comments_amount); +void print_comment(const comment* c); + +char* console_input(); +char* file_input(const char *filename, struct stat* stat_buf); + +#endif //PROJECT_HW_1_H \ No newline at end of file diff --git a/project/src/hw-1.c b/project/src/hw-1.c new file mode 100644 index 0000000..3a5bd8d --- /dev/null +++ b/project/src/hw-1.c @@ -0,0 +1,272 @@ +// +// Created by denactive on 12.03.2021. +// + +#include "hw-1.h" + +char* skip_to_single_quote(const char *str, size_t *line_cnt); +char* skip_to_double_quote(const char *str, size_t *line_cnt); + +// starts from a sym after ' and returns a sym after closing ' +char* skip_to_single_quote(const char* str, size_t *line_cnt) { + if (!line_cnt || !str) + return NULL; + while (*str != '\'') { + if (*str == '\n') + (*line_cnt)++; + if (*str == NULL || *str == EOF || *str == '\0') + return NULL; + // \' avoidance + if (*str == '\\') { + str++; + if (*str == NULL || *str == EOF || *str == '\0') + str--; + } + str++; + } + return (char*)str + 1; +} + +// starts from a sym after " and returns a sym after closing " +char* skip_to_double_quote(const char* str, size_t *line_cnt) { + if (!line_cnt || !str) + return NULL; + while (*str != '\"') { + if (*str == '\n') + (*line_cnt)++; + if (*str == NULL || *str == EOF || *str == '\0') + return NULL; + // \" avoidance + if (*str == '\\') { + str++; + if (*str == NULL || *str == EOF || *str == '\0') + str--; + } + str++; + } + return (char*)str + 1; +} + +char* execute_line_comment(const char *str, size_t *line_cnt, comment **res, size_t *comments_amount) { + if (!line_cnt || !res || !comments_amount || !str) + return NULL; + comment executed = {(char*)str, NULL, *line_cnt, single}; + + while (*str != '\n') { + if (*str == NULL || *str == EOF || *str == '\0') + return NULL; + str++; + } + executed.end = (char*)str - 1; + + // saving + if (res_exp(res, comments_amount)) + return NULL; + + (*res)[(*comments_amount) - 1] = executed; + (*line_cnt)++; + return (char*)str + 1; +} + +char* execute_multiline_comment(const char *str, size_t *line_cnt, comment **res, size_t *comments_amount) { + if (!line_cnt || !res || !comments_amount || !str) + return NULL; + // we are here after /* symbols. + comment executed = {(char*)str, NULL, *line_cnt, single}; + + // an exception for /*/ smtg */ situation + if (*str == '/') + str++; + + // totally safe :) + while (*str != '/' || *(str - 1) != '*') { + if (*str == '\n') { + executed.type = multiline; + (*line_cnt)++; + } + if (*str == NULL || *str == EOF || *str == '\0') + return NULL; + str++; + } + executed.end = (char*)str - 2; + + // saving + if (res_exp(res, comments_amount)) + return NULL; + + (*res)[(*comments_amount) - 1] = executed; + return (char*)str + 1; +} + +int res_exp(comment **res, size_t *comments_amount) { + if (!comments_amount) + return -1; + + size_t size = 0; + if (*comments_amount == 0) { + size = sizeof(comment); + if (*res) { + free(*res); + *res = NULL; + } + *res = (comment*)malloc(size); + if (*res) { + (*comments_amount)++; + return 0; + } else { + return -1; + } + } else { + size = sizeof(comment) * ((*comments_amount) + 1); + comment *tmp = (comment*)realloc(*res, size); + if (tmp) { + (*comments_amount)++; + *res = tmp; + return 0; + } else { + return -1; + } + } +} + +int free_res(comment **res) { + if (!res) + return -1; + free(*res); + *res = NULL; + return 0; +} + +void print_res(const comment *res, size_t *comments_amount) { + size_t comments_amount_local = 0; + if (comments_amount) + comments_amount_local = *comments_amount; + + printf("=================\n"); + if (!res || comments_amount_local == 0) + printf("no comments found"); + + for (size_t i = 0; i < comments_amount_local; i++) { + printf("[%zu]: ", i); + print_comment(&res[i]); + if (i < comments_amount_local - 1) + printf("\n-----------------\n"); + } + printf("\n=================\n"); +} + +// this function allocates memory! +char *console_input() { + char *input = (char*)malloc(BUFFER_SIZE * sizeof(char)); + if (!input) + return NULL; + + printf("Enter C code | Press Ctrl+D to end the input | >> "); + char sym = '\0'; + for (int i = 0; sym != EOF && i < BUFFER_SIZE; i++) { + sym = getc(stdin); + if (i == BUFFER_SIZE - 1) { + printf("\nWarning: Buffer overflow - only %d symbols were saved", BUFFER_SIZE - 1); + break; + } + input[i] = sym; + } + printf("\n"); + + //safety + input[BUFFER_SIZE - 1] = '\0'; + return input; +} + +void print_comment(const comment* c) { + if (!c) { + printf("An empty comment\n"); + return; + } + printf("line: %zu; type: ", c->line); + if (c->type == single) + printf("single-line;\n"); + if (c->type == multiline) + printf("multiline;\n"); + + for (char* addr = c->beg; addr <= c->end; addr++) + printf("%c", *addr); +} + +char* file_input(const char* filename, struct stat* stat_buf) { + int fdin = 0; + if ((fdin = open(filename, O_RDONLY)) < 0) { + printf("Error | Usage %s invalid\n", filename); + NULL; + } + + // gain file size + if (fstat(fdin, stat_buf) < 0) { + printf("Error | Impossible to get the %s size\n", filename); + return NULL; + } + + // using mmap + void* content = NULL; + if ((content = mmap(0, stat_buf->st_size, PROT_READ, MAP_SHARED, fdin, 0)) == MAP_FAILED) { + printf("Error | mmap error\n"); + return NULL; + } + + return (char*)content; +} + +int parse_comments(const char* str, size_t *line_cnt, comment **res, size_t *comments_amount) { + if (!line_cnt || !res || !comments_amount || !str) + return -1; + + if (*res && *comments_amount == 0) { + free(*res); + *res = NULL; + } + if (*res == NULL) + *comments_amount = 0; + + while (*str != '\0' && *str != NULL && *str != EOF) { + switch (*str) { + case '\"': + str = skip_to_double_quote(str + 1, line_cnt); + if (!str) { + printf("Error | syntax error\n"); + return SYNTAX_ERROR; + } + break; + case '\'': + str = skip_to_single_quote(str + 1, line_cnt); + if (!str) { + printf("Error | syntax error\n"); + return SYNTAX_ERROR; + } + break; + case '\n': + (*line_cnt)++; + str++; + break; + case '/': + if (*(str + 1) == '/') { + str = execute_line_comment(str + 2, line_cnt, res, comments_amount); + if (!str) { + free_res(res); + return -1; + } + } + if (*(str + 1) == '*') { + str = execute_multiline_comment(str + 2, line_cnt, res, comments_amount); + if (!str) { + free_res(res); + return -1; + } + } + break; + default: + str++; + break; + } + } + return 0; +} \ No newline at end of file diff --git a/project/src/program.c b/project/src/program.c new file mode 100644 index 0000000..68ace5b --- /dev/null +++ b/project/src/program.c @@ -0,0 +1,39 @@ +#include "hw-1.h" + +int main(int argc, const char** argv) { + char* input = NULL; + struct stat stat_buf = {}; + + if (argc > 1) { + input = file_input(argv[1], &stat_buf); + } else { + input = console_input(); + } + + if (!input) { + printf("Error | Empty input\n"); + return -1; + } + + comment *res = NULL; + size_t comments_amount = 0; + size_t line_cnt = 1; + int exec_code = parse_comments(input, &line_cnt, &res, &comments_amount); + + if (exec_code == -1) + return -1; + + if (exec_code == 0) + print_res(res, &comments_amount); + + if (argc > 1) { + // file mapping closing + if (munmap((void*)input, stat_buf.st_size)) + printf("Error | failed to unmap %s\n", argv[1]); + } else { + free(input); + } + + free_res(&res); + return 0; +} diff --git a/testing/ci-install-linux.sh b/testing/ci-install-linux.sh new file mode 100644 index 0000000..e68ba17 --- /dev/null +++ b/testing/ci-install-linux.sh @@ -0,0 +1,26 @@ +sudo add-apt-repository -y ppa:ubuntu-toolchain-r/test +sudo apt-get update -qq + +sudo apt-get install -qq g++-5 +sudo update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-5 90 + +sudo apt-get install cmake + +sudo apt-get install libgtest-dev +cd /usr/src/gtest +sudo cmake CMakeLists.txt +sudo make +sudo cp ./lib/libgtest*.a /usr/lib +cd - + +sudo apt-get install -y valgrind + +sudo apt-get install -y cppcheck + +#gcovr +#Installing python is unnesessary +#sudo apt install -y python3-pip +sudo apt-get install python3-setuptools && sudo pip3 install git+https://github.com/gcovr/gcovr.git + +#lcov +sudo apt-get install lcov diff --git a/testing/ci-install-osx.sh b/testing/ci-install-osx.sh new file mode 100644 index 0000000..e69de29 diff --git a/testing/logic/answers/1.txt b/testing/logic/answers/1.txt new file mode 100644 index 0000000..2b73f76 --- /dev/null +++ b/testing/logic/answers/1.txt @@ -0,0 +1,4 @@ +================= +[0]: line: 1; type: single-line; +simple comment +================= diff --git a/testing/logic/answers/10.txt b/testing/logic/answers/10.txt new file mode 100644 index 0000000..cbbc078 --- /dev/null +++ b/testing/logic/answers/10.txt @@ -0,0 +1,5 @@ +================= +[0]: line: 1; type: multiline; +multi +line comments +================= diff --git a/testing/logic/answers/11.txt b/testing/logic/answers/11.txt new file mode 100644 index 0000000..ba49bdd --- /dev/null +++ b/testing/logic/answers/11.txt @@ -0,0 +1,28 @@ +================= +[0]: line: 1; type: multiline; + +h +e +r +e + +"is" + +a + +"really silly" + c + o + m + + + + m + e + 'n' + t +/structure/ +----------------- +[1]: line: 24; type: single-line; + this is a 24th line +================= diff --git a/testing/logic/answers/12.txt b/testing/logic/answers/12.txt new file mode 100644 index 0000000..e07f9b5 --- /dev/null +++ b/testing/logic/answers/12.txt @@ -0,0 +1,16 @@ +================= +[0]: line: 1; type: single-line; +line-1 +----------------- +[1]: line: 2; type: single-line; +line-2 +----------------- +[2]: line: 3; type: single-line; +line-3 +----------------- +[3]: line: 6; type: single-line; +line-6 +----------------- +[4]: line: 9; type: single-line; +line-9 +================= diff --git a/testing/logic/answers/13.txt b/testing/logic/answers/13.txt new file mode 100644 index 0000000..77b6536 --- /dev/null +++ b/testing/logic/answers/13.txt @@ -0,0 +1,25 @@ +================= +[0]: line: 16; type: single-line; +line 16 +----------------- +[1]: line: 18; type: multiline; + +19 +20 +21 +22 +23 + +----------------- +[2]: line: 26; type: single-line; +26 line))) +----------------- +[3]: line: 29; type: single-line; +29 line)) (( // ////// +----------------- +[4]: line: 30; type: single-line; +30 line))0 /*hi // */ "'"' '/' '\n' "/" bye( +----------------- +[5]: line: 32; type: single-line; +why is this singleline? (line 32) +================= diff --git a/testing/logic/answers/14.txt b/testing/logic/answers/14.txt new file mode 100644 index 0000000..a5284bc --- /dev/null +++ b/testing/logic/answers/14.txt @@ -0,0 +1 @@ +Error | syntax error diff --git a/testing/logic/answers/15.txt b/testing/logic/answers/15.txt new file mode 100644 index 0000000..0d81c20 --- /dev/null +++ b/testing/logic/answers/15.txt @@ -0,0 +1,20 @@ +================= +[0]: line: 1; type: single-line; +this is a quotes exception test +----------------- +[1]: line: 3; type: single-line; +'a' +----------------- +[2]: line: 5; type: single-line; +'/' +----------------- +[3]: line: 7; type: single-line; +"but this should" <-- watch quotes here +----------------- +[4]: line: 8; type: multiline; + +// +/ +/* / + +================= diff --git a/testing/logic/answers/16.txt b/testing/logic/answers/16.txt new file mode 100644 index 0000000..a5284bc --- /dev/null +++ b/testing/logic/answers/16.txt @@ -0,0 +1 @@ +Error | syntax error diff --git a/testing/logic/answers/17.txt b/testing/logic/answers/17.txt new file mode 100644 index 0000000..b397180 --- /dev/null +++ b/testing/logic/answers/17.txt @@ -0,0 +1,136 @@ +================= +[0]: line: 1; type: single-line; +comment +----------------- +[1]: line: 2; type: single-line; +comment +----------------- +[2]: line: 3; type: single-line; +comment +----------------- +[3]: line: 4; type: single-line; +comment +----------------- +[4]: line: 5; type: single-line; +comment +----------------- +[5]: line: 6; type: single-line; +comment +----------------- +[6]: line: 7; type: single-line; +comment +----------------- +[7]: line: 8; type: single-line; +comment +----------------- +[8]: line: 9; type: single-line; +comment +----------------- +[9]: line: 10; type: single-line; +comment +----------------- +[10]: line: 11; type: single-line; +comment +----------------- +[11]: line: 12; type: single-line; +comment +----------------- +[12]: line: 13; type: single-line; +comment +----------------- +[13]: line: 14; type: single-line; +comment +----------------- +[14]: line: 15; type: single-line; +comment +----------------- +[15]: line: 16; type: single-line; +comment +----------------- +[16]: line: 17; type: single-line; +comment +----------------- +[17]: line: 18; type: single-line; +comment +----------------- +[18]: line: 19; type: single-line; +comment +----------------- +[19]: line: 20; type: single-line; +comment +----------------- +[20]: line: 21; type: single-line; +comment +----------------- +[21]: line: 22; type: single-line; +comment +----------------- +[22]: line: 23; type: single-line; +comment +----------------- +[23]: line: 24; type: single-line; +comment +----------------- +[24]: line: 25; type: single-line; +word +----------------- +[25]: line: 26; type: single-line; +word +----------------- +[26]: line: 27; type: single-line; +word +----------------- +[27]: line: 28; type: single-line; +word +----------------- +[28]: line: 29; type: single-line; +word +----------------- +[29]: line: 30; type: single-line; +word +----------------- +[30]: line: 31; type: single-line; +word +----------------- +[31]: line: 32; type: single-line; +word +----------------- +[32]: line: 33; type: single-line; +word +----------------- +[33]: line: 34; type: single-line; +word +----------------- +[34]: line: 35; type: single-line; +word +----------------- +[35]: line: 36; type: single-line; +word +----------------- +[36]: line: 37; type: single-line; +word +----------------- +[37]: line: 38; type: single-line; +word +----------------- +[38]: line: 39; type: single-line; +word +----------------- +[39]: line: 40; type: single-line; +word +----------------- +[40]: line: 41; type: single-line; +word +----------------- +[41]: line: 42; type: single-line; +word +----------------- +[42]: line: 43; type: single-line; +word +----------------- +[43]: line: 44; type: single-line; +word +----------------- +[44]: line: 45; type: single-line; +comment +================= diff --git a/testing/logic/answers/2.txt b/testing/logic/answers/2.txt new file mode 100644 index 0000000..e85a75f --- /dev/null +++ b/testing/logic/answers/2.txt @@ -0,0 +1,3 @@ +================= +no comments found +================= diff --git a/testing/logic/answers/3.txt b/testing/logic/answers/3.txt new file mode 100644 index 0000000..2d3f63a --- /dev/null +++ b/testing/logic/answers/3.txt @@ -0,0 +1,4 @@ +================= +[0]: line: 1; type: single-line; +simple multiline +================= diff --git a/testing/logic/answers/4.txt b/testing/logic/answers/4.txt new file mode 100644 index 0000000..6c32010 --- /dev/null +++ b/testing/logic/answers/4.txt @@ -0,0 +1,6 @@ +================= +[0]: line: 1; type: multiline; +realy +multiline + +================= diff --git a/testing/logic/answers/5.txt b/testing/logic/answers/5.txt new file mode 100644 index 0000000..f002d67 --- /dev/null +++ b/testing/logic/answers/5.txt @@ -0,0 +1,5 @@ +================= +[0]: line: 1; type: multiline; + +multiline +================= diff --git a/testing/logic/answers/6.txt b/testing/logic/answers/6.txt new file mode 100644 index 0000000..366c18f --- /dev/null +++ b/testing/logic/answers/6.txt @@ -0,0 +1,10 @@ +================= +[0]: line: 1; type: single-line; +double +----------------- +[1]: line: 2; type: single-line; +comment +----------------- +[2]: line: 2; type: single-line; +case +================= diff --git a/testing/logic/answers/7.txt b/testing/logic/answers/7.txt new file mode 100644 index 0000000..aa5f92f --- /dev/null +++ b/testing/logic/answers/7.txt @@ -0,0 +1,4 @@ +================= +[0]: line: 1; type: single-line; +and a comment +================= diff --git a/testing/logic/answers/8.txt b/testing/logic/answers/8.txt new file mode 100644 index 0000000..32ce0a2 --- /dev/null +++ b/testing/logic/answers/8.txt @@ -0,0 +1,4 @@ +================= +[0]: line: 6; type: single-line; + pretty comment +================= diff --git a/testing/logic/answers/9.txt b/testing/logic/answers/9.txt new file mode 100644 index 0000000..96e4e07 --- /dev/null +++ b/testing/logic/answers/9.txt @@ -0,0 +1,4 @@ +================= +[0]: line: 2; type: single-line; +multiline comment in a single row +================= diff --git a/testing/logic/cases/1.txt b/testing/logic/cases/1.txt new file mode 100644 index 0000000..45380ab --- /dev/null +++ b/testing/logic/cases/1.txt @@ -0,0 +1 @@ +//simple comment diff --git a/testing/logic/cases/10.txt b/testing/logic/cases/10.txt new file mode 100644 index 0000000..a749c49 --- /dev/null +++ b/testing/logic/cases/10.txt @@ -0,0 +1,2 @@ +this if a hard test for "/*quotes*/" and /*multi +line comments*/ diff --git a/testing/logic/cases/11.txt b/testing/logic/cases/11.txt new file mode 100644 index 0000000..ca30405 --- /dev/null +++ b/testing/logic/cases/11.txt @@ -0,0 +1,24 @@ +hello one more time/* +h +e +r +e + +"is" + +a + +"really silly" + c + o + m + + + + m + e + 'n' + t +/structure/*/ + +// this is a 24th line diff --git a/testing/logic/cases/12.txt b/testing/logic/cases/12.txt new file mode 100644 index 0000000..07664ca --- /dev/null +++ b/testing/logic/cases/12.txt @@ -0,0 +1,9 @@ +//line-1 +//line-2 +//line-3 + + +//line-6 + + +//line-9 diff --git a/testing/logic/cases/13.txt b/testing/logic/cases/13.txt new file mode 100644 index 0000000..8e9d5e9 --- /dev/null +++ b/testing/logic/cases/13.txt @@ -0,0 +1,32 @@ + + + + + + + + + + + + + + + +this is //line 16 + +/* +19 +20 +21 +22 +23 +*/ + +//26 line))) + + +//29 line)) (( // ////// +//30 line))0 /*hi // */ "'"' '/' '\n' "/" bye( + +/*why is this singleline? (line 32)*/ diff --git a/testing/logic/cases/14.txt b/testing/logic/cases/14.txt new file mode 100644 index 0000000..6092a0d --- /dev/null +++ b/testing/logic/cases/14.txt @@ -0,0 +1,6 @@ +//oh nooo + +//is this a Syntax error ? + +probably "yea + diff --git a/testing/logic/cases/15.txt b/testing/logic/cases/15.txt new file mode 100644 index 0000000..484ca97 --- /dev/null +++ b/testing/logic/cases/15.txt @@ -0,0 +1,17 @@ +//this is a quotes exception test +'a' +//'a' +'/' +//'/' +"this should not be printed" +//"but this should" <-- watch quotes here +/* +// +/ +/* / +*/ + +"wtf these quates \" are \' still \" not 'closed' ? +" + +"/*hello world again*/" diff --git a/testing/logic/cases/16.txt b/testing/logic/cases/16.txt new file mode 100644 index 0000000..27e4e27 --- /dev/null +++ b/testing/logic/cases/16.txt @@ -0,0 +1 @@ +"this is invalid string I swear //"" diff --git a/testing/logic/cases/17.txt b/testing/logic/cases/17.txt new file mode 100644 index 0000000..1caf4a0 --- /dev/null +++ b/testing/logic/cases/17.txt @@ -0,0 +1,45 @@ +//comment +//comment +//comment +//comment +//comment +//comment +//comment +//comment +//comment +//comment +//comment +//comment +//comment +//comment +//comment +//comment +//comment +//comment +//comment +//comment +//comment +//comment +//comment +//comment +//word +//word +//word +//word +//word +//word +//word +//word +//word +//word +//word +//word +//word +//word +//word +//word +//word +//word +//word +//word +//comment diff --git a/testing/logic/cases/2.txt b/testing/logic/cases/2.txt new file mode 100644 index 0000000..5b0edfe --- /dev/null +++ b/testing/logic/cases/2.txt @@ -0,0 +1 @@ +no comments diff --git a/testing/logic/cases/3.txt b/testing/logic/cases/3.txt new file mode 100644 index 0000000..b8d46b4 --- /dev/null +++ b/testing/logic/cases/3.txt @@ -0,0 +1 @@ +/*simple multiline*/ diff --git a/testing/logic/cases/4.txt b/testing/logic/cases/4.txt new file mode 100644 index 0000000..e9ad373 --- /dev/null +++ b/testing/logic/cases/4.txt @@ -0,0 +1,3 @@ +/*realy +multiline +*/ diff --git a/testing/logic/cases/5.txt b/testing/logic/cases/5.txt new file mode 100644 index 0000000..b26dc59 --- /dev/null +++ b/testing/logic/cases/5.txt @@ -0,0 +1,2 @@ +bodied/* +multiline*/ diff --git a/testing/logic/cases/6.txt b/testing/logic/cases/6.txt new file mode 100644 index 0000000..2d7a1a2 --- /dev/null +++ b/testing/logic/cases/6.txt @@ -0,0 +1,2 @@ +/*double*/ +/*comment*/ missing word //case diff --git a/testing/logic/cases/7.txt b/testing/logic/cases/7.txt new file mode 100644 index 0000000..c969501 --- /dev/null +++ b/testing/logic/cases/7.txt @@ -0,0 +1,2 @@ +some text//and a comment + diff --git a/testing/logic/cases/8.txt b/testing/logic/cases/8.txt new file mode 100644 index 0000000..4ea06cc --- /dev/null +++ b/testing/logic/cases/8.txt @@ -0,0 +1,7 @@ +some +long +text +and +here is a +// pretty comment + diff --git a/testing/logic/cases/9.txt b/testing/logic/cases/9.txt new file mode 100644 index 0000000..948ddef --- /dev/null +++ b/testing/logic/cases/9.txt @@ -0,0 +1,2 @@ +hello world +here is a /*multiline comment in a single row*/ of text diff --git a/testing/openfile/answers/1.txt b/testing/openfile/answers/1.txt new file mode 100644 index 0000000..3b18e51 --- /dev/null +++ b/testing/openfile/answers/1.txt @@ -0,0 +1 @@ +hello world diff --git a/testing/openfile/answers/2.txt b/testing/openfile/answers/2.txt new file mode 100644 index 0000000..7d03278 --- /dev/null +++ b/testing/openfile/answers/2.txt @@ -0,0 +1,3 @@ +here +we +go again diff --git a/testing/openfile/answers/3.txt b/testing/openfile/answers/3.txt new file mode 100644 index 0000000..8179f38 --- /dev/null +++ b/testing/openfile/answers/3.txt @@ -0,0 +1,26 @@ + std::string test_filename = "../testing/easytests/logic/" + std::to_string(i) + ".txt"; + std::string answer_filename = "../testing/easyanswers/logic/" + std::to_string(i) + ".txt"; + std::fstream is(answer_filename); + ASSERT_TRUE(is.is_open()); + std::string answer_str; + char sym = '\0'; + while (is.get(sym)) + answer_str += sym; + is.close(); + + int fd[2]; + pipe(fd); + pid_t pid_fork = fork(); + int status = 0; + + if (!pid_fork) { + // Дочерний процесс + close(fd[0]); + dup2(fd[1], STDOUT_FILENO); + + std::string res; + execl("program", "program", test_filename.c_str(), NULL); + + close(fd[1]); + exit(0); + } diff --git a/testing/openfile/answers/4.txt b/testing/openfile/answers/4.txt new file mode 100644 index 0000000..78d2957 --- /dev/null +++ b/testing/openfile/answers/4.txt @@ -0,0 +1,49 @@ +// +// Created by denactive on 12.03.2021. +// +#ifndef PROJECT_HW_1_H +#define PROJECT_HW_1_H + +#include +#include +#include +#include +#include +#include +#include +#include + + +#define DEBUG 0 +#define BUFFER_SIZE 1024 + +enum { + single, + multiline +}; + +typedef struct { + char* beg; + char* end; + size_t line; + unsigned int type; +} comment; + +int parse_comments(char* input); +int parse_comments_from_file(const char *filename); +int parse_comments_from_console(); + +char* skip_to_single_quote(char *str, size_t *line_cnt); +char* skip_to_double_quote(char *str, size_t *line_cnt); +char* execute_line_comment(char *str, size_t *line_cnt, comment **res, size_t *comments_amount); +char* execute_multiline_comment(char *str, size_t *line_cnt, comment **res, size_t *comments_amount); + +int res_exp(comment **res, size_t *comments_amount); +int free_res(comment **res); + +char* console_input(); +char* file_input(const char *filename, struct stat* stat_buf); +void print_res(const comment *res, size_t *comments_amount); +void print_comment(const comment* c); + +#endif //PROJECT_HW_1_H diff --git a/testing/openfile/cases/1.txt b/testing/openfile/cases/1.txt new file mode 100644 index 0000000..3b18e51 --- /dev/null +++ b/testing/openfile/cases/1.txt @@ -0,0 +1 @@ +hello world diff --git a/testing/openfile/cases/2.txt b/testing/openfile/cases/2.txt new file mode 100644 index 0000000..7d03278 --- /dev/null +++ b/testing/openfile/cases/2.txt @@ -0,0 +1,3 @@ +here +we +go again diff --git a/testing/openfile/cases/3.txt b/testing/openfile/cases/3.txt new file mode 100644 index 0000000..8179f38 --- /dev/null +++ b/testing/openfile/cases/3.txt @@ -0,0 +1,26 @@ + std::string test_filename = "../testing/easytests/logic/" + std::to_string(i) + ".txt"; + std::string answer_filename = "../testing/easyanswers/logic/" + std::to_string(i) + ".txt"; + std::fstream is(answer_filename); + ASSERT_TRUE(is.is_open()); + std::string answer_str; + char sym = '\0'; + while (is.get(sym)) + answer_str += sym; + is.close(); + + int fd[2]; + pipe(fd); + pid_t pid_fork = fork(); + int status = 0; + + if (!pid_fork) { + // Дочерний процесс + close(fd[0]); + dup2(fd[1], STDOUT_FILENO); + + std::string res; + execl("program", "program", test_filename.c_str(), NULL); + + close(fd[1]); + exit(0); + } diff --git a/testing/openfile/cases/4.txt b/testing/openfile/cases/4.txt new file mode 100644 index 0000000..78d2957 --- /dev/null +++ b/testing/openfile/cases/4.txt @@ -0,0 +1,49 @@ +// +// Created by denactive on 12.03.2021. +// +#ifndef PROJECT_HW_1_H +#define PROJECT_HW_1_H + +#include +#include +#include +#include +#include +#include +#include +#include + + +#define DEBUG 0 +#define BUFFER_SIZE 1024 + +enum { + single, + multiline +}; + +typedef struct { + char* beg; + char* end; + size_t line; + unsigned int type; +} comment; + +int parse_comments(char* input); +int parse_comments_from_file(const char *filename); +int parse_comments_from_console(); + +char* skip_to_single_quote(char *str, size_t *line_cnt); +char* skip_to_double_quote(char *str, size_t *line_cnt); +char* execute_line_comment(char *str, size_t *line_cnt, comment **res, size_t *comments_amount); +char* execute_multiline_comment(char *str, size_t *line_cnt, comment **res, size_t *comments_amount); + +int res_exp(comment **res, size_t *comments_amount); +int free_res(comment **res); + +char* console_input(); +char* file_input(const char *filename, struct stat* stat_buf); +void print_res(const comment *res, size_t *comments_amount); +void print_comment(const comment* c); + +#endif //PROJECT_HW_1_H diff --git a/testing/tests.cpp b/testing/tests.cpp new file mode 100644 index 0000000..84d5615 --- /dev/null +++ b/testing/tests.cpp @@ -0,0 +1,206 @@ +#include "gtest/gtest.h" +#include +#include +#include +#include + +#define LOGIC_TESTS_COUNT 17 +#define TESTS_OPEN_FILE_COUNT 4 + +extern "C" { + #include "hw-1.h" + #include "../project/src/hw-1.c" +}; + +// TODO: no console print in funcs, but print in main + +TEST(LogicTest, Main) { + std::cout << "Logic test" << std::endl; + for (int i = 1; i <= LOGIC_TESTS_COUNT; i++) { + std::string test_filename = "../testing/logic/cases/" + std::to_string(i) + ".txt"; + std::string answer_filename = "../testing/logic/answers/" + std::to_string(i) + ".txt"; + std::cout << "\tTesting " << test_filename << std::endl; + std::fstream is(answer_filename); + ASSERT_TRUE(is.is_open()); + std::string answer_str; + char sym = '\0'; + while (is.get(sym)) + answer_str += sym; + is.close(); + + int fd[2]; + pipe(fd); + pid_t pid_fork = fork(); + int status = 0; + + if (!pid_fork) { + // Дочерний процесс + close(fd[0]); + dup2(fd[1], STDOUT_FILENO); + + execl("program", "program", test_filename.c_str(), NULL); + + close(fd[1]); + exit(0); + } + + // Родительский процесс + close(fd[1]); + + ssize_t sz; + char* buf = (char*)calloc(20 * BUFFER_SIZE, sizeof(char)); + int err = 0; + if (!buf) + err = -1; + ASSERT_EQ(err, 0); + + sz = read(fd[0], buf, 20 * BUFFER_SIZE); + close(fd[0]); + ASSERT_GT(sz, 0); + waitpid(pid_fork, &status, 0); + + EXPECT_STREQ(buf, answer_str.c_str()); + free(buf); + } +} + +TEST(OpenFile, EasyTest) { + std::cout << "File opening test" << std::endl; + for (int i = 1; i <= TESTS_OPEN_FILE_COUNT; i++) { + std::string test_filename = "../testing/openfile/cases/" + std::to_string(i) + ".txt"; + std::string answer_filename = "../testing/openfile/answers/" + std::to_string(i) + ".txt"; + std::cout << "\tTesting " << test_filename << std::endl; + std::fstream is(answer_filename); + ASSERT_TRUE(is.is_open()); + std::string answer_str; + char sym = '\0'; + while (is.get(sym)) + answer_str += sym; + is.close(); + + struct stat stat_buf; + std::string res = file_input(test_filename.c_str(), &stat_buf); + EXPECT_STREQ(res.c_str(), answer_str.c_str()); + } +} + +TEST(ErrorTest, BadFile) { + const char invalid_file [] = "not_existing_file.wtf"; + std::cout << "File opening test" << std::endl; + std::cout << "\tTesting " << invalid_file << std::endl; + + struct stat stat_buf; + char* res = file_input(invalid_file, &stat_buf); + EXPECT_FALSE(res); +} + +TEST(ErrorTest, SingleQuotesSkipping) { + const char invalid_line [] = "' here we can see an opening quote, but no closing one"; + std::cout << "[Error test] | no closing single quote in a file" << std::endl; + + size_t cnt = 1; + char* res = skip_to_single_quote(const_cast(&invalid_line[1]), &cnt); + EXPECT_FALSE(res); + EXPECT_EQ(cnt, 1); +} + +TEST(ErrorTest, SingleQuotesSkippingMultiline) { + const char invalid_line [] = "\" here we can see\nan opening quote,\nbut no closing one"; + std::cout << "[Error test] | no closing single quote in a multiline file" << std::endl; + + size_t cnt = 1; + char* res = skip_to_single_quote(const_cast(&invalid_line[1]), &cnt); + EXPECT_FALSE(res); + EXPECT_EQ(cnt, 3); +} + +TEST(ErrorTest, DoubleQuotesSkipping) { + const char invalid_line [] = "' here we can see an opening quote, but no closing one"; + std::cout << "[Error test] | no closing double quote in a file" << std::endl; + + size_t cnt = 1; + char* res = skip_to_single_quote(const_cast(&invalid_line[1]), &cnt); + EXPECT_FALSE(res); + EXPECT_EQ(cnt, 1); +} + +TEST(ErrorTest, DoubleQuotesSkippingMultiline) { + const char invalid_line [] = "\" here we can see\nan opening quote,\nbut no closing one"; + std::cout << "Error test | no closing double quote in a multiline file" << std::endl; + + size_t cnt = 1; + char* res = skip_to_single_quote(const_cast(&invalid_line[1]), &cnt); + EXPECT_FALSE(res); + EXPECT_EQ(cnt, 3); +} + +TEST(EdgeTest, SlashesAfterOpeningMultilineComment) { + const char line [] = "/this is fucked up multiline\n/*/"; + const char answer [] = "/this is fucked up multiline\n/"; + std::cout << "[ EdgeTest ] | /*/ comment /*/ situation" << std::endl; + + size_t line_cnt = 1; + size_t comments_cnt = 0; + comment* res = NULL; + execute_multiline_comment(const_cast(line), &line_cnt, &res, &comments_cnt); + + ASSERT_NE(res, nullptr); + EXPECT_EQ(line_cnt, 2); + EXPECT_EQ(comments_cnt, 1); + EXPECT_EQ(res[0].type, multiline); + EXPECT_EQ(res[0].line, 1); + std::string res_line; + for (char* i = res[0].beg; i <= res[0].end; i++) + res_line += *i; + EXPECT_STREQ(res_line.c_str(), answer); + free_res(&res); +} + +TEST(EdgeTest, ShieldingSingleQuotes) { + const char line_const [] = "this is a \\'line'"; // this is a \'line' + const char answer [] = "this is a \\'line"; + char* line = (char*)malloc(strlen(line_const) + 1); + ASSERT_NE(line, nullptr); + strcpy(line, line_const); + line[strlen(line_const)] = '\0'; + + std::cout << "[ EdgeTest ] | \\' situation" << std::endl; + + size_t line_cnt = 1; + char* after_closing_quote = skip_to_single_quote(line, &line_cnt); + + ASSERT_NE(after_closing_quote, nullptr); + EXPECT_EQ(line_cnt, 1); + std::string res_line; + for (char* i = line; i < after_closing_quote - 1; i++) + res_line += *i; + EXPECT_STREQ(res_line.c_str(), answer); + free(line); +} + +TEST(EdgeTest, ShieldingDoubleQuotes) { + const char line_const [] = "this is a \\'line\""; // this is a \'line' + const char answer [] = "this is a \\'line"; + char* line = (char*)malloc(strlen(line_const) + 1); + ASSERT_NE(line, nullptr); + strcpy(line, line_const); + line[strlen(line_const)] = '\0'; + + std::cout << "[ EdgeTest ] | \\\" situation" << std::endl; + + size_t line_cnt = 1; + char* after_closing_quote = skip_to_double_quote(line, &line_cnt); + + ASSERT_NE(after_closing_quote, nullptr); + EXPECT_EQ(line_cnt, 1); + std::string res_line; + for (char* i = line; i < after_closing_quote - 1; i++) + res_line += *i; + EXPECT_STREQ(res_line.c_str(), answer); + free(line); +} + +int main(int argc, char **argv) { + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} \ No newline at end of file diff --git "a/\320\277\320\276\320\272\321\200\321\213\321\202\320\270\320\265.png" "b/\320\277\320\276\320\272\321\200\321\213\321\202\320\270\320\265.png" new file mode 100644 index 0000000..b7e9774 Binary files /dev/null and "b/\320\277\320\276\320\272\321\200\321\213\321\202\320\270\320\265.png" differ