From f9fac8d44f66239437c2906365efd98a03bea2d6 Mon Sep 17 00:00:00 2001 From: DanilaKn Date: Mon, 23 Oct 2023 16:43:57 +0300 Subject: [PATCH 01/18] =?UTF-8?q?(#283)=20=D0=94=D0=BE=D0=B1=D0=B0=D0=B2?= =?UTF-8?q?=D0=B8=D0=BB=20unit=20=D1=82=D0=B5=D1=81=D1=82=D1=8B=20=D0=B8?= =?UTF-8?q?=20=D0=BD=D0=B5=D1=81=D0=BA=D0=BE=D0=BB=D1=8C=D0=BA=D0=BE=20?= =?UTF-8?q?=D0=BF=D1=80=D0=B8=D0=BC=D0=B5=D1=80=D0=BE=D0=B2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CMakeLists.txt | 3 +- apps/TestsApp/CMakeLists.txt | 6 +- apps/TestsApp/src/UnitTests.cpp | 104 ++++++++++++++++++++++++++++++++ apps/TestsApp/src/main.cpp | 16 +++-- 4 files changed, 121 insertions(+), 8 deletions(-) create mode 100644 apps/TestsApp/src/UnitTests.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 7d5540c4..27bbc5a7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -14,4 +14,5 @@ add_subdirectory(libs/Interpreter) add_subdirectory(libs/InputGenerator) add_subdirectory(apps/InterpreterApp) add_subdirectory(apps/InputGeneratorApp) -add_subdirectory(apps/TestsApp) \ No newline at end of file +add_subdirectory(apps/TestsApp) +add_subdirectory(googletest) \ No newline at end of file diff --git a/apps/TestsApp/CMakeLists.txt b/apps/TestsApp/CMakeLists.txt index a74c4337..53d6d62f 100644 --- a/apps/TestsApp/CMakeLists.txt +++ b/apps/TestsApp/CMakeLists.txt @@ -4,7 +4,9 @@ project(TestsApp) # Create a sources variable with a link to all cpp files to compile set(SOURCES src/Example.cpp - src/main.cpp) + src/main.cpp + src/UnitTests.cpp) + # Add a library with the above sources add_executable(${PROJECT_NAME} ${SOURCES}) @@ -18,9 +20,9 @@ target_link_libraries(${PROJECT_NAME} Interpreter Tester Objects + gtest ) enable_testing() - add_test(NAME UnitTests COMMAND ${PROJECT_NAME}) \ No newline at end of file diff --git a/apps/TestsApp/src/UnitTests.cpp b/apps/TestsApp/src/UnitTests.cpp new file mode 100644 index 00000000..466107d8 --- /dev/null +++ b/apps/TestsApp/src/UnitTests.cpp @@ -0,0 +1,104 @@ +#include "AutomatonToImage/AutomatonToImage.h" +#include "InputGenerator/RegexGenerator.h" +#include "InputGenerator/TasksGenerator.h" +#include "Interpreter/Interpreter.h" +#include "Objects/FiniteAutomaton.h" +#include "Objects/Grammar.h" +#include "Objects/Language.h" +#include "Objects/Regex.h" +#include "Objects/TransformationMonoid.h" +#include "Objects/iLogTemplate.h" +#include "Tester/Tester.h" +#include +#include +#include +#include "gtest/gtest.h" + +TEST(TestCaseName, GlaisterShallit) { + auto check_classes_number = [](string rgx_str) { + return (Regex(rgx_str).to_glushkov().get_classes_number_GlaisterShallit()); + }; + EXPECT_EQ(1, 1); + EXPECT_EQ(check_classes_number("abs"), 4); + EXPECT_EQ(check_classes_number("a*b*c*"), 3); + EXPECT_EQ(check_classes_number("aa*bb*cc*"), 4); + EXPECT_EQ(check_classes_number("ab|abc"), 4); + EXPECT_EQ(check_classes_number("a(b|c)(a|b)(b|c)"), 5); +} + + + +TEST(TestCaseName, Test_random_regex_parsing) { + RegexGenerator rg(15, 10, 5, 3); + for (int i = 0; i < 30; i++) { + string str = rg.generate_regex(); + Regex r1(str); + string r1_str = r1.to_txt(); + Regex r2(r1_str); + EXPECT_EQ(true, Regex::equivalent(r1, r2)); + } +} + + +TEST(TestCaseName, Test_test_fa_equal) { + vector states1; + for (int i = 0; i < 6; i++) { + State s = {i, {i}, to_string(i), false, map>()}; + states1.push_back(s); + } + states1[0].set_transition(1, "b"); + states1[0].set_transition(2, "b"); + states1[0].set_transition(5, "c"); + states1[1].set_transition(3, "a"); + states1[1].set_transition(4, "c"); + states1[2].set_transition(4, "a"); + states1[5].set_transition(4, "a"); + states1[3].is_terminal = true; + states1[4].is_terminal = true; + FiniteAutomaton fa1(0, states1, {"a", "b", "c"}); + + vector states2; + for (int i = 0; i < 6; i++) { + State s = {i, {i}, to_string(i), false, map>()}; + states2.push_back(s); + } + states2[0].set_transition(1, "b"); + states2[0].set_transition(2, "b"); + states2[0].set_transition(5, "c"); + states2[1].set_transition(3, "a"); + states2[1].set_transition(3, "c"); + states2[2].set_transition(4, "a"); + states2[5].set_transition(4, "a"); + states2[3].is_terminal = true; + states2[4].is_terminal = true; + FiniteAutomaton fa2(0, states2, {"a", "b", "c"}); + + vector states3; + for (int i = 0; i < 6; i++) { + State s = {i, {i}, to_string(i), false, map>()}; + states3.push_back(s); + } + states3[5].set_transition(4, "b"); + states3[5].set_transition(3, "b"); + states3[5].set_transition(0, "c"); + states3[4].set_transition(2, "a"); + states3[4].set_transition(1, "c"); + states3[3].set_transition(1, "a"); + states3[0].set_transition(1, "a"); + states3[2].is_terminal = true; + states3[1].is_terminal = true; + FiniteAutomaton fa3(5, states3, {"a", "b", "c"}); + + EXPECT_TRUE(FiniteAutomaton::equal(fa1, fa1)); + EXPECT_TRUE(!FiniteAutomaton::equal(fa1, fa2)); + EXPECT_TRUE(FiniteAutomaton::equal(fa1, fa3)); + EXPECT_TRUE(FiniteAutomaton::equal(Regex("(aab|aab)*").to_thompson().remove_eps(), + Regex("(aab|aab)*").to_glushkov())); + EXPECT_TRUE(FiniteAutomaton::equal(Regex("a(a)*ab(bb)*baa").to_thompson().remove_eps(), + Regex("a(a)*ab(bb)*baa").to_glushkov())); + EXPECT_TRUE(FiniteAutomaton::equal( + Regex("a(bbb*aaa*)*bb*|aaa*(bbb*aaa*)*|b(aaa*bbb*)*aa*|bbb*(aaa*bbb*)*") + .to_thompson() + .remove_eps(), + Regex("a(bbb*aaa*)*bb*|aaa*(bbb*aaa*)*|b(aaa*bbb*)*aa*|bbb*(aaa*bbb*)*").to_glushkov())); +} diff --git a/apps/TestsApp/src/main.cpp b/apps/TestsApp/src/main.cpp index a4d50078..f0b2890d 100644 --- a/apps/TestsApp/src/main.cpp +++ b/apps/TestsApp/src/main.cpp @@ -1,11 +1,17 @@ #include "TestsApp/Example.h" +// #include "gmock/gmock.h" +#include "gtest/gtest.h" #include using namespace std; -int main() { +int main(int argc, char **argv) { cout << "Test\n"; // Тестирование - Example::test_all(); - Example::all_examples(); - Example::logger_test(); -} \ No newline at end of file + // Example::test_all(); + // Example::all_examples(); + // Example::logger_test(); + testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} + + From 6e63dffca73716cd8644ab93825e9ea07739551e Mon Sep 17 00:00:00 2001 From: DanilaKn Date: Mon, 23 Oct 2023 16:58:21 +0300 Subject: [PATCH 02/18] =?UTF-8?q?(#283)=20=D0=B4=D0=BE=D0=B1=D0=B0=D0=B2?= =?UTF-8?q?=D0=B8=D0=BB=20=D0=B2=20cmake=20FetchContent=5FDeclare,=20?= =?UTF-8?q?=D1=87=D1=82=D0=BE=D0=B1=D1=8B=20=D0=BD=D0=B5=20=D0=BF=D0=B8?= =?UTF-8?q?=D1=81=D0=B0=D1=82=D1=8C=20=D0=BA=D0=B0=D0=B6=D0=B4=D0=BE=D0=BC?= =?UTF-8?q?=D1=83=20git=20clone=20...googletest?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CMakeLists.txt | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 27bbc5a7..f60dbd2e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -15,4 +15,12 @@ add_subdirectory(libs/InputGenerator) add_subdirectory(apps/InterpreterApp) add_subdirectory(apps/InputGeneratorApp) add_subdirectory(apps/TestsApp) -add_subdirectory(googletest) \ No newline at end of file + +include(FetchContent) +FetchContent_Declare( + googletest + URL https://github.com/google/googletest/archive/03597a01ee50ed33e9dfd640b249b4be3799d395.zip +) + +set(gtest_force_shared_crt ON CACHE BOOL "" FORCE) +FetchContent_MakeAvailable(googletest) \ No newline at end of file From c8346effe9fcffefdae266f8676e2fd7acf74230 Mon Sep 17 00:00:00 2001 From: DanilaKn Date: Mon, 23 Oct 2023 19:46:51 +0300 Subject: [PATCH 03/18] =?UTF-8?q?(#283)=20=D1=82=D0=B5=D1=81=D1=82=D1=8B?= =?UTF-8?q?=20=D0=B2=20=D0=BA=D0=B0=D0=B6=D0=B4=D0=BE=D0=B9=20=D0=B2=D0=B5?= =?UTF-8?q?=D1=82=D0=BA=D0=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/cmake.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/cmake.yml b/.github/workflows/cmake.yml index d45d9d72..05e993a3 100644 --- a/.github/workflows/cmake.yml +++ b/.github/workflows/cmake.yml @@ -2,9 +2,9 @@ name: CMake on: push: - branches: [ "main" ] + branches: [ "*" ] pull_request: - branches: [ "main" ] + branches: [ "*" ] env: # Customize the CMake build type here (Release, Debug, RelWithDebInfo, etc.) From b43b66fa34cef94a524647c65cf3657c355f09d1 Mon Sep 17 00:00:00 2001 From: DanilaKn Date: Mon, 23 Oct 2023 19:59:49 +0300 Subject: [PATCH 04/18] =?UTF-8?q?(#283)=20=D1=80=D0=B0=D0=B7=D0=B4=D0=B5?= =?UTF-8?q?=D0=BB=D0=B5=D0=BD=D0=B8=D0=B5=20unit=20=D1=82=D0=B5=D1=81?= =?UTF-8?q?=D1=82=D0=BE=D0=B2=20=D0=B8=20=D0=B8=D0=BD=D1=82=D0=B5=D0=B3?= =?UTF-8?q?=D1=80=D0=B0=D1=86=D0=B8=D0=BE=D0=BD=D0=BD=D1=8B=D1=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/cmake.yml | 8 ------- .github/workflows/unitTests.yml | 39 +++++++++++++++++++++++++++++++++ 2 files changed, 39 insertions(+), 8 deletions(-) create mode 100644 .github/workflows/unitTests.yml diff --git a/.github/workflows/cmake.yml b/.github/workflows/cmake.yml index 05e993a3..04bdba54 100644 --- a/.github/workflows/cmake.yml +++ b/.github/workflows/cmake.yml @@ -33,13 +33,5 @@ jobs: - name: Build # Build your program with the given configuration run: cmake --build ${{github.workspace}}/build - - - name: Test - #working-directory: ${{github.workspace}}/build/apps/TestsApp - # Execute tests defined by the CMake configuration. - # See https://cmake.org/cmake/help/latest/manual/ctest.1.html for more detail - # ну почему не из корня ... - #run: ctest -C ${{env.BUILD_TYPE}} - run: ./build/apps/TestsApp/TestsApp \ No newline at end of file diff --git a/.github/workflows/unitTests.yml b/.github/workflows/unitTests.yml new file mode 100644 index 00000000..9ca91088 --- /dev/null +++ b/.github/workflows/unitTests.yml @@ -0,0 +1,39 @@ +name: UnitTests + +on: + push: + branches: [ "*" ] + pull_request: + branches: [ "*" ] + +env: + # Customize the CMake build type here (Release, Debug, RelWithDebInfo, etc.) + BUILD_TYPE: Release + +jobs: + build: + # The CMake configure and build commands are platform agnostic and should work equally well on Windows or Mac. + # You can convert this to a matrix build if you need cross-platform coverage. + # See: https://docs.github.com/en/free-pro-team@latest/actions/learn-github-actions/managing-complex-workflows#using-a-build-matrix + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v3 + - name: Configure CMake + # Configure CMake in a 'build' subdirectory. `CMAKE_BUILD_TYPE` is only required if you are using a single-configuration generator such as make. + # See https://cmake.org/cmake/help/latest/variable/CMAKE_BUILD_TYPE.html?highlight=cmake_build_type + run: cmake -B ${{github.workspace}}/build + + - name: Build + # Build your program with the given configuration + run: cmake --build ${{github.workspace}}/build + + - name: Test + #working-directory: ${{github.workspace}}/build/apps/TestsApp + # Execute tests defined by the CMake configuration. + # See https://cmake.org/cmake/help/latest/manual/ctest.1.html for more detail + # ну почему не из корня ... + #run: ctest -C ${{env.BUILD_TYPE}} + run: ./build/apps/TestsApp/TestsApp + + \ No newline at end of file From 560bf7db3faae8162671a9e1fcf75b69a9e0c936 Mon Sep 17 00:00:00 2001 From: DanilaKn Date: Mon, 23 Oct 2023 20:02:10 +0300 Subject: [PATCH 05/18] (#283) fix cmake.yml --- .github/workflows/cmake.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/cmake.yml b/.github/workflows/cmake.yml index 04bdba54..ea3d7db6 100644 --- a/.github/workflows/cmake.yml +++ b/.github/workflows/cmake.yml @@ -2,9 +2,9 @@ name: CMake on: push: - branches: [ "*" ] + branches: [ "main" ] pull_request: - branches: [ "*" ] + branches: [ main" ] env: # Customize the CMake build type here (Release, Debug, RelWithDebInfo, etc.) From a76a3f208a661bff99b2ba8945ae1a4a3952cc6d Mon Sep 17 00:00:00 2001 From: DanilaKn Date: Mon, 23 Oct 2023 20:10:12 +0300 Subject: [PATCH 06/18] =?UTF-8?q?(#283)=20=D1=82=D0=B5=D0=BF=D0=B5=D1=80?= =?UTF-8?q?=D1=8C=20googletest=20=D0=BF=D0=BE=D0=B4=D1=82=D1=8F=D0=B3?= =?UTF-8?q?=D0=B8=D0=B2=D0=B0=D0=B5=D1=82=D1=81=D1=8F=20=D1=82=D0=BE=D0=BB?= =?UTF-8?q?=D1=8C=D0=BA=D0=BE=20=D0=BF=D1=80=D0=B8=20=D1=81=D0=B1=D0=BE?= =?UTF-8?q?=D1=80=D0=BA=D0=B5=20TestApp?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/cmake.yml | 2 +- .github/workflows/unitTests.yml | 6 +----- CMakeLists.txt | 11 +---------- apps/TestsApp/CMakeLists.txt | 10 ++++++++++ 4 files changed, 13 insertions(+), 16 deletions(-) diff --git a/.github/workflows/cmake.yml b/.github/workflows/cmake.yml index ea3d7db6..9a61de9e 100644 --- a/.github/workflows/cmake.yml +++ b/.github/workflows/cmake.yml @@ -4,7 +4,7 @@ on: push: branches: [ "main" ] pull_request: - branches: [ main" ] + branches: [ "main" ] env: # Customize the CMake build type here (Release, Debug, RelWithDebInfo, etc.) diff --git a/.github/workflows/unitTests.yml b/.github/workflows/unitTests.yml index 9ca91088..d6f2425d 100644 --- a/.github/workflows/unitTests.yml +++ b/.github/workflows/unitTests.yml @@ -1,10 +1,6 @@ name: UnitTests -on: - push: - branches: [ "*" ] - pull_request: - branches: [ "*" ] +on: [ push ] env: # Customize the CMake build type here (Release, Debug, RelWithDebInfo, etc.) diff --git a/CMakeLists.txt b/CMakeLists.txt index f60dbd2e..7d5540c4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -14,13 +14,4 @@ add_subdirectory(libs/Interpreter) add_subdirectory(libs/InputGenerator) add_subdirectory(apps/InterpreterApp) add_subdirectory(apps/InputGeneratorApp) -add_subdirectory(apps/TestsApp) - -include(FetchContent) -FetchContent_Declare( - googletest - URL https://github.com/google/googletest/archive/03597a01ee50ed33e9dfd640b249b4be3799d395.zip -) - -set(gtest_force_shared_crt ON CACHE BOOL "" FORCE) -FetchContent_MakeAvailable(googletest) \ No newline at end of file +add_subdirectory(apps/TestsApp) \ No newline at end of file diff --git a/apps/TestsApp/CMakeLists.txt b/apps/TestsApp/CMakeLists.txt index 53d6d62f..3f905d42 100644 --- a/apps/TestsApp/CMakeLists.txt +++ b/apps/TestsApp/CMakeLists.txt @@ -2,6 +2,16 @@ project(TestsApp) # Create a sources variable with a link to all cpp files to compile + +include(FetchContent) +FetchContent_Declare( + googletest + URL https://github.com/google/googletest/archive/03597a01ee50ed33e9dfd640b249b4be3799d395.zip +) + +set(gtest_force_shared_crt ON CACHE BOOL "" FORCE) +FetchContent_MakeAvailable(googletest) + set(SOURCES src/Example.cpp src/main.cpp From 64d7489b83ad2c2b3a89d2ed5f46cca271ac3ffa Mon Sep 17 00:00:00 2001 From: DanilaKn Date: Sun, 5 Nov 2023 02:31:14 +0300 Subject: [PATCH 07/18] =?UTF-8?q?(#283)=20=D0=9F=D0=B5=D1=80=D0=B5=D0=BD?= =?UTF-8?q?=D0=B5=D1=81=20=D1=82=D0=B5=D1=81=D1=82=D1=8B=20=D0=B8=D0=B7=20?= =?UTF-8?q?Example=20=D0=B2=20UnitTests.cpp?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/TestsApp/src/Example.cpp | 2 + apps/TestsApp/src/UnitTests.cpp | 399 ++++++++++++++++++++++++++++++-- apps/TestsApp/src/main.cpp | 9 +- 3 files changed, 390 insertions(+), 20 deletions(-) diff --git a/apps/TestsApp/src/Example.cpp b/apps/TestsApp/src/Example.cpp index 132141e5..5c3fe326 100644 --- a/apps/TestsApp/src/Example.cpp +++ b/apps/TestsApp/src/Example.cpp @@ -798,6 +798,7 @@ void Example::test_ambiguity() { } }); } + void Example::test_arden() { auto test_equivalence = [](string rgx_str) { Regex reg(rgx_str); @@ -818,6 +819,7 @@ void Example::test_arden() { test_equivalence("((b(((ba|b)|||(b))*)))"); test_equivalence("(((((a*)((a*)|bb)(((|||((b)))))))))"); } + void Example::test_pump_length() { assert(Regex("abaa").pump_length() == 5); } diff --git a/apps/TestsApp/src/UnitTests.cpp b/apps/TestsApp/src/UnitTests.cpp index 466107d8..aa22198e 100644 --- a/apps/TestsApp/src/UnitTests.cpp +++ b/apps/TestsApp/src/UnitTests.cpp @@ -9,21 +9,22 @@ #include "Objects/TransformationMonoid.h" #include "Objects/iLogTemplate.h" #include "Tester/Tester.h" -#include #include #include #include "gtest/gtest.h" TEST(TestCaseName, GlaisterShallit) { + auto check_classes_number = [](string rgx_str) { return (Regex(rgx_str).to_glushkov().get_classes_number_GlaisterShallit()); }; - EXPECT_EQ(1, 1); - EXPECT_EQ(check_classes_number("abs"), 4); - EXPECT_EQ(check_classes_number("a*b*c*"), 3); - EXPECT_EQ(check_classes_number("aa*bb*cc*"), 4); - EXPECT_EQ(check_classes_number("ab|abc"), 4); - EXPECT_EQ(check_classes_number("a(b|c)(a|b)(b|c)"), 5); + ASSERT_EQ(1, 1); + ASSERT_EQ(check_classes_number("abs"), 4); + ASSERT_EQ(check_classes_number("a*b*c*"), 3); + ASSERT_EQ(check_classes_number("aa*bb*cc*"), 4); + ASSERT_EQ(check_classes_number("ab|abc"), 4); + ASSERT_EQ(check_classes_number("a(b|c)(a|b)(b|c)"), 5); + } @@ -35,12 +36,12 @@ TEST(TestCaseName, Test_random_regex_parsing) { Regex r1(str); string r1_str = r1.to_txt(); Regex r2(r1_str); - EXPECT_EQ(true, Regex::equivalent(r1, r2)); + ASSERT_EQ(true, Regex::equivalent(r1, r2)); } } -TEST(TestCaseName, Test_test_fa_equal) { +TEST(TestCaseName, Test_fa_equal) { vector states1; for (int i = 0; i < 6; i++) { State s = {i, {i}, to_string(i), false, map>()}; @@ -89,16 +90,384 @@ TEST(TestCaseName, Test_test_fa_equal) { states3[1].is_terminal = true; FiniteAutomaton fa3(5, states3, {"a", "b", "c"}); - EXPECT_TRUE(FiniteAutomaton::equal(fa1, fa1)); - EXPECT_TRUE(!FiniteAutomaton::equal(fa1, fa2)); - EXPECT_TRUE(FiniteAutomaton::equal(fa1, fa3)); - EXPECT_TRUE(FiniteAutomaton::equal(Regex("(aab|aab)*").to_thompson().remove_eps(), + ASSERT_TRUE(FiniteAutomaton::equal(fa1, fa1)); + ASSERT_TRUE(!FiniteAutomaton::equal(fa1, fa2)); + ASSERT_TRUE(FiniteAutomaton::equal(fa1, fa3)); + ASSERT_TRUE(FiniteAutomaton::equal(Regex("(aab|aab)*").to_thompson().remove_eps(), Regex("(aab|aab)*").to_glushkov())); - EXPECT_TRUE(FiniteAutomaton::equal(Regex("a(a)*ab(bb)*baa").to_thompson().remove_eps(), + ASSERT_TRUE(FiniteAutomaton::equal(Regex("a(a)*ab(bb)*baa").to_thompson().remove_eps(), Regex("a(a)*ab(bb)*baa").to_glushkov())); - EXPECT_TRUE(FiniteAutomaton::equal( + ASSERT_TRUE(FiniteAutomaton::equal( Regex("a(bbb*aaa*)*bb*|aaa*(bbb*aaa*)*|b(aaa*bbb*)*aa*|bbb*(aaa*bbb*)*") .to_thompson() .remove_eps(), Regex("a(bbb*aaa*)*bb*|aaa*(bbb*aaa*)*|b(aaa*bbb*)*aa*|bbb*(aaa*bbb*)*").to_glushkov())); } + + +TEST(TestCaseName, Test_fa_equiv) { + vector states1; + for (int i = 0; i < 3; i++) { + State s = {i, {i}, to_string(i), false, map>()}; + states1.push_back(s); + } + states1[0].set_transition(0, "c"); + states1[0].set_transition(1, "d"); + states1[1].set_transition(2, "c"); + states1[1].set_transition(0, "d"); + states1[2].set_transition(1, "c"); + states1[2].set_transition(2, "d"); + states1[0].is_terminal = true; + FiniteAutomaton fa1(0, states1, {"c", "d"}); + + vector states2; + for (int i = 0; i < 4; i++) { + State s = {i, {i}, to_string(i), false, map>()}; + states2.push_back(s); + } + states2[0].set_transition(0, "c"); + states2[0].set_transition(1, "d"); + states2[1].set_transition(2, "c"); + states2[1].set_transition(0, "d"); + states2[2].set_transition(3, "c"); + states2[2].set_transition(2, "d"); + states2[3].set_transition(2, "c"); + states2[3].set_transition(0, "d"); + states2[0].is_terminal = true; + FiniteAutomaton fa2(0, states2, {"c", "d"}); + + ASSERT_TRUE(FiniteAutomaton::equivalent(fa1, fa2)); +} + + +TEST(TestCaseName, Test__bisimilar) { + vector states1; + for (int i = 0; i < 3; i++) { + State s = {i, {i}, to_string(i), false, map>()}; + states1.push_back(s); + } + states1[0].set_transition(1, "a"); + states1[0].set_transition(1, "eps"); + states1[0].set_transition(2, "b"); + states1[1].set_transition(2, "a"); + states1[1].set_transition(1, "b"); + states1[2].set_transition(1, "a"); + states1[2].set_transition(1, "eps"); + states1[2].set_transition(0, "b"); + states1[0].is_terminal = true; + states1[2].is_terminal = true; + FiniteAutomaton fa1(1, states1, {"a", "b"}); + + vector states2; + for (int i = 0; i < 2; i++) { + State s = {i, {i}, to_string(i), false, map>()}; + states2.push_back(s); + } + states2[0].set_transition(1, "a"); + states2[0].set_transition(1, "eps"); + states2[0].set_transition(0, "b"); + states2[1].set_transition(0, "a"); + states2[1].set_transition(1, "b"); + states2[0].is_terminal = true; + FiniteAutomaton fa2(1, states2, {"a", "b"}); + + ASSERT_TRUE(FiniteAutomaton::bisimilar(fa1, fa2)); +} + +TEST(TestCaseName, Test_merge_bisimilar) { + FiniteAutomaton fa = Regex("(a|b)*b").to_glushkov(); + FiniteAutomaton fa1 = fa.merge_bisimilar(); + + vector states2; + for (int i = 0; i < 3; i++) { + State s = {i, {i}, to_string(i), false, map>()}; + states2.push_back(s); + } + states2[0].set_transition(1, "a"); + states2[0].set_transition(1, "eps"); + states2[0].set_transition(2, "b"); + states2[1].set_transition(2, "a"); + states2[1].set_transition(1, "b"); + states2[2].set_transition(1, "a"); + states2[2].set_transition(1, "eps"); + states2[2].set_transition(0, "b"); + states2[0].is_terminal = true; + states2[2].is_terminal = true; + FiniteAutomaton fa2(1, states2, {"a", "b"}); + + vector states3; + for (int i = 0; i < 2; i++) { + State s = {i, {i}, to_string(i), false, map>()}; + states3.push_back(s); + } + states3[0].set_transition(0, "b"); + states3[0].set_transition(1, "a"); + states3[1].set_transition(0, "eps"); + states3[1].set_transition(0, "a"); + states3[1].set_transition(1, "b"); + states3[1].is_terminal = true; + FiniteAutomaton fa3(0, states3, {"a", "b"}); + + ASSERT_TRUE(FiniteAutomaton::equal(Regex("(a|b)*b").to_ilieyu(), fa1)); + ASSERT_TRUE(FiniteAutomaton::equal(fa2.merge_bisimilar(), fa3)); +} + + +TEST(TestCaseName, Test_regex_subset) { + Regex r1("a*baa"); + Regex r2("abaa"); + + ASSERT_TRUE(r1.subset(r2)); + ASSERT_TRUE(!r2.subset(r1)); + ASSERT_TRUE(!Regex("ab*").subset(Regex("a*b*"))); +} + +TEST(TestCaseName, Test_regex_equal) { + Regex r1("a(bbb*aaa*)*bb*|aaa*(bbb*aaa*)*"); + Regex r2("aaa*(bbb*aaa*)*|a(bbb*aaa*)*bb*"); + Regex r3("a(bbb*aaa*)*bb*|aaa*(bbb*aaa*)"); + + ASSERT_TRUE(Regex::equal(r1, r2)); + ASSERT_TRUE(!Regex::equal(r1.linearize(), r1)); + ASSERT_TRUE(Regex::equal(r1.linearize(), r1.linearize())); + ASSERT_TRUE(!Regex::equal(r1, r3)); +} + +TEST(TestCaseName, Test_ambiguity) { + enum AutomatonType { + thompson, + glushkov, + ilieyu + }; + using Test = tuple; + vector tests = { + //{0, "(a*)*", thompson, FiniteAutomaton::exponentially_ambiguous}, + {1, "a*a*", glushkov, FiniteAutomaton::polynomially_ambigious}, + {2, "abc", thompson, FiniteAutomaton::unambigious}, + //{3, "b|a", thompson, FiniteAutomaton::almost_unambigious}, + {4, "(aa|aa)*", glushkov, FiniteAutomaton::exponentially_ambiguous}, + {5, "(aab|aab)*", glushkov, FiniteAutomaton::exponentially_ambiguous}, + {6, "a*a*((a)*)*", glushkov, FiniteAutomaton::polynomially_ambigious}, + //{7, "a*a*((a)*)*", thompson, + // FiniteAutomaton::exponentially_ambiguous}, + //{8, "a*(b*)*", thompson, FiniteAutomaton::exponentially_ambiguous}, + //{9, "a*((ab)*)*", thompson, FiniteAutomaton::exponentially_ambiguous}, + {10, "(aa|aa)(aa|bb)*|a(ba)*", glushkov, FiniteAutomaton::almost_unambigious}, + {11, "(aaa)*(a|)(a|)", ilieyu, FiniteAutomaton::almost_unambigious}, + {12, "(a|)(ab|aaa|baa)*(a|)", glushkov, FiniteAutomaton::almost_unambigious}, + {13, "(a|b|c)*(d|d)*(a|b|c|d)*", glushkov, FiniteAutomaton::almost_unambigious}, + {14, "(ac*|ad*)*", glushkov, FiniteAutomaton::exponentially_ambiguous}, + {15, "(a|b|c)*(a|b|c|d)(a|b|c)*|(a|b)*ca*", glushkov, FiniteAutomaton::almost_unambigious}, + {16, "(a|b|c)*(a|b|c|d)(a|b|c)*|(ac*|ad*)*", glushkov, FiniteAutomaton::almost_unambigious}, + {17, + "(ab)*ab(ab)*|(ac)*(ac)*|(d|c)*", // (abab)*abab(abab)*|(aac)*(aac)*|(b|d|c)* + glushkov, FiniteAutomaton::almost_unambigious}, + {18, "(abab)*abab(abab)*|(aac)*(aac)*", glushkov, FiniteAutomaton::polynomially_ambigious}, + {19, "(ab)*ab(ab)*", // (abab)*abab(abab)* + glushkov, FiniteAutomaton::polynomially_ambigious}, + {20, "(ab)*ab(ab)*|(ac)*(ac)*", glushkov, FiniteAutomaton::polynomially_ambigious}, + // {21, "(a|b)*(f*)*q", thompson, + // FiniteAutomaton::exponentially_ambiguous}, + {22, "((bb*c|c)c*b|bb*b|b)(b|(c|bb*c)c*b|bb*b)*", glushkov, + FiniteAutomaton::exponentially_ambiguous}, + }; + + for_each(tests.begin(), tests.end(), [](const Test& test) { + auto [test_number, reg_string, type, expected_res] = test; + // cout << test_number << endl; + switch (type) { + case thompson: + ASSERT_TRUE(Regex(reg_string).to_thompson().ambiguity() == expected_res); + break; + case glushkov: + ASSERT_TRUE(Regex(reg_string).to_glushkov().ambiguity() == expected_res); + break; + case ilieyu: + ASSERT_TRUE(Regex(reg_string).to_ilieyu().ambiguity() == expected_res); + break; + } + }); +} + +TEST(TestCaseName,Test_arden) { + auto test_equivalence = [](string rgx_str) { + Regex reg(rgx_str); + ASSERT_TRUE(Regex::equivalent(reg, reg.to_thompson().to_regex())); + ASSERT_TRUE(Regex::equivalent(reg, reg.to_glushkov().to_regex())); + ASSERT_TRUE(Regex::equivalent(reg, reg.to_ilieyu().to_regex())); + ASSERT_TRUE(Regex::equivalent(reg, reg.to_antimirov().to_regex())); + }; + + test_equivalence("a"); + test_equivalence("a*"); + test_equivalence("(ab)*a"); + test_equivalence("a(a)*ab(bb)*baa"); + test_equivalence("(b)*(b)"); + test_equivalence("a*|"); + test_equivalence("|b((b((a)*)(a(|(a))))*)"); + test_equivalence("(((a*)))(((a(b|)|a)*||b))"); + test_equivalence("((b(((ba|b)|||(b))*)))"); + test_equivalence("(((((a*)((a*)|bb)(((|||((b)))))))))"); +} + +TEST(TestCaseName, Test_pump_length) { + ASSERT_TRUE(Regex("abaa").pump_length() == 5); +} + +TEST(TestCaseName, Test_fa_to_pgrammar) { + // cout << "fa to grammar\n"; + vector states1; + for (int i = 0; i < 5; i++) { + State s = {i, {i}, to_string(i), false, map>()}; + states1.push_back(s); + } + + states1[4].set_transition(1, "a"); + states1[1].set_transition(2, "b"); + states1[1].set_transition(4, "c"); + states1[2].set_transition(2, "b"); + states1[2].set_transition(2, "c"); + states1[2].is_terminal = true; + states1[0].set_transition(4, "c"); + states1[3].set_transition(0, "a"); + states1[3].set_transition(0, "b"); + states1[4].is_terminal = true; + FiniteAutomaton dfa1 = FiniteAutomaton(3, states1, {"a", "b", "c"}); + + Grammar g; + + // cout << "1\n"; + g.fa_to_prefix_grammar(dfa1); + // cout << "2\n"; + ASSERT_TRUE(FiniteAutomaton::equivalent(dfa1, g.prefix_grammar_to_automaton())); + // cout << "3\n"; + g.fa_to_prefix_grammar_TM(dfa1); + // cout << "4\n"; + ASSERT_TRUE(FiniteAutomaton::equivalent(dfa1, g.prefix_grammar_to_automaton())); +} + +TEST(TestCaseName, Test_is_one_unambiguous) { + Regex r1("(a|b)*a"); + Regex r2("(a|b)*(ac|bd)"); + Regex r3("(a|b)*a(a|b)"); + Regex r4("(c(a|b)*c)*"); + Regex r5("a(bbb*aaa*)*bb*|aaa*(bbb*aaa*)*|b(aaa*bbb*)*aa*|"); + + // ok + ASSERT_TRUE(r1.to_glushkov().is_one_unambiguous()); + // doesn't fulfills the orbit property + ASSERT_TRUE(!r2.to_glushkov().is_one_unambiguous()); + // consists of a single orbit, but neither a nor b is consistent + ASSERT_TRUE(!r3.to_glushkov().is_one_unambiguous()); + // ok + ASSERT_TRUE(r4.to_glushkov().is_one_unambiguous()); + // doesn't fulfills the orbit property + ASSERT_TRUE(!r5.to_glushkov().is_one_unambiguous()); +}; + +TEST(TestCaseName, Test_get_one_unambiguous_regex) { + auto check_one_unambiguous = [](string rgx_str, bool expected_res) { + ASSERT_TRUE(Regex(rgx_str).get_one_unambiguous_regex().is_one_unambiguous() == expected_res); + }; + // ok + check_one_unambiguous("(a|b)*a", true); + // doesn't fulfills the orbit property + check_one_unambiguous("(a|b)*(ac|bd)", false); + // consists of a single orbit, but neither a nor b is consistent + check_one_unambiguous("(a|b)*a(a|b)", false); + // ok + check_one_unambiguous("(c(a|b)*c)*", true); + // doesn't fulfills the orbit property + check_one_unambiguous("a(bbb*aaa*)*bb*|aaa*(bbb*aaa*)*|b(aaa*bbb*)*aa*|", false); +} + +TEST(TestCaseName, test_interpreter) { + Interpreter interpreter; + interpreter.set_log_mode(Interpreter::LogMode::nothing); + ASSERT_TRUE(!interpreter.run_line("A = Annote (Glushkova {a})")); + ASSERT_TRUE(interpreter.run_line(" N1 = ( ( Glushkov ({ab|a}) )) ")); + ASSERT_TRUE(interpreter.run_line(" N2 = (Annote N1)")); + ASSERT_TRUE(!interpreter.run_line("N2 = (Glushkov N1)")); + ASSERT_TRUE(!interpreter.run_line("Equiv N1 N3")); + ASSERT_TRUE(interpreter.run_line(" Equiv (( N1)) ( (Reverse .Reverse (N2) !! ))")); + ASSERT_TRUE(interpreter.run_line("Test (Glushkov {a*}) {a*} 1")); + + ASSERT_TRUE(interpreter.run_line("A = Annote.Glushkov.DeAnnote {a}")); + ASSERT_TRUE(interpreter.run_line("B = Annote (Glushkov.DeAnnote {a})")); + ASSERT_TRUE(interpreter.run_line("B = Annote (Glushkov(DeAnnote {a}))")); + ASSERT_TRUE(interpreter.run_line("A = Annote .Glushkov. DeAnnote {a} !! ")); + ASSERT_TRUE(interpreter.run_line("B = Annote (Glushkov.DeAnnote {a}) !! ")); + ASSERT_TRUE(interpreter.run_line("B = Annote ( Glushkov(DeAnnote {a})) !! ")); + ASSERT_TRUE(interpreter.run_line("B = Annote (Glushkov {a} !!)")); + ASSERT_TRUE(interpreter.run_line("B = Annote (Glushkov(DeAnnote {a} !!) !!) !!")); + + // Arrays + ASSERT_TRUE(interpreter.run_line("A = []")); + ASSERT_TRUE(interpreter.run_line("A = [[] []]")); + ASSERT_TRUE(interpreter.run_line("A = [{a} {b}]")); + ASSERT_TRUE(interpreter.run_line("A = [[(([{a}]))] [{a} []]]")); + ASSERT_TRUE(!interpreter.run_line("A = [[(([{a}])] [{a} []]]")); + ASSERT_TRUE(!interpreter.run_line("A = [[([{a}]))] [{a} []]]")); + ASSERT_TRUE(!interpreter.run_line("A = [[(([{a}]))] [{a} []]")); + ASSERT_TRUE(!interpreter.run_line("A = [[(([a}]))] [{a} (Glushkov(DeAnnote {a} !!) !!) []]]")); + + // Normalize + ASSERT_TRUE(interpreter.run_line("A = Normalize {abc} [[{a} {b}]]")); + ASSERT_TRUE(!interpreter.run_line("A = Normalize {abc} [[{a} []]]")); +} + +TEST(TestCaseName, Test_TransformationMonoid) { + FiniteAutomaton fa1 = Regex("a*b*c*").to_thompson().minimize(); + TransformationMonoid tm1(fa1); + ASSERT_TRUE(tm1.class_card() == 7); + ASSERT_TRUE(tm1.class_length() == 2); + ASSERT_TRUE(tm1.is_minimal()); + ASSERT_TRUE(tm1.get_classes_number_MyhillNerode() == 3); + + vector states; + for (int i = 0; i < 5; i++) { + State s = {i, {i}, to_string(i), false, map>()}; + states.push_back(s); + } + states[0].set_transition(1, "a"); + states[1].set_transition(2, "c"); + states[2].set_transition(3, "a"); + states[3].set_transition(2, "c"); + states[3].set_transition(4, "b"); + states[4].set_transition(4, "b"); + states[4].set_transition(4, "c"); + states[4].is_terminal = true; + FiniteAutomaton fa2(0, states, {"a", "b", "c"}); + TransformationMonoid tm2(fa2); + ASSERT_TRUE(tm2.class_card() == 12); + ASSERT_TRUE(tm2.class_length() == 4); + ASSERT_TRUE(tm2.is_minimal() == 1); + ASSERT_TRUE(tm2.get_classes_number_MyhillNerode() == 5); + + FiniteAutomaton fa3 = Regex("ab|b").to_glushkov().minimize(); + TransformationMonoid tm3(fa3); + ASSERT_TRUE(tm3.is_minimal()); + + FiniteAutomaton fa4 = Regex("a").to_glushkov().minimize(); + TransformationMonoid tm4(fa4); + ASSERT_TRUE(tm4.is_minimal()); + + FiniteAutomaton fa5 = Regex("b*a*").to_thompson().minimize(); + TransformationMonoid tm5(fa5); + ASSERT_TRUE(tm5.is_minimal()); +} + +TEST(TestCaseName, Test_GlaisterShallit) { + auto check_classes_number = [](string rgx_str, int num) { + ASSERT_TRUE(Regex(rgx_str).to_glushkov().get_classes_number_GlaisterShallit() == num); + }; + check_classes_number("abc", 4); + check_classes_number("a*b*c*", 3); + check_classes_number("aa*bb*cc*", 4); + check_classes_number("ab|abc", 4); + check_classes_number("a(a|b)*(a|b)", 3); + check_classes_number("a((a|b)*)*(b|c)", 3); + check_classes_number("a(b|c)(a|b)(b|c)", 5); + check_classes_number("abc|bca", 6); + check_classes_number("abc|bbc", 4); +} \ No newline at end of file diff --git a/apps/TestsApp/src/main.cpp b/apps/TestsApp/src/main.cpp index f0b2890d..3dc1ee5b 100644 --- a/apps/TestsApp/src/main.cpp +++ b/apps/TestsApp/src/main.cpp @@ -2,16 +2,15 @@ // #include "gmock/gmock.h" #include "gtest/gtest.h" #include +#include using namespace std; + int main(int argc, char **argv) { cout << "Test\n"; // Тестирование - // Example::test_all(); - // Example::all_examples(); - // Example::logger_test(); - testing::InitGoogleTest(&argc, argv); - return RUN_ALL_TESTS(); + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS();; } From 2fabd3d1a5f3056f8251e86f558f59ec9d610175 Mon Sep 17 00:00:00 2001 From: DanilaKn Date: Mon, 6 Nov 2023 13:32:21 +0300 Subject: [PATCH 08/18] =?UTF-8?q?(#283)=20=D0=A3=D0=B1=D1=80=D0=B0=D0=BB?= =?UTF-8?q?=20=D0=BC=D0=B5=D1=82=D0=BE=D0=B4=D1=8B=20=D1=81=20assert=20?= =?UTF-8?q?=D0=B8=D0=B7=20Example?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/TestsApp/include/TestsApp/Example.h | 19 - apps/TestsApp/src/Example.cpp | 462 ----------------------- apps/TestsApp/src/UnitTests.cpp | 2 +- apps/TestsApp/src/main.cpp | 1 - 4 files changed, 1 insertion(+), 483 deletions(-) diff --git a/apps/TestsApp/include/TestsApp/Example.h b/apps/TestsApp/include/TestsApp/Example.h index f0a7ce26..7948173f 100644 --- a/apps/TestsApp/include/TestsApp/Example.h +++ b/apps/TestsApp/include/TestsApp/Example.h @@ -27,7 +27,6 @@ class Example { static void intersection(); static void regex_parsing(); static void regex_generating(); - static void random_regex_parsing(); static void tasks_generating(); static void parsing_regex(string); static void transformation_monoid_example(); @@ -48,22 +47,4 @@ class Example { static void arden_lemma_testing(); static void fa_to_pgrammar(); static void logger_test(); - - // запуск всех тестов - static void test_all(); - static void test_fa_equal(); - static void test_fa_equiv(); - static void test_bisimilar(); - static void test_regex_subset(); - static void test_merge_bisimilar(); - static void test_regex_equal(); - static void test_ambiguity(); - static void test_arden(); - static void test_pump_length(); - static void test_is_one_unambiguous(); - static void test_get_one_unambiguous_regex(); - static void test_interpreter(); - static void test_TransformationMonoid(); - static void test_GlaisterShallit(); - static void test_fa_to_pgrammar(); }; \ No newline at end of file diff --git a/apps/TestsApp/src/Example.cpp b/apps/TestsApp/src/Example.cpp index 5c3fe326..d744bbf6 100644 --- a/apps/TestsApp/src/Example.cpp +++ b/apps/TestsApp/src/Example.cpp @@ -187,19 +187,6 @@ void Example::tasks_generating() { cout << "\n" << TG.generate_task(5, 6, false, true); // для динам. тайпчека } -void Example::random_regex_parsing() { - RegexGenerator rg(15, 10, 5, 3); - for (int i = 0; i < 30; i++) { - string str = rg.generate_regex(); - cout << "\n" << str << "\n"; - Regex r1(str); - string r1_str = r1.to_txt(); - Regex r2(r1_str); - cout << r1_str << endl; - assert(Regex::equivalent(r1, r2)); - } -} - void Example::parsing_regex(string str) { cout << str << endl; Regex r(str); @@ -533,297 +520,6 @@ void Example::arden_lemma_testing() { }); } -// TEST - -void Example::test_all() { - test_fa_equal(); - test_fa_equiv(); - test_bisimilar(); - test_regex_subset(); - test_merge_bisimilar(); - test_regex_equal(); - test_ambiguity(); - test_arden(); - test_pump_length(); - test_is_one_unambiguous(); - test_get_one_unambiguous_regex(); - test_interpreter(); - test_TransformationMonoid(); - test_GlaisterShallit(); - test_fa_to_pgrammar(); - cout << "all tests passed\n\n"; -} - -void Example::test_fa_equal() { - vector states1; - for (int i = 0; i < 6; i++) { - State s = {i, {i}, to_string(i), false, map>()}; - states1.push_back(s); - } - states1[0].set_transition(1, "b"); - states1[0].set_transition(2, "b"); - states1[0].set_transition(5, "c"); - states1[1].set_transition(3, "a"); - states1[1].set_transition(4, "c"); - states1[2].set_transition(4, "a"); - states1[5].set_transition(4, "a"); - states1[3].is_terminal = true; - states1[4].is_terminal = true; - FiniteAutomaton fa1(0, states1, {"a", "b", "c"}); - - vector states2; - for (int i = 0; i < 6; i++) { - State s = {i, {i}, to_string(i), false, map>()}; - states2.push_back(s); - } - states2[0].set_transition(1, "b"); - states2[0].set_transition(2, "b"); - states2[0].set_transition(5, "c"); - states2[1].set_transition(3, "a"); - states2[1].set_transition(3, "c"); - states2[2].set_transition(4, "a"); - states2[5].set_transition(4, "a"); - states2[3].is_terminal = true; - states2[4].is_terminal = true; - FiniteAutomaton fa2(0, states2, {"a", "b", "c"}); - - vector states3; - for (int i = 0; i < 6; i++) { - State s = {i, {i}, to_string(i), false, map>()}; - states3.push_back(s); - } - states3[5].set_transition(4, "b"); - states3[5].set_transition(3, "b"); - states3[5].set_transition(0, "c"); - states3[4].set_transition(2, "a"); - states3[4].set_transition(1, "c"); - states3[3].set_transition(1, "a"); - states3[0].set_transition(1, "a"); - states3[2].is_terminal = true; - states3[1].is_terminal = true; - FiniteAutomaton fa3(5, states3, {"a", "b", "c"}); - - assert(FiniteAutomaton::equal(fa1, fa1)); - assert(!FiniteAutomaton::equal(fa1, fa2)); - assert(FiniteAutomaton::equal(fa1, fa3)); - assert(FiniteAutomaton::equal(Regex("(aab|aab)*").to_thompson().remove_eps(), - Regex("(aab|aab)*").to_glushkov())); - assert(FiniteAutomaton::equal(Regex("a(a)*ab(bb)*baa").to_thompson().remove_eps(), - Regex("a(a)*ab(bb)*baa").to_glushkov())); - assert(FiniteAutomaton::equal( - Regex("a(bbb*aaa*)*bb*|aaa*(bbb*aaa*)*|b(aaa*bbb*)*aa*|bbb*(aaa*bbb*)*") - .to_thompson() - .remove_eps(), - Regex("a(bbb*aaa*)*bb*|aaa*(bbb*aaa*)*|b(aaa*bbb*)*aa*|bbb*(aaa*bbb*)*").to_glushkov())); -} - -void Example::test_fa_equiv() { - vector states1; - for (int i = 0; i < 3; i++) { - State s = {i, {i}, to_string(i), false, map>()}; - states1.push_back(s); - } - states1[0].set_transition(0, "c"); - states1[0].set_transition(1, "d"); - states1[1].set_transition(2, "c"); - states1[1].set_transition(0, "d"); - states1[2].set_transition(1, "c"); - states1[2].set_transition(2, "d"); - states1[0].is_terminal = true; - FiniteAutomaton fa1(0, states1, {"c", "d"}); - - vector states2; - for (int i = 0; i < 4; i++) { - State s = {i, {i}, to_string(i), false, map>()}; - states2.push_back(s); - } - states2[0].set_transition(0, "c"); - states2[0].set_transition(1, "d"); - states2[1].set_transition(2, "c"); - states2[1].set_transition(0, "d"); - states2[2].set_transition(3, "c"); - states2[2].set_transition(2, "d"); - states2[3].set_transition(2, "c"); - states2[3].set_transition(0, "d"); - states2[0].is_terminal = true; - FiniteAutomaton fa2(0, states2, {"c", "d"}); - - assert(FiniteAutomaton::equivalent(fa1, fa2)); -} - -void Example::test_bisimilar() { - vector states1; - for (int i = 0; i < 3; i++) { - State s = {i, {i}, to_string(i), false, map>()}; - states1.push_back(s); - } - states1[0].set_transition(1, "a"); - states1[0].set_transition(1, "eps"); - states1[0].set_transition(2, "b"); - states1[1].set_transition(2, "a"); - states1[1].set_transition(1, "b"); - states1[2].set_transition(1, "a"); - states1[2].set_transition(1, "eps"); - states1[2].set_transition(0, "b"); - states1[0].is_terminal = true; - states1[2].is_terminal = true; - FiniteAutomaton fa1(1, states1, {"a", "b"}); - - vector states2; - for (int i = 0; i < 2; i++) { - State s = {i, {i}, to_string(i), false, map>()}; - states2.push_back(s); - } - states2[0].set_transition(1, "a"); - states2[0].set_transition(1, "eps"); - states2[0].set_transition(0, "b"); - states2[1].set_transition(0, "a"); - states2[1].set_transition(1, "b"); - states2[0].is_terminal = true; - FiniteAutomaton fa2(1, states2, {"a", "b"}); - - assert(FiniteAutomaton::bisimilar(fa1, fa2)); -} - -void Example::test_merge_bisimilar() { - FiniteAutomaton fa = Regex("(a|b)*b").to_glushkov(); - FiniteAutomaton fa1 = fa.merge_bisimilar(); - - vector states2; - for (int i = 0; i < 3; i++) { - State s = {i, {i}, to_string(i), false, map>()}; - states2.push_back(s); - } - states2[0].set_transition(1, "a"); - states2[0].set_transition(1, "eps"); - states2[0].set_transition(2, "b"); - states2[1].set_transition(2, "a"); - states2[1].set_transition(1, "b"); - states2[2].set_transition(1, "a"); - states2[2].set_transition(1, "eps"); - states2[2].set_transition(0, "b"); - states2[0].is_terminal = true; - states2[2].is_terminal = true; - FiniteAutomaton fa2(1, states2, {"a", "b"}); - - vector states3; - for (int i = 0; i < 2; i++) { - State s = {i, {i}, to_string(i), false, map>()}; - states3.push_back(s); - } - states3[0].set_transition(0, "b"); - states3[0].set_transition(1, "a"); - states3[1].set_transition(0, "eps"); - states3[1].set_transition(0, "a"); - states3[1].set_transition(1, "b"); - states3[1].is_terminal = true; - FiniteAutomaton fa3(0, states3, {"a", "b"}); - - assert(FiniteAutomaton::equal(Regex("(a|b)*b").to_ilieyu(), fa1)); - assert(FiniteAutomaton::equal(fa2.merge_bisimilar(), fa3)); -} - -void Example::test_regex_subset() { - Regex r1("a*baa"); - Regex r2("abaa"); - - assert(r1.subset(r2)); - assert(!r2.subset(r1)); - assert(!Regex("ab*").subset(Regex("a*b*"))); -} - -void Example::test_regex_equal() { - Regex r1("a(bbb*aaa*)*bb*|aaa*(bbb*aaa*)*"); - Regex r2("aaa*(bbb*aaa*)*|a(bbb*aaa*)*bb*"); - Regex r3("a(bbb*aaa*)*bb*|aaa*(bbb*aaa*)"); - - assert(Regex::equal(r1, r2)); - assert(!Regex::equal(r1.linearize(), r1)); - assert(Regex::equal(r1.linearize(), r1.linearize())); - assert(!Regex::equal(r1, r3)); -} - -void Example::test_ambiguity() { - enum AutomatonType { - thompson, - glushkov, - ilieyu - }; - using Test = tuple; - vector tests = { - //{0, "(a*)*", thompson, FiniteAutomaton::exponentially_ambiguous}, - {1, "a*a*", glushkov, FiniteAutomaton::polynomially_ambigious}, - {2, "abc", thompson, FiniteAutomaton::unambigious}, - //{3, "b|a", thompson, FiniteAutomaton::almost_unambigious}, - {4, "(aa|aa)*", glushkov, FiniteAutomaton::exponentially_ambiguous}, - {5, "(aab|aab)*", glushkov, FiniteAutomaton::exponentially_ambiguous}, - {6, "a*a*((a)*)*", glushkov, FiniteAutomaton::polynomially_ambigious}, - //{7, "a*a*((a)*)*", thompson, - // FiniteAutomaton::exponentially_ambiguous}, - //{8, "a*(b*)*", thompson, FiniteAutomaton::exponentially_ambiguous}, - //{9, "a*((ab)*)*", thompson, FiniteAutomaton::exponentially_ambiguous}, - {10, "(aa|aa)(aa|bb)*|a(ba)*", glushkov, FiniteAutomaton::almost_unambigious}, - {11, "(aaa)*(a|)(a|)", ilieyu, FiniteAutomaton::almost_unambigious}, - {12, "(a|)(ab|aaa|baa)*(a|)", glushkov, FiniteAutomaton::almost_unambigious}, - {13, "(a|b|c)*(d|d)*(a|b|c|d)*", glushkov, FiniteAutomaton::almost_unambigious}, - {14, "(ac*|ad*)*", glushkov, FiniteAutomaton::exponentially_ambiguous}, - {15, "(a|b|c)*(a|b|c|d)(a|b|c)*|(a|b)*ca*", glushkov, FiniteAutomaton::almost_unambigious}, - {16, "(a|b|c)*(a|b|c|d)(a|b|c)*|(ac*|ad*)*", glushkov, FiniteAutomaton::almost_unambigious}, - {17, - "(ab)*ab(ab)*|(ac)*(ac)*|(d|c)*", // (abab)*abab(abab)*|(aac)*(aac)*|(b|d|c)* - glushkov, FiniteAutomaton::almost_unambigious}, - {18, "(abab)*abab(abab)*|(aac)*(aac)*", glushkov, FiniteAutomaton::polynomially_ambigious}, - {19, "(ab)*ab(ab)*", // (abab)*abab(abab)* - glushkov, FiniteAutomaton::polynomially_ambigious}, - {20, "(ab)*ab(ab)*|(ac)*(ac)*", glushkov, FiniteAutomaton::polynomially_ambigious}, - // {21, "(a|b)*(f*)*q", thompson, - // FiniteAutomaton::exponentially_ambiguous}, - {22, "((bb*c|c)c*b|bb*b|b)(b|(c|bb*c)c*b|bb*b)*", glushkov, - FiniteAutomaton::exponentially_ambiguous}, - }; - - for_each(tests.begin(), tests.end(), [](const Test& test) { - auto [test_number, reg_string, type, expected_res] = test; - cout << test_number << endl; - switch (type) { - case thompson: - assert(Regex(reg_string).to_thompson().ambiguity() == expected_res); - break; - case glushkov: - assert(Regex(reg_string).to_glushkov().ambiguity() == expected_res); - break; - case ilieyu: - assert(Regex(reg_string).to_ilieyu().ambiguity() == expected_res); - break; - } - }); -} - -void Example::test_arden() { - auto test_equivalence = [](string rgx_str) { - Regex reg(rgx_str); - assert(Regex::equivalent(reg, reg.to_thompson().to_regex())); - assert(Regex::equivalent(reg, reg.to_glushkov().to_regex())); - assert(Regex::equivalent(reg, reg.to_ilieyu().to_regex())); - assert(Regex::equivalent(reg, reg.to_antimirov().to_regex())); - }; - - test_equivalence("a"); - test_equivalence("a*"); - test_equivalence("(ab)*a"); - test_equivalence("a(a)*ab(bb)*baa"); - test_equivalence("(b)*(b)"); - test_equivalence("a*|"); - test_equivalence("|b((b((a)*)(a(|(a))))*)"); - test_equivalence("(((a*)))(((a(b|)|a)*||b))"); - test_equivalence("((b(((ba|b)|||(b))*)))"); - test_equivalence("(((((a*)((a*)|bb)(((|||((b)))))))))"); -} - -void Example::test_pump_length() { - assert(Regex("abaa").pump_length() == 5); -} - void Example::fa_to_pgrammar() { FiniteAutomaton a1 = Regex("(c,1(ab*a|b*)*d,1)|(c,2(ba*b|a*)*d,25)") .to_glushkov() @@ -868,162 +564,4 @@ void Example::fa_to_pgrammar() { cout << g.pg_to_txt(); cout << "+++++++++++++++++++++++++++++" << endl; cout << g.prefix_grammar_to_automaton().to_txt(); -} - -void Example::test_fa_to_pgrammar() { - // cout << "fa to grammar\n"; - vector states1; - for (int i = 0; i < 5; i++) { - State s = {i, {i}, to_string(i), false, map>()}; - states1.push_back(s); - } - - states1[4].set_transition(1, "a"); - states1[1].set_transition(2, "b"); - states1[1].set_transition(4, "c"); - states1[2].set_transition(2, "b"); - states1[2].set_transition(2, "c"); - states1[2].is_terminal = true; - states1[0].set_transition(4, "c"); - states1[3].set_transition(0, "a"); - states1[3].set_transition(0, "b"); - states1[4].is_terminal = true; - FiniteAutomaton dfa1 = FiniteAutomaton(3, states1, {"a", "b", "c"}); - - Grammar g; - - // cout << "1\n"; - g.fa_to_prefix_grammar(dfa1); - // cout << "2\n"; - assert(FiniteAutomaton::equivalent(dfa1, g.prefix_grammar_to_automaton())); - // cout << "3\n"; - g.fa_to_prefix_grammar_TM(dfa1); - // cout << "4\n"; - assert(FiniteAutomaton::equivalent(dfa1, g.prefix_grammar_to_automaton())); -} - -void Example::test_is_one_unambiguous() { - Regex r1("(a|b)*a"); - Regex r2("(a|b)*(ac|bd)"); - Regex r3("(a|b)*a(a|b)"); - Regex r4("(c(a|b)*c)*"); - Regex r5("a(bbb*aaa*)*bb*|aaa*(bbb*aaa*)*|b(aaa*bbb*)*aa*|"); - - // ok - assert(r1.to_glushkov().is_one_unambiguous()); - // doesn't fulfills the orbit property - assert(!r2.to_glushkov().is_one_unambiguous()); - // consists of a single orbit, but neither a nor b is consistent - assert(!r3.to_glushkov().is_one_unambiguous()); - // ok - assert(r4.to_glushkov().is_one_unambiguous()); - // doesn't fulfills the orbit property - assert(!r5.to_glushkov().is_one_unambiguous()); -}; - -void Example::test_get_one_unambiguous_regex() { - auto check_one_unambiguous = [](string rgx_str, bool expected_res) { - assert(Regex(rgx_str).get_one_unambiguous_regex().is_one_unambiguous() == expected_res); - }; - // ok - check_one_unambiguous("(a|b)*a", true); - // doesn't fulfills the orbit property - check_one_unambiguous("(a|b)*(ac|bd)", false); - // consists of a single orbit, but neither a nor b is consistent - check_one_unambiguous("(a|b)*a(a|b)", false); - // ok - check_one_unambiguous("(c(a|b)*c)*", true); - // doesn't fulfills the orbit property - check_one_unambiguous("a(bbb*aaa*)*bb*|aaa*(bbb*aaa*)*|b(aaa*bbb*)*aa*|", false); -} - -void Example::test_interpreter() { - Interpreter interpreter; - interpreter.set_log_mode(Interpreter::LogMode::nothing); - assert(!interpreter.run_line("A = Annote (Glushkova {a})")); - assert(interpreter.run_line(" N1 = ( ( Glushkov ({ab|a}) )) ")); - assert(interpreter.run_line(" N2 = (Annote N1)")); - assert(!interpreter.run_line("N2 = (Glushkov N1)")); - assert(!interpreter.run_line("Equiv N1 N3")); - assert(interpreter.run_line(" Equiv (( N1)) ( (Reverse .Reverse (N2) !! ))")); - assert(interpreter.run_line("Test (Glushkov {a*}) {a*} 1")); - - assert(interpreter.run_line("A = Annote.Glushkov.DeAnnote {a}")); - assert(interpreter.run_line("B = Annote (Glushkov.DeAnnote {a})")); - assert(interpreter.run_line("B = Annote (Glushkov(DeAnnote {a}))")); - assert(interpreter.run_line("A = Annote .Glushkov. DeAnnote {a} !! ")); - assert(interpreter.run_line("B = Annote (Glushkov.DeAnnote {a}) !! ")); - assert(interpreter.run_line("B = Annote ( Glushkov(DeAnnote {a})) !! ")); - assert(interpreter.run_line("B = Annote (Glushkov {a} !!)")); - assert(interpreter.run_line("B = Annote (Glushkov(DeAnnote {a} !!) !!) !!")); - - // Arrays - assert(interpreter.run_line("A = []")); - assert(interpreter.run_line("A = [[] []]")); - assert(interpreter.run_line("A = [{a} {b}]")); - assert(interpreter.run_line("A = [[(([{a}]))] [{a} []]]")); - assert(!interpreter.run_line("A = [[(([{a}])] [{a} []]]")); - assert(!interpreter.run_line("A = [[([{a}]))] [{a} []]]")); - assert(!interpreter.run_line("A = [[(([{a}]))] [{a} []]")); - assert(!interpreter.run_line("A = [[(([a}]))] [{a} (Glushkov(DeAnnote {a} !!) !!) []]]")); - - // Normalize - assert(interpreter.run_line("A = Normalize {abc} [[{a} {b}]]")); - assert(!interpreter.run_line("A = Normalize {abc} [[{a} []]]")); -} - -void Example::test_TransformationMonoid() { - FiniteAutomaton fa1 = Regex("a*b*c*").to_thompson().minimize(); - TransformationMonoid tm1(fa1); - assert(tm1.class_card() == 7); - assert(tm1.class_length() == 2); - assert(tm1.is_minimal()); - assert(tm1.get_classes_number_MyhillNerode() == 3); - - vector states; - for (int i = 0; i < 5; i++) { - State s = {i, {i}, to_string(i), false, map>()}; - states.push_back(s); - } - states[0].set_transition(1, "a"); - states[1].set_transition(2, "c"); - states[2].set_transition(3, "a"); - states[3].set_transition(2, "c"); - states[3].set_transition(4, "b"); - states[4].set_transition(4, "b"); - states[4].set_transition(4, "c"); - states[4].is_terminal = true; - FiniteAutomaton fa2(0, states, {"a", "b", "c"}); - TransformationMonoid tm2(fa2); - assert(tm2.class_card() == 12); - assert(tm2.class_length() == 4); - assert(tm2.is_minimal() == 1); - assert(tm2.get_classes_number_MyhillNerode() == 5); - - FiniteAutomaton fa3 = Regex("ab|b").to_glushkov().minimize(); - TransformationMonoid tm3(fa3); - assert(tm3.is_minimal()); - - FiniteAutomaton fa4 = Regex("a").to_glushkov().minimize(); - TransformationMonoid tm4(fa4); - assert(tm4.is_minimal()); - - FiniteAutomaton fa5 = Regex("b*a*").to_thompson().minimize(); - TransformationMonoid tm5(fa5); - assert(tm5.is_minimal()); -} - -void Example::test_GlaisterShallit() { - auto check_classes_number = [](string rgx_str, int num) { - assert(Regex(rgx_str).to_glushkov().get_classes_number_GlaisterShallit() == num); - }; - check_classes_number("abc", 4); - check_classes_number("a*b*c*", 3); - check_classes_number("aa*bb*cc*", 4); - check_classes_number("ab|abc", 4); - check_classes_number("a(a|b)*(a|b)", 3); - check_classes_number("a((a|b)*)*(b|c)", 3); - check_classes_number("a(b|c)(a|b)(b|c)", 5); - check_classes_number("abc|bca", 6); - check_classes_number("abc|bbc", 4); } \ No newline at end of file diff --git a/apps/TestsApp/src/UnitTests.cpp b/apps/TestsApp/src/UnitTests.cpp index aa22198e..0a047e9a 100644 --- a/apps/TestsApp/src/UnitTests.cpp +++ b/apps/TestsApp/src/UnitTests.cpp @@ -13,7 +13,7 @@ #include #include "gtest/gtest.h" -TEST(TestCaseName, GlaisterShallit) { +TEST(TestCaseName, Test_GlaisterShallit) { auto check_classes_number = [](string rgx_str) { return (Regex(rgx_str).to_glushkov().get_classes_number_GlaisterShallit()); diff --git a/apps/TestsApp/src/main.cpp b/apps/TestsApp/src/main.cpp index 3dc1ee5b..79a0482a 100644 --- a/apps/TestsApp/src/main.cpp +++ b/apps/TestsApp/src/main.cpp @@ -1,5 +1,4 @@ #include "TestsApp/Example.h" -// #include "gmock/gmock.h" #include "gtest/gtest.h" #include #include From f2dce378ae4c1089918fdc798bb0b779548750af Mon Sep 17 00:00:00 2001 From: DanilaKn Date: Mon, 6 Nov 2023 13:36:59 +0300 Subject: [PATCH 09/18] =?UTF-8?q?(#283)=20=D0=98=D1=81=D0=BF=D1=80=D0=B0?= =?UTF-8?q?=D0=B2=D0=BB=D0=B5=D0=BD=D0=B8=D0=B5=20=D1=82=D0=B5=D1=81=D1=82?= =?UTF-8?q?=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/TestsApp/src/UnitTests.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/TestsApp/src/UnitTests.cpp b/apps/TestsApp/src/UnitTests.cpp index 0a047e9a..a467b45c 100644 --- a/apps/TestsApp/src/UnitTests.cpp +++ b/apps/TestsApp/src/UnitTests.cpp @@ -13,7 +13,7 @@ #include #include "gtest/gtest.h" -TEST(TestCaseName, Test_GlaisterShallit) { +TEST(TestCaseName, Test_glaister_shallit) { auto check_classes_number = [](string rgx_str) { return (Regex(rgx_str).to_glushkov().get_classes_number_GlaisterShallit()); From 661144504cb4a3c722808d95a343ae01cf583668 Mon Sep 17 00:00:00 2001 From: Alexander Delman Date: Mon, 6 Nov 2023 15:55:05 +0300 Subject: [PATCH 10/18] (#283) formatting --- apps/TestsApp/src/UnitTests.cpp | 52 ++++++++++----------------------- apps/TestsApp/src/main.cpp | 7 ++--- 2 files changed, 17 insertions(+), 42 deletions(-) diff --git a/apps/TestsApp/src/UnitTests.cpp b/apps/TestsApp/src/UnitTests.cpp index a467b45c..54f9d24b 100644 --- a/apps/TestsApp/src/UnitTests.cpp +++ b/apps/TestsApp/src/UnitTests.cpp @@ -1,33 +1,14 @@ #include "AutomatonToImage/AutomatonToImage.h" #include "InputGenerator/RegexGenerator.h" -#include "InputGenerator/TasksGenerator.h" #include "Interpreter/Interpreter.h" #include "Objects/FiniteAutomaton.h" #include "Objects/Grammar.h" #include "Objects/Language.h" #include "Objects/Regex.h" #include "Objects/TransformationMonoid.h" -#include "Objects/iLogTemplate.h" #include "Tester/Tester.h" -#include -#include #include "gtest/gtest.h" - -TEST(TestCaseName, Test_glaister_shallit) { - - auto check_classes_number = [](string rgx_str) { - return (Regex(rgx_str).to_glushkov().get_classes_number_GlaisterShallit()); - }; - ASSERT_EQ(1, 1); - ASSERT_EQ(check_classes_number("abs"), 4); - ASSERT_EQ(check_classes_number("a*b*c*"), 3); - ASSERT_EQ(check_classes_number("aa*bb*cc*"), 4); - ASSERT_EQ(check_classes_number("ab|abc"), 4); - ASSERT_EQ(check_classes_number("a(b|c)(a|b)(b|c)"), 5); - -} - - +#include TEST(TestCaseName, Test_random_regex_parsing) { RegexGenerator rg(15, 10, 5, 3); @@ -40,7 +21,6 @@ TEST(TestCaseName, Test_random_regex_parsing) { } } - TEST(TestCaseName, Test_fa_equal) { vector states1; for (int i = 0; i < 6; i++) { @@ -94,9 +74,9 @@ TEST(TestCaseName, Test_fa_equal) { ASSERT_TRUE(!FiniteAutomaton::equal(fa1, fa2)); ASSERT_TRUE(FiniteAutomaton::equal(fa1, fa3)); ASSERT_TRUE(FiniteAutomaton::equal(Regex("(aab|aab)*").to_thompson().remove_eps(), - Regex("(aab|aab)*").to_glushkov())); + Regex("(aab|aab)*").to_glushkov())); ASSERT_TRUE(FiniteAutomaton::equal(Regex("a(a)*ab(bb)*baa").to_thompson().remove_eps(), - Regex("a(a)*ab(bb)*baa").to_glushkov())); + Regex("a(a)*ab(bb)*baa").to_glushkov())); ASSERT_TRUE(FiniteAutomaton::equal( Regex("a(bbb*aaa*)*bb*|aaa*(bbb*aaa*)*|b(aaa*bbb*)*aa*|bbb*(aaa*bbb*)*") .to_thompson() @@ -104,7 +84,6 @@ TEST(TestCaseName, Test_fa_equal) { Regex("a(bbb*aaa*)*bb*|aaa*(bbb*aaa*)*|b(aaa*bbb*)*aa*|bbb*(aaa*bbb*)*").to_glushkov())); } - TEST(TestCaseName, Test_fa_equiv) { vector states1; for (int i = 0; i < 3; i++) { @@ -139,8 +118,7 @@ TEST(TestCaseName, Test_fa_equiv) { ASSERT_TRUE(FiniteAutomaton::equivalent(fa1, fa2)); } - -TEST(TestCaseName, Test__bisimilar) { +TEST(TestCaseName, Test_bisimilar) { vector states1; for (int i = 0; i < 3; i++) { State s = {i, {i}, to_string(i), false, map>()}; @@ -212,7 +190,6 @@ TEST(TestCaseName, Test_merge_bisimilar) { ASSERT_TRUE(FiniteAutomaton::equal(fa2.merge_bisimilar(), fa3)); } - TEST(TestCaseName, Test_regex_subset) { Regex r1("a*baa"); Regex r2("abaa"); @@ -289,8 +266,8 @@ TEST(TestCaseName, Test_ambiguity) { }); } -TEST(TestCaseName,Test_arden) { - auto test_equivalence = [](string rgx_str) { +TEST(TestCaseName, Test_arden) { + auto test_equivalence = [](const string& rgx_str) { Regex reg(rgx_str); ASSERT_TRUE(Regex::equivalent(reg, reg.to_thompson().to_regex())); ASSERT_TRUE(Regex::equivalent(reg, reg.to_glushkov().to_regex())); @@ -355,29 +332,30 @@ TEST(TestCaseName, Test_is_one_unambiguous) { // ok ASSERT_TRUE(r1.to_glushkov().is_one_unambiguous()); - // doesn't fulfills the orbit property + // doesn't fulfill the orbit property ASSERT_TRUE(!r2.to_glushkov().is_one_unambiguous()); // consists of a single orbit, but neither a nor b is consistent ASSERT_TRUE(!r3.to_glushkov().is_one_unambiguous()); // ok ASSERT_TRUE(r4.to_glushkov().is_one_unambiguous()); - // doesn't fulfills the orbit property + // doesn't fulfill the orbit property ASSERT_TRUE(!r5.to_glushkov().is_one_unambiguous()); -}; +} TEST(TestCaseName, Test_get_one_unambiguous_regex) { - auto check_one_unambiguous = [](string rgx_str, bool expected_res) { - ASSERT_TRUE(Regex(rgx_str).get_one_unambiguous_regex().is_one_unambiguous() == expected_res); + auto check_one_unambiguous = [](const string& rgx_str, bool expected_res) { + ASSERT_TRUE(Regex(rgx_str).get_one_unambiguous_regex().is_one_unambiguous() == + expected_res); }; // ok check_one_unambiguous("(a|b)*a", true); - // doesn't fulfills the orbit property + // doesn't fulfill the orbit property check_one_unambiguous("(a|b)*(ac|bd)", false); // consists of a single orbit, but neither a nor b is consistent check_one_unambiguous("(a|b)*a(a|b)", false); // ok check_one_unambiguous("(c(a|b)*c)*", true); - // doesn't fulfills the orbit property + // doesn't fulfill the orbit property check_one_unambiguous("a(bbb*aaa*)*bb*|aaa*(bbb*aaa*)*|b(aaa*bbb*)*aa*|", false); } @@ -458,7 +436,7 @@ TEST(TestCaseName, Test_TransformationMonoid) { } TEST(TestCaseName, Test_GlaisterShallit) { - auto check_classes_number = [](string rgx_str, int num) { + auto check_classes_number = [](const string& rgx_str, int num) { ASSERT_TRUE(Regex(rgx_str).to_glushkov().get_classes_number_GlaisterShallit() == num); }; check_classes_number("abc", 4); diff --git a/apps/TestsApp/src/main.cpp b/apps/TestsApp/src/main.cpp index 79a0482a..3db9912d 100644 --- a/apps/TestsApp/src/main.cpp +++ b/apps/TestsApp/src/main.cpp @@ -4,12 +4,9 @@ #include using namespace std; - -int main(int argc, char **argv) { +int main(int argc, char** argv) { cout << "Test\n"; // Тестирование ::testing::InitGoogleTest(&argc, argv); - return RUN_ALL_TESTS();; + return RUN_ALL_TESTS(); } - - From 98ee9f8b11f48e47164397e2b4d994d4492f8fd9 Mon Sep 17 00:00:00 2001 From: DanilaKn Date: Wed, 8 Nov 2023 17:05:05 +0300 Subject: [PATCH 11/18] =?UTF-8?q?(#283)=20=D0=A0=D0=B0=D0=B7=D0=B4=D0=B5?= =?UTF-8?q?=D0=BB=D0=B8=D0=BB=20=D1=82=D0=B5=D1=81=D1=82=D1=8B=20=D0=BF?= =?UTF-8?q?=D0=BE=20=D1=82=D0=B8=D0=BF=D0=B0=D0=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/integrationTests.yml | 35 ++++++++++++++++++ .github/workflows/unitTests.yml | 2 +- CMakeLists.txt | 4 +- apps/IntegrationTestsApp/CMakeLists.txt | 37 +++++++++++++++++++ .../src/IntegrationTests.cpp | 1 + .../src/main.cpp | 3 +- apps/MetamorphicTestsApp/CMakeLists.txt | 37 +++++++++++++++++++ .../src/MetamorphicTests.cpp | 1 + apps/MetamorphicTestsApp/src/main.cpp | 11 ++++++ .../{TestsApp => UnitTestsApp}/CMakeLists.txt | 2 +- .../include/UnitTestsApp}/Example.h | 0 .../src/Example.cpp | 2 +- .../src/UnitTests.cpp | 0 apps/UnitTestsApp/src/main.cpp | 12 ++++++ 14 files changed, 141 insertions(+), 6 deletions(-) create mode 100644 .github/workflows/integrationTests.yml create mode 100644 apps/IntegrationTestsApp/CMakeLists.txt create mode 100644 apps/IntegrationTestsApp/src/IntegrationTests.cpp rename apps/{TestsApp => IntegrationTestsApp}/src/main.cpp (81%) create mode 100644 apps/MetamorphicTestsApp/CMakeLists.txt create mode 100644 apps/MetamorphicTestsApp/src/MetamorphicTests.cpp create mode 100644 apps/MetamorphicTestsApp/src/main.cpp rename apps/{TestsApp => UnitTestsApp}/CMakeLists.txt (97%) rename apps/{TestsApp/include/TestsApp => UnitTestsApp/include/UnitTestsApp}/Example.h (100%) rename apps/{TestsApp => UnitTestsApp}/src/Example.cpp (99%) rename apps/{TestsApp => UnitTestsApp}/src/UnitTests.cpp (100%) create mode 100644 apps/UnitTestsApp/src/main.cpp diff --git a/.github/workflows/integrationTests.yml b/.github/workflows/integrationTests.yml new file mode 100644 index 00000000..fca36c90 --- /dev/null +++ b/.github/workflows/integrationTests.yml @@ -0,0 +1,35 @@ +name: IntegrationTests + +on: [ push ] + +env: + # Customize the CMake build type here (Release, Debug, RelWithDebInfo, etc.) + BUILD_TYPE: Release + +jobs: + build: + # The CMake configure and build commands are platform agnostic and should work equally well on Windows or Mac. + # You can convert this to a matrix build if you need cross-platform coverage. + # See: https://docs.github.com/en/free-pro-team@latest/actions/learn-github-actions/managing-complex-workflows#using-a-build-matrix + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v3 + - name: Configure CMake + # Configure CMake in a 'build' subdirectory. `CMAKE_BUILD_TYPE` is only required if you are using a single-configuration generator such as make. + # See https://cmake.org/cmake/help/latest/variable/CMAKE_BUILD_TYPE.html?highlight=cmake_build_type + run: cmake -B ${{github.workspace}}/build + + - name: Build + # Build your program with the given configuration + run: cmake --build ${{github.workspace}}/build + + - name: Test + #working-directory: ${{github.workspace}}/build/apps/TestsApp + # Execute tests defined by the CMake configuration. + # See https://cmake.org/cmake/help/latest/manual/ctest.1.html for more detail + # ну почему не из корня ... + #run: ctest -C ${{env.BUILD_TYPE}} + run: ./build/apps/IntegrationTestsApp/IntegrationTestsApp + + \ No newline at end of file diff --git a/.github/workflows/unitTests.yml b/.github/workflows/unitTests.yml index d6f2425d..70ba8992 100644 --- a/.github/workflows/unitTests.yml +++ b/.github/workflows/unitTests.yml @@ -30,6 +30,6 @@ jobs: # See https://cmake.org/cmake/help/latest/manual/ctest.1.html for more detail # ну почему не из корня ... #run: ctest -C ${{env.BUILD_TYPE}} - run: ./build/apps/TestsApp/TestsApp + run: ./build/apps/UnitTestsApp/UnitTestsApp \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt index 7d5540c4..1d1a16e9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -14,4 +14,6 @@ add_subdirectory(libs/Interpreter) add_subdirectory(libs/InputGenerator) add_subdirectory(apps/InterpreterApp) add_subdirectory(apps/InputGeneratorApp) -add_subdirectory(apps/TestsApp) \ No newline at end of file +add_subdirectory(apps/UnitTestsApp) +add_subdirectory(apps/IntegrationTestsApp) +add_subdirectory(apps/MetamorphicTestsApp) \ No newline at end of file diff --git a/apps/IntegrationTestsApp/CMakeLists.txt b/apps/IntegrationTestsApp/CMakeLists.txt new file mode 100644 index 00000000..2047bf6e --- /dev/null +++ b/apps/IntegrationTestsApp/CMakeLists.txt @@ -0,0 +1,37 @@ +# Set the project name +project(IntegrationTestsApp) + +# Create a sources variable with a link to all cpp files to compile + +include(FetchContent) +FetchContent_Declare( + googletest + URL https://github.com/google/googletest/archive/03597a01ee50ed33e9dfd640b249b4be3799d395.zip +) + +set(gtest_force_shared_crt ON CACHE BOOL "" FORCE) +FetchContent_MakeAvailable(googletest) + +set(SOURCES + src/main.cpp + src/IntegrationTests.cpp) + + +# Add a library with the above sources +add_executable(${PROJECT_NAME} ${SOURCES}) + +target_include_directories(${PROJECT_NAME} + PUBLIC ${PROJECT_SOURCE_DIR}/include + ) + +target_link_libraries(${PROJECT_NAME} + InputGenerator + Interpreter + Tester + Objects + gtest + ) + +enable_testing() +add_test(NAME IntegrationTests + COMMAND ${PROJECT_NAME}) \ No newline at end of file diff --git a/apps/IntegrationTestsApp/src/IntegrationTests.cpp b/apps/IntegrationTestsApp/src/IntegrationTests.cpp new file mode 100644 index 00000000..3497014c --- /dev/null +++ b/apps/IntegrationTestsApp/src/IntegrationTests.cpp @@ -0,0 +1 @@ +#include "gtest/gtest.h" \ No newline at end of file diff --git a/apps/TestsApp/src/main.cpp b/apps/IntegrationTestsApp/src/main.cpp similarity index 81% rename from apps/TestsApp/src/main.cpp rename to apps/IntegrationTestsApp/src/main.cpp index 3db9912d..63fb136b 100644 --- a/apps/TestsApp/src/main.cpp +++ b/apps/IntegrationTestsApp/src/main.cpp @@ -1,11 +1,10 @@ -#include "TestsApp/Example.h" #include "gtest/gtest.h" #include #include using namespace std; int main(int argc, char** argv) { - cout << "Test\n"; + cout << "Integration Tests\n"; // Тестирование ::testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS(); diff --git a/apps/MetamorphicTestsApp/CMakeLists.txt b/apps/MetamorphicTestsApp/CMakeLists.txt new file mode 100644 index 00000000..917f40c5 --- /dev/null +++ b/apps/MetamorphicTestsApp/CMakeLists.txt @@ -0,0 +1,37 @@ +# Set the project name +project(MetamorphicTestsApp) + +# Create a sources variable with a link to all cpp files to compile + +include(FetchContent) +FetchContent_Declare( + googletest + URL https://github.com/google/googletest/archive/03597a01ee50ed33e9dfd640b249b4be3799d395.zip +) + +set(gtest_force_shared_crt ON CACHE BOOL "" FORCE) +FetchContent_MakeAvailable(googletest) + +set(SOURCES + src/main.cpp + src/MetamorphicTests.cpp) + + +# Add a library with the above sources +add_executable(${PROJECT_NAME} ${SOURCES}) + +target_include_directories(${PROJECT_NAME} + PUBLIC ${PROJECT_SOURCE_DIR}/include + ) + +target_link_libraries(${PROJECT_NAME} + InputGenerator + Interpreter + Tester + Objects + gtest + ) + +enable_testing() +add_test(NAME IntegrationTests + COMMAND ${PROJECT_NAME}) \ No newline at end of file diff --git a/apps/MetamorphicTestsApp/src/MetamorphicTests.cpp b/apps/MetamorphicTestsApp/src/MetamorphicTests.cpp new file mode 100644 index 00000000..3497014c --- /dev/null +++ b/apps/MetamorphicTestsApp/src/MetamorphicTests.cpp @@ -0,0 +1 @@ +#include "gtest/gtest.h" \ No newline at end of file diff --git a/apps/MetamorphicTestsApp/src/main.cpp b/apps/MetamorphicTestsApp/src/main.cpp new file mode 100644 index 00000000..80bb5ed4 --- /dev/null +++ b/apps/MetamorphicTestsApp/src/main.cpp @@ -0,0 +1,11 @@ +#include "gtest/gtest.h" +#include +#include +using namespace std; + +int main(int argc, char** argv) { + cout << "Metamorphic Tests\n"; + // Тестирование + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} diff --git a/apps/TestsApp/CMakeLists.txt b/apps/UnitTestsApp/CMakeLists.txt similarity index 97% rename from apps/TestsApp/CMakeLists.txt rename to apps/UnitTestsApp/CMakeLists.txt index 3f905d42..64811668 100644 --- a/apps/TestsApp/CMakeLists.txt +++ b/apps/UnitTestsApp/CMakeLists.txt @@ -1,5 +1,5 @@ # Set the project name -project(TestsApp) +project(UnitTestsApp) # Create a sources variable with a link to all cpp files to compile diff --git a/apps/TestsApp/include/TestsApp/Example.h b/apps/UnitTestsApp/include/UnitTestsApp/Example.h similarity index 100% rename from apps/TestsApp/include/TestsApp/Example.h rename to apps/UnitTestsApp/include/UnitTestsApp/Example.h diff --git a/apps/TestsApp/src/Example.cpp b/apps/UnitTestsApp/src/Example.cpp similarity index 99% rename from apps/TestsApp/src/Example.cpp rename to apps/UnitTestsApp/src/Example.cpp index d744bbf6..2e9db86e 100644 --- a/apps/TestsApp/src/Example.cpp +++ b/apps/UnitTestsApp/src/Example.cpp @@ -1,4 +1,4 @@ -#include "TestsApp/Example.h" +#include "UnitTestsApp/Example.h" void Example::determinize() { vector states; diff --git a/apps/TestsApp/src/UnitTests.cpp b/apps/UnitTestsApp/src/UnitTests.cpp similarity index 100% rename from apps/TestsApp/src/UnitTests.cpp rename to apps/UnitTestsApp/src/UnitTests.cpp diff --git a/apps/UnitTestsApp/src/main.cpp b/apps/UnitTestsApp/src/main.cpp new file mode 100644 index 00000000..087e824b --- /dev/null +++ b/apps/UnitTestsApp/src/main.cpp @@ -0,0 +1,12 @@ +#include "UnitTestsApp/Example.h" +#include "gtest/gtest.h" +#include +#include +using namespace std; + +int main(int argc, char** argv) { + cout << "Unit Tests\n"; + // Тестирование + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} From 595c985e717ce6c4abe50d32d40e73b22d57d2a3 Mon Sep 17 00:00:00 2001 From: DanilaKn Date: Wed, 8 Nov 2023 17:15:44 +0300 Subject: [PATCH 12/18] =?UTF-8?q?(#283)=20=D0=B4=D0=BE=D0=B1=D0=B0=D0=B2?= =?UTF-8?q?=D0=B8=D0=BB=20MetamorphicTests=20=D0=B2=20github=20actions?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/metamorphicTests.yml | 35 ++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100644 .github/workflows/metamorphicTests.yml diff --git a/.github/workflows/metamorphicTests.yml b/.github/workflows/metamorphicTests.yml new file mode 100644 index 00000000..a270ce96 --- /dev/null +++ b/.github/workflows/metamorphicTests.yml @@ -0,0 +1,35 @@ +name: MetamorphicTests + +on: [ push ] + +env: + # Customize the CMake build type here (Release, Debug, RelWithDebInfo, etc.) + BUILD_TYPE: Release + +jobs: + build: + # The CMake configure and build commands are platform agnostic and should work equally well on Windows or Mac. + # You can convert this to a matrix build if you need cross-platform coverage. + # See: https://docs.github.com/en/free-pro-team@latest/actions/learn-github-actions/managing-complex-workflows#using-a-build-matrix + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v3 + - name: Configure CMake + # Configure CMake in a 'build' subdirectory. `CMAKE_BUILD_TYPE` is only required if you are using a single-configuration generator such as make. + # See https://cmake.org/cmake/help/latest/variable/CMAKE_BUILD_TYPE.html?highlight=cmake_build_type + run: cmake -B ${{github.workspace}}/build + + - name: Build + # Build your program with the given configuration + run: cmake --build ${{github.workspace}}/build + + - name: Test + #working-directory: ${{github.workspace}}/build/apps/TestsApp + # Execute tests defined by the CMake configuration. + # See https://cmake.org/cmake/help/latest/manual/ctest.1.html for more detail + # ну почему не из корня ... + #run: ctest -C ${{env.BUILD_TYPE}} + run: ./build/apps/MetamorphicTestsApp/MetamorphicTestsApp + + \ No newline at end of file From c2c993eb77eebf172174f0913480e2328e59abbe Mon Sep 17 00:00:00 2001 From: DanilaKn Date: Thu, 9 Nov 2023 11:42:18 +0300 Subject: [PATCH 13/18] =?UTF-8?q?(#290)=20=D0=94=D0=BE=D0=B1=D0=B0=D0=B2?= =?UTF-8?q?=D0=B8=D0=BB=20=D0=BF=D0=BE=D0=B4=D0=B4=D0=B5=D1=80=D0=B6=D0=BA?= =?UTF-8?q?=D1=83=20=D0=BE=D1=82=D1=80=D0=B8=D1=86=D0=B0=D0=BD=D0=B8=D1=8F?= =?UTF-8?q?=20=D0=B2=20=D0=BF=D0=B0=D1=80=D1=81=D0=B5=D1=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- libs/Objects/include/Objects/AlgExpression.h | 5 +- libs/Objects/src/AlgExpression.cpp | 61 +++++++++++++++----- 2 files changed, 51 insertions(+), 15 deletions(-) diff --git a/libs/Objects/include/Objects/AlgExpression.h b/libs/Objects/include/Objects/AlgExpression.h index 6a2d9942..0e5480e4 100644 --- a/libs/Objects/include/Objects/AlgExpression.h +++ b/libs/Objects/include/Objects/AlgExpression.h @@ -15,6 +15,7 @@ class AlgExpression : public BaseObject { alt, // | conc, // . star, // * + minus, // ^ symb, // alphabet symbol eps, // Epsilon squareBrL, // [ @@ -38,6 +39,7 @@ class AlgExpression : public BaseObject { conc, // Unary: star, + minus, // Terminal: symb, // [i] @@ -86,7 +88,8 @@ class AlgExpression : public BaseObject { AlgExpression* scan_symb(const vector&, int, int); AlgExpression* scan_eps(const vector&, int, int); AlgExpression* scan_par(const vector&, int, int); - static bool update_balance(const AlgExpression::Lexeme&, int&); + AlgExpression* scan_minus(const vector&, int, int); + static void update_balance(const AlgExpression::Lexeme&, int&); // список листьев дерева regex vector pre_order_travers(); diff --git a/libs/Objects/src/AlgExpression.cpp b/libs/Objects/src/AlgExpression.cpp index 53c255cf..c1d57cf0 100644 --- a/libs/Objects/src/AlgExpression.cpp +++ b/libs/Objects/src/AlgExpression.cpp @@ -111,6 +111,9 @@ string AlgExpression::to_txt() const { // ставим скобки при итерации, если символов > 1 str1 = "(" + str1 + ")"; break; + case Type::minus: + symb = '^'; + return symb + str1; default: break; } @@ -161,6 +164,8 @@ string AlgExpression::type_to_str() const { return "*"; case Type::symb: return "symb"; + case Type::minus: + return "^"; default: break; } @@ -235,6 +240,9 @@ vector AlgExpression::parse_string(string str) { char c = str[index]; Lexeme lexeme; switch (c) { + case '^': + lexeme.type = Lexeme::Type::minus; + break; case '(': lexeme.type = Lexeme::Type::parL; brackets_checker.push('('); @@ -330,7 +338,8 @@ vector AlgExpression::parse_string(string str) { ( // AlgExpression::Lexeme right lexeme.type == Lexeme::Type::symb || lexeme.type == Lexeme::Type::parL || - lexeme.type == Lexeme::Type::squareBrL || lexeme.type == Lexeme::Type::ref)) { + lexeme.type == Lexeme::Type::squareBrL || lexeme.type == Lexeme::Type::ref || + lexeme.type == Lexeme::Type::minus)) { // We place . between lexemes.emplace_back(Lexeme::Type::conc); } @@ -411,33 +420,60 @@ bool AlgExpression::from_string(const string& str) { AlgExpression* AlgExpression::expr(const vector& lexemes, int index_start, int index_end) { AlgExpression* p; - p = scan_alt(lexemes, index_start, index_end); + p = scan_symb(lexemes, index_start, index_end); if (!p) { - p = scan_conc(lexemes, index_start, index_end); + p = scan_eps(lexemes, index_start, index_end); } + if (!p) { - p = scan_star(lexemes, index_start, index_end); + p = scan_alt(lexemes, index_start, index_end); + } + if (!p) { + p = scan_conc(lexemes, index_start, index_end); } if (!p) { - p = scan_symb(lexemes, index_start, index_end); + p = scan_minus(lexemes, index_start, index_end); } if (!p) { - p = scan_eps(lexemes, index_start, index_end); + p = scan_star(lexemes, index_start, index_end); } if (!p) { p = scan_par(lexemes, index_start, index_end); } + return p; } -bool AlgExpression::update_balance(const AlgExpression::Lexeme& l, int& balance) { +void AlgExpression::update_balance(const AlgExpression::Lexeme& l, int& balance) { if (l.type == Lexeme::Type::parL || l.type == Lexeme::Type::squareBrL) { balance++; } if (l.type == Lexeme::Type::parR || l.type == Lexeme::Type::squareBrR) { balance--; } - return balance >= 0; + return; +} + +AlgExpression* AlgExpression::scan_minus(const vector& lexemes, + int index_start, int index_end) { + AlgExpression* p = nullptr; + + if (lexemes[index_start].type != Lexeme::Type::minus) { + return nullptr; + } + + AlgExpression* l = expr(lexemes, index_start + 1, index_end); + if (l == nullptr) { + delete l; + return nullptr; + } + p = make(); + p->term_l = l; + p->value = lexemes[index_start]; + p->type = minus; + + p->alphabet = l->alphabet; + return p; } AlgExpression* AlgExpression::scan_conc(const vector& lexemes, @@ -445,8 +481,7 @@ AlgExpression* AlgExpression::scan_conc(const vector& lex AlgExpression* p = nullptr; int balance = 0; for (int i = index_start; i < index_end; i++) { - if (!update_balance(lexemes[i], balance)) - return nullptr; + update_balance(lexemes[i], balance); if (lexemes[i].type == Lexeme::Type::conc && balance == 0) { AlgExpression* l = expr(lexemes, index_start, i); AlgExpression* r = expr(lexemes, i + 1, index_end); @@ -477,8 +512,7 @@ AlgExpression* AlgExpression::scan_star(const vector& lex AlgExpression* p = nullptr; int balance = 0; for (int i = index_start; i < index_end; i++) { - if (!update_balance(lexemes[i], balance)) - return nullptr; + update_balance(lexemes[i], balance); if (lexemes[i].type == Lexeme::Type::star && balance == 0) { AlgExpression* l = expr(lexemes, index_start, i); if (l == nullptr || l->type == AlgExpression::eps) { @@ -503,8 +537,7 @@ AlgExpression* AlgExpression::scan_alt(const vector& lexe AlgExpression* p = nullptr; int balance = 0; for (int i = index_start; i < index_end; i++) { - if (!update_balance(lexemes[i], balance)) - return nullptr; + update_balance(lexemes[i], balance); if (lexemes[i].type == Lexeme::Type::alt && balance == 0) { AlgExpression* l = expr(lexemes, index_start, i); AlgExpression* r = expr(lexemes, i + 1, index_end); From 3ba9ca370b85f704cfa763738600931d41681369 Mon Sep 17 00:00:00 2001 From: DanilaKn Date: Thu, 9 Nov 2023 23:42:12 +0300 Subject: [PATCH 14/18] =?UTF-8?q?(#290)=20Fix=20=D0=BE=D1=88=D0=B8=D0=B1?= =?UTF-8?q?=D0=BE=D0=BA=20=D0=B8=20unit=20=D1=82=D0=B5=D1=81=D1=82=20?= =?UTF-8?q?=D0=BD=D0=B0=20=D0=BE=D1=82=D1=80=D0=B8=D1=86=D0=B0=D0=BD=D0=B8?= =?UTF-8?q?=D0=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/UnitTestsApp/src/UnitTests.cpp | 8 ++++++++ libs/Objects/src/AlgExpression.cpp | 2 +- libs/Objects/src/BackRefRegex.cpp | 5 +++-- 3 files changed, 12 insertions(+), 3 deletions(-) diff --git a/apps/UnitTestsApp/src/UnitTests.cpp b/apps/UnitTestsApp/src/UnitTests.cpp index 54f9d24b..dc1baa55 100644 --- a/apps/UnitTestsApp/src/UnitTests.cpp +++ b/apps/UnitTestsApp/src/UnitTests.cpp @@ -10,6 +10,14 @@ #include "gtest/gtest.h" #include +TEST(TestCaseName, Test_regex_minus) { + string str = "^(c^(a^(b)d))e"; + Regex r1(str); + string r1_str = r1.to_txt(); + Regex r2(r1_str); + ASSERT_EQ(true, Regex::equivalent(r1, r2)); +} + TEST(TestCaseName, Test_random_regex_parsing) { RegexGenerator rg(15, 10, 5, 3); for (int i = 0; i < 30; i++) { diff --git a/libs/Objects/src/AlgExpression.cpp b/libs/Objects/src/AlgExpression.cpp index c1d57cf0..e10b0bb9 100644 --- a/libs/Objects/src/AlgExpression.cpp +++ b/libs/Objects/src/AlgExpression.cpp @@ -92,7 +92,7 @@ string AlgExpression::to_txt() const { if (term_l && term_l->type == Type::alt) { str1 = "(" + str1 + ")"; } - if (term_r && term_l->type == Type::alt) { + if (term_r && term_r->type == Type::alt) { str2 = "(" + str2 + ")"; } break; diff --git a/libs/Objects/src/BackRefRegex.cpp b/libs/Objects/src/BackRefRegex.cpp index 2799b80b..8761b82e 100644 --- a/libs/Objects/src/BackRefRegex.cpp +++ b/libs/Objects/src/BackRefRegex.cpp @@ -58,7 +58,7 @@ template const BackRefRegex* BackRefRegex::cast(const T* ptr) { } string BackRefRegex::to_txt() const { - BackRefRegex* br_term_l; + BackRefRegex* br_term_l, *br_term_r; string str1, str2; if (term_l) { str1 = term_l->to_txt(); @@ -66,6 +66,7 @@ string BackRefRegex::to_txt() const { } if (term_r) { str2 = term_r->to_txt(); + br_term_r = cast(term_r); } string symb; switch (type) { @@ -73,7 +74,7 @@ string BackRefRegex::to_txt() const { if (term_l && br_term_l->type == Type::alt) { str1 = "(" + str1 + ")"; } - if (term_r && br_term_l->type == Type::alt) { + if (term_r && br_term_r->type == Type::alt) { str2 = "(" + str2 + ")"; } break; From 6978ad8efd7572aa8dc5ee670d51fd6c22d2546d Mon Sep 17 00:00:00 2001 From: xendalm Date: Fri, 10 Nov 2023 15:10:24 +0300 Subject: [PATCH 15/18] (#271) regex lexer tests --- .clang-format | 3 +- apps/UnitTestsApp/src/UnitTests.cpp | 57 ++++++++++++++++---- libs/Objects/CMakeLists.txt | 10 ++++ libs/Objects/include/Objects/AlgExpression.h | 5 +- libs/Objects/src/AlgExpression.cpp | 21 ++++---- 5 files changed, 75 insertions(+), 21 deletions(-) diff --git a/.clang-format b/.clang-format index 1be1c078..9f9a7610 100644 --- a/.clang-format +++ b/.clang-format @@ -7,4 +7,5 @@ AllowShortIfStatementsOnASingleLine: Never SpaceBeforeParens: ControlStatements AllowShortFunctionsOnASingleLine: Empty AlignAfterOpenBracket: Align -ColumnLimit: 100 \ No newline at end of file +ColumnLimit: 100 +BinPackArguments: false \ No newline at end of file diff --git a/apps/UnitTestsApp/src/UnitTests.cpp b/apps/UnitTestsApp/src/UnitTests.cpp index dc1baa55..a28bdef2 100644 --- a/apps/UnitTestsApp/src/UnitTests.cpp +++ b/apps/UnitTestsApp/src/UnitTests.cpp @@ -10,12 +10,44 @@ #include "gtest/gtest.h" #include -TEST(TestCaseName, Test_regex_minus) { - string str = "^(c^(a^(b)d))e"; - Regex r1(str); - string r1_str = r1.to_txt(); - Regex r2(r1_str); - ASSERT_EQ(true, Regex::equivalent(r1, r2)); +TEST(ParseStringTest, Test_regex_lexer) { + using L = AlgExpression::Lexeme::Type; + + struct Test { + string regex_str; + bool want_err; + int lexemes_len = 0; + }; + + vector tests = { + {"[]", true}, + {"[]:", true}, + {"[a]", true}, + {"[a]:", true}, + {"[[a]:1", true}, + {"a]:1", true}, + {"[a]:1", false, 3}, + {"&", true}, + {"&1", false, 1}, + {"[b[a]:1&1]:2&2", false, 11}, + }; + + for (const auto& t : tests) { + stringstream message; + message << "Case: " << t.regex_str << ", WantErr: " << t.want_err; + SCOPED_TRACE(message.str()); + + vector l = AlgExpression::parse_string(t.regex_str); + ASSERT_FALSE(l.empty()); + + if (t.want_err) { + ASSERT_EQ(L::error, l[0].type); + } else { + ASSERT_NE(L::error, l[0].type); + ASSERT_EQ(t.lexemes_len, l.size()); + // TODO: добавить проверку содержимого l + } + } } TEST(TestCaseName, Test_random_regex_parsing) { @@ -246,14 +278,19 @@ TEST(TestCaseName, Test_ambiguity) { {16, "(a|b|c)*(a|b|c|d)(a|b|c)*|(ac*|ad*)*", glushkov, FiniteAutomaton::almost_unambigious}, {17, "(ab)*ab(ab)*|(ac)*(ac)*|(d|c)*", // (abab)*abab(abab)*|(aac)*(aac)*|(b|d|c)* - glushkov, FiniteAutomaton::almost_unambigious}, + glushkov, + FiniteAutomaton::almost_unambigious}, {18, "(abab)*abab(abab)*|(aac)*(aac)*", glushkov, FiniteAutomaton::polynomially_ambigious}, - {19, "(ab)*ab(ab)*", // (abab)*abab(abab)* - glushkov, FiniteAutomaton::polynomially_ambigious}, + {19, + "(ab)*ab(ab)*", // (abab)*abab(abab)* + glushkov, + FiniteAutomaton::polynomially_ambigious}, {20, "(ab)*ab(ab)*|(ac)*(ac)*", glushkov, FiniteAutomaton::polynomially_ambigious}, // {21, "(a|b)*(f*)*q", thompson, // FiniteAutomaton::exponentially_ambiguous}, - {22, "((bb*c|c)c*b|bb*b|b)(b|(c|bb*c)c*b|bb*b)*", glushkov, + {22, + "((bb*c|c)c*b|bb*b|b)(b|(c|bb*c)c*b|bb*b)*", + glushkov, FiniteAutomaton::exponentially_ambiguous}, }; diff --git a/libs/Objects/CMakeLists.txt b/libs/Objects/CMakeLists.txt index d78f0881..1d1ff0f5 100644 --- a/libs/Objects/CMakeLists.txt +++ b/libs/Objects/CMakeLists.txt @@ -1,6 +1,15 @@ # Set the project name project(Objects) +include(FetchContent) +FetchContent_Declare( + googletest + URL https://github.com/google/googletest/archive/03597a01ee50ed33e9dfd640b249b4be3799d395.zip +) + +set(gtest_force_shared_crt ON CACHE BOOL "" FORCE) +FetchContent_MakeAvailable(googletest) + # Create a sources variable with a link to all cpp files to compile set(SOURCES src/TransformationMonoid.cpp @@ -26,4 +35,5 @@ target_include_directories(${PROJECT_NAME} target_link_libraries(${PROJECT_NAME} Fraction AutomatonToImage + gtest ) \ No newline at end of file diff --git a/libs/Objects/include/Objects/AlgExpression.h b/libs/Objects/include/Objects/AlgExpression.h index 0e5480e4..6ab887af 100644 --- a/libs/Objects/include/Objects/AlgExpression.h +++ b/libs/Objects/include/Objects/AlgExpression.h @@ -2,10 +2,13 @@ #include "BaseObject.h" #include "iLogTemplate.h" +#include "gtest/gtest.h" #include #include class AlgExpression : public BaseObject { + FRIEND_TEST(ParseStringTest, Test_regex_lexer); + protected: struct Lexeme { enum Type { @@ -15,7 +18,7 @@ class AlgExpression : public BaseObject { alt, // | conc, // . star, // * - minus, // ^ + minus, // ^ symb, // alphabet symbol eps, // Epsilon squareBrL, // [ diff --git a/libs/Objects/src/AlgExpression.cpp b/libs/Objects/src/AlgExpression.cpp index e10b0bb9..698a439f 100644 --- a/libs/Objects/src/AlgExpression.cpp +++ b/libs/Objects/src/AlgExpression.cpp @@ -402,7 +402,7 @@ bool AlgExpression::from_string(const string& str) { return true; } - vector l = parse_string(str); + vector l = parse_string(str); AlgExpression* root = expr(l, 0, l.size()); if (root == nullptr || root->type == eps) { @@ -440,7 +440,7 @@ AlgExpression* AlgExpression::expr(const vector& lexemes, if (!p) { p = scan_par(lexemes, index_start, index_end); } - + return p; } @@ -451,11 +451,10 @@ void AlgExpression::update_balance(const AlgExpression::Lexeme& l, int& balance) if (l.type == Lexeme::Type::parR || l.type == Lexeme::Type::squareBrR) { balance--; } - return; } AlgExpression* AlgExpression::scan_minus(const vector& lexemes, - int index_start, int index_end) { + int index_start, int index_end) { AlgExpression* p = nullptr; if (lexemes[index_start].type != Lexeme::Type::minus) { @@ -473,7 +472,7 @@ AlgExpression* AlgExpression::scan_minus(const vector& le p->type = minus; p->alphabet = l->alphabet; - return p; + return p; } AlgExpression* AlgExpression::scan_conc(const vector& lexemes, @@ -638,15 +637,19 @@ bool AlgExpression::contains_eps() const { } bool AlgExpression::equality_checker(const AlgExpression* expr1, const AlgExpression* expr2) { - if (expr1 == nullptr && expr2 == nullptr) return true; - if (expr1 == nullptr || expr2 == nullptr) return false; - if (expr1->value.type != expr2->value.type) return false; + if (expr1 == nullptr && expr2 == nullptr) + return true; + if (expr1 == nullptr || expr2 == nullptr) + return false; + if (expr1->value.type != expr2->value.type) + return false; if (expr1->value.type == Lexeme::Type::symb) { alphabet_symbol r1_symb, r2_symb; r1_symb = expr1->value.symbol; r2_symb = expr2->value.symbol; - if (r1_symb != r2_symb) return false; + if (r1_symb != r2_symb) + return false; } if (equality_checker(expr1->term_l, expr2->term_l) && From 713c8f3a065265694f64ef960d97678777fae0fe Mon Sep 17 00:00:00 2001 From: DanilaKn Date: Fri, 10 Nov 2023 19:25:55 +0300 Subject: [PATCH 16/18] =?UTF-8?q?(#290)=20=D0=9F=D0=B5=D1=80=D0=B5=D0=BD?= =?UTF-8?q?=D0=B5=D1=81=20=D0=BC=D0=B5=D1=82=D0=BE=D0=B4=D1=8B=20=D0=B8?= =?UTF-8?q?=D0=B7=20=20AlgExpression=20=D0=B2=20Regex,=20=D0=B4=D0=BE?= =?UTF-8?q?=D0=B1=D0=B0=D0=B2=D0=B8=D0=BB=20=D0=BA=D0=BB=D0=B0=D1=81=D1=81?= =?UTF-8?q?=20=D0=B4=D0=BB=D1=8F=20=D1=8E=D0=BD=D0=B8=D1=82=20=D1=82=D0=B5?= =?UTF-8?q?=D1=81=D1=82=D0=BE=D0=B2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../include/UnitTestsApp/UnitTests.h | 29 +++++++++++ apps/UnitTestsApp/src/UnitTests.cpp | 29 +++++------ apps/UnitTestsApp/src/main.cpp | 4 +- libs/Objects/CMakeLists.txt | 10 ---- libs/Objects/include/Objects/AlgExpression.h | 8 ++- libs/Objects/include/Objects/Regex.h | 5 ++ libs/Objects/src/AlgExpression.cpp | 42 ++++------------ libs/Objects/src/Regex.cpp | 49 +++++++++++++++++++ 8 files changed, 110 insertions(+), 66 deletions(-) create mode 100644 apps/UnitTestsApp/include/UnitTestsApp/UnitTests.h diff --git a/apps/UnitTestsApp/include/UnitTestsApp/UnitTests.h b/apps/UnitTestsApp/include/UnitTestsApp/UnitTests.h new file mode 100644 index 00000000..1bda687a --- /dev/null +++ b/apps/UnitTestsApp/include/UnitTestsApp/UnitTests.h @@ -0,0 +1,29 @@ +#pragma once + +#include "AutomatonToImage/AutomatonToImage.h" +#include "InputGenerator/RegexGenerator.h" +#include "Interpreter/Interpreter.h" +#include "Objects/AlgExpression.h" +#include "Objects/FiniteAutomaton.h" +#include "Objects/Grammar.h" +#include "Objects/Language.h" +#include "Objects/Regex.h" +#include "Objects/TransformationMonoid.h" +#include "Tester/Tester.h" +#include "gtest/gtest.h" +#include + +class UnitTests +{ +public: + UnitTests(){}; + + static int InitTests(int argc, char** argv) { + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); + }; + + using Lexeme = AlgExpression::Lexeme; + using LexemeType = AlgExpression::Lexeme::Type; + static std::vector parse_string(std::string str) {return AlgExpression::parse_string(str);}; +}; diff --git a/apps/UnitTestsApp/src/UnitTests.cpp b/apps/UnitTestsApp/src/UnitTests.cpp index a28bdef2..e0d99604 100644 --- a/apps/UnitTestsApp/src/UnitTests.cpp +++ b/apps/UnitTestsApp/src/UnitTests.cpp @@ -1,18 +1,6 @@ -#include "AutomatonToImage/AutomatonToImage.h" -#include "InputGenerator/RegexGenerator.h" -#include "Interpreter/Interpreter.h" -#include "Objects/FiniteAutomaton.h" -#include "Objects/Grammar.h" -#include "Objects/Language.h" -#include "Objects/Regex.h" -#include "Objects/TransformationMonoid.h" -#include "Tester/Tester.h" -#include "gtest/gtest.h" -#include +#include "UnitTestsApp/UnitTests.h" TEST(ParseStringTest, Test_regex_lexer) { - using L = AlgExpression::Lexeme::Type; - struct Test { string regex_str; bool want_err; @@ -30,6 +18,13 @@ TEST(ParseStringTest, Test_regex_lexer) { {"&", true}, {"&1", false, 1}, {"[b[a]:1&1]:2&2", false, 11}, + // тесты на отрицание + {"^a", false, 2}, + {"a^|b", true}, + {"d^*^b", true}, + {"d|^|b", true}, + {"a^", false, 4}, // a . ^ eps + {"a|(c^)", false, 8}, // a | ( c . ^ eps ) }; for (const auto& t : tests) { @@ -37,13 +32,13 @@ TEST(ParseStringTest, Test_regex_lexer) { message << "Case: " << t.regex_str << ", WantErr: " << t.want_err; SCOPED_TRACE(message.str()); - vector l = AlgExpression::parse_string(t.regex_str); + vector l = UnitTests::parse_string(t.regex_str); ASSERT_FALSE(l.empty()); if (t.want_err) { - ASSERT_EQ(L::error, l[0].type); + ASSERT_EQ(UnitTests::LexemeType::error, l[0].type); } else { - ASSERT_NE(L::error, l[0].type); + ASSERT_NE(UnitTests::LexemeType::error, l[0].type); ASSERT_EQ(t.lexemes_len, l.size()); // TODO: добавить проверку содержимого l } @@ -493,4 +488,4 @@ TEST(TestCaseName, Test_GlaisterShallit) { check_classes_number("a(b|c)(a|b)(b|c)", 5); check_classes_number("abc|bca", 6); check_classes_number("abc|bbc", 4); -} \ No newline at end of file +} diff --git a/apps/UnitTestsApp/src/main.cpp b/apps/UnitTestsApp/src/main.cpp index 087e824b..3418bd4e 100644 --- a/apps/UnitTestsApp/src/main.cpp +++ b/apps/UnitTestsApp/src/main.cpp @@ -1,4 +1,5 @@ #include "UnitTestsApp/Example.h" +#include "UnitTestsApp/UnitTests.h" #include "gtest/gtest.h" #include #include @@ -7,6 +8,5 @@ using namespace std; int main(int argc, char** argv) { cout << "Unit Tests\n"; // Тестирование - ::testing::InitGoogleTest(&argc, argv); - return RUN_ALL_TESTS(); + return UnitTests::InitTests(argc, argv); } diff --git a/libs/Objects/CMakeLists.txt b/libs/Objects/CMakeLists.txt index 1d1ff0f5..d78f0881 100644 --- a/libs/Objects/CMakeLists.txt +++ b/libs/Objects/CMakeLists.txt @@ -1,15 +1,6 @@ # Set the project name project(Objects) -include(FetchContent) -FetchContent_Declare( - googletest - URL https://github.com/google/googletest/archive/03597a01ee50ed33e9dfd640b249b4be3799d395.zip -) - -set(gtest_force_shared_crt ON CACHE BOOL "" FORCE) -FetchContent_MakeAvailable(googletest) - # Create a sources variable with a link to all cpp files to compile set(SOURCES src/TransformationMonoid.cpp @@ -35,5 +26,4 @@ target_include_directories(${PROJECT_NAME} target_link_libraries(${PROJECT_NAME} Fraction AutomatonToImage - gtest ) \ No newline at end of file diff --git a/libs/Objects/include/Objects/AlgExpression.h b/libs/Objects/include/Objects/AlgExpression.h index 6ab887af..8158e846 100644 --- a/libs/Objects/include/Objects/AlgExpression.h +++ b/libs/Objects/include/Objects/AlgExpression.h @@ -2,12 +2,10 @@ #include "BaseObject.h" #include "iLogTemplate.h" -#include "gtest/gtest.h" #include #include class AlgExpression : public BaseObject { - FRIEND_TEST(ParseStringTest, Test_regex_lexer); protected: struct Lexeme { @@ -18,7 +16,7 @@ class AlgExpression : public BaseObject { alt, // | conc, // . star, // * - minus, // ^ + negative, // ^ symb, // alphabet symbol eps, // Epsilon squareBrL, // [ @@ -42,7 +40,7 @@ class AlgExpression : public BaseObject { conc, // Unary: star, - minus, + negative, // Terminal: symb, // [i] @@ -91,7 +89,6 @@ class AlgExpression : public BaseObject { AlgExpression* scan_symb(const vector&, int, int); AlgExpression* scan_eps(const vector&, int, int); AlgExpression* scan_par(const vector&, int, int); - AlgExpression* scan_minus(const vector&, int, int); static void update_balance(const AlgExpression::Lexeme&, int&); // список листьев дерева regex @@ -135,4 +132,5 @@ class AlgExpression : public BaseObject { friend class FiniteAutomaton; friend class Tester; + friend class UnitTests; }; \ No newline at end of file diff --git a/libs/Objects/include/Objects/Regex.h b/libs/Objects/include/Objects/Regex.h index 10e6e609..7d34eff8 100644 --- a/libs/Objects/include/Objects/Regex.h +++ b/libs/Objects/include/Objects/Regex.h @@ -36,6 +36,11 @@ class Regex : public AlgExpression { void normalize_this_regex(const vector>&); // переписывание regex по // пользовательским правилам + // Построение из вектора лексем дерева регулярного выражения + // 2 и 3 аргумент - это начальный и конечный индекс рассматриваемых лексем в векторе + Regex* expr(const vector&, int, int) override; + Regex* scan_minus(const vector&, int, int); + public: Regex() = default; Regex(const string&); diff --git a/libs/Objects/src/AlgExpression.cpp b/libs/Objects/src/AlgExpression.cpp index 698a439f..54df5f7b 100644 --- a/libs/Objects/src/AlgExpression.cpp +++ b/libs/Objects/src/AlgExpression.cpp @@ -111,7 +111,7 @@ string AlgExpression::to_txt() const { // ставим скобки при итерации, если символов > 1 str1 = "(" + str1 + ")"; break; - case Type::minus: + case Type::negative: symb = '^'; return symb + str1; default: @@ -164,7 +164,7 @@ string AlgExpression::type_to_str() const { return "*"; case Type::symb: return "symb"; - case Type::minus: + case Type::negative: return "^"; default: break; @@ -241,7 +241,7 @@ vector AlgExpression::parse_string(string str) { Lexeme lexeme; switch (c) { case '^': - lexeme.type = Lexeme::Type::minus; + lexeme.type = Lexeme::Type::negative; break; case '(': lexeme.type = Lexeme::Type::parL; @@ -284,11 +284,14 @@ vector AlgExpression::parse_string(string str) { brackets_are_empty = false; break; case '|': + if (index != 0 && lexemes.back().type == Lexeme::Type::negative) + return {Lexeme::Type::error}; lexeme.type = Lexeme::Type::alt; break; case '*': if (index == 0 || (index != 0 && (lexemes.back().type == Lexeme::Type::star || - lexemes.back().type == Lexeme::Type::alt))) + lexemes.back().type == Lexeme::Type::alt || + lexemes.back().type == Lexeme::Type::negative))) return {Lexeme::Type::error}; lexeme.type = Lexeme::Type::star; break; @@ -339,7 +342,7 @@ vector AlgExpression::parse_string(string str) { // AlgExpression::Lexeme right lexeme.type == Lexeme::Type::symb || lexeme.type == Lexeme::Type::parL || lexeme.type == Lexeme::Type::squareBrL || lexeme.type == Lexeme::Type::ref || - lexeme.type == Lexeme::Type::minus)) { + lexeme.type == Lexeme::Type::negative)) { // We place . between lexemes.emplace_back(Lexeme::Type::conc); } @@ -348,7 +351,7 @@ vector AlgExpression::parse_string(string str) { ((lexeme.type == Lexeme::Type::alt && (lexemes.back().type == Lexeme::Type::parL || lexemes.back().type == Lexeme::Type::squareBrL)) || - (lexemes.back().type == Lexeme::Type::alt && + ((lexemes.back().type == Lexeme::Type::alt || lexemes.back().type == Lexeme::Type::negative) && (lexeme.type == Lexeme::Type::parR || lexeme.type == Lexeme::Type::squareBrR || lexeme.type == Lexeme::Type::alt)))) { // We place eps between @@ -386,7 +389,7 @@ vector AlgExpression::parse_string(string str) { lexemes.insert(lexemes.begin(), {Lexeme::Type::eps}); } - if (lexemes.back().type == Lexeme::Type::alt) { + if (lexemes.back().type == Lexeme::Type::alt || lexemes.back().type == Lexeme::Type::negative) { lexemes.emplace_back(Lexeme::Type::eps); } @@ -431,9 +434,6 @@ AlgExpression* AlgExpression::expr(const vector& lexemes, if (!p) { p = scan_conc(lexemes, index_start, index_end); } - if (!p) { - p = scan_minus(lexemes, index_start, index_end); - } if (!p) { p = scan_star(lexemes, index_start, index_end); } @@ -453,28 +453,6 @@ void AlgExpression::update_balance(const AlgExpression::Lexeme& l, int& balance) } } -AlgExpression* AlgExpression::scan_minus(const vector& lexemes, - int index_start, int index_end) { - AlgExpression* p = nullptr; - - if (lexemes[index_start].type != Lexeme::Type::minus) { - return nullptr; - } - - AlgExpression* l = expr(lexemes, index_start + 1, index_end); - if (l == nullptr) { - delete l; - return nullptr; - } - p = make(); - p->term_l = l; - p->value = lexemes[index_start]; - p->type = minus; - - p->alphabet = l->alphabet; - return p; -} - AlgExpression* AlgExpression::scan_conc(const vector& lexemes, int index_start, int index_end) { AlgExpression* p = nullptr; diff --git a/libs/Objects/src/Regex.cpp b/libs/Objects/src/Regex.cpp index b59ab520..dbc91a0f 100644 --- a/libs/Objects/src/Regex.cpp +++ b/libs/Objects/src/Regex.cpp @@ -72,6 +72,55 @@ template vector Regex::cast(vector ptrs) { return regexPointers; } +Regex* Regex::expr(const vector& lexemes, int index_start, + int index_end) { + AlgExpression* p; + p = scan_symb(lexemes, index_start, index_end); + if (!p) { + p = scan_eps(lexemes, index_start, index_end); + } + + if (!p) { + p = scan_alt(lexemes, index_start, index_end); + } + if (!p) { + p = scan_conc(lexemes, index_start, index_end); + } + if (!p) { + p = scan_minus(lexemes, index_start, index_end); + } + if (!p) { + p = scan_star(lexemes, index_start, index_end); + } + if (!p) { + p = scan_par(lexemes, index_start, index_end); + } + + return cast(p); +} + +Regex* Regex::scan_minus(const vector& lexemes, + int index_start, int index_end) { + Regex* p = nullptr; + + if (lexemes[index_start].type != Lexeme::Type::negative) { + return nullptr; + } + + Regex* l = expr(lexemes, index_start + 1, index_end); + if (l == nullptr) { + delete l; + return nullptr; + } + p = make(); + p->term_l = l; + p->value = lexemes[index_start]; + p->type = negative; + + p->alphabet = l->alphabet; + return p; +} + // возвращает пару <вектор сотсояний, max_index> pair, int> Regex::get_thompson(int max_index) const { string str; // идентификатор состояния From 0cf6c966a41d739816621f39fd98e69e209ae345 Mon Sep 17 00:00:00 2001 From: DanilaKn Date: Sat, 11 Nov 2023 01:29:28 +0300 Subject: [PATCH 17/18] =?UTF-8?q?(#290)=20=D0=9F=D1=80=D0=B0=D0=B2=D0=BA?= =?UTF-8?q?=D0=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../include/UnitTestsApp/UnitTests.h | 2 +- apps/UnitTestsApp/src/main.cpp | 2 +- libs/Objects/include/Objects/AlgExpression.h | 5 +++- libs/Objects/include/Objects/Regex.h | 2 -- libs/Objects/src/AlgExpression.cpp | 24 ------------------- 5 files changed, 6 insertions(+), 29 deletions(-) diff --git a/apps/UnitTestsApp/include/UnitTestsApp/UnitTests.h b/apps/UnitTestsApp/include/UnitTestsApp/UnitTests.h index 1bda687a..d20abd79 100644 --- a/apps/UnitTestsApp/include/UnitTestsApp/UnitTests.h +++ b/apps/UnitTestsApp/include/UnitTestsApp/UnitTests.h @@ -18,7 +18,7 @@ class UnitTests public: UnitTests(){}; - static int InitTests(int argc, char** argv) { + static int RunTests(int argc, char** argv) { ::testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS(); }; diff --git a/apps/UnitTestsApp/src/main.cpp b/apps/UnitTestsApp/src/main.cpp index 3418bd4e..a18639eb 100644 --- a/apps/UnitTestsApp/src/main.cpp +++ b/apps/UnitTestsApp/src/main.cpp @@ -8,5 +8,5 @@ using namespace std; int main(int argc, char** argv) { cout << "Unit Tests\n"; // Тестирование - return UnitTests::InitTests(argc, argv); + return UnitTests::RunTests(argc, argv); } diff --git a/libs/Objects/include/Objects/AlgExpression.h b/libs/Objects/include/Objects/AlgExpression.h index 8158e846..518951e5 100644 --- a/libs/Objects/include/Objects/AlgExpression.h +++ b/libs/Objects/include/Objects/AlgExpression.h @@ -80,9 +80,12 @@ class AlgExpression : public BaseObject { // Turns string into lexeme vector static vector parse_string(string); bool from_string(const string&); + // возвращаемый тип нижеперечисленных методов зависит от типа объекта (Regex/BackRefRegex) // внутреннее состояние не имеет значения - virtual AlgExpression* expr(const vector&, int, int); + // Построение из вектора лексем дерева регулярного выражения + // 2 и 3 аргумент - это начальный и конечный индекс рассматриваемых лексем в векторе + virtual AlgExpression* expr(const vector&, int, int) = 0; AlgExpression* scan_conc(const vector&, int, int); AlgExpression* scan_star(const vector&, int, int); AlgExpression* scan_alt(const vector&, int, int); diff --git a/libs/Objects/include/Objects/Regex.h b/libs/Objects/include/Objects/Regex.h index 7d34eff8..9ad56970 100644 --- a/libs/Objects/include/Objects/Regex.h +++ b/libs/Objects/include/Objects/Regex.h @@ -36,8 +36,6 @@ class Regex : public AlgExpression { void normalize_this_regex(const vector>&); // переписывание regex по // пользовательским правилам - // Построение из вектора лексем дерева регулярного выражения - // 2 и 3 аргумент - это начальный и конечный индекс рассматриваемых лексем в векторе Regex* expr(const vector&, int, int) override; Regex* scan_minus(const vector&, int, int); diff --git a/libs/Objects/src/AlgExpression.cpp b/libs/Objects/src/AlgExpression.cpp index 54df5f7b..8ea7d5bb 100644 --- a/libs/Objects/src/AlgExpression.cpp +++ b/libs/Objects/src/AlgExpression.cpp @@ -420,30 +420,6 @@ bool AlgExpression::from_string(const string& str) { return true; } -AlgExpression* AlgExpression::expr(const vector& lexemes, int index_start, - int index_end) { - AlgExpression* p; - p = scan_symb(lexemes, index_start, index_end); - if (!p) { - p = scan_eps(lexemes, index_start, index_end); - } - - if (!p) { - p = scan_alt(lexemes, index_start, index_end); - } - if (!p) { - p = scan_conc(lexemes, index_start, index_end); - } - if (!p) { - p = scan_star(lexemes, index_start, index_end); - } - if (!p) { - p = scan_par(lexemes, index_start, index_end); - } - - return p; -} - void AlgExpression::update_balance(const AlgExpression::Lexeme& l, int& balance) { if (l.type == Lexeme::Type::parL || l.type == Lexeme::Type::squareBrL) { balance++; From 0684467ad0c14528c106e9c0472bc06ab6e481b3 Mon Sep 17 00:00:00 2001 From: DanilaKn Date: Sat, 11 Nov 2023 02:20:44 +0300 Subject: [PATCH 18/18] =?UTF-8?q?(#290)=20=D0=94=D0=B5=D1=84=D0=BE=D0=BB?= =?UTF-8?q?=D1=82=D0=BD=D1=8B=D0=B9=20=D1=84=D0=BB=D0=B0=D0=B3=20=D0=B4?= =?UTF-8?q?=D0=BB=D1=8F=20cast?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- libs/Objects/include/Objects/BackRefRegex.h | 4 ++-- libs/Objects/include/Objects/Regex.h | 4 ++-- libs/Objects/src/BackRefRegex.cpp | 13 +++++-------- libs/Objects/src/Regex.cpp | 10 +++++----- 4 files changed, 14 insertions(+), 17 deletions(-) diff --git a/libs/Objects/include/Objects/BackRefRegex.h b/libs/Objects/include/Objects/BackRefRegex.h index 18316787..df06be8a 100644 --- a/libs/Objects/include/Objects/BackRefRegex.h +++ b/libs/Objects/include/Objects/BackRefRegex.h @@ -24,8 +24,8 @@ class BackRefRegex : public AlgExpression { BackRefRegex(const BackRefRegex&); // dynamic_cast к типу BackRefRegex* - template static BackRefRegex* cast(T* ptr); - template static const BackRefRegex* cast(const T* ptr); + template static BackRefRegex* cast(T* ptr, bool NotNullPtr = true); + template static const BackRefRegex* cast(const T* ptr, bool NotNullPtr = true); string to_txt() const override; }; \ No newline at end of file diff --git a/libs/Objects/include/Objects/Regex.h b/libs/Objects/include/Objects/Regex.h index 9ad56970..fac596f5 100644 --- a/libs/Objects/include/Objects/Regex.h +++ b/libs/Objects/include/Objects/Regex.h @@ -48,8 +48,8 @@ class Regex : public AlgExpression { Regex(const Regex&) = default; // dynamic_cast к типу Regex* - template static Regex* cast(T* ptr); - template static const Regex* cast(const T* ptr); + template static Regex* cast(T* ptr, bool NotNullPtr = true); + template static const Regex* cast(const T* ptr, bool NotNullPtr = true); // dynamic_cast каждого элемента вектора к типу Regex* template static vector cast(vector ptr); diff --git a/libs/Objects/src/BackRefRegex.cpp b/libs/Objects/src/BackRefRegex.cpp index 8761b82e..b9c6feaa 100644 --- a/libs/Objects/src/BackRefRegex.cpp +++ b/libs/Objects/src/BackRefRegex.cpp @@ -39,18 +39,18 @@ BackRefRegex* BackRefRegex::make() const { return new BackRefRegex; } -template BackRefRegex* BackRefRegex::cast(T* ptr) { +template BackRefRegex* BackRefRegex::cast(T* ptr, bool NotNullPtr) { auto* r = dynamic_cast(ptr); - if (!r) { + if (!r && NotNullPtr) { throw std::runtime_error("Failed to cast to BackRefRegex"); } return r; } -template const BackRefRegex* BackRefRegex::cast(const T* ptr) { +template const BackRefRegex* BackRefRegex::cast(const T* ptr, bool NotNullPtr) { auto* r = dynamic_cast(ptr); - if (!r) { + if (!r && NotNullPtr) { throw std::runtime_error("Failed to cast to BackRefRegex"); } @@ -153,10 +153,7 @@ BackRefRegex* BackRefRegex::expr(const vector& lexemes, i if (!p) { p = scan_square_br(lexemes, index_start, index_end); } - if (!p) { - return nullptr; - } - return cast(p); + return cast(p, false); } BackRefRegex* BackRefRegex::scan_ref(const vector& lexemes, int index_start, diff --git a/libs/Objects/src/Regex.cpp b/libs/Objects/src/Regex.cpp index dbc91a0f..d471a2f0 100644 --- a/libs/Objects/src/Regex.cpp +++ b/libs/Objects/src/Regex.cpp @@ -40,18 +40,18 @@ Regex* Regex::make() const { return new Regex; } -template Regex* Regex::cast(T* ptr) { +template Regex* Regex::cast(T* ptr, bool NotNullPtr) { auto* r = dynamic_cast(ptr); - if (!r) { + if (!r && NotNullPtr) { throw runtime_error("Failed to cast to Regex"); } return r; } -template const Regex* Regex::cast(const T* ptr) { +template const Regex* Regex::cast(const T* ptr, bool NotNullPtr) { auto* r = dynamic_cast(ptr); - if (!r) { + if (!r && NotNullPtr) { throw runtime_error("Failed to cast to Regex"); } @@ -96,7 +96,7 @@ Regex* Regex::expr(const vector& lexemes, int index_start p = scan_par(lexemes, index_start, index_end); } - return cast(p); + return cast(p, false); } Regex* Regex::scan_minus(const vector& lexemes,