From b832feb3894d95a82e88da05bb9fa29c6da26211 Mon Sep 17 00:00:00 2001
From: "Rafael G. Martins" <rafael@rafaelmartins.eng.br>
Date: Sun, 1 Jan 2017 18:14:22 +0100
Subject: make: added a bunch of tests

---
 .gitignore                              |   3 +
 Makefile.am                             |  44 ++
 configure.ac                            |   3 +-
 src/blogc-make/exec.h                   |   2 +
 tests/blogc-make/check_atom.c           | 154 ++++++
 tests/blogc-make/check_blogc_make.sh.in | 796 ++++++++++++++++++++++++++++++++
 tests/blogc-make/check_exec.c           | 138 ++++++
 7 files changed, 1139 insertions(+), 1 deletion(-)
 create mode 100644 tests/blogc-make/check_atom.c
 create mode 100755 tests/blogc-make/check_blogc_make.sh.in
 create mode 100644 tests/blogc-make/check_exec.c

diff --git a/.gitignore b/.gitignore
index 844d416..b6ded60 100644
--- a/.gitignore
+++ b/.gitignore
@@ -67,6 +67,9 @@ blogc*.html
 /tests/blogc-git-receiver/check_post_receive.sh
 /tests/blogc-git-receiver/check_shell_command_parser
 /tests/blogc-git-receiver/check_shell.sh
+/tests/blogc-make/check_atom
+/tests/blogc-make/check_blogc_make.sh
+/tests/blogc-make/check_exec
 /tests/blogc-make/check_settings
 /tests/blogc-runserver/check_httpd_utils
 /tests/blogc-runserver/check_mime
diff --git a/Makefile.am b/Makefile.am
index bd69302..7650ccc 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -406,6 +406,12 @@ check_SCRIPTS += \
 endif
 endif
 
+if BUILD_MAKE
+check_SCRIPTS += \
+	tests/blogc-make/check_blogc_make.sh \
+	$(NULL)
+endif
+
 check_SCRIPTS += \
 	tests/blogc/check_blogc.sh \
 	$(NULL)
@@ -731,9 +737,47 @@ endif
 
 if BUILD_MAKE_LIB
 check_PROGRAMS += \
+	tests/blogc-make/check_atom \
+	tests/blogc-make/check_exec \
 	tests/blogc-make/check_settings \
 	$(NULL)
 
+tests_blogc_make_check_atom_SOURCES = \
+	tests/blogc-make/check_atom.c \
+	$(NULL)
+
+tests_blogc_make_check_atom_CFLAGS = \
+	$(CMOCKA_CFLAGS) \
+	$(NULL)
+
+tests_blogc_make_check_atom_LDFLAGS = \
+	-no-install \
+	$(NULL)
+
+tests_blogc_make_check_atom_LDADD = \
+	$(CMOCKA_LIBS) \
+	libblogc_make.la \
+	libblogc_common.la \
+	$(NULL)
+
+tests_blogc_make_check_exec_SOURCES = \
+	tests/blogc-make/check_exec.c \
+	$(NULL)
+
+tests_blogc_make_check_exec_CFLAGS = \
+	$(CMOCKA_CFLAGS) \
+	$(NULL)
+
+tests_blogc_make_check_exec_LDFLAGS = \
+	-no-install \
+	$(NULL)
+
+tests_blogc_make_check_exec_LDADD = \
+	$(CMOCKA_LIBS) \
+	libblogc_make.la \
+	libblogc_common.la \
+	$(NULL)
+
 tests_blogc_make_check_settings_SOURCES = \
 	tests/blogc-make/check_settings.c \
 	$(NULL)
diff --git a/configure.ac b/configure.ac
index cc08106..0fdbf6a 100644
--- a/configure.ac
+++ b/configure.ac
@@ -227,7 +227,8 @@ AC_CONFIG_FILES([tests/blogc-git-receiver/check_post_receive.sh],
                 [chmod +x tests/blogc-git-receiver/check_post_receive.sh])
 AC_CONFIG_FILES([tests/blogc-git-receiver/check_shell.sh],
                 [chmod +x tests/blogc-git-receiver/check_shell.sh])
