chore: update c, h, md files
This commit is contained in:
@@ -0,0 +1,448 @@
|
||||
/* retoor <retoor@molodetz.nl> */
|
||||
#define _POSIX_C_SOURCE 200809L
|
||||
#include "../include/lorex.h"
|
||||
#include <regex.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
#define ITERATIONS 10000
|
||||
#define WARMUP 1000
|
||||
|
||||
typedef struct {
|
||||
const char *name;
|
||||
const char *pattern;
|
||||
const char *text;
|
||||
int expect_match;
|
||||
} benchmark_t;
|
||||
|
||||
typedef struct {
|
||||
double lorex_compile_us;
|
||||
double lorex_match_us;
|
||||
double lorex_total_us;
|
||||
double posix_compile_us;
|
||||
double posix_match_us;
|
||||
double posix_total_us;
|
||||
int lorex_matched;
|
||||
int posix_matched;
|
||||
int lorex_failed;
|
||||
int posix_failed;
|
||||
} result_t;
|
||||
|
||||
static benchmark_t benchmarks[] = {
|
||||
{"literal_short", "hello", "hello world", 1},
|
||||
{"literal_medium", "the quick brown", "the quick brown fox jumps over the lazy dog", 1},
|
||||
{"literal_long", "Lorem ipsum dolor sit amet", "Lorem ipsum dolor sit amet, consectetur adipiscing elit", 1},
|
||||
{"literal_nomatch", "xyz", "the quick brown fox jumps over the lazy dog", 0},
|
||||
{"literal_end", "dog", "the quick brown fox jumps over the lazy dog", 1},
|
||||
{"literal_repeated", "abcabc", "xyzabcabcdef", 1},
|
||||
|
||||
{"dot_single", "a.c", "abc", 1},
|
||||
{"dot_multiple", "a..b", "aXYb", 1},
|
||||
{"dot_many", "a.....b", "a12345b", 1},
|
||||
{"dot_star", "a.*b", "aXXXXXXXXXXb", 1},
|
||||
{"dot_plus", "a.+b", "aXXXXXXXXXXb", 1},
|
||||
|
||||
{"anchor_start", "^the", "the quick brown fox", 1},
|
||||
{"anchor_end", "fox$", "the quick brown fox", 1},
|
||||
{"anchor_both", "^hello$", "hello", 1},
|
||||
{"anchor_start_nomatch", "^fox", "the quick brown fox", 0},
|
||||
{"anchor_end_nomatch", "the$", "the quick brown fox", 0},
|
||||
|
||||
{"star_simple", "ab*c", "abbbbc", 1},
|
||||
{"star_zero", "ab*c", "ac", 1},
|
||||
{"star_greedy", "a.*b", "aXbXbXb", 1},
|
||||
{"star_repeated", "a*b*c*", "aaabbbccc", 1},
|
||||
{"star_empty", "a*", "", 1},
|
||||
|
||||
{"plus_simple", "ab+c", "abbbbc", 1},
|
||||
{"plus_one", "ab+c", "abc", 1},
|
||||
{"plus_nomatch", "ab+c", "ac", 0},
|
||||
{"plus_greedy", "a.+b", "aXbXbXb", 1},
|
||||
|
||||
{"question_present", "colou?r", "colour", 1},
|
||||
{"question_absent", "colou?r", "color", 1},
|
||||
{"question_multiple", "a?b?c?d", "abcd", 1},
|
||||
|
||||
{"class_vowels", "[aeiou]", "hello", 1},
|
||||
{"class_digits", "[0-9]+", "abc123def", 1},
|
||||
{"class_alpha", "[a-zA-Z]+", "HelloWorld", 1},
|
||||
{"class_alnum", "[a-zA-Z0-9]+", "Test123", 1},
|
||||
{"class_neg_digit", "[^0-9]+", "hello", 1},
|
||||
{"class_neg_alpha", "[^a-zA-Z]+", "12345", 1},
|
||||
{"class_complex", "[a-zA-Z_][a-zA-Z0-9_]*", "variable_name_123", 1},
|
||||
|
||||
{"alt_simple", "cat|dog", "I have a cat", 1},
|
||||
{"alt_simple2", "cat|dog", "I have a dog", 1},
|
||||
{"alt_three", "red|green|blue", "the color is green", 1},
|
||||
{"alt_nomatch", "cat|dog", "I have a bird", 0},
|
||||
{"alt_words", "hello|world|test", "this is a test", 1},
|
||||
|
||||
{"group_simple", "(ab)+", "ababab", 1},
|
||||
{"group_alt", "(cat|dog)s?", "cats", 1},
|
||||
{"group_nested", "((a)(b))+", "ababab", 1},
|
||||
{"group_complex", "(a(b(c)))+", "abcabc", 1},
|
||||
|
||||
{"quant_exact", "a{3}", "aaa", 1},
|
||||
{"quant_exact_long", "a{10}", "aaaaaaaaaa", 1},
|
||||
{"quant_range", "a{2,4}", "aaa", 1},
|
||||
{"quant_min", "a{3,}", "aaaaa", 1},
|
||||
{"quant_combined", "[0-9]{3}-[0-9]{4}", "555-1234", 1},
|
||||
|
||||
{"email_simple", "[a-z]+@[a-z]+\\.[a-z]+", "test@example.com", 1},
|
||||
{"email_complex", "[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}", "user.name+tag@sub.example.com", 1},
|
||||
{"ip_address", "[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}", "192.168.1.100", 1},
|
||||
{"url_http", "https?://[a-zA-Z0-9.-]+", "https://www.example.com", 1},
|
||||
{"phone_us", "[0-9]{3}-[0-9]{3}-[0-9]{4}", "555-123-4567", 1},
|
||||
{"date_iso", "[0-9]{4}-[0-9]{2}-[0-9]{2}", "2024-01-15", 1},
|
||||
{"time_hms", "[0-9]{2}:[0-9]{2}:[0-9]{2}", "14:30:45", 1},
|
||||
{"hex_color", "#[0-9a-fA-F]{6}", "#ff00ff", 1},
|
||||
|
||||
{"word_boundary", "[a-zA-Z]+", "hello world test", 1},
|
||||
{"whitespace", "[ \\t\\n]+", "hello world", 1},
|
||||
{"identifier", "[a-zA-Z_][a-zA-Z0-9_]*", "_privateVar123", 1},
|
||||
{"number_int", "-?[0-9]+", "-12345", 1},
|
||||
{"number_float", "-?[0-9]+\\.[0-9]+", "3.14159", 1},
|
||||
|
||||
{"long_text_start", "^The", "The quick brown fox jumps over the lazy dog. The quick brown fox jumps over the lazy dog. The quick brown fox jumps over the lazy dog.", 1},
|
||||
{"long_text_end", "dog\\.$", "The quick brown fox jumps over the lazy dog. The quick brown fox jumps over the lazy dog. The quick brown fox jumps over the lazy dog.", 1},
|
||||
{"long_text_middle", "fox", "The quick brown fox jumps over the lazy dog. The quick brown fox jumps over the lazy dog. The quick brown fox jumps over the lazy dog.", 1},
|
||||
{"long_text_nomatch", "elephant", "The quick brown fox jumps over the lazy dog. The quick brown fox jumps over the lazy dog. The quick brown fox jumps over the lazy dog.", 0},
|
||||
|
||||
{"repeated_ab", "(ab){5}", "ababababab", 1},
|
||||
{"repeated_word", "(hello ){3}", "hello hello hello ", 1},
|
||||
{"alternation_long", "one|two|three|four|five|six|seven|eight|nine|ten", "the number is seven", 1},
|
||||
|
||||
{"escape_dot", "3\\.14", "pi is 3.14", 1},
|
||||
{"escape_star", "a\\*b", "a*b", 1},
|
||||
{"escape_plus", "c\\+\\+", "c++", 1},
|
||||
{"escape_parens", "\\(test\\)", "(test)", 1},
|
||||
{"escape_brackets", "\\[0\\]", "array[0]", 1},
|
||||
|
||||
{"stress_star", "a*a*a*a*a*b", "aaaaab", 1},
|
||||
{"stress_plus", "a+a+a+a+a+b", "aaaaab", 1},
|
||||
{"stress_nested", "((a+)+)+b", "aaaab", 1},
|
||||
{"stress_alt", "(a|aa|aaa|aaaa)+b", "aaaab", 1},
|
||||
|
||||
{"nomatch_literal", "notfound", "the quick brown fox", 0},
|
||||
{"nomatch_pattern", "^end", "start middle end", 0},
|
||||
{"nomatch_class", "[0-9]+", "no digits here", 0},
|
||||
|
||||
{NULL, NULL, NULL, 0}
|
||||
};
|
||||
|
||||
static double get_time_us(void) {
|
||||
struct timeval tv;
|
||||
gettimeofday(&tv, NULL);
|
||||
return tv.tv_sec * 1000000.0 + tv.tv_usec;
|
||||
}
|
||||
|
||||
static result_t run_benchmark(benchmark_t *bench) {
|
||||
result_t res = {0};
|
||||
double start, end;
|
||||
|
||||
for (int i = 0; i < WARMUP; i++) {
|
||||
lorex_error_t err;
|
||||
lorex_regex_t *re = lorex_compile(bench->pattern, &err);
|
||||
if (re) {
|
||||
lorex_match_t m;
|
||||
lorex_search(re, bench->text, &m);
|
||||
lorex_free(re);
|
||||
}
|
||||
}
|
||||
|
||||
start = get_time_us();
|
||||
for (int i = 0; i < ITERATIONS; i++) {
|
||||
lorex_error_t err;
|
||||
lorex_regex_t *re = lorex_compile(bench->pattern, &err);
|
||||
if (!re) {
|
||||
res.lorex_failed = 1;
|
||||
break;
|
||||
}
|
||||
lorex_free(re);
|
||||
}
|
||||
end = get_time_us();
|
||||
res.lorex_compile_us = (end - start) / ITERATIONS;
|
||||
|
||||
start = get_time_us();
|
||||
{
|
||||
lorex_error_t err;
|
||||
lorex_regex_t *re = lorex_compile(bench->pattern, &err);
|
||||
if (re) {
|
||||
for (int i = 0; i < ITERATIONS; i++) {
|
||||
lorex_match_t m;
|
||||
res.lorex_matched = lorex_search(re, bench->text, &m) ? 1 : 0;
|
||||
}
|
||||
lorex_free(re);
|
||||
}
|
||||
}
|
||||
end = get_time_us();
|
||||
res.lorex_match_us = (end - start) / ITERATIONS;
|
||||
res.lorex_total_us = res.lorex_compile_us + res.lorex_match_us;
|
||||
|
||||
for (int i = 0; i < WARMUP; i++) {
|
||||
regex_t preg;
|
||||
if (regcomp(&preg, bench->pattern, REG_EXTENDED) == 0) {
|
||||
regmatch_t pmatch[1];
|
||||
regexec(&preg, bench->text, 1, pmatch, 0);
|
||||
regfree(&preg);
|
||||
}
|
||||
}
|
||||
|
||||
start = get_time_us();
|
||||
for (int i = 0; i < ITERATIONS; i++) {
|
||||
regex_t preg;
|
||||
if (regcomp(&preg, bench->pattern, REG_EXTENDED) != 0) {
|
||||
res.posix_failed = 1;
|
||||
break;
|
||||
}
|
||||
regfree(&preg);
|
||||
}
|
||||
end = get_time_us();
|
||||
res.posix_compile_us = (end - start) / ITERATIONS;
|
||||
|
||||
start = get_time_us();
|
||||
{
|
||||
regex_t preg;
|
||||
if (regcomp(&preg, bench->pattern, REG_EXTENDED) == 0) {
|
||||
for (int i = 0; i < ITERATIONS; i++) {
|
||||
regmatch_t pmatch[1];
|
||||
res.posix_matched = (regexec(&preg, bench->text, 1, pmatch, 0) == 0) ? 1 : 0;
|
||||
}
|
||||
regfree(&preg);
|
||||
}
|
||||
}
|
||||
end = get_time_us();
|
||||
res.posix_match_us = (end - start) / ITERATIONS;
|
||||
res.posix_total_us = res.posix_compile_us + res.posix_match_us;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
int main(void) {
|
||||
printf("================================================================================\n");
|
||||
printf(" LOREX vs POSIX REGEX PERFORMANCE BENCHMARK\n");
|
||||
printf("================================================================================\n\n");
|
||||
printf("Configuration:\n");
|
||||
printf(" Iterations per test: %d\n", ITERATIONS);
|
||||
printf(" Warmup iterations: %d\n", WARMUP);
|
||||
printf("\n");
|
||||
|
||||
int total_tests = 0;
|
||||
int lorex_wins = 0;
|
||||
int posix_wins = 0;
|
||||
int ties = 0;
|
||||
double total_lorex_time = 0;
|
||||
double total_posix_time = 0;
|
||||
|
||||
int lorex_compile_wins = 0;
|
||||
int posix_compile_wins = 0;
|
||||
int lorex_match_wins = 0;
|
||||
int posix_match_wins = 0;
|
||||
|
||||
printf("================================================================================\n");
|
||||
printf("%-25s | %-12s | %-12s | %-12s | %-8s\n", "TEST NAME", "LOREX (us)", "POSIX (us)", "SPEEDUP", "WINNER");
|
||||
printf("================================================================================\n");
|
||||
|
||||
for (int i = 0; benchmarks[i].name != NULL; i++) {
|
||||
benchmark_t *bench = &benchmarks[i];
|
||||
result_t res = run_benchmark(bench);
|
||||
|
||||
if (res.lorex_failed || res.posix_failed) {
|
||||
printf("%-25s | %-12s | %-12s | %-12s | %-8s\n",
|
||||
bench->name,
|
||||
res.lorex_failed ? "FAILED" : "OK",
|
||||
res.posix_failed ? "FAILED" : "OK",
|
||||
"-", "-");
|
||||
continue;
|
||||
}
|
||||
|
||||
total_tests++;
|
||||
total_lorex_time += res.lorex_total_us;
|
||||
total_posix_time += res.posix_total_us;
|
||||
|
||||
double speedup = res.posix_total_us / res.lorex_total_us;
|
||||
const char *winner;
|
||||
|
||||
if (speedup > 1.05) {
|
||||
winner = "LOREX";
|
||||
lorex_wins++;
|
||||
} else if (speedup < 0.95) {
|
||||
winner = "POSIX";
|
||||
posix_wins++;
|
||||
} else {
|
||||
winner = "TIE";
|
||||
ties++;
|
||||
}
|
||||
|
||||
if (res.lorex_compile_us < res.posix_compile_us) lorex_compile_wins++;
|
||||
else posix_compile_wins++;
|
||||
|
||||
if (res.lorex_match_us < res.posix_match_us) lorex_match_wins++;
|
||||
else posix_match_wins++;
|
||||
|
||||
printf("%-25s | %10.3f | %10.3f | %10.2fx | %-8s\n",
|
||||
bench->name,
|
||||
res.lorex_total_us,
|
||||
res.posix_total_us,
|
||||
speedup,
|
||||
winner);
|
||||
}
|
||||
|
||||
printf("================================================================================\n\n");
|
||||
|
||||
printf("================================================================================\n");
|
||||
printf(" DETAILED RESULTS\n");
|
||||
printf("================================================================================\n\n");
|
||||
|
||||
printf("%-25s | %-20s | %-20s\n", "TEST NAME", "LOREX (compile/match)", "POSIX (compile/match)");
|
||||
printf("--------------------------------------------------------------------------------\n");
|
||||
|
||||
for (int i = 0; benchmarks[i].name != NULL; i++) {
|
||||
benchmark_t *bench = &benchmarks[i];
|
||||
result_t res = run_benchmark(bench);
|
||||
|
||||
if (res.lorex_failed || res.posix_failed) continue;
|
||||
|
||||
printf("%-25s | %8.3f / %8.3f | %8.3f / %8.3f\n",
|
||||
bench->name,
|
||||
res.lorex_compile_us, res.lorex_match_us,
|
||||
res.posix_compile_us, res.posix_match_us);
|
||||
}
|
||||
|
||||
printf("\n================================================================================\n");
|
||||
printf(" SUMMARY\n");
|
||||
printf("================================================================================\n\n");
|
||||
|
||||
printf("Total tests: %d\n", total_tests);
|
||||
printf("\n");
|
||||
printf("Overall wins:\n");
|
||||
printf(" LOREX wins: %d (%.1f%%)\n", lorex_wins, 100.0 * lorex_wins / total_tests);
|
||||
printf(" POSIX wins: %d (%.1f%%)\n", posix_wins, 100.0 * posix_wins / total_tests);
|
||||
printf(" Ties: %d (%.1f%%)\n", ties, 100.0 * ties / total_tests);
|
||||
printf("\n");
|
||||
printf("Compilation phase wins:\n");
|
||||
printf(" LOREX faster: %d\n", lorex_compile_wins);
|
||||
printf(" POSIX faster: %d\n", posix_compile_wins);
|
||||
printf("\n");
|
||||
printf("Matching phase wins:\n");
|
||||
printf(" LOREX faster: %d\n", lorex_match_wins);
|
||||
printf(" POSIX faster: %d\n", posix_match_wins);
|
||||
printf("\n");
|
||||
printf("Total time (all tests):\n");
|
||||
printf(" LOREX: %.3f us\n", total_lorex_time);
|
||||
printf(" POSIX: %.3f us\n", total_posix_time);
|
||||
printf(" Overall speedup: %.2fx %s\n",
|
||||
total_posix_time > total_lorex_time ? total_posix_time / total_lorex_time : total_lorex_time / total_posix_time,
|
||||
total_posix_time > total_lorex_time ? "(LOREX faster)" : "(POSIX faster)");
|
||||
|
||||
printf("\n================================================================================\n");
|
||||
printf(" CATEGORY BREAKDOWN\n");
|
||||
printf("================================================================================\n\n");
|
||||
|
||||
typedef struct {
|
||||
const char *category;
|
||||
const char *prefix;
|
||||
double lorex_total;
|
||||
double posix_total;
|
||||
int count;
|
||||
} category_t;
|
||||
|
||||
category_t categories[] = {
|
||||
{"Literal matching", "literal_", 0, 0, 0},
|
||||
{"Dot metacharacter", "dot_", 0, 0, 0},
|
||||
{"Anchors", "anchor_", 0, 0, 0},
|
||||
{"Star quantifier", "star_", 0, 0, 0},
|
||||
{"Plus quantifier", "plus_", 0, 0, 0},
|
||||
{"Question quantifier", "question_", 0, 0, 0},
|
||||
{"Character classes", "class_", 0, 0, 0},
|
||||
{"Alternation", "alt_", 0, 0, 0},
|
||||
{"Groups", "group_", 0, 0, 0},
|
||||
{"Brace quantifiers", "quant_", 0, 0, 0},
|
||||
{"Real-world patterns", "email_", 0, 0, 0},
|
||||
{"Escape sequences", "escape_", 0, 0, 0},
|
||||
{"Stress tests", "stress_", 0, 0, 0},
|
||||
{"No-match tests", "nomatch_", 0, 0, 0},
|
||||
{NULL, NULL, 0, 0, 0}
|
||||
};
|
||||
|
||||
for (int i = 0; benchmarks[i].name != NULL; i++) {
|
||||
benchmark_t *bench = &benchmarks[i];
|
||||
result_t res = run_benchmark(bench);
|
||||
if (res.lorex_failed || res.posix_failed) continue;
|
||||
|
||||
for (int j = 0; categories[j].category != NULL; j++) {
|
||||
if (strncmp(bench->name, categories[j].prefix, strlen(categories[j].prefix)) == 0) {
|
||||
categories[j].lorex_total += res.lorex_total_us;
|
||||
categories[j].posix_total += res.posix_total_us;
|
||||
categories[j].count++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
printf("%-25s | %-12s | %-12s | %-12s | %-8s\n", "CATEGORY", "LOREX (us)", "POSIX (us)", "SPEEDUP", "WINNER");
|
||||
printf("--------------------------------------------------------------------------------\n");
|
||||
|
||||
for (int i = 0; categories[i].category != NULL; i++) {
|
||||
if (categories[i].count == 0) continue;
|
||||
|
||||
double speedup = categories[i].posix_total / categories[i].lorex_total;
|
||||
const char *winner = speedup > 1.0 ? "LOREX" : "POSIX";
|
||||
|
||||
printf("%-25s | %10.3f | %10.3f | %10.2fx | %-8s\n",
|
||||
categories[i].category,
|
||||
categories[i].lorex_total,
|
||||
categories[i].posix_total,
|
||||
speedup > 1.0 ? speedup : 1.0 / speedup,
|
||||
winner);
|
||||
}
|
||||
|
||||
printf("\n================================================================================\n");
|
||||
printf(" PATTERN DETAILS\n");
|
||||
printf("================================================================================\n\n");
|
||||
|
||||
for (int i = 0; benchmarks[i].name != NULL; i++) {
|
||||
benchmark_t *bench = &benchmarks[i];
|
||||
result_t res = run_benchmark(bench);
|
||||
|
||||
printf("Test: %s\n", bench->name);
|
||||
printf(" Pattern: %s\n", bench->pattern);
|
||||
printf(" Text: %.50s%s\n", bench->text, strlen(bench->text) > 50 ? "..." : "");
|
||||
printf(" Expected: %s\n", bench->expect_match ? "MATCH" : "NO MATCH");
|
||||
|
||||
if (res.lorex_failed) {
|
||||
printf(" LOREX: FAILED TO COMPILE\n");
|
||||
} else {
|
||||
printf(" LOREX: %s (compile: %.3f us, match: %.3f us, total: %.3f us)\n",
|
||||
res.lorex_matched ? "MATCHED" : "NO MATCH",
|
||||
res.lorex_compile_us, res.lorex_match_us, res.lorex_total_us);
|
||||
}
|
||||
|
||||
if (res.posix_failed) {
|
||||
printf(" POSIX: FAILED TO COMPILE\n");
|
||||
} else {
|
||||
printf(" POSIX: %s (compile: %.3f us, match: %.3f us, total: %.3f us)\n",
|
||||
res.posix_matched ? "MATCHED" : "NO MATCH",
|
||||
res.posix_compile_us, res.posix_match_us, res.posix_total_us);
|
||||
}
|
||||
|
||||
if (!res.lorex_failed && !res.posix_failed) {
|
||||
double speedup = res.posix_total_us / res.lorex_total_us;
|
||||
if (speedup > 1.0) {
|
||||
printf(" Result: LOREX is %.2fx faster\n", speedup);
|
||||
} else {
|
||||
printf(" Result: POSIX is %.2fx faster\n", 1.0 / speedup);
|
||||
}
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
printf("================================================================================\n");
|
||||
printf(" BENCHMARK COMPLETE\n");
|
||||
printf("================================================================================\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
+125
-125
@@ -1,5 +1,5 @@
|
||||
/* retoor <retoor@molodetz.nl> */
|
||||
#include "../include/loreg.h"
|
||||
#include "../include/lorex.h"
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
@@ -22,211 +22,211 @@ static int total_failed = 0;
|
||||
} while(0)
|
||||
|
||||
TEST(basic_literals) {
|
||||
loreg_error_t err;
|
||||
loreg_regex_t *re = loreg_compile("hello", &err);
|
||||
lorex_error_t err;
|
||||
lorex_regex_t *re = lorex_compile("hello", &err);
|
||||
ASSERT(re != NULL, "compile hello");
|
||||
|
||||
loreg_match_t m;
|
||||
ASSERT(loreg_search(re, "hello", &m), "match hello");
|
||||
ASSERT(loreg_search(re, "say hello world", &m), "search hello");
|
||||
ASSERT(!loreg_search(re, "helo", &m), "no match helo");
|
||||
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");
|
||||
|
||||
loreg_free(re);
|
||||
lorex_free(re);
|
||||
}
|
||||
|
||||
TEST(metacharacters) {
|
||||
loreg_error_t err;
|
||||
loreg_match_t m;
|
||||
lorex_error_t err;
|
||||
lorex_match_t m;
|
||||
|
||||
loreg_regex_t *re = loreg_compile("a.c", &err);
|
||||
lorex_regex_t *re = lorex_compile("a.c", &err);
|
||||
ASSERT(re != NULL, "compile a.c");
|
||||
ASSERT(loreg_search(re, "abc", &m), "match abc");
|
||||
ASSERT(loreg_search(re, "axc", &m), "match axc");
|
||||
ASSERT(!loreg_search(re, "ac", &m), "no match ac");
|
||||
loreg_free(re);
|
||||
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 = loreg_compile("^start", &err);
|
||||
re = lorex_compile("^start", &err);
|
||||
ASSERT(re != NULL, "compile ^start");
|
||||
ASSERT(loreg_search(re, "start here", &m), "match start here");
|
||||
ASSERT(!loreg_search(re, "not start", &m), "no match not start");
|
||||
loreg_free(re);
|
||||
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 = loreg_compile("end$", &err);
|
||||
re = lorex_compile("end$", &err);
|
||||
ASSERT(re != NULL, "compile end$");
|
||||
ASSERT(loreg_search(re, "the end", &m), "match the end");
|
||||
ASSERT(!loreg_search(re, "end here", &m), "no match end here");
|
||||
loreg_free(re);
|
||||
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) {
|
||||
loreg_error_t err;
|
||||
loreg_match_t m;
|
||||
lorex_error_t err;
|
||||
lorex_match_t m;
|
||||
|
||||
loreg_regex_t *re = loreg_compile("ab*c", &err);
|
||||
lorex_regex_t *re = lorex_compile("ab*c", &err);
|
||||
ASSERT(re != NULL, "compile ab*c");
|
||||
ASSERT(loreg_search(re, "ac", &m), "match ac");
|
||||
ASSERT(loreg_search(re, "abc", &m), "match abc");
|
||||
ASSERT(loreg_search(re, "abbbbc", &m), "match abbbbc");
|
||||
loreg_free(re);
|
||||
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 = loreg_compile("ab+c", &err);
|
||||
re = lorex_compile("ab+c", &err);
|
||||
ASSERT(re != NULL, "compile ab+c");
|
||||
ASSERT(!loreg_search(re, "ac", &m), "no match ac");
|
||||
ASSERT(loreg_search(re, "abc", &m), "match abc");
|
||||
ASSERT(loreg_search(re, "abbbbc", &m), "match abbbbc");
|
||||
loreg_free(re);
|
||||
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 = loreg_compile("ab?c", &err);
|
||||
re = lorex_compile("ab?c", &err);
|
||||
ASSERT(re != NULL, "compile ab?c");
|
||||
ASSERT(loreg_search(re, "ac", &m), "match ac");
|
||||
ASSERT(loreg_search(re, "abc", &m), "match abc");
|
||||
ASSERT(!loreg_search(re, "abbc", &m), "no match abbc");
|
||||
loreg_free(re);
|
||||
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 = loreg_compile("a{3}", &err);
|
||||
re = lorex_compile("a{3}", &err);
|
||||
ASSERT(re != NULL, "compile a{3}");
|
||||
ASSERT(loreg_search(re, "aaa", &m), "match aaa");
|
||||
ASSERT(!loreg_search(re, "aa", &m), "no match aa");
|
||||
loreg_free(re);
|
||||
ASSERT(lorex_search(re, "aaa", &m), "match aaa");
|
||||
ASSERT(!lorex_search(re, "aa", &m), "no match aa");
|
||||
lorex_free(re);
|
||||
|
||||
re = loreg_compile("a{2,4}", &err);
|
||||
re = lorex_compile("a{2,4}", &err);
|
||||
ASSERT(re != NULL, "compile a{2,4}");
|
||||
ASSERT(loreg_search(re, "aa", &m), "match aa");
|
||||
ASSERT(loreg_search(re, "aaa", &m), "match aaa");
|
||||
ASSERT(loreg_search(re, "aaaa", &m), "match aaaa");
|
||||
ASSERT(!loreg_search(re, "a", &m), "no match a");
|
||||
loreg_free(re);
|
||||
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) {
|
||||
loreg_error_t err;
|
||||
loreg_match_t m;
|
||||
lorex_error_t err;
|
||||
lorex_match_t m;
|
||||
|
||||
loreg_regex_t *re = loreg_compile("[aeiou]", &err);
|
||||
lorex_regex_t *re = lorex_compile("[aeiou]", &err);
|
||||
ASSERT(re != NULL, "compile [aeiou]");
|
||||
ASSERT(loreg_search(re, "a", &m), "match a");
|
||||
ASSERT(loreg_search(re, "test", &m), "match test");
|
||||
ASSERT(!loreg_search(re, "xyz", &m), "no match xyz");
|
||||
loreg_free(re);
|
||||
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 = loreg_compile("[a-z]", &err);
|
||||
re = lorex_compile("[a-z]", &err);
|
||||
ASSERT(re != NULL, "compile [a-z]");
|
||||
ASSERT(loreg_search(re, "m", &m), "match m");
|
||||
ASSERT(!loreg_search(re, "5", &m), "no match 5");
|
||||
loreg_free(re);
|
||||
ASSERT(lorex_search(re, "m", &m), "match m");
|
||||
ASSERT(!lorex_search(re, "5", &m), "no match 5");
|
||||
lorex_free(re);
|
||||
|
||||
re = loreg_compile("[^0-9]", &err);
|
||||
re = lorex_compile("[^0-9]", &err);
|
||||
ASSERT(re != NULL, "compile [^0-9]");
|
||||
ASSERT(loreg_search(re, "a", &m), "match a");
|
||||
ASSERT(!loreg_search(re, "5", &m), "no match 5");
|
||||
loreg_free(re);
|
||||
ASSERT(lorex_search(re, "a", &m), "match a");
|
||||
ASSERT(!lorex_search(re, "5", &m), "no match 5");
|
||||
lorex_free(re);
|
||||
|
||||
re = loreg_compile("\\d", &err);
|
||||
re = lorex_compile("\\d", &err);
|
||||
ASSERT(re != NULL, "compile \\d");
|
||||
ASSERT(loreg_search(re, "5", &m), "match 5");
|
||||
ASSERT(!loreg_search(re, "a", &m), "no match a");
|
||||
loreg_free(re);
|
||||
ASSERT(lorex_search(re, "5", &m), "match 5");
|
||||
ASSERT(!lorex_search(re, "a", &m), "no match a");
|
||||
lorex_free(re);
|
||||
|
||||
re = loreg_compile("\\w+", &err);
|
||||
re = lorex_compile("\\w+", &err);
|
||||
ASSERT(re != NULL, "compile \\w+");
|
||||
ASSERT(loreg_search(re, "hello_123", &m), "match hello_123");
|
||||
loreg_free(re);
|
||||
ASSERT(lorex_search(re, "hello_123", &m), "match hello_123");
|
||||
lorex_free(re);
|
||||
|
||||
re = loreg_compile("\\s", &err);
|
||||
re = lorex_compile("\\s", &err);
|
||||
ASSERT(re != NULL, "compile \\s");
|
||||
ASSERT(loreg_search(re, " ", &m), "match space");
|
||||
ASSERT(loreg_search(re, "\t", &m), "match tab");
|
||||
ASSERT(!loreg_search(re, "a", &m), "no match a");
|
||||
loreg_free(re);
|
||||
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) {
|
||||
loreg_error_t err;
|
||||
loreg_match_t m;
|
||||
lorex_error_t err;
|
||||
lorex_match_t m;
|
||||
|
||||
loreg_regex_t *re = loreg_compile("(ab)+", &err);
|
||||
lorex_regex_t *re = lorex_compile("(ab)+", &err);
|
||||
ASSERT(re != NULL, "compile (ab)+");
|
||||
ASSERT(loreg_search(re, "ab", &m), "match ab");
|
||||
ASSERT(loreg_search(re, "abab", &m), "match abab");
|
||||
ASSERT(!loreg_search(re, "a", &m), "no match a");
|
||||
loreg_free(re);
|
||||
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 = loreg_compile("(\\d+)-(\\d+)", &err);
|
||||
re = lorex_compile("(\\d+)-(\\d+)", &err);
|
||||
ASSERT(re != NULL, "compile groups");
|
||||
ASSERT(loreg_search(re, "123-456", &m), "match 123-456");
|
||||
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");
|
||||
loreg_free(re);
|
||||
lorex_free(re);
|
||||
}
|
||||
|
||||
TEST(alternation) {
|
||||
loreg_error_t err;
|
||||
loreg_match_t m;
|
||||
lorex_error_t err;
|
||||
lorex_match_t m;
|
||||
|
||||
loreg_regex_t *re = loreg_compile("cat|dog", &err);
|
||||
lorex_regex_t *re = lorex_compile("cat|dog", &err);
|
||||
ASSERT(re != NULL, "compile cat|dog");
|
||||
ASSERT(loreg_search(re, "cat", &m), "match cat");
|
||||
ASSERT(loreg_search(re, "dog", &m), "match dog");
|
||||
ASSERT(!loreg_search(re, "rat", &m), "no match rat");
|
||||
loreg_free(re);
|
||||
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 = loreg_compile("(red|blue) car", &err);
|
||||
re = lorex_compile("(red|blue) car", &err);
|
||||
ASSERT(re != NULL, "compile (red|blue) car");
|
||||
ASSERT(loreg_search(re, "red car", &m), "match red car");
|
||||
ASSERT(loreg_search(re, "blue car", &m), "match blue car");
|
||||
ASSERT(!loreg_search(re, "green car", &m), "no match green car");
|
||||
loreg_free(re);
|
||||
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) {
|
||||
loreg_error_t err;
|
||||
loreg_match_t m;
|
||||
lorex_error_t err;
|
||||
lorex_match_t m;
|
||||
|
||||
loreg_regex_t *re = loreg_compile("1\\.5", &err);
|
||||
lorex_regex_t *re = lorex_compile("1\\.5", &err);
|
||||
ASSERT(re != NULL, "compile 1\\.5");
|
||||
ASSERT(loreg_search(re, "1.5", &m), "match 1.5");
|
||||
ASSERT(!loreg_search(re, "1x5", &m), "no match 1x5");
|
||||
loreg_free(re);
|
||||
ASSERT(lorex_search(re, "1.5", &m), "match 1.5");
|
||||
ASSERT(!lorex_search(re, "1x5", &m), "no match 1x5");
|
||||
lorex_free(re);
|
||||
|
||||
re = loreg_compile("\\(test\\)", &err);
|
||||
re = lorex_compile("\\(test\\)", &err);
|
||||
ASSERT(re != NULL, "compile \\(test\\)");
|
||||
ASSERT(loreg_search(re, "(test)", &m), "match (test)");
|
||||
loreg_free(re);
|
||||
ASSERT(lorex_search(re, "(test)", &m), "match (test)");
|
||||
lorex_free(re);
|
||||
}
|
||||
|
||||
TEST(real_patterns) {
|
||||
loreg_error_t err;
|
||||
loreg_match_t m;
|
||||
lorex_error_t err;
|
||||
lorex_match_t m;
|
||||
|
||||
loreg_regex_t *re = loreg_compile("[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}", &err);
|
||||
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(loreg_search(re, "user@example.com", &m), "match email");
|
||||
ASSERT(!loreg_search(re, "invalid", &m), "no match invalid");
|
||||
loreg_free(re);
|
||||
ASSERT(lorex_search(re, "user@example.com", &m), "match email");
|
||||
ASSERT(!lorex_search(re, "invalid", &m), "no match invalid");
|
||||
lorex_free(re);
|
||||
|
||||
re = loreg_compile("\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}", &err);
|
||||
re = lorex_compile("\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}", &err);
|
||||
ASSERT(re != NULL, "compile ip");
|
||||
ASSERT(loreg_search(re, "192.168.1.1", &m), "match ip");
|
||||
loreg_free(re);
|
||||
ASSERT(lorex_search(re, "192.168.1.1", &m), "match ip");
|
||||
lorex_free(re);
|
||||
|
||||
re = loreg_compile("https?://[a-zA-Z0-9.-]+(/[a-zA-Z0-9./-]*)?", &err);
|
||||
re = lorex_compile("https?://[a-zA-Z0-9.-]+(/[a-zA-Z0-9./-]*)?", &err);
|
||||
ASSERT(re != NULL, "compile url");
|
||||
ASSERT(loreg_search(re, "http://example.com", &m), "match http");
|
||||
ASSERT(loreg_search(re, "https://example.com/path", &m), "match https");
|
||||
loreg_free(re);
|
||||
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) {
|
||||
loreg_error_t err;
|
||||
lorex_error_t err;
|
||||
|
||||
loreg_regex_t *re = loreg_compile("(abc", &err);
|
||||
lorex_regex_t *re = lorex_compile("(abc", &err);
|
||||
ASSERT(re == NULL, "unbalanced paren");
|
||||
ASSERT(err == LOREG_ERR_UNBALANCED_PAREN, "correct error");
|
||||
ASSERT(err == LOREX_ERR_UNBALANCED_PAREN, "correct error");
|
||||
}
|
||||
|
||||
int main(void) {
|
||||
printf("loreg comprehensive tests\n");
|
||||
printf("lorex comprehensive tests\n");
|
||||
printf("========================\n\n");
|
||||
|
||||
clock_t start = clock();
|
||||
|
||||
+245
-8
@@ -1,5 +1,5 @@
|
||||
/* retoor <retoor@molodetz.nl> */
|
||||
#include "../include/loreg.h"
|
||||
#include "../include/lorex.h"
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
@@ -10,22 +10,22 @@ static int failed = 0;
|
||||
#define NO_MATCH(pat, txt) test_match(pat, txt, 0, __LINE__)
|
||||
|
||||
static void test_match(const char *pattern, const char *text, int expect, int line) {
|
||||
loreg_error_t err;
|
||||
loreg_regex_t *re = loreg_compile(pattern, &err);
|
||||
lorex_error_t err;
|
||||
lorex_regex_t *re = lorex_compile(pattern, &err);
|
||||
if (!re) {
|
||||
printf("FAIL line %d: compile error for '%s': %s\n", line, pattern, loreg_error_string(err));
|
||||
printf("FAIL line %d: compile error for '%s': %s\n", line, pattern, lorex_error_string(err));
|
||||
failed++;
|
||||
return;
|
||||
}
|
||||
loreg_match_t m;
|
||||
int result = loreg_search(re, text, &m) ? 1 : 0;
|
||||
lorex_match_t m;
|
||||
int result = lorex_search(re, text, &m) ? 1 : 0;
|
||||
if (result != expect) {
|
||||
printf("FAIL line %d: '%s' vs '%s' expected %s\n", line, pattern, text, expect ? "match" : "no match");
|
||||
failed++;
|
||||
} else {
|
||||
passed++;
|
||||
}
|
||||
loreg_free(re);
|
||||
lorex_free(re);
|
||||
}
|
||||
|
||||
static void test_literals(void) {
|
||||
@@ -613,8 +613,240 @@ static void test_pathological_patterns(void) {
|
||||
MATCH("(a?){5}a{5}", "aaaaa");
|
||||
}
|
||||
|
||||
static void test_anchored_match(void) {
|
||||
printf(" anchored match (lorex_match)...\n");
|
||||
lorex_error_t err;
|
||||
lorex_match_t m;
|
||||
|
||||
lorex_regex_t *re = lorex_compile("abc", &err);
|
||||
if (re) {
|
||||
if (lorex_match(re, "abc", &m)) {
|
||||
passed++;
|
||||
} else {
|
||||
printf("FAIL: lorex_match should match 'abc' against 'abc'\n");
|
||||
failed++;
|
||||
}
|
||||
if (!lorex_match(re, "xabc", &m)) {
|
||||
passed++;
|
||||
} else {
|
||||
printf("FAIL: lorex_match should not match 'abc' against 'xabc'\n");
|
||||
failed++;
|
||||
}
|
||||
if (lorex_match(re, "abcx", &m)) {
|
||||
passed++;
|
||||
} else {
|
||||
printf("FAIL: lorex_match should match 'abc' at start of 'abcx'\n");
|
||||
failed++;
|
||||
}
|
||||
lorex_free(re);
|
||||
}
|
||||
|
||||
re = lorex_compile("^abc$", &err);
|
||||
if (re) {
|
||||
if (lorex_match(re, "abc", &m)) {
|
||||
passed++;
|
||||
} else {
|
||||
printf("FAIL: lorex_match should match '^abc$' against 'abc'\n");
|
||||
failed++;
|
||||
}
|
||||
if (!lorex_match(re, "abcx", &m)) {
|
||||
passed++;
|
||||
} else {
|
||||
printf("FAIL: lorex_match should not match '^abc$' against 'abcx'\n");
|
||||
failed++;
|
||||
}
|
||||
lorex_free(re);
|
||||
}
|
||||
|
||||
re = lorex_compile("a.*z", &err);
|
||||
if (re) {
|
||||
if (lorex_match(re, "abcz", &m)) {
|
||||
passed++;
|
||||
} else {
|
||||
printf("FAIL: lorex_match should match 'a.*z' against 'abcz'\n");
|
||||
failed++;
|
||||
}
|
||||
if (!lorex_match(re, "xabcz", &m)) {
|
||||
passed++;
|
||||
} else {
|
||||
printf("FAIL: lorex_match should not match 'a.*z' against 'xabcz'\n");
|
||||
failed++;
|
||||
}
|
||||
lorex_free(re);
|
||||
}
|
||||
}
|
||||
|
||||
static void test_error_strings(void) {
|
||||
printf(" error strings...\n");
|
||||
|
||||
if (strcmp(lorex_error_string(LOREX_OK), "success") == 0) {
|
||||
passed++;
|
||||
} else {
|
||||
printf("FAIL: LOREX_OK should return 'success'\n");
|
||||
failed++;
|
||||
}
|
||||
|
||||
if (strcmp(lorex_error_string(LOREX_ERR_INVALID_PATTERN), "invalid pattern") == 0) {
|
||||
passed++;
|
||||
} else {
|
||||
printf("FAIL: LOREX_ERR_INVALID_PATTERN error string\n");
|
||||
failed++;
|
||||
}
|
||||
|
||||
if (strcmp(lorex_error_string(LOREX_ERR_UNBALANCED_PAREN), "unbalanced parentheses") == 0) {
|
||||
passed++;
|
||||
} else {
|
||||
printf("FAIL: LOREX_ERR_UNBALANCED_PAREN error string\n");
|
||||
failed++;
|
||||
}
|
||||
|
||||
if (strcmp(lorex_error_string(LOREX_ERR_EMPTY_GROUP), "empty group") == 0) {
|
||||
passed++;
|
||||
} else {
|
||||
printf("FAIL: LOREX_ERR_EMPTY_GROUP error string\n");
|
||||
failed++;
|
||||
}
|
||||
|
||||
if (strcmp(lorex_error_string(LOREX_ERR_INVALID_QUANTIFIER), "invalid quantifier") == 0) {
|
||||
passed++;
|
||||
} else {
|
||||
printf("FAIL: LOREX_ERR_INVALID_QUANTIFIER error string\n");
|
||||
failed++;
|
||||
}
|
||||
|
||||
if (strcmp(lorex_error_string(LOREX_ERR_INVALID_ESCAPE), "invalid escape sequence") == 0) {
|
||||
passed++;
|
||||
} else {
|
||||
printf("FAIL: LOREX_ERR_INVALID_ESCAPE error string\n");
|
||||
failed++;
|
||||
}
|
||||
|
||||
if (strcmp(lorex_error_string(LOREX_ERR_OUT_OF_MEMORY), "out of memory") == 0) {
|
||||
passed++;
|
||||
} else {
|
||||
printf("FAIL: LOREX_ERR_OUT_OF_MEMORY error string\n");
|
||||
failed++;
|
||||
}
|
||||
|
||||
if (strcmp(lorex_error_string(LOREX_ERR_STATE_OVERFLOW), "state overflow") == 0) {
|
||||
passed++;
|
||||
} else {
|
||||
printf("FAIL: LOREX_ERR_STATE_OVERFLOW error string\n");
|
||||
failed++;
|
||||
}
|
||||
|
||||
if (strcmp(lorex_error_string((lorex_error_t)99), "unknown error") == 0) {
|
||||
passed++;
|
||||
} else {
|
||||
printf("FAIL: unknown error code should return 'unknown error'\n");
|
||||
failed++;
|
||||
}
|
||||
}
|
||||
|
||||
static void test_parser_errors(void) {
|
||||
printf(" parser errors...\n");
|
||||
lorex_error_t err;
|
||||
lorex_regex_t *re;
|
||||
|
||||
re = lorex_compile("(abc", &err);
|
||||
if (re == NULL && err == LOREX_ERR_UNBALANCED_PAREN) {
|
||||
passed++;
|
||||
} else {
|
||||
printf("FAIL: '(abc' should fail with unbalanced paren\n");
|
||||
failed++;
|
||||
if (re) lorex_free(re);
|
||||
}
|
||||
|
||||
re = lorex_compile("((a)", &err);
|
||||
if (re == NULL && err == LOREX_ERR_UNBALANCED_PAREN) {
|
||||
passed++;
|
||||
} else {
|
||||
printf("FAIL: '((a)' should fail with unbalanced paren\n");
|
||||
failed++;
|
||||
if (re) lorex_free(re);
|
||||
}
|
||||
|
||||
re = lorex_compile("a{5,2}", &err);
|
||||
if (re == NULL) {
|
||||
passed++;
|
||||
} else {
|
||||
printf("FAIL: 'a{5,2}' should fail (min > max)\n");
|
||||
failed++;
|
||||
lorex_free(re);
|
||||
}
|
||||
|
||||
re = lorex_compile("*abc", &err);
|
||||
if (re == NULL) {
|
||||
passed++;
|
||||
} else {
|
||||
printf("FAIL: '*abc' should fail\n");
|
||||
failed++;
|
||||
lorex_free(re);
|
||||
}
|
||||
|
||||
re = lorex_compile("+abc", &err);
|
||||
if (re == NULL) {
|
||||
passed++;
|
||||
} else {
|
||||
printf("FAIL: '+abc' should fail\n");
|
||||
failed++;
|
||||
lorex_free(re);
|
||||
}
|
||||
|
||||
re = lorex_compile("?abc", &err);
|
||||
if (re == NULL) {
|
||||
passed++;
|
||||
} else {
|
||||
printf("FAIL: '?abc' should fail\n");
|
||||
failed++;
|
||||
lorex_free(re);
|
||||
}
|
||||
}
|
||||
|
||||
static void test_bracket_char_classes(void) {
|
||||
printf(" bracket character classes...\n");
|
||||
MATCH("[\\d]", "5");
|
||||
MATCH("[\\d]+", "12345");
|
||||
NO_MATCH("[\\d]", "a");
|
||||
MATCH("[\\w]", "a");
|
||||
MATCH("[\\w]", "Z");
|
||||
MATCH("[\\w]", "5");
|
||||
MATCH("[\\w]", "_");
|
||||
NO_MATCH("[\\w]", " ");
|
||||
MATCH("[\\s]", " ");
|
||||
MATCH("[\\s]", "\t");
|
||||
NO_MATCH("[\\s]", "a");
|
||||
MATCH("[a\\d]", "a");
|
||||
MATCH("[a\\d]", "5");
|
||||
NO_MATCH("[a\\d]", "b");
|
||||
MATCH("[\\da-z]", "5");
|
||||
MATCH("[\\da-z]", "m");
|
||||
NO_MATCH("[\\da-z]", "M");
|
||||
MATCH("[\\w\\s]+", "hello world");
|
||||
MATCH("[0-9\\s]+", "1 2 3");
|
||||
MATCH("[\\w-]+", "hello-world");
|
||||
}
|
||||
|
||||
static void test_special_escapes(void) {
|
||||
printf(" special escape sequences...\n");
|
||||
MATCH("\\n", "\n");
|
||||
MATCH("a\\nb", "a\nb");
|
||||
MATCH("\\t", "\t");
|
||||
MATCH("a\\tb", "a\tb");
|
||||
MATCH("\\r", "\r");
|
||||
MATCH("a\\rb", "a\rb");
|
||||
MATCH("\\n\\t\\r", "\n\t\r");
|
||||
MATCH("[\\n]", "\n");
|
||||
MATCH("[\\t]", "\t");
|
||||
MATCH("[\\r]", "\r");
|
||||
MATCH("[\\n\\t]+", "\n\t\n");
|
||||
NO_MATCH("\\n", "n");
|
||||
NO_MATCH("\\t", "t");
|
||||
NO_MATCH("\\r", "r");
|
||||
}
|
||||
|
||||
int main(void) {
|
||||
printf("loreg integration tests\n");
|
||||
printf("lorex integration tests\n");
|
||||
printf("=======================\n\n");
|
||||
|
||||
test_literals();
|
||||
@@ -641,6 +873,11 @@ int main(void) {
|
||||
test_nested_groups();
|
||||
test_real_world_patterns();
|
||||
test_pathological_patterns();
|
||||
test_anchored_match();
|
||||
test_error_strings();
|
||||
test_parser_errors();
|
||||
test_bracket_char_classes();
|
||||
test_special_escapes();
|
||||
|
||||
printf("\n=======================\n");
|
||||
printf("integration: %d passed, %d failed\n", passed, failed);
|
||||
|
||||
+31
-31
@@ -1,5 +1,5 @@
|
||||
/* retoor <retoor@molodetz.nl> */
|
||||
#include "../include/loreg.h"
|
||||
#include "../include/lorex.h"
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
@@ -23,21 +23,21 @@ static int tests_failed = 0;
|
||||
} while(0)
|
||||
|
||||
#define ASSERT_MATCH(pattern, text) do { \
|
||||
loreg_error_t err; \
|
||||
loreg_regex_t *re = loreg_compile(pattern, &err); \
|
||||
lorex_error_t err; \
|
||||
lorex_regex_t *re = lorex_compile(pattern, &err); \
|
||||
ASSERT(re != NULL); \
|
||||
loreg_match_t result; \
|
||||
ASSERT(loreg_search(re, text, &result) == true); \
|
||||
loreg_free(re); \
|
||||
lorex_match_t result; \
|
||||
ASSERT(lorex_search(re, text, &result) == true); \
|
||||
lorex_free(re); \
|
||||
} while(0)
|
||||
|
||||
#define ASSERT_NO_MATCH(pattern, text) do { \
|
||||
loreg_error_t err; \
|
||||
loreg_regex_t *re = loreg_compile(pattern, &err); \
|
||||
lorex_error_t err; \
|
||||
lorex_regex_t *re = lorex_compile(pattern, &err); \
|
||||
ASSERT(re != NULL); \
|
||||
loreg_match_t result; \
|
||||
ASSERT(loreg_search(re, text, &result) == false); \
|
||||
loreg_free(re); \
|
||||
lorex_match_t result; \
|
||||
ASSERT(lorex_search(re, text, &result) == false); \
|
||||
lorex_free(re); \
|
||||
} while(0)
|
||||
|
||||
TEST(simple_char) {
|
||||
@@ -209,53 +209,53 @@ TEST(complex_url) {
|
||||
}
|
||||
|
||||
TEST(group_capture) {
|
||||
loreg_error_t err;
|
||||
loreg_regex_t *re = loreg_compile("(\\d+)-(\\d+)", &err);
|
||||
lorex_error_t err;
|
||||
lorex_regex_t *re = lorex_compile("(\\d+)-(\\d+)", &err);
|
||||
ASSERT(re != NULL);
|
||||
|
||||
loreg_match_t result;
|
||||
ASSERT(loreg_search(re, "123-456", &result));
|
||||
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);
|
||||
|
||||
loreg_free(re);
|
||||
lorex_free(re);
|
||||
}
|
||||
|
||||
TEST(nested_groups) {
|
||||
loreg_error_t err;
|
||||
loreg_regex_t *re = loreg_compile("((a)(b))", &err);
|
||||
lorex_error_t err;
|
||||
lorex_regex_t *re = lorex_compile("((a)(b))", &err);
|
||||
ASSERT(re != NULL);
|
||||
|
||||
loreg_match_t result;
|
||||
ASSERT(loreg_search(re, "ab", &result));
|
||||
lorex_match_t result;
|
||||
ASSERT(lorex_search(re, "ab", &result));
|
||||
ASSERT(result.group_count == 3);
|
||||
|
||||
loreg_free(re);
|
||||
lorex_free(re);
|
||||
}
|
||||
|
||||
TEST(empty_pattern) {
|
||||
loreg_error_t err;
|
||||
loreg_regex_t *re = loreg_compile("", &err);
|
||||
lorex_error_t err;
|
||||
lorex_regex_t *re = lorex_compile("", &err);
|
||||
ASSERT(re != NULL);
|
||||
|
||||
loreg_match_t result;
|
||||
ASSERT(loreg_match(re, "anything", &result));
|
||||
lorex_match_t result;
|
||||
ASSERT(lorex_match(re, "anything", &result));
|
||||
|
||||
loreg_free(re);
|
||||
lorex_free(re);
|
||||
}
|
||||
|
||||
TEST(match_position) {
|
||||
loreg_error_t err;
|
||||
loreg_regex_t *re = loreg_compile("test", &err);
|
||||
lorex_error_t err;
|
||||
lorex_regex_t *re = lorex_compile("test", &err);
|
||||
ASSERT(re != NULL);
|
||||
|
||||
loreg_match_t result;
|
||||
ASSERT(loreg_search(re, "xxxtestyyy", &result));
|
||||
lorex_match_t result;
|
||||
ASSERT(lorex_search(re, "xxxtestyyy", &result));
|
||||
ASSERT(result.match_start == 3);
|
||||
ASSERT(result.match_end == 7);
|
||||
|
||||
loreg_free(re);
|
||||
lorex_free(re);
|
||||
}
|
||||
|
||||
int main(void) {
|
||||
|
||||
+2
-2
@@ -27,11 +27,11 @@ static nfa_t *compile_pattern(const char *pattern) {
|
||||
parser_t parser;
|
||||
parser_init(&parser, pattern);
|
||||
ast_node_t *ast = parser_parse(&parser);
|
||||
if (!ast || parser_get_error(&parser) != LOREG_OK) {
|
||||
if (!ast || parser_get_error(&parser) != LOREX_OK) {
|
||||
ast_free(ast);
|
||||
return NULL;
|
||||
}
|
||||
loreg_error_t error;
|
||||
lorex_error_t error;
|
||||
nfa_t *nfa = nfa_from_ast(ast, &error);
|
||||
ast_free(ast);
|
||||
return nfa;
|
||||
|
||||
+2
-2
@@ -245,7 +245,7 @@ TEST(complex_pattern) {
|
||||
ast_node_t *ast = parser_parse(&parser);
|
||||
|
||||
ASSERT(ast != NULL);
|
||||
ASSERT(parser_get_error(&parser) == LOREG_OK);
|
||||
ASSERT(parser_get_error(&parser) == LOREX_OK);
|
||||
|
||||
ast_free(ast);
|
||||
}
|
||||
@@ -255,7 +255,7 @@ TEST(unbalanced_paren) {
|
||||
parser_init(&parser, "(abc");
|
||||
ast_node_t *ast = parser_parse(&parser);
|
||||
|
||||
ASSERT(ast == NULL || parser_get_error(&parser) == LOREG_ERR_UNBALANCED_PAREN);
|
||||
ASSERT(ast == NULL || parser_get_error(&parser) == LOREX_ERR_UNBALANCED_PAREN);
|
||||
|
||||
ast_free(ast);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user