diff --git a/.github/workflows/check-homework.yml b/.github/workflows/check-homework.yml index 5696ca6..9a98b6b 100644 --- a/.github/workflows/check-homework.yml +++ b/.github/workflows/check-homework.yml @@ -3,168 +3,8 @@ name: CI on: [pull_request] jobs: - add_progress_bar_comment: - runs-on: ubuntu-latest - steps: - - name: Find Comment - uses: peter-evans/find-comment@v1 - id: fc - with: - issue-number: ${{ github.event.pull_request.number }} - comment-author: 'github-actions[bot]' - body-includes: With ❤️ from Homework Bot 🤖 - - name: Create comment - if: steps.fc.outputs.comment-id == '' - uses: peter-evans/create-or-update-comment@v1 - with: - comment-id: ${{ steps.fc.outputs.comment-id }} - issue-number: ${{ github.event.pull_request.number }} - body: | - ## Tests are running! Please wait! - - ![Progress gif](https://cdn.dribbble.com/users/2015153/screenshots/6592242/progess-bar2.gif) - - > Progress gif from https://dribbble.com/shots/6592242-Please-wait-Animation# - - With ❤️ from Homework Bot 🤖 - - name: Update comment - if: steps.fc.outputs.comment-id != '' - uses: peter-evans/create-or-update-comment@v1 - with: - comment-id: ${{ steps.fc.outputs.comment-id }} - edit-mode: replace - body: | - ## Tests are running! Please wait! - - ![Progress gif](https://cdn.dribbble.com/users/2015153/screenshots/6592242/progess-bar2.gif) - - > Progress gif from https://dribbble.com/shots/6592242-Please-wait-Animation# - - With ❤️ from Homework Bot 🤖 - - check_homework: - runs-on: ubuntu-latest - steps: - - name: Checkout this homework - uses: actions/checkout@v2 - with: - path: homework - - name: Checkout homework definitions - uses: actions/checkout@v2 - with: - repository: cpp-for-yourself/homework-definitions - path: definitions - - name: Set up Python - uses: actions/setup-python@v2 - with: - python-version: '3.8' - architecture: 'x64' - - name: Install prerequisites - run: | - sudo apt install -y libgtest-dev - python -m pip install --upgrade pip pipenv ruamel.yaml schema homework-checker - - name: Run tests - run: | - mkdir checker - cp definitions/homework.yml checker/ - cp -r homework/homeworks checker/ - cd checker - check_homework -v -i homework.yml -o results.md - - name: Upload result md file - uses: actions/upload-artifact@v2 - with: - name: homework_result - path: checker/results.md - - upload_results_as_comment: - needs: check_homework - runs-on: ubuntu-latest - steps: - - name: Download result md file - uses: actions/download-artifact@v2 - with: - name: homework_result - - name: Render template - id: template - uses: chuhlomin/render-template@v1.2 - with: - template: results.md - - name: Find Comment - uses: peter-evans/find-comment@v1 - id: fc - with: - issue-number: ${{ github.event.pull_request.number }} - comment-author: 'github-actions[bot]' - body-includes: With ❤️ from Homework Bot 🤖 - - name: Update comment with test results - uses: peter-evans/create-or-update-comment@v1 - with: - comment-id: ${{ steps.fc.outputs.comment-id }} - issue-number: ${{ github.event.pull_request.number }} - body: ${{ steps.template.outputs.result }} - edit-mode: replace - - upload_results_to_wiki: - needs: check_homework - runs-on: ubuntu-latest - steps: - - name: Download result md file - uses: actions/download-artifact@v2 - with: - name: homework_result - - name: Find Comment - uses: peter-evans/find-comment@v1 - id: fc - with: - issue-number: ${{ github.event.pull_request.number }} - comment-author: 'github-actions[bot]' - body-includes: With 💙 from Homework Bot 🤖 - - name: Checkout wiki - uses: actions/checkout@v2 - with: - repository: ${{ github.repository }}.wiki - path: wiki - - name: Upload result to wiki - run: | - echo \`\`\` > wiki/Home.md - echo Author: ${{ github.actor }} >> wiki/Home.md - echo Branch: ${{ github.head_ref }} >> wiki/Home.md - echo Commit: ${{ github.sha }} >> wiki/Home.md - echo \`\`\` >> wiki/Home.md - cat results.md >> wiki/Home.md - cd wiki - git config user.name homework-bot - git config user.email homework-bot@github.com - git add . - git commit -m "Update results" --allow-empty - git push - - name: Comment on wiki access failure - uses: peter-evans/create-or-update-comment@v1 - if: failure() - with: - comment-id: ${{ steps.fc.outputs.comment-id }} - issue-number: ${{ github.event.pull_request.number }} - body: | - # ‼️ Wiki is empty ‼️ - - To fix this error you will have to perform the following actions once: - 1. Create _any_ (even empty) page in the wiki by clicking this link: ${{ github.server_url }}/${{ github.repository }}/wiki/_new - 2. Rerun the actions by clicking the 🔄 Re-run all jobs button here: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }} - - --- - - With 💙 from Homework Bot 🤖 - edit-mode: replace - - name: Comment on wiki access success - uses: peter-evans/create-or-update-comment@v1 - if: success() - with: - comment-id: ${{ steps.fc.outputs.comment-id }} - issue-number: ${{ github.event.pull_request.number }} - body: | - # ✅ Wiki is available - - Check it out at: ${{ github.server_url }}/${{ github.repository }}/wiki - - With 💙 from Homework Bot 🤖 - edit-mode: replace + run_all_tests: + name: Run all tests + uses: cpp-for-yourself/ci-jobs/.github/workflows/check-homework.yml@main + with: + homework-definitions-branch: main \ No newline at end of file diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..e49f5b2 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "homeworks/homework_4/no_strings_attached/external/googletest"] + path = homeworks/homework_4/no_strings_attached/external/googletest + url = https://github.com/google/googletest.git diff --git a/homeworks/homework_4/no_strings_attached/CMakeLists.txt b/homeworks/homework_4/no_strings_attached/CMakeLists.txt new file mode 100644 index 0000000..acac191 --- /dev/null +++ b/homeworks/homework_4/no_strings_attached/CMakeLists.txt @@ -0,0 +1,29 @@ +cmake_minimum_required(VERSION 3.16..3.24) +project(no_strings_attached VERSION 1 + DESCRIPTION "Writing a string processing library" + LANGUAGES CXX) + +if(NOT CMAKE_BUILD_TYPE) + set(CMAKE_BUILD_TYPE Release CACHE STRING "" FORCE) +endif() + +message(STATUS "CMAKE_BUILD_TYPE: ${CMAKE_BUILD_TYPE}") + +add_library(cxx_setup INTERFACE) +target_compile_options(cxx_setup INTERFACE -Wall -Wpedantic -Wextra) +target_compile_features(cxx_setup INTERFACE cxx_std_17) +target_include_directories(cxx_setup INTERFACE ${PROJECT_SOURCE_DIR}) + +# Update the submodules here +include(external/UpdateSubmodules.cmake) + +# Enable testing for this project +include(CTest) + +# 🚨 Make sure CMakeLists.txt file exists in the subdirectories! +add_subdirectory(examples) +add_subdirectory(external) +add_subdirectory(${PROJECT_NAME}) + + + diff --git a/homeworks/homework_4/no_strings_attached/compile_run_bash.sh b/homeworks/homework_4/no_strings_attached/compile_run_bash.sh new file mode 100644 index 0000000..ba592a9 --- /dev/null +++ b/homeworks/homework_4/no_strings_attached/compile_run_bash.sh @@ -0,0 +1,22 @@ +echo " ******** Current working directory ******** " +pwd +echo " -------- -------- -------- -------- -------- -------- -------- -------- -------- --------" + +echo " ******** BUILD directory ******** " +rm -r build +mkdir build +echo " -------- -------- -------- -------- -------- -------- -------- -------- -------- --------" + +echo " ******** CMAKE ******** " +cmake -S . -B build +cmake --build build +echo " -------- -------- -------- -------- -------- -------- -------- -------- -------- --------" + +echo " ******** Google Test ********" +GTEST_COLOR=1 ctest --test-dir build --output-on-failure +#GTEST_COLOR=1 ctest --test-dir build --verbose +echo " -------- -------- -------- -------- -------- -------- -------- -------- -------- --------" + +#echo " ******** Run Binary ********" +#./build/examples/split_strings +echo " -------- -------- -------- -------- -------- -------- -------- -------- -------- --------" \ No newline at end of file diff --git a/homeworks/homework_4/no_strings_attached/examples/CMakeLists.txt b/homeworks/homework_4/no_strings_attached/examples/CMakeLists.txt new file mode 100644 index 0000000..b689a0a --- /dev/null +++ b/homeworks/homework_4/no_strings_attached/examples/CMakeLists.txt @@ -0,0 +1,5 @@ +add_executable(split_strings split_strings.cpp) +target_link_libraries(split_strings PRIVATE cxx_setup string_split) + +add_executable(trim_strings trim_strings.cpp) +target_link_libraries(trim_strings PRIVATE cxx_setup string_trim) \ No newline at end of file diff --git a/homeworks/homework_4/no_strings_attached/examples/split_strings.cpp b/homeworks/homework_4/no_strings_attached/examples/split_strings.cpp new file mode 100644 index 0000000..f3359a2 --- /dev/null +++ b/homeworks/homework_4/no_strings_attached/examples/split_strings.cpp @@ -0,0 +1,33 @@ +#include +#include +#include +#include + +int main(){ + +std::string string_to_be_splitted; +std::string delimiter = " "; +int number_of_chunks_to_keep = 2; + +std::cout << "Example program that splits strings."< Splitted_string = no_strings_attached::Split(string_to_be_splitted,delimiter); +std::cout << "Your split string: "; +for(auto index1:Splitted_string) { + std::cout <<"'"<< index1 <<"'"<<' '; + } + +std::cout < Splitted_string2 = no_strings_attached::Split(string_to_be_splitted,delimiter,number_of_chunks_to_keep); +// std::cout << "Your split string2: "; +// for(auto index2:Splitted_string2) { +// std::cout <<"'"<< index2 <<"'"<<' '; +// } + +// std::cout < +#include +#include +#include + +using no_strings_attached::Side; + +int main(){ + +std::string string_to_be_trimmed; +char char_to_trim =' '; + +std::cout << "Example program that trims strings."< +#include +#include +#include + + +namespace no_strings_attached{ + + std::vector Split(const std::string& str, const std::string& delimiter){ + //std::cout << " Debug : function entry "< Nend-1){ + split_string = ""; + + }else{ + split_string = str.substr(Nstart+next_start,Nend-(Nstart+next_start)); + //std::cout << " Debug : @middle "< Split(const std::string& str, const std::string& delimiter, int number_of_chunks_to_keep){ + + int next_start = delimiter.size(); + + //std::cout << " Debug : next_start = "< n_vec; + + std::vector container; + + std::string split_string; + std::string string_init = str; + + // To find indexes of all delimiter (METHOD 2) + if (string_init.find(delimiter) != std::string::npos){ + n = 0; + //std::cout << "Debug: found delimiter"< Nend-1){ + split_string = ""; + + }else{ + split_string = str.substr(Nstart+next_start,Nend-(Nstart+next_start)); + //std::cout << " Debug : @middle "< number_of_chunks_to_keep){ + container.resize(number_of_chunks_to_keep) ; + } + + return container; + } + } + +} \ No newline at end of file diff --git a/homeworks/homework_4/no_strings_attached/no_strings_attached/string_split.h b/homeworks/homework_4/no_strings_attached/no_strings_attached/string_split.h new file mode 100644 index 0000000..fcda43b --- /dev/null +++ b/homeworks/homework_4/no_strings_attached/no_strings_attached/string_split.h @@ -0,0 +1,10 @@ +#include +#include +#pragma once + +namespace no_strings_attached{ + + std::vector Split(const std::string& , const std::string& ); + std::vector Split(const std::string& , const std::string& , int); + +} \ No newline at end of file diff --git a/homeworks/homework_4/no_strings_attached/no_strings_attached/string_split_test.cpp b/homeworks/homework_4/no_strings_attached/no_strings_attached/string_split_test.cpp new file mode 100644 index 0000000..86c9822 --- /dev/null +++ b/homeworks/homework_4/no_strings_attached/no_strings_attached/string_split_test.cpp @@ -0,0 +1,56 @@ +#include +#include +#include +#include + +// TEST is a macro, i.e., preprocessor replaces it with some code +namespace { +using no_strings_attached::Split; +} + +TEST(SplitValidationTest, SplitDelimeterNotFound) { + auto test_string = ""; + const auto split_on_empty = Split("", " "); + ASSERT_FALSE(split_on_empty.empty()) + << "Failed to split: '" << test_string << "'"; + EXPECT_EQ("", split_on_empty.front()) + << "Failed to split: '" << test_string << "'"; + test_string = "hello"; + const auto split_no_space = Split(test_string, " "); + ASSERT_FALSE(split_no_space.empty()) + << "Failed to split: '" << test_string << "'"; + EXPECT_EQ("hello", split_no_space.front()) + << "Failed to split: '" << test_string << "'"; +} + +TEST(SplitValidationTest, SplitTwoWordsOnString) { + const auto test_string = "hello world"; + const auto split = Split(test_string, " "); + ASSERT_EQ(2UL, split.size()) << "Failed to split: '" << test_string << "'"; + EXPECT_EQ("hello", split.front()) + << "Failed to split: '" << test_string << "'"; + EXPECT_EQ("world", split.back()) + << "Failed to split: '" << test_string << "'"; +} + +TEST(SplitValidationTest, SplitMoreWords) { + const auto test_string = "some_string__split__with_underscores"; + const auto split = Split(test_string, "__"); + ASSERT_EQ(3UL, split.size()) << "Failed to split: '" << test_string << "'"; + EXPECT_EQ("some_string", split[0]) + << "Failed to split: '" << test_string << "'"; + EXPECT_EQ("split", split[1]) << "Failed to split: '" << test_string << "'"; + EXPECT_EQ("with_underscores", split[2]) + << "Failed to split: '" << test_string << "'"; +} + +TEST(SplitValidationTest, RepeatedString) { + const auto test_string = "split_me__and_me"; + const auto split = Split(test_string, "_"); + ASSERT_EQ(5UL, split.size()) << "Failed to split: '" << test_string << "'"; + EXPECT_EQ("split", split[0]) << "Failed to split: '" << test_string << "'"; + EXPECT_EQ("me", split[1]) << "Failed to split: '" << test_string << "'"; + EXPECT_EQ("", split[2]) << "Failed to split: '" << test_string << "'"; + EXPECT_EQ("and", split[3]) << "Failed to split: '" << test_string << "'"; + EXPECT_EQ("me", split[4]) << "Failed to split: '" << test_string << "'"; +} diff --git a/homeworks/homework_4/no_strings_attached/no_strings_attached/string_trim.cpp b/homeworks/homework_4/no_strings_attached/no_strings_attached/string_trim.cpp new file mode 100644 index 0000000..649efea --- /dev/null +++ b/homeworks/homework_4/no_strings_attached/no_strings_attached/string_trim.cpp @@ -0,0 +1,115 @@ +#include +#include +#include + +namespace no_strings_attached{ + + //A function that allows trimming strings from a given direction: + std::string Trim(const std::string& str, char char_to_trim, Side side){ + + int next_start = 1; // since char type + + int start_index, end_index, count; + + std::string trim_str_init = str; + + if(trim_str_init.find(char_to_trim) != std::string::npos){ + + switch(side){ + + case Side::kLeft: + if((start_index = trim_str_init.find_first_of(char_to_trim)) == 0){ + + end_index = trim_str_init.find_first_not_of(char_to_trim,start_index); + count = end_index-start_index; + trim_str_init.replace(start_index, count, ""); + return trim_str_init; + + }else{ + + return str; + } + break; + + case Side::kRight: + if((start_index = trim_str_init.find_last_of(char_to_trim)) == trim_str_init.size()-1){ + + end_index = trim_str_init.find_last_not_of(char_to_trim); //find_last_not_of( const basic_string& str,size_type pos = npos ) + count = start_index - end_index; + trim_str_init.replace(end_index+next_start, count, ""); + return trim_str_init; + + }else{ + + return str; + } + break; + + case Side::kBoth: + if((start_index = trim_str_init.find_first_of(char_to_trim)) == 0){ + + end_index = trim_str_init.find_first_not_of(char_to_trim,start_index); + count = end_index-start_index; + trim_str_init.replace(start_index, count, ""); + } + + if((start_index = trim_str_init.find_last_of(char_to_trim)) == trim_str_init.size()-1){ + + end_index = trim_str_init.find_last_not_of(char_to_trim); //find_last_not_of( const basic_string& str,size_type pos = npos ) + count = start_index - end_index; + trim_str_init.replace(end_index+next_start, count, ""); + + } + return trim_str_init; + break; + + + } + + }else{ + return str; + } + + + + } + + + + + + // An overload of this function function that allows trimming spaces from both sides: + std::string Trim(const std::string& str){ + + int next_start = 1; // since space character + + int start_index, end_index, count; + + std::string trim_str_init = str; + + std::string char_to_trim = " "; // space character + + if(trim_str_init.find(char_to_trim) != std::string::npos){ + + if((start_index = trim_str_init.find_first_of(char_to_trim)) == 0){ + + end_index = trim_str_init.find_first_not_of(char_to_trim,start_index); + count = end_index-start_index; + trim_str_init.replace(start_index, count, ""); + } + + if((start_index = trim_str_init.find_last_of(char_to_trim)) == trim_str_init.size()-1){ + + end_index = trim_str_init.find_last_not_of(char_to_trim); //find_last_not_of( const basic_string& str,size_type pos = npos ) + count = start_index - end_index; + trim_str_init.replace(end_index+next_start, count, ""); + + } + return trim_str_init; + + }else{ + return str; + } + } + +} \ No newline at end of file diff --git a/homeworks/homework_4/no_strings_attached/no_strings_attached/string_trim.h b/homeworks/homework_4/no_strings_attached/no_strings_attached/string_trim.h new file mode 100644 index 0000000..6960889 --- /dev/null +++ b/homeworks/homework_4/no_strings_attached/no_strings_attached/string_trim.h @@ -0,0 +1,12 @@ +#include +#include +#pragma once + +namespace no_strings_attached{ + + enum class Side {kLeft,kRight,kBoth}; // 💡 This enum class should be defined here (not in string_trim.cpp) + + std::string Trim(const std::string& , char , Side); + std::string Trim(const std::string& ); + +} diff --git a/homeworks/homework_4/no_strings_attached/no_strings_attached/string_trim_test.cpp b/homeworks/homework_4/no_strings_attached/no_strings_attached/string_trim_test.cpp new file mode 100644 index 0000000..89ea752 --- /dev/null +++ b/homeworks/homework_4/no_strings_attached/no_strings_attached/string_trim_test.cpp @@ -0,0 +1,56 @@ +#include +#include +#include +#include + +namespace { +using no_strings_attached::Side; +using no_strings_attached::Trim; +} // namespace + +TEST(TrimValidationTest, TrimEmpty) { + const auto test_string = ""; + const auto trimmed_both_sides = Trim(test_string); + const auto trimmed_both_sides_explicit = Trim(test_string, ' ', Side::kBoth); + const auto trimmed_left_side = Trim(test_string, ' ', Side::kLeft); + const auto trimmed_right_side = Trim(test_string, ' ', Side::kRight); + EXPECT_EQ(trimmed_both_sides, test_string); + EXPECT_EQ(trimmed_both_sides_explicit, test_string); + EXPECT_EQ(trimmed_left_side, test_string); + EXPECT_EQ(trimmed_right_side, test_string); +} + +TEST(TrimValidationTest, TrimTrivial) { + const auto test_string = "hello"; + const auto trimmed_both_sides = Trim(test_string); + const auto trimmed_both_sides_explicit = Trim(test_string, ' ', Side::kBoth); + const auto trimmed_left_side = Trim(test_string, ' ', Side::kLeft); + const auto trimmed_right_side = Trim(test_string, ' ', Side::kRight); + EXPECT_EQ(trimmed_both_sides, test_string) + << "Failed to trim string: '" << test_string << "'"; + EXPECT_EQ(trimmed_both_sides_explicit, test_string) + << "Failed to trim string: '" << test_string << "'"; + EXPECT_EQ(trimmed_left_side, test_string) + << "Failed to trim string: '" << test_string << "'"; + EXPECT_EQ(trimmed_right_side, test_string) + << "Failed to trim string: '" << test_string << "'"; +} + +TEST(TrimValidationTest, TrimCorrect) { + const auto test_string = " hello "; + const auto trimmed_both_sides = Trim(test_string); + const auto trimmed_both_sides_explicit = Trim(test_string, ' ', Side::kBoth); + const auto trimmed_left_side = Trim(test_string, ' ', Side::kLeft); + const auto trimmed_right_side = Trim(test_string, ' ', Side::kRight); + const auto expected_both_trimmed = "hello"; + EXPECT_EQ(trimmed_both_sides, expected_both_trimmed) + << "Failed to trim string: '" << test_string << "'"; + EXPECT_EQ(trimmed_both_sides_explicit, expected_both_trimmed) + << "Failed to trim string: '" << test_string << "'"; + const auto expected_left_trimmed = "hello "; + EXPECT_EQ(trimmed_left_side, expected_left_trimmed) + << "Failed to trim string: '" << test_string << "'"; + const auto expected_right_trimmed = " hello"; + EXPECT_EQ(trimmed_right_side, expected_right_trimmed) + << "Failed to trim string: '" << test_string << "'"; +} \ No newline at end of file