Index: uspace/lib/pcut/Makefile
===================================================================
--- uspace/lib/pcut/Makefile	(revision 15d0046f9b3c481dc13462cd9c94e9f757fa743d)
+++ uspace/lib/pcut/Makefile	(revision 9b201262edcb92c27cf4a25a8379320113426ab7)
@@ -4,4 +4,24 @@
 
 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
@@ -9,2 +29,7 @@
 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/helenos.test.mak
===================================================================
--- uspace/lib/pcut/helenos.test.mak	(revision 9b201262edcb92c27cf4a25a8379320113426ab7)
+++ uspace/lib/pcut/helenos.test.mak	(revision 9b201262edcb92c27cf4a25a8379320113426ab7)
@@ -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 15d0046f9b3c481dc13462cd9c94e9f757fa743d)
+++ uspace/lib/pcut/include/pcut/asserts.h	(revision 9b201262edcb92c27cf4a25a8379320113426ab7)
@@ -39,4 +39,11 @@
 #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 */
 
@@ -46,8 +53,10 @@
  * (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 *fmt, ...);
+void pcut_failed_assertion_fmt(const char *filename, int line, const char *fmt, ...);
 
 /** OS-agnostic string comparison.
@@ -70,4 +79,17 @@
 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 */
 
@@ -77,9 +99,8 @@
  * 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__)
+ * @param ... Printf-like arguments.
+ */
+#define PCUT_ASSERTION_FAILED(...) \
+	PCUT_ASSERTION_FAILED_INTERNAL(__VA_ARGS__, "")
 
 
@@ -115,9 +136,9 @@
  */
 #define PCUT_ASSERT_EQUALS(expected, actual) \
-		do {\
-			if (!((expected) == (actual))) { \
-				PCUT_ASSERTION_FAILED("Expected <"#expected "> but got <" #actual ">"); \
-			} \
-		} while (0)
+	do {\
+		if (!((expected) == (actual))) { \
+			PCUT_ASSERTION_FAILED("Expected <"#expected "> but got <" #actual ">"); \
+		} \
+	} while (0)
 
 /** Asserts that given pointer is NULL.
Index: uspace/lib/pcut/include/pcut/datadef.h
===================================================================
--- uspace/lib/pcut/include/pcut/datadef.h	(revision 15d0046f9b3c481dc13462cd9c94e9f757fa743d)
+++ uspace/lib/pcut/include/pcut/datadef.h	(revision 9b201262edcb92c27cf4a25a8379320113426ab7)
@@ -39,4 +39,13 @@
 /** @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,
@@ -54,4 +63,11 @@
 };
 
+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;
@@ -59,4 +75,7 @@
 /** 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. */
@@ -73,8 +92,19 @@
 	 */
 	int type;
-	union {
-		/** Test-specific time-out in seconds. */
-		int timeout;
-	};
+	/** 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 ***);
 };
 
@@ -89,48 +119,27 @@
 	int id;
 
-	/** Discriminator for the union.
-	 *
-	 * Use PCUT_KIND_* to determine which field of the union is used.
-	 */
+	/** Discriminator for this item. */
 	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;
-	};
+
+	/** 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;
 };
-
-#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 */
Index: uspace/lib/pcut/include/pcut/helper.h
===================================================================
--- uspace/lib/pcut/include/pcut/helper.h	(revision 9b201262edcb92c27cf4a25a8379320113426ab7)
+++ uspace/lib/pcut/include/pcut/helper.h	(revision 9b201262edcb92c27cf4a25a8379320113426ab7)
@@ -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/tests.h
===================================================================
--- uspace/lib/pcut/include/pcut/tests.h	(revision 15d0046f9b3c481dc13462cd9c94e9f757fa743d)
+++ uspace/lib/pcut/include/pcut/tests.h	(revision 9b201262edcb92c27cf4a25a8379320113426ab7)
@@ -37,4 +37,5 @@
 #define PCUT_TESTS_H_GUARD
 
+#include <pcut/helper.h>
 #include <pcut/datadef.h>
 
@@ -81,10 +82,4 @@
 /** @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.
  *
@@ -132,11 +127,11 @@
  */
 #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__ \
-		};
+	static pcut_item_t PCUT_ITEM_NAME(number) = { \
+		&PCUT_ITEM_NAME_PREV(number), \
+		NULL, \
+		-1, \
+		itemkind, \
+		__VA_ARGS__ \
+	}
 
 /** @endcond */
@@ -156,5 +151,5 @@
  */
 #define PCUT_TEST_SET_TIMEOUT(time_out) \
-	{ .type = PCUT_EXTRA_TIMEOUT, .timeout = (time_out) }
+	{ PCUT_EXTRA_TIMEOUT, (time_out) }
 
 /** Skip current test.
@@ -163,5 +158,5 @@
  */
 #define PCUT_TEST_SKIP \
