#include "../src/regex/regex.h"

#include <assert.h>
#include <stdlib.h>

void testLifetime(void)
{
	allocator_t allocator;
	Allocator_CreateSystemAllocator(&allocator);
	Regex regex;
	Regex_Create(&regex, &allocator);


	Regex_Destroy(&regex);
	assert(allocator.reserved == 0);
	Allocator_DestroySystemAllocator(&allocator);
	return;
}

void testLiteral(void)
{
	StringView test_string_0 = StringView_FromString("Hello World");
	allocator_t allocator;
	Allocator_CreateSystemAllocator(&allocator);
	Regex regex;
	assert(Regex_Create(&regex, &allocator) == EXIT_SUCCESS);

	assert(Regex_Compile(&regex, test_string_0) == EXIT_SUCCESS);

	RegexMatch match;
	assert(Regex_FirstMatch(&regex, test_string_0, &match) == EXIT_SUCCESS);
	assert(StringView_Equal(match.match, test_string_0));

	RegexMatch_Destroy(&match);

	Regex_Destroy(&regex);
	assert(allocator.reserved == 0);
	Allocator_DestroySystemAllocator(&allocator);
	return;
}

void testBackslash(void)
{
	StringView regex_string = StringView_FromString("Hello World\\\\");
	StringView match_string = StringView_FromString("Hello World\\");
	allocator_t allocator;
	Allocator_CreateSystemAllocator(&allocator);
	Regex regex;
	assert(Regex_Create(&regex, &allocator) == EXIT_SUCCESS);

	assert(Regex_Compile(&regex, regex_string) == EXIT_SUCCESS);

	RegexMatch match;
	assert(Regex_FirstMatch(&regex, match_string, &match) == EXIT_SUCCESS);
	assert(StringView_Equal(match.match, match_string));

	RegexMatch_Destroy(&match);

	Regex_Destroy(&regex);
	assert(allocator.reserved == 0);
	Allocator_DestroySystemAllocator(&allocator);
	return;
}

void testGroup(void)
{
	StringView regex_string = StringView_FromString("(Hello) (World)");
	StringView match_string = StringView_FromString("Hello World");
	allocator_t allocator;
	Allocator_CreateSystemAllocator(&allocator);
	Regex regex;
	assert(Regex_Create(&regex, &allocator) == EXIT_SUCCESS);

	assert(Regex_Compile(&regex, regex_string) == EXIT_SUCCESS);

	RegexMatch match;
	assert(Regex_FirstMatch(&regex, match_string, &match) == EXIT_SUCCESS);
	assert(StringView_Equal(match.match, match_string));
	assert(RegexMatch_HaveNumberedCapture(&match, 1));
	assert(RegexMatch_HaveNumberedCapture(&match, 2));

	Regex_Destroy(&regex);
	RegexMatch_Destroy(&match);
	assert(allocator.reserved == 0);
	Allocator_DestroySystemAllocator(&allocator);
	return;
}

void testOption(void)
{
	StringView regex_string = StringView_FromString("abc|def|");
	StringView match_string_0 = StringView_FromString("abc");
	StringView match_string_1 = StringView_FromString("def");
	StringView match_string_2 = StringView_FromString("");
	allocator_t allocator;
	Allocator_CreateSystemAllocator(&allocator);

	Regex regex;
	assert(Regex_Create(&regex, &allocator) == EXIT_SUCCESS);

	assert(Regex_Compile(&regex, regex_string) == EXIT_SUCCESS);

	RegexMatch match;

	assert(Regex_FirstMatch(&regex, match_string_0, &match) == EXIT_SUCCESS);
	assert(StringView_Equal(match.match, match_string_0));

	assert(Regex_FirstMatch(&regex, match_string_1, &match) == EXIT_SUCCESS);
	assert(StringView_Equal(match.match, match_string_1));

	assert(Regex_FirstMatch(&regex, match_string_2, &match) == EXIT_SUCCESS);
	assert(StringView_Equal(match.match, match_string_2));

	Regex_Destroy(&regex);
	assert(allocator.reserved == 0);
	Allocator_DestroySystemAllocator(&allocator);
	return;
}

void testQuantifier(void)
{
	StringView regex_string = StringView_FromString("\\??");
	StringView match_string_0 = StringView_FromString("?");
	StringView match_string_1 = StringView_FromString("");
	allocator_t allocator;
	Allocator_CreateSystemAllocator(&allocator);

	Regex regex;
	assert(Regex_Create(&regex, &allocator) == EXIT_SUCCESS);

	assert(Regex_Compile(&regex, regex_string) == EXIT_SUCCESS);

	RegexMatch match;

	assert(Regex_FirstMatch(&regex, match_string_0, &match) == EXIT_SUCCESS);
	assert(StringView_Equal(match.match, match_string_0));

	assert(Regex_FirstMatch(&regex, match_string_1, &match) == EXIT_SUCCESS);
	assert(StringView_Equal(match.match, match_string_1));

	Regex_Destroy(&regex);
	assert(allocator.reserved == 0);
	Allocator_DestroySystemAllocator(&allocator);
	return;
}

int main()
{
	testLifetime();
	testLiteral();
	testBackslash();
	testGroup();
	testOption();
	testQuantifier();
	return 0;
}