Index: uspace/lib/pcut/README.rst
===================================================================
--- uspace/lib/pcut/README.rst	(revision 01579ad1020d073a91a73278666eb1fa947e04f5)
+++ uspace/lib/pcut/README.rst	(revision 134ac5d540e7a16b331b62d90010680153d6fbd6)
@@ -22,74 +22,42 @@
 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
+More details can be found on PCUT wiki on GitHub:
+https://github.com/vhotspur/pcut/wiki
 
 
-Main goal - simple to use
--------------------------
+Quick-start example
+-------------------
 
-Let's illustrate how PCUT aims to be simple when creating unit tests for
-function ``intmin`` that ought to return smaller of its two arguments.::
+The following code tests the standard ``atoi`` function::
 
-	int intmin(int a, int b) {
-		return a > b ? b : a;
+	#include <pcut/pcut.h>
+	#include <stdlib.h>
+	
+	PCUT_INIT
+	
+	PCUT_TEST(atoi_zero) {
+	    PCUT_ASSERT_INT_EQUALS(0, atoi("0"));
 	}
 	
-Individual test-cases for such method could cover following cases: getting
-minimal of
-
-- two same numbers
-- negative and positive number
-- two negative numbers
-- two positive numbers
-- "corner case" numbers, such as minimal and maximal represented number
-
-In PCUT, that would be translated to the following code:::
-
-	#include <pcut/test.h>
-	#include <limits.h>
-	/* Other include to have declaration of intmin */
-	
-	PCUT_INIT
-
-	PCUT_TEST_SUITE(intmin_tests);
-
-	PCUT_TEST(same_number) {
-		PCUT_ASSERT_INT_EQUALS(719, intmin(719, 719) );
-		PCUT_ASSERT_INT_EQUALS(-4589, intmin(-4589, -4589) );
+	PCUT_TEST(atoi_positive) {
+	    PCUT_ASSERT_INT_EQUALS(42, atoi("42"));
 	}
 	
-	PCUT_TEST(positive_and_negative) {
-		PCUT_ASSERT_INT_EQUALS(-5, intmin(-5, 71) );
-		PCUT_ASSERT_INT_EQUALS(-17, intmin(423, -17) );
+	PCUT_TEST(atoi_negative) {
+	    PCUT_ASSERT_INT_EQUALS(-273, atoi("-273"));
 	}
 	
-	PCUT_TEST(same_sign) {
-		PCUT_ASSERT_INT_EQUALS(22, intmin(129, 22) );
-		PCUT_ASSERT_INT_EQUALS(-37, intmin(-37, -1) );
-	}
-	
-	PCUT_TEST(corner_cases) {
-		PCUT_ASSERT_INT_EQUALS(INT_MIN, intmin(INT_MIN, -1234) );
-		PCUT_ASSERT_INT_EQUALS(9876, intmin(9876, INT_MAX) );
-	}
-
 	PCUT_MAIN()
 
-And that's all.
-You do not need to manually specify which tests to run etc., 
-everything is done magically via the ``PCUT_INIT``, ``PCUT_MAIN`` and
-``PCUT_TEST`` macros.
-All you need to do is to compile this code and link it with ``libpcut``.
-Result of the linking would be an executable that runs the tests and
-reports the results.
+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.
 
-
-Examples
---------
+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.
 
 
Index: uspace/lib/pcut/base.mak
===================================================================
--- uspace/lib/pcut/base.mak	(revision 01579ad1020d073a91a73278666eb1fa947e04f5)
+++ uspace/lib/pcut/base.mak	(revision 134ac5d540e7a16b331b62d90010680153d6fbd6)
@@ -31,4 +31,7 @@
 PCUT_CFLAGS = -Wall -Wextra -std=c99 -Werror -I$(PCUT_INCLUDE)
 
+PCUT_PREPROC_SOURCES = \
+	src/preproc.c
+
 PCUT_SOURCES = \
 	src/assert.c \
Index: uspace/lib/pcut/include/pcut/asserts.h
===================================================================
--- uspace/lib/pcut/include/pcut/asserts.h	(revision 134ac5d540e7a16b331b62d90010680153d6fbd6)
+++ uspace/lib/pcut/include/pcut/asserts.h	(revision 134ac5d540e7a16b331b62d90010680153d6fbd6)
@@ -0,0 +1,278 @@
+/*
+ * 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>
+
+/** @cond devel */
+
+/** Raise assertion error.
+ *
+ * This function immediately terminates current test and executes a tear-down
+ * (if registered).
+ *
+ * @param fmt Printf-like format string.
+ * @param ... Extra arguments.
+ */
+void pcut_failed_assertion_fmt(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);
+
+/** @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 fmt Printf-like format string.
+ * @param ... Extra arguments.
+ */
+#define PCUT_ASSERTION_FAILED(fmt, ...) \
+	pcut_failed_assertion_fmt(__FILE__ ":%d: " fmt, __LINE__, ##__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 134ac5d540e7a16b331b62d90010680153d6fbd6)
+++ uspace/lib/pcut/include/pcut/datadef.h	(revision 134ac5d540e7a16b331b62d90010680153d6fbd6)
@@ -0,0 +1,138 @@
+/*
+ * 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 */
+
+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
+};
+
+/** 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;
+
+/** 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;
+	union {
+		/** Test-specific time-out in seconds. */
+		int timeout;
+	};
+};
+
+/** @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 the union.
+	 *
+	 * Use PCUT_KIND_* to determine which field of the union is used.
+	 */
+	int kind;
+	union {
+		struct {
+			const char *name;
+			pcut_setup_func_t setup;
+			pcut_setup_func_t teardown;
+		} suite;
+		struct {
+			const char *name;
+			pcut_test_func_t func;
+			pcut_extra_t *extras;
+		} test;
+		/* setup is used for both set-up and tear-down */
+		struct {
+			pcut_setup_func_t func;
+		} setup;
+		struct {
+			pcut_item_t *last;
+		} nested;
+		struct {
+			int dummy;
+		} meta;
+	};
+};
+
+#ifdef PCUT_DEBUG_BUILD
+#define PCUT_DEBUG(msg, ...) \
+	printf("[PCUT]: Debug: " msg "\n", ##__VA_ARGS__)
+#else
+
+/** 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.
+ */
+#define PCUT_DEBUG(msg, ...) (void)0
+#endif
+
+/** @endcond */
+
+#endif
Index: uspace/lib/pcut/include/pcut/impl.h
===================================================================
--- uspace/lib/pcut/include/pcut/impl.h	(revision 01579ad1020d073a91a73278666eb1fa947e04f5)
+++ 	(revision )
@@ -1,184 +1,0 @@
-/*
- * 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.
- */
-
-#if !defined(PCUT_TEST_H_GUARD) && !defined(PCUT_INTERNAL)
-#error "You cannot include this file directly."
-#endif
-
-#ifndef PCUT_IMPL_H_GUARD
-#define PCUT_IMPL_H_GUARD
-
-#include "prevs.h"
-#include <stdlib.h>
-
-enum {
-	PCUT_KIND_SKIP,
-	PCUT_KIND_NESTED,
-	PCUT_KIND_SETUP,
-	PCUT_KIND_TEARDOWN,
-	PCUT_KIND_TESTSUITE,
-	PCUT_KIND_TEST
-};
-
-typedef struct pcut_item pcut_item_t;
-typedef void (*pcut_test_func_t)(void);
-typedef void (*pcut_setup_func_t)(void);
-
-struct pcut_item {
-	pcut_item_t *previous;
-	pcut_item_t *next;
-	int id;
-	int kind;
-	union {
-		struct {
-			const char *name;
-			pcut_setup_func_t setup;
-			pcut_setup_func_t teardown;
-		} suite;
-		struct {
-			const char *name;
-			pcut_test_func_t func;
-		} test;
-		/* setup is used for both set-up and tear-down */
-		struct {
-			pcut_setup_func_t func;
-		} setup;
-		struct {
-			pcut_item_t *last;
-		} nested;
-		struct {
-			int dummy;
-		} meta;
-	};
-};
-
-void pcut_failed_assertion(const char *message);
-void pcut_failed_assertion_fmt(const char *fmt, ...);
-int pcut_str_equals(const char *a, const char *b);
-int pcut_main(pcut_item_t *last, int argc, char *argv[]);
-
-#define PCUT_ASSERTION_FAILED(fmt, ...) \
-	pcut_failed_assertion_fmt(__FILE__ ":%d: " fmt, __LINE__, ##__VA_ARGS__)
-
-#define PCUT_JOIN_IMPL(a, b) a##b
-#define PCUT_JOIN(a, b) PCUT_JOIN_IMPL(a, b)
-
-#define PCUT_ITEM_NAME(number) \
-	PCUT_JOIN(pcut_item_, number)
-
-#define PCUT_ITEM_NAME_PREV(number) \
-	PCUT_JOIN(pcut_item_, PCUT_JOIN(PCUT_PREV_, number))
-
-#define PCUT_ADD_ITEM(number, itemkind, ...) \
-		static pcut_item_t PCUT_ITEM_NAME(number) = { \
-				.previous = &PCUT_ITEM_NAME_PREV(number), \
-				.next = NULL, \
-				.id = -1, \
-				.kind = itemkind, \
-				__VA_ARGS__ \
-		}; \
-
-#define PCUT_TEST_IMPL(testname, number) \
-		static void PCUT_JOIN(test_, testname)(void); \
-		PCUT_ADD_ITEM(number, PCUT_KIND_TEST, \
-				.test = { \
-					.name = #testname, \
-					.func = PCUT_JOIN(test_, testname) \
-				} \
-		) \
-		void PCUT_JOIN(test_, testname)(void)
-
-#define PCUT_TEST_SUITE_IMPL(suitename, number) \
-		PCUT_ADD_ITEM(number, PCUT_KIND_TESTSUITE, \
-				.suite = { \
-					.name = #suitename, \
-					.setup = NULL, \
-					.teardown = NULL \
-				} \
-		)
-
-#define PCUT_TEST_BEFORE_IMPL(number) \
-		static void PCUT_JOIN(setup_, number)(void); \
-		PCUT_ADD_ITEM(number, PCUT_KIND_SETUP, \
-				.setup.func = PCUT_JOIN(setup_, number) \
-		) \
-		void PCUT_JOIN(setup_, number)(void)
-
-#define PCUT_TEST_AFTER_IMPL(number) \
-		static void PCUT_JOIN(teardown_, number)(void); \
-		PCUT_ADD_ITEM(number, PCUT_KIND_TEARDOWN, \
-				.setup.func = PCUT_JOIN(teardown_, number) \
-		) \
-		void PCUT_JOIN(teardown_, number)(void)
-
-#define PCUT_EXPORT_IMPL(identifier, number) \
-	pcut_item_t pcut_exported_##identifier = { \
-		.previous = &PCUT_ITEM_NAME_PREV(number), \
-		.next = NULL, \
-		.kind = PCUT_KIND_SKIP \
-	}
-
-/*
- * 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;
- */
-#define PCUT_IMPORT_IMPL(identifier, number) \
-	extern pcut_item_t pcut_exported_##identifier; \
-	PCUT_ADD_ITEM(number, PCUT_KIND_NESTED, \
-		.nested.last = &pcut_exported_##identifier \
-	)
-
-#define PCUT_INIT_IMPL(first_number) \
-	static pcut_item_t PCUT_ITEM_NAME(__COUNTER__) = { \
-		.previous = NULL, \
-		.next = NULL, \
-		.id = -1, \
-		.kind = PCUT_KIND_SKIP \
-	}; \
-	PCUT_TEST_SUITE(Default);
-
-#define PCUT_MAIN_IMPL(last_number) \
-	static pcut_item_t pcut_item_last = { \
-		.previous = &PCUT_JOIN(pcut_item_, PCUT_JOIN(PCUT_PREV_, last_number)), \
-		.kind = PCUT_KIND_SKIP \
-	}; \
-	int main(int argc, char *argv[]) { \
-		return pcut_main(&pcut_item_last, argc, argv); \
-	}
-
-#ifdef PCUT_DEBUG_BUILD
-#define PCUT_DEBUG(msg, ...) \
-	printf("[PCUT]: Debug: " msg "\n", ##__VA_ARGS__)
-#else
-#define PCUT_DEBUG(msg, ...) (void)0
-#endif
-
-#endif
Index: uspace/lib/pcut/include/pcut/pcut.h
===================================================================
--- uspace/lib/pcut/include/pcut/pcut.h	(revision 134ac5d540e7a16b331b62d90010680153d6fbd6)
+++ uspace/lib/pcut/include/pcut/pcut.h	(revision 134ac5d540e7a16b331b62d90010680153d6fbd6)
@@ -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 01579ad1020d073a91a73278666eb1fa947e04f5)
+++ uspace/lib/pcut/include/pcut/prevs.h	(revision 134ac5d540e7a16b331b62d90010680153d6fbd6)
@@ -1,4 +1,4 @@
 /*
- * Copyright (c) 2012-2013 Vojtech Horky
+ * Copyright (c) 2012-2014 Vojtech Horky
  * All rights reserved.
  *
@@ -27,10 +27,14 @@
  */
 
-#if !defined(PCUT_TEST_H_GUARD) && !defined(PCUT_INTERNAL)
-#error "You cannot include this file directly."
-#endif
+/**
+ * @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
@@ -335,4 +339,8 @@
 #define PCUT_PREV_300 299
 
+/** @endcond */
+
 #endif
 
+#endif
+
Index: uspace/lib/pcut/include/pcut/test.h
===================================================================
--- uspace/lib/pcut/include/pcut/test.h	(revision 01579ad1020d073a91a73278666eb1fa947e04f5)
+++ 	(revision )
@@ -1,172 +1,0 @@
-/*
- * 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
- *
- * PCUT: Plain-C unit-testing mini-framework.
- */
-#ifndef PCUT_TEST_H_GUARD
-#define PCUT_TEST_H_GUARD
-
-#include "impl.h"
-
-/** 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.
- *
- * @param pointer The pointer to be tested.
- */
-#define PCUT_ASSERT_NOT_NULL(pointer) \
-	do { \
-		void *pcut_ptr_eval = (pointer); \
-		if (pcut_ptr_eval == (NULL)) { \
-			PCUT_ASSERTION_FAILED("Pointer <" #pointer "> ought not to be NULL"); \
-		} \
-	} while (0)
-
-
-/** 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); \
-		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)
-
-
-/** Define a new test with given name.
- *
- * @param name A valid C identifier name (not quoted).
- */
-#define PCUT_TEST(name) PCUT_TEST_IMPL(name, __COUNTER__)
-
-/** Define a new test suite with given name.
- *
- * All tests following this macro belong to the new suite
- * (up to next occurence of PCUT_TEST_SUITE).
- *
- */
-#define PCUT_TEST_SUITE(name) PCUT_TEST_SUITE_IMPL(name, __COUNTER__)
-
-/** Define a set-up function for a test suite.
- *
- * There could be only a single set-up function for each suite.
- */
-#define PCUT_TEST_BEFORE \
-	PCUT_TEST_BEFORE_IMPL(__COUNTER__)
-
-/** Define a tear-down function for a test suite.
- *
- * There could be only a single tear-down function for each suite.
- */
-#define PCUT_TEST_AFTER \
-	PCUT_TEST_AFTER_IMPL(__COUNTER__)
-
-/** Export test cases from current file. */
-#define PCUT_EXPORT(identifier) \
-	PCUT_EXPORT_IMPL(identifier, __COUNTER__)
-
-/** Import test cases from a different file. */
-#define PCUT_IMPORT(identifier) \
-	PCUT_IMPORT_IMPL(identifier, __COUNTER__)
-
-/** Initialize the PCUT testing framework. */
-#define PCUT_INIT \
-	PCUT_INIT_IMPL(__COUNTER__)
-
-/** Insert code to run all the tests. */
-#define PCUT_MAIN() \
-	PCUT_MAIN_IMPL(__COUNTER__)
-
-#endif
Index: uspace/lib/pcut/include/pcut/tests.h
===================================================================
--- uspace/lib/pcut/include/pcut/tests.h	(revision 134ac5d540e7a16b331b62d90010680153d6fbd6)
+++ uspace/lib/pcut/include/pcut/tests.h	(revision 134ac5d540e7a16b331b62d90010680153d6fbd6)
@@ -0,0 +1,422 @@
+/*
+ * 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/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 */
+
+/** 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)
+
+/** 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) = { \
+				.previous = &PCUT_ITEM_NAME_PREV(number), \
+				.next = NULL, \
+				.id = -1, \
+				.kind = 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) \
+	{ .type = PCUT_EXTRA_TIMEOUT, .timeout = (time_out) }
+
+/** Skip current test.
+ *
+ * Use as argument to PCUT_TEST().
+ */
+#define PCUT_TEST_SKIP \
+	{ .type = PCUT_EXTRA_SKIP }
+
+
+/** @cond devel */
+
+/** Terminate list of extra test options. */
+#define PCUT_TEST_EXTRA_LAST { .type = PCUT_EXTRA_LAST }
+
+/** 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(testname, number, ...) \
+		PCUT_ITEM_COUNTER_INCREMENT \
+		static pcut_extra_t PCUT_ITEM_EXTRAS_NAME(number)[] = { \
+				__VA_ARGS__ \
+		}; \
+		static void PCUT_JOIN(test_, testname)(void); \
+		PCUT_ADD_ITEM(number, PCUT_KIND_TEST, \
+				.test = { \
+					.name = #testname, \
+					.func = PCUT_JOIN(test_, testname), \
+					.extras = PCUT_ITEM_EXTRAS_NAME(number), \
+				} \
+		) \
+		void PCUT_JOIN(test_, testname)(void)
+
+/** @endcond */
+
+/** Define a new test with given name.
+ *
+ * @param name A valid C identifier name (not quoted).
+ * @param ... Extra test properties.
+ */
+#define PCUT_TEST(name, ...) \
+	PCUT_TEST_WITH_NUMBER(name, PCUT_ITEM_COUNTER, ##__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, \
+				.suite = { \
+					.name = #suitename, \
+					.setup = NULL, \
+					.teardown = 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.func = PCUT_ITEM_SETUP_NAME(number) \
+		) \
+		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, \
+				.setup.func = PCUT_ITEM_SETUP_NAME(number) \
+		) \
+		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 = { \
+		.previous = &PCUT_ITEM_NAME_PREV(number), \
+		.next = NULL, \
+		.kind = PCUT_KIND_SKIP \
+	}
+
+/** 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, \
+		.nested.last = &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) = { \
+		.previous = NULL, \
+		.next = NULL, \
+		.id = -1, \
+		.kind = PCUT_KIND_SKIP \
+	}; \
+	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_item_t pcut_item_last = { \
+		.previous = &PCUT_ITEM_NAME_PREV(number), \
+		.kind = PCUT_KIND_SKIP \
+	}; \
+	int main(int argc, char *argv[]) { \
+		return pcut_main(&pcut_item_last, argc, argv); \
+	}
+
+/** @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)
+
+
+/**
+ * @}
+ */
+
+#endif
Index: uspace/lib/pcut/pcut.mak
===================================================================
--- uspace/lib/pcut/pcut.mak	(revision 01579ad1020d073a91a73278666eb1fa947e04f5)
+++ uspace/lib/pcut/pcut.mak	(revision 134ac5d540e7a16b331b62d90010680153d6fbd6)
@@ -29,5 +29,5 @@
 -include base.mak
 
-all: $(PCUT_LIB)
+all: $(PCUT_LIB) $(PCUT_PREPROC)
 
 pcut-clean: check-clean platform-clean
@@ -35,3 +35,9 @@
 
 %.o: %.c
+
+src/%.o: src/%.c
 	$(CC) -c -o $@ $(PCUT_CFLAGS) $<
+
+doxygen:
+	doxygen doc/Doxyfile.devel
+	doxygen doc/Doxyfile.user
Index: uspace/lib/pcut/src/internal.h
===================================================================
--- uspace/lib/pcut/src/internal.h	(revision 01579ad1020d073a91a73278666eb1fa947e04f5)
+++ uspace/lib/pcut/src/internal.h	(revision 134ac5d540e7a16b331b62d90010680153d6fbd6)
@@ -27,8 +27,12 @@
  */
 
+/** @file
+ * Common definitions internally used in PCUT.
+ */
+
 #ifndef PCUT_INTERNAL_H_GUARD
 #define PCUT_INTERNAL_H_GUARD
 
-#include <pcut/test.h>
+#include <pcut/pcut.h>
 #include <stdlib.h>
 
@@ -69,6 +73,4 @@
 pcut_item_t *pcut_get_real_next(pcut_item_t *item);
 pcut_item_t *pcut_get_real(pcut_item_t *item);
-const char* pcut_run_test(pcut_test_func_t function);
-const char* pcut_run_setup_teardown(pcut_setup_func_t function);
 void pcut_print_tests(pcut_item_t *first);
 int pcut_is_arg_with_number(const char *arg, const char *opt, int *value);
@@ -78,13 +80,13 @@
 int pcut_run_test_single(pcut_item_t *test);
 
-extern pcut_item_t *pcut_current_test;
-extern pcut_item_t *pcut_current_suite;
-extern int pcut_running_test_now;
-extern int pcut_running_setup_now;
+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;
-/** Reporting callbacks structure. */
+
+/** @copydoc pcut_report_ops_t */
 struct pcut_report_ops {
 	/** Initialize the reporting, given all tests. */
@@ -116,8 +118,36 @@
 void pcut_report_done(void);
 
+/* OS-dependent functions. */
 
+/** 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);
 
Index: uspace/lib/pcut/src/list.c
===================================================================
--- uspace/lib/pcut/src/list.c	(revision 01579ad1020d073a91a73278666eb1fa947e04f5)
+++ uspace/lib/pcut/src/list.c	(revision 134ac5d540e7a16b331b62d90010680153d6fbd6)
@@ -35,5 +35,5 @@
 #include <stdlib.h>
 #include "internal.h"
-#include <pcut/test.h>
+#include <pcut/pcut.h>
 
 
@@ -118,4 +118,31 @@
 }
 
+/** 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) {
+	assert(first != NULL);
+	if (first->kind == PCUT_KIND_SKIP) {
+		first = pcut_get_real_next(first);
+	}
+	for (pcut_item_t *it = first; it != NULL; it = pcut_get_real_next(it)) {
+		if (it->kind != PCUT_KIND_TEST) {
+			continue;
+		}
+		pcut_extra_t *extras = it->test.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.
  *
@@ -143,4 +170,6 @@
 	}
 
+	detect_skipped_tests(next);
+
 	set_ids(next);
 
Index: uspace/lib/pcut/src/os/generic.c
===================================================================
--- uspace/lib/pcut/src/os/generic.c	(revision 01579ad1020d073a91a73278666eb1fa947e04f5)
+++ uspace/lib/pcut/src/os/generic.c	(revision 134ac5d540e7a16b331b62d90010680153d6fbd6)
@@ -76,5 +76,8 @@
 static char extra_output_buffer[OUTPUT_BUFFER_SIZE];
 
-/** Prepare for a new test. */
+/** 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);
Index: uspace/lib/pcut/src/os/helenos.c
===================================================================
--- uspace/lib/pcut/src/os/helenos.c	(revision 01579ad1020d073a91a73278666eb1fa947e04f5)
+++ uspace/lib/pcut/src/os/helenos.c	(revision 134ac5d540e7a16b331b62d90010680153d6fbd6)
@@ -34,4 +34,5 @@
 #include <stdlib.h>
 #include <str.h>
+#include <str_error.h>
 #include <unistd.h>
 #include <sys/types.h>
@@ -41,4 +42,5 @@
 #include <task.h>
 #include <fcntl.h>
+#include <fibril_synch.h>
 #include "../internal.h"
 
@@ -68,4 +70,12 @@
 }
 
+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. */
@@ -89,5 +99,8 @@
 static char extra_output_buffer[OUTPUT_BUFFER_SIZE];
 
-/** Prepare for a new test. */
+/** 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);
@@ -95,4 +108,45 @@
 	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;
 }
 
@@ -131,6 +185,5 @@
 	int status = TEST_OUTCOME_PASS;
 
-	task_id_t task_id;
-	int rc = task_spawnvf(&task_id, self_path, arguments, files);
+	int rc = task_spawnvf(&test_task_id, self_path, arguments, files);
 	if (rc != EOK) {
 		status = TEST_OUTCOME_ERROR;
@@ -138,7 +191,17 @@
 	}
 
+	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(task_id, &task_exit, &task_retval);
+	rc = task_wait(test_task_id, &task_exit, &task_retval);
 	if (rc != EOK) {
 		status = TEST_OUTCOME_ERROR;
@@ -151,4 +214,9 @@
 	}
 
+	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);
 
Index: uspace/lib/pcut/src/os/stdc.c
===================================================================
--- uspace/lib/pcut/src/os/stdc.c	(revision 01579ad1020d073a91a73278666eb1fa947e04f5)
+++ uspace/lib/pcut/src/os/stdc.c	(revision 134ac5d540e7a16b331b62d90010680153d6fbd6)
@@ -54,2 +54,12 @@
 	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 01579ad1020d073a91a73278666eb1fa947e04f5)
+++ uspace/lib/pcut/src/os/unix.c	(revision 134ac5d540e7a16b331b62d90010680153d6fbd6)
@@ -32,7 +32,10 @@
  */
 
+/** We need _POSX_SOURCE because of kill(). */
+#define _POSIX_SOURCE
 #include <stdlib.h>
 #include <unistd.h>
 #include <sys/types.h>
+#include <signal.h>
 #include <errno.h>
 #include <assert.h>
@@ -51,5 +54,8 @@
 static char extra_output_buffer[OUTPUT_BUFFER_SIZE];
 
-/** Prepare for a new test. */
+/** 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);
@@ -57,4 +63,16 @@
 	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);
 }
 
@@ -124,5 +142,4 @@
 
 	int link_stdout[2], link_stderr[2];
-	pid_t pid;
 
 	int rc = pipe(link_stdout);
@@ -141,6 +158,6 @@
 	}
 
-	pid = fork();
-	if (pid == (pid_t)-1) {
+	child_pid = fork();
+	if (child_pid == (pid_t)-1) {
 		snprintf(error_message_buffer, OUTPUT_BUFFER_SIZE - 1,
 			"fork() failed: %s.", strerror(rc));
@@ -149,5 +166,5 @@
 	}
 
-	if (pid == 0) {
+	if (child_pid == 0) {
 		/* We are the child. */
 		dup2(link_stdout[1], STDOUT_FILENO);
@@ -164,4 +181,7 @@
 	close(link_stderr[1]);
 
+	signal(SIGALRM, kill_child_on_alarm);
+	alarm(pcut_get_test_timeout(test));
+
 	size_t 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);
@@ -169,4 +189,5 @@
 	int status;
 	wait(&status);
+	alarm(0);
 
 	rc = convert_wait_status_to_outcome(status);
Index: uspace/lib/pcut/src/preproc.c
===================================================================
--- uspace/lib/pcut/src/preproc.c	(revision 134ac5d540e7a16b331b62d90010680153d6fbd6)
+++ uspace/lib/pcut/src/preproc.c	(revision 134ac5d540e7a16b331b62d90010680153d6fbd6)
@@ -0,0 +1,128 @@
+/*
+ * 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() {
+	FILE *input = stdin;
+	FILE *output = stdout;
+
+	int last_char_was_identifier = 0;
+	identifier_t last_identifier;
+
+	while (1) {
+		int current_char = fgetc(input);
+		if (current_char == EOF) {
+			break;
+		}
+
+		int 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 01579ad1020d073a91a73278666eb1fa947e04f5)
+++ uspace/lib/pcut/src/print.c	(revision 134ac5d540e7a16b331b62d90010680153d6fbd6)
@@ -32,5 +32,5 @@
  */
 
-#include <pcut/test.h>
+#include <pcut/pcut.h>
 #include <stdio.h>
 #include <stdlib.h>
Index: uspace/lib/pcut/src/report/tap.c
===================================================================
--- uspace/lib/pcut/src/report/tap.c	(revision 01579ad1020d073a91a73278666eb1fa947e04f5)
+++ uspace/lib/pcut/src/report/tap.c	(revision 134ac5d540e7a16b331b62d90010680153d6fbd6)
@@ -48,5 +48,8 @@
 static int failed_tests_in_suite;
 
-/** Initialize the tap output. */
+/** 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);
@@ -56,5 +59,8 @@
 }
 
-/** Report that a suite was started. */
+/** 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;
@@ -64,5 +70,8 @@
 }
 
-/** Report that a suite was completed. */
+/** 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",
@@ -104,5 +113,12 @@
 }
 
-/** Report a completed test. */
+/** 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,
Index: uspace/lib/pcut/src/report/xml.c
===================================================================
--- uspace/lib/pcut/src/report/xml.c	(revision 01579ad1020d073a91a73278666eb1fa947e04f5)
+++ uspace/lib/pcut/src/report/xml.c	(revision 134ac5d540e7a16b331b62d90010680153d6fbd6)
@@ -48,5 +48,8 @@
 static int failed_tests_in_suite;
 
-/** Initialize the XML output. */
+/** Initialize the XML output.
+ *
+ * @param all_items Start of the list with all items.
+ */
 static void xml_init(pcut_item_t *all_items) {
 	printf("<?xml version=\"1.0\"?>\n");
@@ -58,5 +61,8 @@
 }
 
-/** Report that a suite was started. */
+/** 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;
@@ -66,5 +72,8 @@
 }
 
-/** Report that a suite was completed. */
+/** 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->suite.name,
@@ -111,5 +120,12 @@
 }
 
-/** Report a completed test. */
+/** 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,
Index: uspace/lib/pcut/src/run.c
===================================================================
--- uspace/lib/pcut/src/run.c	(revision 01579ad1020d073a91a73278666eb1fa947e04f5)
+++ uspace/lib/pcut/src/run.c	(revision 134ac5d540e7a16b331b62d90010680153d6fbd6)
@@ -267,2 +267,22 @@
 }
 
+/** 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) {
+	PCUT_UNUSED(test);
+
+	int timeout = PCUT_DEFAULT_TEST_TIMEOUT;
+
+	pcut_extra_t *extras = test->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 134ac5d540e7a16b331b62d90010680153d6fbd6)
+++ uspace/lib/pcut/tests/.gitignore	(revision 134ac5d540e7a16b331b62d90010680153d6fbd6)
@@ -0,0 +1,2 @@
+*.run
+*.got
Index: uspace/lib/pcut/tests/alloc.c
===================================================================
--- uspace/lib/pcut/tests/alloc.c	(revision 01579ad1020d073a91a73278666eb1fa947e04f5)
+++ uspace/lib/pcut/tests/alloc.c	(revision 134ac5d540e7a16b331b62d90010680153d6fbd6)
@@ -27,5 +27,5 @@
  */
 
-#include <pcut/test.h>
+#include <pcut/pcut.h>
 #include <stdlib.h>
 #include <stdio.h>
Index: uspace/lib/pcut/tests/asserts.c
===================================================================
--- uspace/lib/pcut/tests/asserts.c	(revision 01579ad1020d073a91a73278666eb1fa947e04f5)
+++ uspace/lib/pcut/tests/asserts.c	(revision 134ac5d540e7a16b331b62d90010680153d6fbd6)
@@ -27,5 +27,5 @@
  */
 
-#include <pcut/test.h>
+#include <pcut/pcut.h>
 #include "tested.h"
 
@@ -47,3 +47,29 @@
 }
 
+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 01579ad1020d073a91a73278666eb1fa947e04f5)
+++ uspace/lib/pcut/tests/asserts.expected	(revision 134ac5d540e7a16b331b62d90010680153d6fbd6)
@@ -1,3 +1,3 @@
-1..3
+1..9
 #> Starting suite Default.
 not ok 1 int_equals failed
