summaryrefslogtreecommitdiff
path: root/tests
diff options
context:
space:
mode:
authorAntti Ajanki <antti.ajanki@iki.fi>2013-08-06 09:07:49 +0300
committerAntti Ajanki <antti.ajanki@iki.fi>2013-08-06 09:07:49 +0300
commit7c81286a59639e139ac7e947378be24410701a5e (patch)
tree88e43b758dc2330e8711ebae80eee0039cc57322 /tests
downloadvdr-plugin-webvideo-7c81286a59639e139ac7e947378be24410701a5e.tar.gz
vdr-plugin-webvideo-7c81286a59639e139ac7e947378be24410701a5e.tar.bz2
import to vdr-developer repo
Diffstat (limited to 'tests')
-rw-r--r--tests/CMakeLists.txt44
-rw-r--r--tests/context_tests.c54
-rw-r--r--tests/context_tests.h23
-rw-r--r--tests/data/links5
-rw-r--r--tests/data/websites/www.youtube.com/menu.xml16
-rw-r--r--tests/libwebvi_tests.c106
-rw-r--r--tests/linkextractor_tests.c158
-rw-r--r--tests/linkextractor_tests.h34
-rw-r--r--tests/linktemplates_tests.c46
-rw-r--r--tests/linktemplates_tests.h23
-rw-r--r--tests/menubuilder_tests.c155
-rw-r--r--tests/menubuilder_tests.h26
-rw-r--r--tests/pipe_tests.c246
-rw-r--r--tests/pipe_tests.h12
-rw-r--r--tests/urlutils_tests.c227
-rw-r--r--tests/urlutils_tests.h38
16 files changed, 1213 insertions, 0 deletions
diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt
new file mode 100644
index 0000000..6166f6f
--- /dev/null
+++ b/tests/CMakeLists.txt
@@ -0,0 +1,44 @@
+ENABLE_TESTING()
+
+SET(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake/modules/")
+
+FIND_PROGRAM(GTESTER_BIN gtester)
+IF(NOT GTESTER_BIN)
+ MESSAGE(FATAL_ERROR "Binary 'gtester' is required for testing!")
+ENDIF()
+
+INCLUDE_DIRECTORIES(. ../src/libwebvi)
+
+FIND_PACKAGE(LibXml2 REQUIRED)
+FIND_PACKAGE(CURL REQUIRED)
+FIND_PACKAGE(LibTidy REQUIRED)
+
+FIND_PACKAGE(PkgConfig)
+PKG_CHECK_MODULES(GLIB REQUIRED glib-2.0)
+ADD_DEFINITIONS(${GLIB_CFLAGS} ${GLIB_CFLAGS_OTHER})
+LINK_DIRECTORIES(${GLIB_LIBRARY_DIRS})
+
+INCLUDE_DIRECTORIES(${LIBXML2_INCLUDE_DIR})
+INCLUDE_DIRECTORIES(${GLIB_INCLUDE_DIRS})
+
+ADD_DEFINITIONS( -DTEST_DATA_DIR="${CMAKE_SOURCE_DIR}/tests/data")
+
+ADD_EXECUTABLE(libwebvi_tests
+ libwebvi_tests.c
+ context_tests.c
+ linktemplates_tests.c
+ linkextractor_tests.c
+ menubuilder_tests.c
+ pipe_tests.c
+ urlutils_tests.c)
+TARGET_LINK_LIBRARIES(libwebvi_tests
+ webvistatic
+ ${GLIB_LIBRARIES}
+ ${LIBXML2_LIBRARIES}
+ ${CURL_LIBRARIES}
+ ${LIBTIDY_LIBRARIES})
+
+ADD_TEST(unittests ${GTESTER_BIN} -k -o testresults.xml ${CMAKE_CURRENT_BINARY_DIR}/libwebvi_tests)
+SET_TESTS_PROPERTIES(unittests PROPERTIES PASS_REGULAR_EXPRESSION "PASS:")
+SET_TESTS_PROPERTIES(unittests PROPERTIES FAIL_REGULAR_EXPRESSION "ERROR:")
+
diff --git a/tests/context_tests.c b/tests/context_tests.c
new file mode 100644
index 0000000..43bf572
--- /dev/null
+++ b/tests/context_tests.c
@@ -0,0 +1,54 @@
+#include "context_tests.h"
+#include "request.h"
+
+void context_fixture_setup(ContextFixture *fixture,
+ gconstpointer test_data)
+{
+ fixture->handle = webvi_context_initialize();
+ g_assert(fixture->handle != 0);
+ fixture->context = get_context_by_handle(fixture->handle);
+ g_assert(fixture->context != NULL);
+}
+
+void context_fixture_teardown(ContextFixture *fixture,
+ gconstpointer test_data)
+{
+ g_assert(fixture->handle != 0);
+ g_assert(fixture->context != NULL);
+ webvi_context_cleanup(fixture->handle);
+ fixture->handle = 0;
+ fixture->context = NULL;
+}
+
+void test_context_create(void) {
+ WebviCtx ctx = webvi_initialize_context();
+ g_assert(ctx != 0);
+ WebviCtx ctx2 = webvi_initialize_context();
+ g_assert(ctx != ctx2);
+
+ webvi_context_cleanup(ctx2);
+ webvi_context_cleanup(ctx);
+}
+
+void test_context_template_path(ContextFixture *fixture,
+ gconstpointer test_data) {
+ const char *tpath = "testpath";
+ webvi_context_set_template_path(fixture->context, tpath);
+ const char *output_path = webvi_context_get_template_path(fixture->context);
+ g_assert_cmpstr(output_path, ==, tpath);
+}
+
+void test_context_request_processing(ContextFixture *fixture,
+ G_GNUC_UNUSED gconstpointer test_data) {
+ WebviRequest *mock_request = request_create("testuri", fixture->context);
+
+ WebviHandle h = webvi_context_add_request(fixture->context, mock_request);
+ g_assert(h != WEBVI_INVALID_HANDLE);
+ WebviRequest *req = webvi_context_get_request(fixture->context, h);
+ g_assert(req == mock_request);
+
+ webvi_context_remove_request(fixture->context, h);
+
+ req = webvi_context_get_request(fixture->context, h);
+ g_assert(req == NULL);
+}
diff --git a/tests/context_tests.h b/tests/context_tests.h
new file mode 100644
index 0000000..1a6907c
--- /dev/null
+++ b/tests/context_tests.h
@@ -0,0 +1,23 @@
+#ifndef CONTEXT_TESTS_H
+#define CONTEXT_TESTS_H
+
+#include <glib.h>
+#include "webvicontext.h"
+
+typedef struct {
+ WebviCtx handle;
+ struct WebviContext *context;
+} ContextFixture;
+
+void context_fixture_setup(ContextFixture *fixture,
+ gconstpointer test_data);
+void context_fixture_teardown(ContextFixture *fixture,
+ gconstpointer test_data);
+
+void test_context_create(void);
+void test_context_template_path(ContextFixture *fixture,
+ gconstpointer test_data);
+void test_context_request_processing(ContextFixture *fixture,
+ gconstpointer test_data);
+
+#endif // CONTEXT_TESTS_H
diff --git a/tests/data/links b/tests/data/links
new file mode 100644
index 0000000..0482470
--- /dev/null
+++ b/tests/data/links
@@ -0,0 +1,5 @@
+### Link configuration file for tests ###
+# Regular link
+http://example\.com/test/
+# Video link
+http://example.com/video/ bin:test_command
diff --git a/tests/data/websites/www.youtube.com/menu.xml b/tests/data/websites/www.youtube.com/menu.xml
new file mode 100644
index 0000000..15f1a0e
--- /dev/null
+++ b/tests/data/websites/www.youtube.com/menu.xml
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<wvmenu>
+ <title>YouTube</title>
+ <description>Video sharing service on which users worldwide can upload their videos</description>
+
+ <link>
+ <label>Search</label>
+ <ref>wvt:///www.youtube.com/search.xml</ref>
+ </link>
+
+ <link>
+ <label>Categories</label>
+ <ref>http://www.youtube.com/channels?feature=guide</ref>
+ </link>
+</wvmenu>
diff --git a/tests/libwebvi_tests.c b/tests/libwebvi_tests.c
new file mode 100644
index 0000000..f754157
--- /dev/null
+++ b/tests/libwebvi_tests.c
@@ -0,0 +1,106 @@
+#include <glib.h>
+#include "context_tests.h"
+#include "linktemplates_tests.h"
+#include "linkextractor_tests.h"
+#include "menubuilder_tests.h"
+#include "pipe_tests.h"
+#include "urlutils_tests.h"
+
+int main(int argc, char** argv)
+{
+ g_test_init(&argc, &argv, NULL);
+
+ g_test_add_func("/context/create", test_context_create);
+ g_test_add("/context/templatepath", ContextFixture, 0, context_fixture_setup,
+ test_context_template_path, context_fixture_teardown);
+ g_test_add("/context/request", ContextFixture, 0, context_fixture_setup,
+ test_context_request_processing, context_fixture_teardown);
+
+ g_test_add("/linktemplates/load", LinkTemplatesFixture, 0,
+ link_templates_fixture_setup, test_link_templates_load,
+ link_templates_fixture_teardown);
+ g_test_add("/linktemplates/get", LinkTemplatesFixture, 0,
+ link_templates_fixture_setup, test_link_templates_get,
+ link_templates_fixture_teardown);
+
+ g_test_add("/linkextractor/extract", LinkExtractorFixture, 0,
+ link_extractor_fixture_setup, test_link_extractor_extract,
+ link_extractor_fixture_teardown);
+ g_test_add("/linkextractor/unrecognized", LinkExtractorFixture, 0,
+ link_extractor_fixture_setup, test_link_extractor_unrecognized_link,
+ link_extractor_fixture_teardown);
+ g_test_add("/linkextractor/append", LinkExtractorFixture, 0,
+ link_extractor_fixture_setup, test_link_extractor_append,
+ link_extractor_fixture_teardown);
+ g_test_add("/linkextractor/invalidHtml", LinkExtractorFixture, 0,
+ link_extractor_fixture_setup, test_link_extractor_invalid_html,
+ link_extractor_fixture_teardown);
+ g_test_add("/linkextractor/relativeURL", LinkExtractorFixture, 0,
+ link_extractor_fixture_setup, test_link_extractor_relative_urls,
+ link_extractor_fixture_teardown);
+ g_test_add("/linkextractor/html_title", LinkExtractorFixture, 0,
+ link_extractor_fixture_setup, test_link_extractor_html_title,
+ link_extractor_fixture_teardown);
+
+ g_test_add_func("/menubuilder/mainmenu", test_mainmenu);
+ g_test_add("/menubuilder/title", MenuBuilderFixture, 0,
+ menu_builder_fixture_setup, test_menu_builder_title,
+ menu_builder_fixture_teardown);
+ g_test_add("/menubuilder/links", MenuBuilderFixture, 0,
+ menu_builder_fixture_setup, test_menu_builder_append_links,
+ menu_builder_fixture_teardown);
+ g_test_add("/menubuilder/encoding", MenuBuilderFixture, 0,
+ menu_builder_fixture_setup, test_menu_builder_link_title_encoding,
+ menu_builder_fixture_teardown);
+
+ g_test_add_func("/pipe/one_component", test_pipe_one_component);
+ g_test_add_func("/pipe/two_components", test_pipe_two_components);
+ g_test_add_func("/pipe/failing_component", test_pipe_failing_component);
+ g_test_add_func("/pipe/append_after_finish",
+ test_pipe_not_appending_after_finished);
+ g_test_add_func("/pipe/state_change_after_finish",
+ test_pipe_state_not_chaning_after_finished);
+ g_test_add_func("/pipe/fdset", test_pipe_fdset);
+ g_test_add_func("/pipe/delete_all", test_pipe_delete_all);
+
+ g_test_add_func("/urlutils/scheme", test_url_scheme);
+ g_test_add_func("/urlutils/scheme_no_scheme", test_url_scheme_no_scheme);
+ g_test_add_func("/urlutils/scheme_double", test_url_scheme_double_scheme);
+ g_test_add_func("/urlutils/scheme_invalid_characters",
+ test_url_scheme_invalid_characters);
+ g_test_add_func("/urlutils/root", test_url_root);
+ g_test_add_func("/urlutils/root_path", test_url_root_full_path);
+ g_test_add_func("/urlutils/root_query", test_url_root_terminated_by_query);
+ g_test_add_func("/urlutils/path", test_url_path);
+ g_test_add_func("/urlutils/path_slash", test_url_path_ends_in_slash);
+ g_test_add_func("/urlutils/path_query", test_url_path_query);
+ g_test_add_func("/urlutils/path_fragment", test_url_path_fragment);
+ g_test_add_func("/urlutils/path_no_path", test_url_path_no_path);
+ g_test_add_func("/urlutils/path_no_server", test_url_path_no_server);
+ g_test_add_func("/urlutils/path_no_scheme", test_url_path_no_scheme);
+ g_test_add_func("/urlutils/dirname", test_url_path_dirname);
+ g_test_add_func("/urlutils/dirname_no_file", test_url_path_dirname_no_file);
+ g_test_add_func("/urlutils/dirname_query", test_url_path_dirname_query);
+ g_test_add_func("/urlutils/dirname_no_server",
+ test_url_path_dirname_no_server);
+ g_test_add_func("/urlutils/query", test_url_path_and_query);
+ g_test_add_func("/urlutils/query_no_query",
+ test_url_path_and_query_no_query);
+ g_test_add_func("/urlutils/query_double_query",
+ test_url_path_and_query_double_query);
+ g_test_add_func("/urlutils/query_fragment", test_url_path_and_query_fragment);
+ g_test_add_func("/urlutils/query_no_path", test_url_path_and_query_no_path);
+ g_test_add_func("/urlutils/rel2abs", test_url_rel2abs_file);
+ g_test_add_func("/urlutils/rel2abs_root", test_url_rel2abs_root);
+ g_test_add_func("/urlutils/rel2abs_query", test_url_rel2abs_query);
+ g_test_add_func("/urlutils/rel2abs_double_query",
+ test_url_rel2abs_double_query);
+ g_test_add_func("/urlutils/rel2abs_append_query",
+ test_url_rel2abs_append_query);
+ g_test_add_func("/urlutils/rel2abs_fragment", test_url_rel2abs_fragment);
+ g_test_add_func("/urlutils/rel2abs_append_fragment",
+ test_url_rel2abs_append_fragment);
+ g_test_add_func("/urlutils/rel2abs_scheme", test_url_rel2abs_scheme);
+
+ return g_test_run();
+}
diff --git a/tests/linkextractor_tests.c b/tests/linkextractor_tests.c
new file mode 100644
index 0000000..2aa9166
--- /dev/null
+++ b/tests/linkextractor_tests.c
@@ -0,0 +1,158 @@
+#include <string.h>
+#include "linkextractor_tests.h"
+
+#define LINK_TEMPLATE_PATH TEST_DATA_DIR "/links"
+
+#define BASEURL "http://example.com/index.html"
+
+#define HTML1_HREF "http://example.com/test/link"
+#define HTML1_TITLE "Test link"
+#define HTML1 "<html><body>" \
+ "<a href=\"" HTML1_HREF "\">" HTML1_TITLE "</a>" \
+ "</body></html>"
+
+#define HTML2_HREF "http://example.com/test/link"
+#define HTML2_TITLE "Test link"
+#define HTML2 "<html><body>" \
+ "<a href=\"" HTML2_HREF "\">" HTML2_TITLE "</a>" \
+ "<a href=\"http://example.com/index.html\">This is an unrecognized link</a>" \
+ "</body></html>"
+
+#define HTML3_HEADER "<html><body>"
+#define HTML3_HREF "http://example.com/test/link"
+#define HTML3_TITLE "Test link"
+#define HTML3_BODY "<a href=\"" HTML3_HREF "\">" HTML3_TITLE "</a>"
+#define HTML3_FOOTER "</body></html>"
+#define HTML_INVALID "<a hrefxxx=0</a>"
+
+#define HTML4_HREF "/test/link"
+#define HTML4_HREF_ABSOLUTE "http://example.com" HTML4_HREF
+#define HTML4_TITLE "Relative link"
+#define HTML4 "<html><body>" \
+ "<a href=\"" HTML4_HREF "\">" HTML4_TITLE "</a>" \
+ "</body></html>"
+
+#define HTML5_HREF "http://example.com/test/link"
+#define HTML5_TITLE "Test link"
+#define HTML5 "<html><body>" \
+ "<a href=\"" HTML5_HREF "\"><span><b> Test</b></span> <span>link</span></a>" \
+ "</body></html>"
+
+
+void link_extractor_fixture_setup(LinkExtractorFixture *fixture,
+ gconstpointer test_data) {
+ fixture->templates = link_templates_create();
+ g_assert(fixture->templates != NULL);
+ link_templates_load(fixture->templates, LINK_TEMPLATE_PATH);
+
+ fixture->extractor = link_extractor_create(fixture->templates, BASEURL);
+ g_assert(fixture->extractor != NULL);
+}
+
+void link_extractor_fixture_teardown(LinkExtractorFixture *fixture,
+ gconstpointer test_data) {
+ link_extractor_delete(fixture->extractor);
+ link_templates_delete(fixture->templates);
+}
+
+void test_link_extractor_extract(LinkExtractorFixture *fixture,
+ G_GNUC_UNUSED gconstpointer test_data) {
+ GPtrArray *links;
+ link_extractor_append(fixture->extractor, HTML1, strlen(HTML1));
+ links = link_extractor_get_links(fixture->extractor);
+ g_assert(links);
+ g_assert(links->len == 1);
+ const struct Link *link = g_ptr_array_index(links, 0);
+ const char *href = link_get_href(link);
+ g_assert(href);
+ g_assert(strcmp(href, HTML1_HREF) == 0);
+ const char *title = link_get_title(link);
+ g_assert(title);
+ g_assert(strcmp(title, HTML1_TITLE) == 0);
+ g_ptr_array_free(links, TRUE);
+}
+
+void test_link_extractor_unrecognized_link(LinkExtractorFixture *fixture,
+ G_GNUC_UNUSED gconstpointer test_data) {
+ GPtrArray *links;
+ link_extractor_append(fixture->extractor, HTML2, strlen(HTML2));
+ links = link_extractor_get_links(fixture->extractor);
+ g_assert(links);
+ g_assert(links->len == 1);
+ const struct Link *link = g_ptr_array_index(links, 0);
+ const char *href = link_get_href(link);
+ g_assert(href);
+ g_assert(strcmp(href, HTML2_HREF) == 0);
+ const char *title = link_get_title(link);
+ g_assert(title);
+ g_assert(strcmp(title, HTML2_TITLE) == 0);
+ g_ptr_array_free(links, TRUE);
+}
+
+void test_link_extractor_append(LinkExtractorFixture *fixture,
+ G_GNUC_UNUSED gconstpointer test_data) {
+ GPtrArray *links;
+ link_extractor_append(fixture->extractor, HTML3_HEADER, strlen(HTML3_HEADER));
+ link_extractor_append(fixture->extractor, HTML3_BODY, strlen(HTML3_BODY));
+ link_extractor_append(fixture->extractor, HTML3_FOOTER, strlen(HTML3_FOOTER));
+ links = link_extractor_get_links(fixture->extractor);
+ g_assert(links);
+ g_assert(links->len == 1);
+ const struct Link *link = g_ptr_array_index(links, 0);
+ const char *href = link_get_href(link);
+ g_assert(href);
+ g_assert(strcmp(href, HTML3_HREF) == 0);
+ const char *title = link_get_title(link);
+ g_assert(title);
+ g_assert(strcmp(title, HTML3_TITLE) == 0);
+ g_ptr_array_free(links, TRUE);
+}
+
+void test_link_extractor_invalid_html(LinkExtractorFixture *fixture,
+ G_GNUC_UNUSED gconstpointer test_data) {
+ GPtrArray *links;
+ link_extractor_append(fixture->extractor, HTML_INVALID, strlen(HTML_INVALID));
+ links = link_extractor_get_links(fixture->extractor);
+ g_assert(links);
+ g_assert(links->len == 0);
+ g_ptr_array_free(links, TRUE);
+}
+
+void test_link_extractor_relative_urls(LinkExtractorFixture *fixture,
+ G_GNUC_UNUSED gconstpointer test_data) {
+ GPtrArray *links;
+ link_extractor_append(fixture->extractor, HTML4, strlen(HTML4));
+ links = link_extractor_get_links(fixture->extractor);
+ g_assert(links);
+ g_assert(links->len == 1);
+ const struct Link *link = g_ptr_array_index(links, 0);
+ const char *href = link_get_href(link);
+ g_assert(href);
+ g_assert(strcmp(href, HTML4_HREF_ABSOLUTE) == 0);
+ const char *title = link_get_title(link);
+ g_assert(title);
+ g_assert(strcmp(title, HTML4_TITLE) == 0);
+ g_ptr_array_free(links, TRUE);
+}
+
+void test_link_extractor_html_title(LinkExtractorFixture *fixture,
+ G_GNUC_UNUSED gconstpointer test_data) {
+ GPtrArray *links;
+ link_extractor_append(fixture->extractor, HTML5, strlen(HTML5));
+ links = link_extractor_get_links(fixture->extractor);
+ g_assert(links);
+ g_assert(links->len == 1);
+ const struct Link *link = g_ptr_array_index(links, 0);
+ const char *href = link_get_href(link);
+ g_assert(href);
+ g_assert(strcmp(href, HTML5_HREF) == 0);
+ const char *title = link_get_title(link);
+ g_assert(title);
+ g_assert(strcmp(title, HTML5_TITLE) == 0);
+ g_ptr_array_free(links, TRUE);
+}
+
+void test_link_extractor_xml(LinkExtractorFixture *fixture,
+ gconstpointer test_data) {
+
+}
diff --git a/tests/linkextractor_tests.h b/tests/linkextractor_tests.h
new file mode 100644
index 0000000..49d2c7f
--- /dev/null
+++ b/tests/linkextractor_tests.h
@@ -0,0 +1,34 @@
+#ifndef LINK_EXTRACTOR_TESTS_H
+#define LINK_EXTRACTOR_TESTS_H
+
+#include "linkextractor.h"
+#include "linktemplates_tests.h"
+
+typedef struct {
+ struct LinkTemplates *templates;
+ struct LinkExtractor *extractor;
+} LinkExtractorFixture;
+
+void link_extractor_fixture_setup(LinkExtractorFixture *fixture,
+ gconstpointer test_data);
+void link_extractor_fixture_teardown(LinkExtractorFixture *fixture,
+ gconstpointer test_data);
+
+void test_link_extractor_extract(LinkExtractorFixture *fixture,
+ gconstpointer test_data);
+void test_link_extractor_unrecognized_link(LinkExtractorFixture *fixture,
+ gconstpointer test_data);
+void test_link_extractor_append(LinkExtractorFixture *fixture,
+ gconstpointer test_data);
+void test_link_extractor_invalid_html(LinkExtractorFixture *fixture,
+ gconstpointer test_data);
+void test_link_extractor_relative_urls(LinkExtractorFixture *fixture,
+ gconstpointer test_data);
+void test_link_extractor_html_title(LinkExtractorFixture *fixture,
+ G_GNUC_UNUSED gconstpointer test_data);
+
+void test_link_extractor_xml(LinkExtractorFixture *fixture,
+ gconstpointer test_data);
+
+
+#endif // LINK_EXTRACTOR_TESTS_H
diff --git a/tests/linktemplates_tests.c b/tests/linktemplates_tests.c
new file mode 100644
index 0000000..bc15e15
--- /dev/null
+++ b/tests/linktemplates_tests.c
@@ -0,0 +1,46 @@
+#include "linktemplates_tests.h"
+
+#define LINK_TEMPLATES_TEST_FILE TEST_DATA_DIR "/links"
+#define TEST_REGULAR_LINK "http://example.com/test/testpage.html"
+#define TEST_IGNORED_LINK "http://example.com/ignoredpage.html"
+#define TEST_STREAM_LINK "http://example.com/video/videopage.html"
+
+void link_templates_fixture_setup(LinkTemplatesFixture *fixture,
+ G_GNUC_UNUSED gconstpointer test_data)
+{
+ fixture->templates = link_templates_create();
+ g_assert(fixture->templates != NULL);
+ link_templates_load(fixture->templates, LINK_TEMPLATES_TEST_FILE);
+}
+
+void link_templates_fixture_teardown(LinkTemplatesFixture *fixture,
+ G_GNUC_UNUSED gconstpointer test_data)
+{
+ link_templates_delete(fixture->templates);
+ fixture->templates = NULL;
+}
+
+void test_link_templates_load(LinkTemplatesFixture *fixture,
+ G_GNUC_UNUSED gconstpointer test_data)
+{
+ g_assert(link_templates_size(fixture->templates) >= 1);
+}
+
+void test_link_templates_get(LinkTemplatesFixture *fixture,
+ G_GNUC_UNUSED gconstpointer test_data)
+{
+ const struct LinkAction *action;
+ action = link_templates_get_action(fixture->templates, TEST_REGULAR_LINK);
+ g_assert(action);
+ g_assert(link_action_get_type(action) == LINK_ACTION_PARSE);
+
+ action = link_templates_get_action(fixture->templates, TEST_IGNORED_LINK);
+ g_assert(!action);
+
+ action = link_templates_get_action(fixture->templates, TEST_STREAM_LINK);
+ g_assert(action);
+ g_assert(link_action_get_type(action) == LINK_ACTION_EXTERNAL_COMMAND);
+ const char *command = link_action_get_command(action);
+ g_assert(command);
+ g_assert(strcmp(command, "test_command") == 0);
+}
diff --git a/tests/linktemplates_tests.h b/tests/linktemplates_tests.h
new file mode 100644
index 0000000..d718d61
--- /dev/null
+++ b/tests/linktemplates_tests.h
@@ -0,0 +1,23 @@
+#ifndef LINK_TEMPLATES_TESTS_H
+#define LINK_TEMPLATES_TESTS_H
+
+#include <unistd.h>
+#include <glib.h>
+#include "linktemplates.h"
+
+typedef struct {
+ struct LinkTemplates *templates;
+} LinkTemplatesFixture;
+
+
+void link_templates_fixture_setup(LinkTemplatesFixture *fixture,
+ gconstpointer test_data);
+void link_templates_fixture_teardown(LinkTemplatesFixture *fixture,
+ gconstpointer test_data);
+
+void test_link_templates_load(LinkTemplatesFixture *fixture,
+ gconstpointer test_data);
+void test_link_templates_get(LinkTemplatesFixture *fixture,
+ gconstpointer test_data);
+
+#endif // LINK_TEMPLATES_TESTS_H
diff --git a/tests/menubuilder_tests.c b/tests/menubuilder_tests.c
new file mode 100644
index 0000000..a34f470
--- /dev/null
+++ b/tests/menubuilder_tests.c
@@ -0,0 +1,155 @@
+#include <string.h>
+#include <stdlib.h>
+#include <stdbool.h>
+#include <libxml/parser.h>
+#include <libxml/tree.h>
+#include "menubuilder_tests.h"
+#include "link.h"
+#include "mainmenu.h"
+
+#define TEST_TITLE "Test menu"
+#define LINK1_HREF "http://example.com/test/link"
+#define LINK1_TITLE "Test link"
+#define LINK2_HREF "http://example.com/video/00001"
+#define LINK2_TITLE "Test stream"
+#define LINK3_HREF "http://example.com/test/link3"
+#define LINK3_TITLE "(large > small) & {50% of huge?}"
+#define LINK3_TITLE_ENCODED "(large &gt; small) &amp; {50% of huge?}"
+
+#define TITLE_TAG "<h1>"
+#define LINK_TAG "<a "
+
+static bool contains_substring(const char *buffer, const char *substr);
+static int count_nonoverlapping_substrings(const char *buffer, const char *substr);
+static void free_link(gpointer data);
+
+void menu_builder_fixture_setup(MenuBuilderFixture *fixture,
+ G_GNUC_UNUSED gconstpointer test_data) {
+ fixture->menu_builder = menu_builder_create();
+ g_assert(fixture->menu_builder != NULL);
+}
+
+void menu_builder_fixture_teardown(MenuBuilderFixture *fixture,
+ G_GNUC_UNUSED gconstpointer test_data) {
+ menu_builder_delete(fixture->menu_builder);
+ fixture->menu_builder = NULL;
+}
+
+void test_menu_builder_title(MenuBuilderFixture *fixture,
+ G_GNUC_UNUSED gconstpointer test_data) {
+ menu_builder_set_title(fixture->menu_builder, TEST_TITLE);
+ char *menu = menu_builder_to_string(fixture->menu_builder);
+ g_assert(menu != NULL);
+ g_assert(contains_substring(menu, TEST_TITLE));
+ int numlinks = count_nonoverlapping_substrings(menu, LINK_TAG);
+ g_assert(numlinks == 0);
+ free(menu);
+}
+
+void test_menu_builder_append_links(MenuBuilderFixture *fixture,
+ G_GNUC_UNUSED gconstpointer test_data) {
+ GPtrArray *links = g_ptr_array_new_with_free_func(free_link);
+ g_assert(links != NULL);
+ g_ptr_array_add(links, link_create(LINK1_HREF, LINK1_TITLE, LINK_ACTION_PARSE));
+ g_ptr_array_add(links, link_create(LINK2_HREF, LINK2_TITLE, LINK_ACTION_EXTERNAL_COMMAND));
+
+ menu_builder_append_link_list(fixture->menu_builder, links);
+ char *menu = menu_builder_to_string(fixture->menu_builder);
+ g_assert(menu != NULL);
+ int numlinks = count_nonoverlapping_substrings(menu, LINK_TAG);
+ g_assert(numlinks == 2);
+ g_assert(contains_substring(menu, LINK1_HREF));
+ g_assert(contains_substring(menu, LINK1_TITLE));
+ g_assert(contains_substring(menu, LINK2_HREF));
+ g_assert(contains_substring(menu, LINK2_TITLE));
+
+ free(menu);
+ g_ptr_array_free(links, TRUE);
+}
+
+void test_menu_builder_link_title_encoding(MenuBuilderFixture *fixture,
+ G_GNUC_UNUSED gconstpointer test_data) {
+ GPtrArray *links = g_ptr_array_new_with_free_func(free_link);
+ g_ptr_array_add(links, link_create(LINK3_HREF, LINK3_TITLE, LINK_ACTION_PARSE));
+
+ menu_builder_append_link_list(fixture->menu_builder, links);
+ char *menu = menu_builder_to_string(fixture->menu_builder);
+ g_assert(menu != NULL);
+ g_assert(contains_substring(menu, LINK3_TITLE_ENCODED));
+
+ free(menu);
+ g_ptr_array_free(links, TRUE);
+}
+
+void test_mainmenu() {
+ char *menu = build_mainmenu(TEST_DATA_DIR "/websites");
+ g_assert(menu);
+
+ xmlDoc *doc = xmlReadMemory(menu, strlen(menu), "mainmenu.xml", NULL, 0);
+ g_assert(doc);
+ xmlNode *root = xmlDocGetRootElement(doc);
+ g_assert(root);
+ g_assert(xmlStrEqual(root->name, BAD_CAST "wvmenu"));
+
+ unsigned int title_count = 0;
+ unsigned int link_count = 0;
+ unsigned int ul_count = 0;
+ xmlNode *node;
+ for (node = root->children; node; node = node->next) {
+ if (xmlStrEqual(node->name, BAD_CAST "title")) {
+ title_count++;
+
+ } else if (xmlStrEqual(node->name, BAD_CAST "ul")) {
+ ul_count++;
+
+ xmlNode *li_node;
+ for (li_node = node->children; li_node; li_node = li_node->next) {
+ g_assert(xmlStrEqual(li_node->name, BAD_CAST "li"));
+
+ xmlNode *a_node;
+ for (a_node = li_node->children; a_node; a_node = a_node->next) {
+ g_assert(xmlStrEqual(a_node->name, BAD_CAST "a"));
+ g_assert(xmlHasProp(a_node, BAD_CAST "href"));
+ link_count++;
+ }
+ }
+
+ } else if (node->type != XML_TEXT_NODE) {
+ g_assert_not_reached();
+ }
+ }
+
+ g_assert(title_count == 1);
+ g_assert(ul_count == 1);
+ g_assert(link_count >= 1);
+
+ xmlFreeDoc(doc);
+ free(menu);
+}
+
+int count_nonoverlapping_substrings(const char *buffer, const char *substr) {
+ if (!buffer || !substr)
+ return 0;
+
+ int count = 0;
+ int substrlen = strlen(substr);
+ const char *p = buffer;
+
+ while ((p = strstr(p, substr))) {
+ p += substrlen;
+ count++;
+ }
+
+ return count;
+}
+
+bool contains_substring(const char *buffer, const char *substr) {
+ if (!buffer || !substr)
+ return false;
+
+ return strstr(buffer, substr) != NULL;
+}
+
+void free_link(gpointer data) {
+ link_delete((struct Link *)data);
+}
diff --git a/tests/menubuilder_tests.h b/tests/menubuilder_tests.h
new file mode 100644
index 0000000..8373224
--- /dev/null
+++ b/tests/menubuilder_tests.h
@@ -0,0 +1,26 @@
+#ifndef MENU_BUILDER_TESTS_H
+#define MENU_BUILDER_TESTS_H
+
+#include <glib.h>
+#include "menubuilder.h"
+
+typedef struct {
+ struct MenuBuilder *menu_builder;
+} MenuBuilderFixture;
+
+
+void menu_builder_fixture_setup(MenuBuilderFixture *fixture,
+ gconstpointer test_data);
+void menu_builder_fixture_teardown(MenuBuilderFixture *fixture,
+ gconstpointer test_data);
+
+void test_menu_builder_title(MenuBuilderFixture *fixture,
+ gconstpointer test_data);
+void test_menu_builder_append_links(MenuBuilderFixture *fixture,
+ gconstpointer test_data);
+void test_menu_builder_link_title_encoding(MenuBuilderFixture *fixture,
+ gconstpointer test_data);
+
+void test_mainmenu();
+
+#endif // MENU_BUILDER_TESTS_H
diff --git a/tests/pipe_tests.c b/tests/pipe_tests.c
new file mode 100644
index 0000000..0dd15ba
--- /dev/null
+++ b/tests/pipe_tests.c
@@ -0,0 +1,246 @@
+#include <stdlib.h>
+#include <string.h>
+#include <glib.h>
+#include "pipecomponent.h"
+#include "pipe_tests.h"
+
+#define TEST_STRING "ABCDEF"
+#define TEST_FD1 1
+#define TEST_FD2 2
+
+typedef struct CountingPipe {
+ PipeComponent p;
+ size_t bytes;
+ gboolean finished;
+ gboolean failed;
+} CountingPipe;
+
+static gboolean delete1_called;
+static gboolean delete2_called;
+
+static CountingPipe *testpipe_create(
+ gboolean (*process)(PipeComponent *, char *, size_t),
+ void (*finished)(PipeComponent *, RequestState state),
+ void (*delete)(PipeComponent *));
+static CountingPipe *testpipe_create_fdset(
+ gboolean (*process)(PipeComponent *, char *, size_t),
+ void (*finished)(PipeComponent *, RequestState state),
+ void (*delete)(PipeComponent *),
+ void (*fdset)(PipeComponent *, fd_set *, fd_set *, fd_set *, int *),
+ gboolean (*handle_socket)(PipeComponent *, int, int));
+static gboolean testpipe_forward(PipeComponent *component, char *buf, size_t len);
+static gboolean testpipe_fail(PipeComponent *component, char *buf, size_t len);
+static void testpipe_fdset1(PipeComponent *self, fd_set *readfd,
+ fd_set *writefd, fd_set *excfd, int *max_fd);
+static void testpipe_fdset2(PipeComponent *self, fd_set *readfd,
+ fd_set *writefd, fd_set *excfd, int *max_fd);
+static void testpipe_finished(PipeComponent *component, RequestState state);
+static void testpipe_delete(PipeComponent *component);
+static void testpipe_delete1(PipeComponent *component);
+static void testpipe_delete2(PipeComponent *component);
+
+void test_pipe_one_component() {
+ CountingPipe *pipe =
+ testpipe_create(testpipe_forward, testpipe_finished, testpipe_delete);
+
+ pipe_component_append(&pipe->p, TEST_STRING, strlen(TEST_STRING));
+ g_assert(!pipe->finished);
+ g_assert(!pipe->failed);
+ g_assert(pipe_component_get_state(&pipe->p) == WEBVISTATE_NOT_FINISHED);
+ g_assert(pipe->bytes == strlen(TEST_STRING));
+
+ pipe_component_finished(&pipe->p, WEBVISTATE_FINISHED_OK);
+ g_assert(pipe->finished);
+ g_assert(!pipe->failed);
+ g_assert(pipe_component_get_state(&pipe->p) == WEBVISTATE_FINISHED_OK);
+ g_assert(pipe->bytes == strlen(TEST_STRING));
+
+ pipe_delete_full(&pipe->p);
+}
+
+void test_pipe_not_appending_after_finished() {
+ CountingPipe *pipe =
+ testpipe_create(testpipe_forward, testpipe_finished, testpipe_delete);
+
+ pipe_component_append(&pipe->p, TEST_STRING, strlen(TEST_STRING));
+ g_assert(pipe->bytes == strlen(TEST_STRING));
+
+ pipe_component_finished(&pipe->p, WEBVISTATE_FINISHED_OK);
+
+ pipe_component_append(&pipe->p, TEST_STRING, strlen(TEST_STRING));
+ g_assert(pipe->bytes == strlen(TEST_STRING));
+
+ pipe_delete_full(&pipe->p);
+}
+
+void test_pipe_state_not_chaning_after_finished() {
+ CountingPipe *pipe =
+ testpipe_create(testpipe_forward, testpipe_finished, testpipe_delete);
+
+ pipe_component_append(&pipe->p, TEST_STRING, strlen(TEST_STRING));
+ g_assert(pipe_component_get_state(&pipe->p) == WEBVISTATE_NOT_FINISHED);
+
+ pipe_component_finished(&pipe->p, WEBVISTATE_INTERNAL_ERROR);
+ g_assert(pipe_component_get_state(&pipe->p) == WEBVISTATE_INTERNAL_ERROR);
+
+ pipe_component_finished(&pipe->p, WEBVISTATE_FINISHED_OK);
+ g_assert(pipe_component_get_state(&pipe->p) == WEBVISTATE_INTERNAL_ERROR);
+
+ pipe_delete_full(&pipe->p);
+}
+
+void test_pipe_two_components() {
+ CountingPipe *first =
+ testpipe_create(testpipe_forward, testpipe_finished, testpipe_delete);
+ CountingPipe *second =
+ testpipe_create(testpipe_forward, testpipe_finished, testpipe_delete);
+ pipe_component_set_next(&first->p, &second->p);
+
+ pipe_component_append(&first->p, TEST_STRING, strlen(TEST_STRING));
+ pipe_component_finished(&first->p, WEBVISTATE_FINISHED_OK);
+
+ g_assert(first->finished);
+ g_assert(!first->failed);
+ g_assert(first->bytes == strlen(TEST_STRING));
+ g_assert(second->finished);
+ g_assert(!second->failed);
+ g_assert(second->bytes == strlen(TEST_STRING));
+
+ pipe_delete_full(&first->p);
+}
+
+void test_pipe_failing_component() {
+ CountingPipe *first =
+ testpipe_create(testpipe_fail, testpipe_finished, testpipe_delete);
+ CountingPipe *second =
+ testpipe_create(testpipe_forward, testpipe_finished, testpipe_delete);
+ pipe_component_set_next(&first->p, &second->p);
+
+ pipe_component_append(&first->p, TEST_STRING, strlen(TEST_STRING));
+ pipe_component_finished(&first->p, WEBVISTATE_FINISHED_OK);
+
+ g_assert(first->failed);
+ g_assert(second->finished);
+ g_assert(second->failed);
+ g_assert(second->bytes == 0);
+
+ pipe_delete_full(&first->p);
+}
+
+void test_pipe_delete_all() {
+ CountingPipe *first =
+ testpipe_create(testpipe_forward, testpipe_finished, testpipe_delete1);
+ CountingPipe *second =
+ testpipe_create(testpipe_forward, testpipe_finished, testpipe_delete2);
+ pipe_component_set_next(&first->p, &second->p);
+
+ delete1_called = FALSE;
+ delete2_called = FALSE;
+
+ pipe_delete_full(&first->p);
+
+ g_assert(delete1_called);
+ g_assert(delete2_called);
+}
+
+void test_pipe_fdset() {
+ fd_set readfds;
+ fd_set writefds;
+ fd_set excfds;
+ int maxfd = 0;
+ CountingPipe *first =
+ testpipe_create_fdset(testpipe_forward, testpipe_finished,
+ testpipe_delete, testpipe_fdset1, NULL);
+ CountingPipe *second =
+ testpipe_create_fdset(testpipe_forward, testpipe_finished,
+ testpipe_delete, testpipe_fdset2, NULL);
+ pipe_component_set_next(&first->p, &second->p);
+
+ FD_ZERO(&readfds);
+ FD_ZERO(&writefds);
+ FD_ZERO(&excfds);
+ pipe_fdset(&first->p, &readfds, &writefds, &excfds, &maxfd);
+ g_assert(FD_ISSET(TEST_FD1, &readfds));
+ g_assert(FD_ISSET(TEST_FD2, &readfds));
+
+ pipe_delete_full(&first->p);
+}
+
+CountingPipe *testpipe_create(
+ gboolean (*process)(PipeComponent *, char *, size_t),
+ void (*finished)(PipeComponent *, RequestState state),
+ void (*delete)(PipeComponent *))
+{
+ CountingPipe *pipe = malloc(sizeof(CountingPipe));
+ g_assert(pipe);
+ memset(pipe, 0, sizeof(CountingPipe));
+ pipe_component_initialize(&pipe->p, process, finished, delete);
+ return pipe;
+}
+
+CountingPipe *testpipe_create_fdset(
+ gboolean (*process)(PipeComponent *, char *, size_t),
+ void (*finished)(PipeComponent *, RequestState state),
+ void (*delete)(PipeComponent *),
+ void (*fdset)(PipeComponent *, fd_set *, fd_set *, fd_set *, int *),
+ gboolean (*handle_socket)(PipeComponent *, int, int))
+{
+ CountingPipe *pipe = malloc(sizeof(CountingPipe));
+ g_assert(pipe);
+ memset(pipe, 0, sizeof(CountingPipe));
+ pipe_component_initialize_fdset(&pipe->p, process, finished, delete,
+ fdset, handle_socket);
+ return pipe;
+}
+
+gboolean testpipe_forward(PipeComponent *component, char *buf, size_t len) {
+ CountingPipe *self = (CountingPipe *)component;
+ self->bytes += len;
+ return TRUE;
+}
+
+gboolean testpipe_fail(PipeComponent *component, char *buf, size_t len) {
+ CountingPipe *self = (CountingPipe *)component;
+ pipe_component_finished(component, WEBVISTATE_INTERNAL_ERROR);
+ return TRUE;
+}
+
+void testpipe_fdset1(PipeComponent *self, fd_set *readfd,
+ fd_set *writefd, fd_set *excfd, int *max_fd)
+{
+ FD_SET(TEST_FD1, readfd);
+ if (TEST_FD1 > *max_fd)
+ *max_fd = TEST_FD1;
+}
+
+void testpipe_fdset2(PipeComponent *self, fd_set *readfd,
+ fd_set *writefd, fd_set *excfd, int *max_fd)
+{
+ FD_SET(TEST_FD2, readfd);
+ if (TEST_FD2 > *max_fd)
+ *max_fd = TEST_FD2;
+}
+
+void testpipe_finished(PipeComponent *component, RequestState state) {
+ CountingPipe *self = (CountingPipe *)component;
+ self->finished = TRUE;
+ if (state != WEBVISTATE_FINISHED_OK)
+ self->failed = TRUE;
+}
+
+void testpipe_delete(PipeComponent *component) {
+ CountingPipe *self = (CountingPipe *)component;
+ free(self);
+}
+
+void testpipe_delete1(PipeComponent *component) {
+ CountingPipe *self = (CountingPipe *)component;
+ delete1_called = TRUE;
+ free(self);
+}
+
+void testpipe_delete2(PipeComponent *component) {
+ CountingPipe *self = (CountingPipe *)component;
+ delete2_called = TRUE;
+ free(self);
+}
diff --git a/tests/pipe_tests.h b/tests/pipe_tests.h
new file mode 100644
index 0000000..4ed02c2
--- /dev/null
+++ b/tests/pipe_tests.h
@@ -0,0 +1,12 @@
+#ifndef PIPE_TESTS_H
+#define PIPE_TESTS_H
+
+void test_pipe_one_component();
+void test_pipe_two_components();
+void test_pipe_failing_component();
+void test_pipe_not_appending_after_finished();
+void test_pipe_state_not_chaning_after_finished();
+void test_pipe_delete_all();
+void test_pipe_fdset();
+
+#endif // PIPE_TESTS_H
diff --git a/tests/urlutils_tests.c b/tests/urlutils_tests.c
new file mode 100644
index 0000000..da5f9e1
--- /dev/null
+++ b/tests/urlutils_tests.c
@@ -0,0 +1,227 @@
+#include "urlutils_tests.h"
+#include "urlutils.h"
+
+void test_url_scheme() {
+ gchar *prefix = url_scheme("http://example.com/");
+ g_assert(prefix);
+ g_assert(strcmp(prefix, "http") == 0);
+ g_free(prefix);
+}
+
+void test_url_scheme_no_scheme() {
+ gchar *prefix = url_scheme("example.com/");
+ g_assert(prefix);
+ g_assert(strcmp(prefix, "") == 0);
+ g_free(prefix);
+}
+
+void test_url_scheme_double_scheme() {
+ gchar *prefix = url_scheme("ftp://http://example.com/");
+ g_assert(prefix);
+ g_assert(strcmp(prefix, "ftp") == 0);
+ g_free(prefix);
+}
+
+void test_url_scheme_invalid_characters() {
+ gchar *prefix = url_scheme("invalid/http://example.com/");
+ g_assert(prefix);
+ g_assert(strcmp(prefix, "") == 0);
+ g_free(prefix);
+}
+
+void test_url_root() {
+ gchar *prefix = url_root("http://example.com/");
+ g_assert(prefix);
+ g_assert(strcmp(prefix, "http://example.com/") == 0);
+ g_free(prefix);
+}
+
+void test_url_root_full_path() {
+ gchar *prefix = url_root("http://example.com/path/to/file.html");
+ g_assert(prefix);
+ g_assert(strcmp(prefix, "http://example.com/") == 0);
+ g_free(prefix);
+}
+
+void test_url_root_terminated_by_query() {
+ gchar *prefix = url_root("http://example.com?query=path");
+ g_assert(prefix);
+ g_assert(strcmp(prefix, "http://example.com/") == 0);
+ g_free(prefix);
+}
+
+void test_url_path() {
+ gchar *prefix = url_path_including_file("http://example.com/path/to/file.html");
+ g_assert(prefix);
+ g_assert(strcmp(prefix, "http://example.com/path/to/file.html") == 0);
+ g_free(prefix);
+}
+
+void test_url_path_ends_in_slash() {
+ gchar *prefix = url_path_including_file("http://example.com/path/");
+ g_assert(prefix);
+ g_assert(strcmp(prefix, "http://example.com/path/") == 0);
+ g_free(prefix);
+}
+
+void test_url_path_query() {
+ gchar *prefix = url_path_including_file("http://example.com/path/to/file.html?foo=bar");
+ g_assert(prefix);
+ g_assert(strcmp(prefix, "http://example.com/path/to/file.html") == 0);
+ g_free(prefix);
+}
+
+void test_url_path_fragment() {
+ gchar *prefix = url_path_including_file("http://example.com/path/to/file.html#frag");
+ g_assert(prefix);
+ g_assert(strcmp(prefix, "http://example.com/path/to/file.html") == 0);
+ g_free(prefix);
+}
+
+void test_url_path_no_path() {
+ gchar *prefix = url_path_including_file("http://example.com");
+ g_assert(prefix);
+ g_assert(strcmp(prefix, "http://example.com/") == 0);
+ g_free(prefix);
+}
+
+void test_url_path_no_server() {
+ gchar *prefix = url_path_including_file("http:///path/file.html");
+ g_assert(prefix);
+ g_assert(strcmp(prefix, "http:///path/file.html") == 0);
+ g_free(prefix);
+}
+
+void test_url_path_no_scheme() {
+ gchar *prefix = url_path_including_file("example.com/path/file.html");
+ g_assert(prefix);
+ g_assert(strcmp(prefix, "example.com/path/file.html") == 0);
+ g_free(prefix);
+}
+
+void test_url_path_dirname() {
+ gchar *prefix = url_path_dirname("http://example.com/path/to/file.html");
+ g_assert(prefix);
+ g_assert(strcmp(prefix, "http://example.com/path/to/") == 0);
+ g_free(prefix);
+}
+
+void test_url_path_dirname_no_file() {
+ gchar *prefix = url_path_dirname("http://example.com/path/to/");
+ g_assert(prefix);
+ g_assert(strcmp(prefix, "http://example.com/path/to/") == 0);
+ g_free(prefix);
+}
+
+void test_url_path_dirname_query() {
+ gchar *prefix = url_path_dirname("http://example.com/path/to/file.html?foo=bar");
+ g_assert(prefix);
+ g_assert(strcmp(prefix, "http://example.com/path/to/") == 0);
+ g_free(prefix);
+}
+
+void test_url_path_dirname_no_server() {
+ gchar *prefix = url_path_dirname("/path/to/file.html");
+ g_assert(prefix);
+ g_assert(strcmp(prefix, "/path/to/") == 0);
+ g_free(prefix);
+}
+
+void test_url_path_and_query() {
+ gchar *prefix = url_path_and_query("http://example.com/path/to/file.html?foo=1&bar=2");
+ g_assert(prefix);
+ g_assert(strcmp(prefix, "http://example.com/path/to/file.html?foo=1&bar=2") == 0);
+ g_free(prefix);
+}
+
+void test_url_path_and_query_no_query() {
+ gchar *prefix = url_path_and_query("http://example.com/path/to/file.html");
+ g_assert(prefix);
+ g_assert(strcmp(prefix, "http://example.com/path/to/file.html") == 0);
+ g_free(prefix);
+}
+
+void test_url_path_and_query_double_query() {
+ gchar *prefix = url_path_and_query("http://example.com/path/to/file.html?foo=1?bar=2");
+ g_assert(prefix);
+ g_assert(strcmp(prefix, "http://example.com/path/to/file.html?foo=1?bar=2") == 0);
+ g_free(prefix);
+}
+
+void test_url_path_and_query_fragment() {
+ gchar *prefix = url_path_and_query("http://example.com/path/to/file.html?foo=1&bar=2#frag");
+ g_assert(prefix);
+ g_assert(strcmp(prefix, "http://example.com/path/to/file.html?foo=1&bar=2") == 0);
+ g_free(prefix);
+}
+
+void test_url_path_and_query_no_path() {
+ gchar *prefix = url_path_and_query("?foo=1&bar=2");
+ g_assert(prefix);
+ g_assert(strcmp(prefix, "?foo=1&bar=2") == 0);
+ g_free(prefix);
+}
+
+void test_url_rel2abs_file() {
+ gchar *abs = relative_url_to_absolute("http://example.com/index.html",
+ "file.html");
+ g_assert(abs);
+ g_assert(strcmp(abs, "http://example.com/file.html") == 0);
+ g_free(abs);
+}
+
+void test_url_rel2abs_root() {
+ gchar *abs = relative_url_to_absolute("http://example.com/path/index.html",
+ "/another/path/file.html");
+ g_assert(abs);
+ g_assert(strcmp(abs, "http://example.com/another/path/file.html") == 0);
+ g_free(abs);
+}
+
+void test_url_rel2abs_query() {
+ gchar *abs = relative_url_to_absolute("http://example.com/index.html?foo=1",
+ "?bar=2");
+ g_assert(abs);
+ g_assert(strcmp(abs, "http://example.com/index.html?bar=2") == 0);
+ g_free(abs);
+}
+
+void test_url_rel2abs_double_query() {
+ gchar *abs = relative_url_to_absolute("http://example.com/index.html?foo=1?bar=2",
+ "?baz=3");
+ g_assert(abs);
+ g_assert(strcmp(abs, "http://example.com/index.html?baz=3") == 0);
+ g_free(abs);
+}
+
+void test_url_rel2abs_append_query() {
+ gchar *abs = relative_url_to_absolute("http://example.com/index.html",
+ "?bar=2");
+ g_assert(abs);
+ g_assert(strcmp(abs, "http://example.com/index.html?bar=2") == 0);
+ g_free(abs);
+}
+
+void test_url_rel2abs_fragment() {
+ gchar *abs = relative_url_to_absolute("http://example.com/index.html#frag",
+ "#bar");
+ g_assert(abs);
+ g_assert(strcmp(abs, "http://example.com/index.html#bar") == 0);
+ g_free(abs);
+}
+
+void test_url_rel2abs_append_fragment() {
+ gchar *abs = relative_url_to_absolute("http://example.com/index.html",
+ "#bar");
+ g_assert(abs);
+ g_assert(strcmp(abs, "http://example.com/index.html#bar") == 0);
+ g_free(abs);
+}
+
+void test_url_rel2abs_scheme() {
+ gchar *abs = relative_url_to_absolute("http://example.com/index.html",
+ "//server.org/path2/file2");
+ g_assert(abs);
+ g_assert(strcmp(abs, "http://server.org/path2/file2") == 0);
+ g_free(abs);
+}
diff --git a/tests/urlutils_tests.h b/tests/urlutils_tests.h
new file mode 100644
index 0000000..e4c796c
--- /dev/null
+++ b/tests/urlutils_tests.h
@@ -0,0 +1,38 @@
+#ifndef URLUTILS_TESTS_H
+#define URLUTILS_TESTS_H
+
+#include <glib.h>
+
+void test_url_scheme();
+void test_url_scheme_no_scheme();
+void test_url_scheme_double_scheme();
+void test_url_scheme_invalid_characters();
+void test_url_root();
+void test_url_root_full_path();
+void test_url_root_terminated_by_query();
+void test_url_path();
+void test_url_path_ends_in_slash();
+void test_url_path_query();
+void test_url_path_fragment();
+void test_url_path_no_path();
+void test_url_path_no_server();
+void test_url_path_no_scheme();
+void test_url_path_dirname();
+void test_url_path_dirname_no_file();
+void test_url_path_dirname_query();
+void test_url_path_dirname_no_server();
+void test_url_path_and_query();
+void test_url_path_and_query_no_query();
+void test_url_path_and_query_double_query();
+void test_url_path_and_query_fragment();
+void test_url_path_and_query_no_path();
+void test_url_rel2abs_file();
+void test_url_rel2abs_root();
+void test_url_rel2abs_query();
+void test_url_rel2abs_double_query();
+void test_url_rel2abs_append_query();
+void test_url_rel2abs_fragment();
+void test_url_rel2abs_append_fragment();
+void test_url_rel2abs_scheme();
+
+#endif // URLUTILS_TESTS_H