summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--infrastructure/BoxPlatform.pm.in5
-rw-r--r--infrastructure/cmake/CMakeLists.txt98
-rwxr-xr-xruntest.pl.in208
3 files changed, 225 insertions, 86 deletions
diff --git a/infrastructure/BoxPlatform.pm.in b/infrastructure/BoxPlatform.pm.in
index 8f9daa81..bdcca279 100644
--- a/infrastructure/BoxPlatform.pm.in
+++ b/infrastructure/BoxPlatform.pm.in
@@ -127,6 +127,11 @@ BEGIN
$platform_link_line_extra = '-L/sw/lib ';
}
}
+
+ if ($target_windows)
+ {
+ $platform_exe_ext = '.exe';
+ }
}
sub make_flag
diff --git a/infrastructure/cmake/CMakeLists.txt b/infrastructure/cmake/CMakeLists.txt
index 2038b1c9..57de5039 100644
--- a/infrastructure/cmake/CMakeLists.txt
+++ b/infrastructure/cmake/CMakeLists.txt
@@ -55,6 +55,23 @@ set(files_to_configure
include(FindPerl)
set(TARGET_PERL ${PERL_EXECUTABLE})
+function(replace_file_if_different dest_file source_file)
+ execute_process(
+ COMMAND "${CMAKE_COMMAND}" -E
+ copy_if_different "${source_file}" "${dest_file}")
+ execute_process(
+ COMMAND "${CMAKE_COMMAND}" -E
+ remove "${source_file}")
+endfunction()
+
+function(move_file_if_exists source_file dest_file)
+ if(EXISTS "${source_file}")
+ execute_process(
+ COMMAND "${CMAKE_COMMAND}" -E
+ rename "${source_file}" "${dest_file}")
+ endif()
+endfunction()
+
foreach(file_to_configure ${files_to_configure})
configure_file("${base_dir}/${file_to_configure}.in" "${base_dir}/${file_to_configure}" @ONLY)
endforeach()
@@ -173,6 +190,18 @@ foreach(module_dep ${module_deps})
message(STATUS "add executable '${module_name}': '${module_files}'")
endif()
add_executable(${module_name} ${module_files})
+
+ # Unfortunately we have to use install(PROGRAMS) instead of
+ # install(TARGETS) because TARGETS doesn't allow us to change
+ # the executable name.
+ install(PROGRAMS "$<TARGET_FILE:${module_name}>"
+ CONFIGURATIONS Debug
+ DESTINATION "${base_dir}/debug/${module_dir}"
+ RENAME "${bin_name}${CMAKE_EXECUTABLE_SUFFIX}")
+ install(PROGRAMS "$<TARGET_FILE:${module_name}>"
+ CONFIGURATIONS Release
+ DESTINATION "${base_dir}/release/${module_dir}"
+ RENAME "${bin_name}${CMAKE_EXECUTABLE_SUFFIX}")
elseif(module_name MATCHES "^test_")
string(REGEX MATCH "^test_(.*)" valid_test ${module_name})
set(test_name ${CMAKE_MATCH_1})
@@ -183,12 +212,62 @@ foreach(module_dep ${module_deps})
endif()
string(REPLACE "TEST_NAME" ${test_name} test_main "${test_template}")
- file(WRITE "${module_path}/_main.cpp" "${test_main}")
+ file(WRITE "${module_path}/_main.cpp.new" "${test_main}")
+ replace_file_if_different(
+ "${module_path}/_main.cpp"
+ "${module_path}/_main.cpp.new")
add_executable(${module_name} ${module_files}
"${module_path}/_main.cpp")
+
+ if(WIN32)
+ install(PROGRAMS "$<TARGET_FILE:${module_name}>"
+ CONFIGURATIONS Debug
+ DESTINATION "${base_dir}/debug/${module_dir}")
+ install(PROGRAMS "$<TARGET_FILE:${module_name}>"
+ CONFIGURATIONS Release
+ DESTINATION "${base_dir}/release/${module_dir}")
+ set(test_executable "$<TARGET_FILE_NAME:${module_name}>")
+ else()
+ # Unfortunately we have to use install(PROGRAMS) instead of
+ # install(TARGETS) because TARGETS doesn't allow us to change
+ # the executable name.
+ install(PROGRAMS "$<TARGET_FILE:${module_name}>"
+ CONFIGURATIONS Debug
+ DESTINATION "${base_dir}/debug/${module_dir}"
+ RENAME "_test")
+ install(PROGRAMS "$<TARGET_FILE:${module_name}>"
+ CONFIGURATIONS Release
+ DESTINATION "${base_dir}/release/${module_dir}"
+ RENAME "_test")
+ set(test_executable "./_test")
+ endif()
+
+ if(${APPVEYOR_MODE})
+ set(appveyor_runtest_pl_switch -a)
+ else()
+ set(appveyor_runtest_pl_switch)
+ endif()
+
+ target_compile_definitions(${module_name} PRIVATE
+ -DTEST_EXECUTABLE="${test_executable}")
add_test(NAME ${test_name}
- COMMAND ${PERL_EXECUTABLE} ${base_dir}/runtest.pl.in ${test_name}
- $<CONFIG> WORKING_DIRECTORY ${base_dir})
+ COMMAND ${PERL_EXECUTABLE} ${base_dir}/runtest.pl
+ ${appveyor_runtest_pl_switch} -c ${test_name}
+ $<CONFIG> "$<TARGET_FILE:${module_name}>" "${test_executable}"
+ WORKING_DIRECTORY ${base_dir})
+
+ if(${APPVEYOR_MODE})
+ execute_process(COMMAND appveyor AddTest -Name ${test_name}
+ -Framework Custom -FileName "")
+ endif()
+
+ # It helps with debugging if the test depends on another step which
+ # prepares the target directory, and is always out of date.
+ add_custom_target(${module_name}-prepare
+ COMMAND ${PERL_EXECUTABLE} ${base_dir}/runtest.pl
+ -n -c ${test_name}
+ $<CONFIG> "$<TARGET_FILE:${module_name}>" "${test_executable}"
+ WORKING_DIRECTORY ${base_dir})
elseif(module_name MATCHES "^(lib_.*|qdbm)$")
if(DEBUG)
message(STATUS "add library '${module_name}': '${module_files}'")
@@ -198,19 +277,6 @@ foreach(module_dep ${module_deps})
message(FATAL_ERROR "Unsupported module type: " ${module_name})
endif()
- if(module_name MATCHES "^(bin|test)_")
- # We need to install binaries in specific places so that test
- # runner can find them:
- install(FILES "$<TARGET_FILE:${module_name}>"
- CONFIGURATIONS Debug
- DESTINATION "${base_dir}/debug/${module_dir}"
- RENAME "${bin_name}${CMAKE_EXECUTABLE_SUFFIX}")
- install(FILES "$<TARGET_FILE:${module_name}>"
- CONFIGURATIONS Release
- DESTINATION "${base_dir}/release/${module_dir}"
- RENAME "${bin_name}${CMAKE_EXECUTABLE_SUFFIX}")
- endif()
-
target_compile_definitions(${module_name} PRIVATE -DBOX_MODULE="${module_name}")
if(dependencies)
diff --git a/runtest.pl.in b/runtest.pl.in
index 2ab60963..a864336b 100755
--- a/runtest.pl.in
+++ b/runtest.pl.in
@@ -3,24 +3,44 @@
use strict;
use warnings;
+use Cwd;
use File::Basename;
use Getopt::Std;
chdir(dirname($0));
-use lib dirname($0).'/infrastructure';
+my $base_dir = getcwd();
+use lib dirname($0)."/infrastructure";
use BoxPlatform;
-my $prepare_only = 0;
-my $verbose_build = 0;
-our ($opt_n, $opt_v);
-getopts('nv');
+my %opts;
+getopts('acnv', \%opts);
# Don't actually run the test, just prepare for it.
-$prepare_only = $opt_n;
-$verbose_build = $opt_v;
+my $cmake_build = $opts{'c'};
+my $prepare_only = $opts{'n'};
+my $verbose_build = $opts{'v'};
+my $appveyor_mode = $opts{'a'};
+
+my $test_name = shift @ARGV;
+my $test_mode = shift @ARGV;
+my $test_src_exe;
+my $test_dst_exe;
+
+if($cmake_build)
+{
+ # To support different build environments (Windows/MSVC and Linux/Makefile) which
+ # place compiled executables in different locations, we need to accept the name of
+ # the compiled test executable as an additional command-line parameter.
+ die "test name is required in cmake mode" unless $test_name;
+ die "test mode is required in cmake mode" unless $test_mode;
+ die "only a single test name is supported in cmake mode" if $test_name =~ /,/;
+ $test_src_exe = shift @ARGV;
+ die "test project source executable path is required in cmake mode" unless $test_src_exe;
+ $test_dst_exe = shift @ARGV;
+ die "test project destination executable name is required in cmake mode" unless $test_dst_exe;
+}
-my ($test_name,$test_mode) = @ARGV;
$test_mode = 'debug' if not defined $test_mode or $test_mode eq '';
$test_mode = lc($test_mode);
@@ -52,7 +72,7 @@ if($test_name ne 'ALL')
}
else
{
- runtest($test_name);
+ runtest($test_name, $test_src_exe, $test_dst_exe);
}
}
else
@@ -107,47 +127,68 @@ __E
exit $exit_code;
+sub appveyor_test_status
+{
+ my ($test_name, $status, $duration, $message, $stdout) = @_;
+
+ if(!$appveyor_mode)
+ {
+ return;
+ }
+
+ # Assume that the test was already "Added" by CMakeLists.txt.
+ my $cmdline = "appveyor UpdateTest -Name $test_name -Framework Custom ".
+ "-FileName \"\" -Outcome $status";
+ if(defined $duration)
+ {
+ $cmdline .= " -Duration ".($duration * 1000);
+ }
+
+ if($message)
+ {
+ $cmdline .= " -ErrorMessage \"$message\"";
+ }
+
+ if(system($cmdline))
+ {
+ warn "AppVeyor test command failed: $cmdline";
+ }
+ else
+ {
+ print "Notified: $cmdline\n";
+ }
+}
+
sub runtest
{
- my ($t) = @_;
+ my ($t, $test_src_exe, $test_dst_exe) = @_;
# Attempt to make this test.
my $flag = ($test_mode eq 'release')?(BoxPlatform::make_flag('RELEASE')):'';
- my ($make_res, $test_project_exe);
+ my $make_res;
+ my $test_dst_dir = "$test_mode/test/$t";
+ my $start_time = time();
- if($target_msvc)
+ if($cmake_build)
{
- $test_project_exe = "test_$t";
- # Assume that MSVC projects are built with CMake, so we can use
- # MSBuild to run the tests.
- my $test_src_dir = "test\\$t";
- my $test_dst_dir = "$test_mode\\test\\$t";
- my $quiet = $verbose_build ? "" : "/consoleloggerparameters:ErrorsOnly";
+ appveyor_test_status($t, "Running", 0);
+
+ # Test executables have a different name on Windows to work around
+ # restrictions on running different executables with the same name.
+ my $test_src_dir = "test/$t";
my @commands = (
- "msbuild /nologo $quiet ".
- "infrastructure\\cmake\\build\\INSTALL.vcxproj",
- "xcopy /s /i /y /q $test_src_dir $test_dst_dir",
- "copy infrastructure\\cmake\\build\\$test_mode\\$test_project_exe.exe $test_dst_dir"
+ "cmake -E remove_directory $test_dst_dir",
+ "cmake -E copy_directory $test_src_dir $test_dst_dir",
+ "cmake -E copy $test_src_exe $test_dst_dir/$test_dst_exe",
+ # We could do a "make install" here, to ensure that everything
+ # is up to date, but it's really slow, verbose and wasteful:
+ # "cmake --build infrastructure/cmake/build --target install",
);
- if(-d $test_dst_dir)
- {
- unshift @commands, "rd /s /q $test_dst_dir";
- }
-
- foreach my $command (@commands)
- {
- $make_res = system($command);
- if ($make_res != 0)
- {
- push @results, "$t: make failed: $command";
- last;
- }
- }
-
- # Windows doesn't support testextra files either, so fake it.
- if ($make_res == 0 and -r "$test_src_dir/testextra")
+ # Our CMake buildsystem doesn't do anything to support testextra files
+ # (Makfile syntax), so fake it.
+ if (-r "$test_src_dir/testextra")
{
open EXTRA, "$test_src_dir/testextra"
or die "$test_src_dir/testextra: $!";
@@ -156,29 +197,17 @@ sub runtest
chomp $line;
if ($line =~ m/^mkdir (.*)/)
{
- mkdir("$test_dst_dir/$1")
- or die "$test_dst_dir/$1: $!";
+ push @commands, "cmake -E make_directory $test_dst_dir/$1";
}
elsif ($line =~ m/^rm -rf (.*)/)
{
- if(-d "$test_dst_dir\\$1")
- {
- my $cmd = "rd /s/q $test_dst_dir\\$1";
- my $status = system($cmd);
- $status == 0 or die "$cmd: failed with ".
- "status $status";
- }
+ push @commands, "cmake -E remove_directory $test_dst_dir/$1";
}
- elsif ($line =~ m/^cp (.*) (.*)/)
+ elsif ($line =~ m/^cp (.*)\*\.\* (.*)/)
{
my ($src, $dst) = ($1, $2);
- $src =~ s|/|\\|g;
- $dst =~ s|/|\\|g;
- my $cmd = "xcopy /s /i /y /q ".
- "$test_dst_dir\\$src $test_dst_dir\\$dst";
- my $status = system($cmd);
- $status == 0 or die "$cmd: failed with ".
- "status $status";
+ push @commands, "cmake -E copy_directory ".
+ "$test_dst_dir/$src $test_dst_dir/$dst";
}
else
{
@@ -187,16 +216,31 @@ sub runtest
}
}
}
+
+ foreach my $command (@commands)
+ {
+ $make_res = system($command);
+ if ($make_res != 0)
+ {
+ push @results, "$t: pre-test command failed: $command";
+ appveyor_test_status($t, "NotRunnable", time() - $start_time,
+ "pre-test command failed: $command");
+ last;
+ }
+ }
}
else
{
my $quiet = $verbose_build ? "VERBOSE=1" : "";
$make_res = system("cd test/$t && $make_command $quiet $flag");
+ $test_dst_exe = "_test$platform_exe_ext";
}
if($make_res != 0)
{
push @results,"$t: make failed";
+ appveyor_test_status($t, "NotRunnable", time() - $start_time,
+ "pre-test commands failed");
$exit_code = 2;
return;
}
@@ -206,17 +250,21 @@ sub runtest
if($prepare_only)
{
+ appveyor_test_status($t, "Skipped", time() - $start_time,
+ "we are only preparing this test");
return;
}
# run it
- if($target_msvc)
+ if($cmake_build)
{
- # no tee.exe, so let's do it ourselves.
+ # no tee.exe on Windows, so let's do it ourselves.
open LOG, ">$logfile" or die "$logfile: $!";
- chdir("$test_mode/test/$t");
- open TEE, "$test_project_exe.exe |"
- or die "$test_project_exe.exe: $!";
+ chdir("$base_dir/$test_mode/test/$t");
+
+ open TEE, "$test_dst_exe |"
+ or die "$test_dst_dir/$test_dst_exe: $!";
+
while (my $line = <TEE>)
{
print $line;
@@ -224,11 +272,12 @@ sub runtest
}
close LOG;
close TEE;
- chdir("../../..");
+ chdir($base_dir);
}
else
{
- $test_res = system("cd $test_mode/test/$t ; ./t 2>&1 " .
+ chdir($base_dir);
+ $test_res = system("cd $test_mode/test/$t ; sh t 2>&1 " .
"| tee ../../../$logfile");
}
@@ -242,19 +291,38 @@ sub runtest
}
close RESULTS;
- chomp $last;
- $last =~ s/\r//;
- push @results, "$t: $last";
-
- if ($last ne "PASSED")
- {
+ if(!defined $last)
+ {
+ push @results, "$t: test produced no output";
+ appveyor_test_status($t, "Failed", time() - $start_time,
+ "test produced no output");
$exit_code = 1;
}
+ else
+ {
+ chomp $last;
+ $last =~ s/\r//;
+ push @results, "$t: $last";
+
+ if ($last ne "PASSED")
+ {
+ $exit_code = 1;
+ appveyor_test_status($t, "Failed", time() - $start_time,
+ "test ended with: $last");
+ }
+ else
+ {
+ appveyor_test_status($t, "Passed", time() - $start_time);
+ }
+ }
}
else
{
+ my $cwd = getcwd();
push @results,
- "$t: failed to open test log file: $logfile: $!";
+ "$t: failed to open test log file: $logfile: $! (in $cwd)";
+ appveyor_test_status($t, "Inconclusive", time() - $start_time,
+ "failed to open test log file: $logfile: $!");
}
# delete test results