@@ -7,3 +7,13 @@
 not ok 3 str_equals failed
 # error: asserts.c:46: Expected <abc> but got <xyz> ("abc" != "xyz")
-#> Finished suite Default (failed 3 of 3).
+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/errno.c
===================================================================
--- uspace/lib/pcut/tests/errno.c	(revision 134ac5d540e7a16b331b62d90010680153d6fbd6)
+++ uspace/lib/pcut/tests/errno.c	(revision 134ac5d540e7a16b331b62d90010680153d6fbd6)
@@ -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 134ac5d540e7a16b331b62d90010680153d6fbd6)
+++ uspace/lib/pcut/tests/errno.expected	(revision 134ac5d540e7a16b331b62d90010680153d6fbd6)
@@ -0,0 +1,7 @@
+1..2
+#> Starting suite Default.
+not ok 1 errno_value failed
+# error: errno.c:46: Expected error 0 (EOK, Success) but got error 2 (No such file or directory)
+not ok 2 errno_variable failed
+# error: errno.c:54: Expected error 0 (EOK, Success) but got error 2 (No such file or directory)
+#> Finished suite Default (failed 2 of 2).
Index: uspace/lib/pcut/tests/helenos.mak
===================================================================
--- uspace/lib/pcut/tests/helenos.mak	(revision 134ac5d540e7a16b331b62d90010680153d6fbd6)
+++ uspace/lib/pcut/tests/helenos.mak	(revision 134ac5d540e7a16b331b62d90010680153d6fbd6)
@@ -0,0 +1,39 @@
+#
+# 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.
+#
+
+
+#
+# Add the check-build target for compiling all the tests
+#
+PCUT_LIB = libpcut.a
+TEST_BASE = tests/
+EXE_EXT = run
+TEST_CFLAGS = $(CFLAGS)
+TEST_LDFLAGS = -n $(LFLAGS) -T $(LINKER_SCRIPT) $(PCUT_LIB) $(LIBS) $(BASE_LIBS)
+-include tests/tests.mak
+clean: check-clean
Index: uspace/lib/pcut/tests/manytests.c
===================================================================
--- uspace/lib/pcut/tests/manytests.c	(revision 01579ad1020d073a91a73278666eb1fa947e04f5)
+++ uspace/lib/pcut/tests/manytests.c	(revision 134ac5d540e7a16b331b62d90010680153d6fbd6)
@@ -27,5 +27,5 @@
  */
 
