Index: HelenOS.config
===================================================================
--- HelenOS.config	(revision 58f26cbc0c1d3b1eee97b21bf0c30c8d9de4acd5)
+++ HelenOS.config	(revision bf45993c05fbff161c55a858a73b7488e832d63c)
@@ -600,4 +600,10 @@
 ! CONFIG_WRITE_CORE_FILES (n/y)
 
+% Include userspace unit tests (PCUT)
+! CONFIG_PCUT_TESTS (n/y)
+
+% Include PCUT self-tests
+! CONFIG_PCUT_SELF_TESTS (n/y)
+
 % Include development files (headers, libraries)
 ! CONFIG_DEVEL_FILES (n/y)
Index: boot/Makefile
===================================================================
--- boot/Makefile	(revision 58f26cbc0c1d3b1eee97b21bf0c30c8d9de4acd5)
+++ boot/Makefile	(revision bf45993c05fbff161c55a858a73b7488e832d63c)
@@ -68,4 +68,39 @@
 		cp "$$file" "$(DIST_PATH)/app/" ; \
 	done
+ifeq ($(CONFIG_PCUT_TESTS),y)
+	echo "echo Running all tests..." >"$(DIST_PATH)/test/run_all"
+	echo "<html><head><title>HelenOS test results</title></head><body>" >"$(DIST_PATH)/test/test.html"
+	echo "<h1>HelenOS test results</h1><ul>" >>"$(DIST_PATH)/test/test.html"
+	for file in $(RD_TESTS) ; do \
+		file2=`basename $$file`; \
+		cp "$$file" "$(DIST_PATH)/test/" ; \
+		echo "echo ' ->' $$file2" >>"$(DIST_PATH)/test/run_all"; \
+		echo "/test/$$file2 | to /test/$$file2.out" >>"$(DIST_PATH)/test/run_all"; \
+		echo "cat /test/$$file2.out" >>"$(DIST_PATH)/test/run_all"; \
+		echo "cp -f /test/$$file2.out /data/web/result-$$file2.txt" >>"$(DIST_PATH)/test/run_all"; \
+		echo "<li><a href=\"result-$$file2.txt\">$$file2</a></li>" >>"$(DIST_PATH)/test/test.html"; \
+	done
+	echo "cp -f /test/test.html /data/web/test.html" >>"$(DIST_PATH)/test/run_all"
+	echo "</ul></body></html>" >>"$(DIST_PATH)/test/test.html"
+endif
+
+ifeq ($(CONFIG_PCUT_SELF_TESTS),y)
+	echo "echo Running all PCUT self-tests..." >"$(DIST_PATH)/test/run_pcut"
+	echo "<html><head><title>Results of PCUT self-tests on HelenOS</title></head><body>" >"$(DIST_PATH)/test/pcut.html"
+	echo "<h1>Results of PCUT self-tests on HelenOS</h1><ul>" >>"$(DIST_PATH)/test/pcut.html"
+	for file in $(USPACE_PATH)/lib/pcut/test-libpcut-*; do \
+		file2=`basename $$file`; \
+		name=`echo "$$file2" | sed 's/test-libpcut-//'`; \
+		cp "$$file" "$(DIST_PATH)/test/" ; \
+		echo "echo ' ->' $$name" >>"$(DIST_PATH)/test/run_pcut"; \
+		echo "/test/$$file2 | to /test/$$file2.out" >>"$(DIST_PATH)/test/run_pcut"; \
+		echo "cat /test/$$file2.out" >>"$(DIST_PATH)/test/run_pcut"; \
+		echo "cp -f /test/$$file2.out /data/web/result-$$file2.txt" >>"$(DIST_PATH)/test/run_pcut"; \
+		echo "<li><a href=\"result-$$file2.txt\">$$name</a></li>" >>"$(DIST_PATH)/test/pcut.html"; \
+	done
+	echo "cp -f /test/pcut.html /data/web/pcut.html" >>"$(DIST_PATH)/test/run_pcut"
+	echo "</ul></body></html>" >>"$(DIST_PATH)/test/pcut.html"
+endif
+
 	for drv in $(RD_DRVS) ; do \
 		drv_dir="`dirname "$$drv"`" ; \
@@ -100,3 +135,4 @@
 	rm -rf $(USPACE_PATH)/dist/inc/*
 	rm -f $(USPACE_PATH)/dist/app/*
+	rm -f $(USPACE_PATH)/dist/test/*
 	rm -f $(USPACE_PATH)/dist/cfg/net/*
Index: boot/Makefile.common
===================================================================
--- boot/Makefile.common	(revision 58f26cbc0c1d3b1eee97b21bf0c30c8d9de4acd5)
+++ boot/Makefile.common	(revision bf45993c05fbff161c55a858a73b7488e832d63c)
@@ -221,4 +221,10 @@
 	$(USPACE_PATH)/app/fontviewer/fontviewer
 
+RD_TESTS = \
+	$(USPACE_PATH)/lib/c/test-libc \
+	$(USPACE_PATH)/lib/posix/test-libposix \
+	$(USPACE_PATH)/app/bdsh/test-bdsh
+
+
 COMPONENTS = \
 	$(KERNEL_PATH)/kernel.bin \
Index: uspace/Makefile
===================================================================
--- uspace/Makefile	(revision 58f26cbc0c1d3b1eee97b21bf0c30c8d9de4acd5)
+++ uspace/Makefile	(revision bf45993c05fbff161c55a858a73b7488e832d63c)
@@ -231,4 +231,5 @@
 	lib/usbvirt \
 	lib/pcm \
+	lib/pcut \
 	lib/bithenge \
 	lib/posix \
@@ -240,4 +241,5 @@
 LIBN_BUILD = $(addsuffix .build,$(LIBN))
 BUILDS := $(addsuffix .build,$(DIRS))
+BUILDS_TESTS := $(addsuffix .build-test,$(DIRS) $(LIBS) lib/c)
 
 CLEANS := $(addsuffix .clean,$(DIRS)) $(addsuffix .clean,$(LIBN)) $(addsuffix .clean,$(LIBS)) $(addsuffix .clean,$(LIBC))
@@ -245,5 +247,8 @@
 .PHONY: all $(LIBC_BUILD) $(LIBS_BUILD) $(LIBN_BUILD) $(BUILDS) $(CLEANS) clean
 
-all: $(BUILDS)
+all: $(BUILDS) $(BUILDS_TESTS)
+
+$(BUILDS_TESTS): $(BUILDS)
+	$(MAKE) -C $(basename $@) all-test PRECHECK=$(PRECHECK)
 
 clean: $(CLEANS)
Index: uspace/Makefile.common
===================================================================
--- uspace/Makefile.common	(revision 58f26cbc0c1d3b1eee97b21bf0c30c8d9de4acd5)
+++ uspace/Makefile.common	(revision bf45993c05fbff161c55a858a73b7488e832d63c)
@@ -78,4 +78,5 @@
 	JOB = $(BINARY).job
 	OUTPUT = $(BINARY)
+	TEST_BINARY = test-$(BINARY)
 	EXTRA_OUTPUT += $(BINARY).disasm
 	EXTRA_CLEAN += $(BINARY).map
@@ -85,4 +86,5 @@
 	JOB = $(LIBRARY).job
 	OUTPUT = $(LIBRARY).a
+	TEST_BINARY = test-$(LIBRARY)
 endif
 
@@ -200,8 +202,22 @@
 endif
 
+# PCUT-based unit tests
+ifneq ($(TEST_SOURCES),)
+	TEST_OUTPUT = $(TEST_BINARY)
+	TEST_CFLAGS = -I$(LIB_PREFIX)/pcut/include -D__helenos__
+	TEST_OUTPUT_LIBS = $(LIB_PREFIX)/pcut/libpcut.a
+	EXTRA_CLEAN += $(TEST_OUTPUT) $(TEST_OUTPUT).map
+ifneq ($(LIBRARY),)
+	TEST_OUTPUT_LIBS += $(OUTPUT)
+endif
+	TEST_OUTPUT_LIBS += $(TEST_LIBS)
+endif
+
 .PHONY: all clean
 
 all: $(VERSION_DEF) $(COMMON_MAKEFILE) $(CONFIG_MAKEFILE) $(CONFIG_HEADER) $(LIBS) $(OUTPUT) $(LOUTPUT) $(EXTRA_OUTPUT)
 	-[ -f $(DEPEND) ] && cp -a $(DEPEND) $(DEPEND_PREV)
+
+all-test: $(TEST_OUTPUT)
 
 clean:
@@ -294,4 +310,5 @@
 OBJECTS := $(addsuffix .o,$(basename $(SOURCES)))
 LOBJECTS := $(addsuffix .lo,$(basename $(SOURCES)))
+TEST_OBJECTS := $(addsuffix .test.o,$(basename $(TEST_SOURCES)))
 
 ifneq ($(BINARY),)
@@ -338,4 +355,12 @@
 endif
 
+ifneq ($(TEST_OUTPUT),)
+$(TEST_OUTPUT): $(LINKER_SCRIPT) $(TEST_OBJECTS) $(TEST_OUTPUT_LIBS)
+	$(LD) -n $(LFLAGS) -T $(LINKER_SCRIPT) -M -Map $(TEST_OUTPUT).map -o $@ $(TEST_OBJECTS) $(TEST_OUTPUT_LIBS) $(LIBS) $(BASE_LIBS)
+ifeq ($(CONFIG_STRIP_BINARIES),y)
+	$(STRIP) $(TEST_OUTPUT)
+endif
+endif
+
 %.o: %.S $(DEPEND)
 	$(GCC) $(DEFS) $(GCC_CFLAGS) -D__ASM__ -c $< -o $@
@@ -356,4 +381,10 @@
 endif
 
+%.test.o: %.c $(DEPEND)
+	$(CC) $(DEFS) $(CFLAGS) $(TEST_CFLAGS) -c $< -o $@
+ifeq ($(PRECHECK),y)
+	$(JOBFILE) $(JOB) $< $@ cc core $(DEFS) $(CFLAGS)
+endif
+
 %.lo: %.S $(DEPEND)
 	$(CC) $(DEFS) $(LIB_CFLAGS) -D__ASM__ -c $< -o $@
@@ -375,5 +406,5 @@
 
 $(DEPEND): $(PRE_DEPEND)
-	makedepend -f - -- $(DEPEND_DEFS) $(CFLAGS) -- $(SOURCES) > $@ 2> /dev/null
+	makedepend -f - -- $(DEPEND_DEFS) $(CFLAGS) -- $(SOURCES) $(TEST_SOURCES) > $@ 2> /dev/null
 	-[ -f $(DEPEND_PREV) ] && diff -q $(DEPEND_PREV) $@ && mv -f $(DEPEND_PREV) $@
 
Index: uspace/app/bdsh/Makefile
===================================================================
--- uspace/app/bdsh/Makefile	(revision 58f26cbc0c1d3b1eee97b21bf0c30c8d9de4acd5)
+++ uspace/app/bdsh/Makefile	(revision bf45993c05fbff161c55a858a73b7488e832d63c)
@@ -65,3 +65,7 @@
 	tok.c
 
+TEST_SOURCES = \
+	tok.c \
+	test/toktest.c
+
 include $(USPACE_PREFIX)/Makefile.common
Index: uspace/app/bdsh/test/toktest.c
===================================================================
--- uspace/app/bdsh/test/toktest.c	(revision bf45993c05fbff161c55a858a73b7488e832d63c)
+++ uspace/app/bdsh/test/toktest.c	(revision bf45993c05fbff161c55a858a73b7488e832d63c)
@@ -0,0 +1,96 @@
+/*
+ * Copyright (c) 2014 Vojtech Horky
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <errno.h>
+#include <str.h>
+#include <stdlib.h>
+
+#include "../tok.h"
+#include <pcut/pcut.h>
+
+PCUT_INIT
+
+#define MAX_TOKENS 32
+#define MAX_INPUT 256
+static tokenizer_t tokenizer;
+static token_t tokens[MAX_TOKENS];
+static char input_buffer[MAX_INPUT];
+
+/* Tokenize the input, asserts that number of tokens is okay. */
+static void prepare(const char *input, size_t expected_token_count) {
+	str_cpy(input_buffer, MAX_INPUT, input);
+
+	int rc = tok_init(&tokenizer, input_buffer, tokens, MAX_TOKENS);
+	PCUT_ASSERT_INT_EQUALS(EOK, rc);
+
+	size_t token_count;
+	rc = tok_tokenize(&tokenizer, &token_count);
+	PCUT_ASSERT_INT_EQUALS(EOK, rc);
+
+
+	PCUT_ASSERT_INT_EQUALS(expected_token_count, token_count);
+}
+
+
+#define ASSERT_TOKEN(index, token_type, token_text) \
+	do { \
+		PCUT_ASSERT_INT_EQUALS(token_type, tokens[index].type); \
+		PCUT_ASSERT_STR_EQUALS(token_text, tokens[index].text); \
+	} while (0)
+
+
+
+PCUT_TEST_SUITE(tokenizer);
+
+PCUT_TEST_AFTER {
+	/* Destroy the tokenizer. */
+	tok_fini(&tokenizer);
+}
+
+
+PCUT_TEST(empty_input) {
+	prepare("", 0);
+}
+
+PCUT_TEST(only_spaces) {
+	prepare("   ", 1);
+
+	ASSERT_TOKEN(0, TOKTYPE_SPACE, "   ");
+}
+
+PCUT_TEST(two_text_tokens) {
+	prepare("alpha  bravo", 3);
+
+	ASSERT_TOKEN(0, TOKTYPE_TEXT, "alpha");
+	ASSERT_TOKEN(1, TOKTYPE_SPACE, "  ");
+	ASSERT_TOKEN(2, TOKTYPE_TEXT, "bravo");
+}
+
+
+
+PCUT_MAIN()
Index: uspace/lib/c/Makefile
===================================================================
--- uspace/lib/c/Makefile	(revision 58f26cbc0c1d3b1eee97b21bf0c30c8d9de4acd5)
+++ uspace/lib/c/Makefile	(revision bf45993c05fbff161c55a858a73b7488e832d63c)
@@ -165,4 +165,8 @@
 	$(ARCH_SOURCES)
 
+TEST_SOURCES = \
+	test/main.c \
+	test/sprintf.c
+
 include $(USPACE_PREFIX)/Makefile.common
 
