From d04ca90f5c3aca60641b2ee63931d66f593bbbd3 Mon Sep 17 00:00:00 2001 From: Thiago de Arruda Date: Thu, 27 Feb 2014 16:57:06 -0300 Subject: [PATCH] Add basic infrastructure for unit testing Tests will be written using the [moonscript](http://moonscript.org/) language, a lua 'dialect' that is whitespace-significant and has a syntax similar to coffeescript. The test framework used is [busted](http://olivinelabs.com/busted/), a bdd framework for lua/moonscript. Luajit has a nice ffi module, which lets lua programs link shared libraries and call it's functions without writing any C code. To take advantage of this fact for testing C functions, a new target was added to CMakeLists.txt, which compiles neovim as a shared library that is loaded by the process running the tests. This commit adds necessary code for downloading and installing a lua package manager(luarocks) locally. It wasn't added as a subtree because there are quite a few blobs in its source tree. --- .gitignore | 17 +++++++++++++++++ Makefile | 11 ++++++++++- scripts/compile-lua.sh | 6 ++++++ scripts/setup-test-tools.sh | 22 +++++++++++++++++++++ scripts/unittest.sh | 6 ++++++ src/CMakeLists.txt | 5 +++++ test/unit/helpers.moon | 35 ++++++++++++++++++++++++++++++++++ test/unit/misc1.moon | 38 +++++++++++++++++++++++++++++++++++++ 8 files changed, 139 insertions(+), 1 deletion(-) create mode 100644 scripts/compile-lua.sh create mode 100644 scripts/setup-test-tools.sh create mode 100644 scripts/unittest.sh create mode 100644 test/unit/helpers.moon create mode 100644 test/unit/misc1.moon diff --git a/.gitignore b/.gitignore index 128b1b1481..aa5c6380e7 100644 --- a/.gitignore +++ b/.gitignore @@ -25,5 +25,22 @@ src/testdir/*.failed src/testdir/X* src/testdir/valgrind.* +# luarocks, not added as a subtree because of the large number of blobs +third-party/luarocks + +# luajit files +third-party/luajit/src/host/buildvm +third-party/luajit/src/host/buildvm_arch.h +third-party/luajit/src/host/minilua +third-party/luajit/src/jit/vmdef.lua +third-party/luajit/src/libluajit.a +third-party/luajit/src/lj_bcdef.h +third-party/luajit/src/lj_ffdef.h +third-party/luajit/src/lj_folddef.h +third-party/luajit/src/lj_libdef.h +third-party/luajit/src/lj_recdef.h +third-party/luajit/src/lj_vm.s +third-party/luajit/src/luajit + # local make targets local.mk diff --git a/Makefile b/Makefile index dcc8cc71ff..88c1364961 100644 --- a/Makefile +++ b/Makefile @@ -11,11 +11,20 @@ build/bin/nvim: deps test: build/bin/nvim cd src/testdir && make -deps: .deps/usr/lib/libuv.a +unittest: build/bin/nvim + sh -e scripts/unittest.sh + +deps: .deps/usr/lib/libuv.a .deps/usr/lib/libluajit-5.1.a .deps/usr/bin/busted .deps/usr/lib/libuv.a: sh -e scripts/compile-libuv.sh +.deps/usr/lib/libluajit-5.1.a: + sh -e scripts/compile-lua.sh + +.deps/usr/bin/busted: + sh -e scripts/setup-test-tools.sh + cmake: clean deps mkdir build cd build && cmake $(CMAKE_FLAGS) $(CMAKE_EXTRA_FLAGS) ../ diff --git a/scripts/compile-lua.sh b/scripts/compile-lua.sh new file mode 100644 index 0000000000..9187c07877 --- /dev/null +++ b/scripts/compile-lua.sh @@ -0,0 +1,6 @@ +. scripts/common.sh + +lua_dir="$pkgroot/third-party/luajit" + +cd "$lua_dir" +make PREFIX="$prefix" install diff --git a/scripts/setup-test-tools.sh b/scripts/setup-test-tools.sh new file mode 100644 index 0000000000..3e4a274f59 --- /dev/null +++ b/scripts/setup-test-tools.sh @@ -0,0 +1,22 @@ +. scripts/common.sh + +luarocks_ver=v2.1.2 +luarocks_repo=keplerproject/luarocks +luarocks_sha1=69ea9b641a5066b1f316847494d8c63a4693977d +luarocks_dir="$pkgroot/third-party/luarocks" + +github_download "$luarocks_repo" "$luarocks_ver" "$luarocks_dir" \ + "$luarocks_sha1" + +cd "$luarocks_dir" + +./configure --prefix="$prefix" --force-config --with-lua="$prefix" \ + --with-lua-include="$prefix/include/luajit-2.0" \ + --lua-suffix="jit" + +make bootstrap + +# install tools for testing +luarocks install moonrocks --server=http://rocks.moonscript.org +moonrocks install moonscript +moonrocks install busted diff --git a/scripts/unittest.sh b/scripts/unittest.sh new file mode 100644 index 0000000000..f792308275 --- /dev/null +++ b/scripts/unittest.sh @@ -0,0 +1,6 @@ +. scripts/common.sh + +(cd "$pkgroot/build" && make) || exit 1 +eval "$(luarocks path)" + +busted --pattern=.moon ./test diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 8c19098f1e..aa1100032a 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -13,6 +13,7 @@ list(APPEND NEOVIM_SOURCES "${PROJECT_BINARY_DIR}/config/auto/pathdef.c") file( GLOB OS_SOURCES os/*.c ) add_executable (nvim ${NEOVIM_SOURCES} ${OS_SOURCES}) +add_library (nvim-test SHARED ${NEOVIM_SOURCES} ${OS_SOURCES}) # The libraries we link against for nvim set(NVIM_LINK_LIBRARIES m ${LibUV_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT}) @@ -28,19 +29,23 @@ if (LibIntl_FOUND) endif() target_link_libraries (nvim ${NVIM_LINK_LIBRARIES}) +target_link_libraries (nvim-test ${NVIM_LINK_LIBRARIES}) include(CheckLibraryExists) check_library_exists(termcap tgetent "" HAVE_LIBTERMCAP) if (HAVE_LIBTERMCAP) target_link_libraries(nvim termcap) + target_link_libraries(nvim-test termcap) else() check_library_exists(curses tgetent "" HAVE_LIBCURSES) if (HAVE_LIBCURSES) target_link_libraries(nvim curses) + target_link_libraries(nvim-test curses) else() find_package(Curses REQUIRED) target_link_libraries(nvim ${CURSES_LIBRARIES}) + target_link_libraries(nvim-test ${CURSES_LIBRARIES}) endif() endif() diff --git a/test/unit/helpers.moon b/test/unit/helpers.moon new file mode 100644 index 0000000000..5705db88a6 --- /dev/null +++ b/test/unit/helpers.moon @@ -0,0 +1,35 @@ +ffi = require 'ffi' + +-- load neovim shared library +libnvim = ffi.load './build/src/libnvim-test.so' + +-- Luajit ffi parser only understands function signatures. +-- This helper function normalizes headers, passes to ffi and returns the +-- library pointer +cimport = (path) -> + -- Can't parse some of vim types, perhaps need to define those before + -- automatically importing to ffi + + -- header_file = io.open path, 'rb' + -- header = header_file\read '*a' + -- header_file.close! + -- header = string.gsub header, '#include[^\n]*\n', '' + -- header = string.gsub header, '#ifndef[^\n]*\n', '' + -- header = string.gsub header, '#define[^\n]*\n', '' + -- header = string.gsub header, '#endif[^\n]*\n', '' + -- ffi.cdef header + + return libnvim + +-- take a pointer to a C-allocated string and return an interned +-- version while also freeing the memory +internalize = (cdata) -> + ffi.gc cdata, ffi.C.free + return ffi.string cdata + +return { + cimport: cimport + internalize: internalize + eq: (expected, actual) -> assert.are.same expected, actual + ffi: ffi +} diff --git a/test/unit/misc1.moon b/test/unit/misc1.moon new file mode 100644 index 0000000000..dbcd192262 --- /dev/null +++ b/test/unit/misc1.moon @@ -0,0 +1,38 @@ +{:cimport, :internalize, :eq, :ffi} = require 'test.unit.helpers' + +misc1 = cimport './src/misc1.h' +cstr = ffi.typeof 'char[?]' + +-- TODO extract constants from vim.h + +describe 'misc1 function', -> + describe 'fullpathcmp', -> + ffi.cdef 'int fullpathcmp(char *s1, char *s2, int checkname);' + fullpathcmp = (s1, s2, cn) -> + s1 = cstr (string.len s1) + 1, s1 + s2 = cstr (string.len s2) + 1, s2 + misc1.fullpathcmp s1, s2, cn or 0 + + f1 = 'f1.o' + f2 = 'f2.o' + f3 = 'test/f1.o' + FPC_SAME = 1 + FPC_DIFF = 2 + FPC_NOTX = 4 + FPC_DIFFX = 6 + FPC_SAMEX = 7 + + before_each -> + -- create the three files that will be used in this spec + (io.open f1, 'w').close! + (io.open f2, 'w').close! + (io.open f3, 'w').close! + + after_each -> + os.remove f1 + os.remove f2 + os.remove f3 + + it 'returns FPC_SAME when passed the same file', -> + eq FPC_SAME, (fullpathcmp f1, f1) +