-#include <pcut/test.h>
+#include <pcut/pcut.h>
 
 /*
Index: uspace/lib/pcut/tests/null.c
===================================================================
--- uspace/lib/pcut/tests/null.c	(revision 01579ad1020d073a91a73278666eb1fa947e04f5)
+++ uspace/lib/pcut/tests/null.c	(revision 134ac5d540e7a16b331b62d90010680153d6fbd6)
@@ -27,5 +27,5 @@
  */
 
-#include <pcut/test.h>
+#include <pcut/pcut.h>
 #include "tested.h"
 
Index: uspace/lib/pcut/tests/nullteardown.c
===================================================================
--- uspace/lib/pcut/tests/nullteardown.c	(revision 01579ad1020d073a91a73278666eb1fa947e04f5)
+++ uspace/lib/pcut/tests/nullteardown.c	(revision 134ac5d540e7a16b331b62d90010680153d6fbd6)
@@ -28,5 +28,5 @@
 
 #include <stdio.h>
-#include <pcut/test.h>
+#include <pcut/pcut.h>
 #include "tested.h"
 
Index: uspace/lib/pcut/tests/printing.c
===================================================================
--- uspace/lib/pcut/tests/printing.c	(revision 01579ad1020d073a91a73278666eb1fa947e04f5)
+++ uspace/lib/pcut/tests/printing.c	(revision 134ac5d540e7a16b331b62d90010680153d6fbd6)
@@ -27,5 +27,5 @@
  */
 