-	{ .type = PCUT_EXTRA_SKIP }
+	{ PCUT_EXTRA_SKIP, 0 }
 
 
@@ -169,5 +164,5 @@
 
 /** Terminate list of extra test options. */
-#define PCUT_TEST_EXTRA_LAST { .type = PCUT_EXTRA_LAST }
+#define PCUT_TEST_EXTRA_LAST { PCUT_EXTRA_LAST, 0 }
 
 /** Define a new test with given name and given item number.
@@ -177,18 +172,19 @@
  * @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)
+#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 */
@@ -196,9 +192,11 @@
 /** 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)
+ * @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) \
+	)
 
 
@@ -221,12 +219,12 @@
  */
 #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 \
-				} \
-		)
+	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.
@@ -237,10 +235,12 @@
  */
 #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)
+	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.
@@ -251,10 +251,12 @@
  */
 #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)
+	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 */
@@ -328,7 +330,9 @@
 	PCUT_ITEM_COUNTER_INCREMENT \
 	pcut_item_t pcut_exported_##identifier = { \
-		.previous = &PCUT_ITEM_NAME_PREV(number), \
-		.next = NULL, \
-		.kind = PCUT_KIND_SKIP \
+		&PCUT_ITEM_NAME_PREV(number), \
+		NULL, \
+		-1, \
+		PCUT_KIND_SKIP, \
+		"exported_" #identifier, NULL, NULL, NULL, NULL, NULL, NULL \
 	}
 
@@ -344,5 +348,6 @@
 	extern pcut_item_t pcut_exported_##identifier; \
 	PCUT_ADD_ITEM(number, PCUT_KIND_NESTED, \
-		.nested.last = &pcut_exported_##identifier \
+		"import_" #identifier, NULL, NULL, NULL, NULL, NULL, \
+		&pcut_exported_##identifier \
 	)
 
@@ -382,8 +387,9 @@
 	PCUT_ITEM_COUNTER_INCREMENT \
 	static pcut_item_t PCUT_ITEM_NAME(first_number) = { \
-		.previous = NULL, \
-		.next = NULL, \
-		.id = -1, \
-		.kind = PCUT_KIND_SKIP \
+		NULL, \
+		NULL, \
+		-1, \
+		PCUT_KIND_SKIP, \
+		"init", NULL, NULL, NULL, NULL, NULL, NULL \
 	}; \
 	PCUT_TEST_SUITE(Default);
@@ -395,9 +401,18 @@
  * @param number Item number.
  */
-#define PCUT_MAIN_WITH_NUMBER(number) \
-	PCUT_ITEM_COUNTER_INCREMENT \
+#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 = { \
-		.previous = &PCUT_ITEM_NAME_PREV(number), \
-		.kind = PCUT_KIND_SKIP \
+		&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[]) { \
@@ -405,4 +420,8 @@
 	}
 
+/** Terminate list of extra options for main. */
+#define PCUT_MAIN_EXTRA_SET_LAST \
+	{ PCUT_MAIN_EXTRA_LAST, NULL, NULL }
+
 /** @endcond */
 
@@ -413,6 +432,46 @@
 /** Insert code to run all the tests. */
 #define PCUT_MAIN() \
-	PCUT_MAIN_WITH_NUMBER(PCUT_ITEM_COUNTER)
-
+	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) \
+ 	)
 
 /**
Index: uspace/lib/pcut/src/assert.c
===================================================================
--- uspace/lib/pcut/src/assert.c	(revision 15d0046f9b3c481dc13462cd9c94e9f757fa743d)
+++ uspace/lib/pcut/src/assert.c	(revision 9b201262edcb92c27cf4a25a8379320113426ab7)
@@ -35,4 +35,7 @@
  */
 
+/** We need _BSD_SOURCE because of vsnprintf() when compiling under C89. */
+#define _BSD_SOURCE
+
 #include "internal.h"
 #include <setjmp.h>
@@ -52,19 +55,18 @@
 static int message_buffer_index = 0;
 
-/** Announce that assertion failed.
- *
- * @warning This function may not return.
- *
- * @param fmt printf-style formatting string.
- *
- */
-void pcut_failed_assertion_fmt(const char *fmt, ...) {
+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;
 
-	va_list args;
-	va_start(args, fmt);
-	vsnprintf(current_buffer, MAX_MESSAGE_LENGTH, fmt, args);
-	va_end(args);
+	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 15d0046f9b3c481dc13462cd9c94e9f757fa743d)
+++ uspace/lib/pcut/src/internal.h	(revision 9b201262edcb92c27cf4a25a8379320113426ab7)
@@ -37,4 +37,28 @@
 #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)
@@ -63,4 +87,13 @@
 /** 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;
@@ -92,4 +125,6 @@
 	/** 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 *);
@@ -101,6 +136,4 @@
 	void (*test_done)(pcut_item_t *, int, const char *, const char *,
 		const char *);
-	/** Finalize the reporting. */
-	void (*done)(void);
 };
 