-
+AC_CONFIG_FILES([tests/blogc-make/check_blogc_make.sh],
+                [chmod +x tests/blogc-make/check_blogc_make.sh])
 AC_OUTPUT
 
 AS_ECHO("
diff --git a/src/blogc-make/exec.h b/src/blogc-make/exec.h
index ecc7f2c..04bd44e 100644
--- a/src/blogc-make/exec.h
+++ b/src/blogc-make/exec.h
@@ -9,8 +9,10 @@
 #ifndef _MAKE_EXEC_H
 #define _MAKE_EXEC_H
 
+#include <stdbool.h>
 #include "../common/error.h"
 #include "../common/utils.h"
+#include "ctx.h"
 #include "settings.h"
 
 int bm_exec_command(const char *cmd, const char *input, char **output,
diff --git a/tests/blogc-make/check_atom.c b/tests/blogc-make/check_atom.c
new file mode 100644
index 0000000..cceec23
--- /dev/null
+++ b/tests/blogc-make/check_atom.c
@@ -0,0 +1,154 @@
+/*
+ * 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 "../../src/blogc-make/atom.h"
+#include "../../src/blogc-make/settings.h"
+#include "../../src/common/file.h"
+#include "../../src/common/error.h"
+#include "../../src/common/utils.h"
+
+
+static void
+test_atom_file(void **state)
+{
+    bm_settings_t *settings = bc_malloc(sizeof(bm_settings_t));
+    settings->settings = bc_trie_new(free);
+    bc_trie_insert(settings->settings, "atom_prefix", bc_strdup("atom"));
+    bc_trie_insert(settings->settings, "atom_ext", bc_strdup(".xml"));
+    bc_trie_insert(settings->settings, "post_prefix", bc_strdup("post"));
+
+    bc_error_t *err = NULL;
+    char *rv = bm_atom_deploy(settings, &err);
+
+    assert_non_null(rv);
+    assert_null(err);
+
+    size_t cmp_len;
+    char *cmp = bc_file_get_contents(rv, true, &cmp_len, &err);
+
+    assert_non_null(cmp);
+    assert_null(err);
+
+    assert_string_equal(cmp,
+        "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"
+        "<feed xmlns=\"http://www.w3.org/2005/Atom\">\n"
+        "  <title type=\"text\">{{ SITE_TITLE }}{% ifdef FILTER_TAG %} - "
+            "{{ FILTER_TAG }}{% endif %}</title>\n"
+        "  <id>{{ BASE_URL }}/atom{% ifdef FILTER_TAG %}/{{ FILTER_TAG }}"
+        "{% endif %}.xml</id>\n"
+        "  <updated>{{ DATE_FIRST_FORMATTED }}</updated>\n"
+        "  <link href=\"{{ BASE_DOMAIN }}{{ BASE_URL }}/\" />\n"
+        "  <link href=\"{{ BASE_DOMAIN }}{{ BASE_URL }}/atom{% ifdef FILTER_TAG %}"
+            "/{{ FILTER_TAG }}{% endif %}.xml\" rel=\"self\" />\n"
+        "  <author>\n"
+        "    <name>{{ AUTHOR_NAME }}</name>\n"
+        "    <email>{{ AUTHOR_EMAIL }}</email>\n"
+        "  </author>\n"
+        "  <subtitle type=\"text\">{{ SITE_TAGLINE }}</subtitle>\n"
+        "  {% block listing %}\n"
+        "  <entry>\n"
+        "    <title type=\"text\">{{ TITLE }}</title>\n"
+        "    <id>{{ BASE_URL }}/post/{{ FILENAME }}/</id>\n"
+        "    <updated>{{ DATE_FORMATTED }}</updated>\n"
+        "    <published>{{ DATE_FORMATTED }}</published>\n"
+        "    <link href=\"{{ BASE_DOMAIN }}{{ BASE_URL }}/post/{{ FILENAME }}/\" />\n"
+        "    <author>\n"
+        "      <name>{{ AUTHOR_NAME }}</name>\n"
+        "      <email>{{ AUTHOR_EMAIL }}</email>\n"
+        "    </author>\n"
+        "    <content type=\"html\"><![CDATA[{{ CONTENT }}]]></content>\n"
+        "  </entry>\n"
+        "  {% endblock %}\n"
+        "</feed>\n");
+
+    free(cmp);
+    bm_atom_destroy(rv);
+    free(rv);
+    bc_trie_free(settings->settings);
+    free(settings);
+}
+
+
+static void
+test_atom_dir(void **state)
+{
+    bm_settings_t *settings = bc_malloc(sizeof(bm_settings_t));
+    settings->settings = bc_trie_new(free);
+    bc_trie_insert(settings->settings, "atom_prefix", bc_strdup("atom"));
+    bc_trie_insert(settings->settings, "atom_ext", bc_strdup("/index.xml"));
+    bc_trie_insert(settings->settings, "post_prefix", bc_strdup("post"));
+
+    bc_error_t *err = NULL;
+    char *rv = bm_atom_deploy(settings, &err);
+
+    assert_non_null(rv);
+    assert_null(err);
+
+    size_t cmp_len;
+    char *cmp = bc_file_get_contents(rv, true, &cmp_len, &err);
+
+    assert_non_null(cmp);
+    assert_null(err);
+
+    assert_string_equal(cmp,
+        "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"
+        "<feed xmlns=\"http://www.w3.org/2005/Atom\">\n"
+        "  <title type=\"text\">{{ SITE_TITLE }}{% ifdef FILTER_TAG %} - "
+            "{{ FILTER_TAG }}{% endif %}</title>\n"
+        "  <id>{{ BASE_URL }}/atom{% ifdef FILTER_TAG %}/{{ FILTER_TAG }}"
+        "{% endif %}/index.xml</id>\n"
+        "  <updated>{{ DATE_FIRST_FORMATTED }}</updated>\n"
+        "  <link href=\"{{ BASE_DOMAIN }}{{ BASE_URL }}/\" />\n"
+        "  <link href=\"{{ BASE_DOMAIN }}{{ BASE_URL }}/atom{% ifdef FILTER_TAG %}"
+            "/{{ FILTER_TAG }}{% endif %}/index.xml\" rel=\"self\" />\n"
+        "  <author>\n"
+        "    <name>{{ AUTHOR_NAME }}</name>\n"
+        "    <email>{{ AUTHOR_EMAIL }}</email>\n"
+        "  </author>\n"
+        "  <subtitle type=\"text\">{{ SITE_TAGLINE }}</subtitle>\n"
+        "  {% block listing %}\n"
+        "  <entry>\n"
+        "    <title type=\"text\">{{ TITLE }}</title>\n"
+        "    <id>{{ BASE_URL }}/post/{{ FILENAME }}/</id>\n"
+        "    <updated>{{ DATE_FORMATTED }}</updated>\n"
+        "    <published>{{ DATE_FORMATTED }}</published>\n"
+        "    <link href=\"{{ BASE_DOMAIN }}{{ BASE_URL }}/post/{{ FILENAME }}/\" />\n"
+        "    <author>\n"
+        "      <name>{{ AUTHOR_NAME }}</name>\n"
+        "      <email>{{ AUTHOR_EMAIL }}</email>\n"
+        "    </author>\n"
+        "    <content type=\"html\"><![CDATA[{{ CONTENT }}]]></content>\n"
+        "  </entry>\n"
+        "  {% endblock %}\n"
+        "</feed>\n");
+
+    free(cmp);
+    bm_atom_destroy(rv);
+    free(rv);
+    bc_trie_free(settings->settings);
+    free(settings);
+}
+
+
+int
+main(void)
+{
+    const UnitTest tests[] = {
+        unit_test(test_atom_file),
+        unit_test(test_atom_dir),
+    };
+    return run_tests(tests);
+}
diff --git a/tests/blogc-make/check_blogc_make.sh.in b/tests/blogc-make/check_blogc_make.sh.in
new file mode 100755
index 0000000..2139664
--- /dev/null
+++ b/tests/blogc-make/check_blogc_make.sh.in
@@ -0,0 +1,796 @@
+#!@BASH@
+
+set -xe -o pipefail
+
+export LC_ALL=C
+
+TEMP="$(mktemp -d)"
+[[ -n "${TEMP}" ]]
+
+trap_func() {
+    [[ -e "${TEMP}/output.txt" ]] && cat "${TEMP}/output.txt"
+    [[ -n "${TEMP}" ]] && rm -rf "${TEMP}"
+}
+
+trap trap_func EXIT
+
+mkdir -p "${TEMP}"/proj{,/templates,/content/post}
+
+
+### minimal settings, will produce no file
+
+cat > "${TEMP}/proj/settings.ini" <<EOF
+[environment]
+AUTHOR_NAME = Lol
+AUTHOR_EMAIL = author@example.com
+SITE_TITLE = Lol's Website
+SITE_TAGLINE = WAT?!
+BASE_DOMAIN = http://example.org
+EOF
+
+${TESTS_ENVIRONMENT} ./blogc-make -f "${TEMP}/proj/settings.ini" 2>&1
+
+
+### default settings with some posts
+
+cat > "${TEMP}/proj/content/post/foo.txt" <<EOF
+TITLE: Foo
+DATE: 2016-10-01
+----------------
+This is foo.
+EOF
+
+cat > "${TEMP}/proj/content/post/bar.txt" <<EOF
+TITLE: Bar
+DATE: 2016-09-01
+----------------
+This is bar.
+EOF
+
+cat > "${TEMP}/proj/templates/main.tmpl" <<EOF
+{% block listing %}
+Listing: {% ifdef FILTER_TAG %}{{ FILTER_TAG }} - {% endif %}{{ TITLE }} - {{ DATE_FORMATTED }}
+{% endblock %}
+{% block entry %}
+{{ TITLE }}{% if BM_TYPE == "post" %} - {{ DATE_FORMATTED }}{% endif %}
+
+{{ CONTENT }}
+{% endblock %}
+EOF
+
+cat >> "${TEMP}/proj/settings.ini" <<EOF
+[posts]
+foo
+bar
+EOF
+
+${TESTS_ENVIRONMENT} ./blogc-make -f "${TEMP}/proj/settings.ini" 2>&1 | tee "${TEMP}/output.txt"
+grep "_build/index\\.html" "${TEMP}/output.txt"
+grep "_build/atom\\.xml" "${TEMP}/output.txt"
+grep "_build/page/1/index\\.html" "${TEMP}/output.txt"
+grep "_build/post/foo/index\\.html" "${TEMP}/output.txt"
+grep "_build/post/bar/index\\.html" "${TEMP}/output.txt"
+
+rm "${TEMP}/output.txt"
+
+cat > "${TEMP}/expected-index.html" <<EOF
+
+Listing: Foo - Oct 01, 2016, 12:00 AM GMT
+
+Listing: Bar - Sep 01, 2016, 12:00 AM GMT
+
+
+EOF
+diff -uN "${TEMP}/proj/_build/index.html" "${TEMP}/expected-index.html"
+diff -uN "${TEMP}/proj/_build/page/1/index.html" "${TEMP}/expected-index.html"
+
+cat > "${TEMP}/expected-atom.xml" <<EOF
+<?xml version="1.0" encoding="utf-8"?>
+<feed xmlns="http://www.w3.org/2005/Atom">
+  <title type="text">Lol's Website</title>
+  <id>/atom.xml</id>
+  <updated>2016-10-01T00:00:00Z</updated>
+  <link href="http://example.org/" />
+  <link href="http://example.org/atom.xml" rel="self" />
+  <author>
+    <name>Lol</name>
+    <email>author@example.com</email>
+  </author>
+  <subtitle type="text">WAT?!</subtitle>
+  
+  <entry>
+    <title type="text">Foo</title>
+    <id>/post/foo/</id>
+    <updated>2016-10-01T00:00:00Z</updated>
+    <published>2016-10-01T00:00:00Z</published>
+    <link href="http://example.org/post/foo/" />
+    <author>
+      <name>Lol</name>
+      <email>author@example.com</email>
+    </author>
+    <content type="html"><![CDATA[<p>This is foo.</p>
+]]></content>
+  </entry>
+  
+  <entry>
+    <title type="text">Bar</title>
+    <id>/post/bar/</id>
+    <updated>2016-09-01T00:00:00Z</updated>
+    <published>2016-09-01T00:00:00Z</published>
+    <link href="http://example.org/post/bar/" />
+    <author>
+      <name>Lol</name>
+      <email>author@example.com</email>
+    </author>
+    <content type="html"><![CDATA[<p>This is bar.</p>
+]]></content>
+  </entry>
+  
+</feed>
+EOF
+diff -uN "${TEMP}/proj/_build/atom.xml" "${TEMP}/expected-atom.xml"
+
+cat > "${TEMP}/expected-post-foo.html" <<EOF
+
+
+Foo - Oct 01, 2016, 12:00 AM GMT
+
+<p>This is foo.</p>
+
+
+EOF
+diff -uN "${TEMP}/proj/_build/post/foo/index.html" "${TEMP}/expected-post-foo.html"
+
+cat > "${TEMP}/expected-post-bar.html" <<EOF
+
+
+Bar - Sep 01, 2016, 12:00 AM GMT
+
+<p>This is bar.</p>
+
+
+EOF
+diff -uN "${TEMP}/proj/_build/post/bar/index.html" "${TEMP}/expected-post-bar.html"
+
+rm -rf "${TEMP}/proj/_build"
+
+
+### default settings with some posts and tags
+
+cat > "${TEMP}/proj/content/post/baz.txt" <<EOF
+TITLE: Baz
+DATE: 2016-08-01
+TAGS: tag1 tag2
+----------------
+This is baz.
+EOF
+
+cat >> "${TEMP}/proj/settings.ini" <<EOF
+baz
+[tags]
+tag1
+tag2
+EOF
+
+${TESTS_ENVIRONMENT} ./blogc-make -f "${TEMP}/proj/settings.ini" 2>&1 | tee "${TEMP}/output.txt"
+grep "_build/index\\.html" "${TEMP}/output.txt"
+grep "_build/atom\\.xml" "${TEMP}/output.txt"
+grep "_build/atom/tag1\\.xml" "${TEMP}/output.txt"
+grep "_build/atom/tag2\\.xml" "${TEMP}/output.txt"
+grep "_build/page/1/index\\.html" "${TEMP}/output.txt"
+grep "_build/post/foo/index\\.html" "${TEMP}/output.txt"
+grep "_build/post/bar/index\\.html" "${TEMP}/output.txt"
+grep "_build/post/baz/index\\.html" "${TEMP}/output.txt"
+grep "_build/tag/tag1/index\\.html" "${TEMP}/output.txt"
+grep "_build/tag/tag2/index\\.html" "${TEMP}/output.txt"
+
+rm "${TEMP}/output.txt"
+
+cat > "${TEMP}/expected-index.html" <<EOF
+
+Listing: Foo - Oct 01, 2016, 12:00 AM GMT
+
+Listing: Bar - Sep 01, 2016, 12:00 AM GMT
+
+Listing: Baz - Aug 01, 2016, 12:00 AM GMT
+
+
+EOF
+diff -uN "${TEMP}/proj/_build/index.html" "${TEMP}/expected-index.html"
+diff -uN "${TEMP}/proj/_build/page/1/index.html" "${TEMP}/expected-index.html"
+
+cat > "${TEMP}/expected-atom.xml" <<EOF
+<?xml version="1.0" encoding="utf-8"?>
+<feed xmlns="http://www.w3.org/2005/Atom">
+  <title type="text">Lol's Website</title>
+  <id>/atom.xml</id>
+  <updated>2016-10-01T00:00:00Z</updated>
+  <link href="http://example.org/" />
+  <link href="http://example.org/atom.xml" rel="self" />
+  <author>
+    <name>Lol</name>
+    <email>author@example.com</email>
+  </author>
+  <subtitle type="text">WAT?!</subtitle>
+  
+  <entry>
+    <title type="text">Foo</title>
+    <id>/post/foo/</id>
+    <updated>2016-10-01T00:00:00Z</updated>
+    <published>2016-10-01T00:00:00Z</published>
+    <link href="http://example.org/post/foo/" />
+    <author>
+      <name>Lol</name>
+      <email>author@example.com</email>
+    </author>
+    <content type="html"><![CDATA[<p>This is foo.</p>
+]]></content>
+  </entry>
+  
+  <entry>
+    <title type="text">Bar</title>
+    <id>/post/bar/</id>
+    <updated>2016-09-01T00:00:00Z</updated>
+    <published>2016-09-01T00:00:00Z</published>
+    <link href="http://example.org/post/bar/" />
+    <author>
+      <name>Lol</name>
+      <email>author@example.com</email>
+    </author>
+    <content type="html"><![CDATA[<p>This is bar.</p>
+]]></content>
+  </entry>
+  
+  <entry>
+    <title type="text">Baz</title>
+    <id>/post/baz/</id>
+    <updated>2016-08-01T00:00:00Z</updated>
+    <published>2016-08-01T00:00:00Z</published>
+    <link href="http://example.org/post/baz/" />
+    <author>
+      <name>Lol</name>
+      <email>author@example.com</email>
+    </author>
+    <content type="html"><![CDATA[<p>This is baz.</p>
+]]></content>
+  </entry>
+  
+</feed>
+EOF
+diff -uN "${TEMP}/proj/_build/atom.xml" "${TEMP}/expected-atom.xml"
+
+cat > "${TEMP}/expected-atom-tag1.xml" <<EOF
+<?xml version="1.0" encoding="utf-8"?>
+<feed xmlns="http://www.w3.org/2005/Atom">
+  <title type="text">Lol's Website - tag1</title>
+  <id>/atom/tag1.xml</id>
+  <updated>2016-08-01T00:00:00Z</updated>
+  <link href="http://example.org/" />
+  <link href="http://example.org/atom/tag1.xml" rel="self" />
+  <author>
+    <name>Lol</name>
+    <email>author@example.com</email>
+  </author>
+  <subtitle type="text">WAT?!</subtitle>
+  
+  <entry>
+    <title type="text">Baz</title>
+    <id>/post/baz/</id>
+    <updated>2016-08-01T00:00:00Z</updated>
+    <published>2016-08-01T00:00:00Z</published>
+    <link href="http://example.org/post/baz/" />
+    <author>
+      <name>Lol</name>
+      <email>author@example.com</email>
+    </author>
+    <content type="html"><![CDATA[<p>This is baz.</p>
+]]></content>
+  </entry>
+  
+</feed>
+EOF
+diff -uN "${TEMP}/proj/_build/atom/tag1.xml" "${TEMP}/expected-atom-tag1.xml"
+
+cat > "${TEMP}/expected-atom-tag2.xml" <<EOF
+<?xml version="1.0" encoding="utf-8"?>
+<feed xmlns="http://www.w3.org/2005/Atom">
+  <title type="text">Lol's Website - tag2</title>
+  <id>/atom/tag2.xml</id>
+  <updated>2016-08-01T00:00:00Z</updated>
+  <link href="http://example.org/" />
+  <link href="http://example.org/atom/tag2.xml" rel="self" />
+  <author>
+    <name>Lol</name>
+    <email>author@example.com</email>
+  </author>
+  <subtitle type="text">WAT?!</subtitle>
+  
+  <entry>
+    <title type="text">Baz</title>
+    <id>/post/baz/</id>
+    <updated>2016-08-01T00:00:00Z</updated>
+    <published>2016-08-01T00:00:00Z</published>
+    <link href="http://example.org/post/baz/" />
+    <author>
+      <name>Lol</name>
+      <email>author@example.com</email>
+    </author>
+    <content type="html"><![CDATA[<p>This is baz.</p>
+]]></content>
+  </entry>
+  
+</feed>
+EOF
+diff -uN "${TEMP}/proj/_build/atom/tag2.xml" "${TEMP}/expected-atom-tag2.xml"
+
+cat > "${TEMP}/expected-post-baz.html" <<EOF
+
+
+Baz - Aug 01, 2016, 12:00 AM GMT
+
+<p>This is baz.</p>
+
+
+EOF
+diff -uN "${TEMP}/proj/_build/post/foo/index.html" "${TEMP}/expected-post-foo.html"
+diff -uN "${TEMP}/proj/_build/post/bar/index.html" "${TEMP}/expected-post-bar.html"
+diff -uN "${TEMP}/proj/_build/post/baz/index.html" "${TEMP}/expected-post-baz.html"
+
+cat > "${TEMP}/expected-tag1.html" <<EOF
+
+Listing: tag1 - Baz - Aug 01, 2016, 12:00 AM GMT
+
+
+EOF
+diff -uN "${TEMP}/proj/_build/tag/tag1/index.html" "${TEMP}/expected-tag1.html"
+
+cat > "${TEMP}/expected-tag2.html" <<EOF
+
+Listing: tag2 - Baz - Aug 01, 2016, 12:00 AM GMT
+
+
+EOF
+diff -uN "${TEMP}/proj/_build/tag/tag2/index.html" "${TEMP}/expected-tag2.html"
+
+rm -rf "${TEMP}/proj/_build"
+
+
+### default settings with some posts, pages and tags
+
+cat > "${TEMP}/proj/content/page1.txt" <<EOF
+TITLE: Page 1
+-------------
+This is page 1.
+EOF
+
+cat > "${TEMP}/proj/content/page2.txt" <<EOF
+TITLE: Page 2
+-------------
+This is page 2.
+EOF
+
+cat >> "${TEMP}/proj/settings.ini" <<EOF
+[pages]
+page1
+page2
+EOF
+
+${TESTS_ENVIRONMENT} ./blogc-make -f "${TEMP}/proj/settings.ini" 2>&1 | tee "${TEMP}/output.txt"
+grep "_build/index\\.html" "${TEMP}/output.txt"
+grep "_build/atom\\.xml" "${TEMP}/output.txt"
+grep "_build/atom/tag1\\.xml" "${TEMP}/output.txt"
+grep "_build/atom/tag2\\.xml" "${TEMP}/output.txt"
+grep "_build/page/1/index\\.html" "${TEMP}/output.txt"
+grep "_build/post/foo/index\\.html" "${TEMP}/output.txt"
+grep "_build/post/bar/index\\.html" "${TEMP}/output.txt"
+grep "_build/post/baz/index\\.html" "${TEMP}/output.txt"
+grep "_build/tag/tag1/index\\.html" "${TEMP}/output.txt"
+grep "_build/tag/tag2/index\\.html" "${TEMP}/output.txt"
+grep "_build/page1/index\\.html" "${TEMP}/output.txt"
+grep "_build/page2/index\\.html" "${TEMP}/output.txt"
+
+rm "${TEMP}/output.txt"
+
+diff -uN "${TEMP}/proj/_build/index.html" "${TEMP}/expected-index.html"
+diff -uN "${TEMP}/proj/_build/page/1/index.html" "${TEMP}/expected-index.html"
+
+diff -uN "${TEMP}/proj/_build/atom.xml" "${TEMP}/expected-atom.xml"
+
+diff -uN "${TEMP}/proj/_build/atom/tag1.xml" "${TEMP}/expected-atom-tag1.xml"
+diff -uN "${TEMP}/proj/_build/atom/tag2.xml" "${TEMP}/expected-atom-tag2.xml"
+
+diff -uN "${TEMP}/proj/_build/post/foo/index.html" "${TEMP}/expected-post-foo.html"
+diff -uN "${TEMP}/proj/_build/post/bar/index.html" "${TEMP}/expected-post-bar.html"
+diff -uN "${TEMP}/proj/_build/post/baz/index.html" "${TEMP}/expected-post-baz.html"
+
+diff -uN "${TEMP}/proj/_build/tag/tag1/index.html" "${TEMP}/expected-tag1.html"
+diff -uN "${TEMP}/proj/_build/tag/tag2/index.html" "${TEMP}/expected-tag2.html"
+
+cat > "${TEMP}/expected-page1.html" <<EOF
+
+
+Page 1
+
+<p>This is page 1.</p>
+
+
+EOF
+diff -uN "${TEMP}/proj/_build/page1/index.html" "${TEMP}/expected-page1.html"
+
+cat > "${TEMP}/expected-page2.html" <<EOF
+
+
+Page 2
+
+<p>This is page 2.</p>
+
+
+EOF
+diff -uN "${TEMP}/proj/_build/page2/index.html" "${TEMP}/expected-page2.html"
+
+rm -rf "${TEMP}/proj"
+mkdir -p "${TEMP}"/proj{,/temp,/contents/poost}
+
+
+### custom settings with some posts
+
+cat > "${TEMP}/proj/contents/poost/foo.blogc" <<EOF
+TITLE: Foo
+DATE: 2016-10-01
+----------------
+This is foo.
+EOF
+
+cat > "${TEMP}/proj/contents/poost/bar.blogc" <<EOF
+TITLE: Bar
+DATE: 2016-09-01
+----------------
+This is bar.
+EOF
+
+cat > "${TEMP}/proj/temp/main.html" <<EOF
+{% block listing %}
+Listing: {% ifdef FILTER_TAG %}{{ FILTER_TAG }} - {% endif %}{{ TITLE }} - {{ DATE_FORMATTED }}
+{% endblock %}
+{% block entry %}
+{{ TITLE }}{% if BM_TYPE == "post" %} - {{ DATE_FORMATTED }}{% endif %}
+
+{{ CONTENT }}
+{% endblock %}
+EOF
+
+cat > "${TEMP}/proj/settings.ini" <<EOF
+[settings]
+content_dir = contents
+template_dir = temp
+main_template = main.html
+source_ext = .blogc
+output_dir = _blogc_build
+pagination_prefix = pagination
+posts_per_page = 1
+atom_posts_per_page = 1
+html_ext = .html
+index_prefix = posts
+post_prefix = poost
+tag_prefix = taag
+atom_prefix = atoom
+atom_ext = /index.xml
+date_format = %b %d, %Y
+locale = en_US.utf8
+
+[environment]
+AUTHOR_NAME = Lol
+AUTHOR_EMAIL = author@example.com
+SITE_TITLE = Lol's Website
+SITE_TAGLINE = WAT?!
+BASE_DOMAIN = http://example.org
+
+[posts]
+foo
+bar
+EOF
+
+${TESTS_ENVIRONMENT} ./blogc-make -f "${TEMP}/proj/settings.ini" 2>&1 | tee "${TEMP}/output.txt"
+grep "_blogc_build/posts\\.html" "${TEMP}/output.txt"
+grep "_blogc_build/atoom/index\\.xml" "${TEMP}/output.txt"
+grep "_blogc_build/pagination/1\\.html" "${TEMP}/output.txt"
+grep "_blogc_build/pagination/2\\.html" "${TEMP}/output.txt"
+grep "_blogc_build/poost/foo\\.html" "${TEMP}/output.txt"
+grep "_blogc_build/poost/bar\\.html" "${TEMP}/output.txt"
+
+rm "${TEMP}/output.txt"
+
+cat > "${TEMP}/expected-index.html" <<EOF
+
+Listing: Foo - Oct 01, 2016
+
+
+EOF
+diff -uN "${TEMP}/proj/_blogc_build/posts.html" "${TEMP}/expected-index.html"
+diff -uN "${TEMP}/proj/_blogc_build/pagination/1.html" "${TEMP}/expected-index.html"
+
+cat > "${TEMP}/expected-page-2.html" <<EOF
+
+Listing: Bar - Sep 01, 2016
+
+
+EOF
+diff -uN "${TEMP}/proj/_blogc_build/pagination/2.html" "${TEMP}/expected-page-2.html"
+
+cat > "${TEMP}/expected-atom.xml" <<EOF
+<?xml version="1.0" encoding="utf-8"?>
+<feed xmlns="http://www.w3.org/2005/Atom">
+  <title type="text">Lol's Website</title>
+  <id>/atoom/index.xml</id>
+  <updated>2016-10-01T00:00:00Z</updated>
+  <link href="http://example.org/" />
+  <link href="http://example.org/atoom/index.xml" rel="self" />
+  <author>
+    <name>Lol</name>
+    <email>author@example.com</email>
+  </author>
+  <subtitle type="text">WAT?!</subtitle>
+  
+  <entry>
+    <title type="text">Foo</title>
+    <id>/poost/foo/</id>
+    <updated>2016-10-01T00:00:00Z</updated>
+    <published>2016-10-01T00:00:00Z</published>
+    <link href="http://example.org/poost/foo/" />
+    <author>
+      <name>Lol</name>
+      <email>author@example.com</email>
+    </author>
+    <content type="html"><![CDATA[<p>This is foo.</p>
+]]></content>
+  </entry>
+  
+</feed>
+EOF
+diff -uN "${TEMP}/proj/_blogc_build/atoom/index.xml" "${TEMP}/expected-atom.xml"
+
+cat > "${TEMP}/expected-post-foo.html" <<EOF
+
+
+Foo - Oct 01, 2016
+
+<p>This is foo.</p>
+
+
+EOF
+diff -uN "${TEMP}/proj/_blogc_build/poost/foo.html" "${TEMP}/expected-post-foo.html"
+
+cat > "${TEMP}/expected-post-bar.html" <<EOF
+
+
+Bar - Sep 01, 2016
+
+<p>This is bar.</p>
+
+
+EOF
+diff -uN "${TEMP}/proj/_blogc_build/poost/bar.html" "${TEMP}/expected-post-bar.html"
+
+rm -rf "${TEMP}/proj/_build"
+
+
+### default settings with some posts and tags
+
+cat > "${TEMP}/proj/contents/poost/baz.blogc" <<EOF
+TITLE: Baz
+DATE: 2016-08-01
+TAGS: tag1 tag2
+----------------
+This is baz.
+EOF
+
+cat >> "${TEMP}/proj/settings.ini" <<EOF
+baz
+[tags]
+tag1
+tag2
+EOF
+
+${TESTS_ENVIRONMENT} ./blogc-make -f "${TEMP}/proj/settings.ini" 2>&1 | tee "${TEMP}/output.txt"
+grep "_blogc_build/posts\\.html" "${TEMP}/output.txt"
+grep "_blogc_build/atoom/index\\.xml" "${TEMP}/output.txt"
+grep "_blogc_build/atoom/tag1/index\\.xml" "${TEMP}/output.txt"
+grep "_blogc_build/atoom/tag2/index\\.xml" "${TEMP}/output.txt"
+grep "_blogc_build/pagination/1\\.html" "${TEMP}/output.txt"
+grep "_blogc_build/pagination/2\\.html" "${TEMP}/output.txt"
+grep "_blogc_build/pagination/3\\.html" "${TEMP}/output.txt"
+grep "_blogc_build/poost/foo\\.html" "${TEMP}/output.txt"
+grep "_blogc_build/poost/bar\\.html" "${TEMP}/output.txt"
+grep "_blogc_build/poost/baz\\.html" "${TEMP}/output.txt"
+grep "_blogc_build/taag/tag1\\.html" "${TEMP}/output.txt"
+grep "_blogc_build/taag/tag2\\.html" "${TEMP}/output.txt"
+
+rm "${TEMP}/output.txt"
+
+diff -uN "${TEMP}/proj/_blogc_build/posts.html" "${TEMP}/expected-index.html"
+diff -uN "${TEMP}/proj/_blogc_build/pagination/1.html" "${TEMP}/expected-index.html"
+diff -uN "${TEMP}/proj/_blogc_build/pagination/2.html" "${TEMP}/expected-page-2.html"
+
+cat > "${TEMP}/expected-page-3.html" <<EOF
+
+Listing: Baz - Aug 01, 2016
+
+
+EOF
+diff -uN "${TEMP}/proj/_blogc_build/pagination/3.html" "${TEMP}/expected-page-3.html"
+
+diff -uN "${TEMP}/proj/_blogc_build/atoom/index.xml" "${TEMP}/expected-atom.xml"
+
+cat > "${TEMP}/expected-atom-tag1.xml" <<EOF
+<?xml version="1.0" encoding="utf-8"?>
+<feed xmlns="http://www.w3.org/2005/Atom">
+  <title type="text">Lol's Website - tag1</title>
+  <id>/atoom/tag1/index.xml</id>
+  <updated>2016-08-01T00:00:00Z</updated>
+  <link href="http://example.org/" />
+  <link href="http://example.org/atoom/tag1/index.xml" rel="self" />
+  <author>
+    <name>Lol</name>
+    <email>author@example.com</email>
+  </author>
+  <subtitle type="text">WAT?!</subtitle>
+  
+  <entry>
+    <title type="text">Baz</title>
+    <id>/poost/baz/</id>
+    <updated>2016-08-01T00:00:00Z</updated>
+    <published>2016-08-01T00:00:00Z</published>
+    <link href="http://example.org/poost/baz/" />
+    <author>
+      <name>Lol</name>
+      <email>author@example.com</email>
+    </author>
+    <content type="html"><![CDATA[<p>This is baz.</p>
+]]></content>
+  </entry>
+  
+</feed>
+EOF
+diff -uN "${TEMP}/proj/_blogc_build/atoom/tag1/index.xml" "${TEMP}/expected-atom-tag1.xml"
+
+cat > "${TEMP}/expected-atom-tag2.xml" <<EOF
+<?xml version="1.0" encoding="utf-8"?>
+<feed xmlns="http://www.w3.org/2005/Atom">
+  <title type="text">Lol's Website - tag2</title>
+  <id>/atoom/tag2/index.xml</id>
+  <updated>2016-08-01T00:00:00Z</updated>
+  <link href="http://example.org/" />
+  <link href="http://example.org/atoom/tag2/index.xml" rel="self" />
+  <author>
+    <name>Lol</name>
+    <email>author@example.com</email>
+  </author>
+  <subtitle type="text">WAT?!</subtitle>
+  
+  <entry>
+    <title type="text">Baz</title>
+    <id>/poost/baz/</id>
+    <updated>2016-08-01T00:00:00Z</updated>
+    <published>2016-08-01T00:00:00Z</published>
+    <link href="http://example.org/poost/baz/" />
+    <author>
+      <name>Lol</name>
+      <email>author@example.com</email>
+    </author>
+    <content type="html"><![CDATA[<p>This is baz.</p>
+]]></content>
+  </entry>
+  
+</feed>
+EOF
+diff -uN "${TEMP}/proj/_blogc_build/atoom/tag2/index.xml" "${TEMP}/expected-atom-tag2.xml"
+
+cat > "${TEMP}/expected-post-baz.html" <<EOF
+
+
+Baz - Aug 01, 2016
+
+<p>This is baz.</p>
+
+
+EOF
+diff -uN "${TEMP}/proj/_blogc_build/poost/foo.html" "${TEMP}/expected-post-foo.html"
+diff -uN "${TEMP}/proj/_blogc_build/poost/bar.html" "${TEMP}/expected-post-bar.html"
+diff -uN "${TEMP}/proj/_blogc_build/poost/baz.html" "${TEMP}/expected-post-baz.html"
+
+cat > "${TEMP}/expected-tag1.html" <<EOF
+
+Listing: tag1 - Baz - Aug 01, 2016
+
+
+EOF
+diff -uN "${TEMP}/proj/_blogc_build/taag/tag1.html" "${TEMP}/expected-tag1.html"
+
+cat > "${TEMP}/expected-tag2.html" <<EOF
+
+Listing: tag2 - Baz - Aug 01, 2016
+
+
+EOF
+diff -uN "${TEMP}/proj/_blogc_build/taag/tag2.html" "${TEMP}/expected-tag2.html"
+
+rm -rf "${TEMP}/proj/_blogc_build"
+
+
+### default settings with some posts, pages and tags
+
+cat > "${TEMP}/proj/contents/page1.blogc" <<EOF
+TITLE: Page 1
+-------------
+This is page 1.
+EOF
+
+cat > "${TEMP}/proj/contents/page2.blogc" <<EOF
+TITLE: Page 2
+-------------
+This is page 2.
+EOF
+
+cat >> "${TEMP}/proj/settings.ini" <<EOF
+[pages]
+page1
+page2
+EOF
+
+${TESTS_ENVIRONMENT} ./blogc-make -f "${TEMP}/proj/settings.ini" 2>&1 | tee "${TEMP}/output.txt"
+grep "_blogc_build/posts\\.html" "${TEMP}/output.txt"
+grep "_blogc_build/atoom/index\\.xml" "${TEMP}/output.txt"
+grep "_blogc_build/atoom/tag1/index\\.xml" "${TEMP}/output.txt"
+grep "_blogc_build/atoom/tag2/index\\.xml" "${TEMP}/output.txt"
+grep "_blogc_build/pagination/1\\.html" "${TEMP}/output.txt"
+grep "_blogc_build/pagination/2\\.html" "${TEMP}/output.txt"
+grep "_blogc_build/pagination/3\\.html" "${TEMP}/output.txt"
+grep "_blogc_build/poost/foo\\.html" "${TEMP}/output.txt"
+grep "_blogc_build/poost/bar\\.html" "${TEMP}/output.txt"
+grep "_blogc_build/poost/baz\\.html" "${TEMP}/output.txt"
+grep "_blogc_build/taag/tag1\\.html" "${TEMP}/output.txt"
+grep "_blogc_build/taag/tag2\\.html" "${TEMP}/output.txt"
+grep "_blogc_build/page1\\.html" "${TEMP}/output.txt"
+grep "_blogc_build/page2\\.html" "${TEMP}/output.txt"
+
+rm "${TEMP}/output.txt"
+
+diff -uN "${TEMP}/proj/_blogc_build/posts.html" "${TEMP}/expected-index.html"
+diff -uN "${TEMP}/proj/_blogc_build/pagination/1.html" "${TEMP}/expected-index.html"
+diff -uN "${TEMP}/proj/_blogc_build/pagination/2.html" "${TEMP}/expected-page-2.html"
+diff -uN "${TEMP}/proj/_blogc_build/pagination/3.html" "${TEMP}/expected-page-3.html"
+
+diff -uN "${TEMP}/proj/_blogc_build/atoom/index.xml" "${TEMP}/expected-atom.xml"
+diff -uN "${TEMP}/proj/_blogc_build/atoom/tag1/index.xml" "${TEMP}/expected-atom-tag1.xml"
+diff -uN "${TEMP}/proj/_blogc_build/atoom/tag2/index.xml" "${TEMP}/expected-atom-tag2.xml"
+
+diff -uN "${TEMP}/proj/_blogc_build/poost/foo.html" "${TEMP}/expected-post-foo.html"
+diff -uN "${TEMP}/proj/_blogc_build/poost/bar.html" "${TEMP}/expected-post-bar.html"
+diff -uN "${TEMP}/proj/_blogc_build/poost/baz.html" "${TEMP}/expected-post-baz.html"
+
+diff -uN "${TEMP}/proj/_blogc_build/taag/tag1.html" "${TEMP}/expected-tag1.html"
+diff -uN "${TEMP}/proj/_blogc_build/taag/tag2.html" "${TEMP}/expected-tag2.html"
+
+cat > "${TEMP}/expected-page1.html" <<EOF
+
+
+Page 1
+
+<p>This is page 1.</p>
+
+
+EOF
+diff -uN "${TEMP}/proj/_blogc_build/page1.html" "${TEMP}/expected-page1.html"
+
+cat > "${TEMP}/expected-page2.html" <<EOF
+
+
+Page 2
+
+<p>This is page 2.</p>
+
+
+EOF
+diff -uN "${TEMP}/proj/_blogc_build/page2.html" "${TEMP}/expected-page2.html"
+
+rm -rf "${TEMP}/proj/_blogc_build"
diff --git a/tests/blogc-make/check_exec.c b/tests/blogc-make/check_exec.c
new file mode 100644
index 0000000..ce87f09
--- /dev/null
+++ b/tests/blogc-make/check_exec.c
@@ -0,0 +1,138 @@
+/*
+ * 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 "../../src/blogc-make/exec.h"
+#include "../../src/blogc-make/settings.h"
+#include "../../src/common/utils.h"
+
+
+static void
+test_build_blogc_cmd_with_settings(void **state)
+{
+    unsetenv("BLOGC");
+
+    bm_settings_t *settings = bc_malloc(sizeof(bm_settings_t));
+    settings->settings = bc_trie_new(free);
+    bc_trie_insert(settings->settings, "locale", bc_strdup("en_US.utf8"));
+    settings->env = bc_trie_new(free);
+    bc_trie_insert(settings->env, "FOO", bc_strdup("BAR"));
+    bc_trie_insert(settings->env, "BAR", bc_strdup("BAZ"));
+    bc_trie_t *variables = bc_trie_new(free);
+    bc_trie_insert(variables, "LOL", bc_strdup("HEHE"));
+
+    char *rv = bm_exec_build_blogc_cmd(settings, variables, true, "main.tmpl",
+        "foo.html", true);
+    assert_string_equal(rv,
+        "LC_ALL='en_US.utf8' blogc -D FOO='BAR' -D BAR='BAZ' -D LOL='HEHE' -l "
+        "-t 'main.tmpl' -o 'foo.html' -i");
+    free(rv);
+
+    rv = bm_exec_build_blogc_cmd(settings, variables, false, NULL, NULL, false);
+    assert_string_equal(rv,
+        "LC_ALL='en_US.utf8' blogc -D FOO='BAR' -D BAR='BAZ' -D LOL='HEHE'");
+    free(rv);
+
+    rv = bm_exec_build_blogc_cmd(settings, NULL, false, NULL, NULL, false);
+    assert_string_equal(rv,
+        "LC_ALL='en_US.utf8' blogc -D FOO='BAR' -D BAR='BAZ'");
+    free(rv);
+
+    setenv("BLOGC", "/path/to/blogc", 1);
+
+    rv = bm_exec_build_blogc_cmd(settings, variables, true, "main.tmpl",
+        "foo.html", true);
+    assert_string_equal(rv,
+        "LC_ALL='en_US.utf8' /path/to/blogc -D FOO='BAR' -D BAR='BAZ' "
+        "-D LOL='HEHE' -l -t 'main.tmpl' -o 'foo.html' -i");
+    free(rv);
+
+    rv = bm_exec_build_blogc_cmd(settings, variables, false, NULL, NULL, false);
+    assert_string_equal(rv,
+        "LC_ALL='en_US.utf8' /path/to/blogc -D FOO='BAR' -D BAR='BAZ' "
+        "-D LOL='HEHE'");
+    free(rv);
+
+    rv = bm_exec_build_blogc_cmd(settings, NULL, false, NULL, NULL, false);
+    assert_string_equal(rv,
+        "LC_ALL='en_US.utf8' /path/to/blogc -D FOO='BAR' -D BAR='BAZ'");
+    free(rv);
+
+    unsetenv("BLOGC");
+
+    bc_trie_free(variables);
+    bc_trie_free(settings->settings);
+    bc_trie_free(settings->env);
+    free(settings);
+}
+
+
+static void
+test_build_blogc_cmd_without_settings(void **state)
+{
+    unsetenv("BLOGC");
+
+    bc_trie_t *variables = bc_trie_new(free);
+    bc_trie_insert(variables, "LOL", bc_strdup("HEHE"));
+
+    char *rv = bm_exec_build_blogc_cmd(NULL, variables, true, "main.tmpl",
+        "foo.html", true);
+    assert_string_equal(rv,
+        "blogc -D LOL='HEHE' -l -t 'main.tmpl' -o 'foo.html' -i");
+    free(rv);
+
+    rv = bm_exec_build_blogc_cmd(NULL, variables, false, NULL, NULL, false);
+    assert_string_equal(rv,
+        "blogc -D LOL='HEHE'");
+    free(rv);
+
+    rv = bm_exec_build_blogc_cmd(NULL, NULL, false, NULL, NULL, false);
+    assert_string_equal(rv,
+        "blogc");
+    free(rv);
+
+    setenv("BLOGC", "/path/to/blogc", 1);
+
+    rv = bm_exec_build_blogc_cmd(NULL, variables, true, "main.tmpl", "foo.html",
+        true);
+    assert_string_equal(rv,
+        "/path/to/blogc -D LOL='HEHE' -l -t 'main.tmpl' -o 'foo.html' -i");
+    free(rv);
+
+    rv = bm_exec_build_blogc_cmd(NULL, variables, false, NULL, NULL, false);
+    assert_string_equal(rv,
+        "/path/to/blogc -D LOL='HEHE'");
+    free(rv);
+
+    rv = bm_exec_build_blogc_cmd(NULL, NULL, false, NULL, NULL, false);
+    assert_string_equal(rv,
+        "/path/to/blogc");
+    free(rv);
+
+    unsetenv("BLOGC");
+
+    bc_trie_free(variables);
+}
+
+
+int
+main(void)
+{
+    const UnitTest tests[] = {
+        unit_test(test_build_blogc_cmd_with_settings),
+        unit_test(test_build_blogc_cmd_without_settings),
+    };
+    return run_tests(tests);
+}
-- 
cgit v1.2.3-18-g5258