-#include <pcut/test.h>
+#include <pcut/pcut.h>
 #include "tested.h"
 #include <stdio.h>
Index: uspace/lib/pcut/tests/simple.c
===================================================================
--- uspace/lib/pcut/tests/simple.c	(revision 01579ad1020d073a91a73278666eb1fa947e04f5)
+++ uspace/lib/pcut/tests/simple.c	(revision 134ac5d540e7a16b331b62d90010680153d6fbd6)
@@ -27,5 +27,5 @@
  */
 
-#include <pcut/test.h>
+#include <pcut/pcut.h>
 #include "tested.h"
 
Index: uspace/lib/pcut/tests/skip.c
===================================================================
--- uspace/lib/pcut/tests/skip.c	(revision 134ac5d540e7a16b331b62d90010680153d6fbd6)
+++ uspace/lib/pcut/tests/skip.c	(revision 134ac5d540e7a16b331b62d90010680153d6fbd6)
@@ -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 134ac5d540e7a16b331b62d90010680153d6fbd6)
+++ uspace/lib/pcut/tests/skip.expected	(revision 134ac5d540e7a16b331b62d90010680153d6fbd6)
@@ -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 01579ad1020d073a91a73278666eb1fa947e04f5)
+++ uspace/lib/pcut/tests/suite1.c	(revision 134ac5d540e7a16b331b62d90010680153d6fbd6)
@@ -27,5 +27,5 @@
  */
 
