#include "pch.h"

#include <Regex.h>

#include "CppUnitTest.h"

using namespace Microsoft::VisualStudio::CppUnitTestFramework;

namespace FrameworkTests
{
    TEST_CLASS (RegexTests)
    {
        TEST_METHOD (MatchTest1)
        {
            auto parser = Framework::Regex::parse("ab+(c{3,6})?|b(a)");
            auto result = parser->match("abccccab", (int)strlen("abccccab"));
            Assert::IsTrue(result->getEntryCount() == 2,
                L"Invalid result count while matching 'abccccab' against "
                L"'ab+(c{3,6})?|b(a)'");
            auto* first = result->z(0);
            auto* second = result->z(1);
            Assert::IsTrue(first->getStart() == 0 && first->getEnd() == 6,
                L"Invalid first result while matching 'abccccab' against "
                L"'ab+(c{3,6})?|b(a)'");
            Assert::IsTrue(first->getGroup(1).getStart() == 2
                               && first->getGroup(1).getEnd() == 6,
                L"Invalid group 1 in result 1 while matching 'abccccab' "
                L"against "
                L"'ab+(c{3,6})?|b(a)'");
            Assert::IsTrue(first->getGroupCount() == 2,
                L"Invalid group count in result 1 while matching 'abccccab' "
                L"against "
                L"'ab+(c{3,6})?|b(a)'");
            Assert::IsTrue(second->getStart() == 6 && second->getEnd() == 8,
                L"Invalid second result while matching 'abccccab' against "
                L"'ab+(c{3,6})?|b(a)'");
            Assert::IsTrue(second->getGroupCount() == 1,
                L"Invalid group count in result 2 while matching 'abccccab' "
                L"against "
                L"'ab+(c{3,6})?|b(a)'");
            result->release();
            parser->release();
        }

        TEST_METHOD (MatchTest2)
        {
            auto parser = Framework::Regex::parse("abc");
            auto result
                = parser->match(" aabc abcc", (int)strlen(" aabc abcc"));
            Assert::IsTrue(result->getEntryCount() == 2,
                L"Invalid result count while matching ' aabc abcc' against "
                L"'abc'");
            auto* first = result->z(0);
            auto* second = result->z(1);
            Assert::IsTrue(first->getStart() == 2 && first->getEnd() == 5,
                L"Invalid first result while matching ' aabc abcc' against "
                L"'abc'");
            Assert::IsTrue(first->getGroupCount() == 1,
                L"Invalid group count in result 1 while matching ' aabc abcc' "
                L"against "
                L"'abc'");
            Assert::IsTrue(second->getStart() == 6 && second->getEnd() == 9,
                L"Invalid second result while matching ' aabc abcc' against "
                L"'abc'");
            Assert::IsTrue(second->getGroupCount() == 1,
                L"Invalid group count in result 2 while matching ' aabc abcc' "
                L"against "
                L"'abc'");
            result->release();
            parser->release();
        }

        TEST_METHOD (MatchTest3)
        {
            auto parser = Framework::Regex::parse("(?:abc)*");
            auto result = parser->match("_aabcabcc", (int)strlen(" aabcabcc"));
            Assert::IsTrue(result->getEntryCount() == 5,
                L"Invalid result count while matching '_aabcabcc' against "
                L"'(?:abc)*'");
            auto* first = result->z(0);
            auto* second = result->z(1);
            auto* third = result->z(2);
            auto* forth = result->z(3);
            auto* fifth = result->z(4);
            Assert::IsTrue(first->getStart() == 0 && first->getEnd() == 0,
                L"Invalid first result while matching '_aabcabcc' against "
                L"'(?:abc)*'");
            Assert::IsTrue(first->getGroupCount() == 1,
                L"Invalid group count in result 1 while matching '_aabcabcc' "
                L"against "
                L"'(?:abc)*'");
            Assert::IsTrue(second->getStart() == 1 && second->getEnd() == 1,
                L"Invalid second result while matching '_aabcabcc' against "
                L"'(?:abc)*'");
            Assert::IsTrue(second->getGroupCount() == 1,
                L"Invalid group count in result 2 while matching '_aabcabcc' "
                L"against "
                L"'(?:abc)*'");
            Assert::IsTrue(third->getStart() == 2 && third->getEnd() == 8,
                L"Invalid third result while matching '_aabcabcc' against "
                L"'(?:abc)*'");
            Assert::IsTrue(third->getGroupCount() == 1,
                L"Invalid group count in result 3 while matching '_aabcabcc' "
                L"against "
                L"'(?:abc)*'");
            Assert::IsTrue(forth->getStart() == 8 && forth->getEnd() == 8,
                L"Invalid result 4 while matching '_aabcabcc' against "
                L"'(?:abc)*'");
            Assert::IsTrue(forth->getGroupCount() == 1,
                L"Invalid group count in result 4 while matching '_aabcabcc' "
                L"against "
                L"'(?:abc)*'");
            Assert::IsTrue(fifth->getStart() == 9 && fifth->getEnd() == 9,
                L"Invalid result 5 while matching '_aabcabcc' against "
                L"'(?:abc)*'");
            Assert::IsTrue(fifth->getGroupCount() == 1,
                L"Invalid group count in result 5 while matching '_aabcabcc' "
                L"against "
                L"'(?:abc)*'");
            result->release();
            parser->release();
        }

        TEST_METHOD (MatchTest4)
        {
            auto parser = Framework::Regex::parse("(?:abc)*?");
            auto result = parser->match("_aabcabcc", (int)strlen(" aabcabcc"));
            Assert::IsTrue(result->getEntryCount() == 8,
                L"Invalid result count while matching '_aabcabcc' against "
                L"'(?:abc)*?'");
            auto* _0 = result->z(0);
            auto* _1 = result->z(1);
            auto* _2 = result->z(2);
            auto* _3 = result->z(3);
            auto* _4 = result->z(4);
            auto* _5 = result->z(5);
            auto* _6 = result->z(6);
            auto* _7 = result->z(7);
            Assert::IsTrue(_0->getStart() == 0 && _0->getEnd() == 0,
                L"Invalid result 1 while matching '_aabcabcc' against "
                L"'(?:abc)*?'");
            Assert::IsTrue(_0->getGroupCount() == 1,
                L"Invalid group count in result 1 while matching '_aabcabcc' "
                L"against "
                L"'(?:abc)*?'");
            Assert::IsTrue(_1->getStart() == 1 && _1->getEnd() == 1,
                L"Invalid result 2 while matching '_aabcabcc' against "
                L"'(?:abc)*?'");
            Assert::IsTrue(_1->getGroupCount() == 1,
                L"Invalid group count in result 2 while matching '_aabcabcc' "
                L"against "
                L"'(?:abc)*?'");
            Assert::IsTrue(_2->getStart() == 2 && _2->getEnd() == 2,
                L"Invalid result 3 while matching '_aabcabcc' against "
                L"'(?:abc)*?'");
            Assert::IsTrue(_2->getGroupCount() == 1,
                L"Invalid group count in result 3 while matching '_aabcabcc' "
                L"against "
                L"'(?:abc)*?'");
            Assert::IsTrue(_3->getStart() == 2 && _3->getEnd() == 5,
                L"Invalid result 4 while matching '_aabcabcc' against "
                L"'(?:abc)*?'");
            Assert::IsTrue(_3->getGroupCount() == 1,
                L"Invalid group count in result 4 while matching '_aabcabcc' "
                L"against "
                L"'(?:abc)*'");
            Assert::IsTrue(_4->getStart() == 5 && _4->getEnd() == 5,
                L"Invalid result 5 while matching '_aabcabcc' against "
                L"'(?:abc)*?'");
            Assert::IsTrue(_4->getGroupCount() == 1,
                L"Invalid group count in result 5 while matching '_aabcabcc' "
                L"against "
                L"'(?:abc)*'");
            Assert::IsTrue(_5->getStart() == 5 && _5->getEnd() == 8,
                L"Invalid result 6 while matching '_aabcabcc' against "
                L"'(?:abc)*?'");
            Assert::IsTrue(_5->getGroupCount() == 1,
                L"Invalid group count in result 6 while matching '_aabcabcc' "
                L"against "
                L"'(?:abc)*'");
            Assert::IsTrue(_6->getStart() == 8 && _6->getEnd() == 8,
                L"Invalid result 7 while matching '_aabcabcc' against "
                L"'(?:abc)*?'");
            Assert::IsTrue(_6->getGroupCount() == 1,
                L"Invalid group count in result 7 while matching '_aabcabcc' "
                L"against "
                L"'(?:abc)*'");
            Assert::IsTrue(_7->getStart() == 9 && _7->getEnd() == 9,
                L"Invalid result 8 while matching '_aabcabcc' against "
                L"'(?:abc)*?'");
            Assert::IsTrue(_7->getGroupCount() == 1,
                L"Invalid group count in result 8 while matching '_aabcabcc' "
                L"against "
                L"'(?:abc)*?'");
            result->release();
            parser->release();
        }

        TEST_METHOD (MatchTest5)
        {
            auto parser = Framework::Regex::parse("(a|b)+");
            auto result
                = parser->match("cabaccccbab", (int)strlen("cabaccccbab"));
            Assert::IsTrue(result->getEntryCount() == 2,
                L"Invalid result count while matching 'cabaccccbab' against "
                L"'a|b'");
            auto* first = result->z(0);
            auto* second = result->z(1);
            Assert::IsTrue(first->getStart() == 1 && first->getEnd() == 4,
                L"Invalid first result while matching 'cabaccccbab' against "
                L"'a|b'");
            Assert::IsTrue(first->getGroupCount() == 2,
                L"Invalid group count in result 1 while matching 'cabaccccbab' "
                L"against "
                L"'a|b'");
            Assert::IsTrue(first->getGroup(1).getStart() == 3
                               && first->getGroup(1).getEnd() == 4,
                L"Invalid group 1 in result 1 while matching 'cabaccccbab' "
                L"against "
                L"'a|b'");
            Assert::IsTrue(second->getStart() == 8 && second->getEnd() == 11,
                L"Invalid second result while matching 'cabaccccbab' against "
                L"'a|b'");
            Assert::IsTrue(second->getGroupCount() == 2,
                L"Invalid group count in result 2 while matching 'cabaccccbab' "
                L"against "
                L"'a|b'");
            Assert::IsTrue(second->getGroup(1).getStart() == 10
                               && second->getGroup(1).getEnd() == 11,
                L"Invalid group 1 in result 2 while matching 'cabaccccbab' "
                L"against "
                L"'a|b'");
            result->release();
            parser->release();
        }

        TEST_METHOD (MatchTest6)
        {
            auto parser = Framework::Regex::parse("(?:^|c)ab");
            auto result = parser->match("abcabcasd", (int)strlen("abcabcasd"));
            Assert::IsTrue(result->getEntryCount() == 2,
                L"Invalid result count while matching 'abcabcasd' against "
                L"'(?:^|c)ab'");
            auto* first = result->z(0);
            auto* second = result->z(1);
            Assert::IsTrue(first->getStart() == 0 && first->getEnd() == 2,
                L"Invalid first result while matching 'abcabcasd' against "
                L"'(?:^|c)ab'");
            Assert::IsTrue(first->getGroupCount() == 1,
                L"Invalid group count in result 1 while matching 'abcabcasd' "
                L"against "
                L"'(?:^|c)ab'");
            Assert::IsTrue(second->getStart() == 2 && second->getEnd() == 5,
                L"Invalid second result while matching 'abcabcasd' against "
                L"'(?:^|c)ab'");
            Assert::IsTrue(second->getGroupCount() == 1,
                L"Invalid group count in result 2 while matching 'abcabcasd' "
                L"against "
                L"'(?:^|c)ab'");
            result->release();
            parser->release();
        }

        TEST_METHOD (MatchTestComplexity)
        {
            Framework::Text regex = "";
            Framework::Text str = "";
            for (int i = 0; i < 20; ++i)
            {
                regex += "a?";
                str += "a";
            }
            for (int i = 0; i < 20; ++i)
            {
                regex += "a";
            }
            auto parser = Framework::Regex::parse(regex);
            auto result = parser->match(str, str.getLength());
            Assert::IsTrue(result->getEntryCount() == 1,
                L"Invalid result count while matching 'a^20' against "
                L"a?^20a^20");
            auto* first = result->z(0);
            Assert::IsTrue(first->getStart() == 0 && first->getEnd() == 20,
                L"Invalid first result while matching 'a^20' against "
                L"'a?^20a^20'");
            result->release();
            parser->release();
        }

        TEST_METHOD (TestNumber0)
        {
            auto parser = Framework::Regex::parse("^[0-9]+$");
            auto* results = parser->match("0", 1);
            bool ok = results->getEntryCount() == 1;
            results->release();
            parser->release();
            Assert::IsTrue(
                ok, L"no result found while matcging '0' against '^[0-9]+$'");
        }

        TEST_METHOD (TestNumber1)
        {
            auto parser = Framework::Regex::parse("^[0-9]+(\\.[0-9]+)?$");
            auto* results = parser->match("0", 1);
            bool ok = results->getEntryCount() == 1;
            results->release();
            parser->release();
            Assert::IsTrue(ok,
                L"no result found while matcging '0' against "
                L"'^[0-9]+(\\.[0-9]+)?$'");
        }

        TEST_METHOD (TestNumber2)
        {
            auto parser = Framework::Regex::parse(
                "^[0-9]+(\\.[0-9]+)?([eE][+-]?[0-9]+)?$");
            auto* results = parser->match("0", 1);
            bool ok = results->getEntryCount() == 1;
            results->release();
            parser->release();
            Assert::IsTrue(ok,
                L"no result found while matcging '0' against "
                L"'^[0-9]+(\\.[0-9]+)?([eE][+-]?[0-9]+)?$'");
        }

        TEST_METHOD (TestNumber3)
        {
            auto parser = Framework::Regex::parse(
                "^[0-9]+(\\.[0-9]+)?([eE][+-]?[0-9]+)?$");
            auto* results = parser->match("1e-3", 1);
            bool ok = results->getEntryCount() == 1;
            results->release();
            parser->release();
            Assert::IsTrue(ok,
                L"no result found while matcging '1e-3' against "
                L"'^[0-9]+(\\.[0-9]+)?([eE][+-]?[0-9]+)?$'");
        }
    };
} // namespace FrameworkTests