diff --git a/CMake/CMakeLists_itest.txt b/CMake/CMakeLists_itest.txt index ae311993d4c783907d41fd546e72a280abbfef63..bf51ad2adcbd3a82d90108e051ae46bd18aaaa03 100644 --- a/CMake/CMakeLists_itest.txt +++ b/CMake/CMakeLists_itest.txt @@ -1,4 +1,3 @@ -find_package(Catch2 REQUIRED) include(Catch) project({project_name}) @@ -23,7 +22,7 @@ set_target_properties(${{PROJECT_NAME_TEST}} PROPERTIES CXX_STANDARD_REQUIRED ON ) -target_link_libraries(${{PROJECT_NAME_TEST}} {target_test_libs} Catch2::Catch2) +target_link_libraries(${{PROJECT_NAME_TEST}} {target_test_libs} catch2) # Include dependencies directories target_include_directories(${{PROJECT_NAME_TEST}} diff --git a/alib2integrationtest/project.conf b/alib2integrationtest/project.conf new file mode 100644 index 0000000000000000000000000000000000000000..bea004a24bb35d88d8812d91f9c4ced89381da4c --- /dev/null +++ b/alib2integrationtest/project.conf @@ -0,0 +1,9 @@ +[General] +category: testing + +[TestDependencies] +project: alib2cli alib2str alib2std alib2common alib2algo alib2data alib2elgo alib2aux +system: stdc++fs + +[CMake:Deps:stdc++fs] +link: stdc++fs diff --git a/alib2integrationtest/test-src/main.cpp b/alib2integrationtest/test-src/main.cpp new file mode 100644 index 0000000000000000000000000000000000000000..f1f402b8b19a1a5195ef48e463d7a5703654d5b1 --- /dev/null +++ b/alib2integrationtest/test-src/main.cpp @@ -0,0 +1,3 @@ +#define CATCH_CONFIG_MAIN +#define CATCH_CONFIG_NO_POSIX_SIGNALS +#include <catch2/catch.hpp> diff --git a/alib2integrationtest/test-src/testing/TestFiles.cpp b/alib2integrationtest/test-src/testing/TestFiles.cpp new file mode 100644 index 0000000000000000000000000000000000000000..9a87addf9a00c791e2aa2401d4a3658a61682d04 --- /dev/null +++ b/alib2integrationtest/test-src/testing/TestFiles.cpp @@ -0,0 +1,44 @@ +#include "TestFiles.hpp" +#include "testfiles_basedir.hpp" + +#include <exception/CommonException.h> +#include <experimental/filesystem> + +std::vector < std::string > TestFiles::Get ( const std::string& regex ) { + return Get ( std::regex ( regex ) ); +} + +std::vector < std::string > TestFiles::Get ( const std::regex& regex ) { + std::vector < std::string > res; + + try { + for ( const std::experimental::filesystem::directory_entry & entry: std::experimental::filesystem::recursive_directory_iterator ( TEST_FILES_BASEDIR ) ) { + std::smatch match; + const std::string path = entry.path ( ); + + if ( std::regex_search ( path, match, regex ) ) { + res.push_back ( path ); + } + } + } catch ( const std::experimental::filesystem::filesystem_error & e ) { + throw exception::CommonException ( e.what ( ) ); + } + + return res; +} + +std::string TestFiles::GetOne ( const std::string& regex ) { + return GetOne ( std::regex ( regex ) ); +} + +std::string TestFiles::GetOne ( const std::regex& regex ) { + std::vector < std::string > res = Get ( regex ); + + if ( res.size ( ) > 1 ) + throw exception::CommonException ( std::string ( "Multiple files found for TestFiles::GetOne. TestFilesDir is " ) + TEST_FILES_BASEDIR ); + + if ( res.size ( ) == 0 ) + throw exception::CommonException ( std::string ( "No files found for TestFiles::GetOne. TestFilesDir is " ) + TEST_FILES_BASEDIR ); + + return res.at ( 0 ); +} diff --git a/alib2integrationtest/test-src/testing/TestFiles.hpp b/alib2integrationtest/test-src/testing/TestFiles.hpp new file mode 100644 index 0000000000000000000000000000000000000000..fdf7b70c4862f531f074d4d95fc77596ab1dcd0d --- /dev/null +++ b/alib2integrationtest/test-src/testing/TestFiles.hpp @@ -0,0 +1,16 @@ +#ifndef _TEST_FILES_ +#define _TEST_FILES_ + +#include <vector> +#include <string> +#include <regex> + +class TestFiles { + public: + static std::vector < std::string > Get ( const std::regex& regex ); + static std::vector < std::string > Get ( const std::string& regex ); + static std::string GetOne ( const std::string& regex ); + static std::string GetOne ( const std::regex& regex ); +}; + +#endif /* _TEST_FILES_ */ diff --git a/alib2integrationtest/test-src/testing/TimeoutAqlTest.cpp b/alib2integrationtest/test-src/testing/TimeoutAqlTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..5db375636118be4a7897272ff4ee4105759eccf0 --- /dev/null +++ b/alib2integrationtest/test-src/testing/TimeoutAqlTest.cpp @@ -0,0 +1,136 @@ +#include "TimeoutAqlTest.hpp" +#include <cstring> +#include <exception/CommonException.h> +#include <parser/Parser.h> + +#include <unistd.h> +#include <sys/wait.h> +#include <signal.h> + +#define PIPE_RD 0 +#define PIPE_WR 1 + +/* Communication between signal handler and the rest of the program */ +int g_Wakeup [ 2 ]; // pipe for wakeup +int g_RecvSignal; // signalled flag + +int waitSignalTimeout ( int timeout ) { + struct timeval tv; + fd_set rd; + + tv.tv_sec = 0; + tv.tv_usec = timeout; + FD_ZERO ( &rd ); + FD_SET ( g_Wakeup [ PIPE_RD ], &rd ); + + select ( g_Wakeup [ PIPE_RD ] + 1, &rd, NULL, NULL, &tv ); + return g_RecvSignal; +} + +void newSigChild ( int ) { + char dummy = 0; + g_RecvSignal = 1; + + // write into the pipe so select can read something, this effectively means that SIGCHILD was raised + if ( write ( g_Wakeup [ PIPE_WR ], &dummy, 1 ) != 1 ) + throw exception::CommonException ( "TimeoutAqlTest: write() failure (wakeup signalling)" ); +} + +int aqlTest ( int fd, const ext::vector < std::string > & queries ) { + cli::Environment environment; + + try { + for ( const std::string & q : queries ) { + cli::Parser parser = cli::Parser ( cli::Lexer ( q ) ); + parser.parse ( ) -> run ( environment ); + } + } catch ( const exception::CommonException & e ) { + const char * what = e.what ( ); + ssize_t what_len = ( ssize_t ) strlen ( what ); + if ( write ( fd, what, what_len ) != what_len ) + throw exception::CommonException ( "TimeoutAqlTest: write() failure (child to parent communication)" ); + return -1; + } + + return environment.getResult ( ); /* 0 = OK */ +} + +std::string readChildOutput ( int fd ) { + static const size_t BUFSIZE = 64; + + std::string res; + int rd; + char buf [ BUFSIZE ]; + + while ( ( rd = read ( fd, &buf, BUFSIZE - 1 ) ) > 0 ) { + res.append ( buf, rd ); + } + + return res; +} + +void _TimeoutAqlTest ( const std::chrono::microseconds & timeout, const ext::vector < std::string > & queries ) { + /* Register SIGCHLD handler */ + struct sigaction act; + memset ( &act, 0, sizeof ( act ) ); + act . sa_handler = newSigChild; + sigaction ( SIGCHLD, &act, NULL ); + + /* parent-child communication ( for exceptions ) */ + int pipefd [ 2 ]; + if ( pipe ( pipefd ) != 0 ) + throw exception::CommonException ( "TimeoutAqlTest: Failed to initialize pipe (child to parent communication)" ); + + /* SIGCHLD was not yet raised, initialize communication pipe */ + g_RecvSignal = 0; + if ( pipe ( g_Wakeup ) ) + throw exception::CommonException ( "TimeoutAqlTest: Failed to initialize pipe (wakeup signalling)" ); + + /* do the forking */ + pid_t x = fork (); + if ( x < 0 ) { + FAIL ( "Fork error" ); + } else if ( x == 0 ) { + /* child, run the test here */ + close ( g_Wakeup [ PIPE_RD ] ); + close ( g_Wakeup [ PIPE_WR ] ); + close ( pipefd [ PIPE_RD ] ); + + /* just in case ... */ + close ( 1 ); + close ( 2 ); + + exit ( aqlTest ( pipefd [ PIPE_WR ], queries ) ); + } + + close ( pipefd [ PIPE_WR ] ); + + /* lets wait the specified time of microseconds, maybe the child will terminate on its own */ + if ( ! waitSignalTimeout ( timeout.count ( ) ) ) { + /* ... and in case it did not ... */ + kill ( x, SIGTERM ); + while ( ! waitSignalTimeout ( 250000 ) ) /* 1/4 second */ + kill ( x, SIGKILL ); + } + + /* child termination confirmed */ + int status; + waitpid ( x, &status, 0 ); + close ( g_Wakeup [ PIPE_RD ] ); + close ( g_Wakeup [ PIPE_WR ] ); + + std::string childOutput = readChildOutput ( pipefd [ PIPE_RD ] ); + + close ( pipefd [ PIPE_RD ] ); + close ( pipefd [ PIPE_WR ] ); + + if ( WIFEXITED ( status ) ) { + // std::cerr << "Child process finished, code " << WEXITSTATUS ( status ) << std::endl; + INFO ( "AqlTest failure. Trying to execute: " << queries ); + INFO ( "Child output was: >" << childOutput << "<" ); + REQUIRE ( WEXITSTATUS ( status ) == 0 ); + } else if ( WIFSIGNALED ( status ) ) { + // std::cerr << "Child process signaled, signal ", WTERMSIG ( status ) << std::endl; + WARN ( "Timeout (" << timeout.count ( ) << " us) reached in test (" << queries << ")" ); + } +} diff --git a/alib2integrationtest/test-src/testing/TimeoutAqlTest.hpp b/alib2integrationtest/test-src/testing/TimeoutAqlTest.hpp new file mode 100644 index 0000000000000000000000000000000000000000..ec27ec3570fa43973ae504655121d658ce3e4d1d --- /dev/null +++ b/alib2integrationtest/test-src/testing/TimeoutAqlTest.hpp @@ -0,0 +1,17 @@ +#ifndef _TIMEOUT_AQL_TEST_HPP__ +#define _TIMEOUT_AQL_TEST_HPP__ + +#include <catch2/catch.hpp> +#include <chrono> +#include <alib/vector> + +using namespace std::chrono_literals; + +void _TimeoutAqlTest ( const std::chrono::microseconds & timeout, const ext::vector < std::string > & queries ); + +template < class D > +void TimeoutAqlTest ( const D & timeout, const ext::vector < std::string > & queries ) { + _TimeoutAqlTest ( std::chrono::duration_cast < std::chrono::microseconds > ( timeout ), queries ); +} + +#endif /* _TIMEOUT_AQL_TEST_HPP__ */ diff --git a/alib2integrationtest/test-src/tests/approximateMatching.cpp b/alib2integrationtest/test-src/tests/approximateMatching.cpp new file mode 100644 index 0000000000000000000000000000000000000000..44de13c0ec1db09e0fa97070211096b77f4c737b --- /dev/null +++ b/alib2integrationtest/test-src/tests/approximateMatching.cpp @@ -0,0 +1,108 @@ +#include <catch2/catch.hpp> +#include <alib/vector> + +#include "testing/TimeoutAqlTest.hpp" +#include "testing/TestFiles.hpp" + +const size_t PATTERN_SIZE = 7; +const size_t SUBJECT_SIZE = 100; +const size_t ALPHABET_SIZE = 4; +const size_t RANDOM_ITERATIONS = 20; + +static std::string qSetError ( const size_t error, const std::string & var ) { + return "execute " + std::to_string ( error ) + " > $" + var; +} + +static std::string qPrepareString ( const std::string &file, const std::string & var ) { + return "execute < " + file + " > $" + var; +} + +static std::string qExtendAlphabet ( const std::string & s1, const std::string & s2 ) { + return "execute string::GeneralAlphabet::add $" + s1 + " <( string::GeneralAlphabet::get $" + s2 + " ) > $" + s1; +} + +static std::string qGenString ( const size_t & len, const size_t &alph_len, const std::string & var ) { + std::ostringstream oss; + oss << "execute string::generate::RandomStringFactory "; + oss << "( size_t )" << rand ( ) % len + 1; + oss << "( size_t )" << rand ( ) % alph_len + 1; + oss << "true | "; + oss << "string::simplify::NormalizeAlphabet - > $" + var; + return oss.str ( ); +} + +static std::string qCreateMatchingAutomaton ( const std::string & algo, const std::string & pattern, const std::string & error, const std::string & var ) { + std::ostringstream oss; + oss << "execute "; + oss << algo << " $" + pattern + " $" + error + " | "; + oss << "automaton::simplify::efficient::EpsilonRemoverIncoming - | "; + oss << "automaton::determinize::Determinize - "; + oss << "> $" << var; + return oss.str ( ); +} + +static std::string qRunAutomaton ( const std::string & automaton, const std::string & subject, const std::string & res ) { + return "execute automaton::run::Occurrences $" + automaton + " $" + subject + " > $" + res; +} + +static std::string qRunDynamicAlgorithm ( const std::string & algo, const std::string &pattern, const std::string & subject, const std::string & error, const std::string & res ) { + std::ostringstream oss; + oss << "execute " << algo << " "; + oss << "$" << subject << " "; + oss << "$" << pattern << " "; + oss << "$" << error << " "; + oss << "> $" << res; + return oss.str ( ); +} + +TEST_CASE ( "Approximate Matching", "[integration]" ) { + auto definition = GENERATE ( as < std::pair < std::string, std::string > > ( ), + std::make_pair ( "stringology::matching::HammingMatchingAutomaton", "stringology::simulations::HammingDynamicProgramming" ), + std::make_pair ( "stringology::matching::HammingMatchingAutomaton", "stringology::simulations::HammingBitParalelism" ), + std::make_pair ( "stringology::matching::LevenshteinMatchingAutomaton", "stringology::simulations::LevenshteinDynamicProgramming" ), + std::make_pair ( "stringology::matching::LevenshteinMatchingAutomaton", "stringology::simulations::LevenshteinBitParalelism" ), + std::make_pair ( "stringology::matching::GeneralizedLevenshteinMatchingAutomaton", "stringology::simulations::GeneralizedLevenshteinDynamicProgramming" ), + std::make_pair ( "stringology::matching::GeneralizedLevenshteinMatchingAutomaton", "stringology::simulations::GeneralizedLevenshteinBitParalelism" ) ); + auto error = GENERATE ( 0, 1, 2, 3, 4, 5, 6 ); + + SECTION ( "Test files" ) { + for ( const std::string & patternFile : TestFiles::Get ( "/string/astringology.test.*.pattern.xml$" ) ) { + static const std::string p ( ".pattern." ), s ( ".subject." ); + std::string subjectFile = patternFile; + + size_t pos = subjectFile.find ( p ); + subjectFile.replace ( pos, s.size ( ), s ); + + ext::vector < std::string > qs = { + qSetError ( error, "error" ), + qPrepareString ( patternFile, "pattern" ), + qPrepareString ( subjectFile, "subject" ), + qExtendAlphabet ( "pattern", "subject" ), + qCreateMatchingAutomaton ( std::get < 0 > ( definition ), "pattern", "error", "automaton" ), + qRunAutomaton ( "automaton", "subject", "res1" ), + qRunDynamicAlgorithm ( std::get < 1 > ( definition ), "pattern", "subject", "error", "res2" ), + "quit compare::SetCompare $res1 $res2", + }; + + TimeoutAqlTest ( 2s, qs ); + } + } + + SECTION ( "Random tests" ) { + for ( size_t i = 0; i < RANDOM_ITERATIONS; i++ ) { + + ext::vector < std::string > qs = { + qSetError ( error, "error" ), + qGenString ( PATTERN_SIZE, ALPHABET_SIZE, "pattern" ), + qGenString ( SUBJECT_SIZE, ALPHABET_SIZE, "subject" ), + qExtendAlphabet ( "pattern", "subject" ), + qCreateMatchingAutomaton ( std::get < 0 > ( definition ), "pattern", "error", "automaton" ), + qRunAutomaton ( "automaton", "subject", "res1" ), + qRunDynamicAlgorithm ( std::get < 1 > ( definition ), "pattern", "subject", "error", "res2" ), + "quit compare::SetCompare $res1 $res2", + }; + + TimeoutAqlTest ( 5s, qs ); + } + } +} diff --git a/alib2integrationtest/test-src/tests/arbologyTest.cpp b/alib2integrationtest/test-src/tests/arbologyTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..30fb5500fa06c5b017176cace09f4de59fb1ac1b --- /dev/null +++ b/alib2integrationtest/test-src/tests/arbologyTest.cpp @@ -0,0 +1,283 @@ +#include <catch2/catch.hpp> +#include <alib/vector> + +#include "testing/TimeoutAqlTest.hpp" +#include "testing/TestFiles.hpp" + +enum class EGenerateType { + PATTERN, + SUBTREE, + NONLINEAR_PATTERN, + NONLINEAR_PATTERN_SINGLE_VAR, + + SUBJECT, +}; + +std::ostream& operator << ( std::ostream& os, const EGenerateType& type ) { + switch ( type ) { + case EGenerateType::PATTERN: + return ( os << "PATTERN" ); + case EGenerateType::SUBTREE: + return ( os << "SUBTREE" ); + case EGenerateType::NONLINEAR_PATTERN: + return ( os << "NONLINEAR_PATTERN" ); + case EGenerateType::NONLINEAR_PATTERN_SINGLE_VAR: + return ( os << "NONLINEAR_PATTERN_SINGLE_VAR"); + case EGenerateType::SUBJECT: + return ( os << "SUBJECT" ); + default: + return ( os << "Unhandled EGenerateType" ); + } +} + +const size_t PATTERN_SIZE = 4; +const size_t ALPHABET_SIZE = 3; +const size_t SUBJECT_HEIGHT = 25; +const size_t PATTERN_HEIGHT = 2; +const size_t RANDOM_ITERATIONS = 20; + +static std::string qGen ( const EGenerateType & type, int height, int nodes, int alphSize, const std::string & output ) { + std::ostringstream oss; + oss << "execute "; + + if ( type == EGenerateType::SUBJECT ) { + oss << "tree::generate::RandomRankedTreeFactory"; + } else if ( type == EGenerateType::PATTERN ) { + oss << "tree::generate::RandomRankedPatternFactory"; + } else if ( type == EGenerateType::SUBTREE ) { + oss << "tree::generate::RandomRankedTreeFactory"; + } else if ( type == EGenerateType::NONLINEAR_PATTERN ) { + oss << "tree::generate::RandomRankedNonlinearPatternFactory"; + } else if ( type == EGenerateType::NONLINEAR_PATTERN_SINGLE_VAR ) { + oss << "tree::generate::RandomRankedNonlinearPatternFactory"; + } + + oss << " (int)" << height; + oss << " (int)" << nodes; + oss << " (int)" << rand ( ) % alphSize + 1; + oss << " (bool) false"; /* alphRand */ + if ( type == EGenerateType::NONLINEAR_PATTERN || type == EGenerateType::NONLINEAR_PATTERN_SINGLE_VAR ) + oss << " (bool)" << ( type == EGenerateType::NONLINEAR_PATTERN_SINGLE_VAR ); + oss << " (int)" << 5; /* rank */ + oss << "> $" << output; + return oss.str ( ); +} + +static std::string search_replace ( std::string text, const std::string & search, const std::string & replace ) { + size_t pos = text.find ( search ); + text.replace ( pos, search.size ( ), replace ); + return text; +} + +static std::vector < std::pair < std::string, std::string > > pair_pattern_subject ( const std::vector < std::string > & files, const std::string & pattern, const std::string & subj ) { + std::vector < std::pair < std::string, std::string > > res; + for ( const auto & file : files ) + res.push_back ( std::make_pair ( file, search_replace ( file, pattern, subj ) ) ); + + return res; +} + + +void runTest ( const std::string & exactPipeline, const std::string &pipeline, const std::string &pFile, const std::string &sFile ) { + ext::vector < std::string > qs = { + "execute < " + pFile + " > $pattern", + "execute < " + sFile + " > $subject", + "execute " + exactPipeline + " > $res1", + "execute " + pipeline + " > $res2", + "quit compare::PrimitiveCompare <(stats::SizeStat $res1) <(stats::SizeStat $res2)", + }; + + TimeoutAqlTest ( 10s, qs ); +} + +void runRandom ( const std::string & exactPipeline, const std::string &pipeline, const EGenerateType &patternType, const size_t& subjSize ) { + ext::vector < std::string > qs = { + qGen ( patternType, PATTERN_HEIGHT, PATTERN_SIZE, ALPHABET_SIZE, "pattern" ), + qGen ( EGenerateType::SUBJECT, SUBJECT_HEIGHT, subjSize, ALPHABET_SIZE, "subject" ), + "execute " + exactPipeline + " > $res1", + "execute " + pipeline + " > $res2", + "quit compare::PrimitiveCompare <(stats::SizeStat $res1) <(stats::SizeStat $res2)", + }; + + TimeoutAqlTest ( 10s, qs ); +} + +TEST_CASE ( "Arbology tests | nonlinear pattern", "[integration]" ) { + auto definition = GENERATE ( as < std::tuple < std::string, std::string, size_t > > ( ), + std::make_tuple ( "Exact Nonlinear Pattern Matching Using Compressed Bit Vectors (PrefixRankedBar)", + "arbology::indexing::NonlinearCompressedBitParallelIndexConstruction (PrefixRankedBarTree)$subject | arbology::query::NonlinearCompressedBitParallelismPatterns - (PrefixRankedBarNonlinearPattern)$pattern", 1000 ), + std::make_tuple ( "Exact Nonlinear Pattern Matching Using Full And Linear Index (PrefixRanked)", + "arbology::indexing::NonlinearFullAndLinearIndexConstruction (PrefixRankedTree)$subject | arbology::query::NonlinearFullAndLinearIndexPatterns - (PrefixRankedNonlinearPattern) $pattern", 1000 ), + std::make_tuple ( "Exact Nonlinear Pattern Matching Using Full And Linear Index (PrefixRankedBar)", + "arbology::indexing::NonlinearFullAndLinearIndexConstruction (PrefixRankedBarTree)$subject | arbology::query::NonlinearFullAndLinearIndexPatterns - (PrefixRankedBarNonlinearPattern) $pattern", 1000 ), + std::make_tuple ( "Exact Nonlinear Tree Pattern Automaton (PrefixRankedBar)", + "arbology::exact::ExactNonlinearTreePatternAutomaton (PrefixRankedBarTree)$subject <(tree::SubtreeWildcard::get $pattern) <(tree::NonlinearAlphabet::get $pattern) <(tree::VariablesBarSymbol::get (PrefixRankedBarNonlinearPattern)$pattern) | " + "automaton::determinize::Determinize - | (SetOfObjects)automaton::run::Result - (LinearString)(PrefixRankedBarNonlinearPattern)$pattern (DefaultStateType){ :Object }", 80 ), + std::make_tuple ( "Exact Pattern Match (NonlinearPattern PrefixRankedBar)", + "arbology::exact::ExactPatternMatch (PrefixRankedBarTree)$subject (PrefixRankedBarNonlinearPattern) <(tree::GeneralAlphabet::add $pattern <(tree::GeneralAlphabet::get $subject))", 1000 ), + std::make_tuple ( "Exact Boyer Moore Horspool (NonlinearPattern PrefixRankedBar)", + "arbology::exact::BoyerMooreHorspool (PrefixRankedBarTree)$subject (PrefixRankedBarNonlinearPattern) <(tree::GeneralAlphabet::add $pattern <(tree::GeneralAlphabet::get $subject))", 1000 ), + std::make_tuple ( "Exact Reversed Boyer Moore Horspool (NonlinearPattern PrefixRankedBar)", + "arbology::exact::ReversedBoyerMooreHorspool (PrefixRankedBarTree)$subject (PrefixRankedBarNonlinearPattern) <(tree::GeneralAlphabet::add $pattern <(tree::GeneralAlphabet::get $subject))", 1000 ), + std::make_tuple ( "Exact Reversed Boyer Moore Horspool (NonlinearPattern PrefixRanked)", + "arbology::exact::ReversedBoyerMooreHorspool (PrefixRankedTree)$subject (PrefixRankedNonlinearPattern) <(tree::GeneralAlphabet::add $pattern <(tree::GeneralAlphabet::get $subject))", 1000 ) ); + + auto exact = "arbology::exact::ExactPatternMatch $subject $pattern"; + auto pattern = EGenerateType::NONLINEAR_PATTERN; + + + SECTION ( "Test files" ) { + for ( const std::pair < std::string, std::string > files : pair_pattern_subject ( TestFiles::Get ( "/tree/aarbology.test[0-9]+.nonlinear.pattern.xml$" ), ".nonlinear.pattern.xml", ".subject.xml" ) ) { + CAPTURE ( std::get < 0 > ( definition ), std::get < 1 > ( definition ), files.first, files.second ); + runTest ( exact, std::get < 1 > ( definition ), files.first, files.second ); + } + } + + SECTION ( "Random tests" ) { + for ( size_t i = 0; i < RANDOM_ITERATIONS; i++ ) { + CAPTURE ( std::get < 0 > ( definition ), std::get < 1 > ( definition ), pattern, std::get < 2 > ( definition ) ); + runRandom ( exact, std::get < 1 > ( definition ), pattern, std::get < 2 > ( definition ) ); + } + } +} + +// -------------------------------------------------------------------------------------------------------------------- + +TEST_CASE ( "Arbology tests | nonlinear pattern ends", "[integration]" ) { + auto definition = GENERATE ( as < std::tuple < std::string, std::string, size_t > > ( ), + std::make_tuple ( "Exact Nonlinear Tree Pattern Automaton (PrefixRanked)", + "arbology::exact::ExactNonlinearTreePatternAutomaton (PrefixRankedTree)$subject <(tree::SubtreeWildcard::get $pattern) <(tree::NonlinearAlphabet::get $pattern) | automaton::determinize::Determinize - |" + "(SetOfObjects)automaton::run::Result - (LinearString)(PrefixRankedNonlinearPattern) $pattern (DefaultStateType) { :Object } ", 80 ) ); + + auto exact = "arbology::exact::ExactPatternMatch $subject $pattern | arbology::transform::BeginToEndIndex $subject -"; + auto pattern = EGenerateType::NONLINEAR_PATTERN_SINGLE_VAR; + + SECTION ( "Test files" ) { + for ( const std::pair < std::string, std::string > files : pair_pattern_subject ( TestFiles::Get ( "/tree/aarbology.test[0-9]+.nonlinear.pattern.xml$" ), ".nonlinear.pattern.xml", ".subject.xml" ) ) { + CAPTURE ( std::get < 0 > ( definition ), std::get < 1 > ( definition ), files.first, files.second ); + runTest ( exact, std::get < 1 > ( definition ), files.first, files.second ); + } + } + + SECTION ( "Random tests" ) { + for ( size_t i = 0; i < RANDOM_ITERATIONS; i++ ) { + CAPTURE ( std::get < 0 > ( definition ), std::get < 1 > ( definition ), pattern, std::get < 2 > ( definition ) ); + runRandom ( exact, std::get < 1 > ( definition ), pattern, std::get < 2 > ( definition ) ); + } + } +} + +// -------------------------------------------------------------------------------------------------------------------- + +TEST_CASE ( "Arbology tests | pattern", "[integration]" ) { + auto definition = GENERATE ( as < std::tuple < std::string, std::string, size_t > > ( ), + std::make_tuple ( "Exact Pattern Matching Using Full And Linear Index (PrefixRankedBar)", + "arbology::indexing::FullAndLinearIndexConstruction (PrefixRankedBarTree) $subject | arbology::query::FullAndLinearIndexPatterns - (PrefixRankedBarPattern) $pattern", 1000 ), + std::make_tuple ( "Exact Pattern Matching Using Full And Linear Index (PrefixRanked)", + "arbology::indexing::FullAndLinearIndexConstruction (PrefixRankedTree) $subject | arbology::query::FullAndLinearIndexPatterns - (PrefixRankedPattern) $pattern", 1000 ), + std::make_tuple ( "Exact Pattern Matching Using Compressed Bit Vectors (PrefixRankedBar)", + "arbology::indexing::CompressedBitParallelIndexConstruction (PrefixRankedBarTree)$subject | arbology::query::CompressedBitParallelismPatterns - (PrefixRankedBarPattern)$pattern", 1000 ), + std::make_tuple ( "Exact Knuth Morris Pratt (Pattern PrefixRankedBar)", + "arbology::exact::KnuthMorrisPratt (PrefixRankedBarTree)$subject (PrefixRankedBarPattern)$pattern", 1000 ), + std::make_tuple ( "Exact Knuth Morris Pratt (Pattern PrefixRanked)", + "arbology::exact::KnuthMorrisPratt (PrefixRankedTree)$subject (PrefixRankedPattern)$pattern", 1000 ), + std::make_tuple ( "Exact Boyer Moore Horspool (Pattern PrefixRankedBar)", + "arbology::exact::BoyerMooreHorspool (PrefixRankedBarTree)$subject (PrefixRankedBarPattern) <(tree::GeneralAlphabet::add $pattern <(tree::GeneralAlphabet::get $subject))", 1000 ), + std::make_tuple ( "Exact Reversed Boyer Moore Horspool (Pattern PrefixRankedBar)", + "arbology::exact::ReversedBoyerMooreHorspool (PrefixRankedBarTree)$subject (PrefixRankedBarPattern) <(tree::GeneralAlphabet::add $pattern <(tree::GeneralAlphabet::get $subject))", 1000 ), + std::make_tuple ( "Exact Reversed Boyer Moore Horspool (Pattern PrefixRanked)", + "arbology::exact::ReversedBoyerMooreHorspool (PrefixRankedTree)$subject (PrefixRankedPattern) <(tree::GeneralAlphabet::add $pattern <(tree::GeneralAlphabet::get $subject))", 1000 ), + std::make_tuple ( "Exact Quick Search (Pattern PrefixRankedBar)", + "arbology::exact::QuickSearch (PrefixRankedBarTree)$subject (PrefixRankedBarPattern)<(tree::GeneralAlphabet::add $pattern <(tree::GeneralAlphabet::get $subject))", 1000 ), + std::make_tuple ( "Exact Reversed Quick Search (Pattern PrefixRankedBar)", + "arbology::exact::ReversedQuickSearch (PrefixRankedBarTree)$subject (PrefixRankedBarPattern)<(tree::GeneralAlphabet::add $pattern <(tree::GeneralAlphabet::get $subject))", 1000 ), + std::make_tuple ( "Exact Reversed Quick Search (Pattern PrefixRanked)", + "arbology::exact::ReversedQuickSearch (PrefixRankedTree)$subject (PrefixRankedPattern)<(tree::GeneralAlphabet::add $pattern <(tree::GeneralAlphabet::get $subject))", 1000 ), + std::make_tuple ( "Exact Dead Zone Using Bad Character Shift And Border Array (Pattern PrefixRanked)", + "arbology::exact::DeadZoneUsingBadCharacterShiftAndBorderArray (PrefixRankedTree)$subject (PrefixRankedPattern)<(tree::GeneralAlphabet::add $pattern <(tree::GeneralAlphabet::get $subject))", 1000 ), + std::make_tuple ( "Exact Dead Zone Using Bad Character Shift And Border Array (Pattern PrefixRankedBar)", + "arbology::exact::DeadZoneUsingBadCharacterShiftAndBorderArray (PrefixRankedBarTree)$subject (PrefixRankedBarPattern)<(tree::GeneralAlphabet::add $pattern <(tree::GeneralAlphabet::get $subject))", 1000 ), + std::make_tuple ( "Exact Pattern Matching Automaton (Pattern Tree)", + "automaton::run::Occurrences <(arbology::exact::ExactPatternMatchingAutomaton <(tree::GeneralAlphabet::add $pattern <(tree::GeneralAlphabet::get $subject)) | automaton::determinize::Determinize - ) $subject", 1000 ), + std::make_tuple ( "Exact Pattern Matching Automaton (PrefixRankedBar)", + "arbology::exact::ExactPatternMatchingAutomaton (PrefixRankedBarPattern) <(tree::GeneralAlphabet::add $pattern <(tree::GeneralAlphabet::get $subject)) | automaton::determinize::Determinize - | automaton::run::Occurrences - (LinearString)(PrefixRankedBarTree)$subject", 1000 ) ); + + auto exact = "arbology::exact::ExactPatternMatch $subject $pattern"; + auto pattern = EGenerateType::PATTERN; + + SECTION ( "Test files" ) { + for ( const std::pair < std::string, std::string > files : pair_pattern_subject ( TestFiles::Get ( "/tree/aarbology.test[0-9]+.pattern.xml$" ), ".pattern.xml", ".subject.xml" ) ) { + CAPTURE ( std::get < 0 > ( definition ), std::get < 1 > ( definition ), files.first, files.second ); + runTest ( exact, std::get < 1 > ( definition ), files.first, files.second ); + } + } + + SECTION ( "Random tests" ) { + for ( size_t i = 0; i < RANDOM_ITERATIONS; i++ ) { + CAPTURE ( std::get < 0 > ( definition ), std::get < 1 > ( definition ), pattern, std::get < 2 > ( definition ) ); + runRandom ( exact, std::get < 1 > ( definition ), pattern, std::get < 2 > ( definition ) ); + } + } +} + +// -------------------------------------------------------------------------------------------------------------------- + +TEST_CASE ( "Arbology tests | pattern ends ", "[integration]" ) { + auto definition = GENERATE ( as < std::tuple < std::string, std::string, size_t > > ( ), + std::make_tuple ( "Exact Pattern Matching Using Compressed Bit Vectors (PrefixRanked)", + "arbology::indexing::CompressedBitParallelIndexConstruction (PrefixRankedTree)$subject | arbology::query::CompressedBitParallelismPatterns - (PrefixRankedPattern)$pattern", 1000 ), + + std::make_tuple ( "Exact Pattern Matching Automaton (PrefixRanked)", + "arbology::exact::ExactPatternMatchingAutomaton (PrefixRankedPattern) <(tree::GeneralAlphabet::add $pattern <(tree::GeneralAlphabet::get $subject) ) | automaton::determinize::Determinize - | " + "automaton::run::Occurrences - (LinearString)(PrefixRankedTree) $subject", 1000 ), + + std::make_tuple ( "Exact Tree Pattern Automaton (PrefixRanked)", + "arbology::exact::ExactTreePatternAutomaton (PrefixRankedTree)$subject <(tree::SubtreeWildcard::get $pattern) | automaton::determinize::Determinize - | (SetOfObjects) automaton::run::Result - (LinearString)(PrefixRankedPattern)$pattern (DefaultStateType) { :Object }", 120 ) ); + + auto exact = "arbology::exact::ExactPatternMatch (PrefixRankedTree)$subject (PrefixRankedPattern)$pattern | arbology::transform::BeginToEndIndex (PrefixRankedTree)$subject -"; + auto pattern = EGenerateType::PATTERN; + + SECTION ( "Test files" ) { + for ( const std::pair < std::string, std::string > files : pair_pattern_subject ( TestFiles::Get ( "/tree/aarbology.test[0-9]+.pattern.xml$" ), ".pattern.xml", ".subject.xml" ) ) { + CAPTURE ( std::get < 0 > ( definition ), std::get < 1 > ( definition ), files.first, files.second ); + runTest ( exact, std::get < 1 > ( definition ), files.first, files.second ); + } + } + + SECTION ( "Random tests" ) { + for ( size_t i = 0; i < RANDOM_ITERATIONS; i++ ) { + CAPTURE ( std::get < 0 > ( definition ), std::get < 1 > ( definition ), pattern, std::get < 2 > ( definition ) ); + runRandom ( exact, std::get < 1 > ( definition ), pattern, std::get < 2 > ( definition ) ); + } + } +} +// -------------------------------------------------------------------------------------------------------------------- + +TEST_CASE ( "Arbology tests | subtree", "[integration]" ) { + auto definition = GENERATE ( as < std::tuple < std::string, std::string, size_t > > ( ), + std::make_tuple ( "Exact Subtree Automaton (Tree)", + "automaton::run::Occurrences <(arbology::exact::ExactSubtreeMatchingAutomaton $pattern | automaton::determinize::Determinize -) $subject", 1000 ), + std::make_tuple ( "Exact Minimized Subtree Automaton (Tree)", + "automaton::run::Occurrences <(arbology::exact::ExactSubtreeMatchingAutomaton $pattern | automaton::determinize::Determinize - | " + "automaton::simplify::Trim - | automaton::simplify::Minimize -) $subject", 1000 ), + std::make_tuple ( "Exact Boyer Moore Horspool (Subtree PrefixRankedBar)", + "arbology::exact::BoyerMooreHorspool (PrefixRankedBarTree)$subject (PrefixRankedBarTree) <(tree::GeneralAlphabet::add $pattern <(tree::GeneralAlphabet::get $subject))", 1000 ) ); + + + auto exact = "arbology::exact::ExactSubtreeMatch $subject $pattern"; + auto pattern = EGenerateType::SUBTREE; + + SECTION ( "Test files" ) { + for ( const std::pair < std::string, std::string > files : pair_pattern_subject ( TestFiles::Get ( "/tree/aarbology.test[0-9]+.subtree.xml$" ), ".subtree.xml", ".subject.xml" ) ) { + CAPTURE ( std::get < 0 > ( definition ), std::get < 1 > ( definition ), files.first, files.second ); + runTest ( exact, std::get < 1 > ( definition ), files.first, files.second ); + } + } + + SECTION ( "Random tests" ) { + for ( size_t i = 0; i < RANDOM_ITERATIONS; i++ ) { + CAPTURE ( std::get < 0 > ( definition ), std::get < 1 > ( definition ), pattern, std::get < 2 > ( definition ) ); + runRandom ( exact, std::get < 1 > ( definition ), pattern, std::get < 2 > ( definition ) ); + } + } +} diff --git a/alib2integrationtest/test-src/tests/conversionsTest.cpp b/alib2integrationtest/test-src/tests/conversionsTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..19e2cc1231a9e1aaa78fece5816df90474aa0f38 --- /dev/null +++ b/alib2integrationtest/test-src/tests/conversionsTest.cpp @@ -0,0 +1,69 @@ +#include <catch2/catch.hpp> +#include <alib/vector> + +#include "testing/TimeoutAqlTest.hpp" +#include "testing/TestFiles.hpp" + +const unsigned RAND_STATES = 15; +const unsigned RAND_ALPHABET = 5; +const double RAND_DENSITY = 2.5; +const size_t ITERATIONS = 50; + +const std::string qGenNFA ( ) { + std::ostringstream oss; + oss << "execute automaton::generate::RandomAutomatonFactory "; + oss << "(size_t)" << rand ( ) % RAND_STATES + 1 << " "; + oss << "(size_t)" << rand ( ) % RAND_ALPHABET + 1 << " "; + oss << "(bool)true "; + oss << "(double)\"" << RAND_DENSITY << "\""; + return oss.str ( ); +} + +TEST_CASE ( "FA-RG-RE conversions test", "[integration]" ) { + auto pipeline = GENERATE ( as < std::string > ( ), + "automaton::convert::ToGrammarLeftRG - | grammar::convert::ToGrammarRightRG - | grammar::convert::ToAutomaton -", + "automaton::convert::ToGrammarRightRG - | grammar::convert::ToGrammarLeftRG - | grammar::convert::ToAutomaton -", + + "automaton::convert::ToRegExpAlgebraic - | regexp::convert::ToAutomatonDerivation -", + "automaton::convert::ToRegExpAlgebraic - | regexp::convert::ToAutomatonGlushkov -", + "automaton::convert::ToRegExpAlgebraic - | regexp::convert::ToAutomatonThompson -", + "automaton::convert::ToRegExpStateElimination - | regexp::convert::ToAutomatonDerivation -", + "automaton::convert::ToRegExpStateElimination - | regexp::convert::ToAutomatonGlushkov -", + "automaton::convert::ToRegExpStateElimination - | regexp::convert::ToAutomatonThompson -", + + "automaton::convert::ToRegExpAlgebraic - | regexp::convert::ToGrammarRightRGDerivation - | grammar::convert::ToGrammarLeftRG - | grammar::convert::ToAutomaton -", + "automaton::convert::ToRegExpAlgebraic - | regexp::convert::ToGrammarRightRGGlushkov - | grammar::convert::ToGrammarLeftRG - | grammar::convert::ToAutomaton -", + "automaton::convert::ToRegExpStateElimination - | regexp::convert::ToGrammarRightRGDerivation - | grammar::convert::ToGrammarLeftRG - | grammar::convert::ToAutomaton -", + "automaton::convert::ToRegExpStateElimination - | regexp::convert::ToGrammarRightRGGlushkov - | grammar::convert::ToGrammarLeftRG - | grammar::convert::ToAutomaton -", + + "automaton::convert::ToGrammarLeftRG - | grammar::convert::ToRegExp - | regexp::convert::ToAutomatonDerivation -", + "automaton::convert::ToGrammarRightRG - | grammar::convert::ToRegExp - | regexp::convert::ToAutomatonDerivation -", + "automaton::convert::ToGrammarLeftRG - | grammar::convert::ToRegExp - | regexp::convert::ToAutomatonThompson -", + "automaton::convert::ToGrammarRightRG - | grammar::convert::ToRegExp - | regexp::convert::ToAutomatonThompson -", + "automaton::convert::ToGrammarLeftRG - | grammar::convert::ToRegExp - | regexp::convert::ToAutomatonGlushkov -", + "automaton::convert::ToGrammarRightRG - | grammar::convert::ToRegExp - | regexp::convert::ToAutomatonGlushkov -" ); + + static const std::string qMinimize ( "automaton::simplify::efficient::EpsilonRemoverIncoming - | automaton::determinize::Determinize - | " + "automaton::simplify::Trim - | automaton::simplify::Minimize - | automaton::simplify::Normalize -" ); + + + SECTION ( "Files tests" ) { + for ( const std::string & inputFile : TestFiles::Get ( "/automaton/aconversion.test.*.xml$" ) ) { + ext::vector < std::string > qs = { + "execute < " + inputFile + " > $gen", + "quit compare::AutomatonCompare <( $gen | " + qMinimize + " )" + " <( $gen | " + pipeline + " | " + qMinimize + ")" + }; + TimeoutAqlTest ( 10s, qs ); + } + } + + SECTION ( "Random tests" ) { + for ( size_t i = 0; i < ITERATIONS; i++ ) { + ext::vector < std::string > qs = { + qGenNFA ( ) + " > $gen", + "quit compare::AutomatonCompare <( $gen | " + qMinimize + " )" + " <( $gen | " + pipeline + " | " + qMinimize + ")" + }; + TimeoutAqlTest ( 10s, qs ); + } + } +} diff --git a/alib2integrationtest/test-src/tests/determinizeTest.cpp b/alib2integrationtest/test-src/tests/determinizeTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..5d49fe6fb8ad839afec7f90a5ad1df01d9c89b07 --- /dev/null +++ b/alib2integrationtest/test-src/tests/determinizeTest.cpp @@ -0,0 +1,29 @@ +#include <catch2/catch.hpp> +#include <alib/vector> + +#include "testing/TimeoutAqlTest.hpp" +#include "testing/TestFiles.hpp" + +TEST_CASE ( "Determinization", "[integration]" ) { + auto definition = GENERATE ( as < std::tuple < std::string, std::string, std::string > > ( ), + std::make_tuple ( "automaton::determinize::Determinize - | automaton::simplify::Trim -", TestFiles::GetOne ( "/automaton/NFSM1.xml$" ), TestFiles::GetOne ( "/automaton/NFSM1.DET.xml$" ) ), + std::make_tuple ( "automaton::determinize::Determinize - | automaton::simplify::Trim -", TestFiles::GetOne ( "/automaton/NFSM2.xml$" ), TestFiles::GetOne ( "/automaton/NFSM2.DET.xml$" ) ), + std::make_tuple ( "automaton::determinize::Determinize - | automaton::simplify::Trim -", TestFiles::GetOne ( "/automaton/NFSM3.xml$" ), TestFiles::GetOne ( "/automaton/NFSM3.DET.xml$" ) ), + std::make_tuple ( "automaton::determinize::Determinize - | automaton::simplify::Trim -", TestFiles::GetOne ( "/automaton/NFSM4.xml$" ), TestFiles::GetOne ( "/automaton/NFSM4.DET.xml$" ) ), + std::make_tuple ( "automaton::determinize::Determinize - | automaton::simplify::Trim -", TestFiles::GetOne ( "/automaton/NFSM5.xml$" ), TestFiles::GetOne ( "/automaton/NFSM5.DET.xml$" ) ), + std::make_tuple ( "automaton::simplify::EpsilonRemoverIncoming - | automaton::determinize::Determinize -", TestFiles::GetOne ( "/automaton/ENFSM2.xml$" ), TestFiles::GetOne ( "/automaton/ENFSM2.DET.xml$" ) ), + std::make_tuple ( "automaton::determinize::Determinize - ", TestFiles::GetOne ( "/automaton/NFTA.xml$" ), TestFiles::GetOne ( "/automaton/NFTA.DET.xml$" ) ), + std::make_tuple ( "automaton::determinize::Determinize - ", TestFiles::GetOne ( "/automaton/NIDPDA0.xml$" ), TestFiles::GetOne ( "/automaton/NIDPDA0.DET.xml$" ) ), + std::make_tuple ( "automaton::determinize::Determinize - ", TestFiles::GetOne ( "/automaton/NIDPDA1.xml$" ), TestFiles::GetOne ( "/automaton/NIDPDA1.DET.xml$" ) ), + std::make_tuple ( "automaton::determinize::Determinize - ", TestFiles::GetOne ( "/automaton/NIDPDA2.xml$" ), TestFiles::GetOne ( "/automaton/NIDPDA2.DET.xml$" ) ), + std::make_tuple ( "automaton::determinize::Determinize - ", TestFiles::GetOne ( "/automaton/NIDPDA3.xml$" ), TestFiles::GetOne ( "/automaton/NIDPDA3.DET.xml$" ) ), + std::make_tuple ( "automaton::determinize::Determinize - | automaton::simplify::Normalize -", TestFiles::GetOne ( "/automaton/NPDA1.xml$" ), TestFiles::GetOne ( "/automaton/NPDA1.DET.xml$" ) ) ); + + ext::vector < std::string > qs = { + "execute < " + std::get < 1 > ( definition ) + " > $input", + "execute < " + std::get < 2 > ( definition ) + " > $expected", + "quit compare::AutomatonCompare <( $input | " + std::get < 0 > ( definition ) + " ) $expected" + }; + + TimeoutAqlTest ( 2s, qs ); +} diff --git a/alib2integrationtest/test-src/tests/dummyTest.cpp b/alib2integrationtest/test-src/tests/dummyTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..3216f53d6a9feff395f1ab91fc500fb024a7a248 --- /dev/null +++ b/alib2integrationtest/test-src/tests/dummyTest.cpp @@ -0,0 +1,14 @@ +#include <catch2/catch.hpp> +#include <alib/vector> + +#include "testing/TimeoutAqlTest.hpp" +#include "testing/TestFiles.hpp" + +TEST_CASE ( "Dummy Test", "[integration][dummy][!mayfail]" ) { + ext::vector < std::string > qs = { + "execute 1", + "exec" + }; + + TimeoutAqlTest ( 1s, qs ); +} diff --git a/alib2integrationtest/test-src/tests/exactMatching.cpp b/alib2integrationtest/test-src/tests/exactMatching.cpp new file mode 100644 index 0000000000000000000000000000000000000000..d6b34df65d6ae3620393983b492eb9860d635a67 --- /dev/null +++ b/alib2integrationtest/test-src/tests/exactMatching.cpp @@ -0,0 +1,85 @@ +#include <catch2/catch.hpp> +#include <alib/vector> + +#include "testing/TimeoutAqlTest.hpp" +#include "testing/TestFiles.hpp" + +const size_t PATTERN_SIZE = 7; +const size_t SUBJECT_SIZE = 100; +const size_t ALPHABET_SIZE = 4; +const size_t RANDOM_ITERATIONS = 20; + +static std::string qExtendAlphabet ( const std::string & s1, const std::string & s2 ) { + return "execute string::GeneralAlphabet::add $" + s1 + " <( string::GeneralAlphabet::get $" + s2 + " ) > "; +} + +static std::string qGenString ( const size_t & len, const size_t &alph_len, const std::string & var ) { + std::ostringstream oss; + oss << "execute string::generate::RandomStringFactory "; + oss << "( size_t )" << rand ( ) % len + 1; + oss << "( size_t )" << rand ( ) % alph_len + 1; + oss << "true | "; + oss << "string::simplify::NormalizeAlphabet - > $" + var; + return oss.str ( ); +} + +TEST_CASE ( "ExactMatching", "[integration]" ) { + auto definition = GENERATE ( as < std::tuple < std::string, std::string, bool > > ( ), + std::make_tuple ( "Exact Boyer Moore", "stringology::exact::BoyerMoore $subject $pattern", true ), + std::make_tuple ( "Exact Boyer Moore Horspool", " stringology::exact::BoyerMooreHorspool $subject $pattern", true ), + std::make_tuple ( "Exact Reversed Boyer Moore Horspool", " stringology::exact::ReversedBoyerMooreHorspool $subject $pattern", true ), + std::make_tuple ( "Quick Search", "stringology::exact::QuickSearch $subject $pattern", true ), + std::make_tuple ( "Exact Dead Zone Using Bad Character Shift", "stringology::exact::DeadZoneUsingBadCharacterShift $subject $pattern", true ), + std::make_tuple ( "Exact Matching Automaton", "automaton::run::Occurrences <(stringology::matching::ExactMatchingAutomaton $pattern | automaton::determinize::Determinize -) $subject", true ), + std::make_tuple ( "DAWG Factors", "stringology::indexing::ExactSuffixAutomaton $subject | stringology::query::SuffixAutomatonFactors - $pattern", false ), + std::make_tuple ( "BNDM Matcher", "stringology::matching::BNDMMatcherConstruction $pattern | stringology::query::BNDMOccurrences - $subject", false ), + std::make_tuple ( "Compressed Bit Parallelism Factors", "stringology::indexing::CompressedBitParallelIndexConstruction $subject | stringology::query::CompressedBitParallelismFactors - $pattern", false ), + std::make_tuple ( "Bit Parallelism Factors", "stringology::indexing::BitParallelIndexConstruction $subject | stringology::query::BitParallelismFactors - $pattern", false ), + std::make_tuple ( "Position Heap Factors", "stringology::indexing::PositionHeapNaive $subject | stringology::query::PositionHeapFactors - $pattern", false ), + std::make_tuple ( "Suffix Array Factors", "stringology::indexing::SuffixArrayNaive $subject | stringology::query::SuffixArrayFactors - $pattern", false ), + std::make_tuple ( "Suffix Trie Factors", "stringology::indexing::SuffixTrieNaive $subject | stringology::query::SuffixTrieFactors - $pattern", false ) ); + + SECTION ( "Test files" ) { + for ( const std::string & patternFile : TestFiles::Get ( "/string/astringology.test.*.pattern.xml$" ) ) { + static const std::string p ( ".pattern." ), s ( ".subject." ); + std::string subjectFile = patternFile; + + size_t pos = subjectFile.find ( p ); + subjectFile.replace ( pos, s.size ( ), s ); + + ext::vector < std::string > qs = { + "execute < " + patternFile + " > $pattern", + "execute < " + subjectFile + " > $subject", + "execute stringology::exact::ExactFactorMatch $subject $pattern > $res1" + }; + + if ( std::get < 2 > ( definition ) ) + qs.push_back ( qExtendAlphabet ( "pattern", "subject" ) ); + + qs.push_back ( "execute " + std::get < 1 > ( definition ) + " > $res2" ); + qs.push_back ( "quit compare::PrimitiveCompare <(stats::SizeStat $res1) <(stats::SizeStat $res2)" ); + + INFO ( std::get < 0 > ( definition ) ); + TimeoutAqlTest ( 2s, qs ); + } + } + + SECTION ( "Random tests" ) { + for ( size_t i = 0; i < RANDOM_ITERATIONS; i++ ) { + ext::vector < std::string > qs = { + qGenString ( PATTERN_SIZE, ALPHABET_SIZE, "pattern" ), + qGenString ( SUBJECT_SIZE, ALPHABET_SIZE, "subject" ), + "execute stringology::exact::ExactFactorMatch $subject $pattern > $res1" + }; + + if ( std::get < 2 > ( definition ) ) + qs.push_back ( qExtendAlphabet ( "pattern", "subject" ) ); + + qs.push_back ( "execute " + std::get < 1 > ( definition ) + " > $res2" ); + qs.push_back ( "quit compare::PrimitiveCompare <(stats::SizeStat $res1) <(stats::SizeStat $res2)" ); + + INFO ( std::get < 0 > ( definition ) ); + TimeoutAqlTest ( 2s, qs ); + } + } +} diff --git a/alib2integrationtest/test-src/tests/glushkovRteTest.cpp b/alib2integrationtest/test-src/tests/glushkovRteTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..e5d9efef9239dc272f4b7f5d7b3ef3d1927c26c5 --- /dev/null +++ b/alib2integrationtest/test-src/tests/glushkovRteTest.cpp @@ -0,0 +1,45 @@ +#include <catch2/catch.hpp> +#include <memory> +#include <alib/vector> +#include <libgen.h> + +#include "testing/TimeoutAqlTest.hpp" +#include "testing/TestFiles.hpp" + +#include "glushkovRteTestGenerators.hpp" + +static size_t TESTCASES = 50; + +std::map < std::string, std::shared_ptr < TreeGenerator > > m_Generators = { + { "rte1.xml", std::make_shared < TreeGenerator1 > ( ) }, + { "rte2.xml", std::make_shared < TreeGenerator2 > ( ) }, + { "rte3.xml", std::make_shared < TreeGenerator3 > ( ) }, + { "rte4.xml", std::make_shared < TreeGenerator4 > ( ) }, + { "rte5.xml", std::make_shared < TreeGenerator5 > ( ) }, + { "rte6.xml", std::make_shared < TreeGenerator6 > ( ) }, + { "rte7.xml", std::make_shared < TreeGenerator7 > ( ) }, + { "rte8.xml", std::make_shared < TreeGenerator8 > ( ) }, + { "rte9.xml", std::make_shared < TreeGenerator9 > ( ) }, +}; + +TEST_CASE ( "GlushkovRTE", "[integration]" ) { + for ( const std::string & file : TestFiles::Get ( "/rte/rte[0-9]+.xml$" ) ) { + char * p_filepath = strdup ( file.c_str ( ) ); + std::string base = basename ( p_filepath ); // be careful, there are posix and gnu versions + free ( p_filepath ); + + try { + for ( size_t i = 0; i < TESTCASES; i++ ) { + ext::vector < std::string > qs = { + "execute < " + file + " | rte::convert::ToPostfixPushdownAutomatonGlushkov - | automaton::determinize::Determinize - > $pda", + "execute \"\\\"" + m_Generators.at ( base ) -> generate ( ) + "\\\"\" | string::Parse @string::String ^ - > $string", + "quit automaton::run::Accept $pda $string", + }; + + TimeoutAqlTest ( 5s, qs ); + } + } catch ( const std::out_of_range & ) { + FAIL ( "No generator assigned for file " << file ); + } + } +} diff --git a/alib2integrationtest/test-src/tests/glushkovRteTestGenerators.hpp b/alib2integrationtest/test-src/tests/glushkovRteTestGenerators.hpp new file mode 100644 index 0000000000000000000000000000000000000000..d2cdab1a4d35e6a5dc1d0cf7c4cd5e63f7addf9c --- /dev/null +++ b/alib2integrationtest/test-src/tests/glushkovRteTestGenerators.hpp @@ -0,0 +1,159 @@ +class TreeGenerator { + protected: + static size_t MAX_DEPTH; + static size_t MAX_LENGTH; + std::string m_Str; + + int randint ( int lo, int hi ) const { + return rand ( ) % ( hi - lo + 1 ) + lo; + } + + public: + std::string generate ( ) { + m_Str.clear ( ); + S ( ); + m_Str += "#$"; + return m_Str; + } + + private: + virtual void S ( size_t depth = 1 ) = 0; +}; + +size_t TreeGenerator::MAX_DEPTH = 200; +size_t TreeGenerator::MAX_LENGTH = 1000; + +/** Generator for rte1.xml */ +class TreeGenerator1 : public TreeGenerator { + private: + void S ( size_t depth = 1 ) { + m_Str += ( depth > MAX_DEPTH || randint ( 0, 1 ) == 0 ) ? "b " : "c "; + S2 ( depth + 1 ); + } + + void S2 ( size_t depth ) { + if ( depth > MAX_DEPTH || randint ( 0, 1 ) == 0 ) + return; + + m_Str += "b a d "; + S2 ( depth + 1 ); + } +}; + +/** Generator for rte2.xml */ +class TreeGenerator2 : public TreeGenerator { + private: + void S ( size_t /* depth = 1 */ ) { + m_Str += "b b a "; + } +}; + +/** Generator for rte3.xml */ +class TreeGenerator3 : public TreeGenerator { + private: + void S ( size_t depth = 1 ) { + if ( depth > MAX_DEPTH || randint ( 0, 1 ) == 0 ) { + m_Str += "b "; + return; + } + + S ( depth + 1 ); + S ( depth + 1 ); + m_Str += "a "; + } +}; + +/** Generator for rte4.xml */ +class TreeGenerator4 : public TreeGenerator { + private: + void S ( size_t depth = 1 ) { + if ( depth > MAX_DEPTH || randint ( 0, 1 ) == 0 ) { + m_Str += "b b a "; + return; + } + + S ( depth + 1 ); + S ( depth + 1 ); + m_Str += "a "; + } +}; + +/** Generator for rte5.xml */ +class TreeGenerator5 : public TreeGenerator { + private: + void S ( size_t /* depth = 1 */ ) { + m_Str += "a "; + } +}; + +/** Generator for rte6.xml */ +class TreeGenerator6 : public TreeGenerator { + private: + void S ( size_t depth = 1 ) { + SL ( depth + 1 ); + SR ( depth + 1 ); + m_Str += "a "; + } + + void SL ( size_t depth ) { + int r = randint ( 0, 1 ); + if ( r == 0 || depth > MAX_DEPTH ) + m_Str += "b "; + else if ( r == 1 ) + S ( depth + 1 ); + } + + void SR ( size_t depth ) { + int r = randint ( 0, 1 ); + if ( r == 0 || depth > MAX_DEPTH ) + m_Str += "c "; + else if ( r == 1 ) + S ( depth + 1 ); + } +}; + +/** Generator for rte7.xml */ +class TreeGenerator7 : public TreeGenerator { + private: + void S ( size_t depth = 1 ) { + m_Str += "c b a "; + S2 ( depth + 1 ); + } + + void S2 ( size_t depth ) { + if ( depth > MAX_DEPTH || randint ( 0, 2 ) == 0 ) + return; + + m_Str += "d "; + S2 ( depth + 1 ); + } +}; + +/** Generator for rte8.xml */ +class TreeGenerator8 : public TreeGenerator { + private: + void S ( size_t depth = 1 ) { + if ( depth > MAX_DEPTH || randint ( 0, 1 ) == 0 ) { + m_Str += std::string ( 1, 'b' + randint ( 0, 3 ) ) + ' '; + return; + } + + S ( depth + 1 ); + S ( depth + 1 ); + m_Str += "a "; + } +}; + +/** Generator for rte9.xml */ +class TreeGenerator9 : public TreeGenerator { + private: + void S ( size_t depth = 1 ) { + if ( depth > MAX_DEPTH || randint ( 0, 1 ) == 0 ) { + m_Str += "b "; + } else { + S ( depth + 1 ); + S ( depth + 1 ); + m_Str += "a "; + } + } +}; diff --git a/alib2integrationtest/test-src/tests/normalizeTest.cpp b/alib2integrationtest/test-src/tests/normalizeTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..5f9a28790d6784c63c2f7d9b5d216e55b75a4d0a --- /dev/null +++ b/alib2integrationtest/test-src/tests/normalizeTest.cpp @@ -0,0 +1,57 @@ +#include <catch2/catch.hpp> +#include <alib/vector> +#include <extensions/container/string.hpp> + +#include "testing/TimeoutAqlTest.hpp" +#include "testing/TestFiles.hpp" + +double RAND_DENSITY = 50; +size_t RAND_NONTERMINALS = 2; +size_t RAND_TERMINALS = 4; +size_t STRING_LENGTHS = 6; +size_t RANDOM_ITERATIONS = 50; + + +std::string qGenerateCfg ( const std::string & var ) { + std::ostringstream oss; + oss << "execute grammar::generate::RandomGrammarFactory" << " "; + oss << "(int) " << rand ( ) % RAND_NONTERMINALS + 1 << " "; + oss << "(int) " << rand ( ) % RAND_TERMINALS + 1 << " "; + oss << "(bool) true "; + oss << "(double) " << RAND_DENSITY << " | "; + oss << "grammar::simplify::EpsilonRemover - | "; + oss << "grammar::simplify::SimpleRulesRemover - > $" << var; + return oss.str(); +} + +TEST_CASE ( "Normalize test", "[integration]" ) { + auto algorithm = GENERATE ( as < std::string > ( ), "grammar::simplify::ToCNF", "grammar::simplify::ToGNF" ); + + SECTION ( "Test Files" ) { + for ( const std::string & file : TestFiles::Get ( "/grammar/anormalization.test.*.xml$" ) ) { + ext::vector < std::string > qs = { + "execute < " + file + " > $cfg", + "execute " + algorithm + " $cfg > $cfg2", + "execute grammar::generate::GenerateUpToLength $cfg " + ext::to_string ( STRING_LENGTHS ) + " > $str", + "execute grammar::generate::GenerateUpToLength $cfg2 " + ext::to_string ( STRING_LENGTHS ) + " > $str2", + "quit compare::TrieCompare $str $str2", + }; + + TimeoutAqlTest ( 1s, qs ); + } + } + + SECTION ( "Random tests" ) { + for ( size_t i = 0; i < RANDOM_ITERATIONS; i++ ) { + ext::vector < std::string > qs = { + qGenerateCfg ( "cfg" ), + "execute " + algorithm + " $cfg > $cfg2", + "execute grammar::generate::GenerateUpToLength $cfg " + ext::to_string ( STRING_LENGTHS ) + " > $str", + "execute grammar::generate::GenerateUpToLength $cfg2 " + ext::to_string ( STRING_LENGTHS ) + " > $str2", + "quit compare::TrieCompare $str $str2", + }; + + TimeoutAqlTest ( 1s, qs ); + } + } +} diff --git a/alib2integrationtest/test-src/tests/readerTest.cpp b/alib2integrationtest/test-src/tests/readerTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..86b032ff0f73cdc723e055da34225219f298d2c3 --- /dev/null +++ b/alib2integrationtest/test-src/tests/readerTest.cpp @@ -0,0 +1,35 @@ +#include <catch2/catch.hpp> +#include <alib/vector> + +#include "testing/TimeoutAqlTest.hpp" +#include "testing/TestFiles.hpp" + +TEST_CASE ( "ReaderTest | Xml", "[integration]" ) { + auto regexp = GENERATE ( as<std::string>(), "/automaton/.*.xml$", "/grammar/.*.xml$", "/regexp/.*.xml$", "/string/.*.xml$", "/rte/.*.xml$" ); + + for ( const std::string & file : TestFiles::Get ( regexp ) ) { + ext::vector < std::string > qs = { + "execute < " + file + " > $object", + "execute $object > /dev/null", + }; + + TimeoutAqlTest ( 1s, qs ); + } +} + +TEST_CASE ( "ReaderTest | Txt ", "[integration]" ) { + auto def = GENERATE ( + std::make_pair ( "automaton::Automaton", "/automaton/.*.txt$" ), + std::make_pair ( "regexp::RegExp", "/regexp/.*.txt$" ), + std::make_pair ( "grammar::Grammar", "/grammar/.*.txt$" ), + std::make_pair ( "string::String", "/string/.*.txt$" ) ); + + for ( const std::string & file : TestFiles::Get ( def.second ) ) { + ext::vector < std::string > qs = { + "execute cli::builtin::ReadFile " + file + " | string::Parse @" + def.first + " ^ - > $object", + "execute $object > /dev/null", + }; + + TimeoutAqlTest ( 1s, qs ); + } +} diff --git a/alib2integrationtest/test-src/tests/regexpDerivationIntegralTest.cpp b/alib2integrationtest/test-src/tests/regexpDerivationIntegralTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..7a06cca9fd5e233d29b42b1b4f2dd6530e849bf3 --- /dev/null +++ b/alib2integrationtest/test-src/tests/regexpDerivationIntegralTest.cpp @@ -0,0 +1,34 @@ +#include <catch2/catch.hpp> +#include <tuple> + +#include "testing/TimeoutAqlTest.hpp" +#include "testing/TestFiles.hpp" + +enum class Op { + DERIVATION, + INTEGRAL +}; + + +TEST_CASE ( "RegExp Derivation/Integral test", "[integration]" ) { + static const std::string mdfa = "regexp::convert::ToAutomatonGlushkov - | automaton::determinize::Determinize - | automaton::simplify::Trim - | automaton::simplify::Minimize - | automaton::simplify::Normalize -"; + + auto definition = GENERATE ( as < std::tuple < Op, std::string, std::string, std::string > > ( ), + std::make_tuple ( Op::DERIVATION, TestFiles::GetOne ( "/regexp/unbounded.oppa.4.13.xml$" ), TestFiles::GetOne ( "/regexp/unbounded.oppa.4.13.d0.xml$" ), "0" ), + std::make_tuple ( Op::DERIVATION, TestFiles::GetOne ( "/regexp/unbounded.oppa.4.13.xml$" ), TestFiles::GetOne ( "/regexp/unbounded.oppa.4.13.d00.xml$" ), "0 0" ), + std::make_tuple ( Op::DERIVATION, TestFiles::GetOne ( "/regexp/unbounded.oppa.4.14.xml$" ), TestFiles::GetOne ( "/regexp/unbounded.oppa.4.14.d1.xml$" ), "1" ), + std::make_tuple ( Op::DERIVATION, TestFiles::GetOne ( "/regexp/unbounded.oppa.4.14.xml$" ), TestFiles::GetOne ( "/regexp/unbounded.oppa.4.14.d10.xml$" ), "1 0" ), + std::make_tuple ( Op::DERIVATION, TestFiles::GetOne ( "/regexp/unbounded.oppa.4.15.xml$" ), TestFiles::GetOne ( "/regexp/unbounded.oppa.4.15.d100.xml$" ), "1 0 0" ), + std::make_tuple ( Op::INTEGRAL, TestFiles::GetOne ( "/regexp/unbounded.oppa.4.16.xml" ), TestFiles::GetOne ( "/regexp/unbounded.oppa.4.16.i1.xml" ), "1" ), + std::make_tuple ( Op::INTEGRAL, TestFiles::GetOne ( "/regexp/Melichar2-94.xml" ), TestFiles::GetOne ( "/regexp/Melichar2-94.i0.xml" ), "0" ), + std::make_tuple ( Op::INTEGRAL, TestFiles::GetOne ( "/regexp/Melichar2-94.xml" ), TestFiles::GetOne ( "/regexp/Melichar2-94.i1.xml" ), "1" ) ); + + ext::vector < std::string > qs = { + "execute < " + std::get < 1 > ( definition ) + " > $regexp", + "execute < " + std::get < 2 > ( definition ) + " > $result", + "execute \"\\\"" + std::get < 3 > ( definition ) + "\\\"\"" + " | string::Parse @string::String ^ - > $string", + "quit compare::AutomatonCompare <( $result | " + mdfa + " ) <( regexp::RegExp" + ( std::get < 0 > ( definition ) == Op::DERIVATION ? "Derivation" : "Integral" ) + " $regexp $string | " + mdfa + " )" + }; + + TimeoutAqlTest ( 1s, qs ); +} diff --git a/alib2integrationtest/test-src/tests/treeNotationTest.cpp b/alib2integrationtest/test-src/tests/treeNotationTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..096c3cb2e877e20e2d7e8f3e7f2c446ec6e243ad --- /dev/null +++ b/alib2integrationtest/test-src/tests/treeNotationTest.cpp @@ -0,0 +1,44 @@ +#include <catch2/catch.hpp> +#include <alib/vector> + +#include "testing/TimeoutAqlTest.hpp" +#include "testing/TestFiles.hpp" + +const size_t SIZE = 100; +const size_t HEIGHT = 15; +const size_t ALPHABET_SIZE = 10; +const size_t RANDOM_ITERATIONS = 15; + + +TEST_CASE ( "TreeNotation tests | Files", "[integration]" ) { + auto casts = GENERATE ( as < std::string > ( ), "(PostfixRankedTree)" ); + + SECTION ( "Test files" ) { + for ( const std::string & file : TestFiles::Get ( "/tree/repeats.*.xml" ) ) { + ext::vector < std::string > qs = { + "execute < " + file + " > $res1", + "execute (RankedTree)" + casts + "$res1 > $res2", + "quit compare::TreeCompare $res1 $res2", + }; + + TimeoutAqlTest ( 1s, qs ); + } + } + + SECTION ( "Random tests" ) { + std::ostringstream oss; + oss << "execute tree::generate::RandomRankedTreeFactory "; + oss << HEIGHT << " " << SIZE << " " << ( rand ( ) % ALPHABET_SIZE + 1 ); + oss << " (bool)true 5 > $res1"; + + for ( size_t i = 0; i < RANDOM_ITERATIONS; i++ ) { + ext::vector < std::string > qs = { + oss.str ( ), + "execute (RankedTree)" + casts + "$res1 > $res2", + "quit compare::TreeCompare $res1 $res2", + }; + + TimeoutAqlTest ( 2s, qs ); + } + } +} diff --git a/alib2integrationtest/test-src/tests/treeRepeatsTest.cpp b/alib2integrationtest/test-src/tests/treeRepeatsTest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..35a3b9e7009d9d773c030cb9c7c50a11ba52b48e --- /dev/null +++ b/alib2integrationtest/test-src/tests/treeRepeatsTest.cpp @@ -0,0 +1,45 @@ +#include <catch2/catch.hpp> +#include <alib/vector> +#include <extensions/container/string.hpp> + +#include "testing/TimeoutAqlTest.hpp" +#include "testing/TestFiles.hpp" + +const size_t SIZE = 100; +const size_t HEIGHT = 15; +const size_t ALPHABET_SIZE = 10; +const size_t RANDOM_ITERATIONS = 15; + +TEST_CASE ( "TreeRepeats", "[integration]" ) { + auto pipeline = GENERATE ( as < std::string > ( ), + "arbology::properties::ExactSubtreeRepeatsFromSubtreeAutomaton (PrefixRankedTree)$tree | tree::NormalizeTreeLabels (RankedTree) -", + "tree::properties::ExactSubtreeRepeatsNaive (PostfixRankedTree)$tree | tree::NormalizeTreeLabels (RankedTree) -", + "tree::properties::ExactSubtreeRepeatsNaive (PostfixRankedTree)$tree | tree::NormalizeTreeLabels (RankedTree) -" ); + + + SECTION ( "Test Files" ) { + for ( const std::string & file : TestFiles::Get ( "/tree/repeats.*.xml" ) ) { + ext::vector < std::string > qs = { + "execute < " + file + " > $tree", + "execute tree::properties::ExactSubtreeRepeatsNaive $tree | tree::NormalizeTreeLabels - > $res1", // naive + "execute " + pipeline + " > $res2", + "quit compare::TreeCompare $res1 $res2", + }; + + TimeoutAqlTest ( 2s, qs ); + } + } + + SECTION ( "Random tests" ) { + for ( size_t i = 0; i < RANDOM_ITERATIONS; i++ ) { + ext::vector < std::string > qs = { + "execute tree::generate::RandomRankedTreeFactory " + ext::to_string ( HEIGHT ) + " " + ext::to_string ( SIZE ) + " " + ext::to_string ( rand ( ) % ALPHABET_SIZE + 1 ) + " (bool)true 5 > $tree", + "execute tree::properties::ExactSubtreeRepeatsNaive $tree | tree::NormalizeTreeLabels - > $res1", // naive + "execute " + pipeline + " > $res2", + "quit compare::TreeCompare $res1 $res2", + }; + + TimeoutAqlTest ( 2s, qs ); + } + } +}