-#include <pcut/test.h>
+#include <pcut/pcut.h>
 #include "tested.h"
 
Index: uspace/lib/pcut/tests/suite2.c
===================================================================
--- uspace/lib/pcut/tests/suite2.c	(revision 01579ad1020d073a91a73278666eb1fa947e04f5)
+++ uspace/lib/pcut/tests/suite2.c	(revision 134ac5d540e7a16b331b62d90010680153d6fbd6)
@@ -27,5 +27,5 @@
  */
 
-#include <pcut/test.h>
+#include <pcut/pcut.h>
 #include "tested.h"
 
Index: uspace/lib/pcut/tests/suite_all.c
===================================================================
--- uspace/lib/pcut/tests/suite_all.c	(revision 01579ad1020d073a91a73278666eb1fa947e04f5)
+++ uspace/lib/pcut/tests/suite_all.c	(revision 134ac5d540e7a16b331b62d90010680153d6fbd6)
@@ -27,5 +27,5 @@
  */
 
-#include <pcut/test.h>
+#include <pcut/pcut.h>
 
 PCUT_INIT
Index: uspace/lib/pcut/tests/suites.c
===================================================================
--- uspace/lib/pcut/tests/suites.c	(revision 01579ad1020d073a91a73278666eb1fa947e04f5)
+++ uspace/lib/pcut/tests/suites.c	(revision 134ac5d540e7a16b331b62d90010680153d6fbd6)
@@ -27,5 +27,5 @@
  */
 
