=== modified file 'Makefile.in' --- old/Makefile.in 2009-12-13 20:25:49 +0000 +++ new/Makefile.in 2009-12-17 06:13:08 +0000 @@ -138,6 +138,7 @@ SCRIPTS = $(bin_SCRIPTS) $(sbin_SCRIPTS) $(grub-mkconfig_SCRIPTS) \ $(lib_SCRIPTS) INFOS = $(info_INFOS) +TESTS = $(check_TESTS) $(check_SCRIPTS) $(check_MODULES) CLEANFILES = MOSTLYCLEANFILES = @@ -168,6 +169,9 @@ -include $(wildcard $(GRUB_CONTRIB)/*/conf/common.mk) endif +# For tests. +include $(srcdir)/conf/tests.mk + ### General targets. CLEANFILES += $(pkglib_DATA) $(pkgdata_DATA) po/*.mo @@ -452,7 +456,15 @@ @echo "$(distdir).tar.gz is ready for distribution" | \ sed 'h;s/./=/g;p;x;p;x' -check: +check: all $(TESTS) + @list="$(check_TESTS) $(check_SCRIPTS)"; \ + for file in $$list; do \ + if $(builddir)/$$file; then \ + echo "$$file: PASS"; \ + else \ + echo "$$file: FAIL"; \ + fi; \ + done .SUFFIX: .SUFFIX: .c .o .S .d === added file 'conf/tests.rmk' --- old/conf/tests.rmk 1970-01-01 00:00:00 +0000 +++ new/conf/tests.rmk 2009-12-17 06:14:48 +0000 @@ -0,0 +1,30 @@ +# -*- makefile -*- + +check_MODULES += functional_test.mod +functional_test_mod_SOURCES = tests/functional_test.c tests/test.c +functional_test_mod_CFLAGS = $(COMMON_CFLAGS) +functional_test_mod_LDFLAGS = $(COMMON_LDFLAGS) + +# Unit tests + +check_TESTS += example_unit_test +example_unit_test_SOURCES = tests/example_unit_test.c kern/list.c kern/misc.c tests/test.c tests/unit_test.c +example_unit_test_CFLAGS = -Wno-format + +check_TESTS += grub_sprintf +grub_sprintf_SOURCES = tests/grub_sprintf.c kern/misc.c kern/list.c tests/test.c tests/unit_test.c +grub_sprintf_CFLAGS = -Wno-error -Wno-format + +# Functional tests + +check_MODULES += example_functional_test.mod +example_functional_test_mod_SOURCES = tests/example_functional_test.c +example_functional_test_mod_CFLAGS = -Wno-format $(COMMON_CFLAGS) +example_functional_test_mod_LDFLAGS = $(COMMON_LDFLAGS) + +# Scripted tests + +check_SCRIPTS += example_scripted_test +example_scripted_test_SOURCES = tests/example_scripted_test.in + + === modified file 'genmk.rb' --- old/genmk.rb 2009-12-13 20:25:49 +0000 +++ new/genmk.rb 2009-12-17 06:11:05 +0000 @@ -413,7 +413,7 @@ PModule.new(prefix, pmod) end - when 'UTILITIES' + when 'UTILITIES', 'TESTS' utils += args.split(/\s+/).collect do |util| Utility.new(prefix, util) end === added file 'include/grub/test.h' --- old/include/grub/test.h 1970-01-01 00:00:00 +0000 +++ new/include/grub/test.h 2009-12-17 06:11:05 +0000 @@ -0,0 +1,84 @@ +#ifndef GRUB_TEST_HEADER +#define GRUB_TEST_HEADER + +#include +#include +#include +#include +#include + +struct grub_test +{ + /* The next test. */ + struct grub_test *next; + + /* The test name. */ + char *name; + + /* The test main function. */ + void (*main) (void); +}; +typedef struct grub_test *grub_test_t; + +extern grub_test_t EXPORT_VAR (grub_test_list); + +void EXPORT_FUNC (grub_test_register) (const char *name, void (*test) (void)); + +void EXPORT_FUNC (grub_test_unregister) (const char *name); + +/* Execute a test and print results. */ +int grub_test_run (const char *name); + +/* Test `cond' for nonzero; log failure otherwise. */ +void grub_test_nonzero (int cond, const char *file, + const char *func, grub_uint32_t line, + const char *fmt, ...) + __attribute__ ((format (printf, 5, 6))); + +#if __STDC_VERSION__ < 199901L +# if __GNUC__ >= 2 +# define __func__ __FUNCTION__ +# else +# define __func__ "" +# endif +#endif + +/* Macro to fill in location details and an optional error message. */ +#define grub_test_assert(cond, ...) \ + grub_test_nonzero(cond, __FILE__, __func__, __LINE__, \ + ## __VA_ARGS__, \ + "assert failed: %s", #cond) + +/* Macro to define a unit test. */ +#define GRUB_UNIT_TEST(name, funp) \ + void grub_unit_test_init (void) \ + { \ + grub_test_register (name, funp); \ + } \ + \ + void grub_unit_test_fini (void) \ + { \ + grub_test_unregister (name); \ + } + +/* Macro to define a functional test. */ +#define GRUB_FUNCTIONAL_TEST(name, funp) \ + GRUB_MOD_INIT(functional_test_##funp) \ + { \ + grub_test_register (name, funp); \ + } \ + \ + GRUB_MOD_FINI(functional_test_##funp) \ + { \ + grub_test_unregister (name); \ + } + +/* Functions that are defined differently for unit and functional tests. */ +void *grub_test_malloc (grub_size_t size); +void grub_test_free (void *ptr); +char *grub_test_strdup (const char *str); +int grub_test_vsprintf (char *str, const char *fmt, va_list args); +int grub_test_printf (const char *fmt, ...) + __attribute__ ((format (printf, 1, 2))); + +#endif /* ! GRUB_TEST_HEADER */ === added directory 'tests' === added file 'tests/example_functional_test.c' --- old/tests/example_functional_test.c 1970-01-01 00:00:00 +0000 +++ new/tests/example_functional_test.c 2009-12-17 06:11:05 +0000 @@ -0,0 +1,17 @@ +/* All tests need to include test.h for GRUB testing framework. */ +#include + +/* Functional test main method. */ +static void +example_test (void) +{ + /* Check if 1st argument is true and report with default error message. */ + grub_test_assert (1 == 1); + + /* Check if 1st argument is true and report with custom error message. */ + grub_test_assert (2 == 2, "2 equal 2 expected"); + grub_test_assert (2 == 3, "2 is not equal to %d", 3); +} + +/* Register example_test method as a functional test. */ +GRUB_FUNCTIONAL_TEST ("example_functional_test", example_test); === added file 'tests/example_scripted_test.in' --- old/tests/example_scripted_test.in 1970-01-01 00:00:00 +0000 +++ new/tests/example_scripted_test.in 2009-12-17 06:11:05 +0000 @@ -0,0 +1,3 @@ +#!/bin/sh -e + +true === added file 'tests/example_unit_test.c' --- old/tests/example_unit_test.c 1970-01-01 00:00:00 +0000 +++ new/tests/example_unit_test.c 2009-12-17 06:11:05 +0000 @@ -0,0 +1,20 @@ +/* Unit tests are normal programs, so they can include C library. */ +#include + +/* All tests need to include test.h for GRUB testing framework. */ +#include + +/* Unit test main method. */ +static void +example_test (void) +{ + /* Check if 1st argument is true and report with default error message. */ + grub_test_assert (1 == 1); + + /* Check if 1st argument is true and report with custom error message. */ + grub_test_assert (2 == 2, "2 equal 2 expected"); + grub_test_assert (2 == 3, "2 is not equal to %d", 3); +} + +/* Register example_test method as a unit test. */ +GRUB_UNIT_TEST ("example_unit_test", example_test); === added file 'tests/functional_test.c' --- old/tests/functional_test.c 1970-01-01 00:00:00 +0000 +++ new/tests/functional_test.c 2009-12-17 06:11:05 +0000 @@ -0,0 +1,89 @@ +#include +#include +#include +#include + +void * +grub_test_malloc (grub_size_t size) +{ + return grub_malloc (size); +} + +void +grub_test_free (void *ptr) +{ + grub_free (ptr); +} + +int +grub_test_vsprintf (char *str, const char *fmt, va_list args) +{ + return grub_vsprintf (str, fmt, args); +} + +char * +grub_test_strdup (const char *str) +{ + return grub_strdup (str); +} + +int +grub_test_printf (const char *fmt, ...) +{ + int r; + va_list ap; + + va_start (ap, fmt); + r = grub_vprintf (fmt, ap); + va_end (ap); + + return r; +} + +static grub_err_t +grub_functional_test (struct grub_extcmd *cmd __attribute__ ((unused)), + int argc, char **args __attribute__ ((unused))) +{ + int i; + int status; + grub_test_t test; + + auto int print_name (grub_test_t test); + int print_name (grub_test_t test) + { + grub_printf ("%s\n", test->name); + return 0; + } + + if (!argc) + { + grub_list_iterate (GRUB_AS_LIST (grub_test_list), + (grub_list_hook_t) print_name); + return GRUB_ERR_NONE; + } + + status = 0; + for (i = 0; i < argc; i++) + { + test = grub_named_list_find (GRUB_AS_NAMED_LIST (grub_test_list), + args[i]); + status = grub_test_run (test->name) ? : status; + } + + return status; +} + +static grub_extcmd_t cmd; + +GRUB_MOD_INIT (functional_test) +{ + cmd = grub_register_extcmd ("functional_test", grub_functional_test, + GRUB_COMMAND_FLAG_CMDLINE, + "functional_test [name ...]", + "Run or list functional tests.", 0); +} + +GRUB_MOD_FINI (functional_test) +{ + grub_unregister_extcmd (cmd); +} === added file 'tests/grub_sprintf.c' --- old/tests/grub_sprintf.c 1970-01-01 00:00:00 +0000 +++ new/tests/grub_sprintf.c 2009-12-17 06:11:05 +0000 @@ -0,0 +1,162 @@ +#include +#include +#include +#include + +#include +#include + +#define TEST(type,fmt,val) \ + do { \ + int r1, r2; \ + char b1[1024]; \ + char b2[1024]; \ + \ + b1[0] = b2[0] = '\0'; \ + r1 = sprintf (b1, fmt, val); \ + r2 = grub_sprintf (b2, fmt, val); \ + \ + grub_test_assert (strcmp (b1, b2) == 0, \ + "for (\"%s\","type") " \ + "result should be (\"%s\",%d) " \ + "but got (\"%s\",%d)", \ + fmt, val, b1, r1, b2, r2); \ + \ + grub_test_assert (r1 == r2, \ + "for (\"%s\","type") " \ + "result should be (\"%s\",%d) " \ + "but got (\"%s\",%d)", \ + fmt, val, b1, r1, b2, r2); \ + } while (0) + +#define D(fmt,v) TEST("%d",fmt,v) +#define U(fmt,v) TEST("%u",fmt,v) +#define x(fmt,v) TEST("%x",fmt,v) +#define X(fmt,v) TEST("%X",fmt,v) +#define P(fmt,v) TEST("%p",fmt,v) +#define S(fmt,s) TEST("%s",fmt,s) + +static void +sprintf_checks (void) +{ + D ("%d", -1); + D ("%d", 0); + D ("%d", 1); + D ("%5d", -1); + D ("%5d", 0); + D ("%5d", 1); + D ("%-5d", -1); + D ("%-5d", 0); + D ("%-5d", 1); + D ("%.5d", -1); + D ("%.5d", 0); + D ("%.5d", 1); + D ("%5.0d", -1); + D ("%5.0d", 0); + D ("%5.0d", 1); + D ("%-5.0d", -1); + D ("%-5.0d", 0); + D ("%-5.0d", 1); + + U ("%d", -1); + U ("%d", 0); + U ("%d", 1); + U ("%5d", -1); + U ("%5d", 0); + U ("%5d", 1); + U ("%-5d", -1); + U ("%-5d", 0); + U ("%-5d", 1); + U ("%.5d", -1); + U ("%.5d", 0); + U ("%.5d", 1); + U ("%5.0d", -1); + U ("%5.0d", 0); + U ("%5.0d", 1); + U ("%-5.0d", -1); + U ("%-5.0d", 0); + U ("%-5.0d", 1); + + x ("%d", -1); + x ("%d", 0); + x ("%d", 1); + x ("%5d", -1); + x ("%5d", 0); + x ("%5d", 1); + x ("%-5d", -1); + x ("%-5d", 0); + x ("%-5d", 1); + x ("%.5d", -1); + x ("%.5d", 0); + x ("%.5d", 1); + x ("%5.0d", -1); + x ("%5.0d", 0); + x ("%5.0d", 1); + x ("%-5.0d", -1); + x ("%-5.0d", 0); + x ("%-5.0d", 1); + + X ("%d", -1); + X ("%d", 0); + X ("%d", 1); + X ("%5d", -1); + X ("%5d", 0); + X ("%5d", 1); + X ("%-5d", -1); + X ("%-5d", 0); + X ("%-5d", 1); + X ("%.5d", -1); + X ("%.5d", 0); + X ("%.5d", 1); + X ("%5.0d", -1); + X ("%5.0d", 0); + X ("%5.0d", 1); + X ("%-5.0d", -1); + X ("%-5.0d", 0); + X ("%-5.0d", 1); + + P ("%p", NULL); + P ("%p", sprintf_checks); + + S ("%s", (char *) NULL); + S ("%s", "abcd"); + S ("%10s", "abcd"); + S ("%10.5s", "abcdefgh"); + S ("%10.5s", "ab"); + S ("%2.5s", "a"); + S ("%2.5s", "abcdefgh"); + + D ("%4.2d", 1); + D ("%4.2d", 12); + D ("%4.2d", 123); + D ("%4.2d", 1234); + D ("%4.2d", 12345); + D ("%3.3d", 12); + D ("%3.3d", 123); + D ("%3.3d", 1234); + D ("%2.4d", 12345); + D ("%2.4d", 1234); + D ("%2.4d", 123); + D ("%2.4d", 12); + D ("%2.4d", 1); + D ("%.0d", 0); + D ("%.0d", 1); + + S ("%4.2s", "1"); + S ("%4.2s", "12"); + S ("%4.2s", "123"); + S ("%4.2s", "1234"); + S ("%4.2s", "12345"); + S ("%3.3s", "12"); + S ("%3.3s", "123"); + S ("%3.3s", "1234"); + S ("%2.4s", "12345"); + S ("%2.4s", "1234"); + S ("%2.4s", "123"); + S ("%2.4s", "12"); + S ("%2.4s", "1"); + + /* add few more here, if necessary */ +} + +GRUB_UNIT_TEST ("grub_sprintf", sprintf_checks); === added file 'tests/test.c' --- old/tests/test.c 1970-01-01 00:00:00 +0000 +++ new/tests/test.c 2009-12-17 06:11:05 +0000 @@ -0,0 +1,150 @@ +#include +#include + +struct grub_test_failure +{ + /* The next failure. */ + struct grub_test_failure *next; + + /* The test source file name. */ + char *file; + + /* The test function name. */ + char *funp; + + /* The test call line number. */ + grub_uint32_t line; + + /* The test failure message. */ + char *message; +}; +typedef struct grub_test_failure *grub_test_failure_t; + +grub_test_t grub_test_list; +static grub_test_failure_t failure_list; + +static void +add_failure (const char *file, + const char *funp, + grub_uint32_t line, const char *fmt, va_list args) +{ + char buf[1024]; + grub_test_failure_t failure; + + failure = (grub_test_failure_t) grub_test_malloc (sizeof (*failure)); + if (!failure) + return; + + grub_test_vsprintf (buf, fmt, args); + + failure->file = grub_test_strdup (file ? : ""); + failure->funp = grub_test_strdup (funp ? : ""); + failure->line = line; + failure->message = grub_test_strdup (buf); + + grub_list_push (GRUB_AS_LIST_P (&failure_list), GRUB_AS_LIST (failure)); +} + +void +free_failures (void) +{ + grub_test_failure_t item; + + while ((item = grub_list_pop (GRUB_AS_LIST_P (&failure_list))) != 0) + { + if (item->message) + grub_test_free (item->message); + + if (item->funp) + grub_test_free (item->funp); + + if (item->file) + grub_test_free (item->file); + + grub_test_free (item); + } + failure_list = 0; +} + +void +grub_test_nonzero (int cond, + const char *file, + const char *funp, grub_uint32_t line, const char *fmt, ...) +{ + va_list ap; + + if (cond) + return; + + va_start (ap, fmt); + add_failure (file, funp, line, fmt, ap); + va_end (ap); +} + +void +grub_test_register (const char *name, void (*test_main) (void)) +{ + grub_test_t test; + + test = (grub_test_t) grub_test_malloc (sizeof (*test)); + if (!test) + return; + + test->name = grub_test_strdup (name); + test->main = test_main; + + grub_list_push (GRUB_AS_LIST_P (&grub_test_list), GRUB_AS_LIST (test)); +} + +void +grub_test_unregister (const char *name) +{ + grub_test_t test; + + test = (grub_test_t) grub_named_list_find + (GRUB_AS_NAMED_LIST (grub_test_list), name); + + if (test) + { + grub_list_remove (GRUB_AS_LIST_P (&grub_test_list), + GRUB_AS_LIST (test)); + + if (test->name) + grub_test_free (test->name); + + grub_test_free (test); + } +} + +int +grub_test_run (const char *name) +{ + grub_test_t test; + + auto int print_failure (grub_test_failure_t item); + int print_failure (grub_test_failure_t item) + { + grub_test_failure_t failure = (grub_test_failure_t) item; + + grub_test_printf (" %s:%s:%u: %s\n", + (failure->file ? : ""), + (failure->funp ? : ""), + failure->line, (failure->message ? : "")); + return 0; + } + + test = grub_named_list_find (GRUB_AS_NAMED_LIST (grub_test_list), name); + if (!test) + return GRUB_ERR_FILE_NOT_FOUND; + + test->main (); + + if (!failure_list) + return GRUB_ERR_NONE; + + grub_test_printf ("%s:\n", test->name); + grub_list_iterate (GRUB_AS_LIST (failure_list), + (grub_list_hook_t) print_failure); + free_failures (); + return GRUB_ERR_TEST_FAILURE; +} === added file 'tests/unit_test.c' --- old/tests/unit_test.c 1970-01-01 00:00:00 +0000 +++ new/tests/unit_test.c 2009-12-17 06:11:05 +0000 @@ -0,0 +1,122 @@ +#include +#include +#include +#include + +#include +#include +#include + +void * +grub_test_malloc (grub_size_t size) +{ + return malloc (size); +} + +void +grub_test_free (void *ptr) +{ + free (ptr); +} + +int +grub_test_vsprintf (char *str, const char *fmt, va_list args) +{ + return vsprintf (str, fmt, args); +} + +char * +grub_test_strdup (const char *str) +{ + return strdup (str); +} + +int +grub_test_printf (const char *fmt, ...) +{ + int r; + va_list ap; + + va_start (ap, fmt); + r = vprintf (fmt, ap); + va_end (ap); + + return r; +} + +int +main (int argc __attribute__ ((unused)), + char *argv[] __attribute__ ((unused))) +{ + int status = 0; + + extern void grub_unit_test_init (void); + extern void grub_unit_test_fini (void); + + auto int run_test (grub_test_t test); + int run_test (grub_test_t test) + { + status = grub_test_run (test->name) ? : status; + return 0; + } + + grub_unit_test_init (); + grub_list_iterate (GRUB_AS_LIST (grub_test_list), + (grub_list_hook_t) run_test); + grub_unit_test_fini (); + + exit (status); +} + +/* Other misc. functions necessary for successful linking. */ + +char * +grub_env_get (const char *name __attribute__ ((unused))) +{ + return NULL; +} + +grub_err_t +grub_error (grub_err_t n, const char *fmt, ...) +{ + va_list ap; + + va_start (ap, fmt); + vfprintf (stderr, fmt, ap); + va_end (ap); + + return n; +} + +void * +grub_malloc (grub_size_t size) +{ + return malloc (size); +} + +void +grub_refresh (void) +{ + fflush (stdout); +} + +void +grub_putchar (int c) +{ + putchar (c); +} + +int +grub_getkey (void) +{ + return -1; +} + +void +grub_exit (void) +{ + exit (1); +} + +struct grub_handler_class grub_term_input_class; +struct grub_handler_class grub_term_output_class;