The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.
use strict;
use warnings;

use File::Spec;
use Test::More;
use Fcntl ();

select STDERR;
$|=1;
select STDOUT;

$ENV{PATH} = '/usr/bin:/bin' if ${^TAINT};

# tests don't work in parallel
flock DATA, Fcntl::LOCK_EX();

sub is_windows { $^O =~ /MSWin32/i }

sub sftp_server {
    my ($sscmd, @ssh, $ssname);

    $sscmd = $ENV{NET_SFTP_FOREIGN_TESTING_SFTP_SERVER_PATH};
    return $sscmd if defined $sscmd;

    if(is_windows) {
	$ssname = 'sftp-server.exe';
	my $pf;
	eval {
	    require Win32;
	    $pf = Win32::GetFolderPath(Win32::CSIDL_PROGRAM_FILES());
	};
	$pf = "C:/Program Files/" unless defined $pf;

	@ssh = ("$pf/openssh/bin/ssh.exe",
		"$pf/openssh/usr/bin/ssh.exe",
		"$pf/bin/ssh.exe",
		"$pf/usr/bin/ssh.exe");
    }
    else {
	$ssname = 'sftp-server';
	@ssh = qw( /usr/bin/ssh
		   /usr/local/bin/ssh
		   /usr/local/openssh/bin/ssh
		   /opt/openssh/bin/ssh
                   /opt/ssh/bin/ssh );
    }

    if (eval {require File::Which; 1}) {
	unshift @ssh, File::Which::where('ssh');
    }
    elsif ($^O !~ /MSWin32/i) {
	chomp(my $ssh = `which ssh`);
	unshift @ssh, $ssh if (!$? and $ssh);
    }

 SEARCH: for (@ssh) {
	my ($vol, $dir) = File::Spec->splitpath($_);

	my $up = File::Spec->rel2abs(File::Spec->catpath($vol, $dir, File::Spec->updir));

	for ( File::Spec->catfile($vol, $dir, $ssname),
	      File::Spec->catfile($up, 'lib', $ssname),
              File::Spec->catfile($up, 'lib64', $ssname),
	      File::Spec->catfile($up, 'libexec', $ssname),
	      File::Spec->catfile($up, 'libexec', 'openssh', $ssname),
	      File::Spec->catfile($up, 'sbin', $ssname),
	      File::Spec->catfile($up, 'lib', 'openssh', $ssname),
              File::Spec->catfile($up, 'lib64', 'openssh', $ssname),
              File::Spec->catfile($up, 'lib', 'misc', $ssname),
              File::Spec->catfile($up, 'lib64', 'misc', $ssname),
	      File::Spec->catfile($up, 'usr', 'lib', $ssname),
              File::Spec->catfile($up, 'usr', 'lib64', $ssname),
	      File::Spec->catfile($up, 'usr', 'libexec', $ssname),
	      File::Spec->catfile($up, 'usr', 'sbin', $ssname) ) {

	    if (-x $_) {
		$sscmd = $_;
		last SEARCH;
	    }
	}
    }

    return $sscmd;
}

sub filediff {
    my ($a, $b) = @_;
    open my $fa, "<", $a or do {
        diag "unable to open file $a";
        return;
    };
    open my $fb, "<", $b or do {
        diag "unable to open file $b";
        return;
    };

    binmode $fa;
    binmode $fb;

    while (1) {
	my $la = read($fa, my $da, 2048);
	my $lb = read($fb, my $db, 2048);
	return 1 unless (defined $la and defined $lb);
	return 1 if $la != $lb;
	return 0 if $la == 0;
	return 1 if $la ne $lb;
    }
}

sub mktestfile {
    my ($fn, $count, $data) = @_;

    open DL, '>', $fn
	or die "unable to create test data file $fn";

    print DL $data for (1..$count);
    close DL;
}

sub new_args {
    my $host = $ENV{NET_SFTP_FOREIGN_TESTING_HOST}; # = 'localhost';
    my $backend = $ENV{NET_SFTP_FOREIGN_TESTING_BACKEND};
    my @diag;

    my @args = (timeout => 20);
    if (defined $backend) {
        push @args, backend => $backend;
        push @diag, "using $backend backend";
    }
    if (defined $host) {
        push @diag, "connecting to host $host";
        push @args, host => $host;
    }
    else {
        my $ss_cmd = sftp_server;
        defined $ss_cmd or plan skip_all => 'sftp-server not found';
        push @diag, "sftp-server found at $ss_cmd";

        if ($ENV{NET_SFTP_FOREIGN_TESTING_WITH_WINE}) {
            push @diag, "running it with wine!";
            $ss_cmd = [wine => $ss_cmd];
        }

        push @args, open2_cmd => $ss_cmd;
    }
    diag join(", ", @diag) if @diag;
    @args;
}

sub dump_error {
    my $sftp = shift;
    if (my $error = $sftp->error) {
        my $status = $sftp->status || 0;
        diag sprintf("SFTP error: %s [%d], status: %s [%d]",
                     $error, $error, $status, $status);
    }
}

1;

__DATA__