add initial test infrastructure
parent
de4a0c65c7
commit
c42e58b868
20
.ci/build-cs
20
.ci/build-cs
|
@ -136,11 +136,29 @@ cd build
|
||||||
|
|
||||||
args=""
|
args=""
|
||||||
if [ -n "${cross}" ]; then
|
if [ -n "${cross}" ]; then
|
||||||
|
if [ "${meson_system}" = "windows" ]; then
|
||||||
|
cat << EOF > meson-exewrapper
|
||||||
|
#!/bin/sh
|
||||||
|
export WINEDEBUG=-all
|
||||||
|
export WINEPREFIX="$(pwd)/.wine"
|
||||||
|
export DISPLAY=
|
||||||
|
wine "\$@"
|
||||||
|
EOF
|
||||||
|
else
|
||||||
|
cat << EOF > meson-exewrapper
|
||||||
|
#!/bin/sh
|
||||||
|
qemu-${qemu_cpu} -L /usr/${expected_triplet} "\$@"
|
||||||
|
EOF
|
||||||
|
fi
|
||||||
|
chmod +x meson-exewrapper
|
||||||
cat << EOF > crossfile
|
cat << EOF > crossfile
|
||||||
[binaries]
|
[binaries]
|
||||||
c = '${CC}'
|
c = '${CC}'
|
||||||
cpp = '${CXX}'
|
cpp = '${CXX}'
|
||||||
|
ar = '${AR}'
|
||||||
|
as = '${AS}'
|
||||||
strip = '${STRIP}'
|
strip = '${STRIP}'
|
||||||
|
exe_wrapper = '$(pwd)/meson-exewrapper'
|
||||||
|
|
||||||
[host_machine]
|
[host_machine]
|
||||||
system = '${meson_system}'
|
system = '${meson_system}'
|
||||||
|
@ -154,7 +172,7 @@ if [ -n "$BUILDTYPE" ]; then
|
||||||
args="${args} --buildtype=$BUILDTYPE"
|
args="${args} --buildtype=$BUILDTYPE"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
meson .. ${args} || exit 1
|
meson .. -Dtests_cross=true ${args} || exit 1
|
||||||
ninja all || exit 1
|
ninja all || exit 1
|
||||||
ninja test || exit 1
|
ninja test || exit 1
|
||||||
cd ..
|
cd ..
|
||||||
|
|
12
meson.build
12
meson.build
|
@ -47,10 +47,22 @@ if get_option('cpp_std') == 'none'
|
||||||
endif
|
endif
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
build_root = meson.current_build_dir()
|
||||||
|
|
||||||
subdir('include')
|
subdir('include')
|
||||||
subdir('src')
|
subdir('src')
|
||||||
subdir('tools')
|
subdir('tools')
|
||||||
|
|
||||||
|
if meson.is_cross_build() and get_option('tests')
|
||||||
|
build_tests = get_option('tests_cross')
|
||||||
|
else
|
||||||
|
build_tests = get_option('tests')
|
||||||
|
endif
|
||||||
|
|
||||||
|
if build_tests
|
||||||
|
subdir('tests')
|
||||||
|
endif
|
||||||
|
|
||||||
pkg = import('pkgconfig')
|
pkg = import('pkgconfig')
|
||||||
|
|
||||||
pkg.generate(
|
pkg.generate(
|
||||||
|
|
|
@ -9,3 +9,15 @@ option('linenoise',
|
||||||
value: 'auto',
|
value: 'auto',
|
||||||
description: 'Use linenoise for the REPL'
|
description: 'Use linenoise for the REPL'
|
||||||
)
|
)
|
||||||
|
|
||||||
|
option('tests',
|
||||||
|
type: 'boolean',
|
||||||
|
value: 'true',
|
||||||
|
description: 'Whether to build tests'
|
||||||
|
)
|
||||||
|
|
||||||
|
option('tests_cross',
|
||||||
|
type: 'boolean',
|
||||||
|
value: 'false',
|
||||||
|
description: 'Whether to build tests when cross-compiling'
|
||||||
|
)
|
||||||
|
|
|
@ -0,0 +1,38 @@
|
||||||
|
lang_tests = [
|
||||||
|
# test_name test_file expected_fail
|
||||||
|
['simple example', 'simple', false],
|
||||||
|
]
|
||||||
|
|
||||||
|
lib_tests = [
|
||||||
|
]
|
||||||
|
|
||||||
|
test_runner = executable('runner',
|
||||||
|
['runner.cc'],
|
||||||
|
dependencies: libcubescript,
|
||||||
|
include_directories: libcubescript_includes,
|
||||||
|
cpp_args: extra_cxxflags,
|
||||||
|
install: false
|
||||||
|
)
|
||||||
|
|
||||||
|
penv = environment()
|
||||||
|
penv.append('PATH', join_paths(build_root, 'src'))
|
||||||
|
|
||||||
|
foreach tcase: lang_tests
|
||||||
|
test(tcase[0],
|
||||||
|
test_runner,
|
||||||
|
args: [join_paths(meson.current_source_dir(), tcase[1] + '.cube')],
|
||||||
|
should_fail: tcase[2],
|
||||||
|
env: penv
|
||||||
|
)
|
||||||
|
endforeach
|
||||||
|
|
||||||
|
foreach tcase: lib_tests
|
||||||
|
test_exe = executable(tcase[0],
|
||||||
|
[tcase[0] + '.cc'],
|
||||||
|
dependencies: libcubescript,
|
||||||
|
include_directories: libcubescript_includes,
|
||||||
|
cpp_args: extra_cxxflags,
|
||||||
|
instalL: false
|
||||||
|
)
|
||||||
|
test(tcase[0], tcase[0], should_fail: tcase[1], env: penv)
|
||||||
|
endforeach
|
|
@ -0,0 +1,89 @@
|
||||||
|
/* a rudimentary test runner for cubescript files */
|
||||||
|
|
||||||
|
#include <cstdio>
|
||||||
|
#include <string>
|
||||||
|
#include <string_view>
|
||||||
|
|
||||||
|
#include <cubescript/cubescript.hh>
|
||||||
|
|
||||||
|
namespace cs = cubescript;
|
||||||
|
|
||||||
|
struct skip_test {};
|
||||||
|
|
||||||
|
static bool do_run_file(cs::state &cs, char const *fname) {
|
||||||
|
FILE *f = std::fopen(fname, "rb");
|
||||||
|
if (!f) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::fseek(f, 0, SEEK_END);
|
||||||
|
auto len = std::ftell(f);
|
||||||
|
std::fseek(f, 0, SEEK_SET);
|
||||||
|
|
||||||
|
auto buf = std::make_unique<char[]>(len + 1);
|
||||||
|
if (!buf) {
|
||||||
|
std::fclose(f);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (std::fread(buf.get(), 1, len, f) != std::size_t(len)) {
|
||||||
|
std::fclose(f);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
buf[len] = '\0';
|
||||||
|
|
||||||
|
cs.run(std::string_view{buf.get(), std::size_t(len)}, fname);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char **argv) {
|
||||||
|
if (argc != 2) {
|
||||||
|
std::fprintf(stderr, "error: incorrect number of arguments\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
cs::state gcs;
|
||||||
|
cs::std_init_all(gcs);
|
||||||
|
|
||||||
|
gcs.new_command("echo", "C", [](auto &s, auto args, auto &) {
|
||||||
|
std::printf("%s\n", args[0].get_string(s).view().data());
|
||||||
|
});
|
||||||
|
|
||||||
|
gcs.new_command("skip_test", "", [](auto &, auto, auto &) {
|
||||||
|
throw skip_test{};
|
||||||
|
});
|
||||||
|
|
||||||
|
/* takes a string so we can print it */
|
||||||
|
gcs.new_command("assert", "ssN", [](auto &s, auto args, auto &ret) {
|
||||||
|
auto val = args[0];
|
||||||
|
val.force_code(s);
|
||||||
|
if (!s.run(val.get_code()).get_bool()) {
|
||||||
|
if (args[2].get_integer() > 1) {
|
||||||
|
throw cs::error{
|
||||||
|
s, "assertion failed: [%s] (%s)",
|
||||||
|
args[0].get_string(s).data(), args[1].get_string(s).data()
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
throw cs::error{
|
||||||
|
s, "assertion failed: [%s]",
|
||||||
|
args[0].get_string(s).data()
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ret = std::move(args[0]);
|
||||||
|
});
|
||||||
|
|
||||||
|
try {
|
||||||
|
do_run_file(gcs, argv[1]);
|
||||||
|
} catch (skip_test) {
|
||||||
|
return 77;
|
||||||
|
} catch (cs::error const &e) {
|
||||||
|
std::fprintf(stderr, "error: %s", e.what().data());
|
||||||
|
return 1;
|
||||||
|
} catch (...) {
|
||||||
|
std::fprintf(stderr, "error: unknown error");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
|
@ -0,0 +1,21 @@
|
||||||
|
// a simple test mainly to serve as an example
|
||||||
|
|
||||||
|
echo "hello world"
|
||||||
|
|
||||||
|
// addition
|
||||||
|
assert [= (+ 5 10) 15]
|
||||||
|
assert [!= (+ 4 5) 11]
|
||||||
|
|
||||||
|
// multiplication
|
||||||
|
assert [= (* 5 2) 10]
|
||||||
|
assert [!= (* 3 4) 13]
|
||||||
|
|
||||||
|
// string equality
|
||||||
|
assert [=s "hello world" "hello world"]
|
||||||
|
assert [!=s "hello world" "dlrow olleh"]
|
||||||
|
|
||||||
|
// simple loop
|
||||||
|
x = 5
|
||||||
|
loop i 3 [x = (* $x 2); echo $x]
|
||||||
|
|
||||||
|
assert [= $x 40]
|
Loading…
Reference in New Issue