From 33d245d0f7687bcab13747ffd5548b89fd8c8796 Mon Sep 17 00:00:00 2001 From: Joshua Warner Date: Thu, 14 Feb 2013 20:54:20 -0700 Subject: [PATCH] add unittest framework --- makefile | 48 +++++++++++++++++++++-- test/test.sh | 13 ++++++- unittest/codegen/assembler-test.cpp | 37 ++++++++++++++++++ unittest/test-harness.cpp | 53 +++++++++++++++++++++++++ unittest/test-harness.h | 60 +++++++++++++++++++++++++++++ 5 files changed, 206 insertions(+), 5 deletions(-) create mode 100644 unittest/codegen/assembler-test.cpp create mode 100644 unittest/test-harness.cpp create mode 100644 unittest/test-harness.h diff --git a/makefile b/makefile index 5ee56d857b..2f766eb2b2 100755 --- a/makefile +++ b/makefile @@ -64,6 +64,7 @@ test-build = $(build)/test src = src classpath-src = classpath test = test +unittest = unittest win32 ?= $(root)/win32 win64 ?= $(root)/win64 winrt ?= $(root)/winrt @@ -997,6 +998,8 @@ heapwalk-sources = $(src)/heapwalk.cpp heapwalk-objects = \ $(call cpp-objects,$(heapwalk-sources),$(src),$(build)) +unittest-objects = $(call cpp-objects,$(unittest-sources),$(unittest),$(build)/unittest/) + ifeq ($(heapdump),true) vm-sources += $(src)/heapdump.cpp vm-heapwalk-objects = $(heapwalk-objects) @@ -1124,6 +1127,8 @@ executable = $(build)/$(name)${exe-suffix} dynamic-library = $(build)/$(so-prefix)jvm$(so-suffix) executable-dynamic = $(build)/$(name)-dynamic$(exe-suffix) +unittest-executable = $(build)/$(name)-unittest${exe-suffix} + ifneq ($(classpath),avian) # Assembler, ConstantPool, and Stream are not technically needed for a # working build, but we include them since our Subroutine test uses @@ -1181,6 +1186,13 @@ test-extra-classes = \ $(call java-classes,$(test-extra-sources),$(test),$(test-build)) test-extra-dep = $(test-build)-extra.dep +unittest-sources = \ + $(wildcard $(unittest)/*.cpp) \ + $(wildcard $(unittest)/codegen/*.cpp) + +unittest-depends = \ + $(wildcard $(unittest)/*.h) + ifeq ($(continuations),true) continuation-tests = \ extra.Continuations \ @@ -1256,11 +1268,11 @@ vg: build $(library-path) $(vg) $(test-executable) $(test-args) .PHONY: test -test: build $(build)/run-tests.sh $(build)/test.sh +test: build $(build)/run-tests.sh $(build)/test.sh $(unittest-executable) ifneq ($(remote-test),true) /bin/sh $(build)/run-tests.sh else - @echo "testing remotely..." $(arch) $(target-arch) + @echo "testing remotely..." rsync $(build) -rav --exclude '*.o' --rsh="ssh -p$(remote-test-port)" $(remote-test-user)@$(remote-test-host):$(remote-test-dir) ssh -p$(remote-test-port) $(remote-test-user)@$(remote-test-host) sh "$(remote-test-dir)/$(platform)-$(arch)$(options)/run-tests.sh" endif @@ -1297,7 +1309,7 @@ endif $(build)/run-tests.sh: $(test-classes) makefile echo 'cd $$(dirname $$0)' > $(@) echo "sh ./test.sh 2>/dev/null \\" >> $(@) - echo "$(shell echo $(library-path) | sed 's|$(build)|\.|g') ./$(name)${exe-suffix} $(mode) \"-Djava.library.path=$$(pwd) -cp test\" log.txt \\" >> $(@) + echo "$(shell echo $(library-path) | sed 's|$(build)|\.|g') ./$(name)-unittest${exe-suffix} ./$(name)${exe-suffix} $(mode) \"-Djava.library.path=$$(pwd) -cp test\" \\" >> $(@) echo "$(call class-names,$(test-build),$(filter-out $(test-support-classes), $(test-classes))) \\" >> $(@) echo "$(continuation-tests) $(tail-tests)" >> $(@) @@ -1356,9 +1368,18 @@ define compile-asm-object $(as) $(asmflags) $(call asm-output,$(@)) $(call asm-input,$(<)) endef +define compile-unittest-object + @echo "compiling $(@)" + @mkdir -p $(dir $(@)) + $(cxx) $(cflags) -c $$($(windows-path) -I$(unittest) $(<)) $(call output,$(@)) +endef + $(vm-cpp-objects): $(build)/%.o: $(src)/%.cpp $(vm-depends) $(compile-object) +$(unittest-objects): $(build)/unittest/%.o: $(unittest)/%.cpp $(vm-depends) $(unittest-depends) + $(compile-unittest-object) + $(test-cpp-objects): $(test-build)/%.o: $(test)/%.cpp $(vm-depends) $(compile-object) @@ -1531,6 +1552,8 @@ executable-objects = $(vm-objects) $(classpath-objects) $(driver-object) \ $(vm-heapwalk-objects) $(boot-object) $(vm-classpath-objects) \ $(javahome-object) $(boot-javahome-object) $(lzma-decode-objects) +unittest-executable-objects = $(unittest-objects) $(vm-objects) + $(executable): $(executable-objects) @echo "linking $(@)" ifeq ($(platform),windows) @@ -1550,6 +1573,25 @@ else endif $(strip) $(strip-all) $(@) + +$(unittest-executable): $(unittest-executable-objects) + @echo "linking $(@)" +ifeq ($(platform),windows) +ifdef ms_cl_compiler + $(ld) $(lflags) $(unittest-executable-objects) -out:$(@) \ + -debug -PDB:$(subst $(exe-suffix),.pdb,$(@)) $(manifest-flags) +ifdef mt + $(mt) -nologo -manifest $(@).manifest -outputresource:"$(@);1" +endif +else + $(dlltool) -z $(@).def $(unittest-executable-objects) + $(dlltool) -d $(@).def -e $(@).exp + $(ld) $(@).exp $(unittest-executable-objects) $(lflags) -o $(@) +endif +else + $(ld) $(unittest-executable-objects) $(rdynamic) $(lflags) $(bootimage-lflags) -o $(@) +endif + $(bootimage-generator): $(bootimage-generator-objects) echo building $(bootimage-generator) arch=$(build-arch) platform=$(bootimage-platform) $(MAKE) mode=$(mode) \ diff --git a/test/test.sh b/test/test.sh index 2dc26b4ef3..e30e90c1cb 100644 --- a/test/test.sh +++ b/test/test.sh @@ -4,20 +4,29 @@ vg="nice valgrind --leak-check=full --num-callers=32 \ --freelist-vol=100000000 --error-exitcode=1" ld_path=${1}; shift +unit_tester=${1}; shift vm=${1}; shift mode=${1}; shift flags=${1}; shift -log=${1}; shift tests=${@} +log=log.txt + export ${ld_path} echo -n "" >${log} +printf "%12s------- Unit tests -------\n" "" +${unit_tester} 2>>${log} +if [ "${?}" != "0" ]; then + trouble=1 +fi + echo +printf "%12s------- Java tests -------\n" "" for test in ${tests}; do - printf "%24s" "${test}: " + printf "%24s: " "${test}" case ${mode} in debug|debug-fast|fast|small ) diff --git a/unittest/codegen/assembler-test.cpp b/unittest/codegen/assembler-test.cpp new file mode 100644 index 0000000000..d7d09a72d3 --- /dev/null +++ b/unittest/codegen/assembler-test.cpp @@ -0,0 +1,37 @@ +/* Copyright (c) 2008-2011, Avian Contributors + + Permission to use, copy, modify, and/or distribute this software + for any purpose with or without fee is hereby granted, provided + that the above copyright notice and this permission notice appear + in all copies. + + There is NO WARRANTY for this software. See license.txt for + details. */ + +#include + +#include "common.h" +#include "codegen/assembler.h" +#include "codegen/targets.h" + +#include "test-harness.h" + +#include "system.h" + + +using namespace avian::codegen; +using namespace vm; + +class BasicAssemblerTest : public Test { +public: + BasicAssemblerTest(): + Test("BasicAssemblerTest") + {} + + virtual void run() { + System* s = makeSystem(0); + Assembler::Architecture* arch = makeArchitectureNative(s, true); + arch->release(); + s->dispose(); + } +} basicAssemblerTest; diff --git a/unittest/test-harness.cpp b/unittest/test-harness.cpp new file mode 100644 index 0000000000..30472298ba --- /dev/null +++ b/unittest/test-harness.cpp @@ -0,0 +1,53 @@ +/* Copyright (c) 2008-2011, Avian Contributors + + Permission to use, copy, modify, and/or distribute this software + for any purpose with or without fee is hereby granted, provided + that the above copyright notice and this permission notice appear + in all copies. + + There is NO WARRANTY for this software. See license.txt for + details. */ + +#include + +#include "common.h" +#include "test-harness.h" + +// since we aren't linking against libstdc++, we must implement this +// ourselves: +extern "C" void __cxa_pure_virtual(void) { abort(); } + +Test* Test::first = 0; +Test** Test::last = &first; + +Test::Test(const char* name): + next(0), + failures(0), + runs(0), + name(name) +{ + *last = this; + last = &next; +} + +bool Test::runAll() { + int failures = 0; + for(Test* t = Test::first; t; t = t->next) { + printf("%24s: ", t->name); + t->run(); + failures += t->failures; + if(t->failures > 0) { + printf("failure\n"); + } else { + printf("success\n"); + } + } + return failures == 0; +} + +int main(int argc UNUSED, char** argv UNUSED) { + if(Test::runAll()) { + return 0; + } + return 1; +} \ No newline at end of file diff --git a/unittest/test-harness.h b/unittest/test-harness.h new file mode 100644 index 0000000000..e977c95c02 --- /dev/null +++ b/unittest/test-harness.h @@ -0,0 +1,60 @@ +/* Copyright (c) 2008-2011, Avian Contributors + + Permission to use, copy, modify, and/or distribute this software + for any purpose with or without fee is hereby granted, provided + that the above copyright notice and this permission notice appear + in all copies. + + There is NO WARRANTY for this software. See license.txt for + details. */ + +#ifndef ARCH_H +#define ARCH_H + +class Test { +private: + Test* next; + static Test* first; + static Test** last; + + friend int main(int argc, char** argv); + + void print(uintptr_t value) { + fprintf(stderr, "%p", reinterpret_cast(value)); + } + + void print(bool value) { + fprintf(stderr, "%s", value ? "true" : "false"); + } + + int failures; + int runs; + +protected: + template + void assertEquals(T expected, T actual) { + if(expected != actual) { + fprintf(stderr, "assertion failure, expected: "); + print(expected); + fprintf(stderr, ", actual: "); + print(actual); + fprintf(stderr, "\n"); + failures++; + } + runs++; + } + + void assertTrue(bool value) { + assertEquals(true, value); + } + +public: + const char* const name; + Test(const char* name); + + virtual void run() = 0; + + static bool runAll(); +}; + +#endif \ No newline at end of file