@@ -120,4 +153,16 @@
 /* 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.
  *
Index: uspace/lib/pcut/src/list.c
===================================================================
--- uspace/lib/pcut/src/list.c	(revision 15d0046f9b3c481dc13462cd9c94e9f757fa743d)
+++ uspace/lib/pcut/src/list.c	(revision 9b201262edcb92c27cf4a25a8379320113426ab7)
@@ -82,17 +82,19 @@
  */
 static void inline_nested_lists(pcut_item_t *nested) {
+	pcut_item_t *first;
+
 	if (nested->kind != PCUT_KIND_NESTED) {
 		return;
 	}
 
-	if (nested->nested.last == NULL) {
+	if (nested->nested == NULL) {
 		nested->kind = PCUT_KIND_SKIP;
 		return;
 	}
 
-	pcut_item_t *first = pcut_fix_list_get_real_head(nested->nested.last);
-	nested->nested.last->next = nested->next;
+	first = pcut_fix_list_get_real_head(nested->nested);
+	nested->nested->next = nested->next;
 	if (nested->next != NULL) {
-		nested->next->previous = nested->nested.last;
+		nested->next->previous = nested->nested;
 	}
 	nested->next = first;
@@ -107,10 +109,14 @@
  */
 static void set_ids(pcut_item_t *first) {
+	int id = 1;
+	pcut_item_t *it;
+
 	assert(first != NULL);
-	int id = 1;
+
 	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)) {
+
+	for (it = first; it != NULL; it = pcut_get_real_next(it)) {
 		it->id = id;
 		id++;
@@ -126,13 +132,19 @@
  */
 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 (pcut_item_t *it = first; it != NULL; it = pcut_get_real_next(it)) {
+
+	for (it = first; it != NULL; it = pcut_get_real_next(it)) {
+		pcut_extra_t *extras;
+
 		if (it->kind != PCUT_KIND_TEST) {
 			continue;
 		}
-		pcut_extra_t *extras = it->test.extras;
+
+		extras = it->extras;
 		while (extras->type != PCUT_EXTRA_LAST) {
 			if (extras->type == PCUT_EXTRA_SKIP) {
@@ -156,11 +168,12 @@
  */
 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);
 
-	pcut_item_t *next = last;
-
-	pcut_item_t *it = last->previous;
+	next = last;
+	it = last->previous;
 	while (it != NULL) {
 		it->next = next;
Index: uspace/lib/pcut/src/main.c
===================================================================
--- uspace/lib/pcut/src/main.c	(revision 15d0046f9b3c481dc13462cd9c94e9f757fa743d)
+++ uspace/lib/pcut/src/main.c	(revision 9b201262edcb92c27cf4a25a8379320113426ab7)
@@ -41,4 +41,12 @@
 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.
@@ -54,6 +62,5 @@
 		return 0;
 	}
-	int val = pcut_str_to_int(arg + opt_len);
-	*value = val;
+	*value = pcut_str_to_int(arg + opt_len);
 	return 1;
 }
@@ -85,4 +92,7 @@
  */
 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)) {
@@ -90,7 +100,4 @@
 	}
 
-	int is_first_test = 1;
-	int total_count = 0;
-
 	for (; it != NULL; it = pcut_get_real_next(it)) {
 		if (it->kind == PCUT_KIND_TESTSUITE) {
@@ -135,15 +142,16 @@
 static void set_setup_teardown_callbacks(pcut_item_t *first) {
 	pcut_item_t *active_suite = NULL;
-	for (pcut_item_t *it = first; it != NULL; it = pcut_get_real_next(it)) {
+	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->suite.setup = it->setup.func;
+				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->suite.teardown = it->setup.func;
+				active_suite->teardown_func = it->teardown_func;
 			}
 			it->kind = PCUT_KIND_SKIP;
@@ -166,9 +174,25 @@
 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) {
@@ -195,4 +219,10 @@
 	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);
 
@@ -218,4 +248,5 @@
 
 	if (run_only_test > 0) {
+		int rc;
 		pcut_item_t *test = pcut_find_by_id(items, run_only_test);
 		if (test == NULL) {
@@ -228,5 +259,4 @@
 		}
 
-		int rc;
 		if (pcut_run_mode == PCUT_RUN_MODE_SINGLE) {
 			rc = pcut_run_test_single(test);
@@ -241,5 +271,5 @@
 	pcut_report_init(items);
 
-	pcut_item_t *it = items;
+	it = items;
 	while (it != NULL) {
 		if (it->kind == PCUT_KIND_TESTSUITE) {
Index: uspace/lib/pcut/src/os/generic.c
===================================================================
--- uspace/lib/pcut/src/os/generic.c	(revision 15d0046f9b3c481dc13462cd9c94e9f757fa743d)
+++ uspace/lib/pcut/src/os/generic.c	(revision 9b201262edcb92c27cf4a25a8379320113426ab7)
@@ -33,4 +33,5 @@
 
 #include <stdlib.h>
+#include <stdio.h>
 #include <sys/types.h>
 #include <errno.h>
@@ -50,5 +51,5 @@
 /* Format the command to launch a test according to OS we are running on. */
 
-#if defined(__WIN64) || defined(__WIN32)
+#if defined(__WIN64) || defined(__WIN32) || defined(_WIN32)
 #include <process.h>
 
@@ -108,17 +109,25 @@
  */
 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);
 
-	char tempfile_name[PCUT_TEMP_FILENAME_BUFFER_SIZE];
 	FORMAT_TEMP_FILENAME(tempfile_name, PCUT_TEMP_FILENAME_BUFFER_SIZE - 1);
-
-	char command[PCUT_COMMAND_LINE_BUFFER_SIZE];
 	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);
 
-	int rc = system(command);
+	rc = system(command);
+
+	PCUT_DEBUG("system() returned 0x%04X", rc);
+
 	rc = convert_wait_status_to_outcome(rc);
 
-	FILE *tempfile = fopen(tempfile_name, "rb");
+	tempfile = fopen(tempfile_name, "rb");
 	if (tempfile == NULL) {
 		pcut_report_test_done(test, TEST_OUTCOME_ERROR, "Failed to open temporary file.", NULL, NULL);
@@ -133,2 +142,8 @@
 }
 
+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 15d0046f9b3c481dc13462cd9c94e9f757fa743d)
+++ uspace/lib/pcut/src/os/helenos.c	(revision 9b201262edcb92c27cf4a25a8379320113426ab7)
@@ -185,5 +185,6 @@
 	int status = TEST_OUTCOME_PASS;
 
-	int rc = task_spawnvf(&test_task_id, self_path, arguments, files);
+	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;
@@ -203,5 +204,5 @@
 	task_exit_t task_exit;
 	int task_retval;
-	rc = task_wait(test_task_id, &task_exit, &task_retval);
+	rc = task_wait(&test_task_wait, &task_exit, &task_retval);
 	if (rc != EOK) {
 		status = TEST_OUTCOME_ERROR;
@@ -227,2 +228,8 @@
 	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/unix.c
===================================================================
--- uspace/lib/pcut/src/os/unix.c	(revision 15d0046f9b3c481dc13462cd9c94e9f757fa743d)
+++ uspace/lib/pcut/src/os/unix.c	(revision 9b201262edcb92c27cf4a25a8379320113426ab7)
@@ -32,6 +32,8 @@
  */
 
-/** We need _POSX_SOURCE because of kill(). */
+/** 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>
@@ -137,11 +139,14 @@
  */
 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);
 
-	int link_stdout[2], link_stderr[2];
-
-	int rc = pipe(link_stdout);
+
+	rc = pipe(link_stdout);
 	if (rc == -1) {
 		snprintf(error_message_buffer, OUTPUT_BUFFER_SIZE - 1,
@@ -184,8 +189,7 @@
 	alarm(pcut_get_test_timeout(test));
 
-	size_t stderr_size = read_all(link_stderr[0], extra_output_buffer, OUTPUT_BUFFER_SIZE - 1);
+	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);
 
-	int status;
 	wait(&status);
 	alarm(0);
@@ -204,2 +208,9 @@
 	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 9b201262edcb92c27cf4a25a8379320113426ab7)
+++ uspace/lib/pcut/src/os/windows.c	(revision 9b201262edcb92c27cf4a25a8379320113426ab7)
@@ -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 15d0046f9b3c481dc13462cd9c94e9f757fa743d)
+++ uspace/lib/pcut/src/preproc.c	(revision 9b201262edcb92c27cf4a25a8379320113426ab7)
@@ -91,5 +91,5 @@
 }
 
-int main() {
+int main(int argc, char *argv[]) {
 	FILE *input = stdin;
 	FILE *output = stdout;
@@ -98,5 +98,11 @@
 	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) {
@@ -104,5 +110,5 @@
 		}
 
-		int current_char_denotes_identifier = is_identifier_char(current_char, last_char_was_identifier);
+		current_char_denotes_identifier = is_identifier_char(current_char, last_char_was_identifier);
 		if (current_char_denotes_identifier) {
 			if (!last_char_was_identifier) {
Index: uspace/lib/pcut/src/print.c
===================================================================
--- uspace/lib/pcut/src/print.c	(revision 15d0046f9b3c481dc13462cd9c94e9f757fa743d)
+++ uspace/lib/pcut/src/print.c	(revision 9b201262edcb92c27cf4a25a8379320113426ab7)
@@ -48,8 +48,8 @@
 		switch (it->kind) {
 		case PCUT_KIND_TEST:
-			printf("TEST %s (%p)\n", it->test.name, it->test.func);
+			printf("TEST %s\n", it->name);
 			break;
 		case PCUT_KIND_TESTSUITE:
-			printf("SUITE %s\n", it->suite.name);
+			printf("SUITE %s\n", it->name);
 			break;
 		case PCUT_KIND_SKIP:
@@ -72,11 +72,12 @@
  */
 void pcut_print_tests(pcut_item_t *first) {
-	for (pcut_item_t *it = pcut_get_real(first); it != NULL; it = pcut_get_real_next(it)) {
+	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->suite.name, it->id);
+			printf("  Suite `%s' [%d]\n", it->name, it->id);
 			break;
 		case PCUT_KIND_TEST:
-			printf("    Test `%s' [%d]\n", it->test.name, it->id);
+			printf("    Test `%s' [%d]\n", it->name, it->id);
 			break;
 		default:
Index: uspace/lib/pcut/src/report/report.c
===================================================================
--- uspace/lib/pcut/src/report/report.c	(revision 15d0046f9b3c481dc13462cd9c94e9f757fa743d)
+++ uspace/lib/pcut/src/report/report.c	(revision 9b201262edcb92c27cf4a25a8379320113426ab7)
@@ -44,7 +44,15 @@
  *
  * @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.
@@ -94,9 +102,11 @@
 	/* Ensure that we do not read past the full_output. */
 	if (full_output[full_output_size - 1] != 0) {
-		// FIXME: can this happen?
+		/* 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;
@@ -111,10 +121,10 @@
 
 		/* Determine the length of the text after the zeros. */
-		size_t message_length = pcut_str_size(full_output);
+		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
+				/* TODO: handle gracefully */
 				return;
 			}
@@ -125,5 +135,5 @@
 			/* Error message. */
 			if (message_length > error_buffer_size) {
-				// TODO: handle gracefully
+				/* TODO: handle gracefully */
 				return;
 			}
@@ -213,6 +223,6 @@
  *
  */
-void pcut_report_done() {
-	REPORT_CALL(done);
-}
-
+void pcut_report_done(void) {
+	REPORT_CALL_NO_ARGS(done);
+}
+
Index: uspace/lib/pcut/src/report/tap.c
===================================================================
--- uspace/lib/pcut/src/report/tap.c	(revision 15d0046f9b3c481dc13462cd9c94e9f757fa743d)
+++ uspace/lib/pcut/src/report/tap.c	(revision 9b201262edcb92c27cf4a25a8379320113426ab7)
@@ -67,5 +67,5 @@
 	failed_tests_in_suite = 0;
 
-	printf("#> Starting suite %s.\n", suite->suite.name);
+	printf("#> Starting suite %s.\n", suite->name);
 }
 
@@ -76,5 +76,5 @@
 static void tap_suite_done(pcut_item_t *suite) {
 	printf("#> Finished suite %s (failed %d of %d).\n",
-			suite->suite.name, failed_tests_in_suite, tests_in_suite);
+			suite->name, failed_tests_in_suite, tests_in_suite);
 }
 
@@ -98,8 +98,9 @@
  */
 static void print_by_lines(const char *message, const char *prefix) {
+	char *next_line_start;
 	if ((message == NULL) || (message[0] == 0)) {
 		return;
 	}
-	char *next_line_start = pcut_str_find_char(message, '\n');
+	next_line_start = pcut_str_find_char(message, '\n');
 	while (next_line_start != NULL) {
 		next_line_start[0] = 0;
@@ -124,5 +125,7 @@
 		const char *error_message, const char *teardown_error_message,
 		const char *extra_output) {
-	const char *test_name = test->test.name;
+	const char *test_name = test->name;
+	const char *status_str = NULL;
+	const char *fail_error_str = NULL;
 
 	if (outcome != TEST_OUTCOME_PASS) {
@@ -130,6 +133,4 @@
 	}
 
-	const char *status_str = NULL;
-	const char *fail_error_str = NULL;
 	switch (outcome) {
 	case TEST_OUTCOME_PASS:
@@ -158,14 +159,11 @@
 
 /** Report testing done. */
-static void tap_done() {
+static void tap_done(void) {
 }
 
 
 pcut_report_ops_t pcut_report_tap = {
-	.init = tap_init,
-	.done = tap_done,
-	.suite_start = tap_suite_start,
-	.suite_done = tap_suite_done,
-	.test_start = tap_test_start,
-	.test_done = tap_test_done
+	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 15d0046f9b3c481dc13462cd9c94e9f757fa743d)
+++ uspace/lib/pcut/src/report/xml.c	(revision 9b201262edcb92c27cf4a25a8379320113426ab7)
@@ -53,9 +53,8 @@
  */
 static void xml_init(pcut_item_t *all_items) {
-	printf("<?xml version=\"1.0\"?>\n");
-
 	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);
 }
@@ -69,5 +68,5 @@
 	failed_tests_in_suite = 0;
 
-	printf("\t<suite name=\"%s\">\n", suite->suite.name);
+	printf("\t<suite name=\"%s\">\n", suite->name);
 }
 
@@ -77,5 +76,5 @@
  */
 static void xml_suite_done(pcut_item_t *suite) {
-	printf("\t</suite><!-- %s: %d / %d -->\n", suite->suite.name,
+	printf("\t</suite><!-- %s: %d / %d -->\n", suite->name,
 		failed_tests_in_suite, tests_in_suite);
 }
@@ -100,4 +99,6 @@
  */
 static void print_by_lines(const char *message, const char *element_name) {
+	char *next_line_start;
+
 	if ((message == NULL) || (message[0] == 0)) {
 		return;
@@ -106,5 +107,5 @@
 	printf("\t\t\t<%s><![CDATA[", element_name);
 
-	char *next_line_start = pcut_str_find_char(message, '\n');
+	next_line_start = pcut_str_find_char(message, '\n');
 	while (next_line_start != NULL) {
 		next_line_start[0] = 0;
@@ -131,5 +132,6 @@
 		const char *error_message, const char *teardown_error_message,
 		const char *extra_output) {
-	const char *test_name = test->test.name;
+	const char *test_name = test->name;
+	const char *status_str = NULL;
 
 	if (outcome != TEST_OUTCOME_PASS) {
@@ -137,5 +139,4 @@
 	}
 
-	const char *status_str = NULL;
 	switch (outcome) {
 	case TEST_OUTCOME_PASS:
@@ -165,5 +166,5 @@
 
 /** Report testing done. */
-static void xml_done() {
+static void xml_done(void) {
 	printf("</report>\n");
 }
@@ -171,9 +172,6 @@
 
 pcut_report_ops_t pcut_report_xml = {
-	.init = xml_init,
-	.done = xml_done,
-	.suite_start = xml_suite_start,
-	.suite_done = xml_suite_done,
-	.test_start = xml_test_start,
-	.test_done = xml_test_done
+	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 15d0046f9b3c481dc13462cd9c94e9f757fa743d)
+++ uspace/lib/pcut/src/run.c	(revision 9b201262edcb92c27cf4a25a8379320113426ab7)
@@ -70,15 +70,19 @@
 
 /** A NULL-like suite. */
-static pcut_item_t default_suite = {
-	.kind = PCUT_KIND_TESTSUITE,
-	.id = -1,
-	.previous = NULL,
-	.next = NULL,
-	.suite = {
-		.name = "Default",
-		.setup = NULL,
-		.teardown = NULL
-	}
-};
+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.
@@ -94,4 +98,5 @@
 		it = it->previous;
 	}
+	init_default_suite_when_needed();
 	return &default_suite;
 }
@@ -115,4 +120,6 @@
  */
 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);
@@ -145,5 +152,5 @@
 		execute_teardown_on_failure = 0;
 		prev_message = message;
-		run_setup_teardown(current_suite->suite.teardown);
+		run_setup_teardown(current_suite->teardown_func);
 
 		/* Tear-down was okay. */
@@ -189,4 +196,6 @@
 	current_test = test;
 
+	pcut_hook_before_test(test);
+
 	/*
 	 * If anything goes wrong, execute the tear-down function
@@ -198,5 +207,5 @@
 	 * Run the set-up function.
 	 */
-	run_setup_teardown(current_suite->suite.setup);
+	run_setup_teardown(current_suite->setup_func);
 
 	/*
@@ -204,5 +213,5 @@
 	 * the actual test.
 	 */
-	test->test.func();
+	test->test_func();
 
 	/*
@@ -211,5 +220,5 @@
 	 */
 	execute_teardown_on_failure = 0;
-	run_setup_teardown(current_suite->suite.teardown);
+	run_setup_teardown(current_suite->teardown_func);
 
 	/*
@@ -234,9 +243,11 @@
  */
 int pcut_run_test_forked(pcut_item_t *test) {
+	int rc;
+
 	report_test_result = 0;
 	print_test_error = 1;
 	leave_means_exit = 1;
 
-	int rc = run_test(test);
+	rc = run_test(test);
 
 	current_test = NULL;
@@ -255,9 +266,11 @@
  */
 int pcut_run_test_single(pcut_item_t *test) {
+	int rc;
+
 	report_test_result = 1;
 	print_test_error = 0;
 	leave_means_exit = 0;
 
-	int rc = run_test(test);
+	rc = run_test(test);
 
 	current_test = NULL;
@@ -273,9 +286,8 @@
  */
 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;
+	pcut_extra_t *extras = test->extras;
+
+
 	while (extras->type != PCUT_EXTRA_LAST) {
 		if (extras->type == PCUT_EXTRA_TIMEOUT) {
Index: uspace/lib/pcut/tests/abort.c
===================================================================
--- uspace/lib/pcut/tests/abort.c	(revision 9b201262edcb92c27cf4a25a8379320113426ab7)
+++ uspace/lib/pcut/tests/abort.c	(revision 9b201262edcb92c27cf4a25a8379320113426ab7)
@@ -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 9b201262edcb92c27cf4a25a8379320113426ab7)
+++ uspace/lib/pcut/tests/abort.expected	(revision 9b201262edcb92c27cf4a25a8379320113426ab7)
@@ -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/alloc.c
===================================================================
--- uspace/lib/pcut/tests/alloc.c	(revision 15d0046f9b3c481dc13462cd9c94e9f757fa743d)
+++ 	(revision )
@@ -1,62 +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.
- */
-
-#include <pcut/pcut.h>
-#include <stdlib.h>
-#include <stdio.h>
-
-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(snprintf) {
-	snprintf(buffer, BUFFER_SIZE - 1, "%d-%s", 56, "abcd");
-	PCUT_ASSERT_STR_EQUALS("56-abcd", buffer);
-}
-
-PCUT_TEST_SUITE(another_without_setup)
-
-PCUT_TEST(whatever) {
-	PCUT_ASSERT_NULL(buffer);
-}
-
-
-PCUT_MAIN()
Index: uspace/lib/pcut/tests/alloc.expected
===================================================================
--- uspace/lib/pcut/tests/alloc.expected	(revision 15d0046f9b3c481dc13462cd9c94e9f757fa743d)
+++ 	(revision )
@@ -1,7 +1,0 @@
-1..2
-#> Starting suite suite_with_setup_and_teardown.
-ok 1 snprintf
-#> Finished suite suite_with_setup_and_teardown (failed 0 of 1).
-#> Starting suite another_without_setup.
-ok 2 whatever
-#> Finished suite another_without_setup (failed 0 of 1).
Index: uspace/lib/pcut/tests/beforeafter.c
===================================================================
--- uspace/lib/pcut/tests/beforeafter.c	(revision 9b201262edcb92c27cf4a25a8379320113426ab7)
+++ uspace/lib/pcut/tests/beforeafter.c	(revision 9b201262edcb92c27cf4a25a8379320113426ab7)
@@ -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 9b201262edcb92c27cf4a25a8379320113426ab7)
+++ uspace/lib/pcut/tests/beforeafter.expected	(revision 9b201262edcb92c27cf4a25a8379320113426ab7)
@@ -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.expected
===================================================================
--- uspace/lib/pcut/tests/errno.expected	(revision 15d0046f9b3c481dc13462cd9c94e9f757fa743d)
+++ uspace/lib/pcut/tests/errno.expected	(revision 9b201262edcb92c27cf4a25a8379320113426ab7)
@@ -2,6 +2,6 @@
 #> 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)
+# 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, Success) but got error 2 (No such file or directory)
+# 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 9b201262edcb92c27cf4a25a8379320113426ab7)
+++ uspace/lib/pcut/tests/inithook.c	(revision 9b201262edcb92c27cf4a25a8379320113426ab7)
@@ -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 9b201262edcb92c27cf4a25a8379320113426ab7)
+++ uspace/lib/pcut/tests/inithook.expected	(revision 9b201262edcb92c27cf4a25a8379320113426ab7)
@@ -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/null.c
===================================================================
--- uspace/lib/pcut/tests/null.c	(revision 15d0046f9b3c481dc13462cd9c94e9f757fa743d)
+++ 	(revision )
@@ -1,42 +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.
- */
-
-#include <pcut/pcut.h>
-#include "tested.h"
-
-PCUT_INIT
-
-PCUT_TEST(access_null_pointer) {
-	int a = 5;
-	int *p = &a;
-	PCUT_ASSERT_INT_EQUALS(5, *p);
-	p = NULL;
-	PCUT_ASSERT_INT_EQUALS(5, *p);
-}
-
-PCUT_MAIN()
Index: uspace/lib/pcut/tests/null.expected
===================================================================
--- uspace/lib/pcut/tests/null.expected	(revision 15d0046f9b3c481dc13462cd9c94e9f757fa743d)
+++ 	(revision )
@@ -1,4 +1,0 @@
-1..1
-#> Starting suite Default.
-not ok 1 access_null_pointer aborted
-#> Finished suite Default (failed 1 of 1).
Index: uspace/lib/pcut/tests/nullteardown.c
===================================================================
--- uspace/lib/pcut/tests/nullteardown.c	(revision 15d0046f9b3c481dc13462cd9c94e9f757fa743d)
+++ 	(revision )
@@ -1,48 +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.
- */
-
-#include <stdio.h>
-#include <pcut/pcut.h>
-#include "tested.h"
-
-PCUT_INIT
-
-PCUT_TEST_AFTER {
-	int a = 5;
-	int *p = &a;
-	PCUT_ASSERT_INT_EQUALS(5, *p);
-	p = NULL;
-	PCUT_ASSERT_INT_EQUALS(5, *p);
-}
-
-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/nullteardown.expected
===================================================================
--- uspace/lib/pcut/tests/nullteardown.expected	(revision 15d0046f9b3c481dc13462cd9c94e9f757fa743d)
+++ 	(revision )
@@ -1,6 +1,0 @@
-1..1
-#> Starting suite Default.
-not ok 1 print_and_fail aborted
-# error: nullteardown.c:45: 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/preinithook.c
===================================================================
--- uspace/lib/pcut/tests/preinithook.c	(revision 9b201262edcb92c27cf4a25a8379320113426ab7)
+++ uspace/lib/pcut/tests/preinithook.c	(revision 9b201262edcb92c27cf4a25a8379320113426ab7)
@@ -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 9b201262edcb92c27cf4a25a8379320113426ab7)
+++ uspace/lib/pcut/tests/preinithook.expected	(revision 9b201262edcb92c27cf4a25a8379320113426ab7)
@@ -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/teardown.c
===================================================================
--- uspace/lib/pcut/tests/teardown.c	(revision 15d0046f9b3c481dc13462cd9c94e9f757fa743d)
+++ uspace/lib/pcut/tests/teardown.c	(revision 9b201262edcb92c27cf4a25a8379320113426ab7)
@@ -50,5 +50,5 @@
 
 
-PCUT_TEST_SUITE(with_failing_teardown)
+PCUT_TEST_SUITE(with_failing_teardown);
 
 PCUT_TEST_AFTER {
Index: uspace/lib/pcut/tests/teardownaborts.c
===================================================================
--- uspace/lib/pcut/tests/teardownaborts.c	(revision 9b201262edcb92c27cf4a25a8379320113426ab7)
+++ uspace/lib/pcut/tests/teardownaborts.c	(revision 9b201262edcb92c27cf4a25a8379320113426ab7)
@@ -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 9b201262edcb92c27cf4a25a8379320113426ab7)
+++ uspace/lib/pcut/tests/teardownaborts.expected	(revision 9b201262edcb92c27cf4a25a8379320113426ab7)
@@ -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/testlist.c
===================================================================
--- uspace/lib/pcut/tests/testlist.c	(revision 9b201262edcb92c27cf4a25a8379320113426ab7)
+++ uspace/lib/pcut/tests/testlist.c	(revision 9b201262edcb92c27cf4a25a8379320113426ab7)
@@ -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 9b201262edcb92c27cf4a25a8379320113426ab7)
+++ uspace/lib/pcut/tests/testlist.expected	(revision 9b201262edcb92c27cf4a25a8379320113426ab7)
@@ -0,0 +1,2 @@
+*****Suite `Default' [1]
+*****Test `unreachable' [2]
Index: uspace/lib/pcut/tests/timeout.c
===================================================================
--- uspace/lib/pcut/tests/timeout.c	(revision 15d0046f9b3c481dc13462cd9c94e9f757fa743d)
+++ uspace/lib/pcut/tests/timeout.c	(revision 9b201262edcb92c27cf4a25a8379320113426ab7)
@@ -28,7 +28,23 @@
 
 #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
@@ -36,5 +52,5 @@
 PCUT_TEST(shall_time_out) {
 	printf("Text before sleeping.\n");
-	sleep(PCUT_DEFAULT_TEST_TIMEOUT * 5);
+	my_sleep(PCUT_DEFAULT_TEST_TIMEOUT * 5);
 	printf("Text after the sleep.\n");
 }
@@ -43,5 +59,5 @@
 		PCUT_TEST_SET_TIMEOUT(PCUT_DEFAULT_TEST_TIMEOUT * 3)) {
 	printf("Text before sleeping.\n");
-	sleep(PCUT_DEFAULT_TEST_TIMEOUT * 2);
+	my_sleep(PCUT_DEFAULT_TEST_TIMEOUT * 2);
 	printf("Text after the sleep.\n");
 }
Index: uspace/lib/pcut/tests/xmlreport.c
===================================================================
--- uspace/lib/pcut/tests/xmlreport.c	(revision 9b201262edcb92c27cf4a25a8379320113426ab7)
+++ uspace/lib/pcut/tests/xmlreport.c	(revision 9b201262edcb92c27cf4a25a8379320113426ab7)
@@ -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 9b201262edcb92c27cf4a25a8379320113426ab7)
+++ uspace/lib/pcut/tests/xmlreport.expected	(revision 9b201262edcb92c27cf4a25a8379320113426ab7)
@@ -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 15d0046f9b3c481dc13462cd9c94e9f757fa743d)
+++ uspace/lib/pcut/update-from-master.sh	(revision 9b201262edcb92c27cf4a25a8379320113426ab7)
@@ -51,5 +51,5 @@
 $RUN rm -f CMakeLists.txt *.cmake run_test.sh
 
-cat >Makefile <<'EOF_MAKEFILE'
+cat >Makefile <<'EOF_MAKEFILE_HEAD'
 #
 # This file was generated by call to update-from-master.sh
@@ -57,4 +57,15 @@
 
 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
@@ -62,3 +73,8 @@
 include $(USPACE_PREFIX)/Makefile.common
 
-EOF_MAKEFILE
+include helenos.test.mak
+
+test-libpcut-%: $(OUTPUT)
+	$(LD) -n $(LFLAGS) -T $(LINKER_SCRIPT) -o $@ $^ $(OUTPUT) $(BASE_LIBS)
+
+EOF_MAKEFILE_TAIL
