/* 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;
}