aboutsummaryrefslogtreecommitdiffstats
path: root/tests/blogc
diff options
context:
space:
mode:
authorRafael G. Martins <rafael@rafaelmartins.eng.br>2016-09-03 19:57:54 +0200
committerRafael G. Martins <rafael@rafaelmartins.eng.br>2016-09-03 20:28:55 +0200
commit74ca21a41bcb5a49d19e65c9ba88f1f864cb7095 (patch)
tree4774587e47abc0ff20453abbf714b63c36697f26 /tests/blogc
parent30ae5fd4f65f48009e6956e42ccc2c9d9ad80901 (diff)
downloadblogc-74ca21a41bcb5a49d19e65c9ba88f1f864cb7095.tar.gz
blogc-74ca21a41bcb5a49d19e65c9ba88f1f864cb7095.tar.bz2
blogc-74ca21a41bcb5a49d19e65c9ba88f1f864cb7095.zip
*: big code reorganization.
- source and tests are now splitted by target - utils lib is now called common still pending move error.c from blogc to common
Diffstat (limited to 'tests/blogc')
-rw-r--r--tests/blogc/check_content_parser.c2208
-rw-r--r--tests/blogc/check_datetime_parser.c671
-rw-r--r--tests/blogc/check_error.c109
-rw-r--r--tests/blogc/check_loader.c771
-rw-r--r--tests/blogc/check_renderer.c1158
-rw-r--r--tests/blogc/check_source_parser.c542
-rw-r--r--tests/blogc/check_template_parser.c1184
7 files changed, 6643 insertions, 0 deletions
diff --git a/tests/blogc/check_content_parser.c b/tests/blogc/check_content_parser.c
new file mode 100644
index 0000000..6cc58ff
--- /dev/null
+++ b/tests/blogc/check_content_parser.c
@@ -0,0 +1,2208 @@
+/*
+ * blogc: A blog compiler.
+ * Copyright (C) 2015-2016 Rafael G. Martins <rafael@rafaelmartins.eng.br>
+ *
+ * This program can be distributed under the terms of the BSD License.
+ * See the file LICENSE.
+ */
+
+#include <stdarg.h>
+#include <stddef.h>
+#include <setjmp.h>
+#include <cmocka.h>
+#include <stdlib.h>
+#include "../../src/blogc/content-parser.h"
+
+
+static void
+test_slugify(void **state)
+{
+ char *s = blogc_slugify(NULL);
+ assert_null(s);
+ s = blogc_slugify("bola");
+ assert_string_equal(s, "bola");
+ free(s);
+ s = blogc_slugify("bola o");
+ assert_string_equal(s, "bola-o");
+ free(s);
+ s = blogc_slugify("Bola O");
+ assert_string_equal(s, "bola-o");
+ free(s);
+ s = blogc_slugify("bola 0");
+ assert_string_equal(s, "bola-0");
+ free(s);
+ s = blogc_slugify("bola () o");
+ assert_string_equal(s, "bola-----o");
+ free(s);
+ s = blogc_slugify("Bola O");
+ assert_string_equal(s, "bola-o");
+ free(s);
+ s = blogc_slugify("bolaço");
+ assert_string_equal(s, "bola--o");
+ free(s);
+}
+
+
+static void
+test_htmlentities(void **state)
+{
+ char *s = blogc_htmlentities(NULL);
+ assert_null(s);
+ s = blogc_htmlentities("asdxcv & < > \" 'sfd/gf");
+ assert_string_equal(s, "asdxcv &amp; &lt; &gt; &quot; &#x27;sfd&#x2F;gf");
+ free(s);
+}
+
+
+static void
+test_fix_description(void **state)
+{
+ assert_null(blogc_fix_description(NULL));
+ char *s = blogc_fix_description("bola");
+ assert_string_equal(s, "bola");
+ free(s);
+ s = blogc_fix_description("bola\n");
+ assert_string_equal(s, "bola");
+ free(s);
+ s = blogc_fix_description("bola\r\n");
+ assert_string_equal(s, "bola");
+ free(s);
+ s = blogc_fix_description("bola\nguda");
+ assert_string_equal(s, "bola guda");
+ free(s);
+ s = blogc_fix_description("bola\nguda\n");
+ assert_string_equal(s, "bola guda");
+ free(s);
+ s = blogc_fix_description("bola\r\nguda\r\n");
+ assert_string_equal(s, "bola guda");
+ free(s);
+
+ s = blogc_fix_description("bola\n guda lol\n asd");
+ assert_string_equal(s, "bola guda lol asd");
+ free(s);
+ s = blogc_fix_description("bola\n guda lol\n asd\n");
+ assert_string_equal(s, "bola guda lol asd");
+ free(s);
+ s = blogc_fix_description("bola\r\n guda lol\r\n asd\r\n");
+ assert_string_equal(s, "bola guda lol asd");
+ free(s);
+ s = blogc_fix_description(" bola\n guda lol\n asd");
+ assert_string_equal(s, "bola guda lol asd");
+ free(s);
+ s = blogc_fix_description(" bola\n guda lol\n asd\n");
+ assert_string_equal(s, "bola guda lol asd");
+ free(s);
+ s = blogc_fix_description(" bola\r\n guda lol\r\n asd\r\n");
+ assert_string_equal(s, "bola guda lol asd");
+ free(s);
+ s = blogc_fix_description("b'o\"l<>a");
+ assert_string_equal(s, "b&#x27;o&quot;l&lt;&gt;a");
+ free(s);
+}
+
+
+static void
+test_is_ordered_list_item(void **state)
+{
+ assert_true(blogc_is_ordered_list_item("1.bola", 2));
+ assert_true(blogc_is_ordered_list_item("1. bola", 3));
+ assert_true(blogc_is_ordered_list_item("12. bola", 4));
+ assert_true(blogc_is_ordered_list_item("123. bola", 5));
+ assert_true(blogc_is_ordered_list_item("1. bola", 6));
+ assert_true(blogc_is_ordered_list_item("1. bola", 5));
+ assert_false(blogc_is_ordered_list_item("1bola", 1));
+ assert_false(blogc_is_ordered_list_item("12bola", 2));
+ assert_false(blogc_is_ordered_list_item("1 . bola", 6));
+ assert_false(blogc_is_ordered_list_item("1. bola", 6));
+ assert_false(blogc_is_ordered_list_item("1.", 2));
+ assert_false(blogc_is_ordered_list_item(NULL, 2));
+}
+
+
+static void
+test_content_parse(void **state)
+{
+ size_t l = 0;
+ char *d = NULL;
+ char *html = blogc_content_parse(
+ "# um\n"
+ "## dois\n"
+ "### tres\n"
+ "#### quatro\n"
+ "##### cinco\n"
+ "###### seis\n"
+ "\n"
+ "bola\n"
+ "chunda\n"
+ "\n"
+ "> bola \n"
+ "> guda\n"
+ "> buga\n"
+ "> \n"
+ "> asd\n"
+ "\n"
+ " <asd>bola</asd>\n"
+ " asd\n"
+ " qwewer\n"
+ "\n"
+ "+++\n"
+ "1. chunda\n"
+ "3. fuuuu\n"
+ "\n"
+ "- chunda2\n"
+ "- fuuuu2\n"
+ "\n"
+ "<style>\n"
+ " chunda\n"
+ "</style>\n"
+ "\n"
+ "guda\n"
+ "yay\n"
+ "\n"
+ "**bola**\n"
+ "-- foo-bar\n"
+ "--- bar\n"
+ "\n"
+ "-- asd\n"
+ "\n"
+ "--- lol\n", &l, &d);
+ assert_non_null(html);
+ assert_int_equal(l, 0);
+ assert_non_null(d);
+ assert_string_equal(d, "bola chunda");
+ assert_string_equal(html,
+ "<h1 id=\"um\">um</h1>\n"
+ "<h2 id=\"dois\">dois</h2>\n"
+ "<h3 id=\"tres\">tres</h3>\n"
+ "<h4 id=\"quatro\">quatro</h4>\n"
+ "<h5 id=\"cinco\">cinco</h5>\n"
+ "<h6 id=\"seis\">seis</h6>\n"
+ "<p>bola\n"
+ "chunda</p>\n"
+ "<blockquote><p>bola<br />\n"
+ "guda\n"
+ "buga</p>\n"
+ "<pre><code>asd</code></pre>\n"
+ "</blockquote>\n"
+ "<pre><code>&lt;asd&gt;bola&lt;&#x2F;asd&gt;\n"
+ " asd\n"
+ "qwewer</code></pre>\n"
+ "<hr />\n"
+ "<ol>\n"
+ "<li>chunda</li>\n"
+ "<li>fuuuu</li>\n"
+ "</ol>\n"
+ "<ul>\n"
+ "<li>chunda2</li>\n"
+ "<li>fuuuu2</li>\n"
+ "</ul>\n"
+ "<style>\n"
+ " chunda\n"
+ "</style>\n"
+ "<p>guda\n"
+ "yay</p>\n"
+ "<p><strong>bola</strong>\n"
+ "&ndash; foo-bar\n"
+ "&mdash; bar</p>\n"
+ "<p>&ndash; asd</p>\n"
+ "<p>&mdash; lol</p>\n");
+ free(html);
+ free(d);
+}
+
+
+static void
+test_content_parse_crlf(void **state)
+{
+ size_t l = 0;
+ char *d = NULL;
+ char *html = blogc_content_parse(
+ "# um\r\n"
+ "## dois\r\n"
+ "### tres\r\n"
+ "#### quatro\r\n"
+ "##### cinco\r\n"
+ "###### seis\r\n"
+ "\r\n"
+ "bola\r\n"
+ "chunda\r\n"
+ "\r\n"
+ "> bola \r\n"
+ "> guda\r\n"
+ "> buga\r\n"
+ "> \r\n"
+ "> asd\r\n"
+ "\r\n"
+ " <asd>bola</asd>\r\n"
+ " asd\r\n"
+ " qwewer\r\n"
+ "\r\n"
+ "+++\r\n"
+ "1. chunda\r\n"
+ "3. fuuuu\r\n"
+ "\r\n"
+ "+ chunda2\r\n"
+ "+ fuuuu2\r\n"
+ "\r\n"
+ "<style>\r\n"
+ " chunda\r\n"
+ "</style>\r\n"
+ "\r\n"
+ "guda\r\n"
+ "yay\r\n"
+ "\r\n"
+ "**bola**\r\n"
+ "-- foo-bar\r\n"
+ "--- bar\r\n"
+ "\r\n"
+ "-- asd\r\n"
+ "\r\n"
+ "--- lol\r\n", &l, &d);
+ assert_non_null(html);
+ assert_int_equal(l, 0);
+ assert_non_null(d);
+ assert_string_equal(d, "bola chunda");
+ assert_string_equal(html,
+ "<h1 id=\"um\">um</h1>\r\n"
+ "<h2 id=\"dois\">dois</h2>\r\n"
+ "<h3 id=\"tres\">tres</h3>\r\n"
+ "<h4 id=\"quatro\">quatro</h4>\r\n"
+ "<h5 id=\"cinco\">cinco</h5>\r\n"
+ "<h6 id=\"seis\">seis</h6>\r\n"
+ "<p>bola\r\n"
+ "chunda</p>\r\n"
+ "<blockquote><p>bola<br />\r\n"
+ "guda\r\n"
+ "buga</p>\r\n"
+ "<pre><code>asd</code></pre>\r\n"
+ "</blockquote>\r\n"
+ "<pre><code>&lt;asd&gt;bola&lt;&#x2F;asd&gt;\r\n"
+ " asd\r\n"
+ "qwewer</code></pre>\r\n"
+ "<hr />\r\n"
+ "<ol>\r\n"
+ "<li>chunda</li>\r\n"
+ "<li>fuuuu</li>\r\n"
+ "</ol>\r\n"
+ "<ul>\r\n"
+ "<li>chunda2</li>\r\n"
+ "<li>fuuuu2</li>\r\n"
+ "</ul>\r\n"
+ "<style>\r\n"
+ " chunda\r\n"
+ "</style>\r\n"
+ "<p>guda\r\n"
+ "yay</p>\r\n"
+ "<p><strong>bola</strong>\r\n"
+ "&ndash; foo-bar\r\n"
+ "&mdash; bar</p>\r\n"
+ "<p>&ndash; asd</p>\r\n"
+ "<p>&mdash; lol</p>\r\n");
+ free(html);
+ free(d);
+}
+
+
+static void
+test_content_parse_with_excerpt(void **state)
+{
+ size_t l = 0;
+ char *d = NULL;
+ char *html = blogc_content_parse(
+ "# test\n"
+ "\n"
+ "chunda\n"
+ "\n"
+ "..\n"
+ "\n"
+ "guda\n"
+ "lol", &l, &d);
+ assert_non_null(html);
+ assert_int_equal(l, 38);
+ assert_non_null(d);
+ assert_string_equal(d, "chunda");
+ assert_string_equal(html,
+ "<h1 id=\"test\">test</h1>\n"
+ "<p>chunda</p>\n"
+ "<p>guda\n"
+ "lol</p>\n");
+ free(html);
+ l = 0;
+ free(d);
+ d = NULL;
+ html = blogc_content_parse(
+ "# test\n"
+ "\n"
+ "chunda\n"
+ "\n"
+ "...\n"
+ "\n"
+ "guda\n"
+ "lol", &l, &d);
+ assert_non_null(html);
+ assert_int_equal(l, 38);
+ assert_non_null(d);
+ assert_string_equal(d, "chunda");
+ assert_string_equal(html,
+ "<h1 id=\"test\">test</h1>\n"
+ "<p>chunda</p>\n"
+ "<p>guda\n"
+ "lol</p>\n");
+ free(html);
+ free(d);
+}
+
+
+static void
+test_content_parse_with_excerpt_crlf(void **state)
+{
+ size_t l = 0;
+ char *d = NULL;
+ char *html = blogc_content_parse(
+ "# test\r\n"
+ "\r\n"
+ "chunda\r\n"
+ "\r\n"
+ "..\r\n"
+ "\r\n"
+ "guda\r\n"
+ "lol", &l, &d);
+ assert_non_null(html);
+ assert_int_equal(l, 40);
+ assert_non_null(d);
+ assert_string_equal(d, "chunda");
+ assert_string_equal(html,
+ "<h1 id=\"test\">test</h1>\r\n"
+ "<p>chunda</p>\r\n"
+ "<p>guda\r\n"
+ "lol</p>\r\n");
+ free(html);
+ l = 0;
+ free(d);
+ d = NULL;
+ html = blogc_content_parse(
+ "# test\r\n"
+ "\r\n"
+ "chunda\r\n"
+ "\r\n"
+ "...\r\n"
+ "\r\n"
+ "guda\r\n"
+ "lol", &l, &d);
+ assert_non_null(html);
+ assert_int_equal(l, 40);
+ assert_non_null(d);
+ assert_string_equal(d, "chunda");
+ assert_string_equal(html,
+ "<h1 id=\"test\">test</h1>\r\n"
+ "<p>chunda</p>\r\n"
+ "<p>guda\r\n"
+ "lol</p>\r\n");
+ free(html);
+ free(d);
+}
+
+
+static void
+test_content_parse_header(void **state)
+{
+ char *html = blogc_content_parse("## bola", NULL, NULL);
+ assert_non_null(html);
+ assert_string_equal(html, "<h2 id=\"bola\">bola</h2>\n");
+ free(html);
+ html = blogc_content_parse("## bola\n", NULL, NULL);
+ assert_non_null(html);
+ assert_string_equal(html, "<h2 id=\"bola\">bola</h2>\n");
+ free(html);
+ html = blogc_content_parse(
+ "bola\n"
+ "\n"
+ "## bola\n"
+ "\n"
+ "guda\n", NULL, NULL);
+ assert_non_null(html);
+ assert_string_equal(html,
+ "<p>bola</p>\n"
+ "<h2 id=\"bola\">bola</h2>\n"
+ "<p>guda</p>\n");
+ free(html);
+}
+
+
+static void
+test_content_parse_header_crlf(void **state)
+{
+ char *html = blogc_content_parse("## bola", NULL, NULL);
+ assert_non_null(html);
+ assert_string_equal(html, "<h2 id=\"bola\">bola</h2>\n");
+ free(html);
+ html = blogc_content_parse("## bola\r\n", NULL, NULL);
+ assert_non_null(html);
+ assert_string_equal(html, "<h2 id=\"bola\">bola</h2>\r\n");
+ free(html);
+ html = blogc_content_parse(
+ "bola\r\n"
+ "\r\n"
+ "## bola\r\n"
+ "\r\n"
+ "guda\r\n", NULL, NULL);
+ assert_non_null(html);
+ assert_string_equal(html,
+ "<p>bola</p>\r\n"
+ "<h2 id=\"bola\">bola</h2>\r\n"
+ "<p>guda</p>\r\n");
+ free(html);
+}
+
+
+static void
+test_content_parse_html(void **state)
+{
+ char *html = blogc_content_parse("<div>\n</div>", NULL, NULL);
+ assert_non_null(html);
+ assert_string_equal(html, "<div>\n</div>\n");
+ free(html);
+ html = blogc_content_parse("<div>\n</div>\n", NULL, NULL);
+ assert_non_null(html);
+ assert_string_equal(html, "<div>\n</div>\n");
+ free(html);
+ html = blogc_content_parse(
+ "bola\n"
+ "\n"
+ "<div>\n"
+ "</div>\n"
+ "\n"
+ "chunda\n", NULL, NULL);
+ assert_non_null(html);
+ assert_string_equal(html,
+ "<p>bola</p>\n"
+ "<div>\n</div>\n"
+ "<p>chunda</p>\n");
+ free(html);
+}
+
+
+static void
+test_content_parse_html_crlf(void **state)
+{
+ char *html = blogc_content_parse("<div>\r\n</div>", NULL, NULL);
+ assert_non_null(html);
+ assert_string_equal(html, "<div>\r\n</div>\r\n");
+ free(html);
+ html = blogc_content_parse("<div>\r\n</div>\r\n", NULL, NULL);
+ assert_non_null(html);
+ assert_string_equal(html, "<div>\r\n</div>\r\n");
+ free(html);
+ html = blogc_content_parse(
+ "bola\r\n"
+ "\r\n"
+ "<div>\r\n"
+ "</div>\r\n"
+ "\r\n"
+ "chunda\r\n", NULL, NULL);
+ assert_non_null(html);
+ assert_string_equal(html,
+ "<p>bola</p>\r\n"
+ "<div>\r\n</div>\r\n"
+ "<p>chunda</p>\r\n");
+ free(html);
+}
+
+
+static void
+test_content_parse_blockquote(void **state)
+{
+ char *html = blogc_content_parse("> bola\n> guda", NULL, NULL);
+ assert_non_null(html);
+ assert_string_equal(html,
+ "<blockquote><p>bola\n"
+ "guda</p>\n"
+ "</blockquote>\n");
+ free(html);
+ html = blogc_content_parse("> bola\n> guda\n", NULL, NULL);
+ assert_non_null(html);
+ assert_string_equal(html,
+ "<blockquote><p>bola\n"
+ "guda</p>\n"
+ "</blockquote>\n");
+ free(html);
+ html = blogc_content_parse(
+ "bola\n"
+ "\n"
+ "> bola\n"
+ "\n"
+ "chunda\n", NULL, NULL);
+ assert_non_null(html);
+ assert_string_equal(html,
+ "<p>bola</p>\n"
+ "<blockquote><p>bola</p>\n"
+ "</blockquote>\n"
+ "<p>chunda</p>\n");
+ free(html);
+ html = blogc_content_parse(
+ "bola\n"
+ "\n"
+ "> bola\n"
+ "> guda\n"
+ "\n"
+ "chunda\n", NULL, NULL);
+ assert_non_null(html);
+ assert_string_equal(html,
+ "<p>bola</p>\n"
+ "<blockquote><p>bola\n"
+ "guda</p>\n"
+ "</blockquote>\n"
+ "<p>chunda</p>\n");
+ free(html);
+}
+
+
+static void
+test_content_parse_blockquote_crlf(void **state)
+{
+ char *html = blogc_content_parse("> bola\r\n> guda", NULL, NULL);
+ assert_non_null(html);
+ assert_string_equal(html,
+ "<blockquote><p>bola\r\n"
+ "guda</p>\r\n"
+ "</blockquote>\r\n");
+ free(html);
+ html = blogc_content_parse("> bola\r\n> guda\r\n", NULL, NULL);
+ assert_non_null(html);
+ assert_string_equal(html,
+ "<blockquote><p>bola\r\n"
+ "guda</p>\r\n"
+ "</blockquote>\r\n");
+ free(html);
+ html = blogc_content_parse(
+ "bola\r\n"
+ "\r\n"
+ "> bola\r\n"
+ "\r\n"
+ "chunda\r\n", NULL, NULL);
+ assert_non_null(html);
+ assert_string_equal(html,
+ "<p>bola</p>\r\n"
+ "<blockquote><p>bola</p>\r\n"
+ "</blockquote>\r\n"
+ "<p>chunda</p>\r\n");
+ free(html);
+ html = blogc_content_parse(
+ "bola\r\n"
+ "\r\n"
+ "> bola\r\n"
+ "> guda\r\n"
+ "\r\n"
+ "chunda\r\n", NULL, NULL);
+ assert_non_null(html);
+ assert_string_equal(html,
+ "<p>bola</p>\r\n"
+ "<blockquote><p>bola\r\n"
+ "guda</p>\r\n"
+ "</blockquote>\r\n"
+ "<p>chunda</p>\r\n");
+ free(html);
+}
+
+
+static void
+test_content_parse_code(void **state)
+{
+ char *html = blogc_content_parse(" bola\n guda", NULL, NULL);
+ assert_non_null(html);
+ assert_string_equal(html,
+ "<pre><code>bola\n"
+ "guda</code></pre>\n");
+ free(html);
+ html = blogc_content_parse(" bola\n guda\n", NULL, NULL);
+ assert_non_null(html);
+ assert_string_equal(html,
+ "<pre><code>bola\n"
+ "guda</code></pre>\n");
+ free(html);
+ html = blogc_content_parse(
+ "bola\n"
+ "\n"
+ " bola\n"
+ " guda\n"
+ "\n"
+ "chunda\n", NULL, NULL);
+ assert_non_null(html);
+ assert_string_equal(html,
+ "<p>bola</p>\n"
+ "<pre><code>bola\n"
+ "guda</code></pre>\n"
+ "<p>chunda</p>\n");
+ free(html);
+}
+
+
+static void
+test_content_parse_code_crlf(void **state)
+{
+ char *html = blogc_content_parse(" bola\r\n guda", NULL, NULL);
+ assert_non_null(html);
+ assert_string_equal(html,
+ "<pre><code>bola\r\n"
+ "guda</code></pre>\r\n");
+ free(html);
+ html = blogc_content_parse(" bola\r\n guda\r\n", NULL, NULL);
+ assert_non_null(html);
+ assert_string_equal(html,
+ "<pre><code>bola\r\n"
+ "guda</code></pre>\r\n");
+ free(html);
+ html = blogc_content_parse(
+ "bola\r\n"
+ "\r\n"
+ " bola\r\n"
+ " guda\r\n"
+ "\r\n"
+ "chunda\r\n", NULL, NULL);
+ assert_non_null(html);
+ assert_string_equal(html,
+ "<p>bola</p>\r\n"
+ "<pre><code>bola\r\n"
+ "guda</code></pre>\r\n"
+ "<p>chunda</p>\r\n");
+ free(html);
+}
+
+
+static void
+test_content_parse_horizontal_rule(void **state)
+{
+ char *html = blogc_content_parse("bola\nguda\n\n**", NULL, NULL);
+ assert_non_null(html);
+ assert_string_equal(html,
+ "<p>bola\n"
+ "guda</p>\n"
+ "<hr />\n");
+ free(html);
+ html = blogc_content_parse("bola\nguda\n\n++++", NULL, NULL);
+ assert_non_null(html);
+ assert_string_equal(html,
+ "<p>bola\n"
+ "guda</p>\n"
+ "<hr />\n");
+ free(html);
+ html = blogc_content_parse("bola\nguda\n\n--\n", NULL, NULL);
+ assert_non_null(html);
+ assert_string_equal(html,
+ "<p>bola\n"
+ "guda</p>\n"
+ "<hr />\n");
+ free(html);
+ html = blogc_content_parse("bola\nguda\n\n****\n", NULL, NULL);
+ assert_non_null(html);
+ assert_string_equal(html,
+ "<p>bola\n"
+ "guda</p>\n"
+ "<hr />\n");
+ free(html);
+ html = blogc_content_parse(
+ "bola\n"
+ "\n"
+ "**\n"
+ "\n"
+ "chunda\n", NULL, NULL);
+ assert_non_null(html);
+ assert_string_equal(html,
+ "<p>bola</p>\n"
+ "<hr />\n"
+ "<p>chunda</p>\n");
+ free(html);
+ html = blogc_content_parse(
+ "bola\n"
+ "\n"
+ "----\n"
+ "\n"
+ "chunda\n", NULL, NULL);
+ assert_non_null(html);
+ assert_string_equal(html,
+ "<p>bola</p>\n"
+ "<hr />\n"
+ "<p>chunda</p>\n");
+ free(html);
+}
+
+
+static void
+test_content_parse_horizontal_rule_crlf(void **state)
+{
+ char *html = blogc_content_parse("bola\r\nguda\r\n\r\n**", NULL, NULL);
+ assert_non_null(html);
+ assert_string_equal(html,
+ "<p>bola\r\n"
+ "guda</p>\r\n"
+ "<hr />\r\n");
+ free(html);
+ html = blogc_content_parse("bola\r\nguda\r\n\r\n++++", NULL, NULL);
+ assert_non_null(html);
+ assert_string_equal(html,
+ "<p>bola\r\n"
+ "guda</p>\r\n"
+ "<hr />\r\n");
+ free(html);
+ html = blogc_content_parse("bola\r\nguda\r\n\r\n--\r\n", NULL, NULL);
+ assert_non_null(html);
+ assert_string_equal(html,
+ "<p>bola\r\n"
+ "guda</p>\r\n"
+ "<hr />\r\n");
+ free(html);
+ html = blogc_content_parse("bola\r\nguda\r\n\r\n****\r\n", NULL, NULL);
+ assert_non_null(html);
+ assert_string_equal(html,
+ "<p>bola\r\n"
+ "guda</p>\r\n"
+ "<hr />\r\n");
+ free(html);
+ html = blogc_content_parse(
+ "bola\r\n"
+ "\r\n"
+ "**\r\n"
+ "\r\n"
+ "chunda\r\n", NULL, NULL);
+ assert_non_null(html);
+ assert_string_equal(html,
+ "<p>bola</p>\r\n"
+ "<hr />\r\n"
+ "<p>chunda</p>\r\n");
+ free(html);
+ html = blogc_content_parse(
+ "bola\r\n"
+ "\r\n"
+ "----\r\n"
+ "\r\n"
+ "chunda\r\n", NULL, NULL);
+ assert_non_null(html);
+ assert_string_equal(html,
+ "<p>bola</p>\r\n"
+ "<hr />\r\n"
+ "<p>chunda</p>\r\n");
+ free(html);
+}
+
+
+static void
+test_content_parse_unordered_list(void **state)
+{
+ char *html = blogc_content_parse(
+ "lol\n"
+ "\n"
+ "* asd\n"
+ "* qwe\n"
+ "* zxc", NULL, NULL);
+ assert_non_null(html);
+ assert_string_equal(html,
+ "<p>lol</p>\n"
+ "<ul>\n"
+ "<li>asd</li>\n"
+ "<li>qwe</li>\n"
+ "<li>zxc</li>\n"
+ "</ul>\n");
+ free(html);
+ html = blogc_content_parse(
+ "lol\n"
+ "\n"
+ "* asd\n"
+ "* qwe\n"
+ "* zxc\n", NULL, NULL);
+ assert_non_null(html);
+ assert_string_equal(html,
+ "<p>lol</p>\n"
+ "<ul>\n"
+ "<li>asd</li>\n"
+ "<li>qwe</li>\n"
+ "<li>zxc</li>\n"
+ "</ul>\n");
+ free(html);
+ html = blogc_content_parse(
+ "lol\n"
+ "\n"
+ "* asd\n"
+ "* qwe\n"
+ "* zxc\n"
+ "\n"
+ "fuuuu\n", NULL, NULL);
+ assert_non_null(html);
+ assert_string_equal(html,
+ "<p>lol</p>\n"
+ "<ul>\n"
+ "<li>asd</li>\n"
+ "<li>qwe</li>\n"
+ "<li>zxc</li>\n"
+ "</ul>\n"
+ "<p>fuuuu</p>\n");
+ free(html);
+ html = blogc_content_parse(
+ "lol\n"
+ "\n"
+ "* asd\n"
+ " cvb\n"
+ "* qwe\n"
+ "* zxc\n"
+ " 1234\n"
+ "\n"
+ "fuuuu\n", NULL, NULL);
+ assert_non_null(html);
+ assert_string_equal(html,
+ "<p>lol</p>\n"
+ "<ul>\n"
+ "<li>asd\n"
+ "cvb</li>\n"
+ "<li>qwe</li>\n"
+ "<li>zxc\n"
+ "1234</li>\n"
+ "</ul>\n"
+ "<p>fuuuu</p>\n");
+ free(html);
+ html = blogc_content_parse(
+ "* asd\n"
+ "* qwe\n"
+ "* zxc", NULL, NULL);
+ assert_non_null(html);
+ assert_string_equal(html,
+ "<ul>\n"
+ "<li>asd</li>\n"
+ "<li> qwe</li>\n"
+ "<li> zxc</li>\n"
+ "</ul>\n");
+ free(html);
+}
+
+
+static void
+test_content_parse_unordered_list_crlf(void **state)
+{
+ char *html = blogc_content_parse(
+ "lol\r\n"
+ "\r\n"
+ "* asd\r\n"
+ "* qwe\r\n"
+ "* zxc", NULL, NULL);
+ assert_non_null(html);
+ assert_string_equal(html,
+ "<p>lol</p>\r\n"
+ "<ul>\r\n"
+ "<li>asd</li>\r\n"
+ "<li>qwe</li>\r\n"
+ "<li>zxc</li>\r\n"
+ "</ul>\r\n");
+ free(html);
+ html = blogc_content_parse(
+ "lol\r\n"
+ "\r\n"
+ "* asd\r\n"
+ "* qwe\r\n"
+ "* zxc\r\n", NULL, NULL);
+ assert_non_null(html);
+ assert_string_equal(html,
+ "<p>lol</p>\r\n"
+ "<ul>\r\n"
+ "<li>asd</li>\r\n"
+ "<li>qwe</li>\r\n"
+ "<li>zxc</li>\r\n"
+ "</ul>\r\n");
+ free(html);
+ html = blogc_content_parse(
+ "lol\r\n"
+ "\r\n"
+ "* asd\r\n"
+ "* qwe\r\n"
+ "* zxc\r\n"
+ "\r\n"
+ "fuuuu\r\n", NULL, NULL);
+ assert_non_null(html);
+ assert_string_equal(html,
+ "<p>lol</p>\r\n"
+ "<ul>\r\n"
+ "<li>asd</li>\r\n"
+ "<li>qwe</li>\r\n"
+ "<li>zxc</li>\r\n"
+ "</ul>\r\n"
+ "<p>fuuuu</p>\r\n");
+ free(html);
+ html = blogc_content_parse(
+ "lol\r\n"
+ "\r\n"
+ "* asd\r\n"
+ " cvb\r\n"
+ "* qwe\r\n"
+ "* zxc\r\n"
+ " 1234\r\n"
+ "\r\n"
+ "fuuuu\r\n", NULL, NULL);
+ assert_non_null(html);
+ assert_string_equal(html,
+ "<p>lol</p>\r\n"
+ "<ul>\r\n"
+ "<li>asd\r\n"
+ "cvb</li>\r\n"
+ "<li>qwe</li>\r\n"
+ "<li>zxc\r\n"
+ "1234</li>\r\n"
+ "</ul>\r\n"
+ "<p>fuuuu</p>\r\n");
+ free(html);
+ html = blogc_content_parse(
+ "* asd\r\n"
+ "* qwe\r\n"
+ "* zxc", NULL, NULL);
+ assert_non_null(html);
+ assert_string_equal(html,
+ "<ul>\r\n"
+ "<li>asd</li>\r\n"
+ "<li> qwe</li>\r\n"
+ "<li> zxc</li>\r\n"
+ "</ul>\r\n");
+ free(html);
+}
+
+
+static void
+test_content_parse_ordered_list(void **state)
+{
+ char *html = blogc_content_parse(
+ "lol\n"
+ "\n"
+ "1. asd\n"
+ "2. qwe\n"
+ "3. zxc", NULL, NULL);
+ assert_non_null(html);
+ assert_string_equal(html,
+ "<p>lol</p>\n"
+ "<ol>\n"
+ "<li>asd</li>\n"
+ "<li>qwe</li>\n"
+ "<li>zxc</li>\n"
+ "</ol>\n");
+ free(html);
+ html = blogc_content_parse(
+ "lol\n"
+ "\n"
+ "1. asd\n"
+ "2. qwe\n"
+ "3. zxc\n", NULL, NULL);
+ assert_non_null(html);
+ assert_string_equal(html,
+ "<p>lol</p>\n"
+ "<ol>\n"
+ "<li>asd</li>\n"
+ "<li>qwe</li>\n"
+ "<li>zxc</li>\n"
+ "</ol>\n");
+ free(html);
+ html = blogc_content_parse(
+ "lol\n"
+ "\n"
+ "1. asd\n"
+ "2. qwe\n"
+ "3. zxc\n"
+ "\n"
+ "fuuuu\n", NULL, NULL);
+ assert_non_null(html);
+ assert_string_equal(html,
+ "<p>lol</p>\n"
+ "<ol>\n"
+ "<li>asd</li>\n"
+ "<li>qwe</li>\n"
+ "<li>zxc</li>\n"
+ "</ol>\n"
+ "<p>fuuuu</p>\n");
+ free(html);
+ html = blogc_content_parse(
+ "lol\n"
+ "\n"
+ "1. asd\n"
+ " cvb\n"
+ "2. qwe\n"
+ "3. zxc\n"
+ " 1234\n"
+ "\n"
+ "fuuuu\n", NULL, NULL);
+ assert_non_null(html);
+ assert_string_equal(html,
+ "<p>lol</p>\n"
+ "<ol>\n"
+ "<li>asd\n"
+ "cvb</li>\n"
+ "<li>qwe</li>\n"
+ "<li>zxc\n"
+ "1234</li>\n"
+ "</ol>\n"
+ "<p>fuuuu</p>\n");
+ free(html);
+ html = blogc_content_parse(
+ "1. asd\n"
+ "2. qwe\n"
+ "3. zxc", NULL, NULL);
+ assert_non_null(html);
+ assert_string_equal(html,
+ "<ol>\n"
+ "<li>asd</li>\n"
+ "<li> qwe</li>\n"
+ "<li> zxc</li>\n"
+ "</ol>\n");
+ free(html);
+}
+
+
+static void
+test_content_parse_ordered_list_crlf(void **state)
+{
+ char *html = blogc_content_parse(
+ "lol\r\n"
+ "\r\n"
+ "1. asd\r\n"
+ "2. qwe\r\n"
+ "3. zxc", NULL, NULL);
+ assert_non_null(html);
+ assert_string_equal(html,
+ "<p>lol</p>\r\n"
+ "<ol>\r\n"
+ "<li>asd</li>\r\n"
+ "<li>qwe</li>\r\n"
+ "<li>zxc</li>\r\n"
+ "</ol>\r\n");
+ free(html);
+ html = blogc_content_parse(
+ "lol\r\n"
+ "\r\n"
+ "1. asd\r\n"
+ "2. qwe\r\n"
+ "3. zxc\r\n", NULL, NULL);
+ assert_non_null(html);
+ assert_string_equal(html,
+ "<p>lol</p>\r\n"
+ "<ol>\r\n"
+ "<li>asd</li>\r\n"
+ "<li>qwe</li>\r\n"
+ "<li>zxc</li>\r\n"
+ "</ol>\r\n");
+ free(html);
+ html = blogc_content_parse(
+ "lol\r\n"
+ "\r\n"
+ "1. asd\r\n"
+ "2. qwe\r\n"
+ "3. zxc\r\n"
+ "\r\n"
+ "fuuuu\r\n", NULL, NULL);
+ assert_non_null(html);
+ assert_string_equal(html,
+ "<p>lol</p>\r\n"
+ "<ol>\r\n"
+ "<li>asd</li>\r\n"
+ "<li>qwe</li>\r\n"
+ "<li>zxc</li>\r\n"
+ "</ol>\r\n"
+ "<p>fuuuu</p>\r\n");
+ free(html);
+ html = blogc_content_parse(
+ "lol\r\n"
+ "\r\n"
+ "1. asd\r\n"
+ " cvb\r\n"
+ "2. qwe\r\n"
+ "3. zxc\r\n"
+ " 1234\r\n"
+ "\r\n"
+ "fuuuu\r\n", NULL, NULL);
+ assert_non_null(html);
+ assert_string_equal(html,
+ "<p>lol</p>\r\n"
+ "<ol>\r\n"
+ "<li>asd\r\n"
+ "cvb</li>\r\n"
+ "<li>qwe</li>\r\n"
+ "<li>zxc\r\n"
+ "1234</li>\r\n"
+ "</ol>\r\n"
+ "<p>fuuuu</p>\r\n");
+ free(html);
+ html = blogc_content_parse(
+ "1. asd\r\n"
+ "2. qwe\r\n"
+ "3. zxc", NULL, NULL);
+ assert_non_null(html);
+ assert_string_equal(html,
+ "<ol>\r\n"
+ "<li>asd</li>\r\n"
+ "<li> qwe</li>\r\n"
+ "<li> zxc</li>\r\n"
+ "</ol>\r\n");
+ free(html);
+}
+
+
+static void
+test_content_parse_description(void **state)
+{
+ char *d = NULL;
+ char *html = blogc_content_parse(
+ "# foo\n"
+ "\n"
+ "bar", NULL, &d);
+ assert_non_null(html);
+ assert_string_equal(html,
+ "<h1 id=\"foo\">foo</h1>\n"
+ "<p>bar</p>\n");
+ assert_non_null(d);
+ assert_string_equal(d, "bar");
+ free(html);
+ free(d);
+ d = NULL;
+ html = blogc_content_parse(
+ "# foo\n"
+ "\n"
+ "bar\n", NULL, &d);
+ assert_non_null(html);
+ assert_string_equal(html,
+ "<h1 id=\"foo\">foo</h1>\n"
+ "<p>bar</p>\n");
+ assert_non_null(d);
+ assert_string_equal(d, "bar");
+ free(html);
+ free(d);
+ d = NULL;
+ html = blogc_content_parse(
+ "# foo\n"
+ "\n"
+ "qwe\n"
+ "bar\n", NULL, &d);
+ assert_non_null(html);
+ assert_string_equal(html,
+ "<h1 id=\"foo\">foo</h1>\n"
+ "<p>qwe\n"
+ "bar</p>\n");
+ assert_non_null(d);
+ assert_string_equal(d, "qwe bar");
+ free(html);
+ free(d);
+ d = NULL;
+ html = blogc_content_parse(
+ "# foo\n"
+ "\n"
+ "> qwe\n"
+ "\n"
+ "bar\n", NULL, &d);
+ assert_non_null(html);
+ assert_string_equal(html,
+ "<h1 id=\"foo\">foo</h1>\n"
+ "<blockquote><p>qwe</p>\n"
+ "</blockquote>\n"
+ "<p>bar</p>\n");
+ assert_non_null(d);
+ assert_string_equal(d, "bar");
+ free(html);
+ free(d);
+ d = NULL;
+ html = blogc_content_parse(
+ "# foo\n"
+ "\n"
+ "> qwe\n"
+ "> zxc\n"
+ "\n"
+ "bar\n", NULL, &d);
+ assert_non_null(html);
+ assert_string_equal(html,
+ "<h1 id=\"foo\">foo</h1>\n"
+ "<blockquote><p>qwe\n"
+ "zxc</p>\n"
+ "</blockquote>\n"
+ "<p>bar</p>\n");
+ assert_non_null(d);
+ assert_string_equal(d, "bar");
+ free(html);
+ free(d);
+}
+
+
+static void
+test_content_parse_description_crlf(void **state)
+{
+ char *d = NULL;
+ char *html = blogc_content_parse(
+ "# foo\r\n"
+ "\r\n"
+ "bar", NULL, &d);
+ assert_non_null(html);
+ assert_string_equal(html,
+ "<h1 id=\"foo\">foo</h1>\r\n"
+ "<p>bar</p>\r\n");
+ assert_non_null(d);
+ assert_string_equal(d, "bar");
+ free(html);
+ free(d);
+ d = NULL;
+ html = blogc_content_parse(
+ "# foo\r\n"
+ "\r\n"
+ "bar\r\n", NULL, &d);
+ assert_non_null(html);
+ assert_string_equal(html,
+ "<h1 id=\"foo\">foo</h1>\r\n"
+ "<p>bar</p>\r\n");
+ assert_non_null(d);
+ assert_string_equal(d, "bar");
+ free(html);
+ free(d);
+ d = NULL;
+ html = blogc_content_parse(
+ "# foo\r\n"
+ "\r\n"
+ "qwe\r\n"
+ "bar\r\n", NULL, &d);
+ assert_non_null(html);
+ assert_string_equal(html,
+ "<h1 id=\"foo\">foo</h1>\r\n"
+ "<p>qwe\r\n"
+ "bar</p>\r\n");
+ assert_non_null(d);
+ assert_string_equal(d, "qwe bar");
+ free(html);
+ free(d);
+ d = NULL;
+ html = blogc_content_parse(
+ "# foo\r\n"
+ "\r\n"
+ "> qwe\r\n"
+ "\r\n"
+ "bar\r\n", NULL, &d);
+ assert_non_null(html);
+ assert_string_equal(html,
+ "<h1 id=\"foo\">foo</h1>\r\n"
+ "<blockquote><p>qwe</p>\r\n"
+ "</blockquote>\r\n"
+ "<p>bar</p>\r\n");
+ assert_non_null(d);
+ assert_string_equal(d, "bar");
+ free(html);
+ free(d);
+ d = NULL;
+ html = blogc_content_parse(
+ "# foo\r\n"
+ "\r\n"
+ "> qwe\r\n"
+ "> zxc\r\n"
+ "\r\n"
+ "bar\r\n", NULL, &d);
+ assert_non_null(html);
+ assert_string_equal(html,
+ "<h1 id=\"foo\">foo</h1>\r\n"
+ "<blockquote><p>qwe\r\n"
+ "zxc</p>\r\n"
+ "</blockquote>\r\n"
+ "<p>bar</p>\r\n");
+ assert_non_null(d);
+ assert_string_equal(d, "bar");
+ free(html);
+ free(d);
+}
+
+
+static void
+test_content_parse_invalid_excerpt(void **state)
+{
+ size_t l = 0;
+ char *d = NULL;
+ char *html = blogc_content_parse(
+ "# test\n"
+ "\n"
+ "chunda\n"
+ "..\n"
+ "\n"
+ "guda\n"
+ "lol", &l, &d);
+ assert_non_null(html);
+ assert_int_equal(l, 0);
+ assert_non_null(d);
+ assert_string_equal(d, "chunda ..");
+ assert_string_equal(html,
+ "<h1 id=\"test\">test</h1>\n"
+ "<p>chunda\n"
+ "..</p>\n"
+ "<p>guda\n"
+ "lol</p>\n");
+ free(html);
+ l = 0;
+ free(d);
+ d = NULL;
+ html = blogc_content_parse(
+ "# test\n"
+ "\n"
+ "chunda\n"
+ "\n"
+ "...\n"
+ "guda\n"
+ "lol", &l, &d);
+ assert_non_null(html);
+ assert_int_equal(l, 0);
+ assert_non_null(d);
+ assert_string_equal(d, "chunda");
+ assert_string_equal(html,
+ "<h1 id=\"test\">test</h1>\n"
+ "<p>chunda</p>\n"
+ "<p>...\n"
+ "guda\n"
+ "lol</p>\n");
+ free(html);
+ l = 0;
+ free(d);
+ d = NULL;
+ html = blogc_content_parse(
+ "# test\n"
+ "\n"
+ "chunda..\n"
+ "\n"
+ "guda\n"
+ "lol", &l, &d);
+ assert_non_null(html);
+ assert_int_equal(l, 0);
+ assert_non_null(d);
+ assert_string_equal(d, "chunda..");
+ assert_string_equal(html,
+ "<h1 id=\"test\">test</h1>\n"
+ "<p>chunda..</p>\n"
+ "<p>guda\n"
+ "lol</p>\n");
+ free(html);
+ l = 0;
+ free(d);
+ d = NULL;
+ html = blogc_content_parse(
+ "# test\n"
+ "\n"
+ "chunda\n"
+ "\n"
+ "...guda\n"
+ "lol", &l, &d);
+ assert_non_null(html);
+ assert_int_equal(l, 0);
+ assert_non_null(d);
+ assert_string_equal(d, "chunda");
+ assert_string_equal(html,
+ "<h1 id=\"test\">test</h1>\n"
+ "<p>chunda</p>\n"
+ "<p>...guda\n"
+ "lol</p>\n");
+ free(html);
+ free(d);
+}
+
+
+static void
+test_content_parse_invalid_header(void **state)
+{
+ char *html = blogc_content_parse(
+ "asd\n"
+ "\n"
+ "##bola\n", NULL, NULL);
+ assert_non_null(html);
+ assert_string_equal(html,
+ "<p>asd</p>\n"
+ "<p>##bola</p>\n");
+ free(html);
+}
+
+
+static void
+test_content_parse_invalid_header_empty(void **state)
+{
+ char *html = blogc_content_parse(
+ "asd\n"
+ "\n"
+ "##\n"
+ "\n"
+ "qwe\n", NULL, NULL);
+ assert_non_null(html);
+ assert_string_equal(html,
+ "<p>asd</p>\n"
+ "<p>##\n"
+ "\n"
+ "qwe</p>\n");
+ free(html);
+}
+
+
+static void
+test_content_parse_invalid_blockquote(void **state)
+{
+ char *html = blogc_content_parse(
+ "> asd\n"
+ "> bola\n"
+ "> foo\n", NULL, NULL);
+ assert_non_null(html);
+ assert_string_equal(html,
+ "<p>&gt; asd\n"
+ "&gt; bola\n"
+ "&gt; foo</p>\n");
+ free(html);
+ html = blogc_content_parse(
+ "> asd\n"
+ "> bola", NULL, NULL);
+ assert_non_null(html);
+ assert_string_equal(html,
+ "<p>&gt; asd\n"
+ "&gt; bola</p>\n");
+ free(html);
+}
+
+
+static void
+test_content_parse_invalid_code(void **state)
+{
+ char *html = blogc_content_parse(
+ " asd\n"
+ " bola\n"
+ " foo\n", NULL, NULL);
+ assert_non_null(html);
+ assert_string_equal(html,
+ "<p> asd\n"
+ " bola\n"
+ " foo</p>\n");
+ free(html);
+ html = blogc_content_parse(
+ " asd\n"
+ " bola\n"
+ " foo", NULL, NULL);
+ assert_non_null(html);
+ assert_string_equal(html,
+ "<p> asd\n"
+ " bola\n"
+ " foo</p>\n");
+ free(html);
+}
+
+
+static void
+test_content_parse_invalid_horizontal_rule(void **state)
+{
+ char *html = blogc_content_parse("** asd", NULL, NULL);
+ assert_non_null(html);
+ assert_string_equal(html, "<p>** asd</p>\n");
+ free(html);
+ html = blogc_content_parse("** asd\n", NULL, NULL);
+ assert_non_null(html);
+ assert_string_equal(html, "<p>** asd</p>\n");
+ free(html);
+}
+
+
+static void
+test_content_parse_invalid_unordered_list(void **state)
+{
+ char *html = blogc_content_parse(
+ "* asd\n"
+ "1. qwe", NULL, NULL);
+ assert_non_null(html);
+ assert_string_equal(html,
+ "<p>* asd\n"
+ "1. qwe</p>\n");
+ free(html);
+ html = blogc_content_parse(
+ "* asd\n"
+ "1. qwe\n"
+ "\n", NULL, NULL);
+ assert_non_null(html);
+ assert_string_equal(html,
+ "<p>* asd\n"
+ "1. qwe</p>\n");
+ free(html);
+ html = blogc_content_parse(
+ "* asd\n"
+ "1. qwe\n", NULL, NULL);
+ assert_non_null(html);
+ assert_string_equal(html,
+ "<p>* asd\n"
+ "1. qwe"
+ "</p>\n");
+ free(html);
+ html = blogc_content_parse(
+ "* asd\n"
+ "1. qwe\n", NULL, NULL);
+ assert_non_null(html);
+ assert_string_equal(html,
+ "<p>* asd\n"
+ "1. qwe"
+ "</p>\n");
+ free(html);
+ html = blogc_content_parse(
+ "chunda\n"
+ "\n"
+ "* asd\n"
+ "1. qwe\n"
+ "\n"
+ "poi\n", NULL, NULL);
+ assert_non_null(html);
+ assert_string_equal(html,
+ "<p>chunda</p>\n"
+ "<p>* asd\n"
+ "1. qwe</p>\n"
+ "<p>poi</p>\n");
+ free(html);
+}
+
+
+static void
+test_content_parse_invalid_ordered_list(void **state)
+{
+ char *html = blogc_content_parse(
+ "1. asd\n"
+ "* qwe", NULL, NULL);
+ assert_non_null(html);
+ assert_string_equal(html,
+ "<p>1. asd\n"
+ "* qwe</p>\n");
+ free(html);
+ html = blogc_content_parse(
+ "1. asd\n"
+ "* qwe\n"
+ "\n", NULL, NULL);
+ assert_non_null(html);
+ assert_string_equal(html,
+ "<p>1. asd\n"
+ "* qwe</p>\n");
+ free(html);
+ html = blogc_content_parse(
+ "1. asd\n"
+ "* qwe\n", NULL, NULL);
+ assert_non_null(html);
+ assert_string_equal(html,
+ "<p>1. asd\n"
+ "* qwe"
+ "</p>\n");
+ free(html);
+ html = blogc_content_parse(
+ "1. asd\n"
+ "* qwe\n", NULL, NULL);
+ assert_non_null(html);
+ assert_string_equal(html,
+ "<p>1. asd\n"
+ "* qwe"
+ "</p>\n");
+ free(html);
+ html = blogc_content_parse(
+ "chunda\n"
+ "\n"
+ "1. asd\n"
+ "* qwe\n"
+ "\n"
+ "poi\n", NULL, NULL);
+ assert_non_null(html);
+ assert_string_equal(html,
+ "<p>chunda</p>\n"
+ "<p>1. asd\n"
+ "* qwe</p>\n"
+ "<p>poi</p>\n");
+ free(html);
+ html = blogc_content_parse(
+ "1 asd\n"
+ "* qwe\n", NULL, NULL);
+ assert_non_null(html);
+ assert_string_equal(html,
+ "<p>1 asd\n"
+ "* qwe</p>\n");
+ free(html);
+ html = blogc_content_parse(
+ "a. asd\n"
+ "2. qwe\n", NULL, NULL);
+ assert_non_null(html);
+ assert_string_equal(html,
+ "<p>a. asd\n"
+ "2. qwe</p>\n");
+ free(html);
+ html = blogc_content_parse(
+ "1.\nasd\n"
+ "2. qwe\n", NULL, NULL);
+ assert_non_null(html);
+ assert_string_equal(html,
+ "<p>1.\n"
+ "asd\n"
+ "2. qwe</p>\n");
+ free(html);
+ html = blogc_content_parse("1.\n", NULL, NULL);
+ assert_non_null(html);
+ assert_string_equal(html, "<p>1.</p>\n");
+ free(html);
+ html = blogc_content_parse("1 ", NULL, NULL);
+ assert_non_null(html);
+ assert_string_equal(html, "<p>1 </p>\n");
+ free(html);
+}
+
+
+static void
+test_content_parse_inline(void **state)
+{
+ char *html = blogc_content_parse_inline(
+ "**bola***asd* [![lol](http://google.com/lol.png) **lol** "
+ "\\[asd\\]\\(qwe\\)](http://google.com) ``chunda`` [[bola]] chunda[9]");
+ assert_non_null(html);
+ assert_string_equal(html,
+ "<strong>bola</strong><em>asd</em> "
+ "<a href=\"http://google.com\"><img src=\"http://google.com/lol.png\" "
+ "alt=\"lol\"> <strong>lol</strong> [asd](qwe)</a> "
+ "<code>chunda</code> <a href=\"bola\">bola</a> chunda[9]");
+ free(html);
+ html = blogc_content_parse_inline("*bola*");
+ assert_non_null(html);
+ assert_string_equal(html, "<em>bola</em>");
+ free(html);
+ html = blogc_content_parse_inline("bola!");
+ assert_non_null(html);
+ assert_string_equal(html, "bola!");
+ free(html);
+}
+
+
+static void
+test_content_parse_inline_em(void **state)
+{
+ char *html = blogc_content_parse_inline("*bola*");
+ assert_non_null(html);
+ assert_string_equal(html, "<em>bola</em>");
+ free(html);
+ html = blogc_content_parse_inline("*bola*\n");
+ assert_non_null(html);
+ assert_string_equal(html, "<em>bola</em>\n");
+ free(html);
+ html = blogc_content_parse_inline("*bo\\*la*\n");
+ assert_non_null(html);
+ assert_string_equal(html, "<em>bo*la</em>\n");
+ free(html);
+ html = blogc_content_parse_inline("_bola_");
+ assert_non_null(html);
+ assert_string_equal(html, "<em>bola</em>");
+ free(html);
+ html = blogc_content_parse_inline("_bola_\n");
+ assert_non_null(html);
+ assert_string_equal(html, "<em>bola</em>\n");
+ free(html);
+ html = blogc_content_parse_inline("_bo\\_la_\n");
+ assert_non_null(html);
+ assert_string_equal(html, "<em>bo_la</em>\n");
+ free(html);
+ html = blogc_content_parse_inline("_**bola**_\n");
+ assert_non_null(html);
+ assert_string_equal(html, "<em><strong>bola</strong></em>\n");
+ free(html);
+ html = blogc_content_parse_inline("_**bo\\_\\*la**_\n");
+ assert_non_null(html);
+ assert_string_equal(html, "<em><strong>bo_*la</strong></em>\n");
+ free(html);
+ html = blogc_content_parse_inline("_**bola\n");
+ assert_non_null(html);
+ assert_string_equal(html, "_**bola\n");
+ free(html);
+ html = blogc_content_parse_inline("**_bola\\*\n");
+ assert_non_null(html);
+ assert_string_equal(html, "**_bola*\n");
+ free(html);
+}
+
+
+static void
+test_content_parse_inline_strong(void **state)
+{
+ char *html = blogc_content_parse_inline("**bola**");
+ assert_non_null(html);
+ assert_string_equal(html, "<strong>bola</strong>");
+ free(html);
+ html = blogc_content_parse_inline("**bola**\n");
+ assert_non_null(html);
+ assert_string_equal(html, "<strong>bola</strong>\n");
+ free(html);
+ html = blogc_content_parse_inline("**bo\\*\\*la**\n");
+ assert_non_null(html);
+ assert_string_equal(html, "<strong>bo**la</strong>\n");
+ free(html);
+ html = blogc_content_parse_inline("__bola__");
+ assert_non_null(html);
+ assert_string_equal(html, "<strong>bola</strong>");
+ free(html);
+ html = blogc_content_parse_inline("__bola__\n");
+ assert_non_null(html);
+ assert_string_equal(html, "<strong>bola</strong>\n");
+ free(html);
+ html = blogc_content_parse_inline("__bo\\_\\_la__\n");
+ assert_non_null(html);
+ assert_string_equal(html, "<strong>bo__la</strong>\n");
+ free(html);
+ html = blogc_content_parse_inline("__*bola*__\n");
+ assert_non_null(html);
+ assert_string_equal(html, "<strong><em>bola</em></strong>\n");
+ free(html);
+ html = blogc_content_parse_inline("__*bo\\_\\*la*__\n");
+ assert_non_null(html);
+ assert_string_equal(html, "<strong><em>bo_*la</em></strong>\n");
+ free(html);
+ html = blogc_content_parse_inline("__*bola\n");
+ assert_non_null(html);
+ assert_string_equal(html, "__*bola\n");
+ free(html);
+ html = blogc_content_parse_inline("__*bola\\_\n");
+ assert_non_null(html);
+ assert_string_equal(html, "__*bola_\n");
+ free(html);
+}
+
+
+static void
+test_content_parse_inline_code(void **state)
+{
+ char *html = blogc_content_parse_inline("``bola``");
+ assert_non_null(html);
+ assert_string_equal(html, "<code>bola</code>");
+ free(html);
+ html = blogc_content_parse_inline("``bola``\n");
+ assert_non_null(html);
+ assert_string_equal(html, "<code>bola</code>\n");
+ free(html);
+ html = blogc_content_parse_inline("`bola`");
+ assert_non_null(html);
+ assert_string_equal(html, "<code>bola</code>");
+ free(html);
+ html = blogc_content_parse_inline("`bola`\n");
+ assert_non_null(html);
+ assert_string_equal(html, "<code>bola</code>\n");
+ free(html);
+ html = blogc_content_parse_inline("``bo*la``\n");
+ assert_non_null(html);
+ assert_string_equal(html, "<code>bo*la</code>\n");
+ free(html);
+ html = blogc_content_parse_inline("``bo<la``\n");
+ assert_non_null(html);
+ assert_string_equal(html, "<code>bo&lt;la</code>\n");
+ free(html);
+ html = blogc_content_parse_inline("`bo\\`\\`la`\n");
+ assert_non_null(html);
+ assert_string_equal(html, "<code>bo``la</code>\n");
+ free(html);
+ html = blogc_content_parse_inline("``bo\\`\\`la``\n");
+ assert_non_null(html);
+ assert_string_equal(html, "<code>bo``la</code>\n");
+ free(html);
+ html = blogc_content_parse_inline("``bola\n");
+ assert_non_null(html);
+ assert_string_equal(html, "``bola\n");
+ free(html);
+ html = blogc_content_parse_inline("`bola\n");
+ assert_non_null(html);
+ assert_string_equal(html, "`bola\n");
+ free(html);
+ html = blogc_content_parse_inline("``bola`\n");
+ assert_non_null(html);
+ assert_string_equal(html, "``bola`\n");
+ free(html);
+}
+
+
+static void
+test_content_parse_inline_link(void **state)
+{
+ char *html = blogc_content_parse_inline("[bola](http://example.org/)");
+ assert_non_null(html);
+ assert_string_equal(html, "<a href=\"http://example.org/\">bola</a>");
+ free(html);
+ html = blogc_content_parse_inline("[bola](http://example.org/)\n");
+ assert_non_null(html);
+ assert_string_equal(html, "<a href=\"http://example.org/\">bola</a>\n");
+ free(html);
+ html = blogc_content_parse_inline("[bola!](http://example.org/)\n");
+ assert_non_null(html);
+ assert_string_equal(html, "<a href=\"http://example.org/\">bola!</a>\n");
+ free(html);
+ html = blogc_content_parse_inline("[bola]\n(http://example.org/)\n");
+ assert_non_null(html);
+ assert_string_equal(html, "<a href=\"http://example.org/\">bola</a>\n");
+ free(html);
+ html = blogc_content_parse_inline("[bola]\r\n(http://example.org/)\n");
+ assert_non_null(html);
+ assert_string_equal(html, "<a href=\"http://example.org/\">bola</a>\n");
+ free(html);
+ html = blogc_content_parse_inline("[bola] \r\n (http://example.org/)\n");
+ assert_non_null(html);
+ assert_string_equal(html, "<a href=\"http://example.org/\">bola</a>\n");
+ free(html);
+ html = blogc_content_parse_inline("[bo\nla](http://example.org/)\n");
+ assert_non_null(html);
+ assert_string_equal(html, "<a href=\"http://example.org/\">bo\nla</a>\n");
+ free(html);
+ html = blogc_content_parse_inline("[``bola``](http://example.org/)\n");
+ assert_non_null(html);
+ assert_string_equal(html, "<a href=\"http://example.org/\"><code>bola</code></a>\n");
+ free(html);
+ html = blogc_content_parse_inline("[``bola(2)[3]**!\\```](http://example.org/)\n");
+ assert_non_null(html);
+ assert_string_equal(html, "<a href=\"http://example.org/\"><code>bola(2)[3]**!`</code></a>\n");
+ free(html);
+ html = blogc_content_parse_inline("test suite!)\n"
+ "depends on [cmocka](http://cmocka.org/), though.\n");
+ assert_non_null(html);
+ assert_string_equal(html, "test suite!)\n"
+ "depends on <a href=\"http://cmocka.org/\">cmocka</a>, though.\n");
+ free(html);
+ html = blogc_content_parse_inline("asd [bola]chunda(1234)");
+ assert_non_null(html);
+ assert_string_equal(html, "asd [bola]chunda(1234)");
+ free(html);
+ // "invalid"
+ html = blogc_content_parse_inline("[bola](\nhttp://example.org/)\n");
+ assert_non_null(html);
+ assert_string_equal(html, "<a href=\"\nhttp://example.org/\">bola</a>\n");
+ free(html);
+ html = blogc_content_parse_inline("[bo[]\\[\\]()la](http://example.org/?\\(\\))\n");
+ assert_non_null(html);
+ assert_string_equal(html, "<a href=\"http://example.org/?()\">bo[][]()la</a>\n");
+ free(html);
+ html = blogc_content_parse_inline("[bola](http://example.org/\n");
+ assert_non_null(html);
+ assert_string_equal(html, "[bola](http:&#x2F;&#x2F;example.org&#x2F;\n");
+ free(html);
+ html = blogc_content_parse_inline("[");
+ assert_non_null(html);
+ assert_string_equal(html, "[");
+ free(html);
+ html = blogc_content_parse_inline("[\n");
+ assert_non_null(html);
+ assert_string_equal(html, "[\n");
+ free(html);
+ html = blogc_content_parse_inline("[a");
+ assert_non_null(html);
+ assert_string_equal(html, "[a");
+ free(html);
+ html = blogc_content_parse_inline("[a\n");
+ assert_non_null(html);
+ assert_string_equal(html, "[a\n");
+ free(html);
+ html = blogc_content_parse_inline("[a]");
+ assert_non_null(html);
+ assert_string_equal(html, "[a]");
+ free(html);
+ html = blogc_content_parse_inline("[a]\n");
+ assert_non_null(html);
+ assert_string_equal(html, "[a]\n");
+ free(html);
+}
+
+
+static void
+test_content_parse_inline_link_auto(void **state)
+{
+ char *html = blogc_content_parse_inline("[[guda]]");
+ assert_non_null(html);
+ assert_string_equal(html, "<a href=\"guda\">guda</a>");
+ free(html);
+ html = blogc_content_parse_inline("[[guda]]\n");
+ assert_non_null(html);
+ assert_string_equal(html, "<a href=\"guda\">guda</a>\n");
+ free(html);
+ html = blogc_content_parse_inline("[[http://example.org/?\\[\\]]]\n");
+ assert_non_null(html);
+ assert_string_equal(html, "<a href=\"http://example.org/?[]\">http://example.org/?[]</a>\n");
+ free(html);
+ html = blogc_content_parse_inline("[[http://example.org/?\\[\\]a]]\n");
+ assert_non_null(html);
+ assert_string_equal(html, "<a href=\"http://example.org/?[]a\">http://example.org/?[]a</a>\n");
+ free(html);
+ html = blogc_content_parse_inline("[[guda]asd]");
+ assert_non_null(html);
+ assert_string_equal(html, "[[guda]asd]");
+ free(html);
+ html = blogc_content_parse_inline("[[guda]asd]\n");
+ assert_non_null(html);
+ assert_string_equal(html, "[[guda]asd]\n");
+ free(html);
+ html = blogc_content_parse_inline("[[guda]asd");
+ assert_non_null(html);
+ assert_string_equal(html, "[[guda]asd");
+ free(html);
+ html = blogc_content_parse_inline("[[guda]asd\n");
+ assert_non_null(html);
+ assert_string_equal(html, "[[guda]asd\n");
+ free(html);
+}
+
+
+static void
+test_content_parse_inline_image(void **state)
+{
+ char *html = blogc_content_parse_inline("![bola](http://example.org/)");
+ assert_non_null(html);
+ assert_string_equal(html, "<img src=\"http://example.org/\" alt=\"bola\">");
+ free(html);
+ html = blogc_content_parse_inline("![bola](http://example.org/)\n");
+ assert_non_null(html);
+ assert_string_equal(html, "<img src=\"http://example.org/\" alt=\"bola\">\n");
+ free(html);
+ html = blogc_content_parse_inline("![bola]\n(http://example.org/)\n");
+ assert_non_null(html);
+ assert_string_equal(html, "<img src=\"http://example.org/\" alt=\"bola\">\n");
+ free(html);
+ html = blogc_content_parse_inline("![bola]\r\n(http://example.org/)\n");
+ assert_non_null(html);
+ assert_string_equal(html, "<img src=\"http://example.org/\" alt=\"bola\">\n");
+ free(html);
+ html = blogc_content_parse_inline("![bola] \r\n (http://example.org/)\n");
+ assert_non_null(html);
+ assert_string_equal(html, "<img src=\"http://example.org/\" alt=\"bola\">\n");
+ free(html);
+ html = blogc_content_parse_inline(
+ "[![This is the image alt text](picture.jpg)](https://blogc.rgm.io)");
+ assert_non_null(html);
+ assert_string_equal(html,
+ "<a href=\"https://blogc.rgm.io\"><img src=\"picture.jpg\" "
+ "alt=\"This is the image alt text\"></a>");
+ free(html);
+ html = blogc_content_parse_inline(
+ "[![This is the image alt text]\n"
+ "(picture.jpg)](https://blogc.rgm.io)");
+ assert_non_null(html);
+ assert_string_equal(html,
+ "<a href=\"https://blogc.rgm.io\"><img src=\"picture.jpg\" "
+ "alt=\"This is the image alt text\"></a>");
+ free(html);
+ html = blogc_content_parse_inline(
+ "[![This is the image alt text]\n"
+ "(picture.jpg)]\n"
+ "(https://blogc.rgm.io)");
+ assert_non_null(html);
+ assert_string_equal(html,
+ "<a href=\"https://blogc.rgm.io\"><img src=\"picture.jpg\" "
+ "alt=\"This is the image alt text\"></a>");
+ free(html);
+ html = blogc_content_parse_inline("asd ![bola]chunda(1234)");
+ assert_non_null(html);
+ assert_string_equal(html, "asd ![bola]chunda(1234)");
+ free(html);
+ // "invalid"
+ html = blogc_content_parse_inline("![bo\nla](http://example.org/)\n");
+ assert_non_null(html);
+ assert_string_equal(html, "<img src=\"http://example.org/\" alt=\"bo\nla\">\n");
+ free(html);
+ html = blogc_content_parse_inline("![bola](\nhttp://example.org/)\n");
+ assert_non_null(html);
+ assert_string_equal(html, "<img src=\"\nhttp://example.org/\" alt=\"bola\">\n");
+ free(html);
+ html = blogc_content_parse_inline("![bo\\[\\]()la](http://example.org/?\\(\\))\n");
+ assert_non_null(html);
+ assert_string_equal(html, "<img src=\"http://example.org/?()\" alt=\"bo[]()la\">\n");
+ free(html);
+ html = blogc_content_parse_inline("![bola](http://example.org/\n");
+ assert_non_null(html);
+ assert_string_equal(html, "![bola](http:&#x2F;&#x2F;example.org&#x2F;\n");
+ free(html);
+ html = blogc_content_parse_inline("!");
+ assert_non_null(html);
+ assert_string_equal(html, "!");
+ free(html);
+ html = blogc_content_parse_inline("![");
+ assert_non_null(html);
+ assert_string_equal(html, "![");
+ free(html);
+ html = blogc_content_parse_inline("!\n");
+ assert_non_null(html);
+ assert_string_equal(html, "!\n");
+ free(html);
+ html = blogc_content_parse_inline("![\n");
+ assert_non_null(html);
+ assert_string_equal(html, "![\n");
+ free(html);
+ html = blogc_content_parse_inline("![a");
+ assert_non_null(html);
+ assert_string_equal(html, "![a");
+ free(html);
+ html = blogc_content_parse_inline("!a\n");
+ assert_non_null(html);
+ assert_string_equal(html, "!a\n");
+ free(html);
+ html = blogc_content_parse_inline("![a\n");
+ assert_non_null(html);
+ assert_string_equal(html, "![a\n");
+ free(html);
+ html = blogc_content_parse_inline("![a]");
+ assert_non_null(html);
+ assert_string_equal(html, "![a]");
+ free(html);
+ html = blogc_content_parse_inline("!a]\n");
+ assert_non_null(html);
+ assert_string_equal(html, "!a]\n");
+ free(html);
+ html = blogc_content_parse_inline("![a]\n");
+ assert_non_null(html);
+ assert_string_equal(html, "![a]\n");
+ free(html);
+}
+
+
+static void
+test_content_parse_inline_line_break(void **state)
+{
+ char *html = blogc_content_parse_inline("asd \n");
+ assert_non_null(html);
+ assert_string_equal(html, "asd<br />\n");
+ free(html);
+ html = blogc_content_parse_inline("asd ");
+ assert_non_null(html);
+ assert_string_equal(html, "asd<br />");
+ free(html);
+ html = blogc_content_parse_inline("asd ");
+ assert_non_null(html);
+ assert_string_equal(html, "asd<br />");
+ free(html);
+ // invalid
+ html = blogc_content_parse_inline("asd ");
+ assert_non_null(html);
+ assert_string_equal(html, "asd ");
+ free(html);
+ html = blogc_content_parse_inline("asd \n");
+ assert_non_null(html);
+ assert_string_equal(html, "asd \n");
+ free(html);
+ html = blogc_content_parse_inline("asd a\n");
+ assert_non_null(html);
+ assert_string_equal(html, "asd a\n");
+ free(html);
+ html = blogc_content_parse_inline("asd a\n");
+ assert_non_null(html);
+ assert_string_equal(html, "asd a\n");
+ free(html);
+}
+
+
+static void
+test_content_parse_inline_line_break_crlf(void **state)
+{
+ char *html = blogc_content_parse_inline("asd \r\n");
+ assert_non_null(html);
+ assert_string_equal(html, "asd<br />\r\n");
+ free(html);
+ html = blogc_content_parse_inline("asd \r\n");
+ assert_non_null(html);
+ assert_string_equal(html, "asd \r\n");
+ free(html);
+}
+
+
+static void
+test_content_parse_inline_endash_emdash(void **state)
+{
+ char *html = blogc_content_parse_inline("foo -- bar");
+ assert_non_null(html);
+ assert_string_equal(html, "foo &ndash; bar");
+ free(html);
+ html = blogc_content_parse_inline("foo --- bar");
+ assert_non_null(html);
+ assert_string_equal(html, "foo &mdash; bar");
+ free(html);
+ html = blogc_content_parse_inline("foo --");
+ assert_non_null(html);
+ assert_string_equal(html, "foo &ndash;");
+ free(html);
+ html = blogc_content_parse_inline("foo ---");
+ assert_non_null(html);
+ assert_string_equal(html, "foo &mdash;");
+ free(html);
+ html = blogc_content_parse_inline("foo \\-\\-");
+ assert_non_null(html);
+ assert_string_equal(html, "foo --");
+ free(html);
+ html = blogc_content_parse_inline("foo \\-\\-\\-");
+ assert_non_null(html);
+ assert_string_equal(html, "foo ---");
+ free(html);
+ html = blogc_content_parse_inline("foo \\---");
+ assert_non_null(html);
+ assert_string_equal(html, "foo -&ndash;");
+ free(html);
+ html = blogc_content_parse_inline("foo \\----");
+ assert_non_null(html);
+ assert_string_equal(html, "foo -&mdash;");
+ free(html);
+ html = blogc_content_parse_inline("foo \\-\\- bar");
+ assert_non_null(html);
+ assert_string_equal(html, "foo -- bar");
+ free(html);
+ html = blogc_content_parse_inline("foo \\-\\-\\- bar");
+ assert_non_null(html);
+ assert_string_equal(html, "foo --- bar");
+ free(html);
+ html = blogc_content_parse_inline("foo \\--- bar");
+ assert_non_null(html);
+ assert_string_equal(html, "foo -&ndash; bar");
+ free(html);
+ html = blogc_content_parse_inline("foo \\---- bar");
+ assert_non_null(html);
+ assert_string_equal(html, "foo -&mdash; bar");
+ free(html);
+ html = blogc_content_parse_inline("`foo -- bar`");
+ assert_non_null(html);
+ assert_string_equal(html, "<code>foo -- bar</code>");
+ free(html);
+ html = blogc_content_parse_inline("`foo --- bar`");
+ assert_non_null(html);
+ assert_string_equal(html, "<code>foo --- bar</code>");
+ free(html);
+ html = blogc_content_parse_inline("``foo -- bar``");
+ assert_non_null(html);
+ assert_string_equal(html, "<code>foo -- bar</code>");
+ free(html);
+ html = blogc_content_parse_inline("``foo --- bar``");
+ assert_non_null(html);
+ assert_string_equal(html, "<code>foo --- bar</code>");
+ free(html);
+}
+
+
+int
+main(void)
+{
+ const UnitTest tests[] = {
+ unit_test(test_slugify),
+ unit_test(test_htmlentities),
+ unit_test(test_fix_description),
+ unit_test(test_is_ordered_list_item),
+ unit_test(test_content_parse),
+ unit_test(test_content_parse_crlf),
+ unit_test(test_content_parse_with_excerpt),
+ unit_test(test_content_parse_with_excerpt_crlf),
+ unit_test(test_content_parse_header),
+ unit_test(test_content_parse_header_crlf),
+ unit_test(test_content_parse_html),
+ unit_test(test_content_parse_html_crlf),
+ unit_test(test_content_parse_blockquote),
+ unit_test(test_content_parse_blockquote_crlf),
+ unit_test(test_content_parse_code),
+ unit_test(test_content_parse_code_crlf),
+ unit_test(test_content_parse_horizontal_rule),
+ unit_test(test_content_parse_horizontal_rule_crlf),
+ unit_test(test_content_parse_unordered_list),
+ unit_test(test_content_parse_unordered_list_crlf),
+ unit_test(test_content_parse_ordered_list),
+ unit_test(test_content_parse_ordered_list_crlf),
+ unit_test(test_content_parse_description),
+ unit_test(test_content_parse_description_crlf),
+ unit_test(test_content_parse_invalid_excerpt),
+ unit_test(test_content_parse_invalid_header),
+ unit_test(test_content_parse_invalid_header_empty),
+ unit_test(test_content_parse_invalid_blockquote),
+ unit_test(test_content_parse_invalid_code),
+ unit_test(test_content_parse_invalid_horizontal_rule),
+ unit_test(test_content_parse_invalid_unordered_list),
+ unit_test(test_content_parse_invalid_ordered_list),
+ unit_test(test_content_parse_inline),
+ unit_test(test_content_parse_inline_em),
+ unit_test(test_content_parse_inline_strong),
+ unit_test(test_content_parse_inline_code),
+ unit_test(test_content_parse_inline_link),
+ unit_test(test_content_parse_inline_link_auto),
+ unit_test(test_content_parse_inline_image),
+ unit_test(test_content_parse_inline_line_break),
+ unit_test(test_content_parse_inline_line_break_crlf),
+ unit_test(test_content_parse_inline_endash_emdash),
+ };
+ return run_tests(tests);
+}
diff --git a/tests/blogc/check_datetime_parser.c b/tests/blogc/check_datetime_parser.c
new file mode 100644
index 0000000..ec0f120
--- /dev/null
+++ b/tests/blogc/check_datetime_parser.c
@@ -0,0 +1,671 @@
+/*
+ * blogc: A blog compiler.
+ * Copyright (C) 2015-2016 Rafael G. Martins <rafael@rafaelmartins.eng.br>
+ *
+ * This program can be distributed under the terms of the BSD License.
+ * See the file LICENSE.
+ */
+
+#include <stdarg.h>
+#include <stddef.h>
+#include <setjmp.h>
+#include <cmocka.h>
+#include <stdlib.h>
+#include <locale.h>
+#include "../../src/blogc/error.h"
+#include "../../src/blogc/datetime-parser.h"
+
+
+static void
+test_convert_datetime(void **state)
+{
+ blogc_error_t *err = NULL;
+ char *dt = blogc_convert_datetime("2010-11-30 12:13:14",
+ "%b %d, %Y, %I:%M:%S %p GMT", &err);
+ assert_null(err);
+ assert_string_equal(dt, "Nov 30, 2010, 12:13:14 PM GMT");
+ free(dt);
+}
+
+
+static void
+test_convert_datetime_implicit_seconds(void **state)
+{
+ blogc_error_t *err = NULL;
+ char *dt = blogc_convert_datetime("2010-11-30 12:13",
+ "%b %d, %Y, %I:%M:%S %p GMT", &err);
+ assert_null(err);
+ assert_string_equal(dt, "Nov 30, 2010, 12:13:00 PM GMT");
+ free(dt);
+}
+
+
+static void
+test_convert_datetime_implicit_minutes(void **state)
+{
+ blogc_error_t *err = NULL;
+ char *dt = blogc_convert_datetime("2010-11-30 12",
+ "%b %d, %Y, %I:%M:%S %p GMT", &err);
+ assert_null(err);
+ assert_string_equal(dt, "Nov 30, 2010, 12:00:00 PM GMT");
+ free(dt);
+}
+
+
+static void
+test_convert_datetime_implicit_hours(void **state)
+{
+ blogc_error_t *err = NULL;
+ char *dt = blogc_convert_datetime("2010-11-30",
+ "%b %d, %Y, %I:%M:%S %p GMT", &err);
+ assert_null(err);
+ assert_string_equal(dt, "Nov 30, 2010, 12:00:00 AM GMT");
+ free(dt);
+}
+
+
+static void
+test_convert_datetime_invalid_formats(void **state)
+{
+ blogc_error_t *err = NULL;
+ char *dt = blogc_convert_datetime("", "%b %d, %Y, %I:%M:%S %p GMT", &err);
+ assert_null(dt);
+ assert_non_null(err);
+ assert_int_equal(err->type, BLOGC_WARNING_DATETIME_PARSER);
+ assert_string_equal(err->msg,
+ "Invalid datetime string. Found '', formats allowed are: "
+ "'yyyy-mm-dd hh:mm:ss', 'yyyy-mm-dd hh:ss', 'yyyy-mm-dd hh' and "
+ "'yyyy-mm-dd'.");
+ blogc_error_free(err);
+
+ err = NULL;
+ dt = blogc_convert_datetime("2", "%b %d, %Y, %I:%M:%S %p GMT", &err);
+ assert_null(dt);
+ assert_non_null(err);
+ assert_int_equal(err->type, BLOGC_WARNING_DATETIME_PARSER);
+ assert_string_equal(err->msg,
+ "Invalid datetime string. Found '2', formats allowed are: "
+ "'yyyy-mm-dd hh:mm:ss', 'yyyy-mm-dd hh:ss', 'yyyy-mm-dd hh' and "
+ "'yyyy-mm-dd'.");
+ blogc_error_free(err);
+
+ err = NULL;
+ dt = blogc_convert_datetime("20", "%b %d, %Y, %I:%M:%S %p GMT", &err);
+ assert_null(dt);
+ assert_non_null(err);
+ assert_int_equal(err->type, BLOGC_WARNING_DATETIME_PARSER);
+ assert_string_equal(err->msg,
+ "Invalid datetime string. Found '20', formats allowed are: "
+ "'yyyy-mm-dd hh:mm:ss', 'yyyy-mm-dd hh:ss', 'yyyy-mm-dd hh' and "
+ "'yyyy-mm-dd'.");
+ blogc_error_free(err);
+
+ err = NULL;
+ dt = blogc_convert_datetime("201", "%b %d, %Y, %I:%M:%S %p GMT", &err);
+ assert_null(dt);
+ assert_non_null(err);
+ assert_int_equal(err->type, BLOGC_WARNING_DATETIME_PARSER);
+ assert_string_equal(err->msg,
+ "Invalid datetime string. Found '201', formats allowed are: "
+ "'yyyy-mm-dd hh:mm:ss', 'yyyy-mm-dd hh:ss', 'yyyy-mm-dd hh' and "
+ "'yyyy-mm-dd'.");
+ blogc_error_free(err);
+
+ err = NULL;
+ dt = blogc_convert_datetime("2010", "%b %d, %Y, %I:%M:%S %p GMT", &err);
+ assert_null(dt);
+ assert_non_null(err);
+ assert_int_equal(err->type, BLOGC_WARNING_DATETIME_PARSER);
+ assert_string_equal(err->msg,
+ "Invalid datetime string. Found '2010', formats allowed are: "
+ "'yyyy-mm-dd hh:mm:ss', 'yyyy-mm-dd hh:ss', 'yyyy-mm-dd hh' and "
+ "'yyyy-mm-dd'.");
+ blogc_error_free(err);
+
+ err = NULL;
+ dt = blogc_convert_datetime("2010-", "%b %d, %Y, %I:%M:%S %p GMT", &err);
+ assert_null(dt);
+ assert_non_null(err);
+ assert_int_equal(err->type, BLOGC_WARNING_DATETIME_PARSER);
+ assert_string_equal(err->msg,
+ "Invalid datetime string. Found '2010-', formats allowed are: "
+ "'yyyy-mm-dd hh:mm:ss', 'yyyy-mm-dd hh:ss', 'yyyy-mm-dd hh' and "
+ "'yyyy-mm-dd'.");
+ blogc_error_free(err);
+
+ err = NULL;
+ dt = blogc_convert_datetime("2010-1", "%b %d, %Y, %I:%M:%S %p GMT", &err);
+ assert_null(dt);
+ assert_non_null(err);
+ assert_int_equal(err->type, BLOGC_WARNING_DATETIME_PARSER);
+ assert_string_equal(err->msg,
+ "Invalid datetime string. Found '2010-1', formats allowed are: "
+ "'yyyy-mm-dd hh:mm:ss', 'yyyy-mm-dd hh:ss', 'yyyy-mm-dd hh' and "
+ "'yyyy-mm-dd'.");
+ blogc_error_free(err);
+
+ err = NULL;
+ dt = blogc_convert_datetime("2010-11", "%b %d, %Y, %I:%M:%S %p GMT", &err);
+ assert_null(dt);
+ assert_non_null(err);
+ assert_int_equal(err->type, BLOGC_WARNING_DATETIME_PARSER);
+ assert_string_equal(err->msg,
+ "Invalid datetime string. Found '2010-11', formats allowed are: "
+ "'yyyy-mm-dd hh:mm:ss', 'yyyy-mm-dd hh:ss', 'yyyy-mm-dd hh' and "
+ "'yyyy-mm-dd'.");
+ blogc_error_free(err);
+
+ err = NULL;
+ dt = blogc_convert_datetime("2010-11-", "%b %d, %Y, %I:%M:%S %p GMT", &err);
+ assert_null(dt);
+ assert_non_null(err);
+ assert_int_equal(err->type, BLOGC_WARNING_DATETIME_PARSER);
+ assert_string_equal(err->msg,
+ "Invalid datetime string. Found '2010-11-', formats allowed are: "
+ "'yyyy-mm-dd hh:mm:ss', 'yyyy-mm-dd hh:ss', 'yyyy-mm-dd hh' and "
+ "'yyyy-mm-dd'.");
+ blogc_error_free(err);
+
+ err = NULL;
+ dt = blogc_convert_datetime("2010-11-3", "%b %d, %Y, %I:%M:%S %p GMT", &err);
+ assert_null(dt);
+ assert_non_null(err);
+ assert_int_equal(err->type, BLOGC_WARNING_DATETIME_PARSER);
+ assert_string_equal(err->msg,
+ "Invalid datetime string. Found '2010-11-3', formats allowed are: "
+ "'yyyy-mm-dd hh:mm:ss', 'yyyy-mm-dd hh:ss', 'yyyy-mm-dd hh' and "
+ "'yyyy-mm-dd'.");
+ blogc_error_free(err);
+
+ err = NULL;
+ dt = blogc_convert_datetime("2010-11-30 ", "%b %d, %Y, %I:%M:%S %p GMT", &err);
+ assert_null(dt);
+ assert_non_null(err);
+ assert_int_equal(err->type, BLOGC_WARNING_DATETIME_PARSER);
+ assert_string_equal(err->msg,
+ "Invalid datetime string. Found '2010-11-30 ', formats allowed are: "
+ "'yyyy-mm-dd hh:mm:ss', 'yyyy-mm-dd hh:ss', 'yyyy-mm-dd hh' and "
+ "'yyyy-mm-dd'.");
+ blogc_error_free(err);
+
+ err = NULL;
+ dt = blogc_convert_datetime("2010-11-30 1", "%b %d, %Y, %I:%M:%S %p GMT", &err);
+ assert_null(dt);
+ assert_non_null(err);
+ assert_int_equal(err->type, BLOGC_WARNING_DATETIME_PARSER);
+ assert_string_equal(err->msg,
+ "Invalid datetime string. Found '2010-11-30 1', formats allowed are: "
+ "'yyyy-mm-dd hh:mm:ss', 'yyyy-mm-dd hh:ss', 'yyyy-mm-dd hh' and "
+ "'yyyy-mm-dd'.");
+ blogc_error_free(err);
+
+ err = NULL;
+ dt = blogc_convert_datetime("2010-11-30 12:1", "%b %d, %Y, %I:%M:%S %p GMT",
+ &err);
+ assert_null(dt);
+ assert_non_null(err);
+ assert_int_equal(err->type, BLOGC_WARNING_DATETIME_PARSER);
+ assert_string_equal(err->msg,
+ "Invalid datetime string. Found '2010-11-30 12:1', formats allowed are: "
+ "'yyyy-mm-dd hh:mm:ss', 'yyyy-mm-dd hh:ss', 'yyyy-mm-dd hh' and "
+ "'yyyy-mm-dd'.");
+ blogc_error_free(err);
+
+ err = NULL;
+ dt = blogc_convert_datetime("2010-11-30 12:13:1", "%b %d, %Y, %I:%M:%S %p GMT",
+ &err);
+ assert_null(dt);
+ assert_non_null(err);
+ assert_int_equal(err->type, BLOGC_WARNING_DATETIME_PARSER);
+ assert_string_equal(err->msg,
+ "Invalid datetime string. Found '2010-11-30 12:13:1', formats allowed are: "
+ "'yyyy-mm-dd hh:mm:ss', 'yyyy-mm-dd hh:ss', 'yyyy-mm-dd hh' and "
+ "'yyyy-mm-dd'.");
+ blogc_error_free(err);
+}
+
+
+static void
+test_convert_datetime_invalid_1st_year(void **state)
+{
+ blogc_error_t *err = NULL;
+ char *dt = blogc_convert_datetime("a010-11-30 12:13:14",
+ "%b %d, %Y, %I:%M:%S %p GMT", &err);
+ assert_null(dt);
+ assert_non_null(err);
+ assert_int_equal(err->type, BLOGC_WARNING_DATETIME_PARSER);
+ assert_string_equal(err->msg,
+ "Invalid first digit of year. Found 'a', must be integer >= 0 and <= 9.");
+ blogc_error_free(err);
+}
+
+
+static void
+test_convert_datetime_invalid_2nd_year(void **state)
+{
+ blogc_error_t *err = NULL;
+ char *dt = blogc_convert_datetime("2a10-11-30 12:13:14",
+ "%b %d, %Y, %I:%M:%S %p GMT", &err);
+ assert_null(dt);
+ assert_non_null(err);
+ assert_int_equal(err->type, BLOGC_WARNING_DATETIME_PARSER);
+ assert_string_equal(err->msg,
+ "Invalid second digit of year. Found 'a', must be integer >= 0 and <= 9.");
+ blogc_error_free(err);
+}
+
+
+static void
+test_convert_datetime_invalid_3rd_year(void **state)
+{
+ blogc_error_t *err = NULL;
+ char *dt = blogc_convert_datetime("20a0-11-30 12:13:14",
+ "%b %d, %Y, %I:%M:%S %p GMT", &err);
+ assert_null(dt);
+ assert_non_null(err);
+ assert_int_equal(err->type, BLOGC_WARNING_DATETIME_PARSER);
+ assert_string_equal(err->msg,
+ "Invalid third digit of year. Found 'a', must be integer >= 0 and <= 9.");
+ blogc_error_free(err);
+}
+
+
+static void
+test_convert_datetime_invalid_4th_year(void **state)
+{
+ blogc_error_t *err = NULL;
+ char *dt = blogc_convert_datetime("201a-11-30 12:13:14",
+ "%b %d, %Y, %I:%M:%S %p GMT", &err);
+ assert_null(dt);
+ assert_non_null(err);
+ assert_int_equal(err->type, BLOGC_WARNING_DATETIME_PARSER);
+ assert_string_equal(err->msg,
+ "Invalid fourth digit of year. Found 'a', must be integer >= 0 and <= 9.");
+ blogc_error_free(err);
+}
+
+
+static void
+test_convert_datetime_invalid_year(void **state)
+{
+ blogc_error_t *err = NULL;
+ char *dt = blogc_convert_datetime("1899-11-30 12:13:14",
+ "%b %d, %Y, %I:%M:%S %p GMT", &err);
+ assert_null(dt);
+ assert_non_null(err);
+ assert_int_equal(err->type, BLOGC_WARNING_DATETIME_PARSER);
+ assert_string_equal(err->msg,
+ "Invalid year. Found 1899, must be >= 1900.");
+ blogc_error_free(err);
+}
+
+
+static void
+test_convert_datetime_invalid_1st_hyphen(void **state)
+{
+ blogc_error_t *err = NULL;
+ char *dt = blogc_convert_datetime("2010 11-30 12:13:14",
+ "%b %d, %Y, %I:%M:%S %p GMT", &err);
+ assert_null(dt);
+ assert_non_null(err);
+ assert_int_equal(err->type, BLOGC_WARNING_DATETIME_PARSER);
+ assert_string_equal(err->msg,
+ "Invalid separator between year and month. Found ' ', must be '-'.");
+ blogc_error_free(err);
+}
+
+
+static void
+test_convert_datetime_invalid_1st_month(void **state)
+{
+ blogc_error_t *err = NULL;
+ char *dt = blogc_convert_datetime("2010-a1-30 12:13:14",
+ "%b %d, %Y, %I:%M:%S %p GMT", &err);
+ assert_null(dt);
+ assert_non_null(err);
+ assert_int_equal(err->type, BLOGC_WARNING_DATETIME_PARSER);
+ assert_string_equal(err->msg,
+ "Invalid first digit of month. Found 'a', must be integer >= 0 and <= 1.");
+ blogc_error_free(err);
+}
+
+
+static void
+test_convert_datetime_invalid_2nd_month(void **state)
+{
+ blogc_error_t *err = NULL;
+ char *dt = blogc_convert_datetime("2010-1a-30 12:13:14",
+ "%b %d, %Y, %I:%M:%S %p GMT", &err);
+ assert_null(dt);
+ assert_non_null(err);
+ assert_int_equal(err->type, BLOGC_WARNING_DATETIME_PARSER);
+ assert_string_equal(err->msg,
+ "Invalid second digit of month. Found 'a', must be integer >= 0 and <= 9.");
+ blogc_error_free(err);
+}
+
+
+static void
+test_convert_datetime_invalid_month(void **state)
+{
+ blogc_error_t *err = NULL;
+ char *dt = blogc_convert_datetime("2010-13-30 12:13:14",
+ "%b %d, %Y, %I:%M:%S %p GMT", &err);
+ assert_null(dt);
+ assert_non_null(err);
+ assert_int_equal(err->type, BLOGC_WARNING_DATETIME_PARSER);
+ assert_string_equal(err->msg,
+ "Invalid month. Found 13, must be >= 1 and <= 12.");
+ blogc_error_free(err);
+}
+
+
+static void
+test_convert_datetime_invalid_2nd_hyphen(void **state)
+{
+ blogc_error_t *err = NULL;
+ char *dt = blogc_convert_datetime("2010-11 30 12:13:14",
+ "%b %d, %Y, %I:%M:%S %p GMT", &err);
+ assert_null(dt);
+ assert_non_null(err);
+ assert_int_equal(err->type, BLOGC_WARNING_DATETIME_PARSER);
+ assert_string_equal(err->msg,
+ "Invalid separator between month and day. Found ' ', must be '-'.");
+ blogc_error_free(err);
+}
+
+
+static void
+test_convert_datetime_invalid_1st_day(void **state)
+{
+ blogc_error_t *err = NULL;
+ char *dt = blogc_convert_datetime("2010-11-a0 12:13:14",
+ "%b %d, %Y, %I:%M:%S %p GMT", &err);
+ assert_null(dt);
+ assert_non_null(err);
+ assert_int_equal(err->type, BLOGC_WARNING_DATETIME_PARSER);
+ assert_string_equal(err->msg,
+ "Invalid first digit of day. Found 'a', must be integer >= 0 and <= 3.");
+ blogc_error_free(err);
+}
+
+
+static void
+test_convert_datetime_invalid_2nd_day(void **state)
+{
+ blogc_error_t *err = NULL;
+ char *dt = blogc_convert_datetime("2010-11-3a 12:13:14",
+ "%b %d, %Y, %I:%M:%S %p GMT", &err);
+ assert_null(dt);
+ assert_non_null(err);
+ assert_int_equal(err->type, BLOGC_WARNING_DATETIME_PARSER);
+ assert_string_equal(err->msg,
+ "Invalid second digit of day. Found 'a', must be integer >= 0 and <= 9.");
+ blogc_error_free(err);
+}
+
+
+static void
+test_convert_datetime_invalid_day(void **state)
+{
+ blogc_error_t *err = NULL;
+ char *dt = blogc_convert_datetime("2010-12-32 12:13:14",
+ "%b %d, %Y, %I:%M:%S %p GMT", &err);
+ assert_null(dt);
+ assert_non_null(err);
+ assert_int_equal(err->type, BLOGC_WARNING_DATETIME_PARSER);
+ assert_string_equal(err->msg,
+ "Invalid day. Found 32, must be >= 1 and <= 31.");
+ blogc_error_free(err);
+}
+
+
+static void
+test_convert_datetime_invalid_space(void **state)
+{
+ blogc_error_t *err = NULL;
+ char *dt = blogc_convert_datetime("2010-11-30-12:13:14",
+ "%b %d, %Y, %I:%M:%S %p GMT", &err);
+ assert_null(dt);
+ assert_non_null(err);
+ assert_int_equal(err->type, BLOGC_WARNING_DATETIME_PARSER);
+ assert_string_equal(err->msg,
+ "Invalid separator between date and time. Found '-', must be ' ' "
+ "(empty space).");
+ blogc_error_free(err);
+}
+
+
+static void
+test_convert_datetime_invalid_1st_hours(void **state)
+{
+ blogc_error_t *err = NULL;
+ char *dt = blogc_convert_datetime("2010-11-30 a2:13:14",
+ "%b %d, %Y, %I:%M:%S %p GMT", &err);
+ assert_null(dt);
+ assert_non_null(err);
+ assert_int_equal(err->type, BLOGC_WARNING_DATETIME_PARSER);
+ assert_string_equal(err->msg,
+ "Invalid first digit of hours. Found 'a', must be integer >= 0 and <= 2.");
+ blogc_error_free(err);
+}
+
+
+static void
+test_convert_datetime_invalid_2nd_hours(void **state)
+{
+ blogc_error_t *err = NULL;
+ char *dt = blogc_convert_datetime("2010-11-30 1a:13:14",
+ "%b %d, %Y, %I:%M:%S %p GMT", &err);
+ assert_null(dt);
+ assert_non_null(err);
+ assert_int_equal(err->type, BLOGC_WARNING_DATETIME_PARSER);
+ assert_string_equal(err->msg,
+ "Invalid second digit of hours. Found 'a', must be integer >= 0 and <= 9.");
+ blogc_error_free(err);
+}
+
+
+static void
+test_convert_datetime_invalid_hours(void **state)
+{
+ blogc_error_t *err = NULL;
+ char *dt = blogc_convert_datetime("2010-12-30 24:13:14",
+ "%b %d, %Y, %I:%M:%S %p GMT", &err);
+ assert_null(dt);
+ assert_non_null(err);
+ assert_int_equal(err->type, BLOGC_WARNING_DATETIME_PARSER);
+ assert_string_equal(err->msg,
+ "Invalid hours. Found 24, must be >= 0 and <= 23.");
+ blogc_error_free(err);
+}
+
+
+static void
+test_convert_datetime_invalid_1st_colon(void **state)
+{
+ blogc_error_t *err = NULL;
+ char *dt = blogc_convert_datetime("2010-11-30 12 13:14",
+ "%b %d, %Y, %I:%M:%S %p GMT", &err);
+ assert_null(dt);
+ assert_non_null(err);
+ assert_int_equal(err->type, BLOGC_WARNING_DATETIME_PARSER);
+ assert_string_equal(err->msg,
+ "Invalid separator between hours and minutes. Found ' ', must be ':'.");
+ blogc_error_free(err);
+}
+
+
+static void
+test_convert_datetime_invalid_1st_minutes(void **state)
+{
+ blogc_error_t *err = NULL;
+ char *dt = blogc_convert_datetime("2010-11-30 12:a3:14",
+ "%b %d, %Y, %I:%M:%S %p GMT", &err);
+ assert_null(dt);
+ assert_non_null(err);
+ assert_int_equal(err->type, BLOGC_WARNING_DATETIME_PARSER);
+ assert_string_equal(err->msg,
+ "Invalid first digit of minutes. Found 'a', must be integer >= 0 and <= 5.");
+ blogc_error_free(err);
+}
+
+
+static void
+test_convert_datetime_invalid_2nd_minutes(void **state)
+{
+ blogc_error_t *err = NULL;
+ char *dt = blogc_convert_datetime("2010-11-30 12:1a:14",
+ "%b %d, %Y, %I:%M:%S %p GMT", &err);
+ assert_null(dt);
+ assert_non_null(err);
+ assert_int_equal(err->type, BLOGC_WARNING_DATETIME_PARSER);
+ assert_string_equal(err->msg,
+ "Invalid second digit of minutes. Found 'a', must be integer >= 0 and <= 9.");
+ blogc_error_free(err);
+}
+
+
+static void
+test_convert_datetime_invalid_2nd_colon(void **state)
+{
+ blogc_error_t *err = NULL;
+ char *dt = blogc_convert_datetime("2010-11-30 12:13 14",
+ "%b %d, %Y, %I:%M:%S %p GMT", &err);
+ assert_null(dt);
+ assert_non_null(err);
+ assert_int_equal(err->type, BLOGC_WARNING_DATETIME_PARSER);
+ assert_string_equal(err->msg,
+ "Invalid separator between minutes and seconds. Found ' ', must be ':'.");
+ blogc_error_free(err);
+}
+
+
+static void
+test_convert_datetime_invalid_1st_seconds(void **state)
+{
+ blogc_error_t *err = NULL;
+ char *dt = blogc_convert_datetime("2010-11-30 12:13:a4",
+ "%b %d, %Y, %I:%M:%S %p GMT", &err);
+ assert_null(dt);
+ assert_non_null(err);
+ assert_int_equal(err->type, BLOGC_WARNING_DATETIME_PARSER);
+ assert_string_equal(err->msg,
+ "Invalid first digit of seconds. Found 'a', must be integer >= 0 and <= 6.");
+ blogc_error_free(err);
+}
+
+
+static void
+test_convert_datetime_invalid_2nd_seconds(void **state)
+{
+ blogc_error_t *err = NULL;
+ char *dt = blogc_convert_datetime("2010-11-30 12:13:1a",
+ "%b %d, %Y, %I:%M:%S %p GMT", &err);
+ assert_null(dt);
+ assert_non_null(err);
+ assert_int_equal(err->type, BLOGC_WARNING_DATETIME_PARSER);
+ assert_string_equal(err->msg,
+ "Invalid second digit of seconds. Found 'a', must be integer >= 0 and <= 9.");
+ blogc_error_free(err);
+}
+
+
+static void
+test_convert_datetime_invalid_seconds(void **state)
+{
+ blogc_error_t *err = NULL;
+ char *dt = blogc_convert_datetime("2010-12-30 12:13:69",
+ "%b %d, %Y, %I:%M:%S %p GMT", &err);
+ assert_null(dt);
+ assert_non_null(err);
+ assert_int_equal(err->type, BLOGC_WARNING_DATETIME_PARSER);
+ assert_string_equal(err->msg,
+ "Invalid seconds. Found 69, must be >= 0 and <= 60.");
+ blogc_error_free(err);
+}
+
+
+static void
+test_convert_datetime_invalid_format_long(void **state)
+{
+ blogc_error_t *err = NULL;
+ char *dt = blogc_convert_datetime("2010-12-30 12:13:14",
+ "bovhsuhxwybfrxoluiejaoqpmoylgvkrjtnuntmcgtupwabexkapnklvkwmddmplfqopvb"
+ "yjsiimtfdeveeeayqvvnthimbqotumngxxenurxhsvyaftwsfdtxqnjluvtcwfkomfffrk"
+ "tywccrvnraagtnedwdjtfobinobbymanppwqxubxeepotdyxuvircyshpmtrqyvbivtycs"
+ "olwvqwdqaswdafohqkthraenpueuywbocrsbmmfoqwgbeixosyjljamcqwecfoxgolyxif"
+ "ltaoamuirnnsvoqcnboueqnnyksawwrdtcsiklanjxeavlaqsaswacmbvmselsnghiviet"
+ "wrftrfimjshrjlwxdhjkktivwmmesihlxkmqpmvfqjuimbmaucdxaqcgjdacgksqdseqko"
+ "prknyjylchdlijfgktveldlewixwrycytrjxxesrcbraydmbgitkldbxxhnjwqdmcwctat"
+ "rtjvrboulykkpvmsthontrunvkylwanwnnbpgwiwrgctfsvfgtxpifmpxhwikcylfeycjl"
+ "scmsjnvwfhlkwevcmvvoypmfqlnrwywkwvinkwbjpgxpdxfckghutcovrdhlatumhfvowb"
+ "fyiowyqpsbqhdxxauflpteyagsjtbulpktxmhkxxbgpetlwnckwsvhgmtasviemjeatejs"
+ "tslaivqeltycdgqylhqadxnrdlldbqdwuabdsrqwlxmetahvkrlvmyfgfftrlujfgktwve"
+ "vwidoqvigelfaohgjtaplygmmiwrcspaqntfhthikewunxhebqbkwiopplcmywvjeehslw"
+ "uaeruwnphdjonqagjatjladqhvlxppyaqgvwpjqggnsccmkjvbxqykaejvgeajqpitkwsq"
+ "gmjiaopomnnlewidhgbgqlblotrnuyokspuvbckqhwnhmgcwyyitmlelnehdvclojvyswj"
+ "jgipsincitulscikxviaruryfraeqssykeftcphtndlfhdxokg", &err);
+ assert_null(dt);
+ assert_non_null(err);
+ assert_int_equal(err->type, BLOGC_WARNING_DATETIME_PARSER);
+ assert_string_equal(err->msg,
+ "Failed to format DATE variable, FORMAT is too long: "
+ "bovhsuhxwybfrxoluiejaoqpmoylgvkrjtnuntmcgtupwabexkapnklvkwmddmplfqopvb"
+ "yjsiimtfdeveeeayqvvnthimbqotumngxxenurxhsvyaftwsfdtxqnjluvtcwfkomfffrk"
+ "tywccrvnraagtnedwdjtfobinobbymanppwqxubxeepotdyxuvircyshpmtrqyvbivtycs"
+ "olwvqwdqaswdafohqkthraenpueuywbocrsbmmfoqwgbeixosyjljamcqwecfoxgolyxif"
+ "ltaoamuirnnsvoqcnboueqnnyksawwrdtcsiklanjxeavlaqsaswacmbvmselsnghiviet"
+ "wrftrfimjshrjlwxdhjkktivwmmesihlxkmqpmvfqjuimbmaucdxaqcgjdacgksqdseqko"
+ "prknyjylchdlijfgktveldlewixwrycytrjxxesrcbraydmbgitkldbxxhnjwqdmcwctat"
+ "rtjvrboulykkpvmsthontrunvkylwanwnnbpgwiwrgctfsvfgtxpifmpxhwikcylfeycjl"
+ "scmsjnvwfhlkwevcmvvoypmfqlnrwywkwvinkwbjpgxpdxfckghutcovrdhlatumhfvowb"
+ "fyiowyqpsbqhdxxauflpteyagsjtbulpktxmhkxxbgpetlwnckwsvhgmtasviemjeatejs"
+ "tslaivqeltycdgqylhqadxnrdlldbqdwuabdsrqwlxmetahvkrlvmyfgfftrlujfgktwve"
+ "vwidoqvigelfaohgjtaplygmmiwrcspaqntfhthikewunxhebqbkwiopplcmywvjeehslw"
+ "uaeruwnphdjonqagjatjladqhvlxppyaqgvwpjqggnsccmkjvbxqykaejvgeajqpitkwsq"
+ "gmjiaopomnnlewidhgbgqlblotrnuyokspuvbckqhwnhmgcwyyitmlelnehdvclojvyswj"
+ "jgipsincitulscikxviaruryfraeqssykeftcphtndlfhdxokg");
+ blogc_error_free(err);
+}
+
+
+int
+main(void)
+{
+ setlocale(LC_ALL, "C");
+ const UnitTest tests[] = {
+ unit_test(test_convert_datetime),
+ unit_test(test_convert_datetime_implicit_seconds),
+ unit_test(test_convert_datetime_implicit_minutes),
+ unit_test(test_convert_datetime_implicit_hours),
+ unit_test(test_convert_datetime_invalid_formats),
+ unit_test(test_convert_datetime_invalid_1st_year),
+ unit_test(test_convert_datetime_invalid_2nd_year),
+ unit_test(test_convert_datetime_invalid_3rd_year),
+ unit_test(test_convert_datetime_invalid_4th_year),
+ unit_test(test_convert_datetime_invalid_year),
+ unit_test(test_convert_datetime_invalid_1st_hyphen),
+ unit_test(test_convert_datetime_invalid_1st_month),
+ unit_test(test_convert_datetime_invalid_2nd_month),
+ unit_test(test_convert_datetime_invalid_month),
+ unit_test(test_convert_datetime_invalid_2nd_hyphen),
+ unit_test(test_convert_datetime_invalid_1st_day),
+ unit_test(test_convert_datetime_invalid_2nd_day),
+ unit_test(test_convert_datetime_invalid_day),
+ unit_test(test_convert_datetime_invalid_space),
+ unit_test(test_convert_datetime_invalid_1st_hours),
+ unit_test(test_convert_datetime_invalid_2nd_hours),
+ unit_test(test_convert_datetime_invalid_hours),
+ unit_test(test_convert_datetime_invalid_1st_colon),
+ unit_test(test_convert_datetime_invalid_1st_minutes),
+ unit_test(test_convert_datetime_invalid_2nd_minutes),
+ //unit_test(test_convert_datetime_invalid_minutes), // not possible
+ unit_test(test_convert_datetime_invalid_2nd_colon),
+ unit_test(test_convert_datetime_invalid_1st_seconds),
+ unit_test(test_convert_datetime_invalid_2nd_seconds),
+ unit_test(test_convert_datetime_invalid_seconds),
+ unit_test(test_convert_datetime_invalid_format_long),
+ };
+ return run_tests(tests);
+}
diff --git a/tests/blogc/check_error.c b/tests/blogc/check_error.c
new file mode 100644
index 0000000..9976ac2
--- /dev/null
+++ b/tests/blogc/check_error.c
@@ -0,0 +1,109 @@
+/*
+ * blogc: A blog compiler.
+ * Copyright (C) 2015-2016 Rafael G. Martins <rafael@rafaelmartins.eng.br>
+ *
+ * This program can be distributed under the terms of the BSD License.
+ * See the file LICENSE.
+ */
+
+#include <stdarg.h>
+#include <stddef.h>
+#include <setjmp.h>
+#include <cmocka.h>
+#include <string.h>
+#include "../../src/blogc/error.h"
+
+
+static void
+test_error_new(void **state)
+{
+ blogc_error_t *error = blogc_error_new(1, "bola %s");
+ assert_non_null(error);
+ assert_int_equal(error->type, 1);
+ assert_string_equal(error->msg, "bola %s");
+ blogc_error_free(error);
+}
+
+
+static void
+test_error_new_printf(void **state)
+{
+ blogc_error_t *error = blogc_error_new_printf(2, "bola %s", "guda");
+ assert_non_null(error);
+ assert_int_equal(error->type, 2);
+ assert_string_equal(error->msg, "bola guda");
+ blogc_error_free(error);
+}
+
+
+static void
+test_error_parser(void **state)
+{
+ const char *a = "bola\nguda\nchunda\n";
+ blogc_error_t *error = blogc_error_parser(1, a, strlen(a), 11, "asd %d", 10);
+ assert_non_null(error);
+ assert_int_equal(error->type, 1);
+ assert_string_equal(error->msg,
+ "asd 10\nError occurred near line 3, position 2: chunda");
+ blogc_error_free(error);
+ a = "bola\nguda\nchunda";
+ error = blogc_error_parser(1, a, strlen(a), 11, "asd %d", 10);
+ assert_non_null(error);
+ assert_int_equal(error->type, 1);
+ assert_string_equal(error->msg,
+ "asd 10\nError occurred near line 3, position 2: chunda");
+ blogc_error_free(error);
+ a = "bola\nguda\nchunda";
+ error = blogc_error_parser(1, a, strlen(a), 0, "asd %d", 10);
+ assert_non_null(error);
+ assert_int_equal(error->type, 1);
+ assert_string_equal(error->msg,
+ "asd 10\nError occurred near line 1, position 1: bola");
+ blogc_error_free(error);
+ a = "";
+ error = blogc_error_parser(1, a, strlen(a), 0, "asd %d", 10);
+ assert_non_null(error);
+ assert_int_equal(error->type, 1);
+ assert_string_equal(error->msg, "asd 10");
+ blogc_error_free(error);
+}
+
+
+static void
+test_error_parser_crlf(void **state)
+{
+ const char *a = "bola\r\nguda\r\nchunda\r\n";
+ blogc_error_t *error = blogc_error_parser(1, a, strlen(a), 13, "asd %d", 10);
+ assert_non_null(error);
+ assert_int_equal(error->type, 1);
+ assert_string_equal(error->msg,
+ "asd 10\nError occurred near line 3, position 2: chunda");
+ blogc_error_free(error);
+ a = "bola\r\nguda\r\nchunda";
+ error = blogc_error_parser(1, a, strlen(a), 13, "asd %d", 10);
+ assert_non_null(error);
+ assert_int_equal(error->type, 1);
+ assert_string_equal(error->msg,
+ "asd 10\nError occurred near line 3, position 2: chunda");
+ blogc_error_free(error);
+ a = "bola\r\nguda\r\nchunda";
+ error = blogc_error_parser(1, a, strlen(a), 0, "asd %d", 10);
+ assert_non_null(error);
+ assert_int_equal(error->type, 1);
+ assert_string_equal(error->msg,
+ "asd 10\nError occurred near line 1, position 1: bola");
+ blogc_error_free(error);
+}
+
+
+int
+main(void)
+{
+ const UnitTest tests[] = {
+ unit_test(test_error_new),
+ unit_test(test_error_new_printf),
+ unit_test(test_error_parser),
+ unit_test(test_error_parser_crlf),
+ };
+ return run_tests(tests);
+}
diff --git a/tests/blogc/check_loader.c b/tests/blogc/check_loader.c
new file mode 100644
index 0000000..8d3d9d6
--- /dev/null
+++ b/tests/blogc/check_loader.c
@@ -0,0 +1,771 @@
+/*
+ * blogc: A blog compiler.
+ * Copyright (C) 2015-2016 Rafael G. Martins <rafael@rafaelmartins.eng.br>
+ *
+ * This program can be distributed under the terms of the BSD License.
+ * See the file LICENSE.
+ */
+
+#include <stdarg.h>
+#include <stddef.h>
+#include <setjmp.h>
+#include <cmocka.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include "../../src/blogc/error.h"
+#include "../../src/blogc/template-parser.h"
+#include "../../src/blogc/loader.h"
+#include "../../src/common/utils.h"
+
+
+static void
+test_get_filename(void **state)
+{
+ char *f = blogc_get_filename("/home/foo/asd/bola.txt");
+ assert_string_equal(f, "bola");
+ free(f);
+ f = blogc_get_filename("/home/foo/asd/bola.guda.txt");
+ assert_string_equal(f, "bola.guda");
+ free(f);
+ f = blogc_get_filename("bola.txt");
+ assert_string_equal(f, "bola");
+ free(f);
+ f = blogc_get_filename("bola.guda.txt");
+ assert_string_equal(f, "bola.guda");
+ free(f);
+ f = blogc_get_filename("/home/foo/asd/bola");
+ assert_string_equal(f, "bola");
+ free(f);
+ f = blogc_get_filename("bola");
+ assert_string_equal(f, "bola");
+ free(f);
+ f = blogc_get_filename("");
+ assert_null(f);
+ free(f);
+ f = blogc_get_filename(NULL);
+ assert_null(f);
+ free(f);
+}
+
+
+char*
+__wrap_blogc_file_get_contents(const char *path, size_t *len, blogc_error_t **err)
+{
+ assert_null(*err);
+ const char *_path = mock_type(const char*);
+ if (_path != NULL)
+ assert_string_equal(path, _path);
+ char *rv = mock_type(char*);
+ *len = 0;
+ if (rv != NULL)
+ *len = strlen(rv);
+ return rv;
+}
+
+
+int
+__wrap_blogc_fprintf(FILE *stream, const char *format, ...)
+{
+ assert_true(stream == mock_type(FILE*));
+ assert_string_equal(format, mock_type(const char*));
+ return strlen(format);
+}
+
+
+static void
+test_template_parse_from_file(void **state)
+{
+ blogc_error_t *err = NULL;
+ will_return(__wrap_blogc_file_get_contents, "bola");
+ will_return(__wrap_blogc_file_get_contents, sb_strdup("{{ BOLA }}\n"));
+ sb_slist_t *l = blogc_template_parse_from_file("bola", &err);
+ assert_null(err);
+ assert_non_null(l);
+ assert_int_equal(sb_slist_length(l), 2);
+ blogc_template_free_stmts(l);
+}
+
+
+static void
+test_template_parse_from_file_null(void **state)
+{
+ blogc_error_t *err = NULL;
+ will_return(__wrap_blogc_file_get_contents, "bola");
+ will_return(__wrap_blogc_file_get_contents, NULL);
+ sb_slist_t *l = blogc_template_parse_from_file("bola", &err);
+ assert_null(err);
+ assert_null(l);
+}
+
+
+static void
+test_source_parse_from_file(void **state)
+{
+ blogc_error_t *err = NULL;
+ will_return(__wrap_blogc_file_get_contents, "bola.txt");
+ will_return(__wrap_blogc_file_get_contents, sb_strdup(
+ "ASD: 123\n"
+ "--------\n"
+ "bola"));
+ sb_trie_t *t = blogc_source_parse_from_file("bola.txt", &err);
+ assert_null(err);
+ assert_non_null(t);
+ assert_int_equal(sb_trie_size(t), 6);
+ assert_string_equal(sb_trie_lookup(t, "ASD"), "123");
+ assert_string_equal(sb_trie_lookup(t, "FILENAME"), "bola");
+ assert_string_equal(sb_trie_lookup(t, "EXCERPT"), "<p>bola</p>\n");
+ assert_string_equal(sb_trie_lookup(t, "CONTENT"), "<p>bola</p>\n");
+ assert_string_equal(sb_trie_lookup(t, "RAW_CONTENT"), "bola");
+ assert_string_equal(sb_trie_lookup(t, "DESCRIPTION"), "bola");
+ sb_trie_free(t);
+}
+
+
+static void
+test_source_parse_from_file_null(void **state)
+{
+ blogc_error_t *err = NULL;
+ will_return(__wrap_blogc_file_get_contents, "bola.txt");
+ will_return(__wrap_blogc_file_get_contents, NULL);
+ sb_trie_t *t = blogc_source_parse_from_file("bola.txt", &err);
+ assert_null(err);
+ assert_null(t);
+}
+
+
+static void
+test_source_parse_from_files(void **state)
+{
+ will_return(__wrap_blogc_file_get_contents, "bola1.txt");
+ will_return(__wrap_blogc_file_get_contents, sb_strdup(
+ "ASD: 123\n"
+ "DATE: 2001-02-03 04:05:06\n"
+ "--------\n"
+ "bola"));
+ will_return(__wrap_blogc_file_get_contents, "bola2.txt");
+ will_return(__wrap_blogc_file_get_contents, sb_strdup(
+ "ASD: 456\n"
+ "DATE: 2002-02-03 04:05:06\n"
+ "--------\n"
+ "bola"));
+ will_return(__wrap_blogc_file_get_contents, "bola3.txt");
+ will_return(__wrap_blogc_file_get_contents, sb_strdup(
+ "ASD: 789\n"
+ "DATE: 2003-02-03 04:05:06\n"
+ "--------\n"
+ "bola"));
+ blogc_error_t *err = NULL;
+ sb_slist_t *s = NULL;
+ s = sb_slist_append(s, sb_strdup("bola1.txt"));
+ s = sb_slist_append(s, sb_strdup("bola2.txt"));
+ s = sb_slist_append(s, sb_strdup("bola3.txt"));
+ sb_trie_t *c = sb_trie_new(free);
+ sb_slist_t *t = blogc_source_parse_from_files(c, s, &err);
+ assert_null(err);
+ assert_non_null(t);
+ assert_int_equal(sb_slist_length(t), 3); // it is enough, no need to look at the items
+ assert_int_equal(sb_trie_size(c), 4);
+ assert_string_equal(sb_trie_lookup(c, "FILENAME_FIRST"), "bola1");
+ assert_string_equal(sb_trie_lookup(c, "FILENAME_LAST"), "bola3");
+ assert_string_equal(sb_trie_lookup(c, "DATE_FIRST"), "2001-02-03 04:05:06");
+ assert_string_equal(sb_trie_lookup(c, "DATE_LAST"), "2003-02-03 04:05:06");
+ sb_trie_free(c);
+ sb_slist_free_full(s, free);
+ sb_slist_free_full(t, (sb_free_func_t) sb_trie_free);
+}
+
+
+static void
+test_source_parse_from_files_filter_by_tag(void **state)
+{
+ will_return(__wrap_blogc_file_get_contents, "bola1.txt");
+ will_return(__wrap_blogc_file_get_contents, sb_strdup(
+ "ASD: 123\n"
+ "DATE: 2001-02-03 04:05:06\n"
+ "TAGS: chunda\n"
+ "--------\n"
+ "bola"));
+ will_return(__wrap_blogc_file_get_contents, "bola2.txt");
+ will_return(__wrap_blogc_file_get_contents, sb_strdup(
+ "ASD: 456\n"
+ "DATE: 2002-02-03 04:05:06\n"
+ "TAGS: bola, chunda\n"
+ "--------\n"
+ "bola"));
+ will_return(__wrap_blogc_file_get_contents, "bola3.txt");
+ will_return(__wrap_blogc_file_get_contents, sb_strdup(
+ "ASD: 789\n"
+ "DATE: 2003-02-03 04:05:06\n"
+ "--------\n"
+ "bola"));
+ blogc_error_t *err = NULL;
+ sb_slist_t *s = NULL;
+ s = sb_slist_append(s, sb_strdup("bola1.txt"));
+ s = sb_slist_append(s, sb_strdup("bola2.txt"));
+ s = sb_slist_append(s, sb_strdup("bola3.txt"));
+ sb_trie_t *c = sb_trie_new(free);
+ sb_trie_insert(c, "FILTER_TAG", sb_strdup("chunda"));
+ sb_slist_t *t = blogc_source_parse_from_files(c, s, &err);
+ assert_null(err);
+ assert_non_null(t);
+ assert_int_equal(sb_slist_length(t), 2); // it is enough, no need to look at the items
+ assert_int_equal(sb_trie_size(c), 5);
+ assert_string_equal(sb_trie_lookup(c, "FILENAME_FIRST"), "bola1");
+ assert_string_equal(sb_trie_lookup(c, "FILENAME_LAST"), "bola2");
+ assert_string_equal(sb_trie_lookup(c, "DATE_FIRST"), "2001-02-03 04:05:06");
+ assert_string_equal(sb_trie_lookup(c, "DATE_LAST"), "2002-02-03 04:05:06");
+ assert_string_equal(sb_trie_lookup(c, "FILTER_TAG"), "chunda");
+ sb_trie_free(c);
+ sb_slist_free_full(s, free);
+ sb_slist_free_full(t, (sb_free_func_t) sb_trie_free);
+}
+
+
+static void
+test_source_parse_from_files_filter_by_page(void **state)
+{
+ will_return(__wrap_blogc_file_get_contents, "bola1.txt");
+ will_return(__wrap_blogc_file_get_contents, sb_strdup(
+ "ASD: 123\n"
+ "DATE: 2001-02-03 04:05:06\n"
+ "--------\n"
+ "bola"));
+ will_return(__wrap_blogc_file_get_contents, "bola2.txt");
+ will_return(__wrap_blogc_file_get_contents, sb_strdup(
+ "ASD: 456\n"
+ "DATE: 2002-02-03 04:05:06\n"
+ "--------\n"
+ "bola"));
+ will_return(__wrap_blogc_file_get_contents, "bola3.txt");
+ will_return(__wrap_blogc_file_get_contents, sb_strdup(
+ "ASD: 789\n"
+ "DATE: 2003-02-03 04:05:06\n"
+ "--------\n"
+ "bola"));
+ will_return(__wrap_blogc_file_get_contents, "bola4.txt");
+ will_return(__wrap_blogc_file_get_contents, sb_strdup(
+ "ASD: 7891\n"
+ "DATE: 2004-02-03 04:05:06\n"
+ "--------\n"
+ "bola"));
+ will_return(__wrap_blogc_file_get_contents, "bola5.txt");
+ will_return(__wrap_blogc_file_get_contents, sb_strdup(
+ "ASD: 7892\n"
+ "DATE: 2005-02-03 04:05:06\n"
+ "--------\n"
+ "bola"));
+ will_return(__wrap_blogc_file_get_contents, "bola6.txt");
+ will_return(__wrap_blogc_file_get_contents, sb_strdup(
+ "ASD: 7893\n"
+ "DATE: 2006-02-03 04:05:06\n"
+ "--------\n"
+ "bola"));
+ will_return(__wrap_blogc_file_get_contents, "bola7.txt");
+ will_return(__wrap_blogc_file_get_contents, sb_strdup(
+ "ASD: 7894\n"
+ "DATE: 2007-02-03 04:05:06\n"
+ "--------\n"
+ "bola"));
+ blogc_error_t *err = NULL;
+ sb_slist_t *s = NULL;
+ s = sb_slist_append(s, sb_strdup("bola1.txt"));
+ s = sb_slist_append(s, sb_strdup("bola2.txt"));
+ s = sb_slist_append(s, sb_strdup("bola3.txt"));
+ s = sb_slist_append(s, sb_strdup("bola4.txt"));
+ s = sb_slist_append(s, sb_strdup("bola5.txt"));
+ s = sb_slist_append(s, sb_strdup("bola6.txt"));
+ s = sb_slist_append(s, sb_strdup("bola7.txt"));
+ sb_trie_t *c = sb_trie_new(free);
+ sb_trie_insert(c, "FILTER_PAGE", sb_strdup("1"));
+ sb_trie_insert(c, "FILTER_PER_PAGE", sb_strdup("2"));
+ sb_slist_t *t = blogc_source_parse_from_files(c, s, &err);
+ assert_null(err);
+ assert_non_null(t);
+ assert_int_equal(sb_slist_length(t), 2); // it is enough, no need to look at the items
+ assert_int_equal(sb_trie_size(c), 10);
+ assert_string_equal(sb_trie_lookup(c, "FILENAME_FIRST"), "bola1");
+ assert_string_equal(sb_trie_lookup(c, "FILENAME_LAST"), "bola2");
+ assert_string_equal(sb_trie_lookup(c, "DATE_FIRST"), "2001-02-03 04:05:06");
+ assert_string_equal(sb_trie_lookup(c, "DATE_LAST"), "2002-02-03 04:05:06");
+ assert_string_equal(sb_trie_lookup(c, "FILTER_PAGE"), "1");
+ assert_string_equal(sb_trie_lookup(c, "FILTER_PER_PAGE"), "2");
+ assert_string_equal(sb_trie_lookup(c, "CURRENT_PAGE"), "1");
+ assert_string_equal(sb_trie_lookup(c, "NEXT_PAGE"), "2");
+ assert_string_equal(sb_trie_lookup(c, "FIRST_PAGE"), "1");
+ assert_string_equal(sb_trie_lookup(c, "LAST_PAGE"), "4");
+ sb_trie_free(c);
+ sb_slist_free_full(s, free);
+ sb_slist_free_full(t, (sb_free_func_t) sb_trie_free);
+}
+
+
+static void
+test_source_parse_from_files_filter_by_page2(void **state)
+{
+ will_return(__wrap_blogc_file_get_contents, "bola1.txt");
+ will_return(__wrap_blogc_file_get_contents, sb_strdup(
+ "ASD: 123\n"
+ "DATE: 2001-02-03 04:05:06\n"
+ "--------\n"
+ "bola"));
+ will_return(__wrap_blogc_file_get_contents, "bola2.txt");
+ will_return(__wrap_blogc_file_get_contents, sb_strdup(
+ "ASD: 456\n"
+ "DATE: 2002-02-03 04:05:06\n"
+ "--------\n"
+ "bola"));
+ will_return(__wrap_blogc_file_get_contents, "bola3.txt");
+ will_return(__wrap_blogc_file_get_contents, sb_strdup(
+ "ASD: 789\n"
+ "DATE: 2003-02-03 04:05:06\n"
+ "--------\n"
+ "bola"));
+ will_return(__wrap_blogc_file_get_contents, "bola4.txt");
+ will_return(__wrap_blogc_file_get_contents, sb_strdup(
+ "ASD: 7891\n"
+ "DATE: 2004-02-03 04:05:06\n"
+ "--------\n"
+ "bola"));
+ will_return(__wrap_blogc_file_get_contents, "bola5.txt");
+ will_return(__wrap_blogc_file_get_contents, sb_strdup(
+ "ASD: 7892\n"
+ "DATE: 2005-02-03 04:05:06\n"
+ "--------\n"
+ "bola"));
+ will_return(__wrap_blogc_file_get_contents, "bola6.txt");
+ will_return(__wrap_blogc_file_get_contents, sb_strdup(
+ "ASD: 7893\n"
+ "DATE: 2006-02-03 04:05:06\n"
+ "--------\n"
+ "bola"));
+ will_return(__wrap_blogc_file_get_contents, "bola7.txt");
+ will_return(__wrap_blogc_file_get_contents, sb_strdup(
+ "ASD: 7894\n"
+ "DATE: 2007-02-03 04:05:06\n"
+ "--------\n"
+ "bola"));
+ blogc_error_t *err = NULL;
+ sb_slist_t *s = NULL;
+ s = sb_slist_append(s, sb_strdup("bola1.txt"));
+ s = sb_slist_append(s, sb_strdup("bola2.txt"));
+ s = sb_slist_append(s, sb_strdup("bola3.txt"));
+ s = sb_slist_append(s, sb_strdup("bola4.txt"));
+ s = sb_slist_append(s, sb_strdup("bola5.txt"));
+ s = sb_slist_append(s, sb_strdup("bola6.txt"));
+ s = sb_slist_append(s, sb_strdup("bola7.txt"));
+ sb_trie_t *c = sb_trie_new(free);
+ sb_trie_insert(c, "FILTER_PAGE", sb_strdup("3"));
+ sb_trie_insert(c, "FILTER_PER_PAGE", sb_strdup("2"));
+ sb_slist_t *t = blogc_source_parse_from_files(c, s, &err);
+ assert_null(err);
+ assert_non_null(t);
+ assert_int_equal(sb_slist_length(t), 2); // it is enough, no need to look at the items
+ assert_int_equal(sb_trie_size(c), 11);
+ assert_string_equal(sb_trie_lookup(c, "FILENAME_FIRST"), "bola5");
+ assert_string_equal(sb_trie_lookup(c, "FILENAME_LAST"), "bola6");
+ assert_string_equal(sb_trie_lookup(c, "DATE_FIRST"), "2005-02-03 04:05:06");
+ assert_string_equal(sb_trie_lookup(c, "DATE_LAST"), "2006-02-03 04:05:06");
+ assert_string_equal(sb_trie_lookup(c, "FILTER_PAGE"), "3");
+ assert_string_equal(sb_trie_lookup(c, "FILTER_PER_PAGE"), "2");
+ assert_string_equal(sb_trie_lookup(c, "CURRENT_PAGE"), "3");
+ assert_string_equal(sb_trie_lookup(c, "PREVIOUS_PAGE"), "2");
+ assert_string_equal(sb_trie_lookup(c, "NEXT_PAGE"), "4");
+ assert_string_equal(sb_trie_lookup(c, "FIRST_PAGE"), "1");
+ assert_string_equal(sb_trie_lookup(c, "LAST_PAGE"), "4");
+ sb_trie_free(c);
+ sb_slist_free_full(s, free);
+ sb_slist_free_full(t, (sb_free_func_t) sb_trie_free);
+}
+
+
+static void
+test_source_parse_from_files_filter_by_page3(void **state)
+{
+ will_return(__wrap_blogc_file_get_contents, "bola1.txt");
+ will_return(__wrap_blogc_file_get_contents, sb_strdup(
+ "ASD: 123\n"
+ "DATE: 2001-02-03 04:05:06\n"
+ "--------\n"
+ "bola"));
+ will_return(__wrap_blogc_file_get_contents, "bola2.txt");
+ will_return(__wrap_blogc_file_get_contents, sb_strdup(
+ "ASD: 456\n"
+ "DATE: 2002-02-03 04:05:06\n"
+ "--------\n"
+ "bola"));
+ will_return(__wrap_blogc_file_get_contents, "bola3.txt");
+ will_return(__wrap_blogc_file_get_contents, sb_strdup(
+ "ASD: 789\n"
+ "DATE: 2003-02-03 04:05:06\n"
+ "--------\n"
+ "bola"));
+ will_return(__wrap_blogc_file_get_contents, "bola4.txt");
+ will_return(__wrap_blogc_file_get_contents, sb_strdup(
+ "ASD: 7891\n"
+ "DATE: 2004-02-03 04:05:06\n"
+ "--------\n"
+ "bola"));
+ will_return(__wrap_blogc_file_get_contents, "bola5.txt");
+ will_return(__wrap_blogc_file_get_contents, sb_strdup(
+ "ASD: 7892\n"
+ "DATE: 2005-02-03 04:05:06\n"
+ "--------\n"
+ "bola"));
+ will_return(__wrap_blogc_file_get_contents, "bola6.txt");
+ will_return(__wrap_blogc_file_get_contents, sb_strdup(
+ "ASD: 7893\n"
+ "DATE: 2006-02-03 04:05:06\n"
+ "--------\n"
+ "bola"));
+ will_return(__wrap_blogc_file_get_contents, "bola7.txt");
+ will_return(__wrap_blogc_file_get_contents, sb_strdup(
+ "ASD: 7894\n"
+ "DATE: 2007-02-03 04:05:06\n"
+ "--------\n"
+ "bola"));
+ blogc_error_t *err = NULL;
+ sb_slist_t *s = NULL;
+ s = sb_slist_append(s, sb_strdup("bola1.txt"));
+ s = sb_slist_append(s, sb_strdup("bola2.txt"));
+ s = sb_slist_append(s, sb_strdup("bola3.txt"));
+ s = sb_slist_append(s, sb_strdup("bola4.txt"));
+ s = sb_slist_append(s, sb_strdup("bola5.txt"));
+ s = sb_slist_append(s, sb_strdup("bola6.txt"));
+ s = sb_slist_append(s, sb_strdup("bola7.txt"));
+ sb_trie_t *c = sb_trie_new(free);
+ sb_trie_insert(c, "FILTER_PAGE", sb_strdup("1"));
+ sb_trie_insert(c, "FILTER_PER_PAGE", sb_strdup("2"));
+ sb_slist_t *t = blogc_source_parse_from_files(c, s, &err);
+ assert_null(err);
+ assert_non_null(t);
+ assert_int_equal(sb_slist_length(t), 2); // it is enough, no need to look at the items
+ assert_int_equal(sb_trie_size(c), 10);
+ assert_string_equal(sb_trie_lookup(c, "FILENAME_FIRST"), "bola1");
+ assert_string_equal(sb_trie_lookup(c, "FILENAME_LAST"), "bola2");
+ assert_string_equal(sb_trie_lookup(c, "DATE_FIRST"), "2001-02-03 04:05:06");
+ assert_string_equal(sb_trie_lookup(c, "DATE_LAST"), "2002-02-03 04:05:06");
+ assert_string_equal(sb_trie_lookup(c, "FILTER_PAGE"), "1");
+ assert_string_equal(sb_trie_lookup(c, "FILTER_PER_PAGE"), "2");
+ assert_string_equal(sb_trie_lookup(c, "CURRENT_PAGE"), "1");
+ assert_string_equal(sb_trie_lookup(c, "NEXT_PAGE"), "2");
+ assert_string_equal(sb_trie_lookup(c, "FIRST_PAGE"), "1");
+ assert_string_equal(sb_trie_lookup(c, "LAST_PAGE"), "4");
+ sb_trie_free(c);
+ sb_slist_free_full(s, free);
+ sb_slist_free_full(t, (sb_free_func_t) sb_trie_free);
+}
+
+
+static void
+test_source_parse_from_files_filter_by_page_and_tag(void **state)
+{
+ will_return(__wrap_blogc_file_get_contents, "bola1.txt");
+ will_return(__wrap_blogc_file_get_contents, sb_strdup(
+ "ASD: 123\n"
+ "DATE: 2001-02-03 04:05:06\n"
+ "--------\n"
+ "bola"));
+ will_return(__wrap_blogc_file_get_contents, "bola2.txt");
+ will_return(__wrap_blogc_file_get_contents, sb_strdup(
+ "ASD: 456\n"
+ "DATE: 2002-02-03 04:05:06\n"
+ "TAGS: chunda\n"
+ "--------\n"
+ "bola"));
+ will_return(__wrap_blogc_file_get_contents, "bola3.txt");
+ will_return(__wrap_blogc_file_get_contents, sb_strdup(
+ "ASD: 789\n"
+ "DATE: 2003-02-03 04:05:06\n"
+ "TAGS: chunda bola\n"
+ "--------\n"
+ "bola"));
+ will_return(__wrap_blogc_file_get_contents, "bola4.txt");
+ will_return(__wrap_blogc_file_get_contents, sb_strdup(
+ "ASD: 7891\n"
+ "DATE: 2004-02-03 04:05:06\n"
+ "TAGS: bola\n"
+ "--------\n"
+ "bola"));
+ will_return(__wrap_blogc_file_get_contents, "bola5.txt");
+ will_return(__wrap_blogc_file_get_contents, sb_strdup(
+ "ASD: 7892\n"
+ "DATE: 2005-02-03 04:05:06\n"
+ "TAGS: chunda\n"
+ "--------\n"
+ "bola"));
+ will_return(__wrap_blogc_file_get_contents, "bola6.txt");
+ will_return(__wrap_blogc_file_get_contents, sb_strdup(
+ "ASD: 7893\n"
+ "DATE: 2006-02-03 04:05:06\n"
+ "--------\n"
+ "bola"));
+ will_return(__wrap_blogc_file_get_contents, "bola7.txt");
+ will_return(__wrap_blogc_file_get_contents, sb_strdup(
+ "ASD: 7894\n"
+ "DATE: 2007-02-03 04:05:06\n"
+ "TAGS: yay chunda\n"
+ "--------\n"
+ "bola"));
+ blogc_error_t *err = NULL;
+ sb_slist_t *s = NULL;
+ s = sb_slist_append(s, sb_strdup("bola1.txt"));
+ s = sb_slist_append(s, sb_strdup("bola2.txt"));
+ s = sb_slist_append(s, sb_strdup("bola3.txt"));
+ s = sb_slist_append(s, sb_strdup("bola4.txt"));
+ s = sb_slist_append(s, sb_strdup("bola5.txt"));
+ s = sb_slist_append(s, sb_strdup("bola6.txt"));
+ s = sb_slist_append(s, sb_strdup("bola7.txt"));
+ sb_trie_t *c = sb_trie_new(free);
+ sb_trie_insert(c, "FILTER_TAG", sb_strdup("chunda"));
+ sb_trie_insert(c, "FILTER_PAGE", sb_strdup("2"));
+ sb_trie_insert(c, "FILTER_PER_PAGE", sb_strdup("2"));
+ sb_slist_t *t = blogc_source_parse_from_files(c, s, &err);
+ assert_null(err);
+ assert_non_null(t);
+ assert_int_equal(sb_slist_length(t), 2); // it is enough, no need to look at the items
+ assert_int_equal(sb_trie_size(c), 11);
+ assert_string_equal(sb_trie_lookup(c, "FILENAME_FIRST"), "bola5");
+ assert_string_equal(sb_trie_lookup(c, "FILENAME_LAST"), "bola7");
+ assert_string_equal(sb_trie_lookup(c, "DATE_FIRST"), "2005-02-03 04:05:06");
+ assert_string_equal(sb_trie_lookup(c, "DATE_LAST"), "2007-02-03 04:05:06");
+ assert_string_equal(sb_trie_lookup(c, "FILTER_TAG"), "chunda");
+ assert_string_equal(sb_trie_lookup(c, "FILTER_PAGE"), "2");
+ assert_string_equal(sb_trie_lookup(c, "FILTER_PER_PAGE"), "2");
+ assert_string_equal(sb_trie_lookup(c, "CURRENT_PAGE"), "2");
+ assert_string_equal(sb_trie_lookup(c, "PREVIOUS_PAGE"), "1");
+ assert_string_equal(sb_trie_lookup(c, "FIRST_PAGE"), "1");
+ assert_string_equal(sb_trie_lookup(c, "LAST_PAGE"), "2");
+ sb_trie_free(c);
+ sb_slist_free_full(s, free);
+ sb_slist_free_full(t, (sb_free_func_t) sb_trie_free);
+}
+
+
+static void
+test_source_parse_from_files_filter_by_page_invalid(void **state)
+{
+ will_return(__wrap_blogc_file_get_contents, "bola1.txt");
+ will_return(__wrap_blogc_file_get_contents, sb_strdup(
+ "ASD: 123\n"
+ "DATE: 2001-02-03 04:05:06\n"
+ "--------\n"
+ "bola"));
+ will_return(__wrap_blogc_file_get_contents, "bola2.txt");
+ will_return(__wrap_blogc_file_get_contents, sb_strdup(
+ "ASD: 456\n"
+ "DATE: 2002-02-03 04:05:06\n"
+ "--------\n"
+ "bola"));
+ will_return(__wrap_blogc_file_get_contents, "bola3.txt");
+ will_return(__wrap_blogc_file_get_contents, sb_strdup(
+ "ASD: 789\n"
+ "DATE: 2003-02-03 04:05:06\n"
+ "--------\n"
+ "bola"));
+ will_return(__wrap_blogc_file_get_contents, "bola4.txt");
+ will_return(__wrap_blogc_file_get_contents, sb_strdup(
+ "ASD: 7891\n"
+ "DATE: 2004-02-03 04:05:06\n"
+ "--------\n"
+ "bola"));
+ will_return(__wrap_blogc_file_get_contents, "bola5.txt");
+ will_return(__wrap_blogc_file_get_contents, sb_strdup(
+ "ASD: 7892\n"
+ "DATE: 2005-02-03 04:05:06\n"
+ "--------\n"
+ "bola"));
+ will_return(__wrap_blogc_file_get_contents, "bola6.txt");
+ will_return(__wrap_blogc_file_get_contents, sb_strdup(
+ "ASD: 7893\n"
+ "DATE: 2006-02-03 04:05:06\n"
+ "--------\n"
+ "bola"));
+ will_return(__wrap_blogc_file_get_contents, "bola7.txt");
+ will_return(__wrap_blogc_file_get_contents, sb_strdup(
+ "ASD: 7894\n"
+ "DATE: 2007-02-03 04:05:06\n"
+ "--------\n"
+ "bola"));
+ blogc_error_t *err = NULL;
+ sb_slist_t *s = NULL;
+ s = sb_slist_append(s, sb_strdup("bola1.txt"));
+ s = sb_slist_append(s, sb_strdup("bola2.txt"));
+ s = sb_slist_append(s, sb_strdup("bola3.txt"));
+ s = sb_slist_append(s, sb_strdup("bola4.txt"));
+ s = sb_slist_append(s, sb_strdup("bola5.txt"));
+ s = sb_slist_append(s, sb_strdup("bola6.txt"));
+ s = sb_slist_append(s, sb_strdup("bola7.txt"));
+ sb_trie_t *c = sb_trie_new(free);
+ sb_trie_insert(c, "FILTER_PAGE", sb_strdup("-1"));
+ sb_trie_insert(c, "FILTER_PER_PAGE", sb_strdup("2"));
+ sb_slist_t *t = blogc_source_parse_from_files(c, s, &err);
+ assert_null(err);
+ assert_non_null(t);
+ assert_int_equal(sb_slist_length(t), 2); // it is enough, no need to look at the items
+ assert_int_equal(sb_trie_size(c), 10);
+ assert_string_equal(sb_trie_lookup(c, "FILENAME_FIRST"), "bola1");
+ assert_string_equal(sb_trie_lookup(c, "FILENAME_LAST"), "bola2");
+ assert_string_equal(sb_trie_lookup(c, "DATE_FIRST"), "2001-02-03 04:05:06");
+ assert_string_equal(sb_trie_lookup(c, "DATE_LAST"), "2002-02-03 04:05:06");
+ assert_string_equal(sb_trie_lookup(c, "FILTER_PAGE"), "-1");
+ assert_string_equal(sb_trie_lookup(c, "FILTER_PER_PAGE"), "2");
+ assert_string_equal(sb_trie_lookup(c, "CURRENT_PAGE"), "1");
+ assert_string_equal(sb_trie_lookup(c, "NEXT_PAGE"), "2");
+ assert_string_equal(sb_trie_lookup(c, "FIRST_PAGE"), "1");
+ assert_string_equal(sb_trie_lookup(c, "LAST_PAGE"), "4");
+ sb_trie_free(c);
+ sb_slist_free_full(s, free);
+ sb_slist_free_full(t, (sb_free_func_t) sb_trie_free);
+}
+
+
+static void
+test_source_parse_from_files_filter_by_page_invalid2(void **state)
+{
+ will_return(__wrap_blogc_file_get_contents, "bola1.txt");
+ will_return(__wrap_blogc_file_get_contents, sb_strdup(
+ "ASD: 123\n"
+ "DATE: 2001-02-03 04:05:06\n"
+ "--------\n"
+ "bola"));
+ will_return(__wrap_blogc_file_get_contents, "bola2.txt");
+ will_return(__wrap_blogc_file_get_contents, sb_strdup(
+ "ASD: 456\n"
+ "DATE: 2002-02-03 04:05:06\n"
+ "--------\n"
+ "bola"));
+ will_return(__wrap_blogc_file_get_contents, "bola3.txt");
+ will_return(__wrap_blogc_file_get_contents, sb_strdup(
+ "ASD: 789\n"
+ "DATE: 2003-02-03 04:05:06\n"
+ "--------\n"
+ "bola"));
+ will_return(__wrap_blogc_file_get_contents, "bola4.txt");
+ will_return(__wrap_blogc_file_get_contents, sb_strdup(
+ "ASD: 7891\n"
+ "DATE: 2004-02-03 04:05:06\n"
+ "--------\n"
+ "bola"));
+ will_return(__wrap_blogc_file_get_contents, "bola5.txt");
+ will_return(__wrap_blogc_file_get_contents, sb_strdup(
+ "ASD: 7892\n"
+ "DATE: 2005-02-03 04:05:06\n"
+ "--------\n"
+ "bola"));
+ will_return(__wrap_blogc_file_get_contents, "bola6.txt");
+ will_return(__wrap_blogc_file_get_contents, sb_strdup(
+ "ASD: 7893\n"
+ "DATE: 2006-02-03 04:05:06\n"
+ "--------\n"
+ "bola"));
+ will_return(__wrap_blogc_file_get_contents, "bola7.txt");
+ will_return(__wrap_blogc_file_get_contents, sb_strdup(
+ "ASD: 7894\n"
+ "DATE: 2007-02-03 04:05:06\n"
+ "--------\n"
+ "bola"));
+ blogc_error_t *err = NULL;
+ sb_slist_t *s = NULL;
+ s = sb_slist_append(s, sb_strdup("bola1.txt"));
+ s = sb_slist_append(s, sb_strdup("bola2.txt"));
+ s = sb_slist_append(s, sb_strdup("bola3.txt"));
+ s = sb_slist_append(s, sb_strdup("bola4.txt"));
+ s = sb_slist_append(s, sb_strdup("bola5.txt"));
+ s = sb_slist_append(s, sb_strdup("bola6.txt"));
+ s = sb_slist_append(s, sb_strdup("bola7.txt"));
+ sb_trie_t *c = sb_trie_new(free);
+ sb_trie_insert(c, "FILTER_PAGE", sb_strdup("5"));
+ sb_trie_insert(c, "FILTER_PER_PAGE", sb_strdup("2"));
+ sb_slist_t *t = blogc_source_parse_from_files(c, s, &err);
+ assert_null(err);
+ assert_null(t);
+ sb_trie_free(c);
+ sb_slist_free_full(s, free);
+}
+
+
+static void
+test_source_parse_from_files_without_all_dates(void **state)
+{
+ will_return(__wrap_blogc_fprintf, stderr);
+ will_return(__wrap_blogc_fprintf,
+ "blogc: warning: 'DATE' variable provided for at least one source "
+ "file, but not for all source files. This means that you may get wrong "
+ "values for 'DATE_FIRST' and 'DATE_LAST' variables.\n");
+ will_return(__wrap_blogc_file_get_contents, "bola1.txt");
+ will_return(__wrap_blogc_file_get_contents, sb_strdup(
+ "ASD: 123\n"
+ "--------\n"
+ "bola"));
+ will_return(__wrap_blogc_file_get_contents, "bola2.txt");
+ will_return(__wrap_blogc_file_get_contents, sb_strdup(
+ "ASD: 456\n"
+ "DATE: 2002-02-03 04:05:06\n"
+ "--------\n"
+ "bola"));
+ will_return(__wrap_blogc_file_get_contents, "bola3.txt");
+ will_return(__wrap_blogc_file_get_contents, sb_strdup(
+ "ASD: 789\n"
+ "DATE: 2003-02-03 04:05:06\n"
+ "--------\n"
+ "bola"));
+ blogc_error_t *err = NULL;
+ sb_slist_t *s = NULL;
+ s = sb_slist_append(s, sb_strdup("bola1.txt"));
+ s = sb_slist_append(s, sb_strdup("bola2.txt"));
+ s = sb_slist_append(s, sb_strdup("bola3.txt"));
+ sb_trie_t *c = sb_trie_new(free);
+ sb_slist_t *t = blogc_source_parse_from_files(c, s, &err);
+ assert_null(err);
+ assert_non_null(t);
+ assert_int_equal(sb_slist_length(t), 3); // it is enough, no need to look at the items
+ assert_int_equal(sb_trie_size(c), 3);
+ assert_string_equal(sb_trie_lookup(c, "FILENAME_FIRST"), "bola1");
+ assert_string_equal(sb_trie_lookup(c, "FILENAME_LAST"), "bola3");
+ assert_string_equal(sb_trie_lookup(c, "DATE_LAST"), "2003-02-03 04:05:06");
+ sb_trie_free(c);
+ sb_slist_free_full(s, free);
+ sb_slist_free_full(t, (sb_free_func_t) sb_trie_free);
+}
+
+
+static void
+test_source_parse_from_files_null(void **state)
+{
+ blogc_error_t *err = NULL;
+ sb_slist_t *s = NULL;
+ sb_trie_t *c = sb_trie_new(free);
+ sb_slist_t *t = blogc_source_parse_from_files(c, s, &err);
+ assert_null(err);
+ assert_null(t);
+ assert_int_equal(sb_slist_length(t), 0);
+ assert_int_equal(sb_trie_size(c), 0);
+ sb_trie_free(c);
+ sb_slist_free_full(s, free);
+ sb_slist_free_full(t, (sb_free_func_t) sb_trie_free);
+}
+
+
+int
+main(void)
+{
+ const UnitTest tests[] = {
+ unit_test(test_get_filename),
+ unit_test(test_template_parse_from_file),
+ unit_test(test_template_parse_from_file_null),
+ unit_test(test_source_parse_from_file),
+ unit_test(test_source_parse_from_file_null),
+ unit_test(test_source_parse_from_files),
+ unit_test(test_source_parse_from_files_filter_by_tag),
+ unit_test(test_source_parse_from_files_filter_by_page),
+ unit_test(test_source_parse_from_files_filter_by_page2),
+ unit_test(test_source_parse_from_files_filter_by_page3),
+ unit_test(test_source_parse_from_files_filter_by_page_and_tag),
+ unit_test(test_source_parse_from_files_filter_by_page_invalid),
+ unit_test(test_source_parse_from_files_filter_by_page_invalid2),
+ unit_test(test_source_parse_from_files_without_all_dates),
+ unit_test(test_source_parse_from_files_null),
+ };
+ return run_tests(tests);
+}
diff --git a/tests/blogc/check_renderer.c b/tests/blogc/check_renderer.c
new file mode 100644
index 0000000..c058788
--- /dev/null
+++ b/tests/blogc/check_renderer.c
@@ -0,0 +1,1158 @@
+/*
+ * blogc: A blog compiler.
+ * Copyright (C) 2015-2016 Rafael G. Martins <rafael@rafaelmartins.eng.br>
+ *
+ * This program can be distributed under the terms of the BSD License.
+ * See the file LICENSE.
+ */
+
+#include <stdarg.h>
+#include <stddef.h>
+#include <setjmp.h>
+#include <cmocka.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <string.h>
+#include "../../src/blogc/error.h"
+#include "../../src/blogc/renderer.h"
+#include "../../src/blogc/source-parser.h"
+#include "../../src/blogc/template-parser.h"
+#include "../../src/common/utils.h"
+
+
+static sb_slist_t*
+create_sources(unsigned int count)
+{
+ const char *s[] = {
+ "BOLA: asd\n"
+ "GUDA: zxc\n"
+ "GUDA2: zxc\n"
+ "DATE: 2015-01-02 03:04:05\n"
+ "DATE_FORMAT: %R\n"
+ "TAGS: foo bar baz\n"
+ "-----\n"
+ "ahahahahahahahaha",
+ "BOLA: asd2\n"
+ "GUDA: zxc2\n"
+ "DATE: 2014-02-03 04:05:06\n"
+ "-----\n"
+ "ahahahahahahahaha2",
+ "BOLA: asd3\n"
+ "GUDA: zxc3\n"
+ "DATE: 2013-01-02 03:04:05\n"
+ "-----\n"
+ "ahahahahahahahaha3",
+ };
+ assert_false(count > 3);
+ blogc_error_t *err = NULL;
+ sb_slist_t *l = NULL;
+ for (unsigned int i = 0; i < count; i++) {
+ l = sb_slist_append(l, blogc_source_parse(s[i], strlen(s[i]), &err));
+ assert_null(err);
+ }
+ assert_int_equal(sb_slist_length(l), count);
+ return l;
+}
+
+
+static void
+test_render_entry(void **state)
+{
+ const char *str =
+ "foo\n"
+ "{% block listing_once %}fuuu{% endblock %}\n"
+ "{% block entry %}\n"
+ "{{ DATE }}\n"
+ "{% ifdef DATE_FORMATTED %}{{ DATE_FORMATTED }}{% endif %}\n"
+ "{% ifdef GUDA %}{{ GUDA }}{% endif %}\n"
+ "{% ifdef CHUNDA %}{{ CHUNDA }}{% endif %}\n"
+ "{% endblock %}\n"
+ "{% block listing %}lol{% endblock %}\n"
+ "{% if GUDA == GUDA2 %}gudabola{% endif %}\n"
+ "{% if GUDA == \"zxc\" %}LOL{% endif %}\n"
+ "{% if GUDA != \"bola\" %}HEHE{% endif %}\n"
+ "{% if GUDA < \"zxd\" %}LOL2{% endif %}\n"
+ "{% if GUDA > \"zxd\" %}LOL3{% else %}ELSE{% endif %}\n"
+ "{% if GUDA <= \"zxc\" %}LOL4{% endif %}\n"
+ "{% foreach TAGS %}lol {{ FOREACH_ITEM }} haha {% endforeach %}\n"
+ "{% foreach TAGS_ASD %}yay{% endforeach %}\n";
+ blogc_error_t *err = NULL;
+ sb_slist_t *l = blogc_template_parse(str, strlen(str), &err);
+ assert_non_null(l);
+ assert_null(err);
+ sb_slist_t *s = create_sources(1);
+ assert_non_null(s);
+ char *out = blogc_render(l, s, NULL, false);
+ assert_string_equal(out,
+ "foo\n"
+ "\n"
+ "\n"
+ "2015-01-02 03:04:05\n"
+ "03:04\n"
+ "zxc\n"
+ "\n"
+ "\n"
+ "\n"
+ "gudabola\n"
+ "LOL\n"
+ "HEHE\n"
+ "LOL2\n"
+ "ELSE\n"
+ "LOL4\n"
+ "lol foo haha lol bar haha lol baz haha \n"
+ "\n");
+ blogc_template_free_stmts(l);
+ sb_slist_free_full(s, (sb_free_func_t) sb_trie_free);
+ free(out);
+}
+
+
+static void
+test_render_listing(void **state)
+{
+ const char *str =
+ "foo\n"
+ "{% block listing_once %}fuuu{% endblock %}\n"
+ "{% block entry %}\n"
+ "{% ifdef GUDA %}{{ GUDA }}{% endif %}\n"
+ "{% ifdef CHUNDA %}{{ CHUNDA }}{% endif %}\n"
+ "{% endblock %}\n"
+ "{% block listing %}\n"
+ "{% ifdef DATE_FORMATTED %}{{ DATE_FORMATTED }}{% endif %}\n"
+ "bola: {% ifdef BOLA %}{{ BOLA }}{% endif %}\n"
+ "{% foreach TAGS %}lol {{ FOREACH_ITEM }} haha {% endforeach %}\n"
+ "{% foreach TAGS_ASD %}yay{% endforeach %}\n"
+ "{% endblock %}\n";
+ blogc_error_t *err = NULL;
+ sb_slist_t *l = blogc_template_parse(str, strlen(str), &err);
+ assert_non_null(l);
+ assert_null(err);
+ sb_slist_t *s = create_sources(3);
+ assert_non_null(s);
+ char *out = blogc_render(l, s, NULL, true);
+ assert_string_equal(out,
+ "foo\n"
+ "fuuu\n"
+ "\n"
+ "\n"
+ "03:04\n"
+ "bola: asd\n"
+ "lol foo haha lol bar haha lol baz haha \n"
+ "\n"
+ "\n"
+ "2014-02-03 04:05:06\n"
+ "bola: asd2\n"
+ "\n"
+ "\n"
+ "\n"
+ "2013-01-02 03:04:05\n"
+ "bola: asd3\n"
+ "\n"
+ "\n"
+ "\n");
+ blogc_template_free_stmts(l);
+ sb_slist_free_full(s, (sb_free_func_t) sb_trie_free);
+ free(out);
+}
+
+
+static void
+test_render_listing_empty(void **state)
+{
+ const char *str =
+ "foo\n"
+ "{% block listing_once %}fuuu{% endblock %}\n"
+ "{% block entry %}\n"
+ "{% ifdef GUDA %}{{ GUDA }}{% endif %}\n"
+ "{% ifdef CHUNDA %}{{ CHUNDA }}{% endif %}\n"
+ "{% endblock %}\n"
+ "{% block listing %}\n"
+ "{% ifdef DATE_FORMATTED %}{{ DATE_FORMATTED }}{% endif %}\n"
+ "bola: {% ifdef BOLA %}{{ BOLA }}{% endif %}\n"
+ "{% foreach TAGS %}lol {{ FOREACH_ITEM }} haha {% endforeach %}\n"
+ "{% endblock %}\n";
+ blogc_error_t *err = NULL;
+ sb_slist_t *l = blogc_template_parse(str, strlen(str), &err);
+ assert_non_null(l);
+ assert_null(err);
+ char *out = blogc_render(l, NULL, NULL, true);
+ assert_string_equal(out,
+ "foo\n"
+ "fuuu\n"
+ "\n"
+ "\n");
+ blogc_template_free_stmts(l);
+ free(out);
+}
+
+
+static void
+test_render_ifdef(void **state)
+{
+ const char *str =
+ "{% block entry %}\n"
+ "{% ifdef CHUNDA %}chunda\n"
+ "{% ifdef GUDA %}guda\n"
+ "{% ifdef BOLA %}bola\n"
+ "{% endif %}\n"
+ "{% endif %}\n"
+ "{% endif %}\n"
+ "{% endblock %}\n";
+ blogc_error_t *err = NULL;
+ sb_slist_t *l = blogc_template_parse(str, strlen(str), &err);
+ assert_non_null(l);
+ assert_null(err);
+ sb_slist_t *s = create_sources(1);
+ assert_non_null(s);
+ char *out = blogc_render(l, s, NULL, false);
+ assert_string_equal(out,
+ "\n"
+ "\n"
+ "\n");
+ blogc_template_free_stmts(l);
+ sb_slist_free_full(s, (sb_free_func_t) sb_trie_free);
+ free(out);
+}
+
+
+static void
+test_render_ifdef2(void **state)
+{
+ const char *str =
+ "{% block entry %}\n"
+ "{% ifdef GUDA %}guda\n"
+ "{% ifdef CHUNDA %}chunda\n"
+ "{% ifdef BOLA %}bola\n"
+ "{% endif %}\n"
+ "{% endif %}\n"
+ "{% endif %}\n"
+ "{% endblock %}\n";
+ blogc_error_t *err = NULL;
+ sb_slist_t *l = blogc_template_parse(str, strlen(str), &err);
+ assert_non_null(l);
+ assert_null(err);
+ sb_slist_t *s = create_sources(1);
+ assert_non_null(s);
+ char *out = blogc_render(l, s, NULL, false);
+ assert_string_equal(out,
+ "\n"
+ "guda\n"
+ "\n"
+ "\n"
+ "\n");
+ blogc_template_free_stmts(l);
+ sb_slist_free_full(s, (sb_free_func_t) sb_trie_free);
+ free(out);
+}
+
+
+static void
+test_render_ifdef3(void **state)
+{
+ const char *str =
+ "{% block entry %}\n"
+ "{% ifdef GUDA %}guda\n"
+ "{% ifdef BOLA %}bola\n"
+ "{% ifdef CHUNDA %}chunda\n"
+ "{% endif %}\n"
+ "{% endif %}\n"
+ "{% endif %}\n"
+ "{% endblock %}\n";
+ blogc_error_t *err = NULL;
+ sb_slist_t *l = blogc_template_parse(str, strlen(str), &err);
+ assert_non_null(l);
+ assert_null(err);
+ sb_slist_t *s = create_sources(1);
+ assert_non_null(s);
+ char *out = blogc_render(l, s, NULL, false);
+ assert_string_equal(out,
+ "\n"
+ "guda\n"
+ "bola\n"
+ "\n"
+ "\n"
+ "\n"
+ "\n");
+ blogc_template_free_stmts(l);
+ sb_slist_free_full(s, (sb_free_func_t) sb_trie_free);
+ free(out);
+}
+
+
+static void
+test_render_ifdef4(void **state)
+{
+ const char *str =
+ "{% block entry %}\n"
+ "{% ifdef GUDA %}guda\n"
+ "{% ifdef BOLA %}bola\n"
+ "{% ifdef CHUNDA %}chunda\n"
+ "{% else %}else\n"
+ "{% endif %}\n"
+ "{% endif %}\n"
+ "{% else %}lol\n"
+ "{% endif %}\n"
+ "{% endblock %}\n";
+ blogc_error_t *err = NULL;
+ sb_slist_t *l = blogc_template_parse(str, strlen(str), &err);
+ assert_non_null(l);
+ assert_null(err);
+ sb_slist_t *s = create_sources(1);
+ assert_non_null(s);
+ char *out = blogc_render(l, s, NULL, false);
+ assert_string_equal(out,
+ "\n"
+ "guda\n"
+ "bola\n"
+ "else\n"
+ "\n"
+ "\n"
+ "\n"
+ "\n");
+ blogc_template_free_stmts(l);
+ sb_slist_free_full(s, (sb_free_func_t) sb_trie_free);
+ free(out);
+}
+
+
+static void
+test_render_ifdef5(void **state)
+{
+ const char *str =
+ "{% block entry %}\n"
+ "{% ifdef GUDA %}guda\n"
+ "{% ifdef CHUNDA %}chunda\n"
+ "{% ifdef BOLA %}bola\n"
+ "{% endif %}\n"
+ "{% else %}else\n"
+ "{% endif %}\n"
+ "{% else %}lol\n"
+ "{% endif %}\n"
+ "{% endblock %}\n";
+ blogc_error_t *err = NULL;
+ sb_slist_t *l = blogc_template_parse(str, strlen(str), &err);
+ assert_non_null(l);
+ assert_null(err);
+ sb_slist_t *s = create_sources(1);
+ assert_non_null(s);
+ char *out = blogc_render(l, s, NULL, false);
+ assert_string_equal(out,
+ "\n"
+ "guda\n"
+ "else\n"
+ "\n"
+ "\n"
+ "\n");
+ blogc_template_free_stmts(l);
+ sb_slist_free_full(s, (sb_free_func_t) sb_trie_free);
+ free(out);
+}
+
+
+static void
+test_render_ifdef6(void **state)
+{
+ const char *str =
+ "{% block entry %}\n"
+ "{% ifdef CHUNDA %}chunda\n"
+ "{% ifdef GUDA %}guda\n"
+ "{% ifdef BOLA %}bola\n"
+ "{% endif %}\n"
+ "{% else %}else\n"
+ "{% endif %}\n"
+ "{% else %}lol\n"
+ "{% endif %}\n"
+ "{% endblock %}\n";
+ blogc_error_t *err = NULL;
+ sb_slist_t *l = blogc_template_parse(str, strlen(str), &err);
+ assert_non_null(l);
+ assert_null(err);
+ sb_slist_t *s = create_sources(1);
+ assert_non_null(s);
+ char *out = blogc_render(l, s, NULL, false);
+ assert_string_equal(out,
+ "\n"
+ "lol\n"
+ "\n"
+ "\n");
+ blogc_template_free_stmts(l);
+ sb_slist_free_full(s, (sb_free_func_t) sb_trie_free);
+ free(out);
+}
+
+
+static void
+test_render_ifdef7(void **state)
+{
+ const char *str =
+ "{% block entry %}\n"
+ "{% ifdef GUDA %}guda\n"
+ "{% ifdef BOLA %}bola\n"
+ "{% ifdef CHUNDA %}chunda\n"
+ "{% endif %}\n"
+ "{% endif %}\n"
+ "{% ifdef CHUNDA %}ch\n"
+ "{% else %}else\n"
+ "{% endif %}\n"
+ "{% endif %}\n"
+ "{% endblock %}\n";
+ blogc_error_t *err = NULL;
+ sb_slist_t *l = blogc_template_parse(str, strlen(str), &err);
+ assert_non_null(l);
+ assert_null(err);
+ sb_slist_t *s = create_sources(1);
+ assert_non_null(s);
+ char *out = blogc_render(l, s, NULL, false);
+ assert_string_equal(out,
+ "\n"
+ "guda\n"
+ "bola\n"
+ "\n"
+ "\n"
+ "else\n"
+ "\n"
+ "\n"
+ "\n");
+ blogc_template_free_stmts(l);
+ sb_slist_free_full(s, (sb_free_func_t) sb_trie_free);
+ free(out);
+}
+
+
+static void
+test_render_ifndef(void **state)
+{
+ const char *str =
+ "{% block entry %}\n"
+ "{% ifndef CHUNDA %}chunda\n"
+ "{% ifdef GUDA %}guda\n"
+ "{% ifndef BOLA %}bola\n"
+ "{% else %}else\n"
+ "{% endif %}\n"
+ "{% endif %}\n"
+ "{% endif %}\n"
+ "{% endblock %}\n";
+ blogc_error_t *err = NULL;
+ sb_slist_t *l = blogc_template_parse(str, strlen(str), &err);
+ assert_non_null(l);
+ assert_null(err);
+ sb_slist_t *s = create_sources(1);
+ assert_non_null(s);
+ char *out = blogc_render(l, s, NULL, false);
+ assert_string_equal(out,
+ "\n"
+ "chunda\n"
+ "guda\n"
+ "else\n"
+ "\n"
+ "\n"
+ "\n"
+ "\n");
+ blogc_template_free_stmts(l);
+ sb_slist_free_full(s, (sb_free_func_t) sb_trie_free);
+ free(out);
+}
+
+
+static void
+test_render_if_eq(void **state)
+{
+ const char *str =
+ "{% block entry %}\n"
+ "{% if GUDA == GUDA2 %}gudabola{% endif %}\n"
+ "{% if GUDA == \"zxc\" %}guda\n"
+ "{% ifdef BOLA %}bola\n"
+ "{% if GUDA > \"zxc\" %}asd\n"
+ "{% else %}else\n"
+ "{% endif %}\n"
+ "{% endif %}\n"
+ "{% endif %}\n"
+ "{% endblock %}\n";
+ blogc_error_t *err = NULL;
+ sb_slist_t *l = blogc_template_parse(str, strlen(str), &err);
+ assert_non_null(l);
+ assert_null(err);
+ sb_slist_t *s = create_sources(1);
+ assert_non_null(s);
+ char *out = blogc_render(l, s, NULL, false);
+ assert_string_equal(out,
+ "\n"
+ "gudabola\n"
+ "guda\n"
+ "bola\n"
+ "else\n"
+ "\n"
+ "\n"
+ "\n"
+ "\n");
+ blogc_template_free_stmts(l);
+ sb_slist_free_full(s, (sb_free_func_t) sb_trie_free);
+ free(out);
+}
+
+
+static void
+test_render_if_neq(void **state)
+{
+ const char *str =
+ "{% block entry %}\n"
+ "{% if GUDA != BOLA %}gudabola{% endif %}\n"
+ "{% if GUDA != \"zxa\" %}guda\n"
+ "{% ifdef BOLA %}bola\n"
+ "{% if GUDA > \"zxc\" %}asd\n"
+ "{% else %}else\n"
+ "{% endif %}\n"
+ "{% endif %}\n"
+ "{% endif %}\n"
+ "{% endblock %}\n";
+ blogc_error_t *err = NULL;
+ sb_slist_t *l = blogc_template_parse(str, strlen(str), &err);
+ assert_non_null(l);
+ assert_null(err);
+ sb_slist_t *s = create_sources(1);
+ assert_non_null(s);
+ char *out = blogc_render(l, s, NULL, false);
+ assert_string_equal(out,
+ "\n"
+ "gudabola\n"
+ "guda\n"
+ "bola\n"
+ "else\n"
+ "\n"
+ "\n"
+ "\n"
+ "\n");
+ blogc_template_free_stmts(l);
+ sb_slist_free_full(s, (sb_free_func_t) sb_trie_free);
+ free(out);
+}
+
+
+static void
+test_render_if_lt(void **state)
+{
+ const char *str =
+ "{% block entry %}\n"
+ "{% if BOLA < GUDA %}gudabola{% endif %}\n"
+ "{% if GUDA < \"zxe\" %}guda\n"
+ "{% ifdef BOLA %}bola\n"
+ "{% if GUDA > \"zxc\" %}asd\n"
+ "{% else %}else\n"
+ "{% endif %}\n"
+ "{% endif %}\n"
+ "{% endif %}\n"
+ "{% endblock %}\n";
+ blogc_error_t *err = NULL;
+ sb_slist_t *l = blogc_template_parse(str, strlen(str), &err);
+ assert_non_null(l);
+ assert_null(err);
+ sb_slist_t *s = create_sources(1);
+ assert_non_null(s);
+ char *out = blogc_render(l, s, NULL, false);
+ assert_string_equal(out,
+ "\n"
+ "gudabola\n"
+ "guda\n"
+ "bola\n"
+ "else\n"
+ "\n"
+ "\n"
+ "\n"
+ "\n");
+ blogc_template_free_stmts(l);
+ sb_slist_free_full(s, (sb_free_func_t) sb_trie_free);
+ free(out);
+}
+
+
+static void
+test_render_if_gt(void **state)
+{
+ const char *str =
+ "{% block entry %}\n"
+ "{% if GUDA > BOLA %}gudabola{% endif %}\n"
+ "{% if GUDA > \"zxa\" %}guda\n"
+ "{% ifdef BOLA %}bola\n"
+ "{% if GUDA > \"zxc\" %}asd\n"
+ "{% else %}else\n"
+ "{% endif %}\n"
+ "{% endif %}\n"
+ "{% endif %}\n"
+ "{% endblock %}\n";
+ blogc_error_t *err = NULL;
+ sb_slist_t *l = blogc_template_parse(str, strlen(str), &err);
+ assert_non_null(l);
+ assert_null(err);
+ sb_slist_t *s = create_sources(1);
+ assert_non_null(s);
+ char *out = blogc_render(l, s, NULL, false);
+ assert_string_equal(out,
+ "\n"
+ "gudabola\n"
+ "guda\n"
+ "bola\n"
+ "else\n"
+ "\n"
+ "\n"
+ "\n"
+ "\n");
+ blogc_template_free_stmts(l);
+ sb_slist_free_full(s, (sb_free_func_t) sb_trie_free);
+ free(out);
+}
+
+
+static void
+test_render_if_lt_eq(void **state)
+{
+ const char *str =
+ "{% block entry %}\n"
+ "{% if BOLA <= GUDA %}gudabola{% endif %}\n"
+ "{% if GUDA <= \"zxc\" %}guda\n"
+ "{% if GUDA <= \"zxe\" %}guda2\n"
+ "{% ifdef BOLA %}bola\n"
+ "{% if GUDA > \"zxc\" %}asd\n"
+ "{% else %}else\n"
+ "{% endif %}\n"
+ "{% endif %}\n"
+ "{% endif %}\n"
+ "{% endif %}\n"
+ "{% endblock %}\n";
+ blogc_error_t *err = NULL;
+ sb_slist_t *l = blogc_template_parse(str, strlen(str), &err);
+ assert_non_null(l);
+ assert_null(err);
+ sb_slist_t *s = create_sources(1);
+ assert_non_null(s);
+ char *out = blogc_render(l, s, NULL, false);
+ assert_string_equal(out,
+ "\n"
+ "gudabola\n"
+ "guda\n"
+ "guda2\n"
+ "bola\n"
+ "else\n"
+ "\n"
+ "\n"
+ "\n"
+ "\n"
+ "\n");
+ blogc_template_free_stmts(l);
+ sb_slist_free_full(s, (sb_free_func_t) sb_trie_free);
+ free(out);
+}
+
+
+static void
+test_render_if_gt_eq(void **state)
+{
+ const char *str =
+ "{% block entry %}\n"
+ "{% if GUDA >= BOLA %}gudabola{% endif %}\n"
+ "{% if GUDA >= \"zxc\" %}guda\n"
+ "{% if GUDA >= \"zxa\" %}guda2\n"
+ "{% ifdef BOLA %}bola\n"
+ "{% if GUDA > \"zxc\" %}asd\n"
+ "{% else %}else\n"
+ "{% endif %}\n"
+ "{% endif %}\n"
+ "{% endif %}\n"
+ "{% endif %}\n"
+ "{% endblock %}\n";
+ blogc_error_t *err = NULL;
+ sb_slist_t *l = blogc_template_parse(str, strlen(str), &err);
+ assert_non_null(l);
+ assert_null(err);
+ sb_slist_t *s = create_sources(1);
+ assert_non_null(s);
+ char *out = blogc_render(l, s, NULL, false);
+ assert_string_equal(out,
+ "\n"
+ "gudabola\n"
+ "guda\n"
+ "guda2\n"
+ "bola\n"
+ "else\n"
+ "\n"
+ "\n"
+ "\n"
+ "\n"
+ "\n");
+ blogc_template_free_stmts(l);
+ sb_slist_free_full(s, (sb_free_func_t) sb_trie_free);
+ free(out);
+}
+
+
+static void
+test_render_foreach(void **state)
+{
+ const char *str =
+ "{% block entry %}\n"
+ "{% foreach TAGS %} {{ FOREACH_ITEM }} {% endforeach %}\n"
+ "{% endblock %}\n";
+ blogc_error_t *err = NULL;
+ sb_slist_t *l = blogc_template_parse(str, strlen(str), &err);
+ assert_non_null(l);
+ assert_null(err);
+ sb_slist_t *s = create_sources(1);
+ assert_non_null(s);
+ char *out = blogc_render(l, s, NULL, false);
+ assert_string_equal(out,
+ "\n"
+ " foo bar baz \n"
+ "\n");
+ blogc_template_free_stmts(l);
+ sb_slist_free_full(s, (sb_free_func_t) sb_trie_free);
+ free(out);
+}
+
+
+static void
+test_render_foreach_if(void **state)
+{
+ const char *str =
+ "{% block entry %}\n"
+ "{% foreach TAGS %} {% if FOREACH_ITEM == \"bar\" %}{{ FOREACH_ITEM }}"
+ "{% endif %} {% endforeach %}\n"
+ "{% endblock %}\n";
+ blogc_error_t *err = NULL;
+ sb_slist_t *l = blogc_template_parse(str, strlen(str), &err);
+ assert_non_null(l);
+ assert_null(err);
+ sb_slist_t *s = create_sources(1);
+ assert_non_null(s);
+ char *out = blogc_render(l, s, NULL, false);
+ assert_string_equal(out,
+ "\n"
+ " bar \n"
+ "\n");
+ blogc_template_free_stmts(l);
+ sb_slist_free_full(s, (sb_free_func_t) sb_trie_free);
+ free(out);
+}
+
+
+static void
+test_render_foreach_if_else(void **state)
+{
+ const char *str =
+ "{% block entry %}\n"
+ "{% foreach TAGS %}{% if FOREACH_ITEM == \"bar\" %}yay"
+ "{% else %}{{ FOREACH_ITEM }}"
+ "{% endif %} {% endforeach %}\n"
+ "{% endblock %}\n";
+ blogc_error_t *err = NULL;
+ sb_slist_t *l = blogc_template_parse(str, strlen(str), &err);
+ assert_non_null(l);
+ assert_null(err);
+ sb_slist_t *s = create_sources(1);
+ assert_non_null(s);
+ char *out = blogc_render(l, s, NULL, false);
+ assert_string_equal(out,
+ "\n"
+ "foo yay baz \n"
+ "\n");
+ blogc_template_free_stmts(l);
+ sb_slist_free_full(s, (sb_free_func_t) sb_trie_free);
+ free(out);
+}
+
+
+static void
+test_render_null(void **state)
+{
+ assert_null(blogc_render(NULL, NULL, NULL, false));
+}
+
+
+static void
+test_render_outside_block(void **state)
+{
+ const char *str =
+ "{% ifdef GUDA %}bola{% endif %}\n"
+ "{{ BOLA }}\n"
+ "{% ifndef CHUNDA %}lol{% endif %}\n";
+ blogc_error_t *err = NULL;
+ sb_slist_t *l = blogc_template_parse(str, strlen(str), &err);
+ assert_non_null(l);
+ assert_null(err);
+ sb_slist_t *s = create_sources(1);
+ assert_non_null(s);
+ sb_trie_t *c = sb_trie_new(free);
+ sb_trie_insert(c, "GUDA", sb_strdup("asd"));
+ char *out = blogc_render(l, s, c, false);
+ assert_string_equal(out,
+ "bola\n"
+ "\n"
+ "lol\n");
+ sb_trie_free(c);
+ blogc_template_free_stmts(l);
+ sb_slist_free_full(s, (sb_free_func_t) sb_trie_free);
+ free(out);
+}
+
+
+static void
+test_render_prefer_local_variable(void **state)
+{
+ const char *str =
+ "{% block entry %}\n"
+ "{% ifdef LOL %}{{ LOL }}{% endif %}\n"
+ "{% ifndef CHUNDA %}chunda\n"
+ "{% ifdef GUDA %}{{ GUDA }}\n"
+ "{% ifndef BOLA %}bola\n"
+ "{% endif %}\n"
+ "{% endif %}\n"
+ "{% endif %}\n"
+ "{% endblock %}\n";
+ blogc_error_t *err = NULL;
+ sb_slist_t *l = blogc_template_parse(str, strlen(str), &err);
+ assert_non_null(l);
+ assert_null(err);
+ sb_slist_t *s = create_sources(1);
+ assert_non_null(s);
+ sb_trie_t *c = sb_trie_new(free);
+ sb_trie_insert(c, "GUDA", sb_strdup("hehe"));
+ sb_trie_insert(c, "LOL", sb_strdup("hmm"));
+ char *out = blogc_render(l, s, c, false);
+ assert_string_equal(out,
+ "\n"
+ "hmm\n"
+ "chunda\n"
+ "zxc\n"
+ "\n"
+ "\n"
+ "\n"
+ "\n");
+ sb_trie_free(c);
+ blogc_template_free_stmts(l);
+ sb_slist_free_full(s, (sb_free_func_t) sb_trie_free);
+ free(out);
+}
+
+
+static void
+test_render_respect_variable_scope(void **state)
+{
+ const char *str =
+ "{{ LOL }}\n"
+ "{{ BOLA }}\n"
+ "{% block entry %}\n"
+ "{% ifdef LOL %}{{ LOL }}{% endif %}\n"
+ "{% ifdef BOLA %}{{ BOLA }}{% endif %}\n"
+ "{% endblock %}\n";
+ blogc_error_t *err = NULL;
+ sb_slist_t *l = blogc_template_parse(str, strlen(str), &err);
+ assert_non_null(l);
+ assert_null(err);
+ sb_slist_t *s = create_sources(1);
+ assert_non_null(s);
+ sb_trie_t *c = sb_trie_new(free);
+ char *out = blogc_render(l, s, c, false);
+ assert_string_equal(out,
+ "\n"
+ "\n"
+ "\n"
+ "\n"
+ "asd\n"
+ "\n");
+ sb_trie_free(c);
+ blogc_template_free_stmts(l);
+ sb_slist_free_full(s, (sb_free_func_t) sb_trie_free);
+ free(out);
+}
+
+
+static void
+test_render_ifcount_bug(void **state)
+{
+ const char *str =
+ "{% block entry %}\n"
+ "{% ifdef TITLE %}<h3>{{ TITLE }}</h3>{% endif %}\n"
+ "{% ifdef IS_POST %}\n"
+ "{% ifdef ASD %}ASD{% endif %}\n"
+ "{% endif %}\n"
+ "{% endblock %}\n";
+ blogc_error_t *err = NULL;
+ sb_slist_t *l = blogc_template_parse(str, strlen(str), &err);
+ assert_non_null(l);
+ assert_null(err);
+ sb_slist_t *s = NULL;
+ s = sb_slist_append(s, sb_trie_new(free));
+ sb_trie_insert(s->data, "TITLE", sb_strdup("bola"));
+ sb_trie_t *c = sb_trie_new(free);
+ char *out = blogc_render(l, s, c, false);
+ assert_string_equal(out,
+ "\n"
+ "<h3>bola</h3>\n"
+ "\n"
+ "\n");
+ sb_trie_free(c);
+ blogc_template_free_stmts(l);
+ sb_slist_free_full(s, (sb_free_func_t) sb_trie_free);
+ free(out);
+}
+
+
+static void
+test_get_variable(void **state)
+{
+ sb_trie_t *g = sb_trie_new(free);
+ sb_trie_insert(g, "NAME", sb_strdup("bola"));
+ sb_trie_insert(g, "TITLE", sb_strdup("bola2"));
+ sb_trie_t *l = sb_trie_new(free);
+ sb_trie_insert(l, "NAME", sb_strdup("chunda"));
+ sb_trie_insert(l, "TITLE", sb_strdup("chunda2"));
+ assert_string_equal(blogc_get_variable("NAME", g, l), "chunda");
+ assert_string_equal(blogc_get_variable("TITLE", g, l), "chunda2");
+ assert_null(blogc_get_variable("BOLA", g, l));
+ sb_trie_free(g);
+ sb_trie_free(l);
+}
+
+
+static void
+test_get_variable_only_local(void **state)
+{
+ sb_trie_t *g = NULL;
+ sb_trie_t *l = sb_trie_new(free);
+ sb_trie_insert(l, "NAME", sb_strdup("chunda"));
+ sb_trie_insert(l, "TITLE", sb_strdup("chunda2"));
+ assert_string_equal(blogc_get_variable("NAME", g, l), "chunda");
+ assert_string_equal(blogc_get_variable("TITLE", g, l), "chunda2");
+ assert_null(blogc_get_variable("BOLA", g, l));
+ sb_trie_free(l);
+}
+
+
+static void
+test_get_variable_only_global(void **state)
+{
+ sb_trie_t *g = sb_trie_new(free);
+ sb_trie_insert(g, "NAME", sb_strdup("bola"));
+ sb_trie_insert(g, "TITLE", sb_strdup("bola2"));
+ sb_trie_t *l = NULL;
+ assert_string_equal(blogc_get_variable("NAME", g, l), "bola");
+ assert_string_equal(blogc_get_variable("TITLE", g, l), "bola2");
+ assert_null(blogc_get_variable("BOLA", g, l));
+ sb_trie_free(g);
+}
+
+
+static void
+test_format_date(void **state)
+{
+ sb_trie_t *g = sb_trie_new(free);
+ sb_trie_insert(g, "DATE_FORMAT", sb_strdup("%H -- %M"));
+ sb_trie_t *l = sb_trie_new(free);
+ sb_trie_insert(l, "DATE_FORMAT", sb_strdup("%R"));
+ char *date = blogc_format_date("2015-01-02 03:04:05", g, l);
+ assert_string_equal(date, "03:04");
+ free(date);
+ sb_trie_free(g);
+ sb_trie_free(l);
+}
+
+
+static void
+test_format_date_with_global_format(void **state)
+{
+ sb_trie_t *g = sb_trie_new(free);
+ sb_trie_insert(g, "DATE_FORMAT", sb_strdup("%H -- %M"));
+ sb_trie_t *l = sb_trie_new(free);
+ char *date = blogc_format_date("2015-01-02 03:04:05", g, l);
+ assert_string_equal(date, "03 -- 04");
+ free(date);
+ sb_trie_free(g);
+ sb_trie_free(l);
+}
+
+
+static void
+test_format_date_without_format(void **state)
+{
+ sb_trie_t *g = sb_trie_new(free);
+ sb_trie_t *l = sb_trie_new(free);
+ char *date = blogc_format_date("2015-01-02 03:04:05", g, l);
+ assert_string_equal(date, "2015-01-02 03:04:05");
+ free(date);
+ sb_trie_free(g);
+ sb_trie_free(l);
+}
+
+
+static void
+test_format_date_without_date(void **state)
+{
+ sb_trie_t *g = sb_trie_new(free);
+ sb_trie_t *l = sb_trie_new(free);
+ char *date = blogc_format_date(NULL, g, l);
+ assert_null(date);
+ free(date);
+ sb_trie_free(g);
+ sb_trie_free(l);
+}
+
+
+static void
+test_format_variable(void **state)
+{
+ // FIXME: test warnings
+ sb_trie_t *g = sb_trie_new(free);
+ sb_trie_insert(g, "NAME", sb_strdup("bola"));
+ sb_trie_insert(g, "TITLE", sb_strdup("bola2"));
+ sb_trie_t *l = sb_trie_new(free);
+ sb_trie_insert(l, "NAME", sb_strdup("chunda"));
+ sb_trie_insert(l, "TITLE", sb_strdup("chunda2"));
+ sb_trie_insert(l, "SIZE", sb_strdup("1234567890987654321"));
+ char *tmp = blogc_format_variable("NAME", g, l, NULL);
+ assert_string_equal(tmp, "chunda");
+ free(tmp);
+ tmp = blogc_format_variable("TITLE", g, l, NULL);
+ assert_string_equal(tmp, "chunda2");
+ free(tmp);
+ tmp = blogc_format_variable("TITLE_2", g, l, NULL);
+ assert_string_equal(tmp, "ch");
+ free(tmp);
+ tmp = blogc_format_variable("SIZE_12", g, l, NULL);
+ assert_string_equal(tmp, "123456789098");
+ free(tmp);
+ tmp = blogc_format_variable("SIZE_200", g, l, NULL);
+ assert_string_equal(tmp, "1234567890987654321");
+ free(tmp);
+ assert_null(blogc_format_variable("SIZE_", g, l, NULL));
+ assert_null(blogc_format_variable("BOLA", g, l, NULL));
+ sb_trie_free(g);
+ sb_trie_free(l);
+}
+
+
+static void
+test_format_variable_with_date(void **state)
+{
+ sb_trie_t *g = sb_trie_new(free);
+ sb_trie_insert(g, "DATE", sb_strdup("2010-11-12 13:14:15"));
+ sb_trie_insert(g, "DATE_FORMAT", sb_strdup("%R"));
+ sb_trie_t *l = sb_trie_new(free);
+ sb_trie_insert(l, "DATE", sb_strdup("2011-12-13 14:15:16"));
+ char *tmp = blogc_format_variable("DATE_FORMATTED", g, l, NULL);
+ assert_string_equal(tmp, "14:15");
+ free(tmp);
+ tmp = blogc_format_variable("DATE_FORMATTED_3", g, l, NULL);
+ assert_string_equal(tmp, "14:");
+ free(tmp);
+ tmp = blogc_format_variable("DATE_FORMATTED_10", g, l, NULL);
+ assert_string_equal(tmp, "14:15");
+ free(tmp);
+ sb_trie_free(g);
+ sb_trie_free(l);
+}
+
+
+static void
+test_format_variable_foreach(void **state)
+{
+ sb_slist_t *l = NULL;
+ l = sb_slist_append(l, sb_strdup("asd"));
+ l = sb_slist_append(l, sb_strdup("qwe"));
+ l = sb_slist_append(l, sb_strdup("zxcvbn"));
+ char *tmp = blogc_format_variable("FOREACH_ITEM", NULL, NULL, l->next);
+ assert_string_equal(tmp, "qwe");
+ free(tmp);
+ tmp = blogc_format_variable("FOREACH_ITEM_4", NULL, NULL,
+ l->next->next);
+ assert_string_equal(tmp, "zxcv");
+ free(tmp);
+ tmp = blogc_format_variable("FOREACH_ITEM_10", NULL, NULL,
+ l->next->next);
+ assert_string_equal(tmp, "zxcvbn");
+ free(tmp);
+ sb_slist_free_full(l, free);
+}
+
+
+static void
+test_format_variable_foreach_empty(void **state)
+{
+ assert_null(blogc_format_variable("FOREACH_ITEM", NULL, NULL, NULL));
+ assert_null(blogc_format_variable("FOREACH_ITEM_4", NULL, NULL, NULL));
+}
+
+
+static void
+test_split_list_variable(void **state)
+{
+ sb_trie_t *g = sb_trie_new(free);
+ sb_trie_insert(g, "TAGS", sb_strdup("asd lol hehe"));
+ sb_trie_t *l = sb_trie_new(free);
+ sb_trie_insert(l, "TAGS", sb_strdup("asd lol XD"));
+ sb_slist_t *tmp = blogc_split_list_variable("TAGS", g, l);
+ assert_string_equal(tmp->data, "asd");
+ assert_string_equal(tmp->next->data, "lol");
+ assert_string_equal(tmp->next->next->data, "XD");
+ sb_slist_free_full(tmp, free);
+ sb_trie_free(g);
+ sb_trie_free(l);
+}
+
+
+static void
+test_split_list_variable_not_found(void **state)
+{
+ sb_trie_t *g = sb_trie_new(free);
+ sb_trie_insert(g, "TAGS", sb_strdup("asd lol hehe"));
+ sb_trie_t *l = sb_trie_new(free);
+ sb_trie_insert(l, "TAGS", sb_strdup("asd lol XD"));
+ sb_slist_t *tmp = blogc_split_list_variable("TAG", g, l);
+ assert_null(tmp);
+ sb_trie_free(g);
+ sb_trie_free(l);
+}
+
+
+int
+main(void)
+{
+ const UnitTest tests[] = {
+ unit_test(test_render_entry),
+ unit_test(test_render_listing),
+ unit_test(test_render_listing_empty),
+ unit_test(test_render_ifdef),
+ unit_test(test_render_ifdef2),
+ unit_test(test_render_ifdef3),
+ unit_test(test_render_ifdef4),
+ unit_test(test_render_ifdef5),
+ unit_test(test_render_ifdef6),
+ unit_test(test_render_ifdef7),
+ unit_test(test_render_ifndef),
+ unit_test(test_render_if_eq),
+ unit_test(test_render_if_neq),
+ unit_test(test_render_if_lt),
+ unit_test(test_render_if_gt),
+ unit_test(test_render_if_lt_eq),
+ unit_test(test_render_if_gt_eq),
+ unit_test(test_render_foreach),
+ unit_test(test_render_foreach_if),
+ unit_test(test_render_foreach_if_else),
+ unit_test(test_render_null),
+ unit_test(test_render_outside_block),
+ unit_test(test_render_prefer_local_variable),
+ unit_test(test_render_respect_variable_scope),
+ unit_test(test_render_ifcount_bug),
+ unit_test(test_get_variable),
+ unit_test(test_get_variable_only_local),
+ unit_test(test_get_variable_only_global),
+ unit_test(test_format_date),
+ unit_test(test_format_date_with_global_format),
+ unit_test(test_format_date_without_format),
+ unit_test(test_format_date_without_date),
+ unit_test(test_format_variable),
+ unit_test(test_format_variable_with_date),
+ unit_test(test_format_variable_foreach),
+ unit_test(test_format_variable_foreach_empty),
+ unit_test(test_split_list_variable),
+ unit_test(test_split_list_variable_not_found),
+ };
+ return run_tests(tests);
+}
diff --git a/tests/blogc/check_source_parser.c b/tests/blogc/check_source_parser.c
new file mode 100644
index 0000000..a1849eb
--- /dev/null
+++ b/tests/blogc/check_source_parser.c
@@ -0,0 +1,542 @@
+/*
+ * blogc: A blog compiler.
+ * Copyright (C) 2015-2016 Rafael G. Martins <rafael@rafaelmartins.eng.br>
+ *
+ * This program can be distributed under the terms of the BSD License.
+ * See the file LICENSE.
+ */
+
+#include <stdarg.h>
+#include <stddef.h>
+#include <setjmp.h>
+#include <cmocka.h>
+#include <string.h>
+#include "../../src/blogc/source-parser.h"
+#include "../../src/blogc/error.h"
+#include "../../src/common/utils.h"
+
+
+static void
+test_source_parse(void **state)
+{
+ const char *a =
+ "VAR1: asd asd\n"
+ "VAR2: 123chunda\n"
+ "----------\n"
+ "# This is a test\n"
+ "\n"
+ "bola\n";
+ blogc_error_t *err = NULL;
+ sb_trie_t *source = blogc_source_parse(a, strlen(a), &err);
+ assert_null(err);
+ assert_non_null(source);
+ assert_int_equal(sb_trie_size(source), 6);
+ assert_string_equal(sb_trie_lookup(source, "VAR1"), "asd asd");
+ assert_string_equal(sb_trie_lookup(source, "VAR2"), "123chunda");
+ assert_string_equal(sb_trie_lookup(source, "EXCERPT"),
+ "<h1 id=\"this-is-a-test\">This is a test</h1>\n"
+ "<p>bola</p>\n");
+ assert_string_equal(sb_trie_lookup(source, "CONTENT"),
+ "<h1 id=\"this-is-a-test\">This is a test</h1>\n"
+ "<p>bola</p>\n");
+ assert_string_equal(sb_trie_lookup(source, "RAW_CONTENT"),
+ "# This is a test\n"
+ "\n"
+ "bola\n");
+ assert_string_equal(sb_trie_lookup(source, "DESCRIPTION"), "bola");
+ sb_trie_free(source);
+}
+
+
+static void
+test_source_parse_crlf(void **state)
+{
+ const char *a =
+ "VAR1: asd asd\r\n"
+ "VAR2: 123chunda\r\n"
+ "----------\r\n"
+ "# This is a test\r\n"
+ "\r\n"
+ "bola\r\n";
+ blogc_error_t *err = NULL;
+ sb_trie_t *source = blogc_source_parse(a, strlen(a), &err);
+ assert_null(err);
+ assert_non_null(source);
+ assert_int_equal(sb_trie_size(source), 6);
+ assert_string_equal(sb_trie_lookup(source, "VAR1"), "asd asd");
+ assert_string_equal(sb_trie_lookup(source, "VAR2"), "123chunda");
+ assert_string_equal(sb_trie_lookup(source, "EXCERPT"),
+ "<h1 id=\"this-is-a-test\">This is a test</h1>\r\n"
+ "<p>bola</p>\r\n");
+ assert_string_equal(sb_trie_lookup(source, "CONTENT"),
+ "<h1 id=\"this-is-a-test\">This is a test</h1>\r\n"
+ "<p>bola</p>\r\n");
+ assert_string_equal(sb_trie_lookup(source, "RAW_CONTENT"),
+ "# This is a test\r\n"
+ "\r\n"
+ "bola\r\n");
+ assert_string_equal(sb_trie_lookup(source, "DESCRIPTION"), "bola");
+ sb_trie_free(source);
+}
+
+
+static void
+test_source_parse_with_spaces(void **state)
+{
+ const char *a =
+ "\n \n"
+ "VAR1: chunda \t \n"
+ "\n\n"
+ "BOLA: guda\n"
+ "----------\n"
+ "# This is a test\n"
+ "\n"
+ "bola\n";
+ blogc_error_t *err = NULL;
+ sb_trie_t *source = blogc_source_parse(a, strlen(a), &err);
+ assert_null(err);
+ assert_non_null(source);
+ assert_int_equal(sb_trie_size(source), 6);
+ assert_string_equal(sb_trie_lookup(source, "VAR1"), "chunda");
+ assert_string_equal(sb_trie_lookup(source, "BOLA"), "guda");
+ assert_string_equal(sb_trie_lookup(source, "EXCERPT"),
+ "<h1 id=\"this-is-a-test\">This is a test</h1>\n"
+ "<p>bola</p>\n");
+ assert_string_equal(sb_trie_lookup(source, "CONTENT"),
+ "<h1 id=\"this-is-a-test\">This is a test</h1>\n"
+ "<p>bola</p>\n");
+ assert_string_equal(sb_trie_lookup(source, "RAW_CONTENT"),
+ "# This is a test\n"
+ "\n"
+ "bola\n");
+ assert_string_equal(sb_trie_lookup(source, "DESCRIPTION"), "bola");
+ sb_trie_free(source);
+}
+
+
+static void
+test_source_parse_with_excerpt(void **state)
+{
+ const char *a =
+ "VAR1: asd asd\n"
+ "VAR2: 123chunda\n"
+ "----------\n"
+ "# This is a test\n"
+ "\n"
+ "bola\n"
+ "\n"
+ "...\n"
+ "\n"
+ "guda\n"
+ "yay";
+ blogc_error_t *err = NULL;
+ sb_trie_t *source = blogc_source_parse(a, strlen(a), &err);
+ assert_null(err);
+ assert_non_null(source);
+ assert_int_equal(sb_trie_size(source), 6);
+ assert_string_equal(sb_trie_lookup(source, "VAR1"), "asd asd");
+ assert_string_equal(sb_trie_lookup(source, "VAR2"), "123chunda");
+ assert_string_equal(sb_trie_lookup(source, "EXCERPT"),
+ "<h1 id=\"this-is-a-test\">This is a test</h1>\n"
+ "<p>bola</p>\n");
+ assert_string_equal(sb_trie_lookup(source, "CONTENT"),
+ "<h1 id=\"this-is-a-test\">This is a test</h1>\n"
+ "<p>bola</p>\n"
+ "<p>guda\n"
+ "yay</p>\n");
+ assert_string_equal(sb_trie_lookup(source, "RAW_CONTENT"),
+ "# This is a test\n"
+ "\n"
+ "bola\n"
+ "\n"
+ "...\n"
+ "\n"
+ "guda\n"
+ "yay");
+ assert_string_equal(sb_trie_lookup(source, "DESCRIPTION"), "bola");
+ sb_trie_free(source);
+}
+
+
+static void
+test_source_parse_with_description(void **state)
+{
+ const char *a =
+ "VAR1: asd asd\n"
+ "VAR2: 123chunda\n"
+ "DESCRIPTION: huehuehuebrbr\n"
+ "----------\n"
+ "# This is a test\n"
+ "\n"
+ "bola\n";
+ blogc_error_t *err = NULL;
+ sb_trie_t *source = blogc_source_parse(a, strlen(a), &err);
+ assert_null(err);
+ assert_non_null(source);
+ assert_int_equal(sb_trie_size(source), 6);
+ assert_string_equal(sb_trie_lookup(source, "VAR1"), "asd asd");
+ assert_string_equal(sb_trie_lookup(source, "VAR2"), "123chunda");
+ assert_string_equal(sb_trie_lookup(source, "EXCERPT"),
+ "<h1 id=\"this-is-a-test\">This is a test</h1>\n"
+ "<p>bola</p>\n");
+ assert_string_equal(sb_trie_lookup(source, "CONTENT"),
+ "<h1 id=\"this-is-a-test\">This is a test</h1>\n"
+ "<p>bola</p>\n");
+ assert_string_equal(sb_trie_lookup(source, "RAW_CONTENT"),
+ "# This is a test\n"
+ "\n"
+ "bola\n");
+ assert_string_equal(sb_trie_lookup(source, "DESCRIPTION"), "huehuehuebrbr");
+ sb_trie_free(source);
+}
+
+
+static void
+test_source_parse_config_empty(void **state)
+{
+ const char *a = "";
+ blogc_error_t *err = NULL;
+ sb_trie_t *source = blogc_source_parse(a, strlen(a), &err);
+ assert_null(source);
+ assert_non_null(err);
+ assert_int_equal(err->type, BLOGC_ERROR_SOURCE_PARSER);
+ assert_string_equal(err->msg, "Your source file is empty.");
+ blogc_error_free(err);
+ sb_trie_free(source);
+}
+
+
+static void
+test_source_parse_config_invalid_key(void **state)
+{
+ const char *a = "bola: guda";
+ blogc_error_t *err = NULL;
+ sb_trie_t *source = blogc_source_parse(a, strlen(a), &err);
+ assert_non_null(err);
+ assert_int_equal(err->type, BLOGC_ERROR_SOURCE_PARSER);
+ assert_string_equal(err->msg,
+ "Can't find a configuration key or the content separator.\n"
+ "Error occurred near line 1, position 1: bola: guda");
+ blogc_error_free(err);
+ sb_trie_free(source);
+}
+
+
+static void
+test_source_parse_config_no_key(void **state)
+{
+ const char *a = "BOLa";
+ blogc_error_t *err = NULL;
+ sb_trie_t *source = blogc_source_parse(a, strlen(a), &err);
+ assert_non_null(err);
+ assert_int_equal(err->type, BLOGC_ERROR_SOURCE_PARSER);
+ assert_string_equal(err->msg,
+ "Invalid configuration key.\n"
+ "Error occurred near line 1, position 4: BOLa");
+ blogc_error_free(err);
+ sb_trie_free(source);
+}
+
+
+static void
+test_source_parse_config_no_key2(void **state)
+{
+ const char *a = "BOLA";
+ blogc_error_t *err = NULL;
+ sb_trie_t *source = blogc_source_parse(a, strlen(a), &err);
+ assert_non_null(err);
+ assert_int_equal(err->type, BLOGC_ERROR_SOURCE_PARSER);
+ assert_string_equal(err->msg,
+ "Your last configuration key is missing ':' and the value\n"
+ "Error occurred near line 1, position 5: BOLA");
+ blogc_error_free(err);
+ sb_trie_free(source);
+}
+
+
+static void
+test_source_parse_config_no_value(void **state)
+{
+ const char *a = "BOLA:\r\n";
+ blogc_error_t *err = NULL;
+ sb_trie_t *source = blogc_source_parse(a, strlen(a), &err);
+ assert_null(source);
+ assert_non_null(err);
+ assert_int_equal(err->type, BLOGC_ERROR_SOURCE_PARSER);
+ assert_string_equal(err->msg,
+ "Configuration value not provided for 'BOLA'.\n"
+ "Error occurred near line 1, position 6: BOLA:");
+ blogc_error_free(err);
+ sb_trie_free(source);
+}
+
+
+static void
+test_source_parse_config_no_value2(void **state)
+{
+ const char *a = "BOLA:";
+ blogc_error_t *err = NULL;
+ sb_trie_t *source = blogc_source_parse(a, strlen(a), &err);
+ assert_null(source);
+ assert_non_null(err);
+ assert_int_equal(err->type, BLOGC_ERROR_SOURCE_PARSER);
+ assert_string_equal(err->msg,
+ "Configuration value not provided for 'BOLA'.\n"
+ "Error occurred near line 1, position 6: BOLA:");
+ blogc_error_free(err);
+ sb_trie_free(source);
+}
+
+
+static void
+test_source_parse_config_reserved_name(void **state)
+{
+ const char *a = "FILENAME: asd\r\n";
+ blogc_error_t *err = NULL;
+ sb_trie_t *source = blogc_source_parse(a, strlen(a), &err);
+ assert_null(source);
+ assert_non_null(err);
+ assert_int_equal(err->type, BLOGC_ERROR_SOURCE_PARSER);
+ assert_string_equal(err->msg,
+ "'FILENAME' variable is forbidden in source files. It will be set "
+ "for you by the compiler.");
+ blogc_error_free(err);
+ sb_trie_free(source);
+}
+
+
+static void
+test_source_parse_config_reserved_name2(void **state)
+{
+ const char *a = "CONTENT: asd\r\n";
+ blogc_error_t *err = NULL;
+ sb_trie_t *source = blogc_source_parse(a, strlen(a), &err);
+ assert_null(source);
+ assert_non_null(err);
+ assert_int_equal(err->type, BLOGC_ERROR_SOURCE_PARSER);
+ assert_string_equal(err->msg,
+ "'CONTENT' variable is forbidden in source files. It will be set "
+ "for you by the compiler.");
+ blogc_error_free(err);
+ sb_trie_free(source);
+}
+
+
+static void
+test_source_parse_config_reserved_name3(void **state)
+{
+ const char *a = "DATE_FORMATTED: asd\r\n";
+ blogc_error_t *err = NULL;
+ sb_trie_t *source = blogc_source_parse(a, strlen(a), &err);
+ assert_null(source);
+ assert_non_null(err);
+ assert_int_equal(err->type, BLOGC_ERROR_SOURCE_PARSER);
+ assert_string_equal(err->msg,
+ "'DATE_FORMATTED' variable is forbidden in source files. It will be set "
+ "for you by the compiler.");
+ blogc_error_free(err);
+ sb_trie_free(source);
+}
+
+
+static void
+test_source_parse_config_reserved_name4(void **state)
+{
+ const char *a = "DATE_FIRST_FORMATTED: asd\r\n";
+ blogc_error_t *err = NULL;
+ sb_trie_t *source = blogc_source_parse(a, strlen(a), &err);
+ assert_null(source);
+ assert_non_null(err);
+ assert_int_equal(err->type, BLOGC_ERROR_SOURCE_PARSER);
+ assert_string_equal(err->msg,
+ "'DATE_FIRST_FORMATTED' variable is forbidden in source files. It will be set "
+ "for you by the compiler.");
+ blogc_error_free(err);
+ sb_trie_free(source);
+}
+
+
+static void
+test_source_parse_config_reserved_name5(void **state)
+{
+ const char *a = "DATE_LAST_FORMATTED: asd\r\n";
+ blogc_error_t *err = NULL;
+ sb_trie_t *source = blogc_source_parse(a, strlen(a), &err);
+ assert_null(source);
+ assert_non_null(err);
+ assert_int_equal(err->type, BLOGC_ERROR_SOURCE_PARSER);
+ assert_string_equal(err->msg,
+ "'DATE_LAST_FORMATTED' variable is forbidden in source files. It will be set "
+ "for you by the compiler.");
+ blogc_error_free(err);
+ sb_trie_free(source);
+}
+
+
+static void
+test_source_parse_config_reserved_name6(void **state)
+{
+ const char *a = "PAGE_FIRST: asd\r\n";
+ blogc_error_t *err = NULL;
+ sb_trie_t *source = blogc_source_parse(a, strlen(a), &err);
+ assert_null(source);
+ assert_non_null(err);
+ assert_int_equal(err->type, BLOGC_ERROR_SOURCE_PARSER);
+ assert_string_equal(err->msg,
+ "'PAGE_FIRST' variable is forbidden in source files. It will be set "
+ "for you by the compiler.");
+ blogc_error_free(err);
+ sb_trie_free(source);
+}
+
+
+static void
+test_source_parse_config_reserved_name7(void **state)
+{
+ const char *a = "PAGE_PREVIOUS: asd\r\n";
+ blogc_error_t *err = NULL;
+ sb_trie_t *source = blogc_source_parse(a, strlen(a), &err);
+ assert_null(source);
+ assert_non_null(err);
+ assert_int_equal(err->type, BLOGC_ERROR_SOURCE_PARSER);
+ assert_string_equal(err->msg,
+ "'PAGE_PREVIOUS' variable is forbidden in source files. It will be set "
+ "for you by the compiler.");
+ blogc_error_free(err);
+ sb_trie_free(source);
+}
+
+
+static void
+test_source_parse_config_reserved_name8(void **state)
+{
+ const char *a = "PAGE_CURRENT: asd\r\n";
+ blogc_error_t *err = NULL;
+ sb_trie_t *source = blogc_source_parse(a, strlen(a), &err);
+ assert_null(source);
+ assert_non_null(err);
+ assert_int_equal(err->type, BLOGC_ERROR_SOURCE_PARSER);
+ assert_string_equal(err->msg,
+ "'PAGE_CURRENT' variable is forbidden in source files. It will be set "
+ "for you by the compiler.");
+ blogc_error_free(err);
+ sb_trie_free(source);
+}
+
+
+static void
+test_source_parse_config_reserved_name9(void **state)
+{
+ const char *a = "PAGE_NEXT: asd\r\n";
+ blogc_error_t *err = NULL;
+ sb_trie_t *source = blogc_source_parse(a, strlen(a), &err);
+ assert_null(source);
+ assert_non_null(err);
+ assert_int_equal(err->type, BLOGC_ERROR_SOURCE_PARSER);
+ assert_string_equal(err->msg,
+ "'PAGE_NEXT' variable is forbidden in source files. It will be set "
+ "for you by the compiler.");
+ blogc_error_free(err);
+ sb_trie_free(source);
+}
+
+
+static void
+test_source_parse_config_reserved_name10(void **state)
+{
+ const char *a = "PAGE_LAST: asd\r\n";
+ blogc_error_t *err = NULL;
+ sb_trie_t *source = blogc_source_parse(a, strlen(a), &err);
+ assert_null(source);
+ assert_non_null(err);
+ assert_int_equal(err->type, BLOGC_ERROR_SOURCE_PARSER);
+ assert_string_equal(err->msg,
+ "'PAGE_LAST' variable is forbidden in source files. It will be set "
+ "for you by the compiler.");
+ blogc_error_free(err);
+ sb_trie_free(source);
+}
+
+
+static void
+test_source_parse_config_reserved_name11(void **state)
+{
+ const char *a = "BLOGC_VERSION: 1.0\r\n";
+ blogc_error_t *err = NULL;
+ sb_trie_t *source = blogc_source_parse(a, strlen(a), &err);
+ assert_null(source);
+ assert_non_null(err);
+ assert_int_equal(err->type, BLOGC_ERROR_SOURCE_PARSER);
+ assert_string_equal(err->msg,
+ "'BLOGC_VERSION' variable is forbidden in source files. It will be set "
+ "for you by the compiler.");
+ blogc_error_free(err);
+ sb_trie_free(source);
+}
+
+
+static void
+test_source_parse_config_value_no_line_ending(void **state)
+{
+ const char *a = "BOLA: asd";
+ blogc_error_t *err = NULL;
+ sb_trie_t *source = blogc_source_parse(a, strlen(a), &err);
+ assert_null(source);
+ assert_non_null(err);
+ assert_int_equal(err->type, BLOGC_ERROR_SOURCE_PARSER);
+ assert_string_equal(err->msg,
+ "No line ending after the configuration value for 'BOLA'.\n"
+ "Error occurred near line 1, position 10: BOLA: asd");
+ blogc_error_free(err);
+ sb_trie_free(source);
+}
+
+
+static void
+test_source_parse_invalid_separator(void **state)
+{
+ const char *a = "BOLA: asd\n---#";
+ blogc_error_t *err = NULL;
+ sb_trie_t *source = blogc_source_parse(a, strlen(a), &err);
+ assert_null(source);
+ assert_non_null(err);
+ assert_int_equal(err->type, BLOGC_ERROR_SOURCE_PARSER);
+ assert_string_equal(err->msg,
+ "Invalid content separator. Must be more than one '-' characters.\n"
+ "Error occurred near line 2, position 4: ---#");
+ blogc_error_free(err);
+ sb_trie_free(source);
+}
+
+
+int
+main(void)
+{
+ const UnitTest tests[] = {
+ unit_test(test_source_parse),
+ unit_test(test_source_parse_crlf),
+ unit_test(test_source_parse_with_spaces),
+ unit_test(test_source_parse_with_excerpt),
+ unit_test(test_source_parse_with_description),
+ unit_test(test_source_parse_config_empty),
+ unit_test(test_source_parse_config_invalid_key),
+ unit_test(test_source_parse_config_no_key),
+ unit_test(test_source_parse_config_no_key2),
+ unit_test(test_source_parse_config_no_value),
+ unit_test(test_source_parse_config_no_value2),
+ unit_test(test_source_parse_config_reserved_name),
+ unit_test(test_source_parse_config_reserved_name2),
+ unit_test(test_source_parse_config_reserved_name3),
+ unit_test(test_source_parse_config_reserved_name4),
+ unit_test(test_source_parse_config_reserved_name5),
+ unit_test(test_source_parse_config_reserved_name6),
+ unit_test(test_source_parse_config_reserved_name7),
+ unit_test(test_source_parse_config_reserved_name8),
+ unit_test(test_source_parse_config_reserved_name9),
+ unit_test(test_source_parse_config_reserved_name10),
+ unit_test(test_source_parse_config_reserved_name11),
+ unit_test(test_source_parse_config_value_no_line_ending),
+ unit_test(test_source_parse_invalid_separator),
+ };
+ return run_tests(tests);
+}
diff --git a/tests/blogc/check_template_parser.c b/tests/blogc/check_template_parser.c
new file mode 100644
index 0000000..3c88fe4
--- /dev/null
+++ b/tests/blogc/check_template_parser.c
@@ -0,0 +1,1184 @@
+/*
+ * blogc: A blog compiler.
+ * Copyright (C) 2015-2016 Rafael G. Martins <rafael@rafaelmartins.eng.br>
+ *
+ * This program can be distributed under the terms of the BSD License.
+ * See the file LICENSE.
+ */
+
+#include <stdarg.h>
+#include <stddef.h>
+#include <setjmp.h>
+#include <cmocka.h>
+#include <string.h>
+#include "../../src/blogc/template-parser.h"
+#include "../../src/blogc/error.h"
+#include "../../src/common/utils.h"
+
+
+static void
+blogc_assert_template_stmt(sb_slist_t *l, const char *value,
+ const blogc_template_stmt_type_t type)
+{
+ blogc_template_stmt_t *stmt = l->data;
+ if (value == NULL)
+ assert_null(stmt->value);
+ else
+ assert_string_equal(stmt->value, value);
+ assert_int_equal(stmt->type, type);
+}
+
+
+static void
+blogc_assert_template_if_stmt(sb_slist_t *l, const char *variable,
+ blogc_template_stmt_operator_t operator, const char *operand)
+{
+ blogc_template_stmt_t *stmt = l->data;
+ assert_string_equal(stmt->value, variable);
+ assert_int_equal(stmt->op, operator);
+ assert_string_equal(stmt->value2, operand);
+ assert_int_equal(stmt->type, BLOGC_TEMPLATE_IF_STMT);
+}
+
+
+static void
+test_template_parse(void **state)
+{
+ const char *a =
+ "Test\n"
+ "\n"
+ " {%- block entry -%}\n"
+ "{% ifdef CHUNDA %}\n"
+ "bola\n"
+ "{% endif %}\n"
+ "{% ifndef BOLA %}\n"
+ "bolao\n"
+ "{%- endif %}\n"
+ "{% endblock %}\n"
+ "{% block listing %}{{ BOLA }}{% endblock %}\n"
+ "{% block listing_once %}asd{% endblock %}\n"
+ "{%- foreach BOLA %}hahaha{% endforeach %}\n"
+ "{% if BOLA == \"1\\\"0\" %}aee{% else %}fffuuuuuuu{% endif %}";
+ blogc_error_t *err = NULL;
+ sb_slist_t *stmts = blogc_template_parse(a, strlen(a), &err);
+ assert_null(err);
+ assert_non_null(stmts);
+ blogc_assert_template_stmt(stmts, "Test",
+ BLOGC_TEMPLATE_CONTENT_STMT);
+ blogc_assert_template_stmt(stmts->next, "entry",
+ BLOGC_TEMPLATE_BLOCK_STMT);
+ blogc_assert_template_stmt(stmts->next->next, "",
+ BLOGC_TEMPLATE_CONTENT_STMT);
+ blogc_assert_template_stmt(stmts->next->next->next, "CHUNDA",
+ BLOGC_TEMPLATE_IFDEF_STMT);
+ blogc_assert_template_stmt(stmts->next->next->next->next, "\nbola\n",
+ BLOGC_TEMPLATE_CONTENT_STMT);
+ blogc_assert_template_stmt(stmts->next->next->next->next->next, NULL,
+ BLOGC_TEMPLATE_ENDIF_STMT);
+ blogc_assert_template_stmt(stmts->next->next->next->next->next->next, "\n",
+ BLOGC_TEMPLATE_CONTENT_STMT);
+ sb_slist_t *tmp = stmts->next->next->next->next->next->next->next;
+ blogc_assert_template_stmt(tmp, "BOLA", BLOGC_TEMPLATE_IFNDEF_STMT);
+ blogc_assert_template_stmt(tmp->next, "\nbolao", BLOGC_TEMPLATE_CONTENT_STMT);
+ blogc_assert_template_stmt(tmp->next->next, NULL, BLOGC_TEMPLATE_ENDIF_STMT);
+ blogc_assert_template_stmt(tmp->next->next->next, "\n",
+ BLOGC_TEMPLATE_CONTENT_STMT);
+ tmp = tmp->next->next->next->next;
+ blogc_assert_template_stmt(tmp, NULL, BLOGC_TEMPLATE_ENDBLOCK_STMT);
+ blogc_assert_template_stmt(tmp->next, "\n", BLOGC_TEMPLATE_CONTENT_STMT);
+ blogc_assert_template_stmt(tmp->next->next, "listing",
+ BLOGC_TEMPLATE_BLOCK_STMT);
+ blogc_assert_template_stmt(tmp->next->next->next, "BOLA",
+ BLOGC_TEMPLATE_VARIABLE_STMT);
+ blogc_assert_template_stmt(tmp->next->next->next->next,
+ NULL, BLOGC_TEMPLATE_ENDBLOCK_STMT);
+ blogc_assert_template_stmt(tmp->next->next->next->next->next, "\n",
+ BLOGC_TEMPLATE_CONTENT_STMT);
+ blogc_assert_template_stmt(tmp->next->next->next->next->next->next,
+ "listing_once", BLOGC_TEMPLATE_BLOCK_STMT);
+ blogc_assert_template_stmt(tmp->next->next->next->next->next->next->next,
+ "asd", BLOGC_TEMPLATE_CONTENT_STMT);
+ blogc_assert_template_stmt(tmp->next->next->next->next->next->next->next->next,
+ NULL, BLOGC_TEMPLATE_ENDBLOCK_STMT);
+ blogc_assert_template_stmt(tmp->next->next->next->next->next->next->next->next->next,
+ "", BLOGC_TEMPLATE_CONTENT_STMT);
+ tmp = tmp->next->next->next->next->next->next->next->next->next->next;
+ blogc_assert_template_stmt(tmp, "BOLA", BLOGC_TEMPLATE_FOREACH_STMT);
+ blogc_assert_template_stmt(tmp->next, "hahaha",
+ BLOGC_TEMPLATE_CONTENT_STMT);
+ blogc_assert_template_stmt(tmp->next->next, NULL,
+ BLOGC_TEMPLATE_ENDFOREACH_STMT);
+ blogc_assert_template_stmt(tmp->next->next->next, "\n",
+ BLOGC_TEMPLATE_CONTENT_STMT);
+ blogc_assert_template_if_stmt(tmp->next->next->next->next, "BOLA",
+ BLOGC_TEMPLATE_OP_EQ, "\"1\\\"0\"");
+ blogc_assert_template_stmt(tmp->next->next->next->next->next, "aee",
+ BLOGC_TEMPLATE_CONTENT_STMT);
+ blogc_assert_template_stmt(tmp->next->next->next->next->next->next, NULL,
+ BLOGC_TEMPLATE_ELSE_STMT);
+ blogc_assert_template_stmt(tmp->next->next->next->next->next->next->next,
+ "fffuuuuuuu", BLOGC_TEMPLATE_CONTENT_STMT);
+ blogc_assert_template_stmt(tmp->next->next->next->next->next->next->next->next,
+ NULL, BLOGC_TEMPLATE_ENDIF_STMT);
+ assert_null(tmp->next->next->next->next->next->next->next->next->next);
+ blogc_template_free_stmts(stmts);
+}
+
+
+static void
+test_template_parse_crlf(void **state)
+{
+ const char *a =
+ "Test\r\n"
+ "\r\n"
+ " {%- block entry -%}\r\n"
+ "{% ifdef CHUNDA %}\r\n"
+ "bola\r\n"
+ "{% endif %}\r\n"
+ "{% ifndef BOLA %}\r\n"
+ "bolao\r\n"
+ "{%- endif %}\r\n"
+ "{% endblock %}\r\n"
+ "{% block listing %}{{ BOLA }}{% endblock %}\r\n"
+ "{% block listing_once %}asd{% endblock %}\r\n"
+ "{%- foreach BOLA %}hahaha{% endforeach %}\r\n"
+ "{% if BOLA == \"1\\\"0\" %}aee{% else %}fffuuuuuuu{% endif %}";
+ blogc_error_t *err = NULL;
+ sb_slist_t *stmts = blogc_template_parse(a, strlen(a), &err);
+ assert_null(err);
+ assert_non_null(stmts);
+ blogc_assert_template_stmt(stmts, "Test",
+ BLOGC_TEMPLATE_CONTENT_STMT);
+ blogc_assert_template_stmt(stmts->next, "entry",
+ BLOGC_TEMPLATE_BLOCK_STMT);
+ blogc_assert_template_stmt(stmts->next->next, "",
+ BLOGC_TEMPLATE_CONTENT_STMT);
+ blogc_assert_template_stmt(stmts->next->next->next, "CHUNDA",
+ BLOGC_TEMPLATE_IFDEF_STMT);
+ blogc_assert_template_stmt(stmts->next->next->next->next, "\r\nbola\r\n",
+ BLOGC_TEMPLATE_CONTENT_STMT);
+ blogc_assert_template_stmt(stmts->next->next->next->next->next, NULL,
+ BLOGC_TEMPLATE_ENDIF_STMT);
+ blogc_assert_template_stmt(stmts->next->next->next->next->next->next, "\r\n",
+ BLOGC_TEMPLATE_CONTENT_STMT);
+ sb_slist_t *tmp = stmts->next->next->next->next->next->next->next;
+ blogc_assert_template_stmt(tmp, "BOLA", BLOGC_TEMPLATE_IFNDEF_STMT);
+ blogc_assert_template_stmt(tmp->next, "\r\nbolao", BLOGC_TEMPLATE_CONTENT_STMT);
+ blogc_assert_template_stmt(tmp->next->next, NULL, BLOGC_TEMPLATE_ENDIF_STMT);
+ blogc_assert_template_stmt(tmp->next->next->next, "\r\n",
+ BLOGC_TEMPLATE_CONTENT_STMT);
+ tmp = tmp->next->next->next->next;
+ blogc_assert_template_stmt(tmp, NULL, BLOGC_TEMPLATE_ENDBLOCK_STMT);
+ blogc_assert_template_stmt(tmp->next, "\r\n", BLOGC_TEMPLATE_CONTENT_STMT);
+ blogc_assert_template_stmt(tmp->next->next, "listing",
+ BLOGC_TEMPLATE_BLOCK_STMT);
+ blogc_assert_template_stmt(tmp->next->next->next, "BOLA",
+ BLOGC_TEMPLATE_VARIABLE_STMT);
+ blogc_assert_template_stmt(tmp->next->next->next->next,
+ NULL, BLOGC_TEMPLATE_ENDBLOCK_STMT);
+ blogc_assert_template_stmt(tmp->next->next->next->next->next, "\r\n",
+ BLOGC_TEMPLATE_CONTENT_STMT);
+ blogc_assert_template_stmt(tmp->next->next->next->next->next->next,
+ "listing_once", BLOGC_TEMPLATE_BLOCK_STMT);
+ blogc_assert_template_stmt(tmp->next->next->next->next->next->next->next,
+ "asd", BLOGC_TEMPLATE_CONTENT_STMT);
+ blogc_assert_template_stmt(tmp->next->next->next->next->next->next->next->next,
+ NULL, BLOGC_TEMPLATE_ENDBLOCK_STMT);
+ blogc_assert_template_stmt(tmp->next->next->next->next->next->next->next->next->next,
+ "", BLOGC_TEMPLATE_CONTENT_STMT);
+ tmp = tmp->next->next->next->next->next->next->next->next->next->next;
+ blogc_assert_template_stmt(tmp, "BOLA", BLOGC_TEMPLATE_FOREACH_STMT);
+ blogc_assert_template_stmt(tmp->next, "hahaha",
+ BLOGC_TEMPLATE_CONTENT_STMT);
+ blogc_assert_template_stmt(tmp->next->next, NULL,
+ BLOGC_TEMPLATE_ENDFOREACH_STMT);
+ blogc_assert_template_stmt(tmp->next->next->next, "\r\n",
+ BLOGC_TEMPLATE_CONTENT_STMT);
+ blogc_assert_template_if_stmt(tmp->next->next->next->next, "BOLA",
+ BLOGC_TEMPLATE_OP_EQ, "\"1\\\"0\"");
+ blogc_assert_template_stmt(tmp->next->next->next->next->next, "aee",
+ BLOGC_TEMPLATE_CONTENT_STMT);
+ blogc_assert_template_stmt(tmp->next->next->next->next->next->next, NULL,
+ BLOGC_TEMPLATE_ELSE_STMT);
+ blogc_assert_template_stmt(tmp->next->next->next->next->next->next->next,
+ "fffuuuuuuu", BLOGC_TEMPLATE_CONTENT_STMT);
+ blogc_assert_template_stmt(tmp->next->next->next->next->next->next->next->next,
+ NULL, BLOGC_TEMPLATE_ENDIF_STMT);
+ assert_null(tmp->next->next->next->next->next->next->next->next->next);
+ blogc_template_free_stmts(stmts);
+}
+
+
+static void
+test_template_parse_html(void **state)
+{
+ const char *a =
+ "<html>\n"
+ " <head>\n"
+ " {% block entry %}\n"
+ " <title>My cool blog >> {{ TITLE }}</title>\n"
+ " {% endblock %}\n"
+ " {% block listing_once %}\n"
+ " <title>My cool blog - Main page</title>\n"
+ " {% endblock %}\n"
+ " </head>\n"
+ " <body>\n"
+ " <h1>My cool blog</h1>\n"
+ " {% block entry %}\n"
+ " <h2>{{ TITLE }}</h2>\n"
+ " {% ifdef DATE %}<h4>Published in: {{ DATE }}</h4>{% endif %}\n"
+ " <pre>{{ CONTENT }}</pre>\n"
+ " {% endblock %}\n"
+ " {% block listing_once %}<ul>{% endblock %}\n"
+ " {% block listing %}<p><a href=\"{{ FILENAME }}.html\">"
+ "{{ TITLE }}</a>{% ifdef DATE %} - {{ DATE }}{% endif %}</p>{% endblock %}\n"
+ " {% block listing_once %}</ul>{% endblock %}\n"
+ " </body>\n"
+ "</html>\n";
+ blogc_error_t *err = NULL;
+ sb_slist_t *stmts = blogc_template_parse(a, strlen(a), &err);
+ assert_null(err);
+ assert_non_null(stmts);
+ blogc_assert_template_stmt(stmts, "<html>\n <head>\n ",
+ BLOGC_TEMPLATE_CONTENT_STMT);
+ blogc_assert_template_stmt(stmts->next, "entry",
+ BLOGC_TEMPLATE_BLOCK_STMT);
+ blogc_assert_template_stmt(stmts->next->next,
+ "\n <title>My cool blog >> ", BLOGC_TEMPLATE_CONTENT_STMT);
+ blogc_assert_template_stmt(stmts->next->next->next, "TITLE",
+ BLOGC_TEMPLATE_VARIABLE_STMT);
+ blogc_assert_template_stmt(stmts->next->next->next->next,
+ "</title>\n ", BLOGC_TEMPLATE_CONTENT_STMT);
+ blogc_assert_template_stmt(stmts->next->next->next->next->next, NULL,
+ BLOGC_TEMPLATE_ENDBLOCK_STMT);
+ blogc_assert_template_stmt(stmts->next->next->next->next->next->next,
+ "\n ", BLOGC_TEMPLATE_CONTENT_STMT);
+ blogc_assert_template_stmt(stmts->next->next->next->next->next->next->next,
+ "listing_once", BLOGC_TEMPLATE_BLOCK_STMT);
+ sb_slist_t *tmp = stmts->next->next->next->next->next->next->next->next;
+ blogc_assert_template_stmt(tmp,
+ "\n <title>My cool blog - Main page</title>\n ",
+ BLOGC_TEMPLATE_CONTENT_STMT);
+ blogc_assert_template_stmt(tmp->next, NULL, BLOGC_TEMPLATE_ENDBLOCK_STMT);
+ blogc_assert_template_stmt(tmp->next->next,
+ "\n </head>\n <body>\n <h1>My cool blog</h1>\n ",
+ BLOGC_TEMPLATE_CONTENT_STMT);
+ blogc_assert_template_stmt(tmp->next->next->next, "entry",
+ BLOGC_TEMPLATE_BLOCK_STMT);
+ blogc_assert_template_stmt(tmp->next->next->next->next,
+ "\n <h2>", BLOGC_TEMPLATE_CONTENT_STMT);
+ blogc_assert_template_stmt(tmp->next->next->next->next->next,
+ "TITLE", BLOGC_TEMPLATE_VARIABLE_STMT);
+ blogc_assert_template_stmt(tmp->next->next->next->next->next->next,
+ "</h2>\n ", BLOGC_TEMPLATE_CONTENT_STMT);
+ blogc_assert_template_stmt(tmp->next->next->next->next->next->next->next,
+ "DATE", BLOGC_TEMPLATE_IFDEF_STMT);
+ tmp = tmp->next->next->next->next->next->next->next->next;
+ blogc_assert_template_stmt(tmp, "<h4>Published in: ",
+ BLOGC_TEMPLATE_CONTENT_STMT);
+ blogc_assert_template_stmt(tmp->next, "DATE", BLOGC_TEMPLATE_VARIABLE_STMT);
+ blogc_assert_template_stmt(tmp->next->next, "</h4>",
+ BLOGC_TEMPLATE_CONTENT_STMT);
+ blogc_assert_template_stmt(tmp->next->next->next, NULL,
+ BLOGC_TEMPLATE_ENDIF_STMT);
+ blogc_assert_template_stmt(tmp->next->next->next->next, "\n <pre>",
+ BLOGC_TEMPLATE_CONTENT_STMT);
+ blogc_assert_template_stmt(tmp->next->next->next->next->next,
+ "CONTENT", BLOGC_TEMPLATE_VARIABLE_STMT);
+ blogc_assert_template_stmt(tmp->next->next->next->next->next->next,
+ "</pre>\n ", BLOGC_TEMPLATE_CONTENT_STMT);
+ blogc_assert_template_stmt(tmp->next->next->next->next->next->next->next,
+ NULL, BLOGC_TEMPLATE_ENDBLOCK_STMT);
+ tmp = tmp->next->next->next->next->next->next->next->next;
+ blogc_assert_template_stmt(tmp, "\n ", BLOGC_TEMPLATE_CONTENT_STMT);
+ blogc_assert_template_stmt(tmp->next, "listing_once",
+ BLOGC_TEMPLATE_BLOCK_STMT);
+ blogc_assert_template_stmt(tmp->next->next, "<ul>",
+ BLOGC_TEMPLATE_CONTENT_STMT);
+ blogc_assert_template_stmt(tmp->next->next->next, NULL,
+ BLOGC_TEMPLATE_ENDBLOCK_STMT);
+ blogc_assert_template_stmt(tmp->next->next->next->next, "\n ",
+ BLOGC_TEMPLATE_CONTENT_STMT);
+ blogc_assert_template_stmt(tmp->next->next->next->next->next,
+ "listing", BLOGC_TEMPLATE_BLOCK_STMT);
+ blogc_assert_template_stmt(tmp->next->next->next->next->next->next,
+ "<p><a href=\"", BLOGC_TEMPLATE_CONTENT_STMT);
+ blogc_assert_template_stmt(tmp->next->next->next->next->next->next->next,
+ "FILENAME", BLOGC_TEMPLATE_VARIABLE_STMT);
+ tmp = tmp->next->next->next->next->next->next->next->next;
+ blogc_assert_template_stmt(tmp, ".html\">", BLOGC_TEMPLATE_CONTENT_STMT);
+ blogc_assert_template_stmt(tmp->next, "TITLE",
+ BLOGC_TEMPLATE_VARIABLE_STMT);
+ blogc_assert_template_stmt(tmp->next->next, "</a>",
+ BLOGC_TEMPLATE_CONTENT_STMT);
+ blogc_assert_template_stmt(tmp->next->next->next, "DATE",
+ BLOGC_TEMPLATE_IFDEF_STMT);
+ blogc_assert_template_stmt(tmp->next->next->next->next, " - ",
+ BLOGC_TEMPLATE_CONTENT_STMT);
+ blogc_assert_template_stmt(tmp->next->next->next->next->next, "DATE",
+ BLOGC_TEMPLATE_VARIABLE_STMT);
+ blogc_assert_template_stmt(tmp->next->next->next->next->next->next,
+ NULL, BLOGC_TEMPLATE_ENDIF_STMT);
+ blogc_assert_template_stmt(tmp->next->next->next->next->next->next->next,
+ "</p>", BLOGC_TEMPLATE_CONTENT_STMT);
+ tmp = tmp->next->next->next->next->next->next->next->next;
+ blogc_assert_template_stmt(tmp, NULL, BLOGC_TEMPLATE_ENDBLOCK_STMT);
+ blogc_assert_template_stmt(tmp->next, "\n ",
+ BLOGC_TEMPLATE_CONTENT_STMT);
+ blogc_assert_template_stmt(tmp->next->next, "listing_once",
+ BLOGC_TEMPLATE_BLOCK_STMT);
+ blogc_assert_template_stmt(tmp->next->next->next, "</ul>",
+ BLOGC_TEMPLATE_CONTENT_STMT);
+ blogc_assert_template_stmt(tmp->next->next->next->next, NULL,
+ BLOGC_TEMPLATE_ENDBLOCK_STMT);
+ blogc_assert_template_stmt(tmp->next->next->next->next->next,
+ "\n </body>\n</html>\n", BLOGC_TEMPLATE_CONTENT_STMT);
+ assert_null(tmp->next->next->next->next->next->next);
+ blogc_template_free_stmts(stmts);
+}
+
+
+static void
+test_template_parse_ifdef_and_var_outside_block(void **state)
+{
+ const char *a =
+ "{% ifdef GUDA %}bola{% endif %}\n"
+ "{{ BOLA }}\n"
+ "{% ifndef CHUNDA %}{{ CHUNDA }}{% endif %}\n";
+ blogc_error_t *err = NULL;
+ sb_slist_t *stmts = blogc_template_parse(a, strlen(a), &err);
+ assert_null(err);
+ assert_non_null(stmts);
+ blogc_assert_template_stmt(stmts, "GUDA", BLOGC_TEMPLATE_IFDEF_STMT);
+ blogc_assert_template_stmt(stmts->next, "bola",
+ BLOGC_TEMPLATE_CONTENT_STMT);
+ blogc_assert_template_stmt(stmts->next->next, NULL,
+ BLOGC_TEMPLATE_ENDIF_STMT);
+ blogc_assert_template_stmt(stmts->next->next->next, "\n",
+ BLOGC_TEMPLATE_CONTENT_STMT);
+ blogc_assert_template_stmt(stmts->next->next->next->next, "BOLA",
+ BLOGC_TEMPLATE_VARIABLE_STMT);
+ blogc_assert_template_stmt(stmts->next->next->next->next->next, "\n",
+ BLOGC_TEMPLATE_CONTENT_STMT);
+ blogc_assert_template_stmt(stmts->next->next->next->next->next->next,
+ "CHUNDA", BLOGC_TEMPLATE_IFNDEF_STMT);
+ sb_slist_t *tmp = stmts->next->next->next->next->next->next->next;
+ blogc_assert_template_stmt(tmp, "CHUNDA", BLOGC_TEMPLATE_VARIABLE_STMT);
+ blogc_assert_template_stmt(tmp->next, NULL, BLOGC_TEMPLATE_ENDIF_STMT);
+ blogc_assert_template_stmt(tmp->next->next, "\n",
+ BLOGC_TEMPLATE_CONTENT_STMT);
+ assert_null(tmp->next->next->next);
+ blogc_template_free_stmts(stmts);
+}
+
+
+static void
+test_template_parse_nested_else(void **state)
+{
+ const char *a =
+ "{% ifdef GUDA %}\n"
+ "{% ifdef BOLA %}\n"
+ "asd\n"
+ "{% else %}\n"
+ "{% ifdef CHUNDA %}\n"
+ "qwe\n"
+ "{% else %}\n"
+ "rty\n"
+ "{% endif %}\n"
+ "{% endif %}\n"
+ "{% ifdef LOL %}\n"
+ "zxc\n"
+ "{% else %}\n"
+ "bnm\n"
+ "{% endif %}\n"
+ "{% endif %}\n";
+ blogc_error_t *err = NULL;
+ sb_slist_t *stmts = blogc_template_parse(a, strlen(a), &err);
+ assert_null(err);
+ assert_non_null(stmts);
+ blogc_assert_template_stmt(stmts, "GUDA", BLOGC_TEMPLATE_IFDEF_STMT);
+ blogc_assert_template_stmt(stmts->next, "\n", BLOGC_TEMPLATE_CONTENT_STMT);
+ blogc_assert_template_stmt(stmts->next->next, "BOLA", BLOGC_TEMPLATE_IFDEF_STMT);
+ blogc_assert_template_stmt(stmts->next->next->next, "\nasd\n",
+ BLOGC_TEMPLATE_CONTENT_STMT);
+ blogc_assert_template_stmt(stmts->next->next->next->next, NULL,
+ BLOGC_TEMPLATE_ELSE_STMT);
+ blogc_assert_template_stmt(stmts->next->next->next->next->next, "\n",
+ BLOGC_TEMPLATE_CONTENT_STMT);
+ blogc_assert_template_stmt(stmts->next->next->next->next->next->next,
+ "CHUNDA", BLOGC_TEMPLATE_IFDEF_STMT);
+ blogc_assert_template_stmt(stmts->next->next->next->next->next->next->next,
+ "\nqwe\n", BLOGC_TEMPLATE_CONTENT_STMT);
+ sb_slist_t *tmp = stmts->next->next->next->next->next->next->next->next;
+ blogc_assert_template_stmt(tmp, NULL, BLOGC_TEMPLATE_ELSE_STMT);
+ blogc_assert_template_stmt(tmp->next, "\nrty\n", BLOGC_TEMPLATE_CONTENT_STMT);
+ blogc_assert_template_stmt(tmp->next->next, NULL,
+ BLOGC_TEMPLATE_ENDIF_STMT);
+ blogc_assert_template_stmt(tmp->next->next->next, "\n",
+ BLOGC_TEMPLATE_CONTENT_STMT);
+ blogc_assert_template_stmt(tmp->next->next->next->next, NULL,
+ BLOGC_TEMPLATE_ENDIF_STMT);
+ blogc_assert_template_stmt(tmp->next->next->next->next->next, "\n",
+ BLOGC_TEMPLATE_CONTENT_STMT);
+ blogc_assert_template_stmt(tmp->next->next->next->next->next->next,
+ "LOL", BLOGC_TEMPLATE_IFDEF_STMT);
+ blogc_assert_template_stmt(tmp->next->next->next->next->next->next->next,
+ "\nzxc\n", BLOGC_TEMPLATE_CONTENT_STMT);
+ tmp = tmp->next->next->next->next->next->next->next->next;
+ blogc_assert_template_stmt(tmp, NULL, BLOGC_TEMPLATE_ELSE_STMT);
+ blogc_assert_template_stmt(tmp->next, "\nbnm\n", BLOGC_TEMPLATE_CONTENT_STMT);
+ blogc_assert_template_stmt(tmp->next->next, NULL,
+ BLOGC_TEMPLATE_ENDIF_STMT);
+ blogc_assert_template_stmt(tmp->next->next->next, "\n",
+ BLOGC_TEMPLATE_CONTENT_STMT);
+ blogc_assert_template_stmt(tmp->next->next->next->next, NULL,
+ BLOGC_TEMPLATE_ENDIF_STMT);
+ blogc_assert_template_stmt(tmp->next->next->next->next->next, "\n",
+ BLOGC_TEMPLATE_CONTENT_STMT);
+ assert_null(tmp->next->next->next->next->next->next);
+ blogc_template_free_stmts(stmts);
+}
+
+
+static void
+test_template_parse_invalid_block_start(void **state)
+{
+ const char *a = "{% ASD %}\n";
+ blogc_error_t *err = NULL;
+ sb_slist_t *stmts = blogc_template_parse(a, strlen(a), &err);
+ assert_non_null(err);
+ assert_null(stmts);
+ assert_int_equal(err->type, BLOGC_ERROR_TEMPLATE_PARSER);
+ assert_string_equal(err->msg,
+ "Invalid statement syntax. Must begin with lowercase letter.\n"
+ "Error occurred near line 1, position 4: {% ASD %}");
+ blogc_error_free(err);
+ a = "{%-- block entry %}\n";
+ err = NULL;
+ stmts = blogc_template_parse(a, strlen(a), &err);
+ assert_non_null(err);
+ assert_null(stmts);
+ assert_int_equal(err->type, BLOGC_ERROR_TEMPLATE_PARSER);
+ assert_string_equal(err->msg,
+ "Invalid statement syntax. Duplicated whitespace cleaner before statement.\n"
+ "Error occurred near line 1, position 4: {%-- block entry %}");
+ blogc_error_free(err);
+ a = "{% block entry --%}\n";
+ err = NULL;
+ stmts = blogc_template_parse(a, strlen(a), &err);
+ assert_non_null(err);
+ assert_null(stmts);
+ assert_int_equal(err->type, BLOGC_ERROR_TEMPLATE_PARSER);
+ assert_string_equal(err->msg,
+ "Invalid statement syntax. Duplicated whitespace cleaner after statement.\n"
+ "Error occurred near line 1, position 17: {% block entry --%}");
+ blogc_error_free(err);
+}
+
+
+static void
+test_template_parse_invalid_block_nested(void **state)
+{
+ const char *a =
+ "{% block entry %}\n"
+ "{% block listing %}\n";
+ blogc_error_t *err = NULL;
+ sb_slist_t *stmts = blogc_template_parse(a, strlen(a), &err);
+ assert_non_null(err);
+ assert_null(stmts);
+ assert_int_equal(err->type, BLOGC_ERROR_TEMPLATE_PARSER);
+ assert_string_equal(err->msg,
+ "Blocks can't be nested.\n"
+ "Error occurred near line 2, position 9: {% block listing %}");
+ blogc_error_free(err);
+}
+
+
+static void
+test_template_parse_invalid_foreach_nested(void **state)
+{
+ const char *a =
+ "{% foreach A %}\n"
+ "{% foreach B %}\n";
+ blogc_error_t *err = NULL;
+ sb_slist_t *stmts = blogc_template_parse(a, strlen(a), &err);
+ assert_non_null(err);
+ assert_null(stmts);
+ assert_int_equal(err->type, BLOGC_ERROR_TEMPLATE_PARSER);
+ assert_string_equal(err->msg,
+ "'foreach' statements can't be nested.\n"
+ "Error occurred near line 2, position 11: {% foreach B %}");
+ blogc_error_free(err);
+}
+
+
+static void
+test_template_parse_invalid_block_not_open(void **state)
+{
+ const char *a = "{% endblock %}\n";
+ blogc_error_t *err = NULL;
+ sb_slist_t *stmts = blogc_template_parse(a, strlen(a), &err);
+ assert_non_null(err);
+ assert_null(stmts);
+ assert_int_equal(err->type, BLOGC_ERROR_TEMPLATE_PARSER);
+ assert_string_equal(err->msg,
+ "'endblock' statement without an open 'block' statement.\n"
+ "Error occurred near line 1, position 12: {% endblock %}");
+ blogc_error_free(err);
+}
+
+
+static void
+test_template_parse_invalid_endif_not_open(void **state)
+{
+ const char *a = "{% block listing %}{% endif %}{% endblock %}\n";
+ blogc_error_t *err = NULL;
+ sb_slist_t *stmts = blogc_template_parse(a, strlen(a), &err);
+ assert_non_null(err);
+ assert_null(stmts);
+ assert_int_equal(err->type, BLOGC_ERROR_TEMPLATE_PARSER);
+ assert_string_equal(err->msg,
+ "'endif' statement without an open 'if', 'ifdef' or 'ifndef' statement.\n"
+ "Error occurred near line 1, position 28: "
+ "{% block listing %}{% endif %}{% endblock %}");
+ blogc_error_free(err);
+}
+
+
+static void
+test_template_parse_invalid_endif_not_open_inside_block(void **state)
+{
+ const char *a = "{% ifdef BOLA %}{% block listing %}{% endif %}{% endblock %}";
+ blogc_error_t *err = NULL;
+ sb_slist_t *stmts = blogc_template_parse(a, strlen(a), &err);
+ assert_non_null(err);
+ assert_null(stmts);
+ assert_int_equal(err->type, BLOGC_ERROR_TEMPLATE_PARSER);
+ assert_string_equal(err->msg,
+ "'endif' statement without an open 'if', 'ifdef' or 'ifndef' statement.\n"
+ "Error occurred near line 1, position 44: {% ifdef BOLA %}{% block "
+ "listing %}{% endif %}{% endblock %}");
+ blogc_error_free(err);
+}
+
+
+static void
+test_template_parse_invalid_else_not_open_inside_block(void **state)
+{
+ const char *a = "{% ifdef BOLA %}{% block listing %}{% else %}{% endif %}{% endblock %}";
+ blogc_error_t *err = NULL;
+ sb_slist_t *stmts = blogc_template_parse(a, strlen(a), &err);
+ assert_non_null(err);
+ assert_null(stmts);
+ assert_int_equal(err->type, BLOGC_ERROR_TEMPLATE_PARSER);
+ assert_string_equal(err->msg,
+ "'else' statement without an open 'if', 'ifdef' or 'ifndef' statement.\n"
+ "Error occurred near line 1, position 43: {% ifdef BOLA %}"
+ "{% block listing %}{% else %}{% endif %}{% endblock %}");
+ blogc_error_free(err);
+}
+
+
+static void
+test_template_parse_invalid_endforeach_not_open(void **state)
+{
+ const char *a = "{% endforeach %}\n";
+ blogc_error_t *err = NULL;
+ sb_slist_t *stmts = blogc_template_parse(a, strlen(a), &err);
+ assert_non_null(err);
+ assert_null(stmts);
+ assert_int_equal(err->type, BLOGC_ERROR_TEMPLATE_PARSER);
+ assert_string_equal(err->msg,
+ "'endforeach' statement without an open 'foreach' statement.\n"
+ "Error occurred near line 1, position 14: {% endforeach %}");
+ blogc_error_free(err);
+}
+
+
+static void
+test_template_parse_invalid_endforeach_not_open_inside_block(void **state)
+{
+ const char *a = "{% foreach TAGS %}{% block entry %}{% endforeach %}"
+ "{% endblock %}\n";
+ blogc_error_t *err = NULL;
+ sb_slist_t *stmts = blogc_template_parse(a, strlen(a), &err);
+ assert_non_null(err);
+ assert_null(stmts);
+ assert_int_equal(err->type, BLOGC_ERROR_TEMPLATE_PARSER);
+ assert_string_equal(err->msg,
+ "'endforeach' statement without an open 'foreach' statement.\n"
+ "Error occurred near line 1, position 49: {% foreach TAGS %}"
+ "{% block entry %}{% endforeach %}{% endblock %}");
+ blogc_error_free(err);
+}
+
+
+static void
+test_template_parse_invalid_endforeach_not_open_inside_block2(void **state)
+{
+ const char *a = "{% block entry %}{% foreach TAGS %}"
+ "{% endforeach %}{% endforeach %}{% endblock %}\n";
+ blogc_error_t *err = NULL;
+ sb_slist_t *stmts = blogc_template_parse(a, strlen(a), &err);
+ assert_non_null(err);
+ assert_null(stmts);
+ assert_int_equal(err->type, BLOGC_ERROR_TEMPLATE_PARSER);
+ assert_string_equal(err->msg,
+ "'endforeach' statement without an open 'foreach' statement.\n"
+ "Error occurred near line 1, position 65: {% block entry %}"
+ "{% foreach TAGS %}{% endforeach %}{% endforeach %}{% endblock %}");
+ blogc_error_free(err);
+}
+
+
+static void
+test_template_parse_invalid_endforeach_not_closed_inside_block(void **state)
+{
+ const char *a = "{% block entry %}{% foreach TAGS %}{% endblock %}"
+ "{% endforeach %}\n";
+ blogc_error_t *err = NULL;
+ sb_slist_t *stmts = blogc_template_parse(a, strlen(a), &err);
+ assert_non_null(err);
+ assert_null(stmts);
+ assert_int_equal(err->type, BLOGC_ERROR_TEMPLATE_PARSER);
+ assert_string_equal(err->msg,
+ "An open 'foreach' statement was not closed inside a 'entry' block!");
+ blogc_error_free(err);
+}
+
+
+static void
+test_template_parse_invalid_endforeach_not_closed_inside_block2(void **state)
+{
+ const char *a = "{% block entry %}{% foreach TAGS %}{% endforeach %}"
+ "{% foreach TAGS %}{% endblock %}{% endforeach %}\n";
+ blogc_error_t *err = NULL;
+ sb_slist_t *stmts = blogc_template_parse(a, strlen(a), &err);
+ assert_non_null(err);
+ assert_null(stmts);
+ assert_int_equal(err->type, BLOGC_ERROR_TEMPLATE_PARSER);
+ assert_string_equal(err->msg,
+ "An open 'foreach' statement was not closed inside a 'entry' block!");
+ blogc_error_free(err);
+}
+
+
+static void
+test_template_parse_invalid_block_name(void **state)
+{
+ const char *a = "{% chunda %}\n";
+ blogc_error_t *err = NULL;
+ sb_slist_t *stmts = blogc_template_parse(a, strlen(a), &err);
+ assert_non_null(err);
+ assert_null(stmts);
+ assert_int_equal(err->type, BLOGC_ERROR_TEMPLATE_PARSER);
+ assert_string_equal(err->msg,
+ "Invalid statement type: Allowed types are: 'block', 'endblock', 'if', "
+ "'ifdef', 'ifndef', 'else', 'endif', 'foreach' and 'endforeach'.\n"
+ "Error occurred near line 1, position 10: {% chunda %}");
+ blogc_error_free(err);
+}
+
+
+static void
+test_template_parse_invalid_block_type_start(void **state)
+{
+ const char *a = "{% block ENTRY %}\n";
+ blogc_error_t *err = NULL;
+ sb_slist_t *stmts = blogc_template_parse(a, strlen(a), &err);
+ assert_non_null(err);
+ assert_null(stmts);
+ assert_int_equal(err->type, BLOGC_ERROR_TEMPLATE_PARSER);
+ assert_string_equal(err->msg,
+ "Invalid block syntax. Must begin with lowercase letter.\n"
+ "Error occurred near line 1, position 10: {% block ENTRY %}");
+ blogc_error_free(err);
+}
+
+
+static void
+test_template_parse_invalid_block_type(void **state)
+{
+ const char *a = "{% block chunda %}\n";
+ blogc_error_t *err = NULL;
+ sb_slist_t *stmts = blogc_template_parse(a, strlen(a), &err);
+ assert_non_null(err);
+ assert_null(stmts);
+ assert_int_equal(err->type, BLOGC_ERROR_TEMPLATE_PARSER);
+ assert_string_equal(err->msg,
+ "Invalid block type. Allowed types are: 'entry', 'listing' and 'listing_once'.\n"
+ "Error occurred near line 1, position 16: {% block chunda %}");
+ blogc_error_free(err);
+}
+
+
+static void
+test_template_parse_invalid_ifdef_start(void **state)
+{
+ const char *a = "{% block entry %}{% ifdef guda %}\n";
+ blogc_error_t *err = NULL;
+ sb_slist_t *stmts = blogc_template_parse(a, strlen(a), &err);
+ assert_non_null(err);
+ assert_null(stmts);
+ assert_int_equal(err->type, BLOGC_ERROR_TEMPLATE_PARSER);
+ assert_string_equal(err->msg,
+ "Invalid variable name. Must begin with uppercase letter.\n"
+ "Error occurred near line 1, position 27: "
+ "{% block entry %}{% ifdef guda %}");
+ blogc_error_free(err);
+}
+
+
+static void
+test_template_parse_invalid_foreach_start(void **state)
+{
+ const char *a = "{% block entry %}{% foreach guda %}\n";
+ blogc_error_t *err = NULL;
+ sb_slist_t *stmts = blogc_template_parse(a, strlen(a), &err);
+ assert_non_null(err);
+ assert_null(stmts);
+ assert_int_equal(err->type, BLOGC_ERROR_TEMPLATE_PARSER);
+ assert_string_equal(err->msg,
+ "Invalid foreach variable name. Must begin with uppercase letter.\n"
+ "Error occurred near line 1, position 29: "
+ "{% block entry %}{% foreach guda %}");
+ blogc_error_free(err);
+}
+
+
+static void
+test_template_parse_invalid_ifdef_variable(void **state)
+{
+ const char *a = "{% block entry %}{% ifdef BoLA %}\n";
+ blogc_error_t *err = NULL;
+ sb_slist_t *stmts = blogc_template_parse(a, strlen(a), &err);
+ assert_non_null(err);
+ assert_null(stmts);
+ assert_int_equal(err->type, BLOGC_ERROR_TEMPLATE_PARSER);
+ assert_string_equal(err->msg,
+ "Invalid variable name. Must be uppercase letter, number or '_'.\n"
+ "Error occurred near line 1, position 28: "
+ "{% block entry %}{% ifdef BoLA %}");
+ blogc_error_free(err);
+}
+
+
+static void
+test_template_parse_invalid_ifdef_variable2(void **state)
+{
+ const char *a = "{% block entry %}{% ifdef 0123 %}\n";
+ blogc_error_t *err = NULL;
+ sb_slist_t *stmts = blogc_template_parse(a, strlen(a), &err);
+ assert_non_null(err);
+ assert_null(stmts);
+ assert_int_equal(err->type, BLOGC_ERROR_TEMPLATE_PARSER);
+ assert_string_equal(err->msg,
+ "Invalid variable name. Must begin with uppercase letter.\n"
+ "Error occurred near line 1, position 27: "
+ "{% block entry %}{% ifdef 0123 %}");
+ blogc_error_free(err);
+}
+
+
+static void
+test_template_parse_invalid_foreach_variable(void **state)
+{
+ const char *a = "{% block entry %}{% foreach BoLA %}\n";
+ blogc_error_t *err = NULL;
+ sb_slist_t *stmts = blogc_template_parse(a, strlen(a), &err);
+ assert_non_null(err);
+ assert_null(stmts);
+ assert_int_equal(err->type, BLOGC_ERROR_TEMPLATE_PARSER);
+ assert_string_equal(err->msg,
+ "Invalid foreach variable name. Must be uppercase letter, number or '_'.\n"
+ "Error occurred near line 1, position 30: "
+ "{% block entry %}{% foreach BoLA %}");
+ blogc_error_free(err);
+}
+
+
+static void
+test_template_parse_invalid_foreach_variable2(void **state)
+{
+ const char *a = "{% block entry %}{% foreach 0123 %}\n";
+ blogc_error_t *err = NULL;
+ sb_slist_t *stmts = blogc_template_parse(a, strlen(a), &err);
+ assert_non_null(err);
+ assert_null(stmts);
+ assert_int_equal(err->type, BLOGC_ERROR_TEMPLATE_PARSER);
+ assert_string_equal(err->msg,
+ "Invalid foreach variable name. Must begin with uppercase letter.\n"
+ "Error occurred near line 1, position 29: {% block entry %}"
+ "{% foreach 0123 %}");
+ blogc_error_free(err);
+}
+
+
+static void
+test_template_parse_invalid_if_operator(void **state)
+{
+ const char *a = "{% block entry %}{% if BOLA = \"asd\" %}\n";
+ blogc_error_t *err = NULL;
+ sb_slist_t *stmts = blogc_template_parse(a, strlen(a), &err);
+ assert_non_null(err);
+ assert_null(stmts);
+ assert_int_equal(err->type, BLOGC_ERROR_TEMPLATE_PARSER);
+ assert_string_equal(err->msg,
+ "Invalid 'if' operator. Must be '<', '>', '<=', '>=', '==' or '!='.\n"
+ "Error occurred near line 1, position 29: "
+ "{% block entry %}{% if BOLA = \"asd\" %}");
+ blogc_error_free(err);
+}
+
+
+static void
+test_template_parse_invalid_if_operand(void **state)
+{
+ const char *a = "{% block entry %}{% if BOLA == asd %}\n";
+ blogc_error_t *err = NULL;
+ sb_slist_t *stmts = blogc_template_parse(a, strlen(a), &err);
+ assert_non_null(err);
+ assert_null(stmts);
+ assert_int_equal(err->type, BLOGC_ERROR_TEMPLATE_PARSER);
+ assert_string_equal(err->msg,
+ "Invalid 'if' operand. Must be double-quoted static string or variable.\n"
+ "Error occurred near line 1, position 32: "
+ "{% block entry %}{% if BOLA == asd %}");
+ blogc_error_free(err);
+}
+
+
+static void
+test_template_parse_invalid_if_operand2(void **state)
+{
+ const char *a = "{% block entry %}{% if BOLA == \"asd %}\n";
+ blogc_error_t *err = NULL;
+ sb_slist_t *stmts = blogc_template_parse(a, strlen(a), &err);
+ assert_non_null(err);
+ assert_null(stmts);
+ assert_int_equal(err->type, BLOGC_ERROR_TEMPLATE_PARSER);
+ assert_string_equal(err->msg,
+ "Found an open double-quoted string.\n"
+ "Error occurred near line 1, position 32: "
+ "{% block entry %}{% if BOLA == \"asd %}");
+ blogc_error_free(err);
+}
+
+
+static void
+test_template_parse_invalid_if_operand3(void **state)
+{
+ const char *a = "{% block entry %}{% if BOLA == 0123 %}\n";
+ blogc_error_t *err = NULL;
+ sb_slist_t *stmts = blogc_template_parse(a, strlen(a), &err);
+ assert_non_null(err);
+ assert_null(stmts);
+ assert_int_equal(err->type, BLOGC_ERROR_TEMPLATE_PARSER);
+ assert_string_equal(err->msg,
+ "Invalid 'if' operand. Must be double-quoted static string or variable.\n"
+ "Error occurred near line 1, position 32: "
+ "{% block entry %}{% if BOLA == 0123 %}");
+ blogc_error_free(err);
+}
+
+
+static void
+test_template_parse_invalid_else1(void **state)
+{
+ const char *a = "{% else %}\n";
+ blogc_error_t *err = NULL;
+ sb_slist_t *stmts = blogc_template_parse(a, strlen(a), &err);
+ assert_non_null(err);
+ assert_null(stmts);
+ assert_int_equal(err->type, BLOGC_ERROR_TEMPLATE_PARSER);
+ assert_string_equal(err->msg,
+ "'else' statement without an open 'if', 'ifdef' or 'ifndef' statement.\n"
+ "Error occurred near line 1, position 8: {% else %}");
+ blogc_error_free(err);
+}
+
+
+static void
+test_template_parse_invalid_else2(void **state)
+{
+ const char *a = "{% if BOLA == \"123\" %}{% if GUDA == \"1\" %}{% else %}{% else %}\n";
+ blogc_error_t *err = NULL;
+ sb_slist_t *stmts = blogc_template_parse(a, strlen(a), &err);
+ assert_non_null(err);
+ assert_null(stmts);
+ assert_int_equal(err->type, BLOGC_ERROR_TEMPLATE_PARSER);
+ assert_string_equal(err->msg,
+ "More than one 'else' statement for an open 'if', 'ifdef' or 'ifndef' "
+ "statement.\nError occurred near line 1, position 60: {% if BOLA == \"123\" "
+ "%}{% if GUDA == \"1\" %}{% else %}{% else %}");
+ blogc_error_free(err);
+}
+
+
+static void
+test_template_parse_invalid_else3(void **state)
+{
+ const char *a =
+ "{% if BOLA == \"123\" %}\n"
+ "{% if GUDA == \"1\" %}\n"
+ "{% else %}\n"
+ "asd\n"
+ "{% endif %}\n"
+ "{% else %}\n"
+ "{% else %}\n";
+ blogc_error_t *err = NULL;
+ sb_slist_t *stmts = blogc_template_parse(a, strlen(a), &err);
+ assert_non_null(err);
+ assert_null(stmts);
+ assert_int_equal(err->type, BLOGC_ERROR_TEMPLATE_PARSER);
+ assert_string_equal(err->msg,
+ "More than one 'else' statement for an open 'if', 'ifdef' or 'ifndef' "
+ "statement.\nError occurred near line 7, position 8: {% else %}");
+ blogc_error_free(err);
+}
+
+
+static void
+test_template_parse_invalid_block_end(void **state)
+{
+ const char *a = "{% block entry }}\n";
+ blogc_error_t *err = NULL;
+ sb_slist_t *stmts = blogc_template_parse(a, strlen(a), &err);
+ assert_non_null(err);
+ assert_null(stmts);
+ assert_int_equal(err->type, BLOGC_ERROR_TEMPLATE_PARSER);
+ assert_string_equal(err->msg,
+ "Invalid statement syntax. Must end with '%}'.\n"
+ "Error occurred near line 1, position 16: {% block entry }}");
+ blogc_error_free(err);
+}
+
+
+static void
+test_template_parse_invalid_variable_name(void **state)
+{
+ const char *a = "{% block entry %}{{ bola }}{% endblock %}\n";
+ blogc_error_t *err = NULL;
+ sb_slist_t *stmts = blogc_template_parse(a, strlen(a), &err);
+ assert_non_null(err);
+ assert_null(stmts);
+ assert_int_equal(err->type, BLOGC_ERROR_TEMPLATE_PARSER);
+ assert_string_equal(err->msg,
+ "Invalid variable name. Must begin with uppercase letter.\n"
+ "Error occurred near line 1, position 21: "
+ "{% block entry %}{{ bola }}{% endblock %}");
+ blogc_error_free(err);
+}
+
+
+static void
+test_template_parse_invalid_variable_name2(void **state)
+{
+ const char *a = "{% block entry %}{{ Bola }}{% endblock %}\n";
+ blogc_error_t *err = NULL;
+ sb_slist_t *stmts = blogc_template_parse(a, strlen(a), &err);
+ assert_non_null(err);
+ assert_null(stmts);
+ assert_int_equal(err->type, BLOGC_ERROR_TEMPLATE_PARSER);
+ assert_string_equal(err->msg,
+ "Invalid variable name. Must be uppercase letter, number or '_'.\n"
+ "Error occurred near line 1, position 22: "
+ "{% block entry %}{{ Bola }}{% endblock %}");
+ blogc_error_free(err);
+}
+
+
+static void
+test_template_parse_invalid_variable_name3(void **state)
+{
+ const char *a = "{% block entry %}{{ 0123 }}{% endblock %}\n";
+ blogc_error_t *err = NULL;
+ sb_slist_t *stmts = blogc_template_parse(a, strlen(a), &err);
+ assert_non_null(err);
+ assert_null(stmts);
+ assert_int_equal(err->type, BLOGC_ERROR_TEMPLATE_PARSER);
+ assert_string_equal(err->msg,
+ "Invalid variable name. Must begin with uppercase letter.\n"
+ "Error occurred near line 1, position 21: {% block entry %}{{ 0123 }}"
+ "{% endblock %}");
+ blogc_error_free(err);
+}
+
+
+static void
+test_template_parse_invalid_variable_end(void **state)
+{
+ const char *a = "{% block entry %}{{ BOLA %}{% endblock %}\n";
+ blogc_error_t *err = NULL;
+ sb_slist_t *stmts = blogc_template_parse(a, strlen(a), &err);
+ assert_non_null(err);
+ assert_null(stmts);
+ assert_int_equal(err->type, BLOGC_ERROR_TEMPLATE_PARSER);
+ assert_string_equal(err->msg,
+ "Invalid statement syntax. Must end with '}}'.\n"
+ "Error occurred near line 1, position 26: "
+ "{% block entry %}{{ BOLA %}{% endblock %}");
+ blogc_error_free(err);
+}
+
+
+static void
+test_template_parse_invalid_close(void **state)
+{
+ const char *a = "{% block entry %%\n";
+ blogc_error_t *err = NULL;
+ sb_slist_t *stmts = blogc_template_parse(a, strlen(a), &err);
+ assert_non_null(err);
+ assert_null(stmts);
+ assert_int_equal(err->type, BLOGC_ERROR_TEMPLATE_PARSER);
+ assert_string_equal(err->msg,
+ "Invalid statement syntax. Must end with '}'.\n"
+ "Error occurred near line 1, position 17: {% block entry %%");
+ blogc_error_free(err);
+}
+
+
+static void
+test_template_parse_invalid_close2(void **state)
+{
+ const char *a = "{% block entry %}{{ BOLA }%{% endblock %}\n";
+ blogc_error_t *err = NULL;
+ sb_slist_t *stmts = blogc_template_parse(a, strlen(a), &err);
+ assert_non_null(err);
+ assert_null(stmts);
+ assert_int_equal(err->type, BLOGC_ERROR_TEMPLATE_PARSER);
+ assert_string_equal(err->msg,
+ "Invalid statement syntax. Must end with '}'.\n"
+ "Error occurred near line 1, position 27: "
+ "{% block entry %}{{ BOLA }%{% endblock %}");
+ blogc_error_free(err);
+}
+
+
+static void
+test_template_parse_invalid_endif_not_closed(void **state)
+{
+ const char *a = "{% block entry %}{% endblock %}{% ifdef BOLA %}\n";
+ blogc_error_t *err = NULL;
+ sb_slist_t *stmts = blogc_template_parse(a, strlen(a), &err);
+ assert_non_null(err);
+ assert_null(stmts);
+ assert_int_equal(err->type, BLOGC_ERROR_TEMPLATE_PARSER);
+ assert_string_equal(err->msg, "1 open 'if', 'ifdef' and/or 'ifndef' statements "
+ "were not closed!");
+ blogc_error_free(err);
+}
+
+
+static void
+test_template_parse_invalid_endif_not_closed_inside_block(void **state)
+{
+ const char *a = "{% block listing %}{% ifdef BOLA %}{% endblock %}{% endif %}";
+ blogc_error_t *err = NULL;
+ sb_slist_t *stmts = blogc_template_parse(a, strlen(a), &err);
+ assert_non_null(err);
+ assert_null(stmts);
+ assert_int_equal(err->type, BLOGC_ERROR_TEMPLATE_PARSER);
+ assert_string_equal(err->msg,
+ "1 open 'if', 'ifdef' and/or 'ifndef' statements were not closed inside "
+ "a 'listing' block!");
+ blogc_error_free(err);
+}
+
+
+static void
+test_template_parse_invalid_else_not_closed_inside_block(void **state)
+{
+ const char *a = "{% block listing %}{% ifdef BOLA %}{% else %}{% endblock %}{% endif %}";
+ blogc_error_t *err = NULL;
+ sb_slist_t *stmts = blogc_template_parse(a, strlen(a), &err);
+ assert_non_null(err);
+ assert_null(stmts);
+ assert_int_equal(err->type, BLOGC_ERROR_TEMPLATE_PARSER);
+ assert_string_equal(err->msg,
+ "1 open 'if', 'ifdef' and/or 'ifndef' statements were not closed inside "
+ "a 'listing' block!");
+ blogc_error_free(err);
+}
+
+
+static void
+test_template_parse_invalid_block_not_closed(void **state)
+{
+ const char *a = "{% block entry %}\n";
+ blogc_error_t *err = NULL;
+ sb_slist_t *stmts = blogc_template_parse(a, strlen(a), &err);
+ assert_non_null(err);
+ assert_null(stmts);
+ assert_int_equal(err->type, BLOGC_ERROR_TEMPLATE_PARSER);
+ assert_string_equal(err->msg, "An open block was not closed!");
+ blogc_error_free(err);
+}
+
+
+static void
+test_template_parse_invalid_foreach_not_closed(void **state)
+{
+ const char *a = "{% foreach ASD %}\n";
+ blogc_error_t *err = NULL;
+ sb_slist_t *stmts = blogc_template_parse(a, strlen(a), &err);
+ assert_non_null(err);
+ assert_null(stmts);
+ assert_int_equal(err->type, BLOGC_ERROR_TEMPLATE_PARSER);
+ assert_string_equal(err->msg, "An open 'foreach' statement was not closed!");
+ blogc_error_free(err);
+}
+
+
+int
+main(void)
+{
+ const UnitTest tests[] = {
+ unit_test(test_template_parse),
+ unit_test(test_template_parse_crlf),
+ unit_test(test_template_parse_html),
+ unit_test(test_template_parse_ifdef_and_var_outside_block),
+ unit_test(test_template_parse_nested_else),
+ unit_test(test_template_parse_invalid_block_start),
+ unit_test(test_template_parse_invalid_block_nested),
+ unit_test(test_template_parse_invalid_foreach_nested),
+ unit_test(test_template_parse_invalid_block_not_open),
+ unit_test(test_template_parse_invalid_endif_not_open),
+ unit_test(test_template_parse_invalid_endif_not_open_inside_block),
+ unit_test(test_template_parse_invalid_else_not_open_inside_block),
+ unit_test(test_template_parse_invalid_endforeach_not_open),
+ unit_test(test_template_parse_invalid_endforeach_not_open_inside_block),
+ unit_test(test_template_parse_invalid_endforeach_not_open_inside_block2),
+ unit_test(test_template_parse_invalid_endforeach_not_closed_inside_block),
+ unit_test(test_template_parse_invalid_endforeach_not_closed_inside_block2),
+ unit_test(test_template_parse_invalid_block_name),
+ unit_test(test_template_parse_invalid_block_type_start),
+ unit_test(test_template_parse_invalid_block_type),
+ unit_test(test_template_parse_invalid_ifdef_start),
+ unit_test(test_template_parse_invalid_foreach_start),
+ unit_test(test_template_parse_invalid_ifdef_variable),
+ unit_test(test_template_parse_invalid_ifdef_variable2),
+ unit_test(test_template_parse_invalid_foreach_variable),
+ unit_test(test_template_parse_invalid_foreach_variable2),
+ unit_test(test_template_parse_invalid_if_operator),
+ unit_test(test_template_parse_invalid_if_operand),
+ unit_test(test_template_parse_invalid_if_operand2),
+ unit_test(test_template_parse_invalid_if_operand3),
+ unit_test(test_template_parse_invalid_else1),
+ unit_test(test_template_parse_invalid_else2),
+ unit_test(test_template_parse_invalid_else3),
+ unit_test(test_template_parse_invalid_block_end),
+ unit_test(test_template_parse_invalid_variable_name),
+ unit_test(test_template_parse_invalid_variable_name2),
+ unit_test(test_template_parse_invalid_variable_name3),
+ unit_test(test_template_parse_invalid_variable_end),
+ unit_test(test_template_parse_invalid_close),
+ unit_test(test_template_parse_invalid_close2),
+ unit_test(test_template_parse_invalid_endif_not_closed),
+ unit_test(test_template_parse_invalid_endif_not_closed_inside_block),
+ unit_test(test_template_parse_invalid_else_not_closed_inside_block),
+ unit_test(test_template_parse_invalid_block_not_closed),
+ unit_test(test_template_parse_invalid_foreach_not_closed),
+ };
+ return run_tests(tests);
+}