See patch.

Uwe.
-- 
http://www.hermann-uwe.de  | http://www.holsham-traders.de
http://www.crazy-hacks.org | http://www.unmaintained-free-software.org
Initial unit testing framework for LinuxBIOS using Check
(http://check.sourceforge.net/).

To run the testsuite simply type 'make check' in the top-level LinuxBIOS
directory or in util/testsuite/unittests.

You need to have Check installed on your system for this to work.
On Debian systems this is done via 'apt-get install check', otherwise
you can compile the package from source.

You can check the current code coverage with tools such as ggcov.

Signed-off-by: Uwe Hermann <[EMAIL PROTECTED]>

Index: util/testsuite/unittests/check.h
===================================================================
--- util/testsuite/unittests/check.h	(Revision 0)
+++ util/testsuite/unittests/check.h	(Revision 0)
@@ -0,0 +1,375 @@
+/*
+ * This file is part of the LinuxBIOS project.
+ *
+ * It was taken from the Check project (src/check.h) and slightly modified
+ * for LinuxBIOS so that it doesn't need external headers anymore.
+ *
+ * Modifications are:
+ * Copyright (C) 2007 Uwe Hermann <[EMAIL PROTECTED]>
+ */
+
+/*-*- mode:C; -*- */
+/*
+ * Check: a unit test framework for C
+ * Copyright (C) 2001, 2002, Arien Malec
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef CHECK_H
+#define CHECK_H
+
+// #include <stddef.h>
+typedef int pid_t;
+
+/* Check: a unit test framework for C
+
+   Check is a unit test framework for C. It features a simple
+   interface for defining unit tests, putting little in the way of the
+   developer. Tests are run in a separate address space, so Check can
+   catch both assertion failures and code errors that cause
+   segmentation faults or other signals. The output from unit tests
+   can be used within source code editors and IDEs.
+
+   Unit tests are created with the START_TEST/END_TEST macro
+   pair. The fail_unless and fail macros are used for creating
+   checks within unit tests; the mark_point macro is useful for
+   trapping the location of signals and/or early exits.
+
+
+   Test cases are created with tcase_create, unit tests are added
+   with tcase_add_test
+
+
+   Suites are created with suite_create; test cases are added
+   with suite_add_tcase
+
+   Suites are run through an SRunner, which is created with
+   srunner_create. Additional suites can be added to an SRunner with
+   srunner_add_suite. An SRunner is freed with srunner_free, which also
+   frees all suites added to the runner. 
+
+   Use srunner_run_all to run a suite and print results.
+
+*/
+
+
+#ifdef __cplusplus
+#define CK_CPPSTART extern "C" {
+CK_CPPSTART
+#endif
+
+// #include <sys/types.h>
+
+/* check version numbers */
+
+#define CHECK_MAJOR_VERSION (0)
+#define CHECK_MINOR_VERSION (9)
+#define CHECK_MICRO_VERSION (5)
+
+extern int check_major_version;
+extern int check_minor_version;
+extern int check_micro_version;
+
+#ifndef NULL
+#define NULL ((void*)0)
+#endif
+
+/* opaque type for a test case
+
+   A TCase represents a test case.  Create with tcase_create, free
+   with tcase_free.  For the moment, test cases can only be run
+   through a suite
+*/
+typedef struct TCase TCase; 
+
+/* type for a test function */
+typedef void (*TFun) (int);
+
+/* type for a setup/teardown function */
+typedef void (*SFun) (void);
+ 
+/* Opaque type for a test suite */
+typedef struct Suite Suite;
+ 
+/* Creates a test suite with the given name */
+Suite *suite_create (const char *name);
+
+/* Add a test case to a suite */
+void suite_add_tcase (Suite *s, TCase *tc);
+
+/* Create a test case */
+TCase *tcase_create (const char *name);
+
+/* Add a test function to a test case (macro version) */
+#define tcase_add_test(tc,tf) tcase_add_test_raise_signal(tc,tf,0)
+
+/* Add a test function with signal handling to a test case (macro version) */
+#define tcase_add_test_raise_signal(tc,tf,signal) \
+   _tcase_add_test((tc),(tf),"" # tf "",(signal), 0, 1)
+
+/* Add a looping test function to a test case (macro version)
+
+   The test will be called in a for(i = s; i < e; i++) loop with each
+   iteration being executed in a new context. The loop variable 'i' is
+   available in the test.
+ */
+#define tcase_add_loop_test(tc,tf,s,e) \
+   _tcase_add_test((tc),(tf),"" # tf "",0,(s),(e))
+ 
+/* Signal version of loop test.  
+   FIXME: add a test case; this is untested as part of Check's tests.
+ */
+#define tcase_add_loop_test_raise_signal(tc,tf,signal,s,e) \
+   _tcase_add_test((tc),(tf),"" # tf "",(signal),(s),(e))
+
+/* Add a test function to a test case
+  (function version -- use this when the macro won't work
+*/
+void _tcase_add_test (TCase *tc, TFun tf, const char *fname, int signal, int start, int end);
+
+/* Add unchecked fixture setup/teardown functions to a test case
+
+   If unchecked fixture functions are run at the start and end of the
+   test case, and not before and after unit tests. Note that unchecked
+   setup/teardown functions are not run in a separate address space,
+   like test functions, and so must not exit or signal (e.g.,
+   segfault)
+
+   Also, when run in CK_NOFORK mode, unchecked fixture functions may
+   lead to different unit test behavior IF unit tests change data
+   setup by the fixture functions.
+*/
+void tcase_add_unchecked_fixture (TCase *tc, SFun setup, SFun teardown);
+
+/* Add fixture setup/teardown functions to a test case
+
+   Checked fixture functions are run before and after unit
+   tests. Unlike unchecked fixture functions, checked fixture
+   functions are run in the same separate address space as the test
+   program, and thus the test function will survive signals or
+   unexpected exits in the fixture function. Also, IF the setup
+   function is idempotent, unit test behavior will be the same in
+   CK_FORK and CK_NOFORK modes.
+
+   However, since fixture functions are run before and after each unit
+   test, they should not be expensive code.
+
+*/ 
+void tcase_add_checked_fixture (TCase *tc, SFun setup, SFun teardown);
+
+/* Set the timeout for all tests in a test case. A test that lasts longer
+   than the timeout (in seconds) will be killed and thus fail with an error.
+   The timeout can also be set globaly with the environment variable
+   CK_DEFAULT_TIMEOUT, the specific setting always takes precedence.
+*/
+void tcase_set_timeout (TCase *tc, int timeout);
+ 
+/* Internal function to mark the start of a test function */
+void tcase_fn_start (const char *fname, const char *file, int line);
+
+/* Start a unit test with START_TEST(unit_name), end with END_TEST
+   One must use braces within a START_/END_ pair to declare new variables
+*/ 
+#define START_TEST(__testname)\
+static void __testname (int _i __attribute__((unused)))\
+{\
+  tcase_fn_start (""# __testname, __FILE__, __LINE__);
+
+/* End a unit test */
+#define END_TEST }
+
+/* Fail the test case unless expr is true */
+/* The space before the comma sign before ## is essential to be compatible
+   with gcc 2.95.3 and earlier.
+*/
+#define fail_unless(expr, ...)\
+        _fail_unless(expr, __FILE__, __LINE__,\
+        "Assertion '"#expr"' failed" , ## __VA_ARGS__, NULL)
+
+/* Fail the test case if expr is true */
+/* The space before the comma sign before ## is essential to be compatible
+   with gcc 2.95.3 and earlier.
+*/
+
+/* FIXME: these macros may conflict with C89 if expr is 
+   FIXME:   strcmp (str1, str2) due to excessive string length. */
+#define fail_if(expr, ...)\
+        _fail_unless(!(expr), __FILE__, __LINE__,\
+        "Failure '"#expr"' occured" , ## __VA_ARGS__, NULL)
+
+/* Always fail */
+#define fail(...) _fail_unless(0, __FILE__, __LINE__, "Failed" , ## __VA_ARGS__, NULL)
+
+/* Non macro version of #fail_unless, with more complicated interface */
+void _fail_unless (int result, const char *file,
+                   int line, const char *expr, ...);
+
+/* Mark the last point reached in a unit test
+   (useful for tracking down where a segfault, etc. occurs)
+*/
+#define mark_point() _mark_point(__FILE__,__LINE__)
+
+/* Non macro version of #mark_point */
+void _mark_point (const char *file, int line);
+
+/* Result of a test */
+enum test_result {
+  CK_PASS, /* Test passed*/
+  CK_FAILURE, /* Test completed but failed */
+  CK_ERROR /* Test failed to complete
+	      (unexpected signal or non-zero early exit) */ 
+};
+
+/* Specifies the how much output an SRunner should produce */
+enum print_output {
+  CK_SILENT, /* No output */
+  CK_MINIMAL, /* Only summary output */
+  CK_NORMAL, /* All failed tests */
+  CK_VERBOSE, /* All tests */
+  CK_ENV, /* Look at environment var */
+  CK_LAST
+};
+
+/* Holds state for a running of a test suite */
+typedef struct SRunner SRunner;
+
+/* Opaque type for a test failure */
+typedef struct TestResult TestResult;
+
+/* accessors for tr fields */
+ enum ck_result_ctx {
+  CK_CTX_SETUP,
+  CK_CTX_TEST,
+  CK_CTX_TEARDOWN
+};
+
+/* Type of result */
+int tr_rtype (TestResult *tr);
+/* Context in which the result occurred */ 
+enum ck_result_ctx tr_ctx (TestResult *tr); 
+/* Failure message */
+const char *tr_msg (TestResult *tr);
+/* Line number at which failure occured */
+int tr_lno (TestResult *tr);
+/* File name at which failure occured */
+const char *tr_lfile (TestResult *tr);
+/* Test case in which unit test was run */
+const char *tr_tcname (TestResult *tr);
+
+/* Creates an SRunner for the given suite */
+SRunner *srunner_create (Suite *s);
+
+/* Adds a Suite to an SRunner */
+void srunner_add_suite (SRunner *sr, Suite *s);
+
+/* Frees an SRunner, all suites added to it and all contained test cases */
+void srunner_free (SRunner *sr);
+
+ 
+/* Test running */
+
+/* Runs an SRunner, printing results as specified (see enum print_output) */
+void srunner_run_all (SRunner *sr, enum print_output print_mode);
+
+ 
+/* Next functions are valid only after the suite has been
+   completely run, of course */
+
+/* Number of failed tests in a run suite. Includes failures + errors */
+int srunner_ntests_failed (SRunner *sr);
+
+/* Total number of tests run in a run suite */
+int srunner_ntests_run (SRunner *sr);
+
+/* Return an array of results for all failures
+  
+   Number of failures is equal to srunner_nfailed_tests.  Memory for
+   the array is malloc'ed and must be freed, but individual TestResults
+   must not
+*/
+TestResult **srunner_failures (SRunner *sr);
+
+/* Return an array of results for all run tests
+
+   Number of results is equal to srunner_ntests_run, and excludes
+   failures due to setup function failure.
+
+   Memory is malloc'ed and must be freed, but individual TestResults
+   must not
+*/  
+TestResult **srunner_results (SRunner *sr);
+
+ 
+/* Printing */
+
+/* Print the results contained in an SRunner */
+void srunner_print (SRunner *sr, enum print_output print_mode);
+  
+  
+/* Set a log file to which to write during test running.
+
+  Log file setting is an initialize only operation -- it should be
+  done immediatly after SRunner creation, and the log file can't be
+  changed after being set.
+*/
+void srunner_set_log (SRunner *sr, const char *fname);
+
+/* Does the SRunner have a log file? */
+int srunner_has_log (SRunner *sr);
+
+/* Return the name of the log file, or NULL if none */
+const char *srunner_log_fname (SRunner *sr);
+
+/* Set a xml file to which to write during test running.
+
+  XML file setting is an initialize only operation -- it should be
+  done immediatly after SRunner creation, and the XML file can't be
+  changed after being set.
+*/
+void srunner_set_xml (SRunner *sr, const char *fname);
+
+/* Does the SRunner have an XML log file? */
+int srunner_has_xml (SRunner *sr);
+
+/* Return the name of the XML file, or NULL if none */
+const char *srunner_xml_fname (SRunner *sr);
+
+
+/* Control forking */
+enum fork_status {
+  CK_FORK,
+  CK_NOFORK
+};
+ 
+/* Get the current fork status */
+enum fork_status srunner_fork_status (SRunner *sr);
+
+/* Set the current fork status */
+void srunner_set_fork_status (SRunner *sr, enum fork_status fstat); 
+  
+/* Fork in a test and make sure messaging and tests work. */
+pid_t check_fork(void);
+
+/* Wait for the pid and exit. If pid is zero, just exit. */
+void check_waitpid_and_exit(pid_t pid);
+
+#ifdef __cplusplus 
+#define CK_CPPEND }
+CK_CPPEND
+#endif
+
+#endif /* CHECK_H */
Index: util/testsuite/unittests/check_clog2.c
===================================================================
--- util/testsuite/unittests/check_clog2.c	(Revision 0)
+++ util/testsuite/unittests/check_clog2.c	(Revision 0)
@@ -0,0 +1,41 @@
+/*
+ * This file is part of the LinuxBIOS project.
+ *
+ * Copyright (C) 2007 Uwe Hermann <[EMAIL PROTECTED]>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+
+#include <lib.h>
+#include "check.h"
+
+START_TEST(test_log2)
+{
+	fail_unless(log2(0) == 0, NULL);
+	fail_unless(log2(1) == 0, NULL);
+	fail_unless(log2(4) == 2, NULL);
+	fail_unless(log2(8) == 3, NULL);
+	fail_unless(log2(1024) == 10, NULL);
+	fail_unless(log2(1024 * 1024) == 20, NULL);
+}
+END_TEST
+
+TCase *test_clog2_create_tests(void)
+{
+	TCase *tc;
+	tc = tcase_create("clog2");
+	tcase_add_test(tc, test_log2);
+	return tc;
+}
Index: util/testsuite/unittests/check_string.c
===================================================================
--- util/testsuite/unittests/check_string.c	(Revision 0)
+++ util/testsuite/unittests/check_string.c	(Revision 0)
@@ -0,0 +1,74 @@
+/*
+ * This file is part of the LinuxBIOS project.
+ *
+ * Copyright (C) 2007 Uwe Hermann <[EMAIL PROTECTED]>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+
+#include <string.h>
+#include "check.h"
+
+START_TEST(test_strlen)
+{
+	fail_unless(strlen("Hello") == 5, NULL);
+	fail_unless(strlen("Hello\nWorld!") == 12, NULL);
+	fail_unless(strlen("") == 0, NULL);
+	fail_unless(strlen("\n") == 1, NULL);
+	fail_unless(strlen("\r") == 1, NULL);
+	fail_unless(strlen("\r\n") == 2, NULL);
+	fail_unless(strlen("\0") == 0, NULL);
+}
+END_TEST
+
+START_TEST(test_strnlen)
+{
+	fail_unless(strnlen("Hello", 10) == 5, NULL);
+	fail_unless(strnlen("Hello", 5) == 5, NULL);
+	fail_unless(strnlen("Hello", 3) == 3, NULL);
+	fail_unless(strnlen("Hello", 0) == 0, NULL);
+	fail_unless(strnlen("Hello\nWorld!", 7) == 7, NULL);
+	fail_unless(strnlen("", 10) == 0, NULL);
+	fail_unless(strnlen("\n", 10) == 1, NULL);
+	fail_unless(strnlen("\r", 10) == 1, NULL);
+	fail_unless(strnlen("\r\n", 10) == 2, NULL);
+	fail_unless(strnlen("\0", 0) == 0, NULL);
+	fail_unless(strnlen("\0", 10) == 0, NULL);
+}
+END_TEST
+
+START_TEST(test_strcmp)
+{
+	fail_unless(strcmp("Hello", "Hello") == 0, NULL);
+	fail_unless(strcmp("123", "124") < 0, NULL);
+	fail_unless(strcmp("124", "123") > 0, NULL);
+	fail_unless(strcmp("abcd", "abc") > 0, NULL);
+	fail_unless(strcmp("abc", "abcd") < 0, NULL);
+	fail_unless(strcmp("", "") == 0, NULL);
+	fail_unless(strcmp("\0", "") == 0, NULL);
+	fail_unless(strcmp("", "\0") == 0, NULL);
+	fail_unless(strcmp("\0", "\0") == 0, NULL);
+}
+END_TEST
+
+TCase *test_string_create_tests(void)
+{
+	TCase *tc;
+	tc = tcase_create("string");
+	tcase_add_test(tc, test_strlen);
+	tcase_add_test(tc, test_strnlen);
+	tcase_add_test(tc, test_strcmp);
+	return tc;
+}
Index: util/testsuite/unittests/runtests.c
===================================================================
--- util/testsuite/unittests/runtests.c	(Revision 0)
+++ util/testsuite/unittests/runtests.c	(Revision 0)
@@ -0,0 +1,50 @@
+/*
+ * This file is part of the LinuxBIOS project.
+ *
+ * Copyright (C) 2007 Uwe Hermann <[EMAIL PROTECTED]>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+
+#include "runtests.h"
+#include "check.h"
+
+int main(void)
+{
+	SRunner *runner;
+	Suite *lbsuite;
+	TCase *tc;
+	int failed;
+
+	lbsuite = suite_create("LinuxBIOS");
+
+	tc = test_clog2_create_tests();
+	suite_add_tcase(lbsuite, tc);
+
+	tc = test_string_create_tests();
+	suite_add_tcase(lbsuite, tc);
+
+	tc = test_device_util_create_tests();
+	suite_add_tcase(lbsuite, tc);
+
+	runner = srunner_create(lbsuite);
+	srunner_run_all(runner, CK_VERBOSE);
+	failed = srunner_ntests_failed(runner);
+
+	srunner_free(runner);
+
+	/* Return 0 upon success, -1 if some test cases failed. */
+	return (failed == 0) ? 0 : -1;
+}
Index: util/testsuite/unittests/check_device_util.c
===================================================================
--- util/testsuite/unittests/check_device_util.c	(Revision 0)
+++ util/testsuite/unittests/check_device_util.c	(Revision 0)
@@ -0,0 +1,148 @@
+/*
+ * This file is part of the LinuxBIOS project.
+ *
+ * Copyright (C) 2007 Uwe Hermann <[EMAIL PROTECTED]>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+
+#include <device/device.h>
+#include <string.h> // FIXME! The unit tests rely on _our_ strcmp() to work!
+#include "check.h"
+
+/* Stubs */
+// TODO: Better stubs?
+struct device dev_root;
+struct device *all_devices = &dev_root;
+struct constructor *all_constructors[] = { NULL };
+struct device *alloc_dev(struct bus *parent, struct device_path *path,
+			 struct device_id *devid) { return NULL; }
+void printk(int msg_level, const char *fmt, ...) {}
+void die(void) {}
+void post_code(void) {}
+
+/* Function prototypes */
+extern resource_t align_up(resource_t val, unsigned long gran);
+extern resource_t align_down(resource_t val, unsigned long gran);
+
+START_TEST(test_id_eq_pci)
+{
+	struct device_id id1 = {.type = DEVICE_ID_PCI,
+		.u = {.pci = {.vendor = 0x2000,.device = 0x4000}}};
+	struct device_id id2 = {.type = DEVICE_ID_PCI,
+		.u = {.pci = {.vendor = 0x2000,.device = 0x4000}}};
+	struct device_id id3 = {.type = DEVICE_ID_PCI,
+		.u = {.pci = {.vendor = 0x9999,.device = 0x4000}}};
+	struct device_id id4 = {.type = DEVICE_ID_PCI,
+		.u = {.pci = {.vendor = 0x2000,.device = 0x9999}}};
+	struct device_id id_i2c = {.type = DEVICE_ID_I2C,
+		.u = {.pci = {.vendor = 0x2000,.device = 0x4000}}};
+		/* This id_i2c is deliberately a "broken" PCI device! */
+	struct device_id id_zero = {.type = DEVICE_ID_PCI,
+		.u = {.pci = {.vendor = 0x0000,.device = 0x0000}}};
+	struct device_id id_ffff = {.type = DEVICE_ID_PCI,
+		.u = {.pci = {.vendor = 0xffff,.device = 0xffff}}};
+	struct device_id id_root = {.type = DEVICE_ID_ROOT};
+
+	fail_unless(id_eq(&id_root, &id1) == 0, NULL);
+	fail_unless(id_eq(&id1, &id_root) == 0, NULL);
+	fail_unless(id_eq(&id1, &id2) == 1, NULL);
+	fail_unless(id_eq(&id1, &id3) == 0, NULL);
+	fail_unless(id_eq(&id1, &id4) == 0, NULL);
+	fail_unless(id_eq(&id_zero, &id1) == 0, NULL);
+	fail_unless(id_eq(&id1, &id_zero) == 0, NULL);
+	fail_unless(id_eq(&id_zero, &id_zero) == 1, NULL);
+	fail_unless(id_eq(&id_ffff, &id1) == 0, NULL);
+	fail_unless(id_eq(&id1, &id_ffff) == 0, NULL);
+	fail_unless(id_eq(&id_ffff, &id_ffff) == 1, NULL);
+	// fail_unless(id_eq(NULL, NULL) == 1, NULL);	// FIXME: Bug?
+
+	/* Comparing a PCI ID to an I2C ID should fail. */
+	fail_unless(id_eq(&id1, &id_i2c) == 0, NULL);
+	fail_unless(id_eq(&id_i2c, &id1) == 0, NULL);
+	fail_unless(id_eq(&id_zero, &id_i2c) == 0, NULL);
+	fail_unless(id_eq(&id_i2c, &id_zero) == 0, NULL);
+	fail_unless(id_eq(&id_ffff, &id_i2c) == 0, NULL);
+	fail_unless(id_eq(&id_i2c, &id_ffff) == 0, NULL);
+}
+END_TEST
+
+START_TEST(test_dev_path)
+{
+	struct device dev_root = {.path = {.type = DEVICE_PATH_ROOT}};
+	struct device dev_pnp = {.path = {.type = DEVICE_PATH_PNP,
+		.u = {.pnp = {.port = 0x1111, .device = 0x2222}}}};
+
+	fail_unless(strcmp(dev_path(NULL), "<null>") == 0, NULL);
+	fail_unless(strcmp(dev_path(&dev_root), "Root Device") == 0, NULL);
+	fail_unless(strcmp(dev_path(&dev_pnp), "PNP: 1111.2222") == 0, NULL);
+	// ...
+}
+END_TEST
+
+START_TEST(test_align_up)
+{
+	fail_unless(align_up(0, 0) == 0, NULL);
+	fail_unless(align_up(0, 1) == 0, NULL);
+	fail_unless(align_up(0, 2) == 0, NULL);
+	fail_unless(align_up(0, 19) == 0, NULL);
+
+	fail_unless(align_up(1, 0) == 1, NULL);
+	fail_unless(align_up(1, 1) == 2, NULL);
+	fail_unless(align_up(1, 2) == 4, NULL);
+	fail_unless(align_up(1, 3) == 8, NULL);
+
+	fail_unless(align_up(2, 0) == 2, NULL); // ...
+	fail_unless(align_up(2, 1) == 2, NULL);
+	fail_unless(align_up(2, 2) == 4, NULL);
+	fail_unless(align_up(2, 3) == 8, NULL);
+
+	fail_unless(align_up(0, 5) == 0, NULL);
+	fail_unless(align_up(1, 5) == 32, NULL);
+	fail_unless(align_up(2, 5) == 32, NULL);
+	fail_unless(align_up(3, 5) == 32, NULL);
+	fail_unless(align_up(18, 5) == 32, NULL);
+	fail_unless(align_up(31, 5) == 32, NULL);
+	fail_unless(align_up(32, 5) == 32, NULL);
+	fail_unless(align_up(33, 5) == 64, NULL);
+	// ...
+}
+END_TEST
+
+START_TEST(test_align_down)
+{
+	fail_unless(align_down(0, 5) == 0, NULL);
+
+	fail_unless(align_down(31, 5) == 0, NULL);
+	fail_unless(align_down(32, 5) == 32, NULL);
+	fail_unless(align_down(33, 5) == 32, NULL);
+	fail_unless(align_down(63, 5) == 32, NULL);
+	fail_unless(align_down(64, 5) == 64, NULL);
+	fail_unless(align_down(65, 5) == 64, NULL);
+	fail_unless(align_down(99, 5) == 96, NULL);
+	// ...
+}
+END_TEST
+
+TCase *test_device_util_create_tests(void)
+{
+	TCase *tc;
+	tc = tcase_create("device_util");
+	tcase_add_test(tc, test_id_eq_pci);
+	tcase_add_test(tc, test_dev_path);
+	tcase_add_test(tc, test_align_up);
+	tcase_add_test(tc, test_align_down);
+	return tc;
+}
Index: util/testsuite/unittests/Makefile
===================================================================
--- util/testsuite/unittests/Makefile	(Revision 0)
+++ util/testsuite/unittests/Makefile	(Revision 0)
@@ -0,0 +1,83 @@
+##
+## This file is part of the LinuxBIOS project.
+##
+## Copyright (C) 2007 Uwe Hermann <[EMAIL PROTECTED]>
+##
+## This program is free software; you can redistribute it and/or modify
+## it under the terms of the GNU General Public License as published by
+## the Free Software Foundation; either version 2 of the License, or
+## (at your option) any later version.
+##
+## This program is distributed in the hope that it will be useful,
+## but WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+## GNU General Public License for more details.
+##
+## You should have received a copy of the GNU General Public License
+## along with this program; if not, write to the Free Software
+## Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+##
+
+src := $(shell pwd)/../../..
+obj := $(shell pwd)/../../../build
+export src obj
+
+# If $(Q) is not set (e.g. because make was invoked in
+# util/testsuite/unittests and not at the top-level), we default to
+# silent mode.
+ifeq ($(Q),)
+V := 0;
+endif
+
+# Make is silent per default, but 'make V=1' will show all compiler calls.
+ifneq ($(V),1)
+Q := @
+endif
+
+# FIXME?
+ARCH       := x86
+
+HOSTCC     := gcc
+
+HOSTCFLAGS := -Wall -g -std=c99 -Wundef -Wstrict-prototypes -Wno-trigraphs \
+	      -fomit-frame-pointer -Werror-implicit-function-declaration \
+	      -Wno-unused -Wno-sign-compare -fno-builtin \
+	      -Wstrict-aliasing -fno-common -ffreestanding -pedantic \
+	      -I$(src) -Iinclude -I$(src)/include -nostdinc \
+	      -I$(src)/include/arch/$(ARCH) \
+	      -fprofile-arcs -ftest-coverage \
+	      -DLINUXBIOS_UNITTEST
+
+# TODO: Check if gcov is available, and only use it if that's the case.
+LDFLAGS    := -L/usr/local/lib -lcheck -lgcov
+
+OBJS       := check_clog2.o clog2.o \
+	      check_string.o \
+	      check_device_util.o device_util.o \
+	      runtests.o
+
+SRCOBJS    := $(src)/lib/clog2.o \
+	      $(src)/device/device_util.o
+
+all: runtests
+
+check: runtests
+	$(Q)./runtests
+
+runtests: $(SRCOBJS) $(OBJS)
+	$(Q)printf "  LD      runtests\n"
+	$(Q)$(HOSTCC) $(HOSTCFLAGS) -o $@ $(OBJS) $(LDFLAGS)
+
+.c.o:
+	$(Q)printf "  HOSTCC  $(subst $(shell pwd)/,,$(@))\n"
+	$(Q)$(HOSTCC) $(HOSTCFLAGS) -c $<
+
+clean:
+	$(Q)printf "  CLEAN   $(subst $(realpath $(src))/,,$(realpath $(shell pwd)))\n"
+	$(Q)rm -f core $(OBJS) *.gcda *.gcno
+
+distclean: clean
+	$(Q)rm -f runtests
+
+.PHONY: clean distclean
+
Index: util/testsuite/unittests/runtests.h
===================================================================
--- util/testsuite/unittests/runtests.h	(Revision 0)
+++ util/testsuite/unittests/runtests.h	(Revision 0)
@@ -0,0 +1,30 @@
+/*
+ * This file is part of the LinuxBIOS project.
+ *
+ * Copyright (C) 2007 Uwe Hermann <[EMAIL PROTECTED]>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+
+#ifndef RUNTESTS_H
+#define RUNTESTS_H
+
+#include "check.h"
+
+TCase *test_clog2_create_tests(void);
+TCase *test_string_create_tests(void);
+TCase *test_device_util_create_tests(void);
+
+#endif
Index: util/testsuite/unittests/README
===================================================================
--- util/testsuite/unittests/README	(Revision 0)
+++ util/testsuite/unittests/README	(Revision 0)
@@ -0,0 +1,50 @@
+-------------------------------------------------------------------------------
+README
+-------------------------------------------------------------------------------
+
+This is a testsuite of unit tests for the LinuxBIOSv3 code.
+
+
+Requirements
+------------
+
+ - Check, a unit testing framework for C, needs to be installed.
+   You can download it from http://check.sourceforge.net/.
+   On Debian systems 'apt-get install check' is sufficient.
+
+
+Running all tests
+-----------------
+
+In the LinuxBIOS top-level directory type:
+
+  $ make check
+
+This will run the complete testsuite of unit tests. If all tests passed, the
+result will look like this:
+
+  100%: Checks: 8, Failures: 0, Errors: 0
+
+Alternatively, you can also run the testsuite from util/testsuite/unittests
+directly by typing:
+
+  $ cd util/testsuite/unittests
+  $ make check
+
+
+Code Coverage
+-------------
+
+In order to estimate the amount of code which is tested ("covered") by the
+current unit tests you can use any coverage tools which can process the
+files *.gcda and *.gcno, which are automatically generated when running the
+testsuite.
+
+One such tool (ggcov) is available from http://ggcov.sourceforge.net/.
+On Debian system you can install ggcov via 'apt-get install ggcov'.
+
+To start the ggcov GUI type:
+
+ $ cd util/testsuite/unittests
+ $ ggcov
+
Index: HACKING
===================================================================
--- HACKING	(Revision 358)
+++ HACKING	(Arbeitskopie)
@@ -102,3 +102,7 @@
   Source: Linux kernel, lib/vsprintf.c
   Current version we use: ?
 
+* util/testsuite/unittests/check.h: LGPLv2.1 or later
+  Source: http://check.sourceforge.net/ (src/check.h)
+  Current version we use: 0.9.5
+
Index: Makefile
===================================================================
--- Makefile	(Revision 358)
+++ Makefile	(Arbeitskopie)
@@ -124,6 +124,9 @@
 doxygen:
 	$(Q)$(DOXYGEN) util/doxygen/Doxyfile.LinuxBIOS
 
+check:
+	$(Q)Q=$(Q) $(MAKE) -C util/testsuite/unittests check
+
 prepare:
 	$(Q)mkdir -p $(obj)
 
@@ -152,6 +155,7 @@
 	$(Q)rm -rf $(DOXYGEN_OUTPUT_DIR)
 	$(Q)printf "  CLEAN   doc/design/newboot.pdf\n"
 	$(Q)rm -f doc/design/newboot.pdf
+	$(Q)Q=$(Q) $(MAKE) -C util/testsuite/unittests clean
 
 distclean: clean
 	$(Q)printf "  CLEAN   .kconfig.d .config .tmpconfig.h .config.old .xcompile\n"
@@ -161,5 +165,5 @@
 	$(Q)printf "  CC      $(subst $(shell pwd)/,,$(@))\n"
 	$(Q)$(CC) $(CFLAGS) -o $@ -c $<
 
-.PHONY: doc doxygen depends prepare prepare2 clean distclean
+.PHONY: doc doxygen depends check prepare prepare2 clean distclean
 
Index: device/device_util.c
===================================================================
--- device/device_util.c	(Revision 358)
+++ device/device_util.c	(Arbeitskopie)
@@ -496,7 +496,7 @@
  * @param gran Granularity we are aligning the number to.
  * @returns The aligned value.
  */
-static resource_t align_up(resource_t val, unsigned long gran)
+resource_t align_up(resource_t val, unsigned long gran)
 {
 	resource_t mask;
 	mask = (1ULL << gran) - 1ULL;
@@ -512,7 +512,7 @@
  * @param gran Granularity we are aligning the number to.
  * @returns The aligned value.
  */
-static resource_t align_down(resource_t val, unsigned long gran)
+resource_t align_down(resource_t val, unsigned long gran)
 {
 	resource_t mask;
 	mask = (1ULL << gran) - 1ULL;

Attachment: signature.asc
Description: Digital signature

-- 
linuxbios mailing list
[email protected]
http://www.linuxbios.org/mailman/listinfo/linuxbios

Reply via email to