-#include <pcut/test.h>
+#include <pcut/pcut.h>
 #include "tested.h"
 
Index: uspace/lib/pcut/tests/teardown.c
===================================================================
--- uspace/lib/pcut/tests/teardown.c	(revision 01579ad1020d073a91a73278666eb1fa947e04f5)
+++ uspace/lib/pcut/tests/teardown.c	(revision 134ac5d540e7a16b331b62d90010680153d6fbd6)
@@ -28,5 +28,5 @@
 
 #include <stdio.h>
-#include <pcut/test.h>
+#include <pcut/pcut.h>
 #include "tested.h"
 
Index: uspace/lib/pcut/tests/tests.mak
===================================================================
--- uspace/lib/pcut/tests/tests.mak	(revision 01579ad1020d073a91a73278666eb1fa947e04f5)
+++ uspace/lib/pcut/tests/tests.mak	(revision 134ac5d540e7a16b331b62d90010680153d6fbd6)
@@ -27,9 +27,10 @@
 #
 
-TEST_DEPS = $(TEST_BASE)tested.o $(PCUT_LIB)
+TEST_DEPS = $(TEST_BASE)tested.o
 
 TEST_APPS = \
 	$(TEST_BASE)alloc.$(EXE_EXT) \
 	$(TEST_BASE)asserts.$(EXE_EXT) \
