From 759e03748a368be8b209dfd113441c05e1a5dcc0 Mon Sep 17 00:00:00 2001 From: Nick Wellnhofer Date: Thu, 20 Nov 2014 13:02:53 +0100 Subject: More tree hierarchy checks and tests --- src/node.c | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'src/node.c') diff --git a/src/node.c b/src/node.c index 624baad..4317dd4 100644 --- a/src/node.c +++ b/src/node.c @@ -348,6 +348,17 @@ S_is_inline(cmark_node *node) { static bool S_can_contain(cmark_node *node, cmark_node *child) { + cmark_node *cur; + + // Verify that child is not an ancestor of node or equal to node. + cur = node; + do { + if (cur == child) { + return false; + } + cur = cur->parent; + } while (cur != NULL); + if (child->type == CMARK_NODE_DOCUMENT) { return false; } -- cgit v1.2.3 From 32be14c39f67eedf356adc4f673b66479b717c7c Mon Sep 17 00:00:00 2001 From: Nick Wellnhofer Date: Thu, 20 Nov 2014 15:17:33 +0100 Subject: Set defaults for new headers and lists --- api_test/main.c | 35 +++++++++++++++++++++++++++++++++++ src/node.c | 19 +++++++++++++++++++ 2 files changed, 54 insertions(+) (limited to 'src/node.c') diff --git a/api_test/main.c b/api_test/main.c index e17beda..933a4bd 100644 --- a/api_test/main.c +++ b/api_test/main.c @@ -36,6 +36,40 @@ static void test_content(test_batch_runner *runner, cmark_node_type type, int allowed_content); +static void +constructor(test_batch_runner *runner) +{ + for (int i = 0; i < num_node_types; ++i) { + cmark_node_type type = node_types[i]; + cmark_node *node = cmark_node_new(type); + OK(runner, node != NULL, "new type %d", type); + + switch (node->type) { + case CMARK_NODE_ATX_HEADER: + case CMARK_NODE_SETEXT_HEADER: + INT_EQ(runner, cmark_node_get_header_level(node), 1, + "default header level is 1"); + node->as.header.level = 1; + break; + + case CMARK_NODE_LIST: + INT_EQ(runner, cmark_node_get_list_type(node), + CMARK_BULLET_LIST, + "default is list type is bullet"); + INT_EQ(runner, cmark_node_get_list_start(node), 1, + "default is list start is 1"); + INT_EQ(runner, cmark_node_get_list_tight(node), 0, + "default is list is loose"); + break; + + default: + break; + } + + cmark_node_destroy(node); + } +} + static void accessors(test_batch_runner *runner) { @@ -398,6 +432,7 @@ int main() { int retval; test_batch_runner *runner = test_batch_runner_new(); + constructor(runner); accessors(runner); create_tree(runner); hierarchy(runner); diff --git a/src/node.c b/src/node.c index 4317dd4..bb9cacc 100644 --- a/src/node.c +++ b/src/node.c @@ -11,6 +11,25 @@ cmark_node* cmark_node_new(cmark_node_type type) { cmark_node *node = (cmark_node *)calloc(1, sizeof(*node)); node->type = type; + + switch (node->type) { + case CMARK_NODE_ATX_HEADER: + case CMARK_NODE_SETEXT_HEADER: + node->as.header.level = 1; + break; + + case CMARK_NODE_LIST: { + cmark_list *list = &node->as.list; + list->list_type = CMARK_BULLET_LIST; + list->start = 1; + list->tight = false; + break; + } + + default: + break; + } + return node; } -- cgit v1.2.3 From 92a4d4cb4eb4a6103f68646a38f8caa29d6df3e3 Mon Sep 17 00:00:00 2001 From: Nick Wellnhofer Date: Sat, 22 Nov 2014 15:41:40 +0100 Subject: Fix and test node_check --- api_test/main.c | 39 ++++++++++++++++++++++++++++++--------- src/blocks.c | 2 +- src/node.c | 55 ++++++++++++++++++++++++++++++------------------------- src/node.h | 4 +++- 4 files changed, 64 insertions(+), 36 deletions(-) (limited to 'src/node.c') diff --git a/api_test/main.c b/api_test/main.c index 1b5725d..f484a53 100644 --- a/api_test/main.c +++ b/api_test/main.c @@ -260,6 +260,22 @@ accessors(test_batch_runner *runner) cmark_node_destroy(doc); } +static void +node_check(test_batch_runner *runner) { + // Construct an incomplete tree. + cmark_node *doc = cmark_node_new(CMARK_NODE_DOCUMENT); + cmark_node *p1 = cmark_node_new(CMARK_NODE_PARAGRAPH); + cmark_node *p2 = cmark_node_new(CMARK_NODE_PARAGRAPH); + doc->first_child = p1; + p1->next = p2; + + INT_EQ(runner, cmark_node_check(doc, NULL), 4, "node_check works"); + INT_EQ(runner, cmark_node_check(doc, NULL), 0, + "node_check fixes tree"); + + cmark_node_destroy(doc); +} + static void create_tree(test_batch_runner *runner) { @@ -268,27 +284,27 @@ create_tree(test_batch_runner *runner) cmark_node *p = cmark_node_new(CMARK_NODE_PARAGRAPH); OK(runner, cmark_node_append_child(doc, p), "append1"); - INT_EQ(runner, cmark_node_check(doc), 0, "append1 consistent"); + INT_EQ(runner, cmark_node_check(doc, NULL), 0, "append1 consistent"); OK(runner, cmark_node_parent(p) == doc, "node_parent"); cmark_node *emph = cmark_node_new(CMARK_NODE_EMPH); OK(runner, cmark_node_prepend_child(p, emph), "prepend1"); - INT_EQ(runner, cmark_node_check(doc), 0, "prepend1 consistent"); + INT_EQ(runner, cmark_node_check(doc, NULL), 0, "prepend1 consistent"); cmark_node *str1 = cmark_node_new(CMARK_NODE_STRING); cmark_node_set_string_content(str1, "Hello, "); OK(runner, cmark_node_prepend_child(p, str1), "prepend2"); - INT_EQ(runner, cmark_node_check(doc), 0, "prepend2 consistent"); + INT_EQ(runner, cmark_node_check(doc, NULL), 0, "prepend2 consistent"); cmark_node *str3 = cmark_node_new(CMARK_NODE_STRING); cmark_node_set_string_content(str3, "!"); OK(runner, cmark_node_append_child(p, str3), "append2"); - INT_EQ(runner, cmark_node_check(doc), 0, "append2 consistent"); + INT_EQ(runner, cmark_node_check(doc, NULL), 0, "append2 consistent"); cmark_node *str2 = cmark_node_new(CMARK_NODE_STRING); cmark_node_set_string_content(str2, "world"); OK(runner, cmark_node_append_child(emph, str2), "append3"); - INT_EQ(runner, cmark_node_check(doc), 0, "append3 consistent"); + INT_EQ(runner, cmark_node_check(doc, NULL), 0, "append3 consistent"); html = (char *)cmark_render_html(doc); STR_EQ(runner, html, "

Hello, world!

\n", @@ -296,22 +312,26 @@ create_tree(test_batch_runner *runner) free(html); OK(runner, cmark_node_insert_before(str1, str3), "ins before1"); - INT_EQ(runner, cmark_node_check(doc), 0, "ins before1 consistent"); + INT_EQ(runner, cmark_node_check(doc, NULL), 0, + "ins before1 consistent"); // 31e OK(runner, cmark_node_first_child(p) == str3, "ins before1 works"); OK(runner, cmark_node_insert_before(str1, emph), "ins before2"); - INT_EQ(runner, cmark_node_check(doc), 0, "ins before2 consistent"); + INT_EQ(runner, cmark_node_check(doc, NULL), 0, + "ins before2 consistent"); // 3e1 OK(runner, cmark_node_last_child(p) == str1, "ins before2 works"); OK(runner, cmark_node_insert_after(str1, str3), "ins after1"); - INT_EQ(runner, cmark_node_check(doc), 0, "ins after1 consistent"); + INT_EQ(runner, cmark_node_check(doc, NULL), 0, + "ins after1 consistent"); // e13 OK(runner, cmark_node_next(str1) == str3, "ins after1 works"); OK(runner, cmark_node_insert_after(str1, emph), "ins after2"); - INT_EQ(runner, cmark_node_check(doc), 0, "ins after2 consistent"); + INT_EQ(runner, cmark_node_check(doc, NULL), 0, + "ins after2 consistent"); // 1e3 OK(runner, cmark_node_previous(emph) == str1, "ins after2 works"); @@ -425,6 +445,7 @@ int main() { constructor(runner); accessors(runner); + node_check(runner); create_tree(runner); hierarchy(runner); diff --git a/src/blocks.c b/src/blocks.c index 58162b5..ab9f667 100644 --- a/src/blocks.c +++ b/src/blocks.c @@ -818,7 +818,7 @@ cmark_node *cmark_finish(cmark_doc_parser *parser) finalize_document(parser); strbuf_free(parser->curline); #if CMARK_DEBUG_NODES - if (cmark_node_check(parser->root)) { + if (cmark_node_check(parser->root, stderr)) { abort(); } #endif diff --git a/src/node.c b/src/node.c index bb9cacc..a79dd82 100644 --- a/src/node.c +++ b/src/node.c @@ -558,58 +558,63 @@ cmark_node_append_child(cmark_node *node, cmark_node *child) } static void -S_print_error(cmark_node *node, const char *elem) +S_print_error(FILE *out, cmark_node *node, const char *elem) { - fprintf(stderr, "Invalid '%s' in node type %s at %d:%d\n", elem, + if (out == NULL) { + return; + } + fprintf(out, "Invalid '%s' in node type %s at %d:%d\n", elem, S_type_string(node), node->start_line, node->start_column); } int -cmark_node_check(cmark_node *node) +cmark_node_check(cmark_node *node, FILE *out) { - cmark_node *cur = node; + cmark_node *cur; int errors = 0; - while (cur) { + if (!node) { + return 0; + } + + cur = node; + while (true) { if (cur->first_child) { if (cur->first_child->parent != cur) { - S_print_error(cur->first_child, "parent"); + S_print_error(out, cur->first_child, "parent"); cur->first_child->parent = cur; ++errors; } cur = cur->first_child; + continue; + } + + next_sibling: + if (cur == node) { + break; } - else if (cur->next) { + if (cur->next) { if (cur->next->prev != cur) { - S_print_error(cur->next, "prev"); + S_print_error(out, cur->next, "prev"); cur->next->prev = cur; ++errors; } if (cur->next->parent != cur->parent) { - S_print_error(cur->next, "parent"); + S_print_error(out, cur->next, "parent"); cur->next->parent = cur->parent; ++errors; } cur = cur->next; + continue; } - else { - if (cur->parent->last_child != cur) { - S_print_error(cur->parent, "last_child"); - cur->parent->last_child = cur; - ++errors; - } - cmark_node *ancestor = cur->parent; - cur = NULL; - - while (ancestor != node->parent) { - if (ancestor->next) { - cur = ancestor->next; - break; - } - ancestor = ancestor->parent; - } + if (cur->parent->last_child != cur) { + S_print_error(out, cur->parent, "last_child"); + cur->parent->last_child = cur; + ++errors; } + cur = cur->parent; + goto next_sibling; } return errors; diff --git a/src/node.h b/src/node.h index 2d7f0a1..d1245a5 100644 --- a/src/node.h +++ b/src/node.h @@ -5,6 +5,8 @@ extern "C" { #endif +#include + #include "cmark.h" #include "buffer.h" #include "chunk.h" @@ -62,7 +64,7 @@ struct cmark_node { }; CMARK_EXPORT int -cmark_node_check(cmark_node *node); +cmark_node_check(cmark_node *node, FILE *out); #ifdef __cplusplus } -- cgit v1.2.3