/* retoor <retoor@molodetz.nl> */
#include "../include/lorex.h"
#include <stdio.h>
#include <string.h>
#include <time.h>
static int total_passed = 0;
static int total_failed = 0;
#define ASSERT(cond, msg) do { \
if (!(cond)) { \
printf(" FAIL: %s\n", msg); \
total_failed++; \
return; \
} \
} while(0)
#define TEST(name) static void test_##name(void)
#define RUN(name) do { \
test_##name(); \
total_passed++; \
} while(0)
TEST(basic_literals) {
lorex_error_t err;
lorex_regex_t *re = lorex_compile("hello", &err);
ASSERT(re != NULL, "compile hello");
lorex_match_t m;
ASSERT(lorex_search(re, "hello", &m), "match hello");
ASSERT(lorex_search(re, "say hello world", &m), "search hello");
ASSERT(!lorex_search(re, "helo", &m), "no match helo");
lorex_free(re);
}
TEST(metacharacters) {
lorex_error_t err;
lorex_match_t m;
lorex_regex_t *re = lorex_compile("a.c", &err);
ASSERT(re != NULL, "compile a.c");
ASSERT(lorex_search(re, "abc", &m), "match abc");
ASSERT(lorex_search(re, "axc", &m), "match axc");
ASSERT(!lorex_search(re, "ac", &m), "no match ac");
lorex_free(re);
re = lorex_compile("^start", &err);
ASSERT(re != NULL, "compile ^start");
ASSERT(lorex_search(re, "start here", &m), "match start here");
ASSERT(!lorex_search(re, "not start", &m), "no match not start");
lorex_free(re);
re = lorex_compile("end$", &err);
ASSERT(re != NULL, "compile end$");
ASSERT(lorex_search(re, "the end", &m), "match the end");
ASSERT(!lorex_search(re, "end here", &m), "no match end here");
lorex_free(re);
}
TEST(quantifiers) {
lorex_error_t err;
lorex_match_t m;
lorex_regex_t *re = lorex_compile("ab*c", &err);
ASSERT(re != NULL, "compile ab*c");
ASSERT(lorex_search(re, "ac", &m), "match ac");
ASSERT(lorex_search(re, "abc", &m), "match abc");
ASSERT(lorex_search(re, "abbbbc", &m), "match abbbbc");
lorex_free(re);
re = lorex_compile("ab+c", &err);
ASSERT(re != NULL, "compile ab+c");
ASSERT(!lorex_search(re, "ac", &m), "no match ac");
ASSERT(lorex_search(re, "abc", &m), "match abc");
ASSERT(lorex_search(re, "abbbbc", &m), "match abbbbc");
lorex_free(re);
re = lorex_compile("ab?c", &err);
ASSERT(re != NULL, "compile ab?c");
ASSERT(lorex_search(re, "ac", &m), "match ac");
ASSERT(lorex_search(re, "abc", &m), "match abc");
ASSERT(!lorex_search(re, "abbc", &m), "no match abbc");
lorex_free(re);
re = lorex_compile("a{3}", &err);
ASSERT(re != NULL, "compile a{3}");
ASSERT(lorex_search(re, "aaa", &m), "match aaa");
ASSERT(!lorex_search(re, "aa", &m), "no match aa");
lorex_free(re);
re = lorex_compile("a{2,4}", &err);
ASSERT(re != NULL, "compile a{2,4}");
ASSERT(lorex_search(re, "aa", &m), "match aa");
ASSERT(lorex_search(re, "aaa", &m), "match aaa");
ASSERT(lorex_search(re, "aaaa", &m), "match aaaa");
ASSERT(!lorex_search(re, "a", &m), "no match a");
lorex_free(re);
}
TEST(character_classes) {
lorex_error_t err;
lorex_match_t m;
lorex_regex_t *re = lorex_compile("[aeiou]", &err);
ASSERT(re != NULL, "compile [aeiou]");
ASSERT(lorex_search(re, "a", &m), "match a");
ASSERT(lorex_search(re, "test", &m), "match test");
ASSERT(!lorex_search(re, "xyz", &m), "no match xyz");
lorex_free(re);
re = lorex_compile("[a-z]", &err);
ASSERT(re != NULL, "compile [a-z]");
ASSERT(lorex_search(re, "m", &m), "match m");
ASSERT(!lorex_search(re, "5", &m), "no match 5");
lorex_free(re);
re = lorex_compile("[^0-9]", &err);
ASSERT(re != NULL, "compile [^0-9]");
ASSERT(lorex_search(re, "a", &m), "match a");
ASSERT(!lorex_search(re, "5", &m), "no match 5");
lorex_free(re);
re = lorex_compile("\\d", &err);
ASSERT(re != NULL, "compile \\d");
ASSERT(lorex_search(re, "5", &m), "match 5");
ASSERT(!lorex_search(re, "a", &m), "no match a");
lorex_free(re);
re = lorex_compile("\\w+", &err);
ASSERT(re != NULL, "compile \\w+");
ASSERT(lorex_search(re, "hello_123", &m), "match hello_123");
lorex_free(re);
re = lorex_compile("\\s", &err);
ASSERT(re != NULL, "compile \\s");
ASSERT(lorex_search(re, " ", &m), "match space");
ASSERT(lorex_search(re, "\t", &m), "match tab");
ASSERT(!lorex_search(re, "a", &m), "no match a");
lorex_free(re);
}
TEST(groups) {
lorex_error_t err;
lorex_match_t m;
lorex_regex_t *re = lorex_compile("(ab)+", &err);
ASSERT(re != NULL, "compile (ab)+");
ASSERT(lorex_search(re, "ab", &m), "match ab");
ASSERT(lorex_search(re, "abab", &m), "match abab");
ASSERT(!lorex_search(re, "a", &m), "no match a");
lorex_free(re);
re = lorex_compile("(\\d+)-(\\d+)", &err);
ASSERT(re != NULL, "compile groups");
ASSERT(lorex_search(re, "123-456", &m), "match 123-456");
ASSERT(m.group_count == 2, "2 groups");
ASSERT(m.groups[0].matched, "group 0 matched");
ASSERT(m.groups[1].matched, "group 1 matched");
lorex_free(re);
}
TEST(alternation) {
lorex_error_t err;
lorex_match_t m;
lorex_regex_t *re = lorex_compile("cat|dog", &err);
ASSERT(re != NULL, "compile cat|dog");
ASSERT(lorex_search(re, "cat", &m), "match cat");
ASSERT(lorex_search(re, "dog", &m), "match dog");
ASSERT(!lorex_search(re, "rat", &m), "no match rat");
lorex_free(re);
re = lorex_compile("(red|blue) car", &err);
ASSERT(re != NULL, "compile (red|blue) car");
ASSERT(lorex_search(re, "red car", &m), "match red car");
ASSERT(lorex_search(re, "blue car", &m), "match blue car");
ASSERT(!lorex_search(re, "green car", &m), "no match green car");
lorex_free(re);
}
TEST(escapes) {
lorex_error_t err;
lorex_match_t m;
lorex_regex_t *re = lorex_compile("1\\.5", &err);
ASSERT(re != NULL, "compile 1\\.5");
ASSERT(lorex_search(re, "1.5", &m), "match 1.5");
ASSERT(!lorex_search(re, "1x5", &m), "no match 1x5");
lorex_free(re);
re = lorex_compile("\\(test\\)", &err);
ASSERT(re != NULL, "compile \\(test\\)");
ASSERT(lorex_search(re, "(test)", &m), "match (test)");
lorex_free(re);
}
TEST(real_patterns) {
lorex_error_t err;
lorex_match_t m;
lorex_regex_t *re = lorex_compile("[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}", &err);
ASSERT(re != NULL, "compile email");
ASSERT(lorex_search(re, "user@example.com", &m), "match email");
ASSERT(!lorex_search(re, "invalid", &m), "no match invalid");
lorex_free(re);
re = lorex_compile("\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}", &err);
ASSERT(re != NULL, "compile ip");
ASSERT(lorex_search(re, "192.168.1.1", &m), "match ip");
lorex_free(re);
re = lorex_compile("https?://[a-zA-Z0-9.-]+(/[a-zA-Z0-9./-]*)?", &err);
ASSERT(re != NULL, "compile url");
ASSERT(lorex_search(re, "http://example.com", &m), "match http");
ASSERT(lorex_search(re, "https://example.com/path", &m), "match https");
lorex_free(re);
}
TEST(error_handling) {
lorex_error_t err;
lorex_regex_t *re = lorex_compile("(abc", &err);
ASSERT(re == NULL, "unbalanced paren");
ASSERT(err == LOREX_ERR_UNBALANCED_PAREN, "correct error");
}
int main(void) {
printf("lorex comprehensive tests\n");
printf("========================\n\n");
clock_t start = clock();
RUN(basic_literals);
RUN(metacharacters);
RUN(quantifiers);
RUN(character_classes);
RUN(groups);
RUN(alternation);
RUN(escapes);
RUN(real_patterns);
RUN(error_handling);
clock_t end = clock();
double elapsed = (double)(end - start) / CLOCKS_PER_SEC;
printf("\n========================\n");
printf("passed: %d, failed: %d\n", total_passed, total_failed);
printf("time: %.3f seconds\n", elapsed);
return total_failed > 0 ? 1 : 0;
}