+	$(TEST_BASE)errno.$(EXE_EXT) \
 	$(TEST_BASE)manytests.$(EXE_EXT) \
 	$(TEST_BASE)multisuite.$(EXE_EXT) \
@@ -38,6 +39,8 @@
 	$(TEST_BASE)printing.$(EXE_EXT) \
 	$(TEST_BASE)simple.$(EXE_EXT) \
+	$(TEST_BASE)skip.$(EXE_EXT) \
 	$(TEST_BASE)suites.$(EXE_EXT) \
-	$(TEST_BASE)teardown.$(EXE_EXT)
+	$(TEST_BASE)teardown.$(EXE_EXT) \
+	$(TEST_BASE)timeout.$(EXE_EXT)
 
 check-build: $(TEST_APPS)
@@ -46,20 +49,32 @@
 
 check-clean:
-	rm -f $(TEST_BASE)*.o $(TEST_BASE)*.$(EXE_EXT) $(TEST_BASE)*.got
+	rm -f $(TEST_BASE)*.o $(TEST_BASE)*.pcut.c $(TEST_BASE)*.$(EXE_EXT) $(TEST_BASE)*.got
 
 $(TEST_BASE)%.$(EXE_EXT): $(TEST_DEPS)
-	$(CC) -o $@ $^ $(TEST_LDFLAGS)
+	$(LD) -o $@ $^ $(TEST_LDFLAGS)
 
