|
/* retoor <retoor@molodetz.nl> */
|
|
#include "../include/parser.h"
|
|
#include <stdio.h>
|
|
#include <assert.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)
|
|
|
|
TEST(single_char) {
|
|
parser_t parser;
|
|
parser_init(&parser, "a");
|
|
ast_node_t *ast = parser_parse(&parser);
|
|
|
|
ASSERT(ast != NULL);
|
|
ASSERT(ast->type == AST_CHAR);
|
|
ASSERT(ast->value == 'a');
|
|
|
|
ast_free(ast);
|
|
}
|
|
|
|
TEST(concat) {
|
|
parser_t parser;
|
|
parser_init(&parser, "ab");
|
|
ast_node_t *ast = parser_parse(&parser);
|
|
|
|
ASSERT(ast != NULL);
|
|
ASSERT(ast->type == AST_CONCAT);
|
|
ASSERT(ast->left->type == AST_CHAR);
|
|
ASSERT(ast->left->value == 'a');
|
|
ASSERT(ast->right->type == AST_CHAR);
|
|
ASSERT(ast->right->value == 'b');
|
|
|
|
ast_free(ast);
|
|
}
|
|
|
|
TEST(alternation) {
|
|
parser_t parser;
|
|
parser_init(&parser, "a|b");
|
|
ast_node_t *ast = parser_parse(&parser);
|
|
|
|
ASSERT(ast != NULL);
|
|
ASSERT(ast->type == AST_ALTER);
|
|
ASSERT(ast->left->type == AST_CHAR);
|
|
ASSERT(ast->left->value == 'a');
|
|
ASSERT(ast->right->type == AST_CHAR);
|
|
ASSERT(ast->right->value == 'b');
|
|
|
|
ast_free(ast);
|
|
}
|
|
|
|
TEST(star) {
|
|
parser_t parser;
|
|
parser_init(&parser, "a*");
|
|
ast_node_t *ast = parser_parse(&parser);
|
|
|
|
ASSERT(ast != NULL);
|
|
ASSERT(ast->type == AST_STAR);
|
|
ASSERT(ast->left->type == AST_CHAR);
|
|
ASSERT(ast->left->value == 'a');
|
|
|
|
ast_free(ast);
|
|
}
|
|
|
|
TEST(plus) {
|
|
parser_t parser;
|
|
parser_init(&parser, "a+");
|
|
ast_node_t *ast = parser_parse(&parser);
|
|
|
|
ASSERT(ast != NULL);
|
|
ASSERT(ast->type == AST_PLUS);
|
|
ASSERT(ast->left->type == AST_CHAR);
|
|
ASSERT(ast->left->value == 'a');
|
|
|
|
ast_free(ast);
|
|
}
|
|
|
|
TEST(question) {
|
|
parser_t parser;
|
|
parser_init(&parser, "a?");
|
|
ast_node_t *ast = parser_parse(&parser);
|
|
|
|
ASSERT(ast != NULL);
|
|
ASSERT(ast->type == AST_QUESTION);
|
|
ASSERT(ast->left->type == AST_CHAR);
|
|
ASSERT(ast->left->value == 'a');
|
|
|
|
ast_free(ast);
|
|
}
|
|
|
|
TEST(group) {
|
|
parser_t parser;
|
|
parser_init(&parser, "(ab)");
|
|
ast_node_t *ast = parser_parse(&parser);
|
|
|
|
ASSERT(ast != NULL);
|
|
ASSERT(ast->type == AST_GROUP);
|
|
ASSERT(ast->group_id == 0);
|
|
ASSERT(ast->left->type == AST_CONCAT);
|
|
|
|
ast_free(ast);
|
|
}
|
|
|
|
TEST(dot) {
|
|
parser_t parser;
|
|
parser_init(&parser, ".");
|
|
ast_node_t *ast = parser_parse(&parser);
|
|
|
|
ASSERT(ast != NULL);
|
|
ASSERT(ast->type == AST_DOT);
|
|
|
|
ast_free(ast);
|
|
}
|
|
|
|
TEST(anchors) {
|
|
parser_t parser;
|
|
parser_init(&parser, "^a$");
|
|
ast_node_t *ast = parser_parse(&parser);
|
|
|
|
ASSERT(ast != NULL);
|
|
ASSERT(ast->type == AST_CONCAT);
|
|
|
|
ast_free(ast);
|
|
}
|
|
|
|
TEST(bracket_simple) {
|
|
parser_t parser;
|
|
parser_init(&parser, "[abc]");
|
|
ast_node_t *ast = parser_parse(&parser);
|
|
|
|
ASSERT(ast != NULL);
|
|
ASSERT(ast->type == AST_BRACKET);
|
|
ASSERT(ast->bracket != NULL);
|
|
ASSERT(ast->bracket->count == 3);
|
|
|
|
ast_free(ast);
|
|
}
|
|
|
|
TEST(bracket_range) {
|
|
parser_t parser;
|
|
parser_init(&parser, "[a-z]");
|
|
ast_node_t *ast = parser_parse(&parser);
|
|
|
|
ASSERT(ast != NULL);
|
|
ASSERT(ast->type == AST_BRACKET);
|
|
ASSERT(ast->bracket != NULL);
|
|
ASSERT(ast->bracket->count == 1);
|
|
ASSERT(ast->bracket->ranges[0].start == 'a');
|
|
ASSERT(ast->bracket->ranges[0].end == 'z');
|
|
|
|
ast_free(ast);
|
|
}
|
|
|
|
TEST(bracket_negated) {
|
|
parser_t parser;
|
|
parser_init(&parser, "[^a]");
|
|
ast_node_t *ast = parser_parse(&parser);
|
|
|
|
ASSERT(ast != NULL);
|
|
ASSERT(ast->type == AST_BRACKET);
|
|
ASSERT(ast->bracket->negated == true);
|
|
|
|
ast_free(ast);
|
|
}
|
|
|
|
TEST(quantifier_exact) {
|
|
parser_t parser;
|
|
parser_init(&parser, "a{3}");
|
|
ast_node_t *ast = parser_parse(&parser);
|
|
|
|
ASSERT(ast != NULL);
|
|
ASSERT(ast->type == AST_QUANTIFIER);
|
|
ASSERT(ast->quant.min == 3);
|
|
ASSERT(ast->quant.max == 3);
|
|
|
|
ast_free(ast);
|
|
}
|
|
|
|
TEST(quantifier_range) {
|
|
parser_t parser;
|
|
parser_init(&parser, "a{2,5}");
|
|
ast_node_t *ast = parser_parse(&parser);
|
|
|
|
ASSERT(ast != NULL);
|
|
ASSERT(ast->type == AST_QUANTIFIER);
|
|
ASSERT(ast->quant.min == 2);
|
|
ASSERT(ast->quant.max == 5);
|
|
|
|
ast_free(ast);
|
|
}
|
|
|
|
TEST(quantifier_open) {
|
|
parser_t parser;
|
|
parser_init(&parser, "a{2,}");
|
|
ast_node_t *ast = parser_parse(&parser);
|
|
|
|
ASSERT(ast != NULL);
|
|
ASSERT(ast->type == AST_QUANTIFIER);
|
|
ASSERT(ast->quant.min == 2);
|
|
ASSERT(ast->quant.max == -1);
|
|
|
|
ast_free(ast);
|
|
}
|
|
|
|
TEST(character_class_digit) {
|
|
parser_t parser;
|
|
parser_init(&parser, "\\d");
|
|
ast_node_t *ast = parser_parse(&parser);
|
|
|
|
ASSERT(ast != NULL);
|
|
ASSERT(ast->type == AST_CLASS_DIGIT);
|
|
|
|
ast_free(ast);
|
|
}
|
|
|
|
TEST(character_class_word) {
|
|
parser_t parser;
|
|
parser_init(&parser, "\\w");
|
|
ast_node_t *ast = parser_parse(&parser);
|
|
|
|
ASSERT(ast != NULL);
|
|
ASSERT(ast->type == AST_CLASS_WORD);
|
|
|
|
ast_free(ast);
|
|
}
|
|
|
|
TEST(complex_pattern) {
|
|
parser_t parser;
|
|
parser_init(&parser, "^([a-z]+)@([a-z]+)\\.([a-z]{2,})$");
|
|
ast_node_t *ast = parser_parse(&parser);
|
|
|
|
ASSERT(ast != NULL);
|
|
ASSERT(parser_get_error(&parser) == LOREX_OK);
|
|
|
|
ast_free(ast);
|
|
}
|
|
|
|
TEST(unbalanced_paren) {
|
|
parser_t parser;
|
|
parser_init(&parser, "(abc");
|
|
ast_node_t *ast = parser_parse(&parser);
|
|
|
|
ASSERT(ast == NULL || parser_get_error(&parser) == LOREX_ERR_UNBALANCED_PAREN);
|
|
|
|
ast_free(ast);
|
|
}
|
|
|
|
TEST(non_greedy) {
|
|
parser_t parser;
|
|
parser_init(&parser, "a*?");
|
|
ast_node_t *ast = parser_parse(&parser);
|
|
|
|
ASSERT(ast != NULL);
|
|
ASSERT(ast->type == AST_STAR);
|
|
ASSERT(ast->quant.greedy == false);
|
|
|
|
ast_free(ast);
|
|
}
|
|
|
|
int main(void) {
|
|
printf("parser tests:\n");
|
|
|
|
RUN_TEST(single_char);
|
|
RUN_TEST(concat);
|
|
RUN_TEST(alternation);
|
|
RUN_TEST(star);
|
|
RUN_TEST(plus);
|
|
RUN_TEST(question);
|
|
RUN_TEST(group);
|
|
RUN_TEST(dot);
|
|
RUN_TEST(anchors);
|
|
RUN_TEST(bracket_simple);
|
|
RUN_TEST(bracket_range);
|
|
RUN_TEST(bracket_negated);
|
|
RUN_TEST(quantifier_exact);
|
|
RUN_TEST(quantifier_range);
|
|
RUN_TEST(quantifier_open);
|
|
RUN_TEST(character_class_digit);
|
|
RUN_TEST(character_class_word);
|
|
RUN_TEST(complex_pattern);
|
|
RUN_TEST(unbalanced_paren);
|
|
RUN_TEST(non_greedy);
|
|
|
|
printf("\nparser: %d passed, %d failed\n", tests_passed, tests_failed);
|
|
return tests_failed > 0 ? 1 : 0;
|
|
}
|