aboutsummaryrefslogtreecommitdiffstats
path: root/com32/lib
diff options
context:
space:
mode:
authorMatt Fleming <matt.fleming@intel.com>2013-07-17 14:53:08 +0100
committerMatt Fleming <matt.fleming@intel.com>2013-07-23 14:58:41 +0100
commit82546447f46cab11f13380fe658b1f79cdd38654 (patch)
treef236c3eeddcab926f1dbba768c549f2cb61b9847 /com32/lib
parent21f8596c58a9791e7ea1f4ba93be17eed60a05b6 (diff)
downloadsyslinux-82546447f46cab11f13380fe658b1f79cdd38654.tar.gz
syslinux-82546447f46cab11f13380fe658b1f79cdd38654.tar.xz
syslinux-82546447f46cab11f13380fe658b1f79cdd38654.zip
tests: Syslinux unit tests
Improve our faith in the validity of the Syslinux code by writing unit tests where possible. These should be used in addition to the regression tests - unit tests are a means of doing very fine-grained testing of code, whereas the regression tests are end-to-end tests that exercise abstract functionality. Unit tests run on your development machine and above all else, their execution time should be kept to a minimum to encourage repeated runs of the unit testsuite. The Syslinux header hierarchy has been reconstructed under tests/unittest/include. This allows us to reuse header files where appropriate by simply creating a file with the same name and including the original, e.g. tests/unittest/include/com32.h: #include <../../../com32/include/com32.h> Places where we need to override definitions (so that the tests build in a dev environment) obviously won't include the original header file, but such scenarios should be kept to a minimum, since you're not really testing any Syslinux code that way. To execute the collection of unit tests type, make unittest Sample output might look like, Executing unit tests Running library unit tests... [+] zonelist passed [+] movebits passed [+] memscan passed Signed-off-by: Matt Fleming <matt.fleming@intel.com>
Diffstat (limited to 'com32/lib')
-rw-r--r--com32/lib/syslinux/tests/Makefile23
-rw-r--r--com32/lib/syslinux/tests/memscan.c75
-rw-r--r--com32/lib/syslinux/tests/movebits.c85
-rw-r--r--com32/lib/syslinux/tests/test-harness.c49
-rw-r--r--com32/lib/syslinux/tests/test.h17
-rw-r--r--com32/lib/syslinux/tests/zonelist.c219
6 files changed, 468 insertions, 0 deletions
diff --git a/com32/lib/syslinux/tests/Makefile b/com32/lib/syslinux/tests/Makefile
new file mode 100644
index 00000000..485a9ce1
--- /dev/null
+++ b/com32/lib/syslinux/tests/Makefile
@@ -0,0 +1,23 @@
+CFLAGS = -I$(topdir)/tests/unittest/include
+
+tests = zonelist movebits memscan
+
+all: banner $(tests)
+ for t in $(tests); \
+ do printf " [+] $$t passed\n" ; ./$$t ; done
+clean:
+ rm $(tests)
+
+banner:
+ printf " Running library unit tests...\n"
+
+harness-files = test-harness.c
+
+zonelist: zonelist.c ../zonelist.c $(harness-files)
+movebits: movebits.c ../movebits.c $(harness-files)
+memscan: memscan.c ../memscan.c
+
+%: %.c
+ $(CC) $(CFLAGS) -o $@ $<
+
+
diff --git a/com32/lib/syslinux/tests/memscan.c b/com32/lib/syslinux/tests/memscan.c
new file mode 100644
index 00000000..bc43a3ed
--- /dev/null
+++ b/com32/lib/syslinux/tests/memscan.c
@@ -0,0 +1,75 @@
+#include "test.h"
+
+#include "../memscan.c"
+
+struct memmap {
+ addr_t start;
+ size_t size;
+ enum syslinux_memmap_types type;
+ bool visited;
+};
+
+static struct memmap memmap[] = {
+ { 0x00000, 0x2000, SMT_FREE, false },
+ { 0x400000, 0x1000, SMT_TERMINAL, false},
+};
+
+#define MEMMAP_SIZE (sizeof(memmap) / sizeof(memmap[0]))
+
+/*
+ * Our dummy memory scanner. This is analogous to bios_scan_memory() or
+ * efi_scan_memory(), etc.
+ */
+static int test_scan_memory(scan_memory_callback_t callback, void *data)
+{
+ int i, rv;
+
+ for (i = 0; i < MEMMAP_SIZE; i++)
+ rv = callback(data, memmap[i].start, memmap[i].size, memmap[i].type);
+
+ return 0;
+}
+
+static int callback(void *data, addr_t start, addr_t size,
+ enum syslinux_memmap_types type)
+{
+ int i;
+
+ for (i = 0; i < MEMMAP_SIZE; i++) {
+ if (memmap[i].start == start && memmap[i].size == size) {
+ memmap[i].visited = true;
+ break;
+ }
+ }
+
+ return 0;
+}
+
+static int verify_visited_all_memmap_entries(void)
+{
+ int i;
+
+ syslinux_memscan_new(test_scan_memory);
+ syslinux_scan_memory(callback, NULL);
+
+ for (i = 0; i < MEMMAP_SIZE; i++) {
+ addr_t start = memmap[i].start;
+ bool visited_entry = memmap[i].visited;
+
+ syslinux_assert(visited_entry, "Didn't pass entry %d to callback", i);
+ }
+
+ return 0;
+}
+
+static int verify_invoked_all_callbacks(void)
+{
+ syslinux_scan_memory(callback, NULL);
+}
+
+int main(int argc, char **argv)
+{
+ verify_visited_all_memmap_entries();
+
+ return 0;
+}
diff --git a/com32/lib/syslinux/tests/movebits.c b/com32/lib/syslinux/tests/movebits.c
new file mode 100644
index 00000000..09c02cb0
--- /dev/null
+++ b/com32/lib/syslinux/tests/movebits.c
@@ -0,0 +1,85 @@
+#include "test.h"
+#include <setjmp.h>
+
+#include "../../../include/minmax.h"
+#include "../zonelist.c"
+#include "test-harness.c"
+
+static int move_to_terminal_region(void)
+{
+ struct syslinux_memmap *mmap;
+ addr_t dst, src;
+ size_t len;
+ int rv = -1;
+ struct mmap_entry entries[] = {
+ { 0x00000, 0x90000, SMT_RESERVED },
+ { 0x90000, 0x10000, SMT_TERMINAL },
+ { 0xa0000, 0xf000, SMT_FREE },
+ { 0x100000, 0x3000, SMT_FREE }
+ };
+
+ mmap = test_build_mmap(entries, array_sz(entries));
+ if (!mmap)
+ goto bail;
+
+ dst = 0x90000;
+ src = 0x1fff000;
+ len = 0xf000;
+
+ rv = syslinux_memmap_find(mmap, &dst, len, false, 16,
+ 0, (addr_t)-1, 0, (addr_t)-1);
+ syslinux_assert(!rv, "Expected to find 0x%x to be SMT_TERMINAL", dst);
+
+ rv = test_attempt_movelist(mmap, dst, src, len);
+ syslinux_assert(!rv, "Expected to move 0x%x to 0x%x, len 0x%x", src, dst, len);
+
+ rv = 0;
+
+bail:
+ syslinux_free_memmap(mmap);
+ return rv;
+}
+
+static int move_to_overlapping_region(void)
+{
+ struct syslinux_memmap *mmap;
+ addr_t dst, src;
+ size_t len;
+ int rv = -1;
+ struct mmap_entry entries[] = {
+ { 0x00000, 0x90000, SMT_RESERVED },
+ { 0x90000, 0x10000, SMT_TERMINAL },
+ { 0xa0000, 0xf000, SMT_FREE },
+ { 0x100000, 0x3000, SMT_TERMINAL },
+ { 0x103000, 0x1000, SMT_FREE },
+ };
+
+ mmap = test_build_mmap(entries, array_sz(entries));
+ if (!mmap)
+ goto bail;
+
+ rv = test_attempt_movelist(mmap, 0x90000, 0x300000, 0x10001);
+ syslinux_assert(!rv, "Allocating across boundary region failed");
+
+ rv = test_attempt_movelist(mmap, 0xa0000, 0x4000000, 0x10000);
+ syslinux_assert(rv, "Move into undefined region succeeded");
+
+ rv = test_attempt_movelist(mmap, 0x80000, 0x200000, 0x10000);
+ syslinux_assert(rv, "Move across incompatible region boundary succeeded");
+
+ rv = test_attempt_movelist(mmap, 0x100000, 0x4000000, 0x4001);
+ syslinux_assert(rv, "Move past end of available regions succeeded");
+
+ rv = 0;
+bail:
+ syslinux_free_memmap(mmap);
+ return rv;
+}
+
+int main(int argc, char **argv)
+{
+ move_to_terminal_region();
+ move_to_overlapping_region();
+
+ return 0;
+}
diff --git a/com32/lib/syslinux/tests/test-harness.c b/com32/lib/syslinux/tests/test-harness.c
new file mode 100644
index 00000000..49e32f87
--- /dev/null
+++ b/com32/lib/syslinux/tests/test-harness.c
@@ -0,0 +1,49 @@
+#include "test.h"
+#include "../addlist.c"
+#include "../freelist.c"
+#include "../movebits.c"
+
+struct syslinux_memmap *test_build_mmap(struct mmap_entry *entries,
+ size_t nr_entries)
+{
+ struct syslinux_memmap *mmap;
+ int i;
+
+ mmap = syslinux_init_memmap();
+ if (!mmap)
+ goto bail;
+
+ for (i = 0; i < nr_entries; i++) {
+ enum syslinux_memmap_types type = entries[i].type;
+ addr_t start = entries[i].start;
+ addr_t size = entries[i].size;
+
+ if (syslinux_add_memmap(&mmap, start, size, type))
+ goto bail;
+ }
+
+ return mmap;
+
+bail:
+ syslinux_free_memmap(mmap);
+ return NULL;
+}
+
+int test_attempt_movelist(struct syslinux_memmap *mmap, addr_t dst,
+ addr_t src, size_t len)
+{
+ struct syslinux_movelist *frags = NULL;
+ struct syslinux_movelist *moves = NULL;
+ int rv;
+
+ rv = syslinux_add_movelist(&frags, dst, src, len);
+ if (rv)
+ goto bail;
+
+ rv = syslinux_compute_movelist(&moves, frags, mmap);
+
+bail:
+ syslinux_free_movelist(frags);
+ syslinux_free_movelist(moves);
+ return rv;
+}
diff --git a/com32/lib/syslinux/tests/test.h b/com32/lib/syslinux/tests/test.h
new file mode 100644
index 00000000..91ba860d
--- /dev/null
+++ b/com32/lib/syslinux/tests/test.h
@@ -0,0 +1,17 @@
+#ifndef _TEST_H_
+#define _TEST_H_
+
+#include "unittest.h"
+#include "syslinux/movebits.h"
+
+#define array_sz(x) (sizeof((x)) / sizeof((x)[0]))
+
+struct mmap_entry {
+ addr_t start;
+ addr_t size;
+ enum syslinux_memmap_types type;
+};
+
+extern struct syslinux_memmap *build_mmap(struct mmap_entry *entries,
+ size_t nr_entries);
+#endif /* _TEST_H_ */
diff --git a/com32/lib/syslinux/tests/zonelist.c b/com32/lib/syslinux/tests/zonelist.c
new file mode 100644
index 00000000..ac7c1743
--- /dev/null
+++ b/com32/lib/syslinux/tests/zonelist.c
@@ -0,0 +1,219 @@
+/*
+ * Unit test.
+ *
+ * We make heavy use of assertions to ensure that our expectations are
+ * met regarding the Syslinux library interfaces. If an assert fails we
+ * keep running the test if possible to try and save as much information
+ * regarding the failures.
+ *
+ * A unit test function should return an error if it failed to setup the
+ * infrastructure, e.g. malloc() fails. If an assertion fires, that is
+ * not mean the test infrastructure failed, merely that the test didn't
+ * pass.
+ *
+ * To work around any include path issues due to the unit tests being
+ * run on the development host we must include all headers with absolute
+ * paths.
+ */
+#include "test.h"
+#include "../zonelist.c"
+#include "test-harness.c"
+
+static int refuse_to_alloc_reserved_region(void)
+{
+ struct syslinux_memmap *mmap;
+ const char *cmdline;
+ size_t kernel_size;
+ bool relocatable = false;
+ size_t alignment = 1;
+ addr_t base;
+ int rv = -1;
+
+ mmap = syslinux_init_memmap();
+ if (!mmap)
+ goto bail;
+
+ if (syslinux_add_memmap(&mmap, 0x90000, 0x10000, SMT_RESERVED))
+ goto bail;
+
+ base = 0x90000;
+ rv = syslinux_memmap_find(mmap, &base, 0x1000, relocatable, alignment,
+ base, base, 0, 640 * 1024);
+ syslinux_assert(rv, "Allocated reserved region 0x%x", base);
+
+ rv = 0;
+
+bail:
+ syslinux_free_memmap(mmap);
+ return rv;
+}
+
+static int refuse_to_alloc_above_max_address(void)
+{
+ struct syslinux_memmap *mmap;
+ addr_t base = 0x100000;
+ size_t size = 0x1000;
+ int rv = -1;
+
+ mmap = syslinux_init_memmap();
+ if (!mmap)
+ goto bail;
+
+ if (syslinux_add_memmap(&mmap, base, size, SMT_FREE))
+ goto bail;
+
+ rv = syslinux_memmap_find(mmap, &base, size, false, 16,
+ base, base, 0, 640 * 1024);
+ syslinux_assert(!rv, "Failed to find a free region");
+
+ syslinux_assert_str(!(base < 0x100000), "Region below min address");
+ syslinux_assert_str(!(base > 0x100000), "Region above max address");
+
+ rv = 0;
+bail:
+ syslinux_free_memmap(mmap);
+ return rv;
+}
+
+static int alloc_region_with_zero_size(void)
+{
+ int rv;
+
+ rv = syslinux_memmap_find(NULL, 0, 0, false, 0, 0, 0, 0, 0);
+ syslinux_assert(!rv, "Should be able to allocate a zero-size region");
+
+ return 0;
+}
+
+static int refuse_to_relocate_region(void)
+{
+ struct syslinux_memmap *mmap;
+ addr_t free_base;
+ size_t free_size;
+ int rv = -1;
+
+ mmap = syslinux_init_memmap();
+ if (!mmap)
+ goto bail;
+
+ free_base = 0x20000;
+ free_size = 0x1000000;
+ if (syslinux_add_memmap(&mmap, free_base, free_size, SMT_FREE))
+ goto bail;
+
+ free_base = 0x10000;
+ free_size = 0x7000;
+ rv = syslinux_memmap_find(mmap, &free_base, free_size, false, 1,
+ 0, (addr_t)-1, (addr_t)0, (addr_t)-1);
+ syslinux_assert(rv, "Relocated region from 0x10000 to 0x%x", free_base);
+
+bail:
+ syslinux_free_memmap(mmap);
+ return rv;
+}
+
+static int only_relocate_upwards(void)
+{
+ struct syslinux_memmap *mmap;
+ addr_t base;
+ int rv = -1;
+
+ mmap = syslinux_init_memmap();
+ if (!mmap)
+ goto bail;
+
+ if (syslinux_add_memmap(&mmap, 0x00010, 0x1000, SMT_FREE))
+ goto bail;
+
+ base = 0x10000;
+ rv = syslinux_memmap_find(mmap, &base, 16, true, 1, 0, (addr_t)-1,
+ 0x2000, (addr_t)-1);
+
+ syslinux_assert(rv, "Should not have found any entry in memmap");
+ syslinux_assert_str(base >= 0x10000,
+ "Relocated in wrong direction 0x%x", base);
+
+ rv = 0;
+bail:
+ syslinux_free_memmap(mmap);
+ return rv;
+}
+
+static int alloc_in_pxe_region(void)
+{
+ struct syslinux_memmap *mmap;
+ addr_t base;
+ int rv = -1;
+
+ mmap = syslinux_init_memmap();
+ if (!mmap)
+ goto bail;
+
+ /* Construct a memmap with a gap where the PXE region usually is */
+ if (syslinux_add_memmap(&mmap, 0x00000, 0x8f000, SMT_FREE))
+ goto bail;
+
+ if (syslinux_add_memmap(&mmap, 0x100000, 0xf000, SMT_FREE))
+ goto bail;
+
+ base = 0x90000;
+ rv = syslinux_memmap_find(mmap, &base, 0x1000, false, 16,
+ 0, (addr_t)-1, 0, (addr_t)-1);
+
+ syslinux_assert(rv, "Shouldn't have allocated none existent region");
+
+bail:
+ syslinux_free_memmap(mmap);
+ return rv;
+}
+
+static int demote_free_region_to_terminal(void)
+{
+ enum syslinux_memmap_types type;
+ struct syslinux_memmap *mmap;
+ int rv = -1;
+ struct mmap_entry entries[] = {
+ { 0x100000, 0x300000, SMT_TERMINAL },
+ { 0x400000, 0x300000, SMT_FREE },
+ { 0x700000, 0x20000, SMT_FREE },
+ { 0x720000, 0x20000, SMT_TERMINAL },
+ };
+
+ mmap = test_build_mmap(entries, array_sz(entries));
+ if (!mmap)
+ goto bail;
+
+ type = syslinux_memmap_type(mmap, 0x100000, 0x500000);
+ syslinux_assert_str(type == SMT_TERMINAL,
+ "Expected SMT_TERMINAL + SMT_FREE region to cause type demotion");
+
+ type = syslinux_memmap_type(mmap, 0x700000, 0x40000);
+ syslinux_assert_str(type == SMT_TERMINAL,
+ "Expected SMT_FREE + SMT_TERMINAL region to cause type demotion");
+
+ type = syslinux_memmap_type(mmap, 0x100000, 0x640000);
+ syslinux_assert_str(type == SMT_TERMINAL,
+ "Expected multiple SMT_{FREE,TERMINAL} regions to cause type demotion");
+
+ rv = 0;
+
+bail:
+ syslinux_free_memmap(mmap);
+ return rv;
+}
+
+int main(int argc, char **argv)
+{
+ refuse_to_alloc_reserved_region();
+ refuse_to_alloc_above_max_address();
+
+ alloc_region_with_zero_size();
+
+ refuse_to_relocate_region();
+ only_relocate_upwards();
+
+ alloc_in_pxe_region();
+ demote_free_region_to_terminal();
+
+ return 0;
+}