-$(TEST_BASE)alloc.$(EXE_EXT): $(TEST_BASE)alloc.o
-$(TEST_BASE)asserts.$(EXE_EXT): $(TEST_BASE)asserts.o
-$(TEST_BASE)manytests.$(EXE_EXT): $(TEST_BASE)manytests.o
-$(TEST_BASE)multisuite.$(EXE_EXT): $(TEST_BASE)suite_all.o $(TEST_BASE)suite1.o $(TEST_BASE)suite2.o
-$(TEST_BASE)null.$(EXE_EXT): $(TEST_BASE)null.o
-$(TEST_BASE)nullteardown.$(EXE_EXT): $(TEST_BASE)nullteardown.o
-$(TEST_BASE)printing.$(EXE_EXT): $(TEST_BASE)printing.o
-$(TEST_BASE)simple.$(EXE_EXT): $(TEST_BASE)simple.o
-$(TEST_BASE)suites.$(EXE_EXT): $(TEST_BASE)suites.o
-$(TEST_BASE)teardown.$(EXE_EXT): $(TEST_BASE)teardown.o
+$(TEST_BASE)alloc.$(EXE_EXT): $(TEST_BASE)alloc.o $(PCUT_LIB)
+$(TEST_BASE)asserts.$(EXE_EXT): $(TEST_BASE)asserts.o $(PCUT_LIB)
+$(TEST_BASE)errno.$(EXE_EXT): $(TEST_BASE)errno.o $(PCUT_LIB)
+$(TEST_BASE)manytests.$(EXE_EXT): $(TEST_BASE)manytests.o $(PCUT_LIB)
+$(TEST_BASE)multisuite.$(EXE_EXT): $(TEST_BASE)suite_all.o $(TEST_BASE)suite1.o $(TEST_BASE)suite2.o $(PCUT_LIB)
+$(TEST_BASE)null.$(EXE_EXT): $(TEST_BASE)null.o $(PCUT_LIB)
+$(TEST_BASE)nullteardown.$(EXE_EXT): $(TEST_BASE)nullteardown.o $(PCUT_LIB)
+$(TEST_BASE)printing.$(EXE_EXT): $(TEST_BASE)printing.o $(PCUT_LIB)
+$(TEST_BASE)simple.$(EXE_EXT): $(TEST_BASE)simple.o $(PCUT_LIB)
+$(TEST_BASE)skip.$(EXE_EXT): $(TEST_BASE)skip.o $(PCUT_LIB)
+$(TEST_BASE)suites.$(EXE_EXT): $(TEST_BASE)suites.o $(PCUT_LIB)
+$(TEST_BASE)teardown.$(EXE_EXT): $(TEST_BASE)teardown.o $(PCUT_LIB)
+$(TEST_BASE)timeout.$(EXE_EXT): $(TEST_BASE)timeout.o $(PCUT_LIB)
 
+
+ifeq ($(NEEDS_PREPROC),y)
+$(TEST_BASE)%.o: $(TEST_BASE)%.pcut.c
+	$(CC) -c -o $@ $(TEST_CFLAGS) $<
+
+$(TEST_BASE)%.pcut.c: $(TEST_BASE)%.c $(PCUT_PREPROC)
+	$(CC) -E $(TEST_CFLAGS) $< | $(PCUT_PREPROC) >$@
+else
 $(TEST_BASE)%.o: $(TEST_BASE)%.c
 	$(CC) -c -o $@ $(TEST_CFLAGS) $<
+endif
Index: uspace/lib/pcut/tests/timeout.c
===================================================================
--- uspace/lib/pcut/tests/timeout.c	(revision 134ac5d540e7a16b331b62d90010680153d6fbd6)
+++ uspace/lib/pcut/tests/timeout.c	(revision 134ac5d540e7a16b331b62d90010680153d6fbd6)
@@ -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 <unistd.h>
+#include <stdio.h>
+#include "tested.h"
+
+PCUT_INIT
+
+PCUT_TEST(shall_time_out) {
+	printf("Text before sleeping.\n");
+	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");
+	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 134ac5d540e7a16b331b62d90010680153d6fbd6)
+++ uspace/lib/pcut/tests/timeout.expected	(revision 134ac5d540e7a16b331b62d90010680153d6fbd6)
@@ -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/unix.mak
===================================================================
--- uspace/lib/pcut/unix.mak	(revision 01579ad1020d073a91a73278666eb1fa947e04f5)
+++ uspace/lib/pcut/unix.mak	(revision 134ac5d540e7a16b331b62d90010680153d6fbd6)
@@ -30,4 +30,5 @@
 OBJ_EXT = o
 PCUT_LIB = libpcut.a
+PCUT_PREPROC = ./pcut.bin
 
 # Installation paths
@@ -39,4 +40,5 @@
 
 PCUT_OBJECTS := $(addsuffix .o,$(basename $(PCUT_SOURCES)))
+PCUT_PREPROC_OBJECTS := $(addsuffix .o,$(basename $(PCUT_PREPROC_SOURCES)))
 
 # Take care of dependencies
@@ -53,5 +55,5 @@
 EXE_EXT = run
 TEST_CFLAGS = $(PCUT_CFLAGS)
-TEST_LDFLAGS = -L. -lpcut
+TEST_LDFLAGS = 
 -include tests/tests.mak
 TEST_APPS_BASENAMES := $(basename $(TEST_APPS))
@@ -75,5 +77,5 @@
 #
 platform-clean:
-	rm -f libpcut.a $(DEPEND)
+	rm -f $(DEPEND) $(PCUT_LIB) $(PCUT_PREPROC)
 
 #
@@ -83,4 +85,7 @@
 	$(AR) rc $@ $(PCUT_OBJECTS)
 	$(RANLIB) $@
+
+$(PCUT_PREPROC): $(PCUT_PREPROC_OBJECTS)
+	$(LD) $(LDFLAGS) -o $@ $(PCUT_PREPROC_OBJECTS)
 
 %.o: $(DEPEND)
