|
/* retoor <retoor@molodetz.nl> */
|
|
#include "../include/lorex.h"
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
|
|
static int tests_passed = 0;
|
|
static int tests_failed = 0;
|
|
|
|
#define TEST(name) static void test_##name(void)
|
|
#define RUN_TEST(name) do { \
|
|
printf(" %s... ", #name); \
|
|
test_##name(); \
|
|
printf("ok\n"); \
|
|
tests_passed++; \
|
|
} while(0)
|
|
|
|
#define ASSERT(cond) do { \
|
|
if (!(cond)) { \
|
|
printf("FAILED at line %d: %s\n", __LINE__, #cond); \
|
|
tests_failed++; \
|
|
return; \
|
|
} \
|
|
} while(0)
|
|
|
|
#define ASSERT_MATCH(pattern, text) do { \
|
|
lorex_error_t err; \
|
|
lorex_regex_t *re = lorex_compile(pattern, &err); \
|
|
ASSERT(re != NULL); \
|
|
lorex_match_t result; \
|
|
ASSERT(lorex_search(re, text, &result) == true); \
|
|
lorex_free(re); \
|
|
} while(0)
|
|
|
|
#define ASSERT_NO_MATCH(pattern, text) do { \
|
|
lorex_error_t err; \
|
|
lorex_regex_t *re = lorex_compile(pattern, &err); \
|
|
ASSERT(re != NULL); \
|
|
lorex_match_t result; \
|
|
ASSERT(lorex_search(re, text, &result) == false); \
|
|
lorex_free(re); \
|
|
} while(0)
|
|
|
|
TEST(simple_char) {
|
|
ASSERT_MATCH("a", "a");
|
|
ASSERT_MATCH("a", "bab");
|
|
ASSERT_NO_MATCH("a", "bcd");
|
|
}
|
|
|
|
TEST(concat) {
|
|
ASSERT_MATCH("ab", "ab");
|
|
ASSERT_MATCH("ab", "xaby");
|
|
ASSERT_NO_MATCH("ab", "ba");
|
|
}
|
|
|
|
TEST(alternation) {
|
|
ASSERT_MATCH("a|b", "a");
|
|
ASSERT_MATCH("a|b", "b");
|
|
ASSERT_MATCH("cat|dog", "cat");
|
|
ASSERT_MATCH("cat|dog", "dog");
|
|
ASSERT_NO_MATCH("cat|dog", "rat");
|
|
}
|
|
|
|
TEST(star) {
|
|
ASSERT_MATCH("a*", "");
|
|
ASSERT_MATCH("a*", "a");
|
|
ASSERT_MATCH("a*", "aaa");
|
|
ASSERT_MATCH("a*b", "b");
|
|
ASSERT_MATCH("a*b", "ab");
|
|
ASSERT_MATCH("a*b", "aaab");
|
|
}
|
|
|
|
TEST(plus) {
|
|
ASSERT_NO_MATCH("a+", "");
|
|
ASSERT_MATCH("a+", "a");
|
|
ASSERT_MATCH("a+", "aaa");
|
|
ASSERT_MATCH("a+b", "ab");
|
|
ASSERT_MATCH("a+b", "aaab");
|
|
}
|
|
|
|
TEST(question) {
|
|
ASSERT_MATCH("a?", "");
|
|
ASSERT_MATCH("a?", "a");
|
|
ASSERT_MATCH("a?b", "b");
|
|
ASSERT_MATCH("a?b", "ab");
|
|
}
|
|
|
|
TEST(dot) {
|
|
ASSERT_MATCH(".", "a");
|
|
ASSERT_MATCH(".", "x");
|
|
ASSERT_MATCH("a.b", "aab");
|
|
ASSERT_MATCH("a.b", "axb");
|
|
ASSERT_NO_MATCH("a.b", "ab");
|
|
}
|
|
|
|
TEST(bracket_simple) {
|
|
ASSERT_MATCH("[abc]", "a");
|
|
ASSERT_MATCH("[abc]", "b");
|
|
ASSERT_MATCH("[abc]", "c");
|
|
ASSERT_NO_MATCH("[abc]", "d");
|
|
}
|
|
|
|
TEST(bracket_range) {
|
|
ASSERT_MATCH("[a-z]", "a");
|
|
ASSERT_MATCH("[a-z]", "m");
|
|
ASSERT_MATCH("[a-z]", "z");
|
|
ASSERT_NO_MATCH("[a-z]", "A");
|
|
ASSERT_NO_MATCH("[a-z]", "0");
|
|
}
|
|
|
|
TEST(bracket_negated) {
|
|
ASSERT_NO_MATCH("[^abc]", "a");
|
|
ASSERT_NO_MATCH("[^abc]", "b");
|
|
ASSERT_MATCH("[^abc]", "d");
|
|
ASSERT_MATCH("[^abc]", "x");
|
|
}
|
|
|
|
TEST(group) {
|
|
ASSERT_MATCH("(ab)", "ab");
|
|
ASSERT_MATCH("(ab)+", "abab");
|
|
ASSERT_MATCH("(a|b)+", "abba");
|
|
}
|
|
|
|
TEST(anchors) {
|
|
ASSERT_MATCH("^a", "a");
|
|
ASSERT_MATCH("^a", "abc");
|
|
ASSERT_NO_MATCH("^a", "ba");
|
|
|
|
ASSERT_MATCH("a$", "a");
|
|
ASSERT_MATCH("a$", "ba");
|
|
ASSERT_NO_MATCH("a$", "ab");
|
|
|
|
ASSERT_MATCH("^abc$", "abc");
|
|
ASSERT_NO_MATCH("^abc$", "xabc");
|
|
ASSERT_NO_MATCH("^abc$", "abcx");
|
|
}
|
|
|
|
TEST(quantifier_exact) {
|
|
ASSERT_MATCH("a{3}", "aaa");
|
|
ASSERT_MATCH("a{3}", "aaaa");
|
|
ASSERT_NO_MATCH("a{3}", "aa");
|
|
}
|
|
|
|
TEST(quantifier_range) {
|
|
ASSERT_MATCH("a{2,4}", "aa");
|
|
ASSERT_MATCH("a{2,4}", "aaa");
|
|
ASSERT_MATCH("a{2,4}", "aaaa");
|
|
ASSERT_NO_MATCH("a{2,4}", "a");
|
|
}
|
|
|
|
TEST(quantifier_open) {
|
|
ASSERT_MATCH("a{2,}", "aa");
|
|
ASSERT_MATCH("a{2,}", "aaaaa");
|
|
ASSERT_NO_MATCH("a{2,}", "a");
|
|
}
|
|
|
|
TEST(class_digit) {
|
|
ASSERT_MATCH("\\d", "0");
|
|
ASSERT_MATCH("\\d", "9");
|
|
ASSERT_MATCH("\\d+", "123");
|
|
ASSERT_NO_MATCH("\\d", "a");
|
|
}
|
|
|
|
TEST(class_word) {
|
|
ASSERT_MATCH("\\w", "a");
|
|
ASSERT_MATCH("\\w", "Z");
|
|
ASSERT_MATCH("\\w", "0");
|
|
ASSERT_MATCH("\\w", "_");
|
|
ASSERT_NO_MATCH("\\w", " ");
|
|
ASSERT_NO_MATCH("\\w", "-");
|
|
}
|
|
|
|
TEST(class_space) {
|
|
ASSERT_MATCH("\\s", " ");
|
|
ASSERT_MATCH("\\s", "\t");
|
|
ASSERT_MATCH("\\s", "\n");
|
|
ASSERT_NO_MATCH("\\s", "a");
|
|
}
|
|
|
|
TEST(class_negated) {
|
|
ASSERT_NO_MATCH("\\D", "0");
|
|
ASSERT_MATCH("\\D", "a");
|
|
ASSERT_NO_MATCH("\\W", "a");
|
|
ASSERT_MATCH("\\W", " ");
|
|
ASSERT_NO_MATCH("\\S", " ");
|
|
ASSERT_MATCH("\\S", "a");
|
|
}
|
|
|
|
TEST(escape_sequences) {
|
|
ASSERT_MATCH("\\.", ".");
|
|
ASSERT_NO_MATCH("\\.", "a");
|
|
ASSERT_MATCH("\\*", "*");
|
|
ASSERT_MATCH("\\+", "+");
|
|
ASSERT_MATCH("\\?", "?");
|
|
}
|
|
|
|
TEST(complex_email) {
|
|
ASSERT_MATCH("[a-z]+@[a-z]+\\.[a-z]+", "test@example.com");
|
|
ASSERT_NO_MATCH("[a-z]+@[a-z]+\\.[a-z]+", "invalid");
|
|
}
|
|
|
|
TEST(complex_phone) {
|
|
ASSERT_MATCH("\\d{3}-\\d{3}-\\d{4}", "123-456-7890");
|
|
ASSERT_NO_MATCH("\\d{3}-\\d{3}-\\d{4}", "123-456-789");
|
|
}
|
|
|
|
TEST(complex_url) {
|
|
ASSERT_MATCH("https?://[a-z]+\\.[a-z]+", "http://example.com");
|
|
ASSERT_MATCH("https?://[a-z]+\\.[a-z]+", "https://example.com");
|
|
}
|
|
|
|
TEST(group_capture) {
|
|
lorex_error_t err;
|
|
lorex_regex_t *re = lorex_compile("(\\d+)-(\\d+)", &err);
|
|
ASSERT(re != NULL);
|
|
|
|
lorex_match_t result;
|
|
ASSERT(lorex_search(re, "123-456", &result));
|
|
ASSERT(result.group_count == 2);
|
|
ASSERT(result.groups[0].matched);
|
|
ASSERT(result.groups[1].matched);
|
|
|
|
lorex_free(re);
|
|
}
|
|
|
|
TEST(nested_groups) {
|
|
lorex_error_t err;
|
|
lorex_regex_t *re = lorex_compile("((a)(b))", &err);
|
|
ASSERT(re != NULL);
|
|
|
|
lorex_match_t result;
|
|
ASSERT(lorex_search(re, "ab", &result));
|
|
ASSERT(result.group_count == 3);
|
|
|
|
lorex_free(re);
|
|
}
|
|
|
|
TEST(empty_pattern) {
|
|
lorex_error_t err;
|
|
lorex_regex_t *re = lorex_compile("", &err);
|
|
ASSERT(re != NULL);
|
|
|
|
lorex_match_t result;
|
|
ASSERT(lorex_match(re, "anything", &result));
|
|
|
|
lorex_free(re);
|
|
}
|
|
|
|
TEST(match_position) {
|
|
lorex_error_t err;
|
|
lorex_regex_t *re = lorex_compile("test", &err);
|
|
ASSERT(re != NULL);
|
|
|
|
lorex_match_t result;
|
|
ASSERT(lorex_search(re, "xxxtestyyy", &result));
|
|
ASSERT(result.match_start == 3);
|
|
ASSERT(result.match_end == 7);
|
|
|
|
lorex_free(re);
|
|
}
|
|
|
|
int main(void) {
|
|
printf("matcher tests:\n");
|
|
|
|
RUN_TEST(simple_char);
|
|
RUN_TEST(concat);
|
|
RUN_TEST(alternation);
|
|
RUN_TEST(star);
|
|
RUN_TEST(plus);
|
|
RUN_TEST(question);
|
|
RUN_TEST(dot);
|
|
RUN_TEST(bracket_simple);
|
|
RUN_TEST(bracket_range);
|
|
RUN_TEST(bracket_negated);
|
|
RUN_TEST(group);
|
|
RUN_TEST(anchors);
|
|
RUN_TEST(quantifier_exact);
|
|
RUN_TEST(quantifier_range);
|
|
RUN_TEST(quantifier_open);
|
|
RUN_TEST(class_digit);
|
|
RUN_TEST(class_word);
|
|
RUN_TEST(class_space);
|
|
RUN_TEST(class_negated);
|
|
RUN_TEST(escape_sequences);
|
|
RUN_TEST(complex_email);
|
|
RUN_TEST(complex_phone);
|
|
RUN_TEST(complex_url);
|
|
RUN_TEST(group_capture);
|
|
RUN_TEST(nested_groups);
|
|
RUN_TEST(empty_pattern);
|
|
RUN_TEST(match_position);
|
|
|
|
printf("\nmatcher: %d passed, %d failed\n", tests_passed, tests_failed);
|
|
return tests_failed > 0 ? 1 : 0;
|
|
}
|