Merge branch 'master' into pr
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 53ef5a5..b050a18 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -424,11 +424,11 @@
 
 SET(srcdir ${CMAKE_CURRENT_SOURCE_DIR}/regress)
 SET(abs_srcdir ${CMAKE_CURRENT_SOURCE_DIR}/regress)
-SET(top_builddir ${CMAKE_BINARY_DIR})
+SET(top_builddir ${CMAKE_CURRENT_BINARY_DIR}) # used to find config.h
 
-CONFIGURE_FILE(regress/runtest.in ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/runtest @ONLY)
-FILE(COPY ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/runtest
-  DESTINATION ${CMAKE_BINARY_DIR}/regress
+CONFIGURE_FILE(regress/runtest.in ${CMAKE_CURRENT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/runtest @ONLY)
+FILE(COPY ${CMAKE_CURRENT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/runtest
+  DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/regress
   FILE_PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE
 )
 
diff --git a/appveyor.yml b/appveyor.yml
index 83e62e0..9954edf 100644
--- a/appveyor.yml
+++ b/appveyor.yml
@@ -1,31 +1,49 @@
 os:
 - Visual Studio 2017
+
 environment:
   matrix:
     - GENERATOR: "Visual Studio 15 2017 Win64"
       TRIPLET: x64-windows
       CMAKE_OPTS: "-DBUILD_SHARED_LIBS=off"
+      CMAKE_CONFIG: Release
+    - GENERATOR: "Visual Studio 15 2017 Win64"
+      TRIPLET: x64-windows
+      CMAKE_OPTS: "-DBUILD_SHARED_LIBS=off"
+      CMAKE_CONFIG: Debug
     - GENERATOR: "Visual Studio 15 2017 Win64"
       TRIPLET: x64-uwp
       CMAKE_OPTS: "-DCMAKE_SYSTEM_NAME=WindowsStore -DCMAKE_SYSTEM_VERSION=10.0"
+      CMAKE_CONFIG: Release
     - GENERATOR: "Visual Studio 15 2017"
       TRIPLET: x86-windows
       CMAKE_OPTS: "-DBUILD_SHARED_LIBS=off"
+      CMAKE_CONFIG: Release
+    - GENERATOR: "Visual Studio 15 2017"
+      TRIPLET: x86-windows
+      CMAKE_OPTS: "-DBUILD_SHARED_LIBS=off"
+      CMAKE_CONFIG: Debug
     - GENERATOR: "Visual Studio 15 2017"
       TRIPLET: x86-uwp
       CMAKE_OPTS: "-DCMAKE_SYSTEM_NAME=WindowsStore -DCMAKE_SYSTEM_VERSION=10.0"
+      CMAKE_CONFIG: Release
     - GENERATOR: "Visual Studio 15 2017 ARM"
       TRIPLET: arm-windows
       CMAKE_OPTS: "-DENABLE_OPENSSL=off"
+      CMAKE_CONFIG: Release
     - GENERATOR: "Visual Studio 15 2017 ARM"
       TRIPLET: arm-uwp
       CMAKE_OPTS: "-DCMAKE_SYSTEM_NAME=WindowsStore -DCMAKE_SYSTEM_VERSION=10.0 -DENABLE_OPENSSL=off"
+      CMAKE_CONFIG: Release
     - GENERATOR: "Visual Studio 15 2017"
       TRIPLET: arm64-windows
       CMAKE_OPTS: "-AARM64 -DENABLE_OPENSSL=off"
+      CMAKE_CONFIG: Release
     - GENERATOR: "Visual Studio 15 2017"
       TRIPLET: arm64-uwp
       CMAKE_OPTS: "-AARM64 -DCMAKE_SYSTEM_NAME=WindowsStore -DCMAKE_SYSTEM_VERSION=10.0 -DENABLE_OPENSSL=off"
+      CMAKE_CONFIG: Release
+
 before_build:
   cmd: >-
     git clone https://github.com/Microsoft/vcpkg
@@ -52,6 +70,12 @@
 
 build_script:
   cmd: >-
-    cmake --build . --config Release --target INSTALL
+    cmake --build . --config %CMAKE_CONFIG% --target INSTALL
 
-    cmake --build . --config Debug --target INSTALL
+    cmake --build . --config %CMAKE_CONFIG%
+
+test_script:
+  cmd: >-
+    set VERBOSE=yes
+
+    ctest -C %CMAKE_CONFIG% --output-on-failure
diff --git a/regress/CMakeLists.txt b/regress/CMakeLists.txt
index 39a3a2c..a43bf90 100644
--- a/regress/CMakeLists.txt
+++ b/regress/CMakeLists.txt
@@ -83,12 +83,12 @@
 	add_stored_in_memory.test
 	buffer-fragment-read.test
 	buffer-fragment-write.test
-        clone-buffer-add.test
-        clone-buffer-delete.test
-        clone-buffer-replace.test
-        clone-fs-add.test
-        clone-fs-delete.test
-        clone-fs-replace.test
+	clone-buffer-add.test
+	clone-buffer-delete.test
+	clone-buffer-replace.test
+	clone-fs-add.test
+	clone-fs-delete.test
+	clone-fs-replace.test
 	cm-default.test
 	count_entries.test
 	decrypt-correct-password-aes128.test
@@ -198,9 +198,17 @@
 	zip64_stored_creation.test
 )
 
+
+set(path "$<TARGET_FILE_DIR:zip>;$ENV{PATH}")
+if (TARGET zlib)
+  set(path "$<TARGET_FILE_DIR:zlib>;${path}")
+endif()
+string(REPLACE ";" "\\;" path "${path}")
+
 FOREACH(CASE ${EXTRA_TESTS})
-  ADD_TEST(${CASE} perl ${CMAKE_BINARY_DIR}/regress/runtest ${CMAKE_CURRENT_SOURCE_DIR}/${CASE})
+  ADD_TEST(NAME ${CASE} COMMAND perl ${CMAKE_CURRENT_BINARY_DIR}/runtest ${CMAKE_CURRENT_SOURCE_DIR}/${CASE})
   SET_TESTS_PROPERTIES(${CASE} PROPERTIES SKIP_RETURN_CODE 77)
+  SET_TESTS_PROPERTIES(${CASE} PROPERTIES ENVIRONMENT "PATH=${path}")
 ENDFOREACH()
 
 INCLUDE_DIRECTORIES(BEFORE ${CMAKE_CURRENT_SOURCE_DIR}/../lib ${CMAKE_CURRENT_SOURCE_DIR}/../src ${CMAKE_CURRENT_BINARY_DIR}/..)
diff --git a/regress/NiHTest.pm b/regress/NiHTest.pm
index 7272aed..2fce7f4 100644
--- a/regress/NiHTest.pm
+++ b/regress/NiHTest.pm
@@ -8,6 +8,7 @@
 use File::Path qw(mkpath remove_tree);
 use Getopt::Long qw(:config posix_default bundling no_ignore_case);
 use IPC::Open3;
+#use IPC::Cmd qw(run);
 use Storable qw(dclone);
 use Symbol 'gensym';
 use UNIVERSAL;
@@ -509,7 +510,8 @@
 sub comparator_zip {
 	my ($self, $got, $expected) = @_;
 
-	my @args = ($self->{zipcmp}, $self->{verbose} ? '-v' : '-q');
+	my $zipcmp = (-f $self->{zipcmp}) ? $self->{zipcmp} : $self->find_program('zipcmp');
+	my @args = ($zipcmp, $self->{verbose} ? '-v' : '-q');
 	push @args, $self->{zipcmp_flags} if ($self->{zipcmp_flags});
 	push @args, ($expected, $got);
 
@@ -740,7 +742,7 @@
 
 	for my $dir (('', "$self->{srcdir}/")) {
 		my $f = "$dir$fname";
-		$f = "../$f" if ($self->{in_sandbox} && $dir !~ m,^/,);
+		$f = "../$f" if ($self->{in_sandbox} && $dir !~ m,^(\w:)?/,);
 
 		return $f if (-f $f);
 	}
@@ -900,7 +902,7 @@
 	my %test = ();
 
 	while (my $line = <TST>) {
-		chomp $line;
+		$line =~ s/(\n|\r)//g;
 
 		next if ($line =~ m/^\#/);
 
@@ -1091,9 +1093,9 @@
 
 	return $ok;
 }
+
+
 sub args_decode {
-
-
 	my ($str, $srcdir) = @_;
 
 	if ($str =~ m/\\/) {
@@ -1135,13 +1137,31 @@
 }
 
 
+sub find_program() {
+	my ($self, $pname) = @_;
+
+	for my $up (('.', '..', '../..', '../../..', '../../../..')) {
+		for my $sub (('.', 'src')) {
+			for my $conf (('.', 'Debug', 'Release', 'Relwithdebinfo', 'Minsizerel')) {
+				for my $ext (('', '.exe')) {
+					my $f = "$up/$sub/$conf/$pname$ext";
+					return $f if (-f $f);
+				}
+			}
+		}
+	}
+
+	return undef;
+}
+
+
 sub run_program {
 	my ($self) = @_;
-	goto &pipein_win32 if $^O eq 'MSWin32' && $self->{test}->{pipein};
+	goto &pipein_win32 if (($^O eq 'MSWin32') or ($^O eq 'msys')) && $self->{test}->{pipein};
 	my ($stdin, $stdout, $stderr);
 	$stderr = gensym;
 
-	my @cmd = ('../' . $self->{test}->{program}, map ({ args_decode($_, $self->{srcdir}); } @{$self->{test}->{args}}));
+	my @cmd = ($self->find_program($self->{test}->{program}), map ({ args_decode($_, $self->{srcdir}); } @{$self->{test}->{args}}));
 
 	### TODO: catch errors?
 
@@ -1171,24 +1191,13 @@
         }
 
 	while (my $line = <$stdout>) {
-		if ($^O eq 'MSWin32') {
-			$line =~ s/[\r\n]+$//;
-		}
-		else {
-			chomp $line;
-		}
+		$line =~ s/(\n|\r)//g;
 		push @{$self->{stdout}}, $line;
 	}
 	my $prg = $self->{test}->{program};
 	$prg =~ s,.*/,,;
 	while (my $line = <$stderr>) {
-		if ($^O eq 'MSWin32') {
-			$line =~ s/[\r\n]+$//;
-		}
-		else {
-			chomp $line;
-		}
-
+		$line =~ s/(\n|\r)//g;
 		$line =~ s/^[^: ]*$prg(\.exe)?: //;
 		if (defined($self->{test}->{'stderr-replace'})) {
 			$line = $self->stderr_rewrite($self->{test}->{'stderr-replace'}, $line);
@@ -1204,7 +1213,9 @@
 sub pipein_win32() {
 	my ($self) = @_;
 
-	my $cmd = "$self->{test}->{pipein}| ..\\$self->{test}->{program} " . join(' ', map ({ args_decode($_, $self->{srcdir}); } @{$self->{test}->{args}}));
+	# TODO this is currently broken, IPC::Cmd::run fails to load
+	my $program = $self->find_program($self->{test}->{program});
+	my $cmd = "$self->{test}->{pipein} | $program " . join(' ', map ({ args_decode($_, $self->{srcdir}); } @{$self->{test}->{args}}));
 	my ($success, $error_message, $full_buf, $stdout_buf, $stderr_buf) = IPC::Cmd::run(command => $cmd);
 	if (!$success) {
 		### TODO: catch errors?
@@ -1276,10 +1287,9 @@
 sub sandbox_remove {
 	my ($self) = @_;
 
-	my $ok = 1;
 	remove_tree($self->{sandbox_dir});
 
-	return $ok;
+	return 1;
 }