/* * Copyright (c) Camden Dixie O'Brien * SPDX-License-Identifier: AGPL-3.0-only */ #include "desugar.h" #include "testing.h" #include static void a_is_unchanged(void) { regex_term_t *terms = malloc(1 * sizeof(regex_term_t)); terms[0].quantifier = REGEX_QUANTIFIER_NONE; terms[0].type = REGEX_TERM_LITERAL; terms[0].literal = 'a'; regex_sequence_t *alternatives = malloc(1 * sizeof(regex_sequence_t)); alternatives[0].count = alternatives[0].capacity = 1; alternatives[0].contents = terms; regex_t t = { .count = 1, .capacity = 1, .contents = alternatives }; desugar_regex(&t); ASSERT_EQ(1, t.count); ASSERT_NOT_NULL(t.contents); ASSERT_EQ(1, t.contents[0].count); ASSERT_NOT_NULL(t.contents[0].contents); ASSERT_EQ(REGEX_QUANTIFIER_NONE, t.contents[0].contents[0].quantifier); ASSERT_EQ(REGEX_TERM_LITERAL, t.contents[0].contents[0].type); ASSERT_EQ('a', t.contents[0].contents[0].literal); regex_free(&t); } static void abc_is_unchanged(void) { regex_term_t *terms = malloc(3 * sizeof(regex_term_t)); terms[0].type = REGEX_TERM_LITERAL; terms[0].literal = 'a'; terms[1].type = REGEX_TERM_LITERAL; terms[1].literal = 'b'; terms[2].type = REGEX_TERM_LITERAL; terms[2].literal = 'c'; regex_sequence_t *alternatives = malloc(1 * sizeof(regex_sequence_t)); alternatives[0].count = alternatives[0].capacity = 3; alternatives[0].contents = terms; regex_t t = { .count = 1, .capacity = 1, .contents = alternatives }; desugar_regex(&t); ASSERT_EQ(1, t.count); ASSERT_NOT_NULL(t.contents); ASSERT_EQ(3, t.contents[0].count); ASSERT_NOT_NULL(t.contents[0].contents); ASSERT_EQ(REGEX_TERM_LITERAL, t.contents[0].contents[0].type); ASSERT_EQ('a', t.contents[0].contents[0].literal); ASSERT_NOT_NULL(t.contents[0].contents); ASSERT_EQ(REGEX_TERM_LITERAL, t.contents[0].contents[1].type); ASSERT_EQ('b', t.contents[0].contents[1].literal); ASSERT_NOT_NULL(t.contents[0].contents); ASSERT_EQ(REGEX_TERM_LITERAL, t.contents[0].contents[2].type); ASSERT_EQ('c', t.contents[0].contents[2].literal); regex_free(&t); } static void a_star_is_unchanged(void) { regex_term_t *terms = malloc(1 * sizeof(regex_term_t)); terms[0].quantifier = REGEX_QUANTIFIER_STAR; terms[0].type = REGEX_TERM_LITERAL; terms[0].literal = 'a'; regex_sequence_t *alternatives = malloc(1 * sizeof(regex_sequence_t)); alternatives[0].count = alternatives[0].capacity = 1; alternatives[0].contents = terms; regex_t t = { .count = 1, .capacity = 1, .contents = alternatives }; desugar_regex(&t); ASSERT_EQ(1, t.count); ASSERT_NOT_NULL(t.contents); ASSERT_EQ(1, t.contents[0].count); ASSERT_NOT_NULL(t.contents[0].contents); ASSERT_EQ(REGEX_QUANTIFIER_STAR, t.contents[0].contents[0].quantifier); ASSERT_EQ(REGEX_TERM_LITERAL, t.contents[0].contents[0].type); ASSERT_EQ('a', t.contents[0].contents[0].literal); regex_free(&t); } static void a_or_b_or_c_is_unchanged(void) { const char *literals = "abc"; regex_sequence_t *alternatives = malloc(3 * sizeof(regex_sequence_t)); for (int i = 0; i < 3; ++i) { regex_term_t *terms = malloc(1 * sizeof(regex_term_t)); terms[0].quantifier = REGEX_QUANTIFIER_NONE; terms[0].type = REGEX_TERM_LITERAL; terms[0].literal = literals[i]; alternatives[i].count = alternatives[i].capacity = 1; alternatives[i].contents = terms; } regex_t t = { .count = 3, .capacity = 3, .contents = alternatives }; desugar_regex(&t); ASSERT_EQ(3, t.count); ASSERT_NOT_NULL(t.contents); for (int i = 0; i < 3; ++i) { ASSERT_EQ(1, t.contents[i].count); ASSERT_NOT_NULL(t.contents[i].contents); ASSERT_EQ( REGEX_QUANTIFIER_NONE, t.contents[i].contents[0].quantifier); ASSERT_EQ(REGEX_TERM_LITERAL, t.contents[i].contents[0].type); ASSERT_EQ(literals[i], t.contents[i].contents[0].literal); } regex_free(&t); } static void subexpr_a_is_unchanged(void) { regex_term_t *inner_terms = malloc(1 * sizeof(regex_term_t)); inner_terms[0].quantifier = REGEX_QUANTIFIER_NONE; inner_terms[0].type = REGEX_TERM_LITERAL; inner_terms[0].literal = 'a'; regex_sequence_t *inner_alternatives = malloc(1 * sizeof(regex_sequence_t)); inner_alternatives[0].count = inner_alternatives[0].capacity = 1; inner_alternatives[0].contents = inner_terms; regex_term_t *terms = malloc(1 * sizeof(regex_term_t)); terms[0].quantifier = REGEX_QUANTIFIER_NONE; terms[0].type = REGEX_TERM_SUBEXPR; terms[0].subexpr.count = terms[0].subexpr.capacity = 1; terms[0].subexpr.contents = inner_alternatives; regex_sequence_t *alternatives = malloc(1 * sizeof(regex_sequence_t)); alternatives[0].count = alternatives[0].capacity = 1; alternatives[0].contents = terms; regex_t t = { .count = 1, .capacity = 1, .contents = alternatives }; desugar_regex(&t); ASSERT_EQ(1, t.count); ASSERT_NOT_NULL(t.contents); ASSERT_EQ(1, t.contents[0].count); ASSERT_NOT_NULL(t.contents[0].contents); ASSERT_EQ(REGEX_QUANTIFIER_NONE, t.contents[0].contents[0].quantifier); ASSERT_EQ(REGEX_TERM_SUBEXPR, t.contents[0].contents[0].type); const regex_t *inner = &t.contents[0].contents[0].subexpr; ASSERT_EQ(1, inner->count); ASSERT_NOT_NULL(inner->contents); ASSERT_EQ(1, inner->contents[0].count); ASSERT_NOT_NULL(inner->contents[0].contents); ASSERT_EQ( REGEX_QUANTIFIER_NONE, inner->contents[0].contents[0].quantifier); ASSERT_EQ(REGEX_TERM_LITERAL, inner->contents[0].contents[0].type); ASSERT_EQ('a', inner->contents[0].contents[0].literal); regex_free(&t); } static void a_plus_becomes_subexpr_aa_star(void) { regex_term_t *terms = malloc(1 * sizeof(regex_term_t)); terms[0].quantifier = REGEX_QUANTIFIER_PLUS; terms[0].type = REGEX_TERM_LITERAL; terms[0].literal = 'a'; regex_sequence_t *alternatives = malloc(1 * sizeof(regex_sequence_t)); alternatives[0].count = alternatives[0].capacity = 1; alternatives[0].contents = terms; regex_t t = { .count = 1, .capacity = 1, .contents = alternatives }; desugar_regex(&t); ASSERT_EQ(1, t.count); ASSERT_NOT_NULL(t.contents); ASSERT_EQ(1, t.contents[0].count); ASSERT_NOT_NULL(t.contents[0].contents); ASSERT_EQ(REGEX_QUANTIFIER_NONE, t.contents[0].contents[0].quantifier); ASSERT_EQ(REGEX_TERM_SUBEXPR, t.contents[0].contents[0].type); const regex_t *inner = &t.contents[0].contents[0].subexpr; ASSERT_EQ(1, inner->count); ASSERT_NOT_NULL(inner->contents); ASSERT_EQ(2, inner->contents[0].count); ASSERT_NOT_NULL(inner->contents[0].contents); ASSERT_EQ( REGEX_QUANTIFIER_NONE, inner->contents[0].contents[0].quantifier); ASSERT_EQ(REGEX_TERM_LITERAL, inner->contents[0].contents[0].type); ASSERT_EQ('a', inner->contents[0].contents[0].literal); ASSERT_EQ( REGEX_QUANTIFIER_STAR, inner->contents[0].contents[1].quantifier); ASSERT_EQ(REGEX_TERM_LITERAL, inner->contents[0].contents[1].type); ASSERT_EQ('a', inner->contents[0].contents[1].literal); regex_free(&t); } static void a_qmark_becomes_subexpr_empty_or_a(void) { regex_term_t *terms = malloc(1 * sizeof(regex_term_t)); terms[0].quantifier = REGEX_QUANTIFIER_QMARK; terms[0].type = REGEX_TERM_LITERAL; terms[0].literal = 'a'; regex_sequence_t *alternatives = malloc(1 * sizeof(regex_sequence_t)); alternatives[0].count = alternatives[0].capacity = 1; alternatives[0].contents = terms; regex_t t = { .count = 1, .capacity = 1, .contents = alternatives }; desugar_regex(&t); ASSERT_EQ(1, t.count); ASSERT_NOT_NULL(t.contents); ASSERT_EQ(1, t.contents[0].count); ASSERT_NOT_NULL(t.contents[0].contents); ASSERT_EQ(REGEX_QUANTIFIER_NONE, t.contents[0].contents[0].quantifier); ASSERT_EQ(REGEX_TERM_SUBEXPR, t.contents[0].contents[0].type); const regex_t *inner = &t.contents[0].contents[0].subexpr; ASSERT_EQ(2, inner->count); ASSERT_NOT_NULL(inner->contents); ASSERT_EQ(1, inner->contents[0].count); ASSERT_NOT_NULL(inner->contents[0].contents); ASSERT_EQ( REGEX_QUANTIFIER_NONE, inner->contents[0].contents[0].quantifier); ASSERT_EQ(REGEX_TERM_EMPTY, inner->contents[0].contents[0].type); ASSERT_EQ(1, inner->contents[1].count); ASSERT_NOT_NULL(inner->contents[1].contents); ASSERT_EQ( REGEX_QUANTIFIER_NONE, inner->contents[1].contents[0].quantifier); ASSERT_EQ(REGEX_TERM_LITERAL, inner->contents[1].contents[0].type); ASSERT_EQ('a', inner->contents[1].contents[0].literal); regex_free(&t); } static void class_abc_becomes_subexpr_a_or_b_or_c(void) { char *options = malloc(3 * sizeof(char)); options[0] = 'a'; options[1] = 'b'; options[2] = 'c'; regex_term_t *terms = malloc(1 * sizeof(regex_term_t)); terms[0].quantifier = REGEX_QUANTIFIER_NONE; terms[0].type = REGEX_TERM_CLASS; terms[0].class.negated = false; terms[0].class.count = terms[0].class.capacity = 3; terms[0].class.contents = options; regex_sequence_t *alternatives = malloc(1 * sizeof(regex_sequence_t)); alternatives[0].count = alternatives[0].capacity = 1; alternatives[0].contents = terms; regex_t t = { .count = 1, .capacity = 1, .contents = alternatives }; desugar_regex(&t); ASSERT_EQ(1, t.count); ASSERT_NOT_NULL(t.contents); ASSERT_EQ(1, t.contents[0].count); ASSERT_NOT_NULL(t.contents[0].contents); ASSERT_EQ(REGEX_QUANTIFIER_NONE, t.contents[0].contents[0].quantifier); ASSERT_EQ(REGEX_TERM_SUBEXPR, t.contents[0].contents[0].type); const regex_t *inner = &t.contents[0].contents[0].subexpr; ASSERT_EQ(3, inner->count); ASSERT_NOT_NULL(inner->contents); ASSERT_EQ(1, inner->contents[0].count); ASSERT_NOT_NULL(inner->contents[0].contents); ASSERT_EQ( REGEX_QUANTIFIER_NONE, inner->contents[0].contents[0].quantifier); ASSERT_EQ(REGEX_TERM_LITERAL, inner->contents[0].contents[0].type); ASSERT_EQ('a', inner->contents[0].contents[0].literal); ASSERT_EQ(1, inner->contents[1].count); ASSERT_NOT_NULL(inner->contents[1].contents); ASSERT_EQ( REGEX_QUANTIFIER_NONE, inner->contents[1].contents[0].quantifier); ASSERT_EQ(REGEX_TERM_LITERAL, inner->contents[1].contents[0].type); ASSERT_EQ('b', inner->contents[1].contents[0].literal); ASSERT_EQ(1, inner->contents[2].count); ASSERT_NOT_NULL(inner->contents[2].contents); ASSERT_EQ( REGEX_QUANTIFIER_NONE, inner->contents[2].contents[0].quantifier); ASSERT_EQ(REGEX_TERM_LITERAL, inner->contents[2].contents[0].type); ASSERT_EQ('c', inner->contents[2].contents[0].literal); regex_free(&t); } int main(void) { TESTING_BEGIN(); a_is_unchanged(); abc_is_unchanged(); a_star_is_unchanged(); a_or_b_or_c_is_unchanged(); subexpr_a_is_unchanged(); a_plus_becomes_subexpr_aa_star(); a_qmark_becomes_subexpr_empty_or_a(); class_abc_becomes_subexpr_a_or_b_or_c(); return TESTING_END(); }