Index: uspace/lib/c/test/main.c
===================================================================
--- uspace/lib/c/test/main.c	(revision bf45993c05fbff161c55a858a73b7488e832d63c)
+++ uspace/lib/c/test/main.c	(revision bf45993c05fbff161c55a858a73b7488e832d63c)
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2014 Vojtech Horky
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+#include <pcut/pcut.h>
+
+PCUT_INIT
+
+PCUT_IMPORT(sprintf);
+
+PCUT_MAIN()
Index: uspace/lib/c/test/sprintf.c
===================================================================
--- uspace/lib/c/test/sprintf.c	(revision bf45993c05fbff161c55a858a73b7488e832d63c)
+++ uspace/lib/c/test/sprintf.c	(revision bf45993c05fbff161c55a858a73b7488e832d63c)
@@ -0,0 +1,95 @@
+/*
+ * Copyright (c) 2014 Vojtech Horky
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+#include <pcut/pcut.h>
+
+#define BUFFER_SIZE 8192
+#define TEQ(expected, actual) PCUT_ASSERT_STR_EQUALS(expected, actual)
+#define TF(expected, format, ...) TEQ(expected, fmt(format, ##__VA_ARGS__))
+
+
+#define SPRINTF_TEST(test_name, expected_string, actual_format, ...) \
+	PCUT_TEST(test_name) { \
+		snprintf(buffer, BUFFER_SIZE, actual_format, ##__VA_ARGS__); \
+		PCUT_ASSERT_STR_EQUALS(expected_string, buffer); \
+	}
+
+PCUT_INIT
+
+PCUT_TEST_SUITE(sprintf);
+
+static char buffer[BUFFER_SIZE];
+
+PCUT_TEST_BEFORE {
+	memset(buffer, 0, BUFFER_SIZE);
+}
+
+
+
+SPRINTF_TEST(no_formatting, "This is a test.", "This is a test.")
+
+
+
+SPRINTF_TEST(string_plain, "some text", "%s", "some text")
+
+SPRINTF_TEST(string_dynamic_width, "  tex", "%*.*s", 5, 3, "text")
+
+SPRINTF_TEST(string_dynamic_width_align_left, "text   ", "%-*.*s", 7, 7, "text")
+
+SPRINTF_TEST(string_pad, "    text", "%8.10s", "text")
+
+SPRINTF_TEST(string_pad_but_cut, "  very lon", "%10.8s", "very long text")
+
+
+
+SPRINTF_TEST(char_basic, "[a]", "[%c]", 'a')
+
+
+
+SPRINTF_TEST(int_various_padding, "[1] [ 02] [03 ] [004] [005]",
+    "[%d] [%3.2d] [%-3.2d] [%2.3d] [%-2.3d]",
+    1, 2, 3, 4, 5)
+
+SPRINTF_TEST(int_negative_various_padding, "[-1] [-02] [-03] [-004] [-005]",
+    "[%d] [%3.2d] [%-3.2d] [%2.3d] [%-2.3d]",
+    -1, -2, -3, -4, -5)
+
+SPRINTF_TEST(long_negative_various_padding, "[-1] [-02] [-03] [-004] [-005]",
+    "[%lld] [%3.2lld] [%-3.2lld] [%2.3lld] [%-2.3lld]",
+    (long long) -1, (long long) -2, (long long) -3, (long long) -4,
+    (long long) -5)
+
+SPRINTF_TEST(int_as_hex, "[0x11] [0x012] [0x013] [0x00014] [0x00015]",
+    "[%#x] [%#5.3x] [%#-5.3x] [%#3.5x] [%#-3.5x]",
+    17, 18, 19, 20, 21)
+
+
+
+
+PCUT_EXPORT(sprintf);
Index: uspace/lib/pcut/Makefile
===================================================================
--- uspace/lib/pcut/Makefile	(revision bf45993c05fbff161c55a858a73b7488e832d63c)
+++ uspace/lib/pcut/Makefile	(revision bf45993c05fbff161c55a858a73b7488e832d63c)
@@ -0,0 +1,35 @@
+#
+# This file was generated by call to update-from-master.sh
+#
+
+USPACE_PREFIX = ../..
+PCUT_TEST_PREFIX = test-libpcut-
+
+EXTRA_OUTPUT = \
+	$(PCUT_TEST_PREFIX)abort$(PCUT_TEST_SUFFIX) \
+	$(PCUT_TEST_PREFIX)asserts$(PCUT_TEST_SUFFIX) \
+	$(PCUT_TEST_PREFIX)beforeafter$(PCUT_TEST_SUFFIX) \
+	$(PCUT_TEST_PREFIX)errno$(PCUT_TEST_SUFFIX) \
+	$(PCUT_TEST_PREFIX)inithook$(PCUT_TEST_SUFFIX) \
+	$(PCUT_TEST_PREFIX)manytests$(PCUT_TEST_SUFFIX) \
+	$(PCUT_TEST_PREFIX)multisuite$(PCUT_TEST_SUFFIX) \
+	$(PCUT_TEST_PREFIX)preinithook$(PCUT_TEST_SUFFIX) \
+	$(PCUT_TEST_PREFIX)printing$(PCUT_TEST_SUFFIX) \
+	$(PCUT_TEST_PREFIX)simple$(PCUT_TEST_SUFFIX) \
+	$(PCUT_TEST_PREFIX)skip$(PCUT_TEST_SUFFIX) \
+	$(PCUT_TEST_PREFIX)suites$(PCUT_TEST_SUFFIX) \
+	$(PCUT_TEST_PREFIX)teardownaborts$(PCUT_TEST_SUFFIX) \
+	$(PCUT_TEST_PREFIX)teardown$(PCUT_TEST_SUFFIX) \
+	$(PCUT_TEST_PREFIX)testlist$(PCUT_TEST_SUFFIX) \
+	$(PCUT_TEST_PREFIX)timeout$(PCUT_TEST_SUFFIX) \
+	$(PCUT_TEST_PREFIX)xmlreport$(PCUT_TEST_SUFFIX) 
+
+include helenos.mak
+
+include $(USPACE_PREFIX)/Makefile.common
+
+include helenos.test.mak
+
+test-libpcut-%: $(OUTPUT)
+	$(LD) -n $(LFLAGS) -T $(LINKER_SCRIPT) -o $@ $^ $(OUTPUT) $(BASE_LIBS)
+
Index: uspace/lib/pcut/README.rst
===================================================================
--- uspace/lib/pcut/README.rst	(revision bf45993c05fbff161c55a858a73b7488e832d63c)
+++ uspace/lib/pcut/README.rst	(revision bf45993c05fbff161c55a858a73b7488e832d63c)
@@ -0,0 +1,75 @@
+PCUT: Plain C Unit Testing mini-framework
+=========================================
+
+PCUT is a very simple framework for unit testing of C code.
+Unlike many other frameworks where you need to specify manually which
+functions belong to a particular test, PCUT provides several smart
+macros that hides this and lets you focus on the most important
+part of testing only: that is, coding the test cases.
+
+This mini-framework is definitely not complete but it offers the basic
+functionality needed for writing unit tests.
+This includes the possibility to group tests into test suites, optionally
+having set-up and tear-down functions.
+There are several assert macros for evaluating the results, their highlight
+is very detailed information about the problem.
+
+The output of the test can come in two forms: either as an XML output suited
+for later processing or in the form of Test-Anything-Protocol.
+PCUT is able to capture standard output and display it together with test
+results.
+And by running each test in a separate process, the whole framework is pretty
+safe against unexpected crashes, such as null pointer dereference.
+
+More details can be found on PCUT wiki on GitHub:
+https://github.com/vhotspur/pcut/wiki
+
+
+Quick-start example
+-------------------
+
+The following code tests the standard ``atoi`` function::
+
+	#include <pcut/pcut.h>
+	#include <stdlib.h>
+	
+	PCUT_INIT
+	
+	PCUT_TEST(atoi_zero) {
+	    PCUT_ASSERT_INT_EQUALS(0, atoi("0"));
+	}
+	
+	PCUT_TEST(atoi_positive) {
+	    PCUT_ASSERT_INT_EQUALS(42, atoi("42"));
+	}
+	
+	PCUT_TEST(atoi_negative) {
+	    PCUT_ASSERT_INT_EQUALS(-273, atoi("-273"));
+	}
+	
+	PCUT_MAIN()
+
+As you can see, there is no manual listing of tests that form the test
+suite etc, only the tests and ``PCUT_INIT`` at the beginning and
+``PCUT_MAIN`` at the end.
+
+This code has to be linked with ``libpcut`` to get an executable that runs
+the tests and reports the results.
+
+More examples, in the form of self-tests, are available in the ``tests/``
+subdirectory.
+Other examples can be found on the Wiki.
+
+
+Building and installing
+-----------------------
+
+PCUT uses CMake (http://www.cmake.org/).
+On Unix systems, following commands build the library and execute the
+built-in tests::
+
+	mkdir build
+	cd build
+	cmake .. && make all test
+
+More details can be found on https://github.com/vhotspur/pcut/wiki/Building.
Index: uspace/lib/pcut/helenos.mak
===================================================================
--- uspace/lib/pcut/helenos.mak	(revision bf45993c05fbff161c55a858a73b7488e832d63c)
+++ uspace/lib/pcut/helenos.mak	(revision bf45993c05fbff161c55a858a73b7488e832d63c)
@@ -0,0 +1,40 @@
+#
+# Copyright (c) 2013 Vojtech Horky
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# - Redistributions of source code must retain the above copyright
+#   notice, this list of conditions and the following disclaimer.
+# - Redistributions in binary form must reproduce the above copyright
+#   notice, this list of conditions and the following disclaimer in the
+#   documentation and/or other materials provided with the distribution.
+# - The name of the author may not be used to endorse or promote products
+#   derived from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+# IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+SOURCES = \
+	src/os/helenos.c \
+	src/assert.c \
+	src/list.c \
+	src/main.c \
+	src/print.c \
+	src/report/report.c \
+	src/report/tap.c \
+	src/report/xml.c \
+	src/run.c
+EXTRA_CFLAGS = -D__helenos__ -Iinclude
+LIBRARY = libpcut
Index: uspace/lib/pcut/helenos.test.mak
===================================================================
--- uspace/lib/pcut/helenos.test.mak	(revision bf45993c05fbff161c55a858a73b7488e832d63c)
+++ uspace/lib/pcut/helenos.test.mak	(revision bf45993c05fbff161c55a858a73b7488e832d63c)
@@ -0,0 +1,53 @@
+# Re-generate with CMake
+
+# abort
+$(PCUT_TEST_PREFIX)abort$(PCUT_TEST_SUFFIX): tests/abort.o
+
+# asserts
+$(PCUT_TEST_PREFIX)asserts$(PCUT_TEST_SUFFIX): tests/asserts.o
+
+# beforeafter
+$(PCUT_TEST_PREFIX)beforeafter$(PCUT_TEST_SUFFIX): tests/beforeafter.o
+
+# errno
+$(PCUT_TEST_PREFIX)errno$(PCUT_TEST_SUFFIX): tests/errno.o
+
+# inithook
+$(PCUT_TEST_PREFIX)inithook$(PCUT_TEST_SUFFIX): tests/inithook.o
+
+# manytests
+$(PCUT_TEST_PREFIX)manytests$(PCUT_TEST_SUFFIX): tests/manytests.o
+
+# multisuite
+$(PCUT_TEST_PREFIX)multisuite$(PCUT_TEST_SUFFIX): tests/suite_all.o tests/suite1.o tests/suite2.o tests/tested.o
+
+# preinithook
+$(PCUT_TEST_PREFIX)preinithook$(PCUT_TEST_SUFFIX): tests/inithook.o
+
+# printing
+$(PCUT_TEST_PREFIX)printing$(PCUT_TEST_SUFFIX): tests/printing.o
+
+# simple
+$(PCUT_TEST_PREFIX)simple$(PCUT_TEST_SUFFIX): tests/simple.o tests/tested.o
+
+# skip
+$(PCUT_TEST_PREFIX)skip$(PCUT_TEST_SUFFIX): tests/skip.o
+
+# suites
+$(PCUT_TEST_PREFIX)suites$(PCUT_TEST_SUFFIX): tests/suites.o tests/tested.o
+
+# teardownaborts
+$(PCUT_TEST_PREFIX)teardownaborts$(PCUT_TEST_SUFFIX): tests/teardownaborts.o
+
+# teardown
+$(PCUT_TEST_PREFIX)teardown$(PCUT_TEST_SUFFIX): tests/teardown.o tests/tested.o
+
+# testlist
+$(PCUT_TEST_PREFIX)testlist$(PCUT_TEST_SUFFIX): tests/testlist.o
+
+# timeout
+$(PCUT_TEST_PREFIX)timeout$(PCUT_TEST_SUFFIX): tests/timeout.o
+
+# xmlreport
+$(PCUT_TEST_PREFIX)xmlreport$(PCUT_TEST_SUFFIX): tests/xmlreport.o tests/tested.o
+
Index: uspace/lib/pcut/include/pcut/asserts.h
===================================================================
--- uspace/lib/pcut/include/pcut/asserts.h	(revision bf45993c05fbff161c55a858a73b7488e832d63c)
+++ uspace/lib/pcut/include/pcut/asserts.h	(revision bf45993c05fbff161c55a858a73b7488e832d63c)
@@ -0,0 +1,299 @@
+/*
+ * Copyright (c) 2014 Vojtech Horky
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @file
+ * Predefined asserts.
+ *
+ * @defgroup asserts Asserts
+ * Predefined asserts you can use with PCUT.
+ * @{
+ */
+#ifndef PCUT_ASSERTS_H_GUARD
+#define PCUT_ASSERTS_H_GUARD
+
+#include <errno.h>
+
+/** @def PCUT_CURRENT_FILENAME
+ * Overwrite contents of __FILE__ when printing assertion errors.
+ */
+#ifndef PCUT_CURRENT_FILENAME
+#define PCUT_CURRENT_FILENAME __FILE__
+#endif
+
+/** @cond devel */
+
+/** Raise assertion error.
+ *
+ * This function immediately terminates current test and executes a tear-down
+ * (if registered).
+ *
+ * @param filename File where the assertion occurred.
+ * @param line Line where the assertion occurred.
+ * @param fmt Printf-like format string.
+ * @param ... Extra arguments.
+ */
+void pcut_failed_assertion_fmt(const char *filename, int line, const char *fmt, ...);
+
+/** OS-agnostic string comparison.
+ *
+ * @param a First string to compare.
+ * @param b Second string to compare.
+ * @return Whether the strings are equal.
+ */
+int pcut_str_equals(const char *a, const char *b);
+
+/** OS-agnostic conversion from error code to error description.
+ *
+ * This function ensures that the description stored in @p buffer is
+ * always a nul-terminated string.
+ *
+ * @param error Error code.
+ * @param buffer Where to store the error description.
+ * @param size Size of the buffer.
+ */
+void pcut_str_error(int error, char *buffer, int size);
+
+/** Raise assertion error (internal version).
+ *
+ * We expect to be always called from PCUT_ASSERTION_FAILED() where
+ * the last argument is empty string to conform to strict ISO C99
+ * ("ISO C99 requires rest arguments to be used").
+ *
+ * @param fmt Printf-like format string.
+ * @param ... Extra arguments.
+ */
+#define PCUT_ASSERTION_FAILED_INTERNAL(fmt, ...) \
+	pcut_failed_assertion_fmt(PCUT_CURRENT_FILENAME, __LINE__, fmt, __VA_ARGS__)
+
+
+/** @endcond */
+
+/** Raise assertion error.
+ *
+ * This macro adds current file and line and triggers immediate test
+ * abort (tear-down function of the test suite is run when available).
+ *
+ * @param ... Printf-like arguments.
+ */
+#define PCUT_ASSERTION_FAILED(...) \
+	PCUT_ASSERTION_FAILED_INTERNAL(__VA_ARGS__, "")
+
+
+/** Generic assertion for a boolean expression.
+ *
+ * @param actual Actually obtained (computed) value we wish to test to true.
+ */
+#define PCUT_ASSERT_TRUE(actual) \
+	do { \
+		if (!(actual)) { \
+			PCUT_ASSERTION_FAILED("Expected true but got <%s>", \
+				#actual); \
+		} \
+	} while (0)
+
+/** Generic assertion for a boolean expression.
+ *
+ * @param actual Actually obtained (computed) value we wish to test to false.
+ */
+#define PCUT_ASSERT_FALSE(actual) \
+	do { \
+		if ((actual)) { \
+			PCUT_ASSERTION_FAILED("Expected false but got <%s>", \
+				#actual); \
+		} \
+	} while (0)
+
+
+/** Generic assertion for types where == is defined.
+ *
+ * @param expected Expected (correct) value.
+ * @param actual Actually obtained (computed) value we wish to test.
+ */
+#define PCUT_ASSERT_EQUALS(expected, actual) \
+	do {\
+		if (!((expected) == (actual))) { \
+			PCUT_ASSERTION_FAILED("Expected <"#expected "> but got <" #actual ">"); \
+		} \
+	} while (0)
+
+/** Asserts that given pointer is NULL.
+ *
+ * @param pointer The pointer to be tested.
+ */
+#define PCUT_ASSERT_NULL(pointer) \
+	do { \
+		void *pcut_ptr_eval = (pointer); \
+		if (pcut_ptr_eval != (NULL)) { \
+			PCUT_ASSERTION_FAILED("Expected <" #pointer "> to be NULL, " \
+				"instead it points to %p", pcut_ptr_eval); \
+		} \
+	} while (0)
+
+/** Asserts that given pointer is not NULL.
+ *
+ * Use this function when directly quoting the original pointer variable
+ * does not provide sufficient information.
+ *
+ * @param pointer The pointer to be tested.
+ * @param pointer_name Name of the pointer.
+ */
+#define PCUT_ASSERT_NOT_NULL_WITH_NAME(pointer, pointer_name) \
+	do { \
+		const void *pcut_ptr_eval = (pointer); \
+		if (pcut_ptr_eval == (NULL)) { \
+			PCUT_ASSERTION_FAILED("Pointer <" pointer_name "> ought not to be NULL"); \
+		} \
+	} while (0)
+
+/** Asserts that given pointer is not NULL.
+ *
+ * @param pointer The pointer to be tested.
+ */
+#define PCUT_ASSERT_NOT_NULL(pointer) \
+	PCUT_ASSERT_NOT_NULL_WITH_NAME(pointer, #pointer)
+
+
+/** Assertion for checking that two integers are equal.
+ *
+ * @param expected Expected (correct) value.
+ * @param actual Actually obtained (computed) value we wish to test.
+ */
+#define PCUT_ASSERT_INT_EQUALS(expected, actual) \
+	do {\
+		long pcut_expected_eval = (expected); \
+		long pcut_actual_eval = (actual); \
+		if (pcut_expected_eval != pcut_actual_eval) { \
+			PCUT_ASSERTION_FAILED("Expected <%ld> but got <%ld> (%s != %s)", \
+				pcut_expected_eval, pcut_actual_eval, \
+				#expected, #actual); \
+		} \
+	} while (0)
+
+/** Assertion for checking that two doubles are close enough.
+ *
+ * @param expected Expected (correct) value.
+ * @param actual Actually obtained (computed) value we wish to test.
+ * @param epsilon How much the actual value can differ from the expected one.
+ */
+#define PCUT_ASSERT_DOUBLE_EQUALS(expected, actual, epsilon) \
+	do {\
+		double pcut_expected_eval = (expected); \
+		double pcut_actual_eval = (actual); \
+		double pcut_epsilon_eval = (epsilon); \
+		double pcut_double_diff = pcut_expected_eval - pcut_actual_eval; \
+		if ((pcut_double_diff < -pcut_epsilon_eval) | (pcut_double_diff > pcut_epsilon_eval)) { \
+			PCUT_ASSERTION_FAILED("Expected <%lf+-%lf> but got <%lf> (%s != %s)", \
+				pcut_expected_eval, pcut_epsilon_eval, pcut_actual_eval, \
+				#expected, #actual); \
+		} \
+	} while (0)
+
+/** Assertion for checking that two strings (`const char *`) are equal.
+ *
+ * @param expected Expected (correct) value.
+ * @param actual Actually obtained (computed) value we wish to test.
+ */
+#define PCUT_ASSERT_STR_EQUALS(expected, actual) \
+	do {\
+		const char *pcut_expected_eval = (expected); \
+		const char *pcut_actual_eval = (actual); \
+		PCUT_ASSERT_NOT_NULL_WITH_NAME(pcut_expected_eval, #expected); \
+		PCUT_ASSERT_NOT_NULL_WITH_NAME(pcut_actual_eval, #actual); \
+		if (!pcut_str_equals(pcut_expected_eval, pcut_actual_eval)) { \
+			PCUT_ASSERTION_FAILED("Expected <%s> but got <%s> (%s != %s)", \
+				pcut_expected_eval, pcut_actual_eval, \
+				#expected, #actual); \
+		} \
+	} while (0)
+
+
+/** Assertion for checking that two strings (`const char *`) are equal or both NULL.
+ *
+ * @param expected Expected (correct) value.
+ * @param actual Actually obtained (computed) value we wish to test.
+ */
+#define PCUT_ASSERT_STR_EQUALS_OR_NULL(expected, actual) \
+	do {\
+		const char *pcut_expected_eval = (expected); \
+		const char *pcut_actual_eval = (actual); \
+		int pcut_both_null = (pcut_expected_eval == NULL) && (pcut_actual_eval == NULL); \
+		int pcut_some_null = (pcut_expected_eval == NULL) || (pcut_actual_eval == NULL); \
+		if (!pcut_both_null && (pcut_some_null || !pcut_str_equals(pcut_expected_eval, pcut_actual_eval))) { \
+			PCUT_ASSERTION_FAILED("Expected <%s> but got <%s> (%s != %s)", \
+				pcut_expected_eval == NULL ? "NULL" : pcut_expected_eval, \
+				pcut_actual_eval == NULL ? "NULL" : pcut_actual_eval, \
+				#expected, #actual); \
+		} \
+	} while (0)
+
+
+/** Assertion for checking errno-style variables for errors.
+ *
+ * Use this function when directly quoting the original error code does
+ * not provide sufficient information.
+ *
+ * @param expected_value Expected errno error code.
+ * @param expected_quoted Expected error code as a string.
+ * @param actual_value Actual value of the error code.
+ */
+#define PCUT_ASSERT_ERRNO_VAL_WITH_NAME(expected_value, expected_quoted, actual_value) \
+	do {\
+		int pcut_expected_eval = (expected_value); \
+		int pcut_actual_eval = (actual_value); \
+		if (pcut_expected_eval != pcut_actual_eval) { \
+			char pcut_expected_description[100]; \
+			char pcut_actual_description[100]; \
+			pcut_str_error(pcut_expected_eval, pcut_expected_description, 100); \
+			pcut_str_error(pcut_actual_eval, pcut_actual_description, 100); \
+			PCUT_ASSERTION_FAILED("Expected error %d (%s, %s) but got error %d (%s)", \
+				pcut_expected_eval, expected_quoted, \
+				pcut_expected_description, \
+				pcut_actual_eval, pcut_actual_description); \
+		} \
+	} while (0)
+
+/** Assertion for checking errno-style variables for errors.
+ *
+ * @param expected Expected errno error code.
+ * @param actual Actual value of the error code.
+ */
+#define PCUT_ASSERT_ERRNO_VAL(expected, actual) \
+	PCUT_ASSERT_ERRNO_VAL_WITH_NAME(expected, #expected, actual)
+
+/** Assertion for checking errno variable for errors.
+ *
+ * @param expected Expected errno error code.
+ */
+#define PCUT_ASSERT_ERRNO(expected) \
+	PCUT_ASSERT_ERRNO_VAL_WITH_NAME(expected, #expected, (errno))
+
+/**
+ * @}
+ */
+
+#endif
Index: uspace/lib/pcut/include/pcut/datadef.h
===================================================================
--- uspace/lib/pcut/include/pcut/datadef.h	(revision bf45993c05fbff161c55a858a73b7488e832d63c)
+++ uspace/lib/pcut/include/pcut/datadef.h	(revision bf45993c05fbff161c55a858a73b7488e832d63c)
@@ -0,0 +1,147 @@
+/*
+ * Copyright (c) 2012-2013 Vojtech Horky
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @file
+ * Data types internally used by PCUT.
+ */
+#ifndef PCUT_DATADEF_H_GUARD
+#define PCUT_DATADEF_H_GUARD
+
+#include <pcut/prevs.h>
+#include <stdlib.h>
+#include <stddef.h>
+
+/** @cond devel */
+
+#if defined(__GNUC__) || defined(__clang__)
+#define PCUT_CC_UNUSED_VARIABLE(name, initializer) \
+	name __attribute__((unused)) = initializer
+#else
+#define PCUT_CC_UNUSED_VARIABLE(name, initializer) \
+	name = initializer
+#endif
+
+
+enum {
+	PCUT_KIND_SKIP,
+	PCUT_KIND_NESTED,
+	PCUT_KIND_SETUP,
+	PCUT_KIND_TEARDOWN,
+	PCUT_KIND_TESTSUITE,
+	PCUT_KIND_TEST
+};
+
+enum {
+	PCUT_EXTRA_TIMEOUT,
+	PCUT_EXTRA_SKIP,
+	PCUT_EXTRA_LAST
+};
+
+enum {
+	PCUT_MAIN_EXTRA_PREINIT_HOOK,
+	PCUT_MAIN_EXTRA_INIT_HOOK,
+	PCUT_MAIN_EXTRA_REPORT_XML,
+	PCUT_MAIN_EXTRA_LAST
+};
+
+/** Generic wrapper for test cases, test suites etc. */
+typedef struct pcut_item pcut_item_t;
+
+/** Extra information about a test. */
+typedef struct pcut_extra pcut_extra_t;
+
+/** Extra information for the main() function. */
+typedef struct pcut_main_extra pcut_main_extra_t;
+
+/** Test method type. */
+typedef void (*pcut_test_func_t)(void);
+
+/** Set-up or tear-down method type. */
+typedef void (*pcut_setup_func_t)(void);
+
+/** @copydoc pcut_extra_t */
+struct pcut_extra {
+	/** Discriminator for the union.
+	 *
+	 * Use PCUT_EXTRA_* to determine which field of the union is used.
+	 */
+	int type;
+	/** Test-specific time-out in seconds. */
+	int timeout;
+};
+
+/** @copydoc pcut_main_extra_t */
+struct pcut_main_extra {
+	/** Discriminator for the union.
+	 *
+	 * Use PCUT_MAIN_EXTRA_* to determine which field of the union is used.
+	 */
+	int type;
+	/** Callback once PCUT initializes itself. */
+	void (*init_hook)(void);
+	/** Callback even before command-line arguments are processed. */
+	void (*preinit_hook)(int *, char ***);
+};
+
+/** @copydoc pcut_item_t */
+struct pcut_item {
+	/** Link to previous item. */
+	pcut_item_t *previous;
+	/** Link to next item. */
+	pcut_item_t *next;
+
+	/** Unique id of this item. */
+	int id;
+
+	/** Discriminator for this item. */
+	int kind;
+
+	/** Name of this item. */
+	const char *name;
+
+	/** Test-case function. */
+	pcut_test_func_t test_func;
+
+	/** Set-up function of a suite. */
+	pcut_setup_func_t setup_func;
+	/** Tear-down function of a suite. */
+	pcut_setup_func_t teardown_func;
+
+	/** Extra attributes. */
+	pcut_extra_t *extras;
+
+	/** Extra attributes for main() function. */
+	pcut_main_extra_t *main_extras;
+
+	/** Nested lists. */
+	pcut_item_t *nested;
+};
+
+/** @endcond */
+
+#endif
Index: uspace/lib/pcut/include/pcut/helper.h
===================================================================
--- uspace/lib/pcut/include/pcut/helper.h	(revision bf45993c05fbff161c55a858a73b7488e832d63c)
+++ uspace/lib/pcut/include/pcut/helper.h	(revision bf45993c05fbff161c55a858a73b7488e832d63c)
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2014 Vojtech Horky
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @file
+ * Helper macros.
+ */
+#ifndef PCUT_HELPER_H_GUARD
+#define PCUT_HELPER_H_GUARD
+
+/** @cond devel */
+
+/** Join the two arguments on preprocessor level (inner call). */
+#define PCUT_JOIN_IMPL(a, b) a##b
+
+/** Join the two arguments on preprocessor level. */
+#define PCUT_JOIN(a, b) PCUT_JOIN_IMPL(a, b)
+
+/** Quote the parameter (inner call). */
+#define PCUT_QUOTE_IMPL(x) #x
+
+/** Quote the parameter. */
+#define PCUT_QUOTE(x) PCUT_QUOTE_IMPL(x)
+
+/** Get first argument from macro var-args. */
+#define PCUT_VARG_GET_FIRST(x, ...) x
+
+/** Get all but first arguments from macro var-args. */
+#define PCUT_VARG_SKIP_FIRST(x, ...) __VA_ARGS__
+
+#endif
Index: uspace/lib/pcut/include/pcut/pcut.h
===================================================================
--- uspace/lib/pcut/include/pcut/pcut.h	(revision bf45993c05fbff161c55a858a73b7488e832d63c)
+++ uspace/lib/pcut/include/pcut/pcut.h	(revision bf45993c05fbff161c55a858a73b7488e832d63c)
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2012-2014 Vojtech Horky
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @file
+ * PCUT: Plain-C unit-testing mini-framework.
+ */
+#ifndef PCUT_PCUT_H_GUARD
+#define PCUT_PCUT_H_GUARD
+
+#include <pcut/asserts.h>
+#include <pcut/tests.h>
+
+#endif
Index: uspace/lib/pcut/include/pcut/prevs.h
===================================================================
--- uspace/lib/pcut/include/pcut/prevs.h	(revision bf45993c05fbff161c55a858a73b7488e832d63c)
+++ uspace/lib/pcut/include/pcut/prevs.h	(revision bf45993c05fbff161c55a858a73b7488e832d63c)
@@ -0,0 +1,346 @@
+/*
+ * Copyright (c) 2012-2014 Vojtech Horky
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * @file
+ * Counter macros internally used by PCUT.
+ */
+
+#ifndef PCUT_PREVS_H_GUARD
+#define PCUT_PREVS_H_GUARD
+
+#ifndef PCUT_DOXYGEN_IS_RUNNING
+/** @cond devel */
+
+#define PCUT_PREV_1 0
+#define PCUT_PREV_2 1
+#define PCUT_PREV_3 2
+#define PCUT_PREV_4 3
+#define PCUT_PREV_5 4
+#define PCUT_PREV_6 5
+#define PCUT_PREV_7 6
+#define PCUT_PREV_8 7
+#define PCUT_PREV_9 8
+#define PCUT_PREV_10 9
+#define PCUT_PREV_11 10
+#define PCUT_PREV_12 11
+#define PCUT_PREV_13 12
+#define PCUT_PREV_14 13
+#define PCUT_PREV_15 14
+#define PCUT_PREV_16 15
+#define PCUT_PREV_17 16
+#define PCUT_PREV_18 17
+#define PCUT_PREV_19 18
+#define PCUT_PREV_20 19
+#define PCUT_PREV_21 20
+#define PCUT_PREV_22 21
+#define PCUT_PREV_23 22
+#define PCUT_PREV_24 23
+#define PCUT_PREV_25 24
+#define PCUT_PREV_26 25
+#define PCUT_PREV_27 26
+#define PCUT_PREV_28 27
+#define PCUT_PREV_29 28
+#define PCUT_PREV_30 29
+#define PCUT_PREV_31 30
+#define PCUT_PREV_32 31
+#define PCUT_PREV_33 32
+#define PCUT_PREV_34 33
+#define PCUT_PREV_35 34
+#define PCUT_PREV_36 35
+#define PCUT_PREV_37 36
+#define PCUT_PREV_38 37
+#define PCUT_PREV_39 38
+#define PCUT_PREV_40 39
+#define PCUT_PREV_41 40
+#define PCUT_PREV_42 41
+#define PCUT_PREV_43 42
+#define PCUT_PREV_44 43
+#define PCUT_PREV_45 44
+#define PCUT_PREV_46 45
+#define PCUT_PREV_47 46
+#define PCUT_PREV_48 47
+#define PCUT_PREV_49 48
+#define PCUT_PREV_50 49
+#define PCUT_PREV_51 50
+#define PCUT_PREV_52 51
+#define PCUT_PREV_53 52
+#define PCUT_PREV_54 53
+#define PCUT_PREV_55 54
+#define PCUT_PREV_56 55
+#define PCUT_PREV_57 56
+#define PCUT_PREV_58 57
+#define PCUT_PREV_59 58
+#define PCUT_PREV_60 59
+#define PCUT_PREV_61 60
+#define PCUT_PREV_62 61
+#define PCUT_PREV_63 62
+#define PCUT_PREV_64 63
+#define PCUT_PREV_65 64
+#define PCUT_PREV_66 65
+#define PCUT_PREV_67 66
+#define PCUT_PREV_68 67
+#define PCUT_PREV_69 68
+#define PCUT_PREV_70 69
+#define PCUT_PREV_71 70
+#define PCUT_PREV_72 71
+#define PCUT_PREV_73 72
+#define PCUT_PREV_74 73
+#define PCUT_PREV_75 74
+#define PCUT_PREV_76 75
+#define PCUT_PREV_77 76
+#define PCUT_PREV_78 77
+#define PCUT_PREV_79 78
+#define PCUT_PREV_80 79
+#define PCUT_PREV_81 80
+#define PCUT_PREV_82 81
+#define PCUT_PREV_83 82
+#define PCUT_PREV_84 83
+#define PCUT_PREV_85 84
+#define PCUT_PREV_86 85
+#define PCUT_PREV_87 86
+#define PCUT_PREV_88 87
+#define PCUT_PREV_89 88
+#define PCUT_PREV_90 89
+#define PCUT_PREV_91 90
+#define PCUT_PREV_92 91
+#define PCUT_PREV_93 92
+#define PCUT_PREV_94 93
+#define PCUT_PREV_95 94
+#define PCUT_PREV_96 95
+#define PCUT_PREV_97 96
+#define PCUT_PREV_98 97
+#define PCUT_PREV_99 98
+#define PCUT_PREV_100 99
+#define PCUT_PREV_101 100
+#define PCUT_PREV_102 101
+#define PCUT_PREV_103 102
+#define PCUT_PREV_104 103
+#define PCUT_PREV_105 104
+#define PCUT_PREV_106 105
+#define PCUT_PREV_107 106
+#define PCUT_PREV_108 107
+#define PCUT_PREV_109 108
+#define PCUT_PREV_110 109
+#define PCUT_PREV_111 110
+#define PCUT_PREV_112 111
+#define PCUT_PREV_113 112
+#define PCUT_PREV_114 113
+#define PCUT_PREV_115 114
+#define PCUT_PREV_116 115
+#define PCUT_PREV_117 116
+#define PCUT_PREV_118 117
+#define PCUT_PREV_119 118
+#define PCUT_PREV_120 119
+#define PCUT_PREV_121 120
+#define PCUT_PREV_122 121
+#define PCUT_PREV_123 122
+#define PCUT_PREV_124 123
+#define PCUT_PREV_125 124
+#define PCUT_PREV_126 125
+#define PCUT_PREV_127 126
+#define PCUT_PREV_128 127
+#define PCUT_PREV_129 128
+#define PCUT_PREV_130 129
+#define PCUT_PREV_131 130
+#define PCUT_PREV_132 131
+#define PCUT_PREV_133 132
+#define PCUT_PREV_134 133
+#define PCUT_PREV_135 134
+#define PCUT_PREV_136 135
+#define PCUT_PREV_137 136
+#define PCUT_PREV_138 137
+#define PCUT_PREV_139 138
+#define PCUT_PREV_140 139
+#define PCUT_PREV_141 140
+#define PCUT_PREV_142 141
+#define PCUT_PREV_143 142
+#define PCUT_PREV_144 143
+#define PCUT_PREV_145 144
+#define PCUT_PREV_146 145
+#define PCUT_PREV_147 146
+#define PCUT_PREV_148 147
+#define PCUT_PREV_149 148
+#define PCUT_PREV_150 149
+#define PCUT_PREV_151 150
+#define PCUT_PREV_152 151
+#define PCUT_PREV_153 152
+#define PCUT_PREV_154 153
+#define PCUT_PREV_155 154
+#define PCUT_PREV_156 155
+#define PCUT_PREV_157 156
+#define PCUT_PREV_158 157
+#define PCUT_PREV_159 158
+#define PCUT_PREV_160 159
+#define PCUT_PREV_161 160
+#define PCUT_PREV_162 161
+#define PCUT_PREV_163 162
+#define PCUT_PREV_164 163
+#define PCUT_PREV_165 164
+#define PCUT_PREV_166 165
+#define PCUT_PREV_167 166
+#define PCUT_PREV_168 167
+#define PCUT_PREV_169 168
+#define PCUT_PREV_170 169
+#define PCUT_PREV_171 170
+#define PCUT_PREV_172 171
+#define PCUT_PREV_173 172
+#define PCUT_PREV_174 173
+#define PCUT_PREV_175 174
+#define PCUT_PREV_176 175
+#define PCUT_PREV_177 176
+#define PCUT_PREV_178 177
+#define PCUT_PREV_179 178
+#define PCUT_PREV_180 179
+#define PCUT_PREV_181 180
+#define PCUT_PREV_182 181
+#define PCUT_PREV_183 182
+#define PCUT_PREV_184 183
+#define PCUT_PREV_185 184
+#define PCUT_PREV_186 185
+#define PCUT_PREV_187 186
+#define PCUT_PREV_188 187
+#define PCUT_PREV_189 188
+#define PCUT_PREV_190 189
+#define PCUT_PREV_191 190
+#define PCUT_PREV_192 191
+#define PCUT_PREV_193 192
+#define PCUT_PREV_194 193
+#define PCUT_PREV_195 194
+#define PCUT_PREV_196 195
+#define PCUT_PREV_197 196
+#define PCUT_PREV_198 197
+#define PCUT_PREV_199 198
+#define PCUT_PREV_200 199
+#define PCUT_PREV_201 200
+#define PCUT_PREV_202 201
+#define PCUT_PREV_203 202
+#define PCUT_PREV_204 203
+#define PCUT_PREV_205 204
+#define PCUT_PREV_206 205
+#define PCUT_PREV_207 206
+#define PCUT_PREV_208 207
+#define PCUT_PREV_209 208
+#define PCUT_PREV_210 209
+#define PCUT_PREV_211 210
+#define PCUT_PREV_212 211
+#define PCUT_PREV_213 212
+#define PCUT_PREV_214 213
+#define PCUT_PREV_215 214
+#define PCUT_PREV_216 215
+#define PCUT_PREV_217 216
+#define PCUT_PREV_218 217
+#define PCUT_PREV_219 218
+#define PCUT_PREV_220 219
+#define PCUT_PREV_221 220
+#define PCUT_PREV_222 221
+#define PCUT_PREV_223 222
+#define PCUT_PREV_224 223
+#define PCUT_PREV_225 224
+#define PCUT_PREV_226 225
+#define PCUT_PREV_227 226
+#define PCUT_PREV_228 227
+#define PCUT_PREV_229 228
+#define PCUT_PREV_230 229
+#define PCUT_PREV_231 230
+#define PCUT_PREV_232 231
+#define PCUT_PREV_233 232
+#define PCUT_PREV_234 233
+#define PCUT_PREV_235 234
+#define PCUT_PREV_236 235
+#define PCUT_PREV_237 236
+#define PCUT_PREV_238 237
+#define PCUT_PREV_239 238
+#define PCUT_PREV_240 239
+#define PCUT_PREV_241 240
+#define PCUT_PREV_242 241
+#define PCUT_PREV_243 242
+#define PCUT_PREV_244 243
+#define PCUT_PREV_245 244
+#define PCUT_PREV_246 245
+#define PCUT_PREV_247 246
+#define PCUT_PREV_248 247
+#define PCUT_PREV_249 248
+#define PCUT_PREV_250 249
+#define PCUT_PREV_251 250
+#define PCUT_PREV_252 251
+#define PCUT_PREV_253 252
+#define PCUT_PREV_254 253
+#define PCUT_PREV_255 254
+#define PCUT_PREV_256 255
+#define PCUT_PREV_257 256
+#define PCUT_PREV_258 257
+#define PCUT_PREV_259 258
+#define PCUT_PREV_260 259
+#define PCUT_PREV_261 260
+#define PCUT_PREV_262 261
+#define PCUT_PREV_263 262
+#define PCUT_PREV_264 263
+#define PCUT_PREV_265 264
+#define PCUT_PREV_266 265
+#define PCUT_PREV_267 266
+#define PCUT_PREV_268 267
+#define PCUT_PREV_269 268
+#define PCUT_PREV_270 269
+#define PCUT_PREV_271 270
+#define PCUT_PREV_272 271
+#define PCUT_PREV_273 272
+#define PCUT_PREV_274 273
+#define PCUT_PREV_275 274
+#define PCUT_PREV_276 275
+#define PCUT_PREV_277 276
+#define PCUT_PREV_278 277
+#define PCUT_PREV_279 278
+#define PCUT_PREV_280 279
+#define PCUT_PREV_281 280
+#define PCUT_PREV_282 281
+#define PCUT_PREV_283 282
+#define PCUT_PREV_284 283
+#define PCUT_PREV_285 284
+#define PCUT_PREV_286 285
+#define PCUT_PREV_287 286
+#define PCUT_PREV_288 287
+#define PCUT_PREV_289 288
+#define PCUT_PREV_290 289
+#define PCUT_PREV_291 290
+#define PCUT_PREV_292 291
+#define PCUT_PREV_293 292
+#define PCUT_PREV_294 293
+#define PCUT_PREV_295 294
+#define PCUT_PREV_296 295
+#define PCUT_PREV_297 296
+#define PCUT_PREV_298 297
+#define PCUT_PREV_299 298
+#define PCUT_PREV_300 299
+
+/** @endcond */
+
+#endif
+
+#endif
+
Index: uspace/lib/pcut/include/pcut/tests.h
===================================================================
--- uspace/lib/pcut/include/pcut/tests.h	(revision bf45993c05fbff161c55a858a73b7488e832d63c)
+++ uspace/lib/pcut/include/pcut/tests.h	(revision bf45993c05fbff161c55a858a73b7488e832d63c)
@@ -0,0 +1,481 @@
+/*
+ * Copyright (c) 2014 Vojtech Horky
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @file
+ * Tests and test suites.
+ *
+ * @defgroup tests Tests
+ * Create test suites and test cases.
+ * @{
+ */
+#ifndef PCUT_TESTS_H_GUARD
+#define PCUT_TESTS_H_GUARD
+
+#include <pcut/helper.h>
+#include <pcut/datadef.h>
+
+/*
+ * Trick with [] and & copied from
+ * http://bytes.com/topic/c/answers/553555-initializer-element-not-constant#post2159846
+ * because following does not work:
+ * extern int *a;
+ * int *b = a;
+ */
+
+
+#ifndef __COUNTER__
+#define PCUT_WITHOUT_COUNTER
+#endif
+
+#ifndef PCUT_WITHOUT_COUNTER
+#define PCUT_ITEM_COUNTER_INCREMENT
+#endif
+
+
+/** Default timeout for a single test (in seconds).
+ * @showinitializer
+ */
+#define PCUT_DEFAULT_TEST_TIMEOUT 3
+
+/** Item counter that is expected to be incremented by preprocessor.
+ *
+ * Used compiler must support __COUNTER__ for this to work without any
+ * extra preprocessing.
+ */
+#ifdef PCUT_WITHOUT_COUNTER
+#define PCUT_ITEM_COUNTER PCUT_you_need_to_run_pcut_preprocessor
+#else
+#define PCUT_ITEM_COUNTER __COUNTER__
+#endif
+
+
+/*
+ * Helper macros
+ * -------------
+ */
+
+/** @cond devel */
+
+/** Produce identifier name for an item with given number.
+ *
+ * @param number Item number.
+ */
+#ifndef PCUT_WITHOUT_COUNTER
+#define PCUT_ITEM_NAME(number) \
+	PCUT_JOIN(pcut_item_, number)
+#else
+#define PCUT_ITEM_NAME(number) PCUT_ITEM_NAME
+#endif
+
+/** Produce identifier name for a preceding item.
+ *
+ * @param number Number of the current item.
+ */
+#ifndef PCUT_WITHOUT_COUNTER
+#define PCUT_ITEM_NAME_PREV(number) \
+	PCUT_JOIN(pcut_item_, PCUT_JOIN(PCUT_PREV_, number))
+#else
+#define PCUT_ITEM_NAME_PREV(number) PCUT_ITEM_NAME_PREV
+#endif
+
+#ifndef PCUT_WITHOUT_COUNTER
+#define PCUT_ITEM_EXTRAS_NAME(number) \
+	PCUT_JOIN(pcut_extras_, number)
+#else
+#define PCUT_ITEM_EXTRAS_NAME(number) PCUT_ITEM2_NAME
+#endif
+
+#ifndef PCUT_WITHOUT_COUNTER
+#define PCUT_ITEM_SETUP_NAME(number) \
+	PCUT_JOIN(pcut_setup_, number)
+#else
+#define PCUT_ITEM_SETUP_NAME(number) PCUT_ITEM3_NAME
+#endif
+
+
+
+/** Create a new item, append it to the list.
+ *
+ * @param number Number of this item.
+ * @param itemkind Kind of this item (PCUT_KIND_*).
+ * @param ... Other initializers of the pcut_item_t.
+ */
+#define PCUT_ADD_ITEM(number, itemkind, ...) \
+	static pcut_item_t PCUT_ITEM_NAME(number) = { \
+		&PCUT_ITEM_NAME_PREV(number), \
+		NULL, \
+		-1, \
+		itemkind, \
+		__VA_ARGS__ \
+	}
+
+/** @endcond */
+
+
+
+/*
+ * Test-case related macros
+ * ------------------------
+ */
+
+/** Define test time-out.
+ *
+ * Use as argument to PCUT_TEST().
+ *
+ * @param time_out Time-out value in seconds.
+ */
+#define PCUT_TEST_SET_TIMEOUT(time_out) \
+	{ PCUT_EXTRA_TIMEOUT, (time_out) }
+
+/** Skip current test.
+ *
+ * Use as argument to PCUT_TEST().
+ */
+#define PCUT_TEST_SKIP \
+	{ PCUT_EXTRA_SKIP, 0 }
+
+
+/** @cond devel */
+
+/** Terminate list of extra test options. */
+#define PCUT_TEST_EXTRA_LAST { PCUT_EXTRA_LAST, 0 }
+
+/** Define a new test with given name and given item number.
+ *
+ * @param testname A valid C identifier name (not quoted).
+ * @param number Number of the item describing this test.
+ * @param ... Extra test properties.
+ */
+#define PCUT_TEST_WITH_NUMBER(number, testname, ...) \
+	PCUT_ITEM_COUNTER_INCREMENT \
+	static pcut_extra_t PCUT_ITEM_EXTRAS_NAME(number)[] = { \
+		__VA_ARGS__ \
+	}; \
+	static int PCUT_CC_UNUSED_VARIABLE(PCUT_JOIN(testname, 0_test_name_missing_or_duplicated), 0); \
+	static void PCUT_JOIN(test_, testname)(void); \
+	PCUT_ADD_ITEM(number, PCUT_KIND_TEST, \
+		PCUT_QUOTE(testname), \
+		PCUT_JOIN(test_, testname), \
+		NULL, NULL, \
+		PCUT_ITEM_EXTRAS_NAME(number), \
+		NULL, NULL \
+	); \
+	void PCUT_JOIN(test_, testname)(void)
+
+/** @endcond */
+
+/** Define a new test with given name.
+ *
+ * @param ... Test name (C identifier) followed by extra test properties.
+ */
+#define PCUT_TEST(...) \
+	PCUT_TEST_WITH_NUMBER(PCUT_ITEM_COUNTER, \
+		PCUT_VARG_GET_FIRST(__VA_ARGS__, this_arg_is_ignored), \
+		PCUT_VARG_SKIP_FIRST(__VA_ARGS__, PCUT_TEST_EXTRA_LAST) \
+	)
+
+
+
+
+
+/*
+ * Test suite related macros
+ * -------------------------
+ */
+
+/** @cond devel */
+
+/** Define and start a new test suite.
+ *
+ * @see PCUT_TEST_SUITE
+ *
+ * @param suitename Suite name (a valid C identifier).
+ * @param number Item number.
+ */
+#define PCUT_TEST_SUITE_WITH_NUMBER(suitename, number) \
+	PCUT_ITEM_COUNTER_INCREMENT \
+	PCUT_ADD_ITEM(number, PCUT_KIND_TESTSUITE, \
+		#suitename, \
+		NULL, \
+		NULL, NULL, \
+		NULL, NULL, \
+		NULL \
+	)
+
+/** Define a set-up function for a test suite.
+ *
+ * @see PCUT_TEST_BEFORE
+ *
+ * @param number Item number.
+ */
+#define PCUT_TEST_BEFORE_WITH_NUMBER(number) \
+	PCUT_ITEM_COUNTER_INCREMENT \
+	static void PCUT_ITEM_SETUP_NAME(number)(void); \
+	PCUT_ADD_ITEM(number, PCUT_KIND_SETUP, \
+		"setup", NULL, \
+		PCUT_ITEM_SETUP_NAME(number), \
+		NULL, NULL, NULL, NULL \
+	); \
+	void PCUT_ITEM_SETUP_NAME(number)(void)
+
+/** Define a tear-down function for a test suite.
+ *
+ * @see PCUT_TEST_AFTER
+ *
+ * @param number Item number.
+ */
+#define PCUT_TEST_AFTER_WITH_NUMBER(number) \
+	PCUT_ITEM_COUNTER_INCREMENT \
+	static void PCUT_ITEM_SETUP_NAME(number)(void); \
+	PCUT_ADD_ITEM(number, PCUT_KIND_TEARDOWN, \
+		"teardown", NULL, NULL, \
+		PCUT_ITEM_SETUP_NAME(number), \
+		NULL, NULL, NULL \
+	); \
+	void PCUT_ITEM_SETUP_NAME(number)(void)
+
+/** @endcond */
+
+
+/** Define and start a new test suite.
+ *
+ * All tests following this macro belong to the new suite
+ * (up to next occurrence of PCUT_TEST_SUITE).
+ *
+ * This command shall be used as is without any extra code.
+ *
+ * @param name Suite name (a valid C identifier).
+ */
+#define PCUT_TEST_SUITE(name) \
+	PCUT_TEST_SUITE_WITH_NUMBER(name, PCUT_ITEM_COUNTER)
+
+/** Define a set-up function for a test suite.
+ *
+ * The code of the function immediately follows this macro.
+ *
+ * @code
+ * PCUT_TEST_SUITE(my_suite);
+ *
+ * PCUT_TEST_BEFORE {
+ *     printf("This is executed before each test in this suite.\n");
+ * }
+ * @endcode
+ *
+ * There could be only a single set-up function for each suite.
+ */
+#define PCUT_TEST_BEFORE \
+	PCUT_TEST_BEFORE_WITH_NUMBER(PCUT_ITEM_COUNTER)
+
+/** Define a tear-down function for a test suite.
+ *
+ * The code of the function immediately follows this macro.
+ *
+ * @code
+ * PCUT_TEST_SUITE(my_suite);
+ *
+ * PCUT_TEST_AFTER {
+ *     printf("This is executed after each test in this suite.\n");
+ * }
+ * @endcode
+ *
+ * There could be only a single tear-down function for each suite.
+ */
+#define PCUT_TEST_AFTER \
+	PCUT_TEST_AFTER_WITH_NUMBER(PCUT_ITEM_COUNTER)
+
+
+
+
+
+/*
+ * Import/export related macros
+ * ----------------------------
+ */
+
+/** @cond devel */
+
+/** Export test cases from current file.
+ *
+ * @see PCUT_EXPORT
+ *
+ * @param identifier Identifier of this block of tests.
+ * @param number Item number.
+ */
+#define PCUT_EXPORT_WITH_NUMBER(identifier, number) \
+	PCUT_ITEM_COUNTER_INCREMENT \
+	pcut_item_t pcut_exported_##identifier = { \
+		&PCUT_ITEM_NAME_PREV(number), \
+		NULL, \
+		-1, \
+		PCUT_KIND_SKIP, \
+		"exported_" #identifier, NULL, NULL, NULL, NULL, NULL, NULL \
+	}
+
+/** Import test cases from a different file.
+ *
+ * @see PCUT_EXPORT
+ *
+ * @param identifier Identifier of the tests to import.
+ * @param number Item number.
+ */
+#define PCUT_IMPORT_WITH_NUMBER(identifier, number) \
+	PCUT_ITEM_COUNTER_INCREMENT \
+	extern pcut_item_t pcut_exported_##identifier; \
+	PCUT_ADD_ITEM(number, PCUT_KIND_NESTED, \
+		"import_" #identifier, NULL, NULL, NULL, NULL, NULL, \
+		&pcut_exported_##identifier \
+	)
+
+/** @endcond */
+
+/** Export test cases from current file.
+ *
+ * @param identifier Identifier of this block of tests.
+ */
+#define PCUT_EXPORT(identifier) \
+	PCUT_EXPORT_WITH_NUMBER(identifier, PCUT_ITEM_COUNTER)
+
+/** Import test cases from a different file.
+ *
+ * @param identifier Identifier of the tests to import.
+ * (previously exported with PCUT_EXPORT).
+ */
+#define PCUT_IMPORT(identifier) \
+	PCUT_IMPORT_WITH_NUMBER(identifier, PCUT_ITEM_COUNTER)
+
+
+
+
+
+/*
+ * PCUT initialization and invocation macros
+ * -----------------------------------------
+ */
+
+/** @cond devel */
+
+/** Initialize the PCUT testing framework with a first item.
+ *
+ * @param first_number Number of the first item.
+ */
+#define PCUT_INIT_WITH_NUMBER(first_number) \
+	PCUT_ITEM_COUNTER_INCREMENT \
+	static pcut_item_t PCUT_ITEM_NAME(first_number) = { \
+		NULL, \
+		NULL, \
+		-1, \
+		PCUT_KIND_SKIP, \
+		"init", NULL, NULL, NULL, NULL, NULL, NULL \
+	}; \
+	PCUT_TEST_SUITE(Default);
+
+int pcut_main(pcut_item_t *last, int argc, char *argv[]);
+
+/** Insert code to run all the tests.
+ *
+ * @param number Item number.
+ */
+#define PCUT_MAIN_WITH_NUMBER(number, ...) \
+	PCUT_ITEM_COUNTER_INCREMENT \
+	static pcut_main_extra_t pcut_main_extras[] = { \
+		__VA_ARGS__ \
+	}; \
+	static pcut_item_t pcut_item_last = { \
+		&PCUT_ITEM_NAME_PREV(number), \
+		NULL, \
+		-1, \
+		PCUT_KIND_SKIP, \
+		"main", NULL, NULL, NULL, \
+		NULL, \
+		pcut_main_extras, \
+		NULL \
+	}; \
+	int main(int argc, char *argv[]) { \
+		return pcut_main(&pcut_item_last, argc, argv); \
+	}
+
+/** Terminate list of extra options for main. */
+#define PCUT_MAIN_EXTRA_SET_LAST \
+	{ PCUT_MAIN_EXTRA_LAST, NULL, NULL }
+
+/** @endcond */
+
+/** Initialize the PCUT testing framework. */
+#define PCUT_INIT \
+	PCUT_INIT_WITH_NUMBER(PCUT_ITEM_COUNTER)
+
+/** Insert code to run all the tests. */
+#define PCUT_MAIN() \
+	PCUT_MAIN_WITH_NUMBER(PCUT_ITEM_COUNTER, PCUT_MAIN_EXTRA_SET_LAST)
+
+
+/** Set callback for PCUT initialization.
+ *
+ * Use from within PCUT_CUSTOM_MAIN().
+ *
+ * @warning The callback is called for each test and also for the wrapping
+ * invocation.
+ */
+#define PCUT_MAIN_SET_INIT_HOOK(callback) \
+	{ PCUT_MAIN_EXTRA_INIT_HOOK, callback, NULL }
+
+/** Set callback for PCUT pre-initialization.
+ *
+ * Use from within PCUT_CUSTOM_MAIN().
+ * This callback is useful only if you want to manipulate command-line
+ * arguments.
+ * You probably will not need this.
+ *
+ * @warning The callback is called for each test and also for the wrapping
+ * invocation.
+ */
+#define PCUT_MAIN_SET_PREINIT_HOOK(callback) \
+	{ PCUT_MAIN_EXTRA_PREINIT_HOOK, NULL, callback }
+
+
+/** Set XML report as default.
+ *
+ * Use from within PCUT_CUSTOM_MAIN().
+ *
+ */
+#define PCUT_MAIN_SET_XML_REPORT \
+	{ PCUT_MAIN_EXTRA_REPORT_XML, NULL, NULL }
+
+
+/** Insert code to run all tests. */
+#define PCUT_CUSTOM_MAIN(...) \
+	PCUT_MAIN_WITH_NUMBER(PCUT_ITEM_COUNTER, \
+		PCUT_VARG_GET_FIRST(__VA_ARGS__, PCUT_MAIN_EXTRA_SET_LAST), \
+		PCUT_VARG_SKIP_FIRST(__VA_ARGS__, PCUT_MAIN_EXTRA_SET_LAST) \
+ 	)
+
+/**
+ * @}
+ */
+
+#endif
Index: uspace/lib/pcut/src/assert.c
===================================================================
--- uspace/lib/pcut/src/assert.c	(revision bf45993c05fbff161c55a858a73b7488e832d63c)
+++ uspace/lib/pcut/src/assert.c	(revision bf45993c05fbff161c55a858a73b7488e832d63c)
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 2012-2013 Vojtech Horky
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * @file
+ * Formatting and processing of failed assertion messages.
+ *
+ * We are using static buffers to prevent any calls to malloc()/free()
+ * by the testing framework.
+ */
+
+/** We need _BSD_SOURCE because of vsnprintf() when compiling under C89. */
+#define _BSD_SOURCE
+
+#include "internal.h"
+#include <setjmp.h>
+#include <stdarg.h>
+#include <stdio.h>
+
+/** Maximum length of failed-assert message. */
+#define MAX_MESSAGE_LENGTH 256
+
+/** How many assertion messages we need to keep in memory at once. */
+#define MESSAGE_BUFFER_COUNT 2
+
+/** Assertion message buffers. */
+static char message_buffer[MESSAGE_BUFFER_COUNT][MAX_MESSAGE_LENGTH + 1];
+
+/** Currently active assertion buffer. */
+static int message_buffer_index = 0;
+
+void pcut_failed_assertion_fmt(const char *filename, int line, const char *fmt, ...) {
+	va_list args;
+	char *current_buffer = message_buffer[message_buffer_index];
+	size_t offset = 0;
+	message_buffer_index = (message_buffer_index + 1) % MESSAGE_BUFFER_COUNT;
+
+	snprintf(current_buffer, MAX_MESSAGE_LENGTH, "%s:%d: ", filename, line);
+	offset = pcut_str_size(current_buffer);
+
+	if (offset + 1 < MAX_MESSAGE_LENGTH) {
+		va_start(args, fmt);
+		vsnprintf(current_buffer + offset, MAX_MESSAGE_LENGTH - offset, fmt, args);
+		va_end(args);
+	}
+
+	pcut_failed_assertion(current_buffer);
+}
Index: uspace/lib/pcut/src/internal.h
===================================================================
--- uspace/lib/pcut/src/internal.h	(revision bf45993c05fbff161c55a858a73b7488e832d63c)
+++ uspace/lib/pcut/src/internal.h	(revision bf45993c05fbff161c55a858a73b7488e832d63c)
@@ -0,0 +1,200 @@
+/*
+ * Copyright (c) 2012-2013 Vojtech Horky
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @file
+ * Common definitions internally used in PCUT.
+ */
+
+#ifndef PCUT_INTERNAL_H_GUARD
+#define PCUT_INTERNAL_H_GUARD
+
+#include <pcut/pcut.h>
+#include <stdlib.h>
+
+
+/** @def PCUT_DEBUG(msg, ...)
+ * Debug printing.
+ *
+ * By default, this macro does nothing. Define PCUT_DEBUG_BUILD to
+ * actually print the messages to the console.
+ *
+ * @param msg Printf-like formatting message.
+ * @param ... Extra arguments for printf.
+ */
+#ifdef PCUT_DEBUG_BUILD
+#include <stdio.h>
+#define PCUT_DEBUG_INTERNAL(msg, ...) \
+	fprintf(stderr, "[PCUT %s:%d]: " msg "%s", __FILE__, __LINE__, __VA_ARGS__)
+#define PCUT_DEBUG(...) \
+	PCUT_DEBUG_INTERNAL( \
+		PCUT_VARG_GET_FIRST(__VA_ARGS__, this_arg_is_ignored), \
+		PCUT_VARG_SKIP_FIRST(__VA_ARGS__, "\n") \
+	)
+#else
+#define PCUT_DEBUG(...) (void)0
+#endif
+
+
+/** Mark a variable as unused. */
+#define PCUT_UNUSED(x) ((void)x)
+
+/** Forking mode for test execution.
+ *
+ * In this mode, each test is run in a separate process.
+ * This ensures that even SIGSEGV does not stop the framework itself.
+ */
+#define PCUT_RUN_MODE_FORKING 1
+
+/** Single-process mode for test execution.
+ *
+ * This mode is used when new process is launched when in forking-mode or
+ * this mode can be used if we are sure that no test would fail
+ * fatally (that is causing an unexpected program exit).
+ */
+#define PCUT_RUN_MODE_SINGLE 2
+
+/** Test outcome: test passed. */
+#define TEST_OUTCOME_PASS 1
+
+/** Test outcome: test failed. */
+#define TEST_OUTCOME_FAIL 2
+
+/** Test outcome: test failed unexpectedly. */
+#define TEST_OUTCOME_ERROR 3
+
+
+/*
+ * Use sprintf_s in Windows but only with Microsoft compiler.
+ * Namely, let MinGW use snprintf.
+ */
+#if (defined(__WIN64) || defined(__WIN32) || defined(_WIN32)) && defined(_MSC_VER)
+#define snprintf sprintf_s
+#endif
+
+extern int pcut_run_mode;
+
+
+pcut_item_t *pcut_fix_list_get_real_head(pcut_item_t *last);
+int pcut_count_tests(pcut_item_t *it);
+void pcut_print_items(pcut_item_t *first);
+
+pcut_item_t *pcut_get_real_next(pcut_item_t *item);
+pcut_item_t *pcut_get_real(pcut_item_t *item);
+void pcut_print_tests(pcut_item_t *first);
+int pcut_is_arg_with_number(const char *arg, const char *opt, int *value);
+
+void pcut_run_test_forking(const char *self_path, pcut_item_t *test);
+int pcut_run_test_forked(pcut_item_t *test);
+int pcut_run_test_single(pcut_item_t *test);
+
+int pcut_get_test_timeout(pcut_item_t *test);
+
+void pcut_failed_assertion(const char *message);
+void pcut_print_fail_message(const char *msg);
+
+/** Reporting callbacks structure. */
+typedef struct pcut_report_ops pcut_report_ops_t;
+
+/** @copydoc pcut_report_ops_t */
+struct pcut_report_ops {
+	/** Initialize the reporting, given all tests. */
+	void (*init)(pcut_item_t *);
+	/** Finalize the reporting. */
+	void (*done)(void);
+	/** Test suite just started. */
+	void (*suite_start)(pcut_item_t *);
+	/** Test suite completed. */
+	void (*suite_done)(pcut_item_t *);
+	/** Test is about to start. */
+	void (*test_start)(pcut_item_t *);
+	/** Test completed. */
+	void (*test_done)(pcut_item_t *, int, const char *, const char *,
+		const char *);
+};
+
+void pcut_report_register_handler(pcut_report_ops_t *ops);
+
+void pcut_report_init(pcut_item_t *all_items);
+void pcut_report_suite_start(pcut_item_t *suite);
+void pcut_report_suite_done(pcut_item_t *suite);
+void pcut_report_test_start(pcut_item_t *test);
+void pcut_report_test_done(pcut_item_t *test, int outcome,
+		const char *error_message, const char *teardown_error_message,
+		const char *extra_output);
+void pcut_report_test_done_unparsed(pcut_item_t *test, int outcome,
+		const char *unparsed_output, size_t unparsed_output_size);
+void pcut_report_done(void);
+
+/* OS-dependent functions. */
+
+/** Hook to execute before test starts.
+ *
+ * Useful for OS-specific preparations prior to launching the actual
+ * test code (i. e. sandboxing the process more etc.).
+ *
+ * This function is not run by the launcher process that only
+ * starts other tests in separate processes.
+ *
+ * @param test The test that is about to be executed.
+ */
+void pcut_hook_before_test(pcut_item_t *test);
+
+/** Tell whether two strings start with the same prefix.
+ *
+ * @param a First string.
+ * @param b Second string.
+ * @param len Length of common prefix.
+ * @return Whether first @p len characters of @p a are the same as in @p b.
+ */
+int pcut_str_start_equals(const char *a, const char *b, int len);
+
+/** Get size of string in bytes.
+ *
+ * @param s String in question.
+ * @return Size of @p s in bytes.
+ */
+int pcut_str_size(const char *s);
+
+/** Convert string to integer.
+ *
+ * @param s String with integer.
+ * @return Converted integer.
+ */
+int pcut_str_to_int(const char *s);
+
+/** Find character in a string.
+ *
+ * @param haystack Where to look for the @p needle.
+ * @param needle Character to find.
+ * @return String starting with @p needle.
+ * @retval NULL there is no @p needle in @p haystack.
+ */
+char *pcut_str_find_char(const char *haystack, const char needle);
+
+
+#endif
Index: uspace/lib/pcut/src/list.c
===================================================================
--- uspace/lib/pcut/src/list.c	(revision bf45993c05fbff161c55a858a73b7488e832d63c)
+++ uspace/lib/pcut/src/list.c	(revision bf45993c05fbff161c55a858a73b7488e832d63c)
@@ -0,0 +1,206 @@
+/*
+ * Copyright (c) 2012-2013 Vojtech Horky
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @file
+ *
+ * Helper functions for working with list of items.
+ */
+
+#include <assert.h>
+#include <stdlib.h>
+#include "internal.h"
+#include <pcut/pcut.h>
+
+
+/** Find next item with actual content.
+ *
+ * @param item Head of the list.
+ * @return First item with actual content or NULL on end of list.
+ */
+pcut_item_t *pcut_get_real_next(pcut_item_t *item) {
+	if (item == NULL) {
+		return NULL;
+	}
+
+	do {
+		item = item->next;
+	} while ((item != NULL) && (item->kind == PCUT_KIND_SKIP));
+
+
+	return item;
+}
+
+/** Retrieve the first item with actual content.
+ *
+ * Unlike pcut_get_real_next(), where we always advance after the
+ * first item, here the @p item itself could be returned.
+ *
+ * @param item Head of the list.
+ * @return First item with actual content or NULL on end of list.
+ */
+pcut_item_t *pcut_get_real(pcut_item_t *item) {
+	if (item == NULL) {
+		return NULL;
+	}
+
+	if (item->kind == PCUT_KIND_SKIP) {
+		return pcut_get_real_next(item);
+	} else {
+		return item;
+	}
+}
+
+
+/** In-line nested lists into the parent.
+ *
+ * @param nested Head of the nested list.
+ */
+static void inline_nested_lists(pcut_item_t *nested) {
+	pcut_item_t *first;
+
+	if (nested->kind != PCUT_KIND_NESTED) {
+		return;
+	}
+
+	if (nested->nested == NULL) {
+		nested->kind = PCUT_KIND_SKIP;
+		return;
+	}
+
+	first = pcut_fix_list_get_real_head(nested->nested);
+	nested->nested->next = nested->next;
+	if (nested->next != NULL) {
+		nested->next->previous = nested->nested;
+	}
+	nested->next = first;
+	first->previous = nested;
+
+	nested->kind = PCUT_KIND_SKIP;
+}
+
+/** Assing unique ids to each item in the list.
+ *
+ * @param first List head.
+ */
+static void set_ids(pcut_item_t *first) {
+	int id = 1;
+	pcut_item_t *it;
+
+	assert(first != NULL);
+
+	if (first->kind == PCUT_KIND_SKIP) {
+		first = pcut_get_real_next(first);
+	}
+
+	for (it = first; it != NULL; it = pcut_get_real_next(it)) {
+		it->id = id;
+		id++;
+	}
+}
+
+/** Hide tests that are marked to be skipped.
+ *
+ * Go through all tests and those that have PCUT_EXTRA_SKIP mark
+ * as skipped with PCUT_KIND_SKIP.
+ *
+ * @param first Head of the list.
+ */
+static void detect_skipped_tests(pcut_item_t *first) {
+	pcut_item_t *it;
+
+	assert(first != NULL);
+	if (first->kind == PCUT_KIND_SKIP) {
+		first = pcut_get_real_next(first);
+	}
+
+	for (it = first; it != NULL; it = pcut_get_real_next(it)) {
+		pcut_extra_t *extras;
+
+		if (it->kind != PCUT_KIND_TEST) {
+			continue;
+		}
+
+		extras = it->extras;
+		while (extras->type != PCUT_EXTRA_LAST) {
+			if (extras->type == PCUT_EXTRA_SKIP) {
+				it->kind = PCUT_KIND_SKIP;
+				break;
+			}
+			extras++;
+		}
+	}
+}
+
+/** Convert the static single-linked list into a flat double-linked list.
+ *
+ * The conversion includes
+ * * adding forward links
+ * * flattening of any nested lists
+ * * assigning of unique ids
+ *
+ * @param last Tail of the list.
+ * @return Head of the fixed list.
+ */
+pcut_item_t *pcut_fix_list_get_real_head(pcut_item_t *last) {
+	pcut_item_t *next, *it;
+
+	last->next = NULL;
+
+	inline_nested_lists(last);
+
+	next = last;
+	it = last->previous;
+	while (it != NULL) {
+		it->next = next;
+		inline_nested_lists(it);
+		next = it;
+		it = it->previous;
+	}
+
+	detect_skipped_tests(next);
+
+	set_ids(next);
+
+	return next;
+}
+
+/** Compute the number of all tests in a list.
+ *
+ * @param it Head of the list.
+ * @return Number of tests.
+ */
+int pcut_count_tests(pcut_item_t *it) {
+	int count = 0;
+	while (it != NULL) {
+		if (it->kind == PCUT_KIND_TEST) {
+			count++;
+		}
+		it = pcut_get_real_next(it);
+	}
+	return count;
+}
Index: uspace/lib/pcut/src/main.c
===================================================================
--- uspace/lib/pcut/src/main.c	(revision bf45993c05fbff161c55a858a73b7488e832d63c)
+++ uspace/lib/pcut/src/main.c	(revision bf45993c05fbff161c55a858a73b7488e832d63c)
@@ -0,0 +1,287 @@
+/*
+ * Copyright (c) 2012-2013 Vojtech Horky
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @file
+ *
+ * The main control loop of the whole library.
+ */
+
+#include "internal.h"
+#include "report/report.h"
+#include <assert.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+/** Current running mode. */
+int pcut_run_mode = PCUT_RUN_MODE_FORKING;
+
+/** Empty list to bypass special handling for NULL. */
+static pcut_main_extra_t empty_main_extra[] = {
+	PCUT_MAIN_EXTRA_SET_LAST
+};
+
+/** Helper for iteration over main extras. */
+#define FOR_EACH_MAIN_EXTRA(extras, it) \
+	for (it = extras; it->type != PCUT_MAIN_EXTRA_LAST; it++)
+
+/** Checks whether the argument is an option followed by a number.
+ *
+ * @param arg Argument from the user.
+ * @param opt Option, including the leading dashes.
+ * @param value Where to store the integer value.
+ * @return Whether @p arg is @p opt followed by a number.
+ */
+int pcut_is_arg_with_number(const char *arg, const char *opt, int *value) {
+	int opt_len = pcut_str_size(opt);
+	if (! pcut_str_start_equals(arg, opt, opt_len)) {
+		return 0;
+	}
+	*value = pcut_str_to_int(arg + opt_len);
+	return 1;
+}
+
+
+/** Find item by its id.
+ *
+ * @param first List to search.
+ * @param id Id to find.
+ * @return The item with given id.
+ * @retval NULL No item with such id exists in the list.
+ */
+static pcut_item_t *pcut_find_by_id(pcut_item_t *first, int id) {
+	pcut_item_t *it = pcut_get_real(first);
+	while (it != NULL) {
+		if (it->id == id) {
+			return it;
+		}
+		it = pcut_get_real_next(it);
+	}
+	return NULL;
+}
+
+/** Run the whole test suite.
+ *
+ * @param suite Suite to run.
+ * @param last Pointer to first item after this suite is stored here.
+ * @param prog_path Path to the current binary (used in forked mode).
+ */
+static void run_suite(pcut_item_t *suite, pcut_item_t **last, const char *prog_path) {
+	int is_first_test = 1;
+	int total_count = 0;
+
+	pcut_item_t *it = pcut_get_real_next(suite);
+	if ((it == NULL) || (it->kind == PCUT_KIND_TESTSUITE)) {
+		goto leave_no_print;
+	}
+
+	for (; it != NULL; it = pcut_get_real_next(it)) {
+		if (it->kind == PCUT_KIND_TESTSUITE) {
+			goto leave_ok;
+		}
+		if (it->kind != PCUT_KIND_TEST) {
+			continue;
+		}
+
+		if (is_first_test) {
+			pcut_report_suite_start(suite);
+			is_first_test = 0;
+		}
+
+		if (pcut_run_mode == PCUT_RUN_MODE_FORKING) {
+			pcut_run_test_forking(prog_path, it);
+		} else {
+			pcut_run_test_single(it);
+		}
+		total_count++;
+	}
+
+leave_ok:
+	if (total_count > 0) {
+		pcut_report_suite_done(suite);
+	}
+
+leave_no_print:
+	if (last != NULL) {
+		*last = it;
+	}
+}
+
+/** Add direct pointers to set-up/tear-down functions to a suites.
+ *
+ * At start-up, set-up and tear-down functions are scattered in the
+ * list as siblings of suites and tests.
+ * This puts them into the structure describing the suite itself.
+ *
+ * @param first First item of the list.
+ */
+static void set_setup_teardown_callbacks(pcut_item_t *first) {
+	pcut_item_t *active_suite = NULL;
+	pcut_item_t *it;
+	for (it = first; it != NULL; it = pcut_get_real_next(it)) {
+		if (it->kind == PCUT_KIND_TESTSUITE) {
+			active_suite = it;
+		} else if (it->kind == PCUT_KIND_SETUP) {
+			if (active_suite != NULL) {
+				active_suite->setup_func = it->setup_func;
+			}
+			it->kind = PCUT_KIND_SKIP;
+		} else if (it->kind == PCUT_KIND_TEARDOWN) {
+			if (active_suite != NULL) {
+				active_suite->teardown_func = it->teardown_func;
+			}
+			it->kind = PCUT_KIND_SKIP;
+		} else {
+			/* Not interesting right now. */
+		}
+	}
+}
+
+/** The main function of PCUT.
+ *
+ * This function is expected to be called as the only function in
+ * normal main().
+ *
+ * @param last Pointer to the last item defined by PCUT_TEST macros.
+ * @param argc Original argc of the program.
+ * @param argv Original argv of the program.
+ * @return Program exit code.
+ */
+int pcut_main(pcut_item_t *last, int argc, char *argv[]) {
+	pcut_item_t *items = pcut_fix_list_get_real_head(last);
+	pcut_item_t *it;
+	pcut_main_extra_t *main_extras = last->main_extras;
+	pcut_main_extra_t *main_extras_it;
+
+	int run_only_suite = -1;
+	int run_only_test = -1;
+
+	if (main_extras == NULL) {
+		main_extras = empty_main_extra;
+	}
+
+	pcut_report_register_handler(&pcut_report_tap);
+
+	FOR_EACH_MAIN_EXTRA(main_extras, main_extras_it) {
+		if (main_extras_it->type == PCUT_MAIN_EXTRA_REPORT_XML) {
+			pcut_report_register_handler(&pcut_report_xml);
+		}
+		if (main_extras_it->type == PCUT_MAIN_EXTRA_PREINIT_HOOK) {
+			main_extras_it->preinit_hook(&argc, &argv);
+		}
+	}
+
+	if (argc > 1) {
+		int i;
+		for (i = 1; i < argc; i++) {
+			pcut_is_arg_with_number(argv[i], "-s", &run_only_suite);
+			pcut_is_arg_with_number(argv[i], "-t", &run_only_test);
+			if (pcut_str_equals(argv[i], "-l")) {
+				pcut_print_tests(items);
+				return 0;
+			}
+			if (pcut_str_equals(argv[i], "-x")) {
+				pcut_report_register_handler(&pcut_report_xml);
+			}
+#ifndef PCUT_NO_LONG_JUMP
+			if (pcut_str_equals(argv[i], "-u")) {
+				pcut_run_mode = PCUT_RUN_MODE_SINGLE;
+			}
+#endif
+		}
+	}
+
+	setvbuf(stdout, NULL, _IONBF, 0);
+	set_setup_teardown_callbacks(items);
+
+	FOR_EACH_MAIN_EXTRA(main_extras, main_extras_it) {
+		if (main_extras_it->type == PCUT_MAIN_EXTRA_INIT_HOOK) {
+			main_extras_it->init_hook();
+		}
+	}
+
+	PCUT_DEBUG("run_only_suite = %d   run_only_test = %d", run_only_suite, run_only_test);
+
+	if ((run_only_suite >= 0) && (run_only_test >= 0)) {
+		printf("Specify either -s or -t!\n");
+		return 1;
+	}
+
+	if (run_only_suite > 0) {
+		pcut_item_t *suite = pcut_find_by_id(items, run_only_suite);
+		if (suite == NULL) {
+			printf("Suite not found, aborting!\n");
+			return 2;
+		}
+		if (suite->kind != PCUT_KIND_TESTSUITE) {
+			printf("Invalid suite id!\n");
+			return 3;
+		}
+
+		run_suite(suite, NULL, argv[0]);
+		return 0;
+	}
+
+	if (run_only_test > 0) {
+		int rc;
+		pcut_item_t *test = pcut_find_by_id(items, run_only_test);
+		if (test == NULL) {
+			printf("Test not found, aborting!\n");
+			return 2;
+		}
+		if (test->kind != PCUT_KIND_TEST) {
+			printf("Invalid test id!\n");
+			return 3;
+		}
+
+		if (pcut_run_mode == PCUT_RUN_MODE_SINGLE) {
+			rc = pcut_run_test_single(test);
+		} else {
+			rc = pcut_run_test_forked(test);
+		}
+
+		return rc;
+	}
+
+	/* Otherwise, run the whole thing. */
+	pcut_report_init(items);
+
+	it = items;
+	while (it != NULL) {
+		if (it->kind == PCUT_KIND_TESTSUITE) {
+			pcut_item_t *tmp;
+			run_suite(it, &tmp, argv[0]);
+			it = tmp;
+		} else {
+			it = pcut_get_real_next(it);
+		}
+	}
+
+	pcut_report_done();
+
+	return 0;
+}
Index: uspace/lib/pcut/src/os/generic.c
===================================================================
--- uspace/lib/pcut/src/os/generic.c	(revision bf45993c05fbff161c55a858a73b7488e832d63c)
+++ uspace/lib/pcut/src/os/generic.c	(revision bf45993c05fbff161c55a858a73b7488e832d63c)
@@ -0,0 +1,149 @@
+/*
+ * Copyright (c) 2013 Vojtech Horky
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @file
+ *
+ * Platform-dependent test execution function when system() is available.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <errno.h>
+#include <assert.h>
+#include <string.h>
+#include "../internal.h"
+
+/** Maximum command-line length. */
+#define PCUT_COMMAND_LINE_BUFFER_SIZE 256
+
+/** Maximum length of a temporary file name. */
+#define PCUT_TEMP_FILENAME_BUFFER_SIZE 128
+
+/** Maximum size of stdout we are able to capture. */
+#define OUTPUT_BUFFER_SIZE 8192
+
+/* Format the command to launch a test according to OS we are running on. */
+
+#if defined(__WIN64) || defined(__WIN32) || defined(_WIN32)
+#include <process.h>
+
+#define FORMAT_COMMAND(buffer, buffer_size, self_path, test_id, temp_file) \
+	snprintf(buffer, buffer_size, "\"\"%s\" -t%d >%s\"", self_path, test_id, temp_file)
+#define FORMAT_TEMP_FILENAME(buffer, buffer_size) \
+	snprintf(buffer, buffer_size, "pcut_%d.tmp", _getpid())
+
+#elif defined(__unix)
+#include <unistd.h>
+
+#define FORMAT_COMMAND(buffer, buffer_size, self_path, test_id, temp_file) \
+	snprintf(buffer, buffer_size, "%s -t%d &>%s", self_path, test_id, temp_file)
+#define FORMAT_TEMP_FILENAME(buffer, buffer_size) \
+	snprintf(buffer, buffer_size, "pcut_%d.tmp", getpid())
+
+#else
+#error "Unknown operating system."
+#endif
+
+/** Buffer for assertion and other error messages. */
+static char error_message_buffer[OUTPUT_BUFFER_SIZE];
+
+/** Buffer for stdout from the test. */
+static char extra_output_buffer[OUTPUT_BUFFER_SIZE];
+
+/** Prepare for a new test.
+ *
+ * @param test Test that is about to start.
+ */
+static void before_test_start(pcut_item_t *test) {
+	pcut_report_test_start(test);
+
+	memset(error_message_buffer, 0, OUTPUT_BUFFER_SIZE);
+	memset(extra_output_buffer, 0, OUTPUT_BUFFER_SIZE);
+}
+
+/** Convert program exit code to test outcome.
+ *
+ * @param status Return value from the system() function.
+ * @return Test outcome code.
+ */
+static int convert_wait_status_to_outcome(int status) {
+	if (status < 0) {
+		return TEST_OUTCOME_ERROR;
+	} else if (status == 0) {
+		return TEST_OUTCOME_PASS;
+	} else {
+		return TEST_OUTCOME_FAIL;
+	}
+}
+
+/** Run the test as a new process and report the result.
+ *
+ * @param self_path Path to itself, that is to current binary.
+ * @param test Test to be run.
+ */
+void pcut_run_test_forking(const char *self_path, pcut_item_t *test) {
+	int rc;
+	FILE *tempfile;
+	char tempfile_name[PCUT_TEMP_FILENAME_BUFFER_SIZE];
+	char command[PCUT_COMMAND_LINE_BUFFER_SIZE];
+
+	before_test_start(test);
+
+	FORMAT_TEMP_FILENAME(tempfile_name, PCUT_TEMP_FILENAME_BUFFER_SIZE - 1);
+	FORMAT_COMMAND(command, PCUT_COMMAND_LINE_BUFFER_SIZE - 1,
+		self_path, (test)->id, tempfile_name);
+	
+	PCUT_DEBUG("Will execute <%s> (temp file <%s>) with system().",
+		command, tempfile_name);
+
+	rc = system(command);
+
+	PCUT_DEBUG("system() returned 0x%04X", rc);
+
+	rc = convert_wait_status_to_outcome(rc);
+
+	tempfile = fopen(tempfile_name, "rb");
+	if (tempfile == NULL) {
+		pcut_report_test_done(test, TEST_OUTCOME_ERROR, "Failed to open temporary file.", NULL, NULL);
+		return;
+	}
+
+	fread(extra_output_buffer, 1, OUTPUT_BUFFER_SIZE, tempfile);
+	fclose(tempfile);
+	remove(tempfile_name);
+
+	pcut_report_test_done_unparsed(test, rc, extra_output_buffer, OUTPUT_BUFFER_SIZE);
+}
+
+void pcut_hook_before_test(pcut_item_t *test) {
+	PCUT_UNUSED(test);
+
+	/* Do nothing. */
+}
+
Index: uspace/lib/pcut/src/os/helenos.c
===================================================================
--- uspace/lib/pcut/src/os/helenos.c	(revision bf45993c05fbff161c55a858a73b7488e832d63c)
+++ uspace/lib/pcut/src/os/helenos.c	(revision bf45993c05fbff161c55a858a73b7488e832d63c)
@@ -0,0 +1,235 @@
+/*
+ * Copyright (c) 2013 Vojtech Horky
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @file
+ *
+ * Implementation of platform-dependent functions for HelenOS.
+ */
+
+#include <stdlib.h>
+#include <str.h>
+#include <str_error.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <errno.h>
+#include <assert.h>
+#include <stdio.h>
+#include <task.h>
+#include <fcntl.h>
+#include <fibril_synch.h>
+#include "../internal.h"
+
+
+/* String functions. */
+
+int pcut_str_equals(const char *a, const char *b) {
+	return str_cmp(a, b) == 0;
+}
+
+
+int pcut_str_start_equals(const char *a, const char *b, int len) {
+	return str_lcmp(a, b, len) == 0;
+}
+
+int pcut_str_size(const char *s) {
+	return str_size(s);
+}
+
+int pcut_str_to_int(const char *s) {
+	int result = strtol(s, NULL, 10);
+	return result;
+}
+
+char *pcut_str_find_char(const char *haystack, const char needle) {
+	return str_chr(haystack, needle);
+}
+
+void pcut_str_error(int error, char *buffer, int size) {
+	const char *str = str_error(error);
+	if (str == NULL) {
+		str = "(strerror failure)";
+	}
+	str_cpy(buffer, size, str);
+}
+
+
+/* Forking-mode related functions. */
+
+/** Maximum width of a test number. */
+#define MAX_TEST_NUMBER_WIDTH 24
+
+/** Maximum length of a temporary file name. */
+#define PCUT_TEMP_FILENAME_BUFFER_SIZE 128
+
+/** Maximum command-line length. */
+#define MAX_COMMAND_LINE_LENGTH 1024
+
+/** Maximum size of stdout we are able to capture. */
+#define OUTPUT_BUFFER_SIZE 8192
+
+/** Buffer for assertion and other error messages. */
+static char error_message_buffer[OUTPUT_BUFFER_SIZE];
+
+/** Buffer for stdout from the test. */
+static char extra_output_buffer[OUTPUT_BUFFER_SIZE];
+
+/** Prepare for a new test.
+ *
+ * @param test Test that is about to be run.
+ */
+static void before_test_start(pcut_item_t *test) {
+	pcut_report_test_start(test);
+
+	memset(error_message_buffer, 0, OUTPUT_BUFFER_SIZE);
+	memset(extra_output_buffer, 0, OUTPUT_BUFFER_SIZE);
+}
+
+/** Mutex guard for forced_termination_cv. */
+static fibril_mutex_t forced_termination_mutex
+	= FIBRIL_MUTEX_INITIALIZER(forced_termination_mutex);
+
+/** Condition-variable for checking whether test timed-out. */
+static fibril_condvar_t forced_termination_cv
+	= FIBRIL_CONDVAR_INITIALIZER(forced_termination_cv);
+
+/** Spawned task id. */
+static task_id_t test_task_id;
+
+/** Flag whether test is still running.
+ *
+ * This flag is used when checking whether test timed-out.
+ */
+static int test_running;
+
+/** Main fibril for checking whether test timed-out.
+ *
+ * @param arg Test that is currently running (pcut_item_t *).
+ * @return EOK Always.
+ */
+static int test_timeout_handler_fibril(void *arg) {
+	pcut_item_t *test = arg;
+	int timeout_sec = pcut_get_test_timeout(test);
+	suseconds_t timeout_us = (suseconds_t) timeout_sec * 1000 * 1000;
+
+	fibril_mutex_lock(&forced_termination_mutex);
+	if (!test_running) {
+		goto leave_no_kill;
+	}
+	int rc = fibril_condvar_wait_timeout(&forced_termination_cv,
+		&forced_termination_mutex, timeout_us);
+	if (rc == ETIMEOUT) {
+		task_kill(test_task_id);
+	}
+leave_no_kill:
+	fibril_mutex_unlock(&forced_termination_mutex);
+	return EOK;
+}
+
+/** Run the test as a new task and report the result.
+ *
+ * @param self_path Path to itself, that is to current binary.
+ * @param test Test to be run.
+ */
+void pcut_run_test_forking(const char *self_path, pcut_item_t *test) {
+	before_test_start(test);
+
+	char tempfile_name[PCUT_TEMP_FILENAME_BUFFER_SIZE];
+	snprintf(tempfile_name, PCUT_TEMP_FILENAME_BUFFER_SIZE - 1, "pcut_%lld.tmp", (unsigned long long) task_get_id());
+	int tempfile = open(tempfile_name, O_CREAT | O_RDWR);
+	if (tempfile < 0) {
+		pcut_report_test_done(test, TEST_OUTCOME_ERROR, "Failed to create temporary file.", NULL, NULL);
+		return;
+	}
+
+	char test_number_argument[MAX_TEST_NUMBER_WIDTH];
+	snprintf(test_number_argument, MAX_TEST_NUMBER_WIDTH, "-t%d", test->id);
+
+	int *files[4];
+	int fd_stdin = fileno(stdin);
+	files[0] = &fd_stdin;
+	files[1] = &tempfile;
+	files[2] = &tempfile;
+	files[3] = NULL;
+
+	const char *const arguments[3] = {
+		self_path,
+		test_number_argument,
+		NULL
+	};
+
+	int status = TEST_OUTCOME_PASS;
+
+	task_wait_t test_task_wait;
+	int rc = task_spawnvf(&test_task_id, &test_task_wait, self_path, arguments, files);
+	if (rc != EOK) {
+		status = TEST_OUTCOME_ERROR;
+		goto leave_close_tempfile;
+	}
+
+	test_running = 1;
+
+	fid_t killer_fibril = fibril_create(test_timeout_handler_fibril, test);
+	if (killer_fibril == 0) {
+		/* FIXME: somehow announce this problem. */
+		task_kill(test_task_id);
+	} else {
+		fibril_add_ready(killer_fibril);
+	}
+
+	task_exit_t task_exit;
+	int task_retval;
+	rc = task_wait(&test_task_wait, &task_exit, &task_retval);
+	if (rc != EOK) {
+		status = TEST_OUTCOME_ERROR;
+		goto leave_close_tempfile;
+	}
+	if (task_exit == TASK_EXIT_UNEXPECTED) {
+		status = TEST_OUTCOME_ERROR;
+	} else {
+		status = task_retval == 0 ? TEST_OUTCOME_PASS : TEST_OUTCOME_FAIL;
+	}
+
+	fibril_mutex_lock(&forced_termination_mutex);
+	test_running = 0;
+	fibril_condvar_signal(&forced_termination_cv);
+	fibril_mutex_unlock(&forced_termination_mutex);
+
+	read_all(tempfile, extra_output_buffer, OUTPUT_BUFFER_SIZE);
+
+leave_close_tempfile:
+	close(tempfile);
+	unlink(tempfile_name);
+
+	pcut_report_test_done_unparsed(test, status, extra_output_buffer, OUTPUT_BUFFER_SIZE);
+}
+
+void pcut_hook_before_test(pcut_item_t *test) {
+	PCUT_UNUSED(test);
+
+	/* Do nothing. */
+}
Index: uspace/lib/pcut/src/os/stdc.c
===================================================================
--- uspace/lib/pcut/src/os/stdc.c	(revision bf45993c05fbff161c55a858a73b7488e832d63c)
+++ uspace/lib/pcut/src/os/stdc.c	(revision bf45993c05fbff161c55a858a73b7488e832d63c)
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2013 Vojtech Horky
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @file
+ *
+ * String operation functions for systems with a standard C library.
+ */
+
+#include <string.h>
+#include "../internal.h"
+
+int pcut_str_equals(const char *a, const char *b) {
+	return strcmp(a, b) == 0;
+}
+
+int pcut_str_start_equals(const char *a, const char *b, int len) {
+	return strncmp(a, b, len) == 0;
+}
+
+int pcut_str_size(const char *s) {
+	return strlen(s);
+}
+
+int pcut_str_to_int(const char *s) {
+	return atoi(s);
+}
+
+char *pcut_str_find_char(const char *haystack, const char needle) {
+	return strchr(haystack, needle);
+}
+
+void pcut_str_error(int error, char *buffer, int size) {
+	const char *str = strerror(error);
+	if (str == NULL) {
+		str = "(strerror failure)";
+	}
+	strncpy(buffer, str, size - 1);
+	/* Ensure correct termination. */
+	buffer[size - 1] = 0;
+}
Index: uspace/lib/pcut/src/os/unix.c
===================================================================
--- uspace/lib/pcut/src/os/unix.c	(revision bf45993c05fbff161c55a858a73b7488e832d63c)
+++ uspace/lib/pcut/src/os/unix.c	(revision bf45993c05fbff161c55a858a73b7488e832d63c)
@@ -0,0 +1,216 @@
+/*
+ * Copyright (c) 2013 Vojtech Horky
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @file
+ *
+ * Unix-specific functions for test execution via the fork() system call.
+ */
+
+/** We need _POSIX_SOURCE because of kill(). */
+#define _POSIX_SOURCE
+/** We need _BSD_SOURCE because of snprintf() when compiling under C89. */
+#define _BSD_SOURCE
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <signal.h>
+#include <errno.h>
+#include <assert.h>
+#include <sys/wait.h>
+#include <stdio.h>
+#include <string.h>
+#include "../internal.h"
+
+/** Maximum size of stdout we are able to capture. */
+#define OUTPUT_BUFFER_SIZE 8192
+
+/** Buffer for assertion and other error messages. */
+static char error_message_buffer[OUTPUT_BUFFER_SIZE];
+
+/** Buffer for stdout from the test. */
+static char extra_output_buffer[OUTPUT_BUFFER_SIZE];
+
+/** Prepare for a new test.
+ *
+ * @param test Test that is about to be run.
+ */
+static void before_test_start(pcut_item_t *test) {
+	pcut_report_test_start(test);
+
+	memset(error_message_buffer, 0, OUTPUT_BUFFER_SIZE);
+	memset(extra_output_buffer, 0, OUTPUT_BUFFER_SIZE);
+}
+
+/** PID of the forked process running the actual test. */
+static pid_t child_pid;
+
+/** Signal handler that kills the child.
+ *
+ * @param sig Signal number.
+ */
+static void kill_child_on_alarm(int sig) {
+	PCUT_UNUSED(sig);
+	kill(child_pid, SIGKILL);
+}
+
+/** Read full buffer from given file descriptor.
+ *
+ * This function exists to overcome the possibility that read() may
+ * not fill the full length of the provided buffer even when EOF is
+ * not reached.
+ *
+ * @param fd Opened file descriptor.
+ * @param buffer Buffer to store data into.
+ * @param buffer_size Size of the @p buffer in bytes.
+ * @return Number of actually read bytes.
+ */
+static size_t read_all(int fd, char *buffer, size_t buffer_size) {
+	ssize_t actually_read;
+	char *buffer_start = buffer;
+	do {
+		actually_read = read(fd, buffer, buffer_size);
+		if (actually_read > 0) {
+			buffer += actually_read;
+			buffer_size -= actually_read;
+			if (buffer_size == 0) {
+				break;
+			}
+		}
+	} while (actually_read > 0);
+	if (buffer_start != buffer) {
+		if (*(buffer - 1) == 10) {
+			*(buffer - 1) = 0;
+			buffer--;
+		}
+	}
+	return buffer - buffer_start;
+}
+
+/** Convert program exit code to test outcome.
+ *
+ * @param status Status value from the wait() function.
+ * @return Test outcome code.
+ */
+static int convert_wait_status_to_outcome(int status) {
+	if (WIFEXITED(status)) {
+		if (WEXITSTATUS(status) != 0) {
+			return TEST_OUTCOME_FAIL;
+		} else {
+			return TEST_OUTCOME_PASS;
+		}
+	}
+
+	if (WIFSIGNALED(status)) {
+		return TEST_OUTCOME_ERROR;
+	}
+
+	return status;
+}
+
+/** Run the test in a forked environment and report the result.
+ *
+ * @param self_path Ignored.
+ * @param test Test to be run.
+ */
+void pcut_run_test_forking(const char *self_path, pcut_item_t *test) {
+	int link_stdout[2], link_stderr[2];
+	int rc, status;
+	size_t stderr_size;
+
+	PCUT_UNUSED(self_path);
+
+	before_test_start(test);
+
+
+	rc = pipe(link_stdout);
+	if (rc == -1) {
+		snprintf(error_message_buffer, OUTPUT_BUFFER_SIZE - 1,
+				"pipe() failed: %s.", strerror(rc));
+		pcut_report_test_done(test, TEST_OUTCOME_ERROR, error_message_buffer, NULL, NULL);
+		return;
+	}
+	rc = pipe(link_stderr);
+	if (rc == -1) {
+		snprintf(error_message_buffer, OUTPUT_BUFFER_SIZE - 1,
+				"pipe() failed: %s.", strerror(rc));
+		pcut_report_test_done(test, TEST_OUTCOME_ERROR, error_message_buffer, NULL, NULL);
+		return;
+	}
+
+	child_pid = fork();
+	if (child_pid == (pid_t)-1) {
+		snprintf(error_message_buffer, OUTPUT_BUFFER_SIZE - 1,
+			"fork() failed: %s.", strerror(rc));
+		rc = TEST_OUTCOME_ERROR;
+		goto leave_close_pipes;
+	}
+
+	if (child_pid == 0) {
+		/* We are the child. */
+		dup2(link_stdout[1], STDOUT_FILENO);
+		close(link_stdout[0]);
+		dup2(link_stderr[1], STDERR_FILENO);
+		close(link_stderr[0]);
+
+		rc = pcut_run_test_forked(test);
+
+		exit(rc);
+	}
+
+	close(link_stdout[1]);
+	close(link_stderr[1]);
+
+	signal(SIGALRM, kill_child_on_alarm);
+	alarm(pcut_get_test_timeout(test));
+
+	stderr_size = read_all(link_stderr[0], extra_output_buffer, OUTPUT_BUFFER_SIZE - 1);
+	read_all(link_stdout[0], extra_output_buffer, OUTPUT_BUFFER_SIZE - 1 - stderr_size);
+
+	wait(&status);
+	alarm(0);
+
+	rc = convert_wait_status_to_outcome(status);
+
+	goto leave_close_parent_pipe;
+
+leave_close_pipes:
+	close(link_stdout[1]);
+	close(link_stderr[1]);
+leave_close_parent_pipe:
+	close(link_stdout[0]);
+	close(link_stderr[0]);
+
+	pcut_report_test_done_unparsed(test, rc, extra_output_buffer, OUTPUT_BUFFER_SIZE);
+}
+
+void pcut_hook_before_test(pcut_item_t *test) {
+	PCUT_UNUSED(test);
+
+	/* Do nothing. */
+}
+
Index: uspace/lib/pcut/src/os/windows.c
===================================================================
--- uspace/lib/pcut/src/os/windows.c	(revision bf45993c05fbff161c55a858a73b7488e832d63c)
+++ uspace/lib/pcut/src/os/windows.c	(revision bf45993c05fbff161c55a858a73b7488e832d63c)
@@ -0,0 +1,325 @@
+/*
+ * Copyright (c) 2014 Vojtech Horky
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @file
+ *
+ * Windows-specific functions for test execution via the popen() system call.
+ */
+
+/*
+ * Code inspired by Creating a Child Process with Redirected Input and Output:
+ * http://msdn.microsoft.com/en-us/library/ms682499%28VS.85%29.aspx
+ */
+
+#include "../internal.h"
+
+#include <windows.h>
+#include <tchar.h>
+#include <stdio.h>
+#include <strsafe.h>
+
+
+/** Maximum size of stdout we are able to capture. */
+#define OUTPUT_BUFFER_SIZE 8192
+
+/** Maximum command-line length. */
+#define PCUT_COMMAND_LINE_BUFFER_SIZE 256
+
+/** Buffer for assertion and other error messages. */
+static char error_message_buffer[OUTPUT_BUFFER_SIZE];
+
+/** Buffer for stdout from the test. */
+static char extra_output_buffer[OUTPUT_BUFFER_SIZE];
+
+/** Prepare for a new test.
+ *
+ * @param test Test that is about to be run.
+ */
+static void before_test_start(pcut_item_t *test) {
+	pcut_report_test_start(test);
+
+	memset(error_message_buffer, 0, OUTPUT_BUFFER_SIZE);
+	memset(extra_output_buffer, 0, OUTPUT_BUFFER_SIZE);
+}
+
+/** Report that a certain function failed.
+ *
+ * @param test Current test.
+ * @param failed_function_name Name of the failed function.
+ */
+static void report_func_fail(pcut_item_t *test, const char *failed_function_name) {
+	/* TODO: get error description. */
+	sprintf_s(error_message_buffer, OUTPUT_BUFFER_SIZE - 1,
+		"%s failed: %s.", failed_function_name, "unknown reason");
+	pcut_report_test_done(test, TEST_OUTCOME_ERROR, error_message_buffer, NULL, NULL);
+}
+
+/** Read full buffer from given file descriptor.
+ *
+ * This function exists to overcome the possibility that read() may
+ * not fill the full length of the provided buffer even when EOF is
+ * not reached.
+ *
+ * @param fd Opened file descriptor.
+ * @param buffer Buffer to store data into.
+ * @param buffer_size Size of the @p buffer in bytes.
+ * @return Number of actually read bytes.
+ */
+static size_t read_all(HANDLE fd, char *buffer, size_t buffer_size) {
+	DWORD actually_read;
+	char *buffer_start = buffer;
+	BOOL okay = FALSE;
+
+	do {
+		okay = ReadFile(fd, buffer, buffer_size, &actually_read, NULL);
+		if (!okay) {
+			break;
+		}
+		if (actually_read > 0) {
+			buffer += actually_read;
+			buffer_size -= actually_read;
+			if (buffer_size == 0) {
+				break;
+			}
+		}
+	} while (actually_read > 0);
+	if (buffer_start != buffer) {
+		if (*(buffer - 1) == 10) {
+			*(buffer - 1) = 0;
+			buffer--;
+		}
+	}
+	return buffer - buffer_start;
+}
+
+struct test_output_data {
+	HANDLE pipe_stdout;
+	HANDLE pipe_stderr;
+	char *output_buffer;
+	size_t output_buffer_size;
+};
+
+static DWORD WINAPI read_test_output_on_background(LPVOID test_output_data_ptr) {
+	size_t stderr_size = 0;
+	struct test_output_data *test_output_data = (struct test_output_data *) test_output_data_ptr;
+
+	stderr_size = read_all(test_output_data->pipe_stderr,
+		test_output_data->output_buffer,
+		test_output_data->output_buffer_size - 1);
+	read_all(test_output_data->pipe_stdout,
+		test_output_data->output_buffer,
+		test_output_data->output_buffer_size - 1 - stderr_size);
+
+	return 0;
+}
+
+/** Run the test as a new process and report the result.
+ *
+ * @param self_path Path to itself, that is to current binary.
+ * @param test Test to be run.
+ */
+void pcut_run_test_forking(const char *self_path, pcut_item_t *test) {
+	/* TODO: clean-up if something goes wrong "in the middle" */
+	BOOL okay = FALSE;
+	DWORD rc;
+	int outcome;
+	int timed_out;
+	int time_out_millis;
+	SECURITY_ATTRIBUTES security_attributes;
+	HANDLE link_stdout[2] = { NULL, NULL };
+	HANDLE link_stderr[2] = { NULL, NULL };
+	HANDLE link_stdin[2] = { NULL, NULL };
+	PROCESS_INFORMATION process_info;
+	STARTUPINFO start_info;
+	char command[PCUT_COMMAND_LINE_BUFFER_SIZE];
+	struct test_output_data test_output_data;
+	HANDLE test_output_thread_reader;
+
+
+	before_test_start(test);
+
+	/* Pipe handles are inherited. */
+	security_attributes.nLength = sizeof(SECURITY_ATTRIBUTES);
+	security_attributes.bInheritHandle = TRUE;
+	security_attributes.lpSecurityDescriptor = NULL;
+
+	/* Create pipe for stdout, make sure it is not inherited. */
+	okay = CreatePipe(&link_stdout[0], &link_stdout[1], &security_attributes, 0);
+	if (!okay) {
+		report_func_fail(test, "CreatePipe(/* stdout */)");
+		return;
+	}
+	okay = SetHandleInformation(link_stdout[0], HANDLE_FLAG_INHERIT, 0);
+	if (!okay) {
+		report_func_fail(test, "SetHandleInformation(/* stdout */)");
+		return;
+	}
+
+	/* Create pipe for stderr, make sure it is not inherited. */
+	okay = CreatePipe(&link_stderr[0], &link_stderr[1], &security_attributes, 0);
+	if (!okay) {
+		report_func_fail(test, "CreatePipe(/* stderr */)");
+		return;
+	}
+	okay = SetHandleInformation(link_stderr[0], HANDLE_FLAG_INHERIT, 0);
+	if (!okay) {
+		report_func_fail(test, "SetHandleInformation(/* stderr */)");
+		return;
+	}
+
+	/* Create pipe for stdin, make sure it is not inherited. */
+	okay = CreatePipe(&link_stdin[0], &link_stdin[1], &security_attributes, 0);
+	if (!okay) {
+		report_func_fail(test, "CreatePipe(/* stdin */)");
+		return;
+	}
+	okay = SetHandleInformation(link_stdin[1], HANDLE_FLAG_INHERIT, 0);
+	if (!okay) {
+		report_func_fail(test, "SetHandleInformation(/* stdin */)");
+		return;
+	}
+
+	/* Prepare information for the child process. */
+	ZeroMemory(&process_info, sizeof(PROCESS_INFORMATION));
+	ZeroMemory(&start_info, sizeof(STARTUPINFO));
+	start_info.cb = sizeof(STARTUPINFO);
+	start_info.hStdError = link_stderr[1];
+	start_info.hStdOutput = link_stdout[1];
+	start_info.hStdInput = link_stdin[0];
+	start_info.dwFlags |= STARTF_USESTDHANDLES;
+
+	/* Format the command line. */
+	sprintf_s(command, PCUT_COMMAND_LINE_BUFFER_SIZE - 1,
+		"\"%s\" -t%d", self_path, test->id);
+
+	/* Run the process. */
+	okay = CreateProcess(NULL, command, NULL, NULL, TRUE, 0, NULL, NULL,
+		&start_info, &process_info);
+
+	if (!okay) {
+		report_func_fail(test, "CreateProcess()");
+		return;
+	}
+
+	// FIXME: kill the process on error
+
+	/* Close handles to the first thread. */
+	CloseHandle(process_info.hThread);
+
+	/* Close the other ends of the pipes. */
+	okay = CloseHandle(link_stdout[1]);
+	if (!okay) {
+		report_func_fail(test, "CloseHandle(/* stdout */)");
+		return;
+	}
+	okay = CloseHandle(link_stderr[1]);
+	if (!okay) {
+		report_func_fail(test, "CloseHandle(/* stderr */)");
+		return;
+	}
+	okay = CloseHandle(link_stdin[0]);
+	if (!okay) {
+		report_func_fail(test, "CloseHandle(/* stdin */)");
+		return;
+	}
+
+	/*
+	 * Read data from stdout and stderr.
+	 * We need to do this in a separate thread to allow the
+	 * time-out to work correctly.
+	 * Probably, this can be done with asynchronous I/O but
+	 * this works for now pretty well.
+	 */
+	test_output_data.pipe_stderr = link_stderr[0];
+	test_output_data.pipe_stdout = link_stdout[0];
+	test_output_data.output_buffer = extra_output_buffer;
+	test_output_data.output_buffer_size = OUTPUT_BUFFER_SIZE;
+
+	test_output_thread_reader = CreateThread(NULL, 0,
+		read_test_output_on_background, &test_output_data,
+		0, NULL);
+
+	if (test_output_thread_reader == NULL) {
+		report_func_fail(test, "CreateThread(/* read test stdout */)");
+		return;
+	}
+
+	/* Wait for the process to terminate. */
+	timed_out = 0;
+	time_out_millis = pcut_get_test_timeout(test) * 1000;
+	rc = WaitForSingleObject(process_info.hProcess, time_out_millis);
+	PCUT_DEBUG("Waiting for test %s (%dms) returned %d.", test->name, time_out_millis, rc);
+	if (rc == WAIT_TIMEOUT) {
+		/* We timed-out: kill the process and wait for its termination again. */
+		timed_out = 1;
+		okay = TerminateProcess(process_info.hProcess, 5);
+		if (!okay) {
+			report_func_fail(test, "TerminateProcess(/* PROCESS_INFORMATION.hProcess */)");
+			return;
+		}
+		rc = WaitForSingleObject(process_info.hProcess, INFINITE);
+	}
+	if (rc != WAIT_OBJECT_0) {
+		report_func_fail(test, "WaitForSingleObject(/* PROCESS_INFORMATION.hProcess */)");
+		return;
+	}
+
+	/* Get the return code and convert it to outcome. */
+	okay = GetExitCodeProcess(process_info.hProcess, &rc);
+	if (!okay) {
+		report_func_fail(test, "GetExitCodeProcess()");
+		return;
+	}
+
+	if (rc == 0) {
+		outcome = TEST_OUTCOME_PASS;
+	} else if ((rc > 0) && (rc < 10) && !timed_out) {
+		outcome = TEST_OUTCOME_FAIL;
+	} else {
+		outcome = TEST_OUTCOME_ERROR;
+	}
+
+	/* Wait for the reader thread (shall be terminated by now). */
+	rc = WaitForSingleObject(test_output_thread_reader, INFINITE);
+	if (rc != WAIT_OBJECT_0) {
+		report_func_fail(test, "WaitForSingleObject(/* stdout reader thread */)");
+		return;
+	}
+
+	pcut_report_test_done_unparsed(test, outcome, extra_output_buffer, OUTPUT_BUFFER_SIZE);
+}
+
+void pcut_hook_before_test(pcut_item_t *test) {
+	PCUT_UNUSED(test);
+
+	/*
+	 * Prevent displaying the dialog informing the user that the
+	 * program unexpectedly failed.
+	 */
+	SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX);
+}
Index: uspace/lib/pcut/src/preproc.c
===================================================================
--- uspace/lib/pcut/src/preproc.c	(revision bf45993c05fbff161c55a858a73b7488e832d63c)
+++ uspace/lib/pcut/src/preproc.c	(revision bf45993c05fbff161c55a858a73b7488e832d63c)
@@ -0,0 +1,134 @@
+/*
+ * Copyright (c) 2014 Vojtech Horky
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <string.h>
+
+#define MAX_IDENTIFIER_LENGTH 256
+
+static int counter = 0;
+
+static void print_numbered_identifier(int value, FILE *output) {
+	fprintf(output, "pcut_item_%d", value);
+}
+
+static void print_numbered_identifier2(int value, FILE *output) {
+	fprintf(output, "pcut_item2_%d", value);
+}
+
+static void print_numbered_identifier3(int value, FILE *output) {
+	fprintf(output, "pcut_item3_%d", value);
+}
+
+typedef struct {
+	char name[MAX_IDENTIFIER_LENGTH];
+	size_t length;
+} identifier_t;
+
+static void identifier_init(identifier_t *identifier) {
+	identifier->name[0] = 0;
+	identifier->length = 0;
+}
+
+static void identifier_add_char(identifier_t *identifier, char c) {
+	if (identifier->length + 1 >= MAX_IDENTIFIER_LENGTH) {
+		fprintf(stderr, "Identifier %s is too long, aborting!\n", identifier->name);
+		exit(1);
+	}
+
+	identifier->name[identifier->length] = c;
+	identifier->length++;
+	identifier->name[identifier->length] = 0;
+}
+
+static void identifier_print_or_expand(identifier_t *identifier, FILE *output) {
+	const char *name = identifier->name;
+	if (strcmp(name, "PCUT_ITEM_NAME") == 0) {
+		print_numbered_identifier(counter, output);
+	} else if (strcmp(name, "PCUT_ITEM_NAME_PREV") == 0) {
+		print_numbered_identifier(counter - 1, output);
+	} else if (strcmp(name, "PCUT_ITEM_COUNTER_INCREMENT") == 0) {
+		counter++;
+	} else if (strcmp(name, "PCUT_ITEM2_NAME") == 0) {
+		print_numbered_identifier2(counter, output);
+	} else if (strcmp(name, "PCUT_ITEM3_NAME") == 0) {
+		print_numbered_identifier3(counter, output);
+	} else {
+		fprintf(output, "%s", name);
+	}
+}
+
+static int is_identifier_char(int c, int inside_identifier) {
+	return isalpha(c) || (c == '_')
+			|| (inside_identifier && isdigit(c));
+}
+
+int main(int argc, char *argv[]) {
+	FILE *input = stdin;
+	FILE *output = stdout;
+
+	int last_char_was_identifier = 0;
+	identifier_t last_identifier;
+
+	/* Unused parameters. */
+	(void) argc;
+	(void) argv;
+
+	while (1) {
+		int current_char_denotes_identifier;
+
+		int current_char = fgetc(input);
+		if (current_char == EOF) {
+			break;
+		}
+
+		current_char_denotes_identifier = is_identifier_char(current_char, last_char_was_identifier);
+		if (current_char_denotes_identifier) {
+			if (!last_char_was_identifier) {
+				identifier_init(&last_identifier);
+			}
+			identifier_add_char(&last_identifier, current_char);
+			last_char_was_identifier = 1;
+		} else {
+			if (last_char_was_identifier) {
+				identifier_print_or_expand(&last_identifier, output);
+			}
+			fprintf(stdout, "%c", current_char);
+			last_char_was_identifier = 0;
+		}
+	}
+
+	if (last_char_was_identifier) {
+		identifier_print_or_expand(&last_identifier, output);
+	}
+	fprintf(output, "\n");
+
+	return 0;
+}
Index: uspace/lib/pcut/src/print.c
===================================================================
--- uspace/lib/pcut/src/print.c	(revision bf45993c05fbff161c55a858a73b7488e832d63c)
+++ uspace/lib/pcut/src/print.c	(revision bf45993c05fbff161c55a858a73b7488e832d63c)
@@ -0,0 +1,88 @@
+/*
+ * Copyright (c) 2012-2013 Vojtech Horky
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @file
+ *
+ * Helper functions for debugging prints.
+ */
+
+#include <pcut/pcut.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+#include "internal.h"
+
+/** Print all items in the given list.
+ *
+ * @param first First item to be printed.
+ */
+void pcut_print_items(pcut_item_t *first) {
+	pcut_item_t *it = first;
+	printf("====>\n");
+	while (it != NULL) {
+		switch (it->kind) {
+		case PCUT_KIND_TEST:
+			printf("TEST %s\n", it->name);
+			break;
+		case PCUT_KIND_TESTSUITE:
+			printf("SUITE %s\n", it->name);
+			break;
+		case PCUT_KIND_SKIP:
+			break;
+		case PCUT_KIND_NESTED:
+			printf("NESTED ...\n");
+			break;
+		default:
+			printf("UNKNOWN (%d)\n", it->kind);
+			break;
+		}
+		it = it->next;
+	}
+	printf("----\n");
+}
+
+/** Print valid items in the list.
+ *
+ * @param first First item to be printed.
+ */
+void pcut_print_tests(pcut_item_t *first) {
+	pcut_item_t *it;
+	for (it = pcut_get_real(first); it != NULL; it = pcut_get_real_next(it)) {
+		switch (it->kind) {
+		case PCUT_KIND_TESTSUITE:
+			printf("  Suite `%s' [%d]\n", it->name, it->id);
+			break;
+		case PCUT_KIND_TEST:
+			printf("    Test `%s' [%d]\n", it->name, it->id);
+			break;
+		default:
+			assert(0 && "unreachable case in item-kind switch");
+			break;
+		}
+	}
+}
Index: uspace/lib/pcut/src/report/report.c
===================================================================
--- uspace/lib/pcut/src/report/report.c	(revision bf45993c05fbff161c55a858a73b7488e832d63c)
+++ uspace/lib/pcut/src/report/report.c	(revision bf45993c05fbff161c55a858a73b7488e832d63c)
@@ -0,0 +1,228 @@
+/*
+ * Copyright (c) 2013 Vojtech Horky
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @file
+ *
+ * Common functions for test results reporting.
+ */
+
+#include "../internal.h"
+#ifndef __helenos__
+#include <string.h>
+#endif
+#include <stdio.h>
+
+/** Currently used report ops. */
+static pcut_report_ops_t *report_ops = NULL;
+
+/** Call a report function if it is available.
+ *
+ * @param op Operation to be called on the pcut_report_ops_t.
+ * @param ... Arguments to the operation.
+ */
+#define REPORT_CALL(op, ...) \
+	if ((report_ops != NULL) && (report_ops->op != NULL)) report_ops->op(__VA_ARGS__)
+
+/** Call a report function if it is available.
+ *
+ * @param op Operation to be called on the pcut_report_ops_t.
+ */
+#define REPORT_CALL_NO_ARGS(op) \
+		if ((report_ops != NULL) && (report_ops->op != NULL)) report_ops->op()
+
+/** Print error message.
+ *
+ * NULL or empty message is silently ignored.
+ *
+ * The message is printed with a special 3-zero-byte prefix to be later
+ * parsed when reporting the results from a different process.
+ *
+ * @param msg The message to be printed.
+ */
+void pcut_print_fail_message(const char *msg) {
+	if (msg == NULL) {
+		return;
+	}
+	if (pcut_str_size(msg) == 0) {
+		return;
+	}
+
+	printf("%c%c%c%s\n%c", 0, 0, 0, msg, 0);
+}
+
+/** Size of buffer for storing error messages or extra test output. */
+#define BUFFER_SIZE 4096
+
+/** Buffer for stdout from the test. */
+static char buffer_for_extra_output[BUFFER_SIZE];
+
+/** Buffer for assertion and other error messages. */
+static char buffer_for_error_messages[BUFFER_SIZE];
+
+/** Parse output of a single test.
+ *
+ * @param full_output Full unparsed output.
+ * @param full_output_size Size of @p full_output in bytes.
+ * @param stdio_buffer Where to store normal output from the test.
+ * @param stdio_buffer_size Size of @p stdio_buffer in bytes.
+ * @param error_buffer Where to store error messages from the test.
+ * @param error_buffer_size Size of @p error_buffer in bytes.
+ */
+static void parse_command_output(const char *full_output, size_t full_output_size,
+		char *stdio_buffer, size_t stdio_buffer_size,
+		char *error_buffer, size_t error_buffer_size) {
+	memset(stdio_buffer, 0, stdio_buffer_size);
+	memset(error_buffer, 0, error_buffer_size);
+
+	/* Ensure that we do not read past the full_output. */
+	if (full_output[full_output_size - 1] != 0) {
+		/* FIXME: can this happen? */
+		return;
+	}
+
+	while (1) {
+		size_t message_length;
+
+		/* First of all, count number of zero bytes before the text. */
+		size_t cont_zeros_count = 0;
+		while (full_output[0] == 0) {
+			cont_zeros_count++;
+			full_output++;
+			full_output_size--;
+			if (full_output_size == 0) {
+				return;
+			}
+		}
+
+		/* Determine the length of the text after the zeros. */
+		message_length = pcut_str_size(full_output);
+
+		if (cont_zeros_count < 2) {
+			/* Okay, standard I/O. */
+			if (message_length > stdio_buffer_size) {
+				/* TODO: handle gracefully */
+				return;
+			}
+			memcpy(stdio_buffer, full_output, message_length);
+			stdio_buffer += message_length;
+			stdio_buffer_size -= message_length;
+		} else {
+			/* Error message. */
+			if (message_length > error_buffer_size) {
+				/* TODO: handle gracefully */
+				return;
+			}
+			memcpy(error_buffer, full_output, message_length);
+			error_buffer += message_length;
+			error_buffer_size -= message_length;
+		}
+
+		full_output += message_length + 1;
+		full_output_size -= message_length + 1;
+	}
+}
+
+/** Use given set of functions for error reporting.
+ *
+ * @param ops Functions to use.
+ */
+void pcut_report_register_handler(pcut_report_ops_t *ops) {
+	report_ops = ops;
+}
+
+/** Initialize the report.
+ *
+ * @param all_items List of all tests that could be run.
+ */
+void pcut_report_init(pcut_item_t *all_items) {
+	REPORT_CALL(init, all_items);
+}
+
+/** Report that a test suite was started.
+ *
+ * @param suite Suite that was just started.
+ */
+void pcut_report_suite_start(pcut_item_t *suite) {
+	REPORT_CALL(suite_start, suite);
+}
+
+/** Report that a test suite was completed.
+ *
+ * @param suite Suite that just completed.
+ */
+void pcut_report_suite_done(pcut_item_t *suite) {
+	REPORT_CALL(suite_done, suite);
+}
+
+/** Report that a test is about to start.
+ *
+ * @param test Test to be run just about now.
+ */
+void pcut_report_test_start(pcut_item_t *test) {
+	REPORT_CALL(test_start, test);
+}
+
+/** Report that a test was completed.
+ *
+ * @param test Test that just finished.
+ * @param outcome Outcome of the test.
+ * @param error_message Buffer with error message.
+ * @param teardown_error_message Buffer with error message from a tear-down function.
+ * @param extra_output Extra output from the test (stdout).
+ */
+void pcut_report_test_done(pcut_item_t *test, int outcome,
+		const char *error_message, const char *teardown_error_message,
+		const char *extra_output) {
+	REPORT_CALL(test_done, test, outcome, error_message, teardown_error_message,
+			extra_output);
+}
+
+/** Report that a test was completed with unparsed test output.
+ *
+ * @param test Test that just finished
+ * @param outcome Outcome of the test.
+ * @param unparsed_output Buffer with all the output from the test.
+ * @param unparsed_output_size Size of @p unparsed_output in bytes.
+ */
+void pcut_report_test_done_unparsed(pcut_item_t *test, int outcome,
+		const char *unparsed_output, size_t unparsed_output_size) {
+
+	parse_command_output(unparsed_output, unparsed_output_size,
+			buffer_for_extra_output, BUFFER_SIZE,
+			buffer_for_error_messages, BUFFER_SIZE);
+
+	pcut_report_test_done(test, outcome, buffer_for_error_messages, NULL, buffer_for_extra_output);
+}
+
+/** Close the report.
+ *
+ */
+void pcut_report_done(void) {
+	REPORT_CALL_NO_ARGS(done);
+}
+
Index: uspace/lib/pcut/src/report/report.h
===================================================================
--- uspace/lib/pcut/src/report/report.h	(revision bf45993c05fbff161c55a858a73b7488e832d63c)
+++ uspace/lib/pcut/src/report/report.h	(revision bf45993c05fbff161c55a858a73b7488e832d63c)
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2012-2013 Vojtech Horky
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @file
+ *
+ * Test results reporting.
+ */
+
+#ifndef PCUT_REPORT_H_GUARD
+#define PCUT_REPORT_H_GUARD
+
+#include "../internal.h"
+
+/** Reporting functions for the test-anything-protocol. */
+extern pcut_report_ops_t pcut_report_tap;
+
+/** Reporting functions for XML report output. */
+extern pcut_report_ops_t pcut_report_xml;
+
+#endif
Index: uspace/lib/pcut/src/report/tap.c
===================================================================
--- uspace/lib/pcut/src/report/tap.c	(revision bf45993c05fbff161c55a858a73b7488e832d63c)
+++ uspace/lib/pcut/src/report/tap.c	(revision bf45993c05fbff161c55a858a73b7488e832d63c)
@@ -0,0 +1,169 @@
+/*
+ * Copyright (c) 2013 Vojtech Horky
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @file
+ *
+ * Test-anything-protocol reporting routines.
+ */
+
+#include "../internal.h"
+#include "report.h"
+#ifndef __helenos__
+#include <string.h>
+#endif
+#include <stdio.h>
+
+/** Counter of all run tests. */
+static int test_counter;
+
+/** Counter for tests in a current suite. */
+static int tests_in_suite;
+
+/** Counter of failed tests in current suite. */
+static int failed_tests_in_suite;
+
+/** Initialize the TAP output.
+ *
+ * @param all_items Start of the list with all items.
+ */
+static void tap_init(pcut_item_t *all_items) {
+	int tests_total = pcut_count_tests(all_items);
+	test_counter = 0;
+
+	printf("1..%d\n", tests_total);
+}
+
+/** Report that a suite was started.
+ *
+ * @param suite Suite that just started.
+ */
+static void tap_suite_start(pcut_item_t *suite) {
+	tests_in_suite = 0;
+	failed_tests_in_suite = 0;
+
+	printf("#> Starting suite %s.\n", suite->name);
+}
+
+/** Report that a suite was completed.
+ *
+ * @param suite Suite that just ended.
+ */
+static void tap_suite_done(pcut_item_t *suite) {
+	printf("#> Finished suite %s (failed %d of %d).\n",
+			suite->name, failed_tests_in_suite, tests_in_suite);
+}
+
+/** Report that a test was started.
+ *
+ * We do nothing - all handling is done after the test completes.
+ *
+ * @param test Test that is started.
+ */
+static void tap_test_start(pcut_item_t *test) {
+	PCUT_UNUSED(test);
+
+	tests_in_suite++;
+	test_counter++;
+}
+
+/** Print the buffer, prefix new line with a given string.
+ *
+ * @param message Message to print.
+ * @param prefix Prefix for each new line, such as comment character.
+ */
+static void print_by_lines(const char *message, const char *prefix) {
+	char *next_line_start;
+	if ((message == NULL) || (message[0] == 0)) {
+		return;
+	}
+	next_line_start = pcut_str_find_char(message, '\n');
+	while (next_line_start != NULL) {
+		next_line_start[0] = 0;
+		printf("%s%s\n", prefix, message);
+		message = next_line_start + 1;
+		next_line_start = pcut_str_find_char(message, '\n');
+	}
+	if (message[0] != 0) {
+		printf("%s%s\n", prefix, message);
+	}
+}
+
+/** Report a completed test.
+ *
+ * @param test Test that just finished.
+ * @param outcome Outcome of the test.
+ * @param error_message Buffer with error message.
+ * @param teardown_error_message Buffer with error message from a tear-down function.
+ * @param extra_output Extra output from the test (stdout).
+ */
+static void tap_test_done(pcut_item_t *test, int outcome,
+		const char *error_message, const char *teardown_error_message,
+		const char *extra_output) {
+	const char *test_name = test->name;
+	const char *status_str = NULL;
+	const char *fail_error_str = NULL;
+
+	if (outcome != TEST_OUTCOME_PASS) {
+		failed_tests_in_suite++;
+	}
+
+	switch (outcome) {
+	case TEST_OUTCOME_PASS:
+		status_str = "ok";
+		fail_error_str = "";
+		break;
+	case TEST_OUTCOME_FAIL:
+		status_str = "not ok";
+		fail_error_str = " failed";
+		break;
+	case TEST_OUTCOME_ERROR:
+		status_str = "not ok";
+		fail_error_str = " aborted";
+		break;
+	default:
+		/* Shall not get here. */
+		break;
+	}
+	printf("%s %d %s%s\n", status_str, test_counter, test_name, fail_error_str);
+
+	print_by_lines(error_message, "# error: ");
+	print_by_lines(teardown_error_message, "# error: ");
+
+	print_by_lines(extra_output, "# stdio: ");
+}
+
+/** Report testing done. */
+static void tap_done(void) {
+}
+
+
+pcut_report_ops_t pcut_report_tap = {
+	tap_init, tap_done,
+	tap_suite_start, tap_suite_done,
+	tap_test_start, tap_test_done
+};
Index: uspace/lib/pcut/src/report/xml.c
===================================================================
--- uspace/lib/pcut/src/report/xml.c	(revision bf45993c05fbff161c55a858a73b7488e832d63c)
+++ uspace/lib/pcut/src/report/xml.c	(revision bf45993c05fbff161c55a858a73b7488e832d63c)
@@ -0,0 +1,177 @@
+/*
+ * Copyright (c) 2013 Vojtech Horky
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @file
+ *
+ * Reporting routines for XML output (non-standard).
+ */
+
+#include "../internal.h"
+#include "report.h"
+#ifndef __helenos__
+#include <string.h>
+#endif
+#include <stdio.h>
+
+/** Counter of all run tests. */
+static int test_counter;
+
+/** Counter for tests in a current suite. */
+static int tests_in_suite;
+
+/** Counter of failed tests in current suite. */
+static int failed_tests_in_suite;
+
+/** Initialize the XML output.
+ *
+ * @param all_items Start of the list with all items.
+ */
+static void xml_init(pcut_item_t *all_items) {
+	int tests_total = pcut_count_tests(all_items);
+	test_counter = 0;
+
+	printf("<?xml version=\"1.0\"?>\n");
+	printf("<report tests-total=\"%d\">\n", tests_total);
+}
+
+/** Report that a suite was started.
+ *
+ * @param suite Suite that just started.
+ */
+static void xml_suite_start(pcut_item_t *suite) {
+	tests_in_suite = 0;
+	failed_tests_in_suite = 0;
+
+	printf("\t<suite name=\"%s\">\n", suite->name);
+}
+
+/** Report that a suite was completed.
+ *
+ * @param suite Suite that just ended.
+ */
+static void xml_suite_done(pcut_item_t *suite) {
+	printf("\t</suite><!-- %s: %d / %d -->\n", suite->name,
+		failed_tests_in_suite, tests_in_suite);
+}
+
+/** Report that a test was started.
+ *
+ * We do nothing - all handling is done after the test completes.
+ *
+ * @param test Test that is started.
+ */
+static void xml_test_start(pcut_item_t *test) {
+	PCUT_UNUSED(test);
+
+	tests_in_suite++;
+	test_counter++;
+}
+
+/** Print the buffer as a CDATA into given element.
+ *
+ * @param message Message to print.
+ * @param element_name Wrapping XML element name.
+ */
+static void print_by_lines(const char *message, const char *element_name) {
+	char *next_line_start;
+
+	if ((message == NULL) || (message[0] == 0)) {
+		return;
+	}
+
+	printf("\t\t\t<%s><![CDATA[", element_name);
+
+	next_line_start = pcut_str_find_char(message, '\n');
+	while (next_line_start != NULL) {
+		next_line_start[0] = 0;
+		printf("%s\n", message);
+		message = next_line_start + 1;
+		next_line_start = pcut_str_find_char(message, '\n');
+	}
+	if (message[0] != 0) {
+		printf("%s\n", message);
+	}
+
+	printf("]]></%s>\n", element_name);
+}
+
+/** Report a completed test.
+ *
+ * @param test Test that just finished.
+ * @param outcome Outcome of the test.
+ * @param error_message Buffer with error message.
+ * @param teardown_error_message Buffer with error message from a tear-down function.
+ * @param extra_output Extra output from the test (stdout).
+ */
+static void xml_test_done(pcut_item_t *test, int outcome,
+		const char *error_message, const char *teardown_error_message,
+		const char *extra_output) {
+	const char *test_name = test->name;
+	const char *status_str = NULL;
+
+	if (outcome != TEST_OUTCOME_PASS) {
+		failed_tests_in_suite++;
+	}
+
+	switch (outcome) {
+	case TEST_OUTCOME_PASS:
+		status_str = "pass";
+		break;
+	case TEST_OUTCOME_FAIL:
+		status_str = "fail";
+		break;
+	case TEST_OUTCOME_ERROR:
+		status_str = "error";
+		break;
+	default:
+		/* Shall not get here. */
+		break;
+	}
+
+	printf("\t\t<testcase name=\"%s\" status=\"%s\">\n", test_name,
+		status_str);
+
+	print_by_lines(error_message, "error-message");
+	print_by_lines(teardown_error_message, "error-message");
+
+	print_by_lines(extra_output, "standard-output");
+
+	printf("\t\t</testcase><!-- %s -->\n", test_name);
+}
+
+/** Report testing done. */
+static void xml_done(void) {
+	printf("</report>\n");
+}
+
+
+pcut_report_ops_t pcut_report_xml = {
+	xml_init, xml_done,
+	xml_suite_start, xml_suite_done,
+	xml_test_start, xml_test_done
+};
Index: uspace/lib/pcut/src/run.c
===================================================================
--- uspace/lib/pcut/src/run.c	(revision bf45993c05fbff161c55a858a73b7488e832d63c)
+++ uspace/lib/pcut/src/run.c	(revision bf45993c05fbff161c55a858a73b7488e832d63c)
@@ -0,0 +1,300 @@
+/*
+ * Copyright (c) 2012-2013 Vojtech Horky
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @file
+ *
+ * Test execution routines.
+ */
+
+#include "internal.h"
+#ifndef PCUT_NO_LONG_JUMP
+#include <setjmp.h>
+#endif
+
+#ifndef PCUT_NO_LONG_JUMP
+/** Long-jump buffer. */
+static jmp_buf start_test_jump;
+#endif
+
+/** Whether to run a tear-down function on a failure.
+ *
+ * Used to determine whether we are already in a tear-down context.
+ */
+static int execute_teardown_on_failure;
+
+/** Whether to report test result at all.
+ *
+ * Used to determine whether we are the forked or the parent process.
+ */
+static int report_test_result;
+
+/** Whether to print test error.
+ *
+ * Used to determine whether we are the forked or the parent process.
+ */
+static int print_test_error;
+
+/** Whether leaving a test means a process exit. */
+static int leave_means_exit;
+
+/** Pointer to currently running test. */
+static pcut_item_t *current_test = NULL;
+
+/** Pointer to current test suite. */
+static pcut_item_t *current_suite = NULL;
+
+/** A NULL-like suite. */
+static pcut_item_t default_suite;
+static int default_suite_initialized = 0;
+
+static void init_default_suite_when_needed() {
+	if (default_suite_initialized) {
+		return;
+	}
+	default_suite.id = -1;
+	default_suite.kind = PCUT_KIND_TESTSUITE;
+	default_suite.previous = NULL;
+	default_suite.next = NULL;
+	default_suite.name = "Default";
+	default_suite.setup_func = NULL;
+	default_suite.teardown_func = NULL;
+}
+
+/** Find the suite given test belongs to.
+ *
+ * @param it The test.
+ * @return Always a valid test suite item.
+ */
+static pcut_item_t *pcut_find_parent_suite(pcut_item_t *it) {
+	while (it != NULL) {
+		if (it->kind == PCUT_KIND_TESTSUITE) {
+			return it;
+		}
+		it = it->previous;
+	}
+	init_default_suite_when_needed();
+	return &default_suite;
+}
+
+/** Run a set-up (tear-down) function.
+ *
+ * @param func Function to run (can be NULL).
+ */
+static void run_setup_teardown(pcut_setup_func_t func) {
+	if (func != NULL) {
+		func();
+	}
+}
+
+/** Terminate current test with given outcome.
+ *
+ * @warning This function may execute a long jump or terminate
+ * current process.
+ *
+ * @param outcome Outcome of the current test.
+ */
+static void leave_test(int outcome) {
+	PCUT_DEBUG("leave_test(outcome=%d), will_exit=%s", outcome,
+		leave_means_exit ? "yes" : "no");
+	if (leave_means_exit) {
+		exit(outcome);
+	}
+
+#ifndef PCUT_NO_LONG_JUMP
+	longjmp(start_test_jump, 1);
+#endif
+}
+
+/** Process a failed assertion.
+ *
+ * @warning This function calls leave_test() and typically will not
+ * return.
+ *
+ * @param message Message describing the failure.
+ */
+void pcut_failed_assertion(const char *message) {
+	static const char *prev_message = NULL;
+	/*
+	 * The assertion failed. We need to abort the current test,
+	 * inform the user and perform some clean-up. That could
+	 * include running the tear-down routine.
+	 */
+	if (print_test_error) {
+		pcut_print_fail_message(message);
+	}
+
+	if (execute_teardown_on_failure) {
+		execute_teardown_on_failure = 0;
+		prev_message = message;
+		run_setup_teardown(current_suite->teardown_func);
+
+		/* Tear-down was okay. */
+		if (report_test_result) {
+			pcut_report_test_done(current_test, TEST_OUTCOME_FAIL,
+				message, NULL, NULL);
+		}
+	} else {
+		if (report_test_result) {
+			pcut_report_test_done(current_test, TEST_OUTCOME_FAIL,
+				prev_message, message, NULL);
+		}
+	}
+
+	prev_message = NULL;
+
+	leave_test(TEST_OUTCOME_FAIL); /* No return. */
+}
+
+/** Run a test.
+ *
+ * @param test Test to execute.
+ * @return Error status (zero means success).
+ */
+static int run_test(pcut_item_t *test) {
+	/*
+	 * Set here as the returning point in case of test failure.
+	 * If we get here, it means something failed during the
+	 * test execution.
+	 */
+#ifndef PCUT_NO_LONG_JUMP
+	int test_finished = setjmp(start_test_jump);
+	if (test_finished) {
+		return 1;
+	}
+#endif
+
+	if (report_test_result) {
+		pcut_report_test_start(test);
+	}
+
+	current_suite = pcut_find_parent_suite(test);
+	current_test = test;
+
+	pcut_hook_before_test(test);
+
+	/*
+	 * If anything goes wrong, execute the tear-down function
+	 * as well.
+	 */
+	execute_teardown_on_failure = 1;
+
+	/*
+	 * Run the set-up function.
+	 */
+	run_setup_teardown(current_suite->setup_func);
+
+	/*
+	 * The setup function was performed, it is time to run
+	 * the actual test.
+	 */
+	test->test_func();
+
+	/*
+	 * Finally, run the tear-down function. We need to clear
+	 * the flag to prevent endless loop.
+	 */
+	execute_teardown_on_failure = 0;
+	run_setup_teardown(current_suite->teardown_func);
+
+	/*
+	 * If we got here, it means everything went well with
+	 * this test.
+	 */
+	if (report_test_result) {
+		pcut_report_test_done(current_test, TEST_OUTCOME_PASS,
+			NULL, NULL, NULL);
+	}
+
+	return 0;
+}
+
+/** Run a test in a forked mode.
+ *
+ * Forked mode means that the caller of the test is already a new
+ * process running this test only.
+ *
+ * @param test Test to execute.
+ * @return Error status (zero means success).
+ */
+int pcut_run_test_forked(pcut_item_t *test) {
+	int rc;
+
+	report_test_result = 0;
+	print_test_error = 1;
+	leave_means_exit = 1;
+
+	rc = run_test(test);
+
+	current_test = NULL;
+	current_suite = NULL;
+
+	return rc;
+}
+
+/** Run a test in a single mode.
+ *
+ * Single mode means that the test is called in the context of the
+ * parent process, that is no new process is forked.
+ *
+ * @param test Test to execute.
+ * @return Error status (zero means success).
+ */
+int pcut_run_test_single(pcut_item_t *test) {
+	int rc;
+
+	report_test_result = 1;
+	print_test_error = 0;
+	leave_means_exit = 0;
+
+	rc = run_test(test);
+
+	current_test = NULL;
+	current_suite = NULL;
+
+	return rc;
+}
+
+/** Tells time-out length for a given test.
+ *
+ * @param test Test for which the time-out is questioned.
+ * @return Timeout in seconds.
+ */
+int pcut_get_test_timeout(pcut_item_t *test) {
+	int timeout = PCUT_DEFAULT_TEST_TIMEOUT;
+	pcut_extra_t *extras = test->extras;
+
+
+	while (extras->type != PCUT_EXTRA_LAST) {
+		if (extras->type == PCUT_EXTRA_TIMEOUT) {
+			timeout = extras->timeout;
+		}
+		extras++;
+	}
+
+	return timeout;
+}
Index: uspace/lib/pcut/tests/.gitignore
===================================================================
--- uspace/lib/pcut/tests/.gitignore	(revision bf45993c05fbff161c55a858a73b7488e832d63c)
+++ uspace/lib/pcut/tests/.gitignore	(revision bf45993c05fbff161c55a858a73b7488e832d63c)
@@ -0,0 +1,2 @@
+*.run
+*.got
Index: uspace/lib/pcut/tests/abort.c
===================================================================
--- uspace/lib/pcut/tests/abort.c	(revision bf45993c05fbff161c55a858a73b7488e832d63c)
+++ uspace/lib/pcut/tests/abort.c	(revision bf45993c05fbff161c55a858a73b7488e832d63c)
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2012-2013 Vojtech Horky
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <pcut/pcut.h>
+#include <stdlib.h>
+
+PCUT_INIT
+
+PCUT_TEST(access_null_pointer) {
+	abort();
+}
+
+PCUT_MAIN()
Index: uspace/lib/pcut/tests/abort.expected
===================================================================
--- uspace/lib/pcut/tests/abort.expected	(revision bf45993c05fbff161c55a858a73b7488e832d63c)
+++ uspace/lib/pcut/tests/abort.expected	(revision bf45993c05fbff161c55a858a73b7488e832d63c)
@@ -0,0 +1,4 @@
+1..1
+#> Starting suite Default.
+not ok 1 access_null_pointer aborted
+#> Finished suite Default (failed 1 of 1).
Index: uspace/lib/pcut/tests/asserts.c
===================================================================
--- uspace/lib/pcut/tests/asserts.c	(revision bf45993c05fbff161c55a858a73b7488e832d63c)
+++ uspace/lib/pcut/tests/asserts.c	(revision bf45993c05fbff161c55a858a73b7488e832d63c)
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2014 Vojtech Horky
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <pcut/pcut.h>
+#include "tested.h"
+
+PCUT_INIT
+
+PCUT_TEST(int_equals) {
+	PCUT_ASSERT_INT_EQUALS(1, 1);
+	PCUT_ASSERT_INT_EQUALS(1, 0);
+}
+
+PCUT_TEST(double_equals) {
+	PCUT_ASSERT_DOUBLE_EQUALS(1., 1., 0.001);
+	PCUT_ASSERT_DOUBLE_EQUALS(1., 0.5, 0.4);
+}
+
+PCUT_TEST(str_equals) {
+	PCUT_ASSERT_STR_EQUALS("xyz", "xyz");
+	PCUT_ASSERT_STR_EQUALS("abc", "xyz");
+}
+
+PCUT_TEST(str_equals_or_null_base) {
+	PCUT_ASSERT_STR_EQUALS_OR_NULL("xyz", "xyz");
+}
+
+PCUT_TEST(str_equals_or_null_different) {
+	PCUT_ASSERT_STR_EQUALS_OR_NULL("abc", "xyz");
+}
+
+PCUT_TEST(str_equals_or_null_one_null) {
+	PCUT_ASSERT_STR_EQUALS_OR_NULL(NULL, "xyz");
+}
+
+PCUT_TEST(str_equals_or_null_both) {
+	PCUT_ASSERT_STR_EQUALS_OR_NULL(NULL, NULL);
+}
+
+PCUT_TEST(assert_true) {
+	PCUT_ASSERT_TRUE(42);
+	PCUT_ASSERT_TRUE(0);
+}
+
+PCUT_TEST(assert_false) {
+	PCUT_ASSERT_FALSE(0);
+	PCUT_ASSERT_FALSE(42);
+}
+
+PCUT_MAIN()
Index: uspace/lib/pcut/tests/asserts.expected
===================================================================
--- uspace/lib/pcut/tests/asserts.expected	(revision bf45993c05fbff161c55a858a73b7488e832d63c)
+++ uspace/lib/pcut/tests/asserts.expected	(revision bf45993c05fbff161c55a858a73b7488e832d63c)
@@ -0,0 +1,19 @@
+1..9
+#> Starting suite Default.
+not ok 1 int_equals failed
+# error: asserts.c:36: Expected <1> but got <0> (1 != 0)
+not ok 2 double_equals failed
+# error: asserts.c:41: Expected <1.000000+-0.400000> but got <0.500000> (1. != 0.5)
+not ok 3 str_equals failed
+# error: asserts.c:46: Expected <abc> but got <xyz> ("abc" != "xyz")
+ok 4 str_equals_or_null_base
+not ok 5 str_equals_or_null_different failed
+# error: asserts.c:54: Expected <abc> but got <xyz> ("abc" != "xyz")
+not ok 6 str_equals_or_null_one_null failed
+# error: asserts.c:58: Expected <NULL> but got <xyz> (NULL != "xyz")
+ok 7 str_equals_or_null_both
+not ok 8 assert_true failed
+# error: asserts.c:67: Expected true but got <0>
+not ok 9 assert_false failed
+# error: asserts.c:72: Expected false but got <42>
+#> Finished suite Default (failed 7 of 9).
Index: uspace/lib/pcut/tests/beforeafter.c
===================================================================
--- uspace/lib/pcut/tests/beforeafter.c	(revision bf45993c05fbff161c55a858a73b7488e832d63c)
+++ uspace/lib/pcut/tests/beforeafter.c	(revision bf45993c05fbff161c55a858a73b7488e832d63c)
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2012-2013 Vojtech Horky
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#define _BSD_SOURCE
+
+#include <pcut/pcut.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+/*
+ * Use sprintf_s in Windows but only with Microsoft compiler.
+ * Namely, let MinGW use snprintf.
+ */
+#if (defined(__WIN64) || defined(__WIN32) || defined(_WIN32)) && defined(_MSC_VER)
+#define snprintf sprintf_s
+#endif
+
+PCUT_INIT
+
+static char *buffer = NULL;
+#define BUFFER_SIZE 512
+
+PCUT_TEST_SUITE(suite_with_setup_and_teardown);
+
+PCUT_TEST_BEFORE {
+	buffer = malloc(BUFFER_SIZE);
+	PCUT_ASSERT_NOT_NULL(buffer);
+}
+
+PCUT_TEST_AFTER {
+	free(buffer);
+	buffer = NULL;
+}
+
+PCUT_TEST(test_with_setup_and_teardown) {
+	snprintf(buffer, BUFFER_SIZE - 1, "%d-%s", 56, "abcd");
+	PCUT_ASSERT_STR_EQUALS("56-abcd", buffer);
+}
+
+PCUT_TEST_SUITE(another_without_setup);
+
+PCUT_TEST(test_without_any_setup_or_teardown) {
+	PCUT_ASSERT_NULL(buffer);
+}
+
+
+PCUT_MAIN()
Index: uspace/lib/pcut/tests/beforeafter.expected
===================================================================
--- uspace/lib/pcut/tests/beforeafter.expected	(revision bf45993c05fbff161c55a858a73b7488e832d63c)
+++ uspace/lib/pcut/tests/beforeafter.expected	(revision bf45993c05fbff161c55a858a73b7488e832d63c)
@@ -0,0 +1,7 @@
+1..2
+#> Starting suite suite_with_setup_and_teardown.
+ok 1 test_with_setup_and_teardown
+#> Finished suite suite_with_setup_and_teardown (failed 0 of 1).
+#> Starting suite another_without_setup.
+ok 2 test_without_any_setup_or_teardown
+#> Finished suite another_without_setup (failed 0 of 1).
Index: uspace/lib/pcut/tests/errno.c
===================================================================
--- uspace/lib/pcut/tests/errno.c	(revision bf45993c05fbff161c55a858a73b7488e832d63c)
+++ uspace/lib/pcut/tests/errno.c	(revision bf45993c05fbff161c55a858a73b7488e832d63c)
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2014 Vojtech Horky
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <pcut/pcut.h>
+#include <errno.h>
+#include "tested.h"
+
+#ifndef EOK
+#define EOK 0
+#endif
+
+PCUT_INIT
+
+PCUT_TEST(errno_value) {
+	int value = EOK;
+	PCUT_ASSERT_ERRNO_VAL(EOK, value);
+	value = ENOENT;
+	PCUT_ASSERT_ERRNO_VAL(ENOENT, value);
+
+	/* This fails. */
+	PCUT_ASSERT_ERRNO_VAL(EOK, value);
+}
+
+PCUT_TEST(errno_variable) {
+	errno = ENOENT;
+	PCUT_ASSERT_ERRNO(ENOENT);
+
+	/* This fails. */
+	PCUT_ASSERT_ERRNO(EOK);
+}
+
+PCUT_MAIN()
Index: uspace/lib/pcut/tests/errno.expected
===================================================================
--- uspace/lib/pcut/tests/errno.expected	(revision bf45993c05fbff161c55a858a73b7488e832d63c)
+++ uspace/lib/pcut/tests/errno.expected	(revision bf45993c05fbff161c55a858a73b7488e832d63c)
@@ -0,0 +1,7 @@
+1..2
+#> Starting suite Default.
+not ok 1 errno_value failed
+# error: errno.c:46: Expected error 0 (EOK, *****) but got error ***** (*****)
+not ok 2 errno_variable failed
+# error: errno.c:54: Expected error 0 (EOK, *****) but got error ***** (*****)
+#> Finished suite Default (failed 2 of 2).
Index: uspace/lib/pcut/tests/inithook.c
===================================================================
--- uspace/lib/pcut/tests/inithook.c	(revision bf45993c05fbff161c55a858a73b7488e832d63c)
+++ uspace/lib/pcut/tests/inithook.c	(revision bf45993c05fbff161c55a858a73b7488e832d63c)
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2014 Vojtech Horky
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <pcut/pcut.h>
+#include "tested.h"
+
+PCUT_INIT
+
+static int init_counter = 0;
+
+static void init_hook(void) {
+	init_counter++;
+}
+
+PCUT_TEST_BEFORE {
+	PCUT_ASSERT_INT_EQUALS(1, init_counter);
+	init_counter++;
+}
+
+PCUT_TEST(check_init_counter) {
+	PCUT_ASSERT_INT_EQUALS(2, init_counter);
+}
+
+PCUT_TEST(check_init_counter_2) {
+	PCUT_ASSERT_INT_EQUALS(2, init_counter);
+}
+
+
+PCUT_CUSTOM_MAIN(
+	PCUT_MAIN_SET_INIT_HOOK(init_hook)
+)
+
Index: uspace/lib/pcut/tests/inithook.expected
===================================================================
--- uspace/lib/pcut/tests/inithook.expected	(revision bf45993c05fbff161c55a858a73b7488e832d63c)
+++ uspace/lib/pcut/tests/inithook.expected	(revision bf45993c05fbff161c55a858a73b7488e832d63c)
@@ -0,0 +1,5 @@
+1..2
+#> Starting suite Default.
+ok 1 check_init_counter
+ok 2 check_init_counter_2
+#> Finished suite Default (failed 0 of 2).
Index: uspace/lib/pcut/tests/manytests.c
===================================================================
--- uspace/lib/pcut/tests/manytests.c	(revision bf45993c05fbff161c55a858a73b7488e832d63c)
+++ uspace/lib/pcut/tests/manytests.c	(revision bf45993c05fbff161c55a858a73b7488e832d63c)
@@ -0,0 +1,120 @@
+/*
+ * Copyright (c) 2012-2013 Vojtech Horky
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <pcut/pcut.h>
+
+/*
+ * Just test how it will look like if a huge number of tests would
+ * be present in the suite.
+ */
+
+PCUT_INIT
+
+PCUT_TEST(my_test_001) { }
+PCUT_TEST(my_test_002) { }
+PCUT_TEST(my_test_003) { }
+PCUT_TEST(my_test_004) { }
+PCUT_TEST(my_test_005) { }
+PCUT_TEST(my_test_006) { }
+PCUT_TEST(my_test_007) { }
+PCUT_TEST(my_test_008) { }
+PCUT_TEST(my_test_009) { }
+PCUT_TEST(my_test_010) { }
+PCUT_TEST(my_test_011) { }
+PCUT_TEST(my_test_012) { }
+PCUT_TEST(my_test_013) { }
+PCUT_TEST(my_test_014) { }
+PCUT_TEST(my_test_015) { }
+PCUT_TEST(my_test_016) { }
+PCUT_TEST(my_test_017) { }
+PCUT_TEST(my_test_018) { }
+PCUT_TEST(my_test_019) { }
+PCUT_TEST(my_test_020) { }
+PCUT_TEST(my_test_021) { }
+PCUT_TEST(my_test_022) { }
+PCUT_TEST(my_test_023) { }
+PCUT_TEST(my_test_024) { }
+PCUT_TEST(my_test_025) { }
+PCUT_TEST(my_test_026) { }
+PCUT_TEST(my_test_027) { }
+PCUT_TEST(my_test_028) { }
+PCUT_TEST(my_test_029) { }
+PCUT_TEST(my_test_030) { }
+PCUT_TEST(my_test_031) { }
+PCUT_TEST(my_test_032) { }
+PCUT_TEST(my_test_033) { }
+PCUT_TEST(my_test_034) { }
+PCUT_TEST(my_test_035) { }
+PCUT_TEST(my_test_036) { }
+PCUT_TEST(my_test_037) { }
+PCUT_TEST(my_test_038) { }
+PCUT_TEST(my_test_039) { }
+PCUT_TEST(my_test_040) { }
+PCUT_TEST(my_test_041) { }
+PCUT_TEST(my_test_042) { }
+PCUT_TEST(my_test_043) { }
+PCUT_TEST(my_test_044) { }
+PCUT_TEST(my_test_045) { }
+PCUT_TEST(my_test_046) { }
+PCUT_TEST(my_test_047) { }
+PCUT_TEST(my_test_048) { }
+PCUT_TEST(my_test_049) { }
+PCUT_TEST(my_test_050) { }
+PCUT_TEST(my_test_051) { }
+PCUT_TEST(my_test_052) { }
+PCUT_TEST(my_test_053) { }
+PCUT_TEST(my_test_054) { }
+PCUT_TEST(my_test_055) { }
+PCUT_TEST(my_test_056) { }
+PCUT_TEST(my_test_057) { }
+PCUT_TEST(my_test_058) { }
+PCUT_TEST(my_test_059) { }
+PCUT_TEST(my_test_060) { }
+PCUT_TEST(my_test_061) { }
+PCUT_TEST(my_test_062) { }
+PCUT_TEST(my_test_063) { }
+PCUT_TEST(my_test_064) { }
+PCUT_TEST(my_test_065) { }
+PCUT_TEST(my_test_066) { }
+PCUT_TEST(my_test_067) { }
+PCUT_TEST(my_test_068) { }
+PCUT_TEST(my_test_069) { }
+PCUT_TEST(my_test_070) { }
+PCUT_TEST(my_test_071) { }
+PCUT_TEST(my_test_072) { }
+PCUT_TEST(my_test_073) { }
+PCUT_TEST(my_test_074) { }
+PCUT_TEST(my_test_075) { }
+PCUT_TEST(my_test_076) { }
+PCUT_TEST(my_test_077) { }
+PCUT_TEST(my_test_078) { }
+PCUT_TEST(my_test_079) { }
+PCUT_TEST(my_test_080) { }
+
+
+PCUT_MAIN()
Index: uspace/lib/pcut/tests/manytests.expected
===================================================================
--- uspace/lib/pcut/tests/manytests.expected	(revision bf45993c05fbff161c55a858a73b7488e832d63c)
+++ uspace/lib/pcut/tests/manytests.expected	(revision bf45993c05fbff161c55a858a73b7488e832d63c)
@@ -0,0 +1,83 @@
+1..80
+#> Starting suite Default.
+ok 1 my_test_001
+ok 2 my_test_002
+ok 3 my_test_003
+ok 4 my_test_004
+ok 5 my_test_005
+ok 6 my_test_006
+ok 7 my_test_007
+ok 8 my_test_008
+ok 9 my_test_009
+ok 10 my_test_010
+ok 11 my_test_011
+ok 12 my_test_012
+ok 13 my_test_013
+ok 14 my_test_014
+ok 15 my_test_015
+ok 16 my_test_016
+ok 17 my_test_017
+ok 18 my_test_018
+ok 19 my_test_019
+ok 20 my_test_020
+ok 21 my_test_021
+ok 22 my_test_022
+ok 23 my_test_023
+ok 24 my_test_024
+ok 25 my_test_025
+ok 26 my_test_026
+ok 27 my_test_027
+ok 28 my_test_028
+ok 29 my_test_029
+ok 30 my_test_030
+ok 31 my_test_031
+ok 32 my_test_032
+ok 33 my_test_033
+ok 34 my_test_034
+ok 35 my_test_035
+ok 36 my_test_036
+ok 37 my_test_037
+ok 38 my_test_038
+ok 39 my_test_039
+ok 40 my_test_040
+ok 41 my_test_041
+ok 42 my_test_042
+ok 43 my_test_043
+ok 44 my_test_044
+ok 45 my_test_045
+ok 46 my_test_046
+ok 47 my_test_047
+ok 48 my_test_048
+ok 49 my_test_049
+ok 50 my_test_050
+ok 51 my_test_051
+ok 52 my_test_052
+ok 53 my_test_053
+ok 54 my_test_054
+ok 55 my_test_055
+ok 56 my_test_056
+ok 57 my_test_057
+ok 58 my_test_058
+ok 59 my_test_059
+ok 60 my_test_060
+ok 61 my_test_061
+ok 62 my_test_062
+ok 63 my_test_063
+ok 64 my_test_064
+ok 65 my_test_065
+ok 66 my_test_066
+ok 67 my_test_067
+ok 68 my_test_068
+ok 69 my_test_069
+ok 70 my_test_070
+ok 71 my_test_071
+ok 72 my_test_072
+ok 73 my_test_073
+ok 74 my_test_074
+ok 75 my_test_075
+ok 76 my_test_076
+ok 77 my_test_077
+ok 78 my_test_078
+ok 79 my_test_079
+ok 80 my_test_080
+#> Finished suite Default (failed 0 of 80).
Index: uspace/lib/pcut/tests/multisuite.expected
===================================================================
--- uspace/lib/pcut/tests/multisuite.expected	(revision bf45993c05fbff161c55a858a73b7488e832d63c)
+++ uspace/lib/pcut/tests/multisuite.expected	(revision bf45993c05fbff161c55a858a73b7488e832d63c)
@@ -0,0 +1,12 @@
+1..4
+#> Starting suite intpow.
+not ok 1 zero_exponent failed
+# error: suite1.c:37: Expected <1> but got <0> (1 != intpow(2, 0))
+not ok 2 one_exponent failed
+# error: suite1.c:41: Expected <2> but got <0> (2 != intpow(2, 1))
+#> Finished suite intpow (failed 2 of 2).
+#> Starting suite intmin.
+not ok 3 test_min failed
+# error: suite2.c:38: Expected <5> but got <654> (5 != intmin(654, 5))
+ok 4 test_same_numbers
+#> Finished suite intmin (failed 1 of 2).
Index: uspace/lib/pcut/tests/preinithook.c
===================================================================
--- uspace/lib/pcut/tests/preinithook.c	(revision bf45993c05fbff161c55a858a73b7488e832d63c)
+++ uspace/lib/pcut/tests/preinithook.c	(revision bf45993c05fbff161c55a858a73b7488e832d63c)
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2014 Vojtech Horky
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <pcut/pcut.h>
+#include "tested.h"
+
+PCUT_INIT
+
+static int init_counter = 1;
+
+static void init_hook(void) {
+	init_counter++;
+}
+
+static void pre_init_hook(int *argc, char **argv[]) {
+	(void) argc;
+	(void) argv;
+	init_counter *= 2;
+}
+
+PCUT_TEST_BEFORE {
+	PCUT_ASSERT_INT_EQUALS(4, init_counter);
+	init_counter++;
+}
+
+PCUT_TEST(check_init_counter) {
+	PCUT_ASSERT_INT_EQUALS(5, init_counter);
+}
+
+PCUT_TEST(check_init_counter_2) {
+	PCUT_ASSERT_INT_EQUALS(5, init_counter);
+}
+
+
+PCUT_CUSTOM_MAIN(
+	PCUT_MAIN_SET_INIT_HOOK(init_hook),
+	PCUT_MAIN_SET_PREINIT_HOOK(pre_init_hook)
+)
+
Index: uspace/lib/pcut/tests/preinithook.expected
===================================================================
--- uspace/lib/pcut/tests/preinithook.expected	(revision bf45993c05fbff161c55a858a73b7488e832d63c)
+++ uspace/lib/pcut/tests/preinithook.expected	(revision bf45993c05fbff161c55a858a73b7488e832d63c)
@@ -0,0 +1,5 @@
+1..2
+#> Starting suite Default.
+ok 1 check_init_counter
+ok 2 check_init_counter_2
+#> Finished suite Default (failed 0 of 2).
Index: uspace/lib/pcut/tests/printing.c
===================================================================
--- uspace/lib/pcut/tests/printing.c	(revision bf45993c05fbff161c55a858a73b7488e832d63c)
+++ uspace/lib/pcut/tests/printing.c	(revision bf45993c05fbff161c55a858a73b7488e832d63c)
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2013 Vojtech Horky
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <pcut/pcut.h>
+#include "tested.h"
+#include <stdio.h>
+
+PCUT_INIT
+
+PCUT_TEST(print_to_stdout) {
+	printf("Printed from a test to stdout!\n");
+}
+
+PCUT_TEST(print_to_stderr) {
+	fprintf(stderr, "Printed from a test to stderr!\n");
+}
+
+PCUT_TEST(print_to_stdout_and_fail) {
+	printf("Printed from a test to stdout!\n");
+	PCUT_ASSERT_NOT_NULL(0);
+}
+
+PCUT_MAIN()
Index: uspace/lib/pcut/tests/printing.expected
===================================================================
--- uspace/lib/pcut/tests/printing.expected	(revision bf45993c05fbff161c55a858a73b7488e832d63c)
+++ uspace/lib/pcut/tests/printing.expected	(revision bf45993c05fbff161c55a858a73b7488e832d63c)
@@ -0,0 +1,10 @@
+1..3
+#> Starting suite Default.
+ok 1 print_to_stdout
+# stdio: Printed from a test to stdout!
+ok 2 print_to_stderr
+# stdio: Printed from a test to stderr!
+not ok 3 print_to_stdout_and_fail failed
+# error: printing.c:45: Pointer <0> ought not to be NULL
+# stdio: Printed from a test to stdout!
+#> Finished suite Default (failed 1 of 3).
Index: uspace/lib/pcut/tests/simple.c
===================================================================
--- uspace/lib/pcut/tests/simple.c	(revision bf45993c05fbff161c55a858a73b7488e832d63c)
+++ uspace/lib/pcut/tests/simple.c	(revision bf45993c05fbff161c55a858a73b7488e832d63c)
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2012-2013 Vojtech Horky
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <pcut/pcut.h>
+#include "tested.h"
+
+PCUT_INIT
+
+PCUT_TEST(zero_exponent) {
+	PCUT_ASSERT_INT_EQUALS(1, intpow(2, 0));
+}
+
+PCUT_TEST(one_exponent) {
+	PCUT_ASSERT_INT_EQUALS(2, intpow(2, 1));
+	PCUT_ASSERT_INT_EQUALS(39, intpow(39, 1));
+}
+
+PCUT_TEST(same_strings) {
+	const char *p = "xyz";
+	PCUT_ASSERT_STR_EQUALS("xyz", p);
+	PCUT_ASSERT_STR_EQUALS("abc", "XXXabd" + 3);
+}
+
+PCUT_MAIN()
Index: uspace/lib/pcut/tests/simple.expected
===================================================================
--- uspace/lib/pcut/tests/simple.expected	(revision bf45993c05fbff161c55a858a73b7488e832d63c)
+++ uspace/lib/pcut/tests/simple.expected	(revision bf45993c05fbff161c55a858a73b7488e832d63c)
@@ -0,0 +1,9 @@
+1..3
+#> Starting suite Default.
+not ok 1 zero_exponent failed
+# error: simple.c:35: Expected <1> but got <0> (1 != intpow(2, 0))
+not ok 2 one_exponent failed
+# error: simple.c:39: Expected <2> but got <0> (2 != intpow(2, 1))
+not ok 3 same_strings failed
+# error: simple.c:46: Expected <abc> but got <abd> ("abc" != "XXXabd" + 3)
+#> Finished suite Default (failed 3 of 3).
Index: uspace/lib/pcut/tests/skip.c
===================================================================
--- uspace/lib/pcut/tests/skip.c	(revision bf45993c05fbff161c55a858a73b7488e832d63c)
+++ uspace/lib/pcut/tests/skip.c	(revision bf45993c05fbff161c55a858a73b7488e832d63c)
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2014 Vojtech Horky
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <pcut/pcut.h>
+#include "tested.h"
+
+PCUT_INIT
+
+PCUT_TEST(normal_test) {
+	PCUT_ASSERT_INT_EQUALS(1, 1);
+}
+
+PCUT_TEST(skipped, PCUT_TEST_SKIP) {
+	PCUT_ASSERT_STR_EQUALS("skip", "not skipped");
+}
+
+PCUT_TEST(again_normal_test) {
+	PCUT_ASSERT_INT_EQUALS(1, 1);
+}
+
+PCUT_MAIN()
Index: uspace/lib/pcut/tests/skip.expected
===================================================================
--- uspace/lib/pcut/tests/skip.expected	(revision bf45993c05fbff161c55a858a73b7488e832d63c)
+++ uspace/lib/pcut/tests/skip.expected	(revision bf45993c05fbff161c55a858a73b7488e832d63c)
@@ -0,0 +1,5 @@
+1..2
+#> Starting suite Default.
+ok 1 normal_test
+ok 2 again_normal_test
+#> Finished suite Default (failed 0 of 2).
Index: uspace/lib/pcut/tests/suite1.c
===================================================================
--- uspace/lib/pcut/tests/suite1.c	(revision bf45993c05fbff161c55a858a73b7488e832d63c)
+++ uspace/lib/pcut/tests/suite1.c	(revision bf45993c05fbff161c55a858a73b7488e832d63c)
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2012-2013 Vojtech Horky
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <pcut/pcut.h>
+#include "tested.h"
+
+PCUT_INIT
+
+PCUT_TEST_SUITE(intpow);
+
+PCUT_TEST(zero_exponent) {
+	PCUT_ASSERT_INT_EQUALS(1, intpow(2, 0));
+}
+
+PCUT_TEST(one_exponent) {
+	PCUT_ASSERT_INT_EQUALS(2, intpow(2, 1));
+	PCUT_ASSERT_INT_EQUALS(39, intpow(39, 1));
+}
+
+PCUT_EXPORT(intpow_suite);
Index: uspace/lib/pcut/tests/suite2.c
===================================================================
--- uspace/lib/pcut/tests/suite2.c	(revision bf45993c05fbff161c55a858a73b7488e832d63c)
+++ uspace/lib/pcut/tests/suite2.c	(revision bf45993c05fbff161c55a858a73b7488e832d63c)
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2012-2013 Vojtech Horky
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <pcut/pcut.h>
+#include "tested.h"
+
+PCUT_INIT
+
+PCUT_TEST_SUITE(intmin);
+
+PCUT_TEST(test_min) {
+	PCUT_ASSERT_INT_EQUALS(5, intmin(5, 654));
+	PCUT_ASSERT_INT_EQUALS(5, intmin(654, 5));
+
+	PCUT_ASSERT_INT_EQUALS(-17, intmin(-17, -2));
+}
+
+PCUT_TEST(test_same_numbers) {
+	PCUT_ASSERT_INT_EQUALS(5, intmin(5, 5));
+	PCUT_ASSERT_INT_EQUALS(719, intmin(719, 719));
+	PCUT_ASSERT_INT_EQUALS(-4589, intmin(-4589, 4589));
+}
+
+PCUT_EXPORT(intmin_suite);
Index: uspace/lib/pcut/tests/suite_all.c
===================================================================
--- uspace/lib/pcut/tests/suite_all.c	(revision bf45993c05fbff161c55a858a73b7488e832d63c)
+++ uspace/lib/pcut/tests/suite_all.c	(revision bf45993c05fbff161c55a858a73b7488e832d63c)
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2012-2013 Vojtech Horky
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <pcut/pcut.h>
+
+PCUT_INIT
+
+PCUT_IMPORT(intpow_suite);
+PCUT_IMPORT(intmin_suite);
+
+PCUT_MAIN()
Index: uspace/lib/pcut/tests/suites.c
===================================================================
--- uspace/lib/pcut/tests/suites.c	(revision bf45993c05fbff161c55a858a73b7488e832d63c)
+++ uspace/lib/pcut/tests/suites.c	(revision bf45993c05fbff161c55a858a73b7488e832d63c)
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2012-2013 Vojtech Horky
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <pcut/pcut.h>
+#include "tested.h"
+
+PCUT_INIT
+
+PCUT_TEST_SUITE(intpow);
+
+PCUT_TEST(zero_exponent) {
+	PCUT_ASSERT_INT_EQUALS(1, intpow(2, 0));
+}
+
+PCUT_TEST(one_exponent) {
+	PCUT_ASSERT_INT_EQUALS(2, intpow(2, 1));
+	PCUT_ASSERT_INT_EQUALS(39, intpow(39, 1));
+}
+
+PCUT_TEST_SUITE(intmin);
+
+PCUT_TEST(test_min) {
+	PCUT_ASSERT_INT_EQUALS(5, intmin(5, 654));
+	PCUT_ASSERT_INT_EQUALS(5, intmin(654, 5));
+
+	PCUT_ASSERT_INT_EQUALS(-17, intmin(-17, -2));
+}
+
+PCUT_MAIN()
Index: uspace/lib/pcut/tests/suites.expected
===================================================================
--- uspace/lib/pcut/tests/suites.expected	(revision bf45993c05fbff161c55a858a73b7488e832d63c)
+++ uspace/lib/pcut/tests/suites.expected	(revision bf45993c05fbff161c55a858a73b7488e832d63c)
@@ -0,0 +1,11 @@
+1..3
+#> Starting suite intpow.
+not ok 1 zero_exponent failed
+# error: suites.c:37: Expected <1> but got <0> (1 != intpow(2, 0))
+not ok 2 one_exponent failed
+# error: suites.c:41: Expected <2> but got <0> (2 != intpow(2, 1))
+#> Finished suite intpow (failed 2 of 2).
+#> Starting suite intmin.
+not ok 3 test_min failed
+# error: suites.c:49: Expected <5> but got <654> (5 != intmin(654, 5))
+#> Finished suite intmin (failed 1 of 1).
Index: uspace/lib/pcut/tests/teardown.c
===================================================================
--- uspace/lib/pcut/tests/teardown.c	(revision bf45993c05fbff161c55a858a73b7488e832d63c)
+++ uspace/lib/pcut/tests/teardown.c	(revision bf45993c05fbff161c55a858a73b7488e832d63c)
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2013 Vojtech Horky
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+#include <pcut/pcut.h>
+#include "tested.h"
+
+PCUT_INIT
+
+
+
+PCUT_TEST_SUITE(with_teardown);
+
+PCUT_TEST_AFTER {
+	printf("This is teardown-function.\n");
+}
+
+PCUT_TEST(empty) {
+}
+
+PCUT_TEST(failing) {
+	PCUT_ASSERT_INT_EQUALS(10, intmin(1, 2));
+}
+
+
+
+PCUT_TEST_SUITE(with_failing_teardown);
+
+PCUT_TEST_AFTER {
+	printf("This is failing teardown-function.\n");
+	PCUT_ASSERT_INT_EQUALS(42, intmin(10, 20));
+}
+
+PCUT_TEST(empty2) {
+}
+
+PCUT_TEST(printing2) {
+	printf("Printed before test failure.\n");
+	PCUT_ASSERT_INT_EQUALS(0, intmin(-17, -19));
+}
+
+PCUT_TEST(failing2) {
+	PCUT_ASSERT_INT_EQUALS(12, intmin(3, 5));
+}
+
+
+PCUT_MAIN()
Index: uspace/lib/pcut/tests/teardown.expected
===================================================================
--- uspace/lib/pcut/tests/teardown.expected	(revision bf45993c05fbff161c55a858a73b7488e832d63c)
+++ uspace/lib/pcut/tests/teardown.expected	(revision bf45993c05fbff161c55a858a73b7488e832d63c)
@@ -0,0 +1,22 @@
+1..5
+#> Starting suite with_teardown.
+ok 1 empty
+# stdio: This is teardown-function.
+not ok 2 failing failed
+# error: teardown.c:47: Expected <10> but got <1> (10 != intmin(1, 2))
+# stdio: This is teardown-function.
+#> Finished suite with_teardown (failed 1 of 2).
+#> Starting suite with_failing_teardown.
+not ok 3 empty2 failed
+# error: teardown.c:56: Expected <42> but got <10> (42 != intmin(10, 20))
+# stdio: This is failing teardown-function.
+not ok 4 printing2 failed
+# error: teardown.c:64: Expected <0> but got <-17> (0 != intmin(-17, -19))
+# error: teardown.c:56: Expected <42> but got <10> (42 != intmin(10, 20))
+# stdio: Printed before test failure.
+# stdio: This is failing teardown-function.
+not ok 5 failing2 failed
+# error: teardown.c:68: Expected <12> but got <3> (12 != intmin(3, 5))
+# error: teardown.c:56: Expected <42> but got <10> (42 != intmin(10, 20))
+# stdio: This is failing teardown-function.
+#> Finished suite with_failing_teardown (failed 3 of 3).
Index: uspace/lib/pcut/tests/teardownaborts.c
===================================================================
--- uspace/lib/pcut/tests/teardownaborts.c	(revision bf45993c05fbff161c55a858a73b7488e832d63c)
+++ uspace/lib/pcut/tests/teardownaborts.c	(revision bf45993c05fbff161c55a858a73b7488e832d63c)
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2012-2013 Vojtech Horky
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+#include <pcut/pcut.h>
+#include <stdlib.h>
+
+PCUT_INIT
+
+PCUT_TEST_AFTER {
+	abort();
+}
+
+PCUT_TEST(print_and_fail) {
+	printf("Tear-down will cause null pointer access...\n");
+	PCUT_ASSERT_NOT_NULL(NULL);
+}
+
+PCUT_MAIN()
Index: uspace/lib/pcut/tests/teardownaborts.expected
===================================================================
--- uspace/lib/pcut/tests/teardownaborts.expected	(revision bf45993c05fbff161c55a858a73b7488e832d63c)
+++ uspace/lib/pcut/tests/teardownaborts.expected	(revision bf45993c05fbff161c55a858a73b7488e832d63c)
@@ -0,0 +1,6 @@
+1..1
+#> Starting suite Default.
+not ok 1 print_and_fail aborted
+# error: teardownaborts.c:41: Pointer <NULL> ought not to be NULL
+# stdio: Tear-down will cause null pointer access...
+#> Finished suite Default (failed 1 of 1).
Index: uspace/lib/pcut/tests/tested.c
===================================================================
--- uspace/lib/pcut/tests/tested.c	(revision bf45993c05fbff161c55a858a73b7488e832d63c)
+++ uspace/lib/pcut/tests/tested.c	(revision bf45993c05fbff161c55a858a73b7488e832d63c)
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2012-2013 Vojtech Horky
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "tested.h"
+
+#define UNUSED(a) ((void)a)
+
+long intpow(int base, int exp) {
+	UNUSED(base); UNUSED(exp);
+	return 0;
+}
+
+int intmin(int a, int b) {
+	UNUSED(b);
+	return a;
+}
Index: uspace/lib/pcut/tests/tested.h
===================================================================
--- uspace/lib/pcut/tests/tested.h	(revision bf45993c05fbff161c55a858a73b7488e832d63c)
+++ uspace/lib/pcut/tests/tested.h	(revision bf45993c05fbff161c55a858a73b7488e832d63c)
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2012-2013 Vojtech Horky
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef TESTED_H
+#define TESTED_H
+
+long intpow(int base, int exp);
+
+int intmin(int a, int b);
+
+#endif
Index: uspace/lib/pcut/tests/testlist.c
===================================================================
--- uspace/lib/pcut/tests/testlist.c	(revision bf45993c05fbff161c55a858a73b7488e832d63c)
+++ uspace/lib/pcut/tests/testlist.c	(revision bf45993c05fbff161c55a858a73b7488e832d63c)
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2014 Vojtech Horky
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <pcut/pcut.h>
+#include "tested.h"
+
+PCUT_INIT
+
+static char *argv_patched[] = {
+	NULL, /* Will be patched at run-time. */
+	(char *) "-l",
+	NULL
+};
+
+static void pre_init_hook(int *argc, char **argv[]) {
+	argv_patched[0] = (*argv)[0];
+	*argc = 2;
+	*argv = argv_patched;
+}
+
+PCUT_TEST(unreachable) {
+	PCUT_ASSERT_TRUE(0 && "unreachable code");
+}
+
+
+PCUT_CUSTOM_MAIN(
+	PCUT_MAIN_SET_PREINIT_HOOK(pre_init_hook)
+)
+
Index: uspace/lib/pcut/tests/testlist.expected
===================================================================
--- uspace/lib/pcut/tests/testlist.expected	(revision bf45993c05fbff161c55a858a73b7488e832d63c)
+++ uspace/lib/pcut/tests/testlist.expected	(revision bf45993c05fbff161c55a858a73b7488e832d63c)
@@ -0,0 +1,2 @@
+*****Suite `Default' [1]
+*****Test `unreachable' [2]
Index: uspace/lib/pcut/tests/timeout.c
===================================================================
--- uspace/lib/pcut/tests/timeout.c	(revision bf45993c05fbff161c55a858a73b7488e832d63c)
+++ uspace/lib/pcut/tests/timeout.c	(revision bf45993c05fbff161c55a858a73b7488e832d63c)
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2012-2013 Vojtech Horky
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <pcut/pcut.h>
+
+#ifdef __unix
+#include <unistd.h>
+#endif
+#if defined(__WIN64) || defined(__WIN32) || defined(_WIN32)
+#include <windows.h>
+#endif
+
+#include <stdio.h>
+#include "tested.h"
+
+static void my_sleep(int sec) {
+#ifdef __unix
+	sleep(sec);
+#endif
+#if defined(__WIN64) || defined(__WIN32) || defined(_WIN32)
+	Sleep(1000 * sec);
+#endif
+}
+
+PCUT_INIT
+
+PCUT_TEST(shall_time_out) {
+	printf("Text before sleeping.\n");
+	my_sleep(PCUT_DEFAULT_TEST_TIMEOUT * 5);
+	printf("Text after the sleep.\n");
+}
+
+PCUT_TEST(custom_time_out,
+		PCUT_TEST_SET_TIMEOUT(PCUT_DEFAULT_TEST_TIMEOUT * 3)) {
+	printf("Text before sleeping.\n");
+	my_sleep(PCUT_DEFAULT_TEST_TIMEOUT * 2);
+	printf("Text after the sleep.\n");
+}
+
+PCUT_MAIN()
Index: uspace/lib/pcut/tests/timeout.expected
===================================================================
--- uspace/lib/pcut/tests/timeout.expected	(revision bf45993c05fbff161c55a858a73b7488e832d63c)
+++ uspace/lib/pcut/tests/timeout.expected	(revision bf45993c05fbff161c55a858a73b7488e832d63c)
@@ -0,0 +1,8 @@
+1..2
+#> Starting suite Default.
+not ok 1 shall_time_out aborted
+# stdio: Text before sleeping.
+ok 2 custom_time_out
+# stdio: Text before sleeping.
+# stdio: Text after the sleep.
+#> Finished suite Default (failed 1 of 2).
Index: uspace/lib/pcut/tests/xmlreport.c
===================================================================
--- uspace/lib/pcut/tests/xmlreport.c	(revision bf45993c05fbff161c55a858a73b7488e832d63c)
+++ uspace/lib/pcut/tests/xmlreport.c	(revision bf45993c05fbff161c55a858a73b7488e832d63c)
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2014 Vojtech Horky
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <pcut/pcut.h>
+#include "tested.h"
+
+#include <pcut/pcut.h>
+#include "tested.h"
+
+PCUT_INIT
+
+PCUT_TEST(zero_exponent) {
+	PCUT_ASSERT_INT_EQUALS(1, intpow(2, 0));
+}
+
+PCUT_TEST(one_exponent) {
+	PCUT_ASSERT_INT_EQUALS(2, intpow(2, 1));
+	PCUT_ASSERT_INT_EQUALS(39, intpow(39, 1));
+}
+
+PCUT_TEST(same_strings) {
+	const char *p = "xyz";
+	PCUT_ASSERT_STR_EQUALS("xyz", p);
+	PCUT_ASSERT_STR_EQUALS("abc", "XXXabd" + 3);
+}
+
+PCUT_CUSTOM_MAIN(
+	PCUT_MAIN_SET_XML_REPORT
+)
Index: uspace/lib/pcut/tests/xmlreport.expected
===================================================================
--- uspace/lib/pcut/tests/xmlreport.expected	(revision bf45993c05fbff161c55a858a73b7488e832d63c)
+++ uspace/lib/pcut/tests/xmlreport.expected	(revision bf45993c05fbff161c55a858a73b7488e832d63c)
@@ -0,0 +1,17 @@
+<?xml version="1.0"?>
+<report tests-total="3">
+	<suite name="Default">
+		<testcase name="zero_exponent" status="fail">
+			<error-message><![CDATA[xmlreport.c:38: Expected <1> but got <0> (1 != intpow(2, 0))
+]]></error-message>
+		</testcase><!-- zero_exponent -->
+		<testcase name="one_exponent" status="fail">
+			<error-message><![CDATA[xmlreport.c:42: Expected <2> but got <0> (2 != intpow(2, 1))
+]]></error-message>
+		</testcase><!-- one_exponent -->
+		<testcase name="same_strings" status="fail">
+			<error-message><![CDATA[xmlreport.c:49: Expected <abc> but got <abd> ("abc" != "XXXabd" + 3)
+]]></error-message>
+		</testcase><!-- same_strings -->
+	</suite><!-- Default: 3 / 3 -->
+</report>
Index: uspace/lib/pcut/update-from-master.sh
===================================================================
--- uspace/lib/pcut/update-from-master.sh	(revision bf45993c05fbff161c55a858a73b7488e832d63c)
+++ uspace/lib/pcut/update-from-master.sh	(revision bf45993c05fbff161c55a858a73b7488e832d63c)
@@ -0,0 +1,80 @@
+#!/bin/sh
+
+#
+# Copyright (c) 2014 Vojtech Horky
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# - Redistributions of source code must retain the above copyright
+#   notice, this list of conditions and the following disclaimer.
+# - Redistributions in binary form must reproduce the above copyright
+#   notice, this list of conditions and the following disclaimer in the
+#   documentation and/or other materials provided with the distribution.
+# - The name of the author may not be used to endorse or promote products
+#   derived from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+# IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+run_echo() {
+	echo "[exec]:" "$@"
+	"$@"
+}
+
+RUN=run_echo
+
+
+# Because of the very first command we issue that deletes about everything
+if ! [ "$1" == "really-overwrite" ]; then
+	echo "Wrong argument, see sources!"
+	exit 1
+fi
+
+$RUN find -not -name update-from-master.sh -delete
+$RUN wget -q https://github.com/vhotspur/pcut/archive/master.zip -O pcut-master.zip
+$RUN unzip -q -u pcut-master.zip
+$RUN mv -f pcut-master/* .
+$RUN rm -rf pcut-master pcut-master.zip
+$RUN rm -rf contrib doc
+$RUN rm -f CMakeLists.txt *.cmake run_test.sh
+
+cat >Makefile <<'EOF_MAKEFILE_HEAD'
+#
+# This file was generated by call to update-from-master.sh
+#
+
+USPACE_PREFIX = ../..
+PCUT_TEST_PREFIX = test-libpcut-
+
+EXTRA_OUTPUT = \
+EOF_MAKEFILE_HEAD
+
+for testfile in tests/*.expected; do
+	testname=`basename "$testfile" .expected`
+	echo "	\$(PCUT_TEST_PREFIX)${testname}\$(PCUT_TEST_SUFFIX) \\"
+done | sed '$s/\\$//' >>Makefile
+
+cat >>Makefile <<'EOF_MAKEFILE_TAIL'
+
+include helenos.mak
+
+include $(USPACE_PREFIX)/Makefile.common
+
+include helenos.test.mak
+
+test-libpcut-%: $(OUTPUT)
+	$(LD) -n $(LFLAGS) -T $(LINKER_SCRIPT) -o $@ $^ $(OUTPUT) $(BASE_LIBS)
+
+EOF_MAKEFILE_TAIL
Index: uspace/lib/posix/Makefile
===================================================================
--- uspace/lib/posix/Makefile	(revision 58f26cbc0c1d3b1eee97b21bf0c30c8d9de4acd5)
+++ uspace/lib/posix/Makefile	(revision bf45993c05fbff161c55a858a73b7488e832d63c)
@@ -79,4 +79,8 @@
 	source/unistd.c
 
+TEST_SOURCES = \
+	test/main.c \
+	test/scanf.c
+
 include $(USPACE_PREFIX)/Makefile.common
 
Index: uspace/lib/posix/test/main.c
===================================================================
--- uspace/lib/posix/test/main.c	(revision bf45993c05fbff161c55a858a73b7488e832d63c)
+++ uspace/lib/posix/test/main.c	(revision bf45993c05fbff161c55a858a73b7488e832d63c)
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2014 Vojtech Horky
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <pcut/pcut.h>
+
+PCUT_INIT
+
+PCUT_IMPORT(scanf);
+
+PCUT_MAIN()
Index: uspace/lib/posix/test/scanf.c
===================================================================
--- uspace/lib/posix/test/scanf.c	(revision bf45993c05fbff161c55a858a73b7488e832d63c)
+++ uspace/lib/posix/test/scanf.c	(revision bf45993c05fbff161c55a858a73b7488e832d63c)
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2014 Vojtech Horky
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#define LIBPOSIX_INTERNAL
+#define __POSIX_DEF__(x) posix_##x
+
+#include "posix/errno.h"
+#include "posix/stdio.h"
+
+#include <pcut/pcut.h>
+
+
+PCUT_INIT
+
+PCUT_TEST_SUITE(scanf);
+
+
+#ifndef UARCH_sparc64
+
+/*
+ * We need some floating point functions for scanf() imlementation
+ * that are not yet available for SPARC-64.
+ */
+
+PCUT_TEST(int_decimal) {
+	int number;
+	int rc = posix_sscanf("4242", "%d", &number);
+	PCUT_ASSERT_INT_EQUALS(1, rc);
+	PCUT_ASSERT_INT_EQUALS(4242, number);
+}
+
+PCUT_TEST(int_negative_decimal) {
+	int number;
+	int rc = posix_sscanf("-53", "%d", &number);
+	PCUT_ASSERT_INT_EQUALS(1, rc);
+	PCUT_ASSERT_INT_EQUALS(-53, number);
+}
+
+#endif
+
+PCUT_EXPORT(scanf);
