use strict;
use warnings;
use Test::More tests=>2146;
#------------------------------------------------------------------
BEGIN { use_ok('SVN::Friendly::Client') or BAIL_OUT; };
my $TEST_CLASS = "SVN::Friendly::Client";
my $CLIENT_CLASS = $TEST_CLASS;
my $CONFIG_CLASS = 'SVN::Friendly::Config';
use SVN::Friendly::Utils;
#------------------------------------------------------------------
# Capabilities and known bugs
# Note: this should be reevaluated from time to time
#------------------------------------------------------------------
my $SKIP_SWIG_BUGS=1;
my $NAG_REPORT_SWIG_BUGS=1;
my %SWIG_BINDING_BUGS;
my @VERSION_SUFFIXES=('', qw(1_1 1_4 1_5 1_6 1_7));
my $IDX_SVN1_4 = 2;
my $IDX_SVN1_7 = $IDX_SVN1_4 + 3;
my $WC_LAST_IDX = $IDX_SVN1_4;
sub isBeforeOrAtRelease {
return ($SVN::Core::VER_MAJOR <= $_[0]) && ($SVN::Core::VER_MINOR <= $_[1]);
}
# remote setting of properties is not supported before 1.7
my $IDX_REMOTE_PROPSET = $IDX_SVN1_7;
#------------------------------------------------------------------
#------------------------------------------------------------------
use Exception::Lite;
Exception::Lite::onDie(4);
# This lets us catch unexpected warnings and trigger a fail event
local $SIG{__WARN__} = sub {
my $sWarning = shift @_;
ok(0, "No warnings");
diag($sWarning);
};
#------------------------------------------------------------------
use URI::file;
#------------------------------------------------------------------
use Test::New qw(testNew);
use Test::Sandbox qw(makeSandbox);
my $SANDBOX_CLASS = 'Test::Sandbox';
my $SANDBOX = $SANDBOX_CLASS->new($TEST_CLASS);
my $IMPORT_DIR = $SANDBOX->addDir();
my $IMPORT_TREE
= { (map {$_=>1} qw(A/ A/B1/ A/B2/ A/B1/C1/ A/B1/C2/))
, 'X.txt' => 'This is an X file'
, 'A/Y.txt' => "This is data for A/Y.txt"
, 'A/B1/Z.dat' => "Data for A/B1/Z.dat"
};
my $IMPORT_PATHS = $SANDBOX->addPaths($IMPORT_DIR, $IMPORT_TREE);
my $IMPORT_LISTING = [ map { /^(.+)\/$/ ? $1 : $_
} keys %$IMPORT_TREE ];
#------------------------------------------------------------------
use SVN::Core;
use SVN::Friendly::Client;
use SVN::Friendly::Repos;
my $REPO_CLASS='SVN::Friendly::Repos';
my $UNVERSIONED_STATUS
= { text_status => $SVN::Wc::Status::unversioned
, prop_status => $SVN::Wc::Status::none
, locked => 0
, copied => 0
, switched => 0
, repos_text_status => $SVN::Wc::Status::none
, repos_prop_status => $SVN::Wc::Status::none
};
my $ADD_STATUS
= { text_status => $SVN::Wc::Status::added
, prop_status => $SVN::Wc::Status::none
, locked => 0
, copied => 0
, switched => 0
, repos_text_status => $SVN::Wc::Status::none
, repos_prop_status => $SVN::Wc::Status::none
};
my $COPY_STATUS
= { text_status => $SVN::Wc::Status::added
, prop_status => $SVN::Wc::Status::none
, locked => 0
, copied => 1
, switched => 0
, repos_text_status => $SVN::Wc::Status::none
, repos_prop_status => $SVN::Wc::Status::none
};
my $NORMAL_STATUS
= { text_status => $SVN::Wc::Status::normal
, prop_status => $SVN::Wc::Status::none
, locked => 0
, copied => 0
, switched => 0
, repos_text_status => $SVN::Wc::Status::none
, repos_prop_status => $SVN::Wc::Status::none
};
# subversion 1.5 adds a svn:mergeinfo property to copied files
my $NORMAL_COPY_STATUS = { %$NORMAL_STATUS };
$NORMAL_COPY_STATUS->{prop_status} = $SVN::Wc::Status::normal
unless isBeforeOrAtRelease(1,4);
my $NORMAL_LOCK_STATUS
= { text_status => $SVN::Wc::Status::normal
, prop_status => $SVN::Wc::Status::none
, locked => 1
, copied => 0
, switched => 0
, repos_text_status => $SVN::Wc::Status::none
, repos_prop_status => $SVN::Wc::Status::none
};
my $NORMAL_PROP_STATUS
= { text_status => $SVN::Wc::Status::normal
, prop_status => $SVN::Wc::Status::normal
, locked => 0
, copied => 0
, switched => 0
, repos_text_status => $SVN::Wc::Status::none
, repos_prop_status => $SVN::Wc::Status::none
};
my $MOD_PROP_STATUS
= { text_status => $SVN::Wc::Status::normal
, prop_status => $SVN::Wc::Status::modified
, locked => 0
, copied => 0
, switched => 0
, repos_text_status => $SVN::Wc::Status::none
, repos_prop_status => $SVN::Wc::Status::none
};
my $DEL_STATUS
= { text_status => $SVN::Wc::Status::deleted
, prop_status => $SVN::Wc::Status::none
, locked => 0
, copied => 0
, switched => 0
, repos_text_status => $SVN::Wc::Status::none
, repos_prop_status => $SVN::Wc::Status::none
};
my $NOT_FOUND_STATUS
= { text_status => $SVN::Wc::Status::none
, prop_status => $SVN::Wc::Status::none
, locked => 0
, copied => 0
, switched => 0
, repos_text_status => $SVN::Wc::Status::none
, repos_prop_status => $SVN::Wc::Status::none
};
#-------------------------------------------------------------------
# Notification action monitoring
#-------------------------------------------------------------------
our $NOISY = 0;
sub okNotifyActions(&$$;$);
my @aNotifications;
my $NOTIFYING;
my $IDX_NOTIFY_ACTION = 0;
my $SOME_STRING_EXCEPTION='';
sub testNotify {
my $sPath = shift @_;
my ($iAction, $iKind, $sMime, $iState, $iRevision) = @_;
push @aNotifications, \@_;
if ($NOISY) {
my $sState = defined($iState)
? $CLIENT_CLASS->getStateAsString($iState) : '';
print STDERR "doing... action=<"
. $CLIENT_CLASS->getActionAsString($iAction)
. ">, state=<$sState>, revision=<$iRevision>, path=<$sPath>"
. ", kind=<$iKind>\n";
}
return 0;
}
#---------------------------------------
# scheduled actions
my $ADD_ACTIONS = [ $SVN::Wc::Notify::Action::add ];
my $DEL_ACTIONS = [ $SVN::Wc::Notify::Action::delete ];
# for some reason the expected action after a copy is add,
# not copy.
my $COPY_ACTIONS = [ $SVN::Wc::Notify::Action::add ];
# this is for moving a single file or empty directory. If the
# directory is non-empty there will be a delete action for the
# directory and each of its members
my $MOVE_ACTIONS = [ $SVN::Wc::Notify::Action::add
, $SVN::Wc::Notify::Action::delete
];
my $REVERT_ACTIONS
= [ $SVN::Wc::Notify::Action::revert ];
#---------------------------------------
# synchronization actions
my $UPDATE_ACTIONS = [ $SVN::Wc::Notify::Action::update_update
, $SVN::Wc::Notify::Action::update_completed
];
my $DEL_COMMIT_ACTIONS
= [ $SVN::Wc::Notify::Action::commit_deleted ];
my $COPY_COMMIT_ACTIONS
= [ $SVN::Wc::Notify::Action::commit_added ];
my $MOVE_COMMIT_ACTIONS
= [ $SVN::Wc::Notify::Action::commit_deleted
, $SVN::Wc::Notify::Action::commit_added
];
my $MOD_COMMIT_ACTIONS
= [ $SVN::Wc::Notify::Action::commit_modified ];
# The constants below are for a committing a single file or empty
# directory. Multiple files and non-empty directories will have
# additional add actions. When committing files, subversion sends
# a list of all the planned actions to the repository first, one
# for each file or dir to be added. Then if there are no show
# stoppers, then and only then does it send the text of any files
# that have been added or modified (commit_postfix_txdelta). See
# http://svn.apache.org/repos/asf/subversion/trunk/notes/subversion-design.html
my $ADD_DIR_COMMIT_ACTIONS
= [ $SVN::Wc::Notify::Action::commit_added ];
my $ADD_FILE_COMMIT_ACTIONS
= [ $SVN::Wc::Notify::Action::commit_added
, $SVN::Wc::Notify::Action::commit_postfix_txdelta];
my $LOCK_FILE_ACTIONS
= [ $SVN::Wc::Notify::Action::locked ];
my $UNLOCK_FILE_ACTIONS
= [ $SVN::Wc::Notify::Action::unlocked ];
#---------------------------------------
# merge and diff actions
my $MERGE_ACTIONS = [ $SVN::Wc::Notify::Action::update_update];
#==================================================================
# TEST SUITES
#==================================================================
sub testDefaults {
my $sName;
#_shiftArray
$sName = '_shiftArray';
okShift1($sName
, \&SVN::Friendly::Client::_shiftArray, undef, []);
okShift1($sName
, \&SVN::Friendly::Client::_shiftArray, [1,2,3], [1,2,3]);
#_shiftBoolean
$sName = '_shiftBoolean';
okShift1($sName, \&SVN::Friendly::Utils::_shiftBoolean, undef, 0);
okShift1($sName, \&SVN::Friendly::Utils::_shiftBoolean, 0, 0);
okShift1($sName, \&SVN::Friendly::Utils::_shiftBoolean, 1, 1);
#_shiftDiffTargets
$sName = '_shiftDiffTargets';
okShiftMany($sName, \&SVN::Friendly::Client::_shiftDiffTargets
, [undef,undef, undef, undef]
, [File::Spec->curdir(), 'BASE'
, File::Spec->curdir(), 'WORKING']);
okShiftMany($sName, \&SVN::Friendly::Client::_shiftDiffTargets
, ['a', undef, undef, undef]
, ['a', 'BASE', 'a', 'WORKING']);
okShiftMany($sName, \&SVN::Friendly::Client::_shiftDiffTargets
, ['a','WORKING', undef, undef]
, ['a', 'WORKING', 'a', 'WORKING']);
okShiftMany($sName, \&SVN::Friendly::Client::_shiftDiffTargets
, ['a', undef, undef, undef]
, ['a','BASE','a', 'WORKING']);
okShiftMany($sName, \&SVN::Friendly::Client::_shiftDiffTargets
, ['a', undef, undef, 'COMMITTED']
, ['a', 'PREV', 'a', 'COMMITTED']);
okShiftMany($sName, \&SVN::Friendly::Client::_shiftDiffTargets
, ['a', undef, undef, 'WORKING']
, ['a', 'BASE', 'a', 'WORKING']);
okShiftMany($sName, \&SVN::Friendly::Client::_shiftDiffTargets
, ['a', undef, undef, 5]
, ['a', 4, 'a', 5]);
okShiftMany($sName, \&SVN::Friendly::Client::_shiftDiffTargets
, ['a','HEAD', undef, undef]
, ['a', 'HEAD', 'a', 'WORKING']);
okShiftMany($sName, \&SVN::Friendly::Client::_shiftDiffTargets
, ['a','BASE', undef, undef]
, ['a', 'BASE', 'a', 'WORKING']);
okShiftMany($sName, \&SVN::Friendly::Client::_shiftDiffTargets
, ['a','COMMITTED', undef, undef]
, ['a', 'COMMITTED', 'a', 'WORKING']);
okShiftMany($sName, \&SVN::Friendly::Client::_shiftDiffTargets
, ['a','PREV', undef, undef]
, ['a', 'PREV', 'a', 'COMMITTED']);
okShiftMany($sName, \&SVN::Friendly::Client::_shiftDiffTargets
, ['a', 0, undef, undef]
, ['a', 0, 'a', 1]);
#_shiftDepth
$sName = '_shiftDepth';
okShift1($sName, \&SVN::Friendly::Client::_shiftDepth
, undef, $SVN::Depth::infinity);
okShift1($sName, \&SVN::Friendly::Client::_shiftDepth
, $SVN::Depth::infinity, $SVN::Depth::infinity);
okShift1($sName, \&SVN::Friendly::Client::_shiftDepth
, $SVN::Depth::empty, $SVN::Depth::empty);
#_shiftErrFile
$sName = '_shiftErrFile';
okShift1($sName, \&SVN::Friendly::Client::_shiftErrFile
, undef, \*STDERR);
okShift1($sName, \&SVN::Friendly::Client::_shiftErrFile
, \*STDERR, \*STDERR);
okShift1($sName, \&SVN::Friendly::Client::_shiftErrFile
, \*STDOUT, \*STDOUT);
okShift1($sName, \&SVN::Friendly::Client::_shiftErrFile
, 'foo', 'foo');
#_shiftHash
$sName = '_shiftHash';
okShift1($sName
, \&SVN::Friendly::Client::_shiftHash, undef, {});
okShift1($sName
, \&SVN::Friendly::Client::_shiftHash, {a=>1}, {a=>1});
#_shiftInt
$sName = '_shiftInt';
okShift1($sName, \&SVN::Friendly::Client::_shiftInt, undef, 0);
okShift1($sName, \&SVN::Friendly::Client::_shiftInt, 1, 1);
okShift1($sName, \&SVN::Friendly::Client::_shiftInt, 0, 0);
okShift1($sName, \&SVN::Friendly::Client::_shiftInt, -1, -1);
#_shiftListFieldMask
$sName = '_shiftListFieldMask';
okShift1($sName, \&SVN::Friendly::Client::_shiftListFieldMask
, undef, $SVN::Friendly::List::Fields::ALL);
okShift1($sName, \&SVN::Friendly::Client::_shiftListFieldMask
, $SVN::Friendly::List::Fields::ALL
, $SVN::Friendly::List::Fields::ALL);
okShift1($sName, \&SVN::Friendly::Client::_shiftListFieldMask
, $SVN::Friendly::List::Fields::LAST_AUTHOR
, $SVN::Friendly::List::Fields::LAST_AUTHOR);
#_shiftOutFile
$sName = '_shiftOutFile';
okShift1($sName, \&SVN::Friendly::Client::_shiftOutFile
, undef, \*STDOUT);
okShift1($sName, \&SVN::Friendly::Client::_shiftOutFile
, \*STDERR, \*STDERR);
okShift1($sName, \&SVN::Friendly::Client::_shiftOutFile
, \*STDOUT, \*STDOUT);
okShift1($sName, \&SVN::Friendly::Client::_shiftOutFile
, 'foo', 'foo');
#_shiftOutputEncoding
$sName = '_shiftOutputEncoding';
my $sDefault = $SVN::_Core::svn_locale_charset;
okShift1($sName, \&SVN::Friendly::Client::_shiftOutputEncoding
, undef, $sDefault);
okShift1($sName, \&SVN::Friendly::Client::_shiftOutputEncoding
, 'UTF-8', 'UTF-8');
#_shiftOutputEol
$sName = '_shiftOutputEol';
okShift1($sName, \&SVN::Friendly::Client::_shiftOutputEol
, undef, undef);
okShift1($sName, \&SVN::Friendly::Client::_shiftOutputEol
, 'CRLF', 'CRLF');
okShift1($sName, \&SVN::Friendly::Client::_shiftOutputEol
, 'LF', 'LF');
#_shiftPegRev
$sName = '_shiftPegRev';
okShiftMany($sName, \&SVN::Friendly::Client::_shiftPegRev
, [undef,undef], ['HEAD','HEAD'], 1);
okShiftMany($sName, \&SVN::Friendly::Client::_shiftPegRev
, ['COMMITTED',undef], ['COMMITTED','COMMITTED'], 1);
okShiftMany($sName, \&SVN::Friendly::Client::_shiftPegRev
, [1,'COMMITTED'], [1,'COMMITTED'], 1);
#_shiftPeg
$sName = '_shiftPeg';
okShift1($sName, \&SVN::Friendly::Client::_shiftPeg, undef, 'HEAD');
okShift1($sName, \&SVN::Friendly::Client::_shiftPeg, 'PREV', 'PREV');
#_shiftRecurse
$sName = '_shiftRecurse';
okShift1($sName, \&SVN::Friendly::Client::_shiftRecurse, undef, 1);
okShift1($sName, \&SVN::Friendly::Client::_shiftRecurse, 0, 0);
okShift1($sName, \&SVN::Friendly::Client::_shiftRecurse, 1, 1);
#_shiftRange
$sName = '_shiftRange';
okShiftMany($sName, \&SVN::Friendly::Client::_shiftRange
, [undef,undef], [0,'HEAD'], 1);
okShiftMany($sName, \&SVN::Friendly::Client::_shiftRange
, ['PREV',undef], ['PREV','HEAD'], 1);
okShiftMany($sName, \&SVN::Friendly::Client::_shiftRange
, [3,47], [3,47], 1);
#_shiftTarget
my $oURI = URI->new('http://www.example.com');
$sName = '_shiftTarget';
okShift1($sName, \&SVN::Friendly::Client::_shiftTarget
, undef, undef);
okShift1($sName, \&SVN::Friendly::Client::_shiftTarget
, 'a', 'a');
okShift1($sName, \&SVN::Friendly::Client::_shiftTarget
, $oURI, $oURI->as_string());
#_shiftTargets
$sName = '_shiftTargets';
okShift1($sName, \&SVN::Friendly::Client::_shiftTargets
, undef, []);
okShift1($sName, \&SVN::Friendly::Client::_shiftTargets
, 'a', ['a']);
okShift1($sName, \&SVN::Friendly::Client::_shiftTargets
, ['a'], ['a']);
okShift1($sName, \&SVN::Friendly::Client::_shiftTargets
, $oURI, [ $oURI->as_string() ]);
okShift1($sName, \&SVN::Friendly::Client::_shiftTargets
, [$oURI], [ $oURI->as_string() ]);
#_shiftString
$sName = '_shiftString';
okShift1($sName, \&SVN::Friendly::Client::_shiftString, undef, '');
okShift1($sName, \&SVN::Friendly::Client::_shiftString, 'a', 'a');
#_shiftTrue
$sName = '_shiftTrue';
okShift1($sName, \&SVN::Friendly::Client::_shiftTrue, undef, 1);
okShift1($sName, \&SVN::Friendly::Client::_shiftTrue, 0, 0);
okShift1($sName, \&SVN::Friendly::Client::_shiftTrue, 1, 1);
#_shiftVisitor
my $crSub = sub {};
okShift1($sName, \&SVN::Friendly::Utils::_shiftVisitor
, undef, $SVN::Friendly::Utils::NOOP);
okShift1($sName, \&SVN::Friendly::Utils::_shiftVisitor
, $crSub, $crSub);
# #_shiftVisitorBaton
# $sName = '_shiftVisitor';
# okShiftMany($sName, \&SVN::Friendly::Client::_shiftVisitorBaton
# , [undef,undef], [$SVN::Friendly::Client::NOOP, undef]);
# okShiftMany($sName, \&SVN::Friendly::Client::_shiftVisitorBaton
# , [$crSub,undef], [$crSub, undef]);
# okShiftMany($sName, \&SVN::Friendly::Client::_shiftVisitorBaton
# , [$crSub,'a'], [$crSub, 'a']);
#_shiftWcPath
$sName = '_shiftWcPath';
okShift1($sName, \&SVN::Friendly::Client::_shiftWcPath
, undef, File::Spec->curdir());
okShift1($sName, \&SVN::Friendly::Client::_shiftWcPath
, 'a', 'a');
#_shiftWcPaths
$sName = '_shiftWcPaths';
okShift1($sName, \&SVN::Friendly::Client::_shiftWcPaths
, undef, []);
okShift1($sName, \&SVN::Friendly::Client::_shiftWcPaths
, 'a', ['a']);
okShift1($sName, \&SVN::Friendly::Client::_shiftWcPaths
, ['a'], ['a']);
}
#--------------------------------------------------------------------
sub testClient_Local_NoAuth {
my ($sName, $oClient, $aaParams, $hProperties);
# client with notifications ($crNotify = \&testNotify
$NOTIFYING=1;
$sName = 'local_NoAuth_notify';
$aaParams = [[ undef, undef, \&testNotify ]
, [ undef, undef, \&testNotify, undef ]
, [ undef, undef, \&testNotify, undef, undef ]
, [ undef, undef, \&testNotify, undef, undef, undef ]
];
$hProperties = { getNotificationCallback => \&testNotify
, getLogMessageCallback => undef
, getCancellationCallback => undef
};
$oClient = testNewClient($sName, $aaParams, $hProperties);
#DEBUG - START
#testAuthentication($sName, $oClient);
#exit(); #STOP_TESTING
#DEBUG - END
testWc($sName, $oClient, 1);
# do configuration tests _after_ testWc so that testWc uses
# the configuration set up by testNewClient
testNotification($sName, $oClient);
testAuthentication($sName, $oClient);
is(ref($oClient->getConfig()), $CONFIG_CLASS
, "$sName - verifying config object");
# client without notifications ($crNotify = undef)
$NOTIFYING=0;
$sName = 'local_NoAuth';
$aaParams = [[]
,[undef]
,[undef,undef]
,[undef,undef,undef]
,[undef,undef,undef,undef]
,[undef,undef,undef,undef, undef]
,[undef,undef,undef,undef, undef, undef]
];
$hProperties = { getNotificationCallback => undef
, getLogMessageCallback => undef
, getCancellationCallback => undef
};
$oClient = testNewClient($sName, $aaParams, $hProperties);
testWc($sName, $oClient, 0);
}
#==================================================================
# UTILITIES
#==================================================================
#--------------------------------------------------------------------
sub _appendRelPathToURL {
my ($sURL, $sRelPath) = @_;
# use local file system rules for "file" protocol.
# for others (http, https, ftp, svn+ssh) assume POSIX path syntax
return $sURL =~ m{^file://(.*)$}
? 'file://' . File::Spec->rel2abs($sRelPath, $1)
: "$sURL/$sRelPath";
}
#--------------------------------------------------------------------
sub _isMinimal {
my $aParams = shift;
return 0 if scalar(@$aParams);
for (@_) { return 0 if defined($_) }
return 1;
}
#--------------------------------------------------------------------
sub _selectPaths {
my ($aPaths, $iStart, $iEnd) = @_;
$iEnd = $iStart unless defined($iStart);
return [ (undef) x $iStart, @$aPaths[$iEnd..$iStart] ];
}
#==================================================================
# SUBTESTS
#==================================================================
#--------------------------------------------------------------------
sub okAdd {
my ($sName, $oClient, $aPaths, $aCreate, $aParams, $hStatus
, $aExpectedActions) = @_;
$aExpectedActions = $ADD_ACTIONS unless defined($aExpectedActions);
my $bVerify = ref($aExpectedActions) eq 'ARRAY' ?1:0;
$aParams =[] unless defined($aParams);
my ($iDepth, $bForceAdd, $bNoIgnore, $bAddParents) = @$aParams;
my $bRecurse = !defined($iDepth) ? undef : ($iDepth? 1 : 0);
my $bMinimal = _isMinimal($aParams);
my @aAdd = $bMinimal
? ( sub { $oClient->add($_[0]) }
, sub { $oClient->add1_1($_[0]) }
, sub { $oClient->add1_4($_[0]) }
, sub { $oClient->add1_5($_[0]) }
, sub { $oClient->add1_6($_[0]) }
, sub { $oClient->add1_7($_[0]) }
)
: ( sub { $oClient->add($_[0], $bRecurse) }
, sub { $oClient->add1_1($_[0], $bRecurse) }
, sub { $oClient->add1_4($_[0], $bRecurse, $bForceAdd
, $bNoIgnore) }
, sub { $oClient->add1_5($_[0], $iDepth, $bForceAdd
, $bNoIgnore, $bAddParents) }
, sub { $oClient->add1_6($_[0], $iDepth, $bForceAdd
, $bNoIgnore, $bAddParents) }
, sub { $oClient->add1_7($_[0], $iDepth, $bForceAdd
, $bNoIgnore, $bAddParents) }
);
if (defined($aCreate)) {
my $aWcs = $aPaths;
my ($sRelPath, $sContent) = @$aCreate;
$aPaths = [ map { $_->addFile($sRelPath, $sContent); } @$aWcs ];
}
for my $i (0..$#$aPaths) {
my $sPath = $aPaths->[$i];
next unless defined($sPath);
my $sTest = "$sName:add$VERSION_SUFFIXES[$i]($sPath)";
okNotifyActions { $aAdd[$i]->($sPath);
} $sTest, $aExpectedActions, 1;
okGetStatus($sName, $oClient, $sPath, $hStatus);
}
return $aPaths;
}
#----------------------------------------------------------------
sub okBlame {
my ($sName, $oClient, $xPaths, $aParams, $iEdits, $sContent) = @_;
my $aExpectedActions
= [ ($SVN::Wc::Notify::Action::blame_revision) x $iEdits ];
#blame only accepts central repository files
#if one tries to use a local path one gets an 'Entry has no URL'
#message
my ($aPaths, $xPeg, $aRanges) = ref($xPaths) ? @$xPaths : ($xPaths);
my ($xStart, $xEnd) = defined($aRanges) && (scalar @$aRanges)
? @{$aRanges->[0]} : (undef, undef);
$aParams = [] unless defined $aParams;
my ($oDiffOptions, $bBlameBinary, $bIncludeMergedRevisions)
= @$aParams;
my $bMinimal = _isMinimal($aParams, $xPeg, $aRanges);
my @aBlame = $bMinimal
? ( sub { $oClient->blame($_[0], $_[1]) }
, sub { $oClient->blame1_1($_[0], $_[1]) }
, sub { $oClient->blame1_4($_[0], $xPeg, $xStart, $xEnd
, $oDiffOptions, $bBlameBinary, $_[1]) }
, sub { $oClient->blame1_5($_[0], $xPeg, $xStart, $xEnd
, $oDiffOptions, $bBlameBinary, $bIncludeMergedRevisions
, $_[1]) }
, sub { $oClient->blame1_6($_[0], $xPeg, $xStart, $xEnd
, $oDiffOptions, $bBlameBinary, $bIncludeMergedRevisions
, $_[1]) }
, sub { $oClient->blame1_7($_[0], $xPeg, $xStart, $xEnd
, $oDiffOptions, $bBlameBinary, $bIncludeMergedRevisions
, $_[1]) }
)
: ( sub { $oClient->blame($_[0],$xStart, $xEnd, $_[1]) }
, sub { $oClient->blame1_1($_[0], $xStart, $xEnd, $_[1]) }
, sub { $oClient->blame1_4($_[0], $xPeg, $xStart, $xEnd
, $oDiffOptions, $bBlameBinary, $_[1]) }
, sub { $oClient->blame1_5($_[0], $xPeg, $xStart, $xEnd
, $oDiffOptions, $bBlameBinary, $bIncludeMergedRevisions
, $_[1]) }
, sub { $oClient->blame1_6($_[0], $xPeg, $xStart, $xEnd
, $oDiffOptions, $bBlameBinary, $bIncludeMergedRevisions
, $_[1]) }
, sub { $oClient->blame1_7($_[0], $xPeg, $xStart, $xEnd
, $oDiffOptions, $bBlameBinary, $bIncludeMergedRevisions
, $_[1]) }
);
my $bOk=1;
my $sMsg='';
my $sBuf='';
my $crVisit = sub {
my ($iLine, $iRevision, $sAuthor, $sISO8601Time, $sLine, $oPool)
= @_;
$sBuf .= "$sLine\n" if defined($sLine);
return unless $bOk; #only capture first set of errors
if ("$iLine" !~ m{\d+}) {
$bOk=0;
$sMsg.= "line: expected \\d+, got <$iLine>\n";
}
if ("$iRevision" !~ m{\d+}) {
$bOk=0;
$sMsg.= "revision: expected \\d+, got <$iRevision>\n";
}
if (!defined($sAuthor) || ref($sAuthor) || !length($sAuthor)) {
$bOk=0;
$sAuthor=defined($sAuthor)?"'$sAuthor'" : 'undef';
$sMsg .= "author: expected non-empty string, got <$sAuthor>\n";
}
if (!defined($sISO8601Time) || ref($sISO8601Time)
|| !length($sISO8601Time)) {
$bOk=0;
$sISO8601Time= defined($sISO8601Time)
? "'$sISO8601Time'" : 'undef';
$sMsg .= "timestamp: expected non-empty string, got "
."<$sISO8601Time>\n";
}
if (!defined($sLine) || ref($sLine) || !length($sLine)) {
$bOk=0;
$sLine=defined($sLine) ? "'$sLine'" : 'undef';
$sMsg .= "line: expected non-empty string, got <$sLine>\n";
}
if (!defined($oPool) || ref($oPool) ne '_p_apr_pool_t') {
$oPool=defined($oPool) ? "'$oPool'" : 'undef';
$sMsg .= 'pool object: expected reference to svn_pool_t'
. "got <$oPool>\n";
}
};
for my $i (0..$#$aPaths) {
my $sPath = $aPaths->[$i];
next unless defined($sPath);
my $sTest = "$sName:blame$VERSION_SUFFIXES[$i]($sPath)";
okNotifyActions { $aBlame[$i]->($sPath, undef);
} $sTest, $aExpectedActions;
$bOk=1;
$sMsg='';
$sBuf='';
okNotifyActions { $aBlame[$i]->($sPath, $crVisit);
} $sTest, $aExpectedActions;
ok($bOk, "$sTest - verifying callback parameters")
or diag($sMsg);
is($sBuf, $sContent, "$sTest - verifying content");
}
}
#----------------------------------------------------------------
sub okCat {
my ($sName, $oClient, $xPaths, $aParams, $sContent) = @_;
my $aExpectedActions = [];
my ($aPaths, $xPeg, $xRev) = ref($xPaths) ? @$xPaths : ($xPaths);
$aParams = [] unless defined $aParams;
my $bMinimal = _isMinimal($aParams, $xPeg, $xRev);
my @aCat = $bMinimal
? ( sub { $oClient->cat($_[0],$xPeg, $_[1]) }
, sub { $oClient->cat1_1($_[1], $_[0]) }
, sub { $oClient->cat1_4($_[1], $_[0]) }
, sub { $oClient->cat1_5($_[1], $_[0]) }
, sub { $oClient->cat1_6($_[1], $_[0]) }
, sub { $oClient->cat1_7($_[1], $_[0]) }
)
: ( sub { $oClient->cat($_[0],$xPeg, $_[1]) }
, sub { $oClient->cat1_1($_[1], $_[0], $xPeg) }
, sub { $oClient->cat1_4($_[1], $_[0]) }
, sub { $oClient->cat1_5($_[1], $_[0]) }
, sub { $oClient->cat1_6($_[1], $_[0]) }
, sub { $oClient->cat1_7($_[1], $_[0]) }
);
for my $i (0..$#$aPaths) {
my $sPath = $aPaths->[$i];
next unless defined($sPath);
my $sTest = "$sName:cat$VERSION_SUFFIXES[$i]($sPath)";
my $sBufOut='';
open( my $fhOut, '>', \$sBufOut)
or die "Cannot open string buffer stream: $!";
okNotifyActions { $aCat[$i]->($sPath, $fhOut);
} $sTest, $aExpectedActions;
is($sBufOut, $sContent, "$sTest - verifying content");
close($fhOut);
}
}
#----------------------------------------------------------------
sub okCheckout {
my ($sName, $oClient, $xRepoURLs, $aPaths, $aParams
, $aRepos, $bWc, $iExpectedRev, $aExpectedActions) = @_;
my ($aRepoURLs, $xPeg, $xRev)
= ref($xRepoURLs) ? @$xRepoURLs : ($xRepoURLs);
$aRepoURLs = [ $aRepoURLs ] if ! ref($aRepoURLs);
my $bCommitted= defined($xPeg) && ($xPeg ne 'WORKING');
if (!defined($aExpectedActions)) {
$aExpectedActions
= [ $SVN::Wc::Notify::Action::update_update
, $SVN::Wc::Notify::Action::update_completed ];
}
$aParams = [] unless defined($aParams);
my ($iDepth, $bSkipExternals
, $bAllowUnversionedObstructions) = @$aParams;
my $bRecurse = !defined($iDepth) ? undef : ($iDepth? 1 : 0);
my $bMinimal = _isMinimal($aParams, $xPeg, $xRev);
my @aCheckout = $bMinimal
?( sub { $oClient->checkout($_[0], undef, $_[1]) }
, sub { $oClient->checkout1_1($_[0], $_[1]) }
, sub { $oClient->checkout1_4($_[0], $_[1]) }
, sub { $oClient->checkout1_5($_[0], $_[1]) }
, sub { $oClient->checkout1_6($_[0], $_[1]) }
, sub { $oClient->checkout1_7($_[0], $_[1]) }
)
:( sub { $oClient->checkout($_[0], $xPeg, $_[1], $bRecurse) }
, sub { $oClient->checkout1_1($_[0], $_[1], $xPeg
, $bRecurse); }
, sub { $oClient->checkout1_4($_[0], $_[1], $xPeg, $xRev
, $bRecurse, $bSkipExternals); }
, sub { $oClient->checkout1_5($_[0], $_[1], $xPeg, $xRev
, $iDepth, $bSkipExternals
, $bAllowUnversionedObstructions); }
, sub { $oClient->checkout1_6($_[0], $_[1], $xPeg, $xRev
, $iDepth, $bSkipExternals
, $bAllowUnversionedObstructions); }
, sub { $oClient->checkout1_7($_[0], $_[1], $xPeg, $xRev
, $iDepth, $bSkipExternals
, $bAllowUnversionedObstructions); }
);
for my $i (0..$#$aPaths) {
my $sPath = $aPaths->[$i];
next if !defined($sPath);
my $oRepo = $aRepos->[$i];
my $sRepoURL = $aRepoURLs->[$i];
my $sTest
="$sName: checkout$VERSION_SUFFIXES[$i]($sPath => $sRepoURL)";
is($oClient->isWorkingCopyPath($sPath), $bWc?1:0
, "$sTest: before checkout");
my $iRev;
okNotifyActions { $iRev = $aCheckout[$i]->($sRepoURL, $sPath)
} $sTest, $aExpectedActions, 1;
is($iRev, $iExpectedRev, "$sTest - verifying revision");
is($oClient->getRepositoryURL($sPath), $sRepoURL
, "$sTest - verifying repository URL");
is($oClient->getRepositoryUUID($sPath), $oRepo->getUUID()
, "$sTest - verifying repository UUID");
is($oClient->isWorkingCopyPath($sPath), 1
, "$sTest: after checkout");
}
}
#--------------------------------------------------------------------
sub okCleanup {
my ($sName, $oClient, $aPaths, $aExpectedActions) = @_;
$aExpectedActions = [] unless defined($aExpectedActions);
my $bVerify = ref($aExpectedActions) eq 'ARRAY' ?1:0;
my @aCleanup
= ( sub { $oClient->cleanup($_[0]) }
, sub { $oClient->cleanup1_1($_[0]) }
, sub { $oClient->cleanup1_4($_[0]) }
, sub { $oClient->cleanup1_5($_[0]) }
, sub { $oClient->cleanup1_6($_[0]) }
, sub { $oClient->cleanup1_7($_[0]) }
);
for my $i (0..$#$aPaths) {
my $sPath = $aPaths->[$i];
next unless defined($sPath);
my $sTest = "$sName:cleanup$VERSION_SUFFIXES[$i]($sPath)";
okNotifyActions { $aCleanup[$i]->($sPath);
} $sTest, $aExpectedActions, 1;
next unless $bVerify;
is($oClient->getStatus($sPath)->locked(), 0
, "$sTest - verifying frozen(locked) status");
}
}
#--------------------------------------------------------------------
sub okCommit {
my ($sName, $oClient, $aPaths, $aParams
, $aExpectedStatus, $iRev, $aExpectedActions) = @_;
local $Test::Builder::Level = $Test::Builder::Level + 1;
$aExpectedStatus = [ ($aExpectedStatus) x scalar(@$aPaths) ]
if (ref($aExpectedStatus) eq 'HASH');
$aExpectedActions = [] unless defined($aExpectedActions);
my $bVerify = ref($aExpectedActions) eq 'ARRAY' ?1:0;
$aParams=[] unless defined($aParams);
my ($sComment, $iDepth, $bKeepLocks, $bKeepChangelists
, $aChangeLists, $hRevProps, $crCommit) = @$aParams;
my $bRecurse = !defined($iDepth) ? undef : ($iDepth? 1 : 0);
my $bNonRecursive = !defined($bRecurse)? undef : ($bRecurse?0:1);
my $bMinimal = _isMinimal($aParams);
#print STDERR "recursive=", (defined($bRecurse)?$bRecurse:'undef')
# , "\n";
my @aCommit = $bMinimal
? ( sub { $oClient->commit($_[0]) }
, sub { $oClient->commit1_1($_[0]) }
, sub { $oClient->commit1_4($_[0]) }
, sub { $oClient->commit1_5($_[0]) }
, sub { $oClient->commit1_6($_[0]) }
, sub { $oClient->commit1_7($_[0]) }
)
: ( sub { $oClient->commit($_[0], $sComment, $bRecurse) }
, sub { $oClient->commit1_1($_[0], $sComment, $bNonRecursive) }
, sub { $oClient->commit1_4($_[0], $sComment, $bRecurse
, $bKeepLocks) }
, sub { $oClient->commit1_5($_[0], $sComment, $iDepth
, $bKeepLocks, $bKeepChangelists, $aChangeLists
, $hRevProps) }
, sub { $oClient->commit1_6($_[0], $sComment, $iDepth
, $bKeepLocks, $bKeepChangelists, $aChangeLists
, $hRevProps) }
, sub { $oClient->commit1_7($_[0], $sComment, $iDepth
, $bKeepLocks, $bKeepChangelists, $aChangeLists
, $hRevProps, $crCommit) }
);
for my $i (0..$#$aPaths) {
my $xPath = $aPaths->[$i];
next unless defined($xPath);
my $aCommit = ref($xPath) eq 'ARRAY' ? $xPath : [ $xPath ];
my $sTest = "$sName:commit$VERSION_SUFFIXES[$i](@$aCommit)";
my $oCommitInfo;
okNotifyActions { $oCommitInfo = $aCommit[$i]->($xPath);
} $sTest, $aExpectedActions, 1;
next unless $bVerify;
#if (!ref($xPath)) {
# local $"="\n\t";
# print STDERR "$sTest:\n\t@{$SANDBOX->list($xPath,1)}";
#}
SKIP:
{
if ($SKIP_SWIG_BUGS && ($i >= $IDX_SVN1_4)) {
my $sBug= "commit: svn_commit_info_t package "
."undefined in SWIG-Perl (1.4), revision method unknown (1.5)";
$SWIG_BINDING_BUGS{$sBug}++;
local $TODO = "SWIG binding bug: need to report\n\t$sBug";
skip $sTest, 1;
}
# eval because if we don't skip this bug it will cause
# a fatal error and we'd rather see the error message and
# continue
eval {
is(defined($oCommitInfo) ? $oCommitInfo->revision : undef
, $iRev, "$sTest - verifying revision number");
} or do {
my $e=$@;
$e='unknown' if defined($e) && !length($e);
warn "$sTest: $e";
};
}
for my $i (0..$#$aCommit) {
my $sCommit = $aCommit->[$i];
my $hExpect = $aExpectedStatus->[$i];
okGetStatus($sTest, $oClient, $sCommit, $hExpect);
}
}
}
#--------------------------------------------------------------------
sub okCopy {
my ($sName, $oClient, $xFrom, $aTo, $sRelPath, $aParams
, $aExpectedActions) = @_;
local $Test::Builder::Level = $Test::Builder::Level + 1;
# $xFrom may be: $sPath
# [ $sPath, $xPeg, $xRev]
# [ $aPaths, $xPeg, $xRev]
my ($aFrom, $xPeg, $xRev) = ref($xFrom) ? @$xFrom : ($xFrom);
$aFrom = [ $aFrom ] if ! ref($aFrom);
my $bLocal = !defined($xPeg) || (uc($xPeg) eq 'WORKING');
$aExpectedActions = ($bLocal ? $COPY_ACTIONS : [])
unless defined($aExpectedActions);
my $bVerify = ref($aExpectedActions) eq 'ARRAY' ?1:0;
if (defined($sRelPath)) {
my $aWcs = $aTo;
my ($sRelPath, $bFile) = ref($sRelPath)
? @$sRelPath : ($sRelPath);
$aTo = [ map { $_->getFullPathName($sRelPath, $bFile) } @$aWcs ];
}
$aParams=[] unless defined($aParams);
my ($sComment, $bCopyAsChild, $bMakeParents
, $hRevProps, $crCommit) = @$aParams;
my $bMinimal = _isMinimal($aParams, $xPeg);
my @aCopy = $bMinimal
? ( sub { $oClient->copy($_[0], $xPeg, $_[1]); }
, sub { $oClient->copy1_1($_[0], $xPeg, $_[1]) }
, sub { $oClient->copy1_4($_[0], $xPeg, $_[1]) }
, sub { $oClient->copy1_5($_[0], $xPeg, $_[1]) }
, sub { $oClient->copy1_6($_[0], $xPeg, $_[1]) }
, sub { $oClient->copy1_7($_[0], $xPeg, $_[1]) }
)
: ( sub { $oClient->copy($_[0], $xPeg, $_[1], $sComment); }
, sub { $oClient->copy1_1($_[0], $xPeg, $_[1], $sComment) }
, sub { $oClient->copy1_4($_[0], $xPeg, $_[1], $sComment) }
, sub { $oClient->copy1_5($_[0], $xPeg, $_[1], $sComment
, $bCopyAsChild, $bMakeParents, $hRevProps) }
, sub { $oClient->copy1_6($_[0], $xPeg, $_[1], $sComment
, $bCopyAsChild, $bMakeParents, $hRevProps) }
, sub { $oClient->copy1_7($_[0], $xPeg, $_[1], $sComment
, $bCopyAsChild, $bMakeParents, $hRevProps
, $crCommit) }
);
for my $i (0..$#$aFrom) {
my $sFrom = $aFrom->[$i];
next unless defined($sFrom);
my $sTo = $aTo->[$i];
my $sTest = "$sName:copy$VERSION_SUFFIXES[$i]($sFrom => $sTo)";
my $hFromStatus = $oClient->getStatus($sFrom);
okNotifyActions { $aCopy[$i]->($sFrom, $sTo);
} $sTest, $aExpectedActions, 1;
okGetStatus("$sTest - verifying preservation of source status"
, $oClient, $sFrom, $hFromStatus);
next unless $bVerify;
if ($bLocal) {
is((-e $sFrom)?1:0, 1
, "$sTest - verifiying existance of source");
okGetStatus("$sTest - verifying target status"
, $oClient, $sTo, $COPY_STATUS);
is((-e $sTo)?1:0, 1, "$sTest - verifiying existance of target");
}
}
return $aTo;
}
#--------------------------------------------------------------------
sub okDelete {
my ($sName, $oClient, $aPaths, $aParams
, $hExpectedStatus, $aExpectedActions) = @_;
my $bLocal = defined($hExpectedStatus) ? 1 : 0;
$aExpectedActions = ($bLocal ? $DEL_ACTIONS : [])
unless defined($aExpectedActions);
$aParams = [] unless defined($aParams);
my ($sComment, $bForce, $bKeepLocal, $hRevProps, $crCommit)
= @$aParams;
my $bMinimal = _isMinimal($aParams);
my @aDelete = $bMinimal
? ( sub { $oClient->delete($_[0]) }
, sub { $oClient->delete1_1($_[0]) }
, sub { $oClient->delete1_4($_[0]) }
, sub { $oClient->delete1_5($_[0]) }
, sub { $oClient->delete1_6($_[0]) }
, sub { $oClient->delete1_7($_[0]) }
)
: ( sub { $oClient->delete($_[0], $sComment, $bForce) }
, sub { $oClient->delete1_1($_[0], $sComment, $bForce) }
, sub { $oClient->delete1_4($_[0], $sComment, $bForce) }
, sub { $oClient->delete1_5($_[0], $sComment, $bForce
, $bKeepLocal, $hRevProps) }
, sub { $oClient->delete1_6($_[0], $sComment, $bForce
, $bKeepLocal, $hRevProps) }
, sub { $oClient->delete1_7($_[0], $sComment, $bForce
, $bKeepLocal, $hRevProps, $crCommit) }
);
for my $i (0..$#$aPaths) {
my $xPath = $aPaths->[$i];
next unless defined($xPath);
my $aPaths = ref($xPath) eq 'ARRAY' ? $xPath : [ $xPath ];
my $sTest;
{
local $"=',';
$sTest = "$sName:delete$VERSION_SUFFIXES[$i](@$aPaths)";
}
#dirs don't get removed until until commit
my @aKeepUntilCommit= $bLocal
? map { (-d $_ ) ? 1 : 0 } @$aPaths
: ();
okNotifyActions { $aDelete[$i]->($xPath);
} $sTest, $aExpectedActions, 1;
if ($bLocal) {
foreach my $i (0..$#$aPaths) {
my $sPath = $aPaths->[$i];
okGetStatus($sName, $oClient, $sPath, $hExpectedStatus);
is((-e $sPath) ? 1:0, $bKeepLocal ? 1 : $aKeepUntilCommit[$i]
, "$sTest - verifying existance status");
}
}
}
return $aPaths;
}
#----------------------------------------------------------------
sub okDiff {
my ($sName, $oClient, $xPath1, $xPath2, $aParams
, $sOut, $sErr, $aExpectedActions)= @_;
$aExpectedActions = [] unless defined($aExpectedActions);
my ($aPath1, $xPeg1) = ref($xPath1) ? @$xPath1 : ($xPath1);
my ($aPath2, $xPeg2) = ref($xPath2) ? @$xPath2 : ($xPath2);
my ($iDepth, $aCmdLineOptions, $bIgnoreAncestry, $bIgnoreDeleted
, $bShowCopiesAsAdds, $bDiffBinary, $bUseGitDiffFormat
, $sHeaderEncoding, $aChangeLists) = @$aParams;
my $bRecurse = !defined($iDepth) ? undef : ($iDepth? 1 : 0);
my $sRelativeToDir = undef;
my $reOut = defined($sOut) && length($sOut)
? qr{\Q$sOut\E} : qr{^\z};
my $reErr = defined($sErr) && length($sErr)
? qr{\Q$sErr\E} : qr{^\z};
my $bMinimal = _isMinimal($aParams, $xPeg1, $xPeg2, $sOut, $sErr);
my @aDiff = $bMinimal
? ( sub { $oClient->diff($_[0], $xPeg1, $_[1])}
, sub {$oClient->diff1_1($aCmdLineOptions
, $_[0], $xPeg1, $_[1])}
, sub {$oClient->diff1_4($aCmdLineOptions
, $_[0], $xPeg1, $_[1])}
, sub {$oClient->diff1_6($aCmdLineOptions
, $_[0], $xPeg1, $_[1])}
, sub {$oClient->diff1_7($aCmdLineOptions
, $_[0], $xPeg1, $_[1])}
)
: ( sub { $oClient->diff($_[0], $xPeg1, $_[1], $xPeg2, $bRecurse
, $aCmdLineOptions, $bIgnoreAncestry, $bIgnoreDeleted
, $_[2], $_[3])}
, sub {$oClient->diff1_1($aCmdLineOptions
, $_[0], $xPeg1, $_[1], $xPeg2, $bRecurse
, $bIgnoreAncestry, $bIgnoreDeleted, $_[2], $_[3])}
, sub {$oClient->diff1_4($aCmdLineOptions
, $_[0], $xPeg1, $_[1], $xPeg2, $bRecurse
, $bIgnoreAncestry, $bIgnoreDeleted, $bDiffBinary
, $sHeaderEncoding, $_[2], $_[3])}
, sub {$oClient->diff1_5($aCmdLineOptions
, $_[0], $xPeg1, $_[1], $xPeg2, $sRelativeToDir
, $iDepth, $bIgnoreAncestry, $bIgnoreDeleted
, $bDiffBinary, $sHeaderEncoding, $_[2], $_[3]
, $aChangeLists)}
, sub {$oClient->diff1_6($aCmdLineOptions
, $_[0], $xPeg1, $_[1], $xPeg2, $sRelativeToDir
, $iDepth, $bIgnoreAncestry, $bIgnoreDeleted
, $bDiffBinary, $sHeaderEncoding, $_[2], $_[3]
, $aChangeLists)}
, sub {$oClient->diff1_7($aCmdLineOptions
, $_[0], $xPeg1, $_[1], $xPeg2, $sRelativeToDir
, $iDepth, $bIgnoreAncestry, $bIgnoreDeleted
, $bShowCopiesAsAdds, $bDiffBinary, $bUseGitDiffFormat
, $sHeaderEncoding, $_[2], $_[3], $aChangeLists)}
);
for my $i (0..$#$aPath1) {
my $sPath1 = $aPath1->[$i];
next unless defined($sPath1);
my $sPath2 = defined($aPath2) ? $aPath2->[$i] : undef;
my $sTest = "$sName: diff$VERSION_SUFFIXES[$i]($sPath1, "
. (defined($sPath2)?$sPath2:'undef').")";
my $fhOut = defined($sOut)
? $SANDBOX->createReadWriteStream() : undef;
my $fhErr = defined($sErr)
? $SANDBOX->createReadWriteStream() : undef;
if (okNotifyActions {
$aDiff[$i]->($sPath1, $sPath2, $fhOut, $fhErr)
} $sTest, $aExpectedActions) {
local $/;
if (defined($fhOut)) {
seek($fhOut, 0, 0);
like(<$fhOut>, $reOut, "$sTest - verifying output stream");
}
if (defined($fhErr)) {
seek($fhErr, 0, 0);
like(<$fhErr>, $reErr, "$sTest - verifying error stream");
}
}
close $fhOut if defined($fhOut);
close $fhErr if defined($fhErr);
}
}
#--------------------------------------------------------------------
sub okExport {
my ($sName, $oClient, $xPaths, $aExport, $aParams
, $aListing, $aExpectedActions) = @_;
$aListing = [ sort @$aListing ];
my ($aPaths, $xPeg, $xRev) = ref($xPaths) ? @$xPaths : ($xPaths);
$aPaths = [ $aPaths ] if ! ref($aPaths);
my $bCommitted= defined($xPeg) && ($xPeg ne 'WORKING');
# if exporting from the repository, one add for each file +
# one for the containing directory
# whether from the repository or working copy,
# there is a update_completed action
if (!defined($aExpectedActions)) {
$aExpectedActions = $bCommitted
? [($SVN::Wc::Notify::Action::update_add)
x (scalar(@$aListing)+1)]
: [];
push @$aExpectedActions
, $SVN::Wc::Notify::Action::update_completed;
}
my $bVerify = ref($aExpectedActions) eq 'ARRAY' ?1:0;
$aParams=[] unless defined($aParams);
my ($iDepth, $bOverwrite, $bSkipExternals, $bIgnoreKeywords
, $sNativeEol, $oPool) = @$aParams;
my $bRecurse = !defined($iDepth) ? undef : ($iDepth? 1 : 0);
my $bMinimal = _isMinimal($aParams, $xPeg, $xRev);
my @aExport = $bMinimal
? ( sub { $oClient->export($_[0],$xPeg, $_[1]) }
, sub { $oClient->export1_1($_[0], $_[1]) }
, sub { $oClient->export1_4($_[0], $_[1]) }
, sub { $oClient->export1_5($_[0], $_[1]) }
, sub { $oClient->export1_6($_[0], $_[1]) }
, sub { $oClient->export1_7($_[0], $_[1]) }
)
: ( sub { $oClient->export($_[0], $xPeg, $_[1], $bOverwrite
, $oPool) }
, sub { $oClient->export1_1($_[0], $_[1], $xPeg, $bOverwrite
, $sNativeEol, $oPool) }
, sub { $oClient->export1_4($_[0], $_[1], $xPeg, $xRev
, $bOverwrite, $bSkipExternals, $bRecurse, $sNativeEol
, $oPool) }
, sub { $oClient->export1_5($_[0], $_[1], $xPeg, $xRev
, $bOverwrite, $bSkipExternals, $iDepth, $sNativeEol
, $oPool) }
, sub { $oClient->export1_6($_[0], $_[1], $xPeg, $xRev
, $bOverwrite, $bSkipExternals, $iDepth, $sNativeEol
, $oPool) }
, sub { $oClient->export1_7($_[0], $_[1], $xPeg, $xRev
, $bOverwrite, $bSkipExternals, $bIgnoreKeywords
, $iDepth, $sNativeEol, $oPool) }
);
for my $i (0..$#$aPaths) {
my $sPath = $aPaths->[$i];
next unless defined($sPath);
my $sExport = $aExport->[$i];
my $sTest
= "$sName: export$VERSION_SUFFIXES[$i]($sPath=>$sExport)";
okNotifyActions { $aExport[$i]->($sPath, $sExport);
} $sTest, $aExpectedActions;
next unless $bVerify;
ok(-d $sExport, "$sTest: exported directory exists");
my $aGot = [ sort @{$SANDBOX->list($sExport,1)} ];
is_deeply($aGot, $aListing
, "$sTest: verifying directory contents")
or diag("got=(@$aGot)\nexpected=(@$aListing)\n");
}
return $aPaths;
}
#--------------------------------------------------------------------
sub okGetStatus {
my ($sTest, $oClient, $sPath, $hExpectedStatus) = @_;
if (defined($hExpectedStatus)
&& (ref($hExpectedStatus) ne 'HASH')) {
$hExpectedStatus
= { text_status => $hExpectedStatus->text_status()
, prop_status => $hExpectedStatus->prop_status()
, locked => $hExpectedStatus->locked()
, copied => $hExpectedStatus->copied()
, switched => $hExpectedStatus->switched()
, repos_text_status => $hExpectedStatus->repos_text_status()
, repos_prop_status => $hExpectedStatus->repos_prop_status()
};
}
my $oStatus = $oClient->getStatus($sPath);
my $hGot = ref($oStatus)
? { text_status => $oStatus->text_status()
, prop_status => $oStatus->prop_status()
, locked => $oStatus->locked()
, copied => $oStatus->copied()
, switched => $oStatus->switched()
, repos_text_status => $oStatus->repos_text_status()
, repos_prop_status => $oStatus->repos_prop_status()
} : $oStatus;
return is_deeply($hGot, $hExpectedStatus
, "$sTest: verifying status");
}
#--------------------------------------------------------------------
sub okImport {
my ($sName, $oClient, $sImport, $aRepoURLs, $sBranch, $aParams
, $iRev, $aListing, $aExpectedActions) = @_;
$aListing = [ sort @$aListing ];
$aExpectedActions
=[ ($SVN::Wc::Notify::Action::commit_added) x scalar(@$aListing) ]
unless defined($aExpectedActions);
my $bVerify = ref($aExpectedActions) eq 'ARRAY' ?1:0;
$aParams=[] unless defined($aParams);
my ($sComment, $iDepth, $bNoIgnore, $bIgnoreUnknownNodeTypes
, $hRevProp, $crCommit, $oPool) = @$aParams;
my $bRecurse = !defined($iDepth) ? undef : ($iDepth? 1 : 0);
my $bNonRecursive = !defined($bRecurse)? undef : ($bRecurse?0:1);
my $bMinimal = _isMinimal($aParams);
my @aImport = $bMinimal
? ( sub { $oClient->import($_[0], $_[1]) }
, sub { $oClient->import1_1($_[0], $_[1]) }
, sub { $oClient->import1_4($_[0], $_[1]) }
, sub { $oClient->import1_5($_[0], $_[1]) }
, sub { $oClient->import1_6($_[0], $_[1]) }
, sub { $oClient->import1_7($_[0], $_[1]) }
)
: ( sub { $oClient->import($_[0], $_[1], $sComment
, $bRecurse, $oPool) }
, sub { $oClient->import1_1($_[0], $_[1], $sComment
, $bNonRecursive, $oPool) }
, sub { $oClient->import1_4($_[0], $_[1], $sComment
, $bNonRecursive, $bNoIgnore, $oPool) }
, sub { $oClient->import1_5($_[0], $_[1], $sComment, $iDepth
, $bNoIgnore, $bIgnoreUnknownNodeTypes, $hRevProp
, $oPool) }
, sub { $oClient->import1_6($_[0], $_[1], $sComment, $iDepth
, $bNoIgnore, $bIgnoreUnknownNodeTypes, $hRevProp
, $oPool) }
, sub { $oClient->import1_7($_[0], $_[1], $sComment, $iDepth
, $bNoIgnore, $bIgnoreUnknownNodeTypes, $hRevProp
, $crCommit, $oPool) }
);
my @aPaths;
for my $i (0..$#$aRepoURLs) {
my $sRepoURL = $aRepoURLs->[$i];
next unless defined($sRepoURL);
# POSIX paths can be appended to http URL's but not necessarily
# file URLs.
my $sPath = $sRepoURL =~ m{^file://(.*)$}
? 'file://' . File::Spec->rel2abs($sBranch, $1)
: "$sRepoURL/$sBranch";
push @aPaths, $sPath;
my $sTest
= "$sName: import$VERSION_SUFFIXES[$i]($sImport=>$sPath)";
my $oCommitInfo;
okNotifyActions { $oCommitInfo = $aImport[$i]->($sImport,$sPath);
} $sTest, $aExpectedActions, 1;
next unless $bVerify;
SKIP: {
if ($SKIP_SWIG_BUGS && ($i >= $IDX_SVN1_4)) {
my $sBug="commit: svn_commit_info_t package "
."undefined in SWIG-Perl";
$SWIG_BINDING_BUGS{$sBug}++;
local $TODO = "SWIG binding bug: need to report\n\t$sBug";
skip $sTest, 1;
}
# eval because if we don't skip this bug it will cause
# a fatal error and we'd rather see the error message and
# continue
eval {
is(defined($oCommitInfo) ? $oCommitInfo->revision : undef
, $iRev, "$sTest - verifying revision number");
} or do {
my $e=$@;
$e='unknown' if defined($e) && !length($e);
warn "$sTest: $e";
};
}
my $aGot = [ sort @{$oClient->getPathList($sPath, $iRev)} ];
is_deeply($aGot, $aListing
, "$sTest: verifying directory contents")
or diag("got=(@$aGot)\nexpected=(@$aListing)\n");
}
return \@aPaths;
}
#--------------------------------------------------------------------
sub okInfo {
my ($sName, $oClient, $xPaths, $aParams
, $iVisits, $hExpectedInfo, $aExpectedActions) = @_;
$aExpectedActions = [] unless defined($aExpectedActions);
my ($aPaths, $xPeg, $xRev) = ref($xPaths) ? @$xPaths : ($xPaths);
$aParams = [] unless defined($aParams);
my ($iDepth, $aChangeLists) = @$aParams;
my $bRecurse = !defined($iDepth) ? undef : ($iDepth? 1 : 0);
my $bMinimal = _isMinimal($aParams, $xPeg, $xRev);
my @aInfo = $bMinimal
? ( sub { $oClient->info($_[0],$xPeg, $xRev, $_[1]) }
, sub { $oClient->info1_1($_[0], $xPeg, $xRev, $_[1]) }
, sub { $oClient->info1_4($_[0], $xPeg, $xRev, $_[1]) }
, sub { $oClient->info1_5($_[0], $xPeg, $xRev, $_[1]) }
, sub { $oClient->info1_6($_[0], $xPeg, $xRev, $_[1]) }
, sub { $oClient->info1_7($_[0], $xPeg, $xRev, $_[1]) }
)
: ( sub { $oClient->info($_[0],$xPeg, $xRev, $_[1]) }
, sub { $oClient->info1_1($_[0], $xPeg, $xRev, $_[1]) }
, sub { $oClient->info1_4($_[0], $xPeg, $xRev, $_[1]
, $bRecurse) }
, sub { $oClient->info1_5($_[0], $xPeg, $xRev, $_[1]
, $iDepth, $aChangeLists) }
, sub { $oClient->info1_6($_[0], $xPeg, $xRev, $_[1]
, $iDepth, $aChangeLists) }
, sub { $oClient->info1_7($_[0], $xPeg, $xRev, $_[1]
, $iDepth, $aChangeLists) }
);
my $bOk=1;
my $sMsg='';
my $hInfo={};
my @aVisits;
my $IDX_PATH = 0;
my $IDX_REV=1;
my $IDX_LOCK = 2;
my $crVisit = sub {
my ($sPath, $oInfo, $oPool) = @_;
my $sRepoURL = $oInfo->URL();
my $xPeg = $oInfo->rev();
my $xLocked = $oInfo->lock();
push @aVisits, [$sRepoURL, $xPeg, $xLocked];
if ($NOISY) {
print STDERR "info: url=<$sRepoURL> rev=<$xPeg"
. "> kind=<" . $CLIENT_CLASS->getKindAsString($oInfo->kind())
. "> repo_root=<" . $oInfo->repos_root_URL()
. "> lock=<" . ($xLocked ? $xLocked : 'undef')
. ">\n";
}
return unless $bOk; # only capture errors once
if (!defined($sPath) || ref($sPath) || !length($sPath)) {
$bOk=0;
$sPath=defined($sPath) ? "'$sPath'" : 'undef';
$sMsg .= "path: expected non-empty string, got <$sPath>\n";
}
if (!defined($oInfo) || ref($oInfo) ne '_p_svn_info_t') {
$oInfo=defined($oInfo) ? "'$oInfo'" : 'undef';
$sMsg .= 'info object: expected reference to svn_info_t'
. ", got <$oInfo>\n";
}
if (!defined($oPool) || ref($oPool) ne '_p_apr_pool_t') {
$oPool=defined($oPool) ? "'$oPool'" : 'undef';
$sMsg .= 'pool object: expected reference to svn_pool_t'
. ", got <$oPool>\n";
}
if (scalar(@aVisits) == 1) {
$hInfo->{last_changed_rev} = $oInfo->last_changed_rev;
$hInfo->{kind} = $oInfo->kind();
$hInfo->{lock} = $oInfo->lock()?1:0;
$hInfo->{repos_UUID} = $oInfo->repos_UUID();
$hInfo->{repos_URL} = $oInfo->repos_root_URL();
}
};
for my $i (0..$#$aPaths) {
my $sPath = $aPaths->[$i];
next unless defined($sPath);
my $sTest = "$sName:info$VERSION_SUFFIXES[$i]($sPath)";
okNotifyActions { $aInfo[$i]->($sPath, undef);
} $sTest, $aExpectedActions;
@aVisits=();
$bOk=1;
$sMsg='';
okNotifyActions { $aInfo[$i]->($sPath, $crVisit);
} $sTest, $aExpectedActions;
$hExpectedInfo->{repos_UUID}
= $oClient->getRepositoryUUID($sPath);
$hExpectedInfo->{repos_URL}
= $oClient->getRepositoryRootURL($sPath);
is_deeply($hInfo, $hExpectedInfo
, "$sTest - verifying retrieved data");
is(scalar(@aVisits), $iVisits, "$sTest - verifying visit count");
ok($bOk, "$sTest - verifying callback parameters")
or diag($sMsg);
}
}
#----------------------------------------------------------------
sub okList {
my ($sName, $oClient, $xPath, $aParams
, $aListing, $aExpectedActions) = @_;
my $aExpectedPaths = defined($aListing) ? [ sort @$aListing ] : [];
$aExpectedActions = [] unless defined($aExpectedActions);
my ($aPaths, $xPeg, $xRev) = ref($xPath) ? @$xPath : ($xPath);
$aParams = [] unless defined($aParams);
my ($crVisit, $iDepth, $iFields, $bFetchLocks) = @$aParams;
my $bRecurse = !defined($iDepth) ? undef : ($iDepth? 1 : 0);
my $bMinimal = _isMinimal($aParams, $xPeg, $xRev);
my @aGot;
my $crSavePaths = sub { push @aGot, $_[0] };
my @aList = $bMinimal
? ( sub { $oClient->list($_[0], $xPeg, $_[1]) }
, sub { $oClient->list1_1($_[0], $xPeg, $bRecurse, $_[1]) }
, sub { $oClient->list1_4($_[0], $xPeg, $xRev, $bRecurse
, $iFields, $bFetchLocks, $_[1]) }
, sub { $oClient->list1_5($_[0], $xPeg, $xRev, $iDepth
, $bFetchLocks, $_[1]) }
, sub { $oClient->list1_6($_[0], $xPeg, $xRev, $iDepth
, $bFetchLocks, $_[1]) }
, sub { $oClient->list1_7($_[0], $xPeg, $xRev, $iDepth
, $bFetchLocks, $_[1]) }
)
: ( sub { $oClient->list($_[0], $xPeg, $_[1], $bRecurse) }
, sub { $oClient->list1_1($_[0], $xPeg, $bRecurse, $_[1]) }
, sub { $oClient->list1_4($_[0], $xPeg, $xRev, $bRecurse
, $iFields, $bFetchLocks, $_[1]) }
, sub { $oClient->list1_5($_[0], $xPeg, $xRev, $iDepth
, $bFetchLocks, $_[1]) }
, sub { $oClient->list1_6($_[0], $xPeg, $xRev, $iDepth
, $bFetchLocks, $_[1]) }
, sub { $oClient->list1_7($_[0], $xPeg, $xRev, $iDepth
, $bFetchLocks, $_[1]) }
);
for my $i (0..$#$aPaths) {
my $sPath = $aPaths->[$i];
next unless defined($sPath);
my $sTest = "$sName:list$VERSION_SUFFIXES[$i]($sPath)";
SKIP: {
if ($SKIP_SWIG_BUGS && ($i == $IDX_SVN1_4)) {
my $sBug="list: svn_client_list thunk undefined in SWIG-Perl";
$SWIG_BINDING_BUGS{$sBug}++;
local $TODO = "SWIG binding bug: need to report\n\t$sBug";
skip $sTest, 1;
}
okNotifyActions { $aList[$i]->($sPath, $crVisit);
} $sTest, $aExpectedActions;
# eval this in case we don't skip the bug
eval {
@aGot=();
$aList[$i]->($sPath, $crSavePaths);
is_deeply([sort @aGot], $aExpectedPaths
, "$sTest - verifying path list")
or diag("\ngot=(@{[sort @aGot]})"
."\nexpected=(@$aExpectedPaths)\n");
return 1;
} or do {
my $e=$@;
$e='unknown reason' if defined($e) && !length($e);
warn "$sTest: $e";
}
}
}
# these methods are only have a 1.1 version
{
my $sPath = $aPaths->[0];
my $sTest = "$sName:ls($sPath)";
my $hEntries = $oClient->ls1_1($sPath, $xPeg, $bRecurse);
is_deeply([sort keys %$hEntries], $aExpectedPaths
, "$sTest - verifying hash keys");
is_deeply([ grep { ref($_) ne '_p_svn_dirent_t'
} values %$hEntries]
,[], "$sTest - verifying hash values");
$sTest = "$sName:getPathList($sPath)";
my $aPaths = $oClient->getPathList($sPath, $xPeg, $xRev);
is_deeply([ sort @$aPaths], $aExpectedPaths, $sTest);
}
}
#--------------------------------------------------------------------
sub okLock {
my ($sName, $oClient, $aPaths, $aParams, $aExpectedActions) = @_;
$aParams=[] unless defined($aParams);
my ($sComment, $bStealLock) = @$aParams;
my $bMinimal = _isMinimal($aParams);
my @aLock = $bMinimal
? ( sub { $oClient->lock($_[0]) }
, sub { $oClient->lock1_1($_[0]) }
, sub { $oClient->lock1_4($_[0]) }
, sub { $oClient->lock1_5($_[0]) }
, sub { $oClient->lock1_6($_[0]) }
, sub { $oClient->lock1_7($_[0]) }
)
: ( sub { $oClient->lock($_[0], $sComment, $bStealLock) }
, sub { $oClient->lock1_1($_[0], $sComment, $bStealLock) }
, sub { $oClient->lock1_4($_[0], $sComment, $bStealLock) }
, sub { $oClient->lock1_5($_[0], $sComment, $bStealLock) }
, sub { $oClient->lock1_6($_[0], $sComment, $bStealLock) }
, sub { $oClient->lock1_7($_[0], $sComment, $bStealLock) }
);
for my $i (0..$#$aPaths) {
my $sPath = $aPaths->[$i];
next unless defined($sPath);
my $sTest = "$sName:lock$VERSION_SUFFIXES[$i]($sPath)";
okNotifyActions { $aLock[$i]->($sPath);
} $sTest, $aExpectedActions,1;
my $oLock = $oClient->getInfo($sPath)->lock();
ok($oLock, "$sName - verifying lock status");
is($oLock->comment(), $sComment, "$sName - verifying comment");
}
}
#--------------------------------------------------------------------
sub okLog {
my ($sName, $oClient, $xPaths, $aParams
, $iVisits, $aExpectedLogMessages, $aExpectedActions) = @_;
$aExpectedActions = [] unless defined($aExpectedActions);
my ($aPaths, $xPeg, $aRevRanges)
= ref($xPaths) ? @$xPaths : ($xPaths);
$aParams = [] unless defined($aParams);
my ($iDepth, $iVisitLimit, $bChangedPaths, $bStrictNodeHistory
, $bIncludeMergedRevisions, $aRevProps) = @$aParams;
my $bRecurse = !defined($iDepth) ? undef : ($iDepth? 1 : 0);
my ($xStart, $xEnd) = defined($aRevRanges) && scalar($aRevRanges)
? @{$aRevRanges->[0]} : (undef, undef);
my $bMinimal = _isMinimal($aParams);
my @aLog = $bMinimal
? ( sub { $oClient->log($_[0],$xStart, $xEnd, $_[1]) }
, sub { $oClient->log1_1($_[0],$xStart, $xEnd
, $bChangedPaths, $bStrictNodeHistory, $_[1]) }
, sub { $oClient->log1_4($_[0], $xPeg, $xStart, $xEnd
, $iVisitLimit, $bChangedPaths, $bStrictNodeHistory
, $_[1]) }
, sub { $oClient->log1_5($_[0], $xPeg, $xStart, $xEnd
, $iVisitLimit, $bChangedPaths, $bStrictNodeHistory
, $bIncludeMergedRevisions, $aRevProps, $_[1]) }
, sub { $oClient->log1_6($_[0], $xPeg, $aRevRanges
, $iVisitLimit, $bChangedPaths, $bStrictNodeHistory
, $bIncludeMergedRevisions, $aRevProps, $_[1]) }
, sub { $oClient->log1_7($_[0], $xPeg, $aRevRanges
, $iVisitLimit, $bChangedPaths, $bStrictNodeHistory
, $bIncludeMergedRevisions, $aRevProps, $_[1]) }
)
: ( sub { $oClient->log($_[0],$xStart, $xEnd, $_[1]
, $bChangedPaths, $bStrictNodeHistory) }
, sub { $oClient->log1_1($_[0],$xStart, $xEnd
, $bChangedPaths, $bStrictNodeHistory, $_[1]) }
, sub { $oClient->log1_4($_[0], $xPeg, $xStart, $xEnd
, $iVisitLimit, $bChangedPaths, $bStrictNodeHistory
, $_[1]) }
, sub { $oClient->log1_5($_[0], $xPeg, $xStart, $xEnd
, $iVisitLimit, $bChangedPaths, $bStrictNodeHistory
, $bIncludeMergedRevisions, $aRevProps, $_[1]) }
, sub { $oClient->log1_6($_[0], $xPeg, $aRevRanges
, $iVisitLimit, $bChangedPaths, $bStrictNodeHistory
, $bIncludeMergedRevisions, $aRevProps, $_[1]) }
, sub { $oClient->log1_7($_[0], $xPeg, $aRevRanges
, $iVisitLimit, $bChangedPaths, $bStrictNodeHistory
, $bIncludeMergedRevisions, $aRevProps, $_[1]) }
);
my $bOk=1;
my $sMsg='';
my @aGotMessages;
my $iGotVisits=0;
my $crVisit1 = sub {
my ($hChangedPaths, $iRev, $sAuthor, $sDate, $sMessage
, $oPool) = @_;
push @aGotMessages, $sMessage;
$iGotVisits++;
return unless $bOk; # only capture errors once
$sMsg="rev=$iRev\n";
if ($bChangedPaths) {
if (!defined($hChangedPaths)
|| (ref($hChangedPaths) ne 'HASH')) {
$bOk=0;
$hChangedPaths= defined($hChangedPaths)
? "'$hChangedPaths'" : 'undef';
$sMsg .= 'changed paths hash: expected reference to svn_log_t'
. "m got <$hChangedPaths>\n";
}
} elsif (defined($hChangedPaths)) {
$bOk=0;
$sMsg .= "changed paths hash: unexpectedly defined - log() "
. "was not called with bChangedPaths=true";
}
if ($iRev !~ m{\d+}) {
$bOk=0;
$sMsg.= "revision: expected \\d+, got <$iRev>\n";
}
if (!defined($sDate) || ref($sDate)
|| !length($sDate)) {
$bOk=0;
$sDate= defined($sDate) ? "'$sDate'" : 'undef';
$sMsg .= "timestamp: expected non-empty string, got "
."<$sDate>\n";
}
if (!defined($sAuthor) || ref($sAuthor) || !length($sAuthor)) {
$bOk=0;
$sAuthor=defined($sAuthor) ? "'$sAuthor'" : 'undef';
$sMsg .= "author: expected non-empty string, got <$sAuthor>\n";
}
if (!defined($sMessage) || ref($sMessage)) {
$bOk=0;
$sMessage=defined($sMessage) ? "'$sMessage'" : 'undef';
$sMsg .= "message: expected a string, got <$sMessage>\n";
}
if (!defined($oPool) || ref($oPool) ne '_p_apr_pool_t') {
$oPool=defined($oPool) ? "'$oPool'" : 'undef';
$sMsg .= 'pool object: expected reference to svn_pool_t'
. ", got <$oPool>\n";
}
};
my $crVisit2 = sub {
my ($oLogEntry, $oPool) = @_;
if (!defined($oLogEntry)
|| ref($oLogEntry) ne '_p_svn_log_entry_t') {
$oLogEntry=defined($oLogEntry) ? "'$oLogEntry'" : 'undef';
$sMsg .= 'pool object: expected reference to svn_pool_t'
. ", got <$oLogEntry>\n";
}
if (!defined($oPool) || ref($oPool) ne '_p_apr_pool_t') {
$oPool=defined($oPool) ? "'$oPool'" : 'undef';
$sMsg .= 'pool object: expected reference to svn_pool_t'
. "got <$oPool>\n";
}
};
my @aVisitors = ($crVisit1, $crVisit1, $crVisit1
, $crVisit2, $crVisit2, $crVisit2);
for my $i (0..$#$aPaths) {
my $sPath = $aPaths->[$i];
next unless defined($sPath);
my $sTest = "$sName:log$VERSION_SUFFIXES[$i]($sPath)";
okNotifyActions { $aLog[$i]->($sPath, undef);
} $sTest, $aExpectedActions;
$iGotVisits=0;
$bOk=1;
$sMsg='';
@aGotMessages=();
okNotifyActions { $aLog[$i]->($sPath, $aVisitors[$i]);
} $sTest, $aExpectedActions;
is($iGotVisits, $iVisits, "$sTest - verifying visit count");
is_deeply(\@aGotMessages, $aExpectedLogMessages
, "$sTest - verifying log messages");
ok($bOk, "$sTest - verifying callback parameters")
or diag($sMsg);
}
}
#----------------------------------------------------------------
sub okMerge {
my ($sName, $oClient, $xPath1, $xPath2, $aWcs, $aParams
, $aList, $aExpectedActions)= @_;
$aExpectedActions = $MERGE_ACTIONS
unless defined($aExpectedActions);
my ($aPath1, $xPeg1) = ref($xPath1) ? @$xPath1 : ($xPath1);
my ($aPath2, $xPeg2) = ref($xPath2) ? @$xPath2 : ($xPath2);
my ($iDepth, $aMergeOptions, $bIgnoreAncestry, $bForceDelete
, $bDryRun, $bRecordOnly, $bAllowMixedRevs) = @$aParams;
my $bRecurse = !defined($iDepth) ? undef : ($iDepth? 1 : 0);
my $bMinimal = _isMinimal($aParams, $xPeg1, $xPeg2);
my @aMerge = $bMinimal
? ( sub { $oClient->merge($_[0], $xPeg1, $_[1], $xPeg2, $_[2])}
, sub {$oClient->merge1_1($_[0], $xPeg1, $_[1], $xPeg2,$_[2])}
, sub {$oClient->merge1_4($_[0], $xPeg1, $_[1], $xPeg2,$_[2])}
, sub {$oClient->merge1_5($_[0], $xPeg1, $_[1], $xPeg2,$_[2])}
, sub {$oClient->merge1_6($_[0], $xPeg1, $_[1], $xPeg2,$_[2])}
, sub {$oClient->merge1_7($_[0], $xPeg1, $_[1], $xPeg2,$_[2])}
)
: ( sub { $oClient->merge($_[0], $xPeg1, $_[1], $xPeg2, $_[2]
, $bRecurse, $bIgnoreAncestry, $bForceDelete, $bDryRun
)}
, sub {$oClient->merge1_1($_[0], $xPeg1, $_[1], $xPeg2, $_[2]
, $bRecurse, $bIgnoreAncestry, $bForceDelete, $bDryRun
)}
, sub {$oClient->merge1_4($_[0], $xPeg1, $_[1], $xPeg2, $_[2]
, $bRecurse, $bIgnoreAncestry, $bForceDelete, $bDryRun
, $aMergeOptions)}
, sub {$oClient->merge1_5($_[0], $xPeg1, $_[1], $xPeg2, $_[2]
, $iDepth, $bIgnoreAncestry, $bForceDelete, $bRecordOnly
, $bDryRun, $aMergeOptions)}
, sub {$oClient->merge1_6($_[0], $xPeg1, $_[1], $xPeg2, $_[2]
, $iDepth, $bIgnoreAncestry, $bForceDelete, $bRecordOnly
, $bDryRun, $aMergeOptions)}
, sub {$oClient->merge1_7($_[0], $xPeg1, $_[1], $xPeg2, $_[2]
, $iDepth, $bIgnoreAncestry, $bForceDelete, $bRecordOnly
, $bDryRun, $bAllowMixedRevs, $aMergeOptions)}
);
for my $i (0..$#$aPath1) {
my $sPath1 = $aPath1->[$i];
next unless defined($sPath1);
my $sPath2 = defined($aPath2) ? $aPath2->[$i] : undef;
my $sWc = $aWcs->[$i];
my $sTest = "$sName: merge$VERSION_SUFFIXES[$i]("
."$sPath1 - $sPath2 => $sWc)";
okNotifyActions { $aMerge[$i]->($sPath1, $sPath2, $sWc)
} $sTest, $aExpectedActions, 1;
# TODO:
# get listing of files - from repo? from local dir?
# compare to list.
}
}
#--------------------------------------------------------------------
sub okMkdir {
my ($sName, $oClient, $aPaths, $sRelPath, $aParams, $hExpectedStatus
, $aExpectedActions) = @_;
my $bLocal = defined($hExpectedStatus)?1:0;
$aExpectedActions=($bLocal ? $ADD_ACTIONS : [])
unless defined($aExpectedActions);
my $bVerify = ref($aExpectedActions) eq 'ARRAY' ?1:0;
$aParams=[] unless defined($aParams);
my ($sComment, $bMakeParents, $hRevProps, $crCommit) = @$aParams;
my $bMinimal = _isMinimal($aParams);
if (defined($sRelPath)) {
my $aWcs = $aPaths;
$aPaths = [ map { $_->getFullPathName($sRelPath) } @$aWcs ];
}
my @aMkdir = $bMinimal
? ( sub { $oClient->mkdir($_[0]) }
, sub { $oClient->mkdir1_1($_[0]) }
, sub { $oClient->mkdir1_4($_[0]) }
, sub { $oClient->mkdir1_5($_[0]) }
, sub { $oClient->mkdir1_6($_[0]) }
, sub { $oClient->mkdir1_7($_[0]) }
)
: ( sub { $oClient->mkdir($_[0], $sComment) }
, sub { $oClient->mkdir1_1($_[0], $sComment) }
, sub { $oClient->mkdir1_4($_[0], $sComment) }
, sub { $oClient->mkdir1_5($_[0], $sComment, $bMakeParents
, $hRevProps) }
, sub { $oClient->mkdir1_6($_[0], $sComment, $bMakeParents
, $hRevProps) }
, sub { $oClient->mkdir1_7($_[0], $sComment, $bMakeParents
, $hRevProps, $crCommit) }
);
for my $i (0..$#$aPaths) {
my $sPath = $aPaths->[$i];
next unless defined($sPath);
my $sTest = "$sName: mkdir$VERSION_SUFFIXES[$i]($sPath)";
okNotifyActions { $aMkdir[$i]->($sPath);
} $sTest, $aExpectedActions, 1;
if ($bLocal) {
okGetStatus($sTest, $oClient, $sPath, $hExpectedStatus);
}
next unless $bVerify;
if ($bLocal) {
ok(-d $sPath, "$sTest: created directory exists");
}
}
return $aPaths;
}
#--------------------------------------------------------------------
sub okMove {
my ($sName, $oClient, $aFrom, $aTo, $xRelPath, $aParams
, $aExpectedActions) = @_;
$aExpectedActions = $MOVE_ACTIONS unless defined($aExpectedActions);
my $bVerify = ref($aExpectedActions) eq 'ARRAY' ?1:0;
if (defined($xRelPath)) {
my $aWcs = $aTo;
my ($sRelPath, $bFile)= ref($xRelPath) ? @$xRelPath : ($xRelPath);
$aTo = [ map { $_->getFullPathName($sRelPath, $bFile) } @$aWcs ];
}
$aParams = [] unless defined($aParams);
my ($crCommit, $bForce, $bMoveAsChild, $bMakeParents, $hRevProps)
= @$aParams;
my $bMinimal = _isMinimal($aParams);
my @aMove = $bMinimal
? ( sub { $oClient->move($_[0], $_[1]); }
, sub { $oClient->move1_1($_[0], undef, $_[1]) }
, sub { $oClient->move1_4($_[0], $_[1]) }
, sub { $oClient->move1_5($_[0], $_[1]) }
, sub { $oClient->move1_6($_[0], $_[1]) }
, sub { $oClient->move1_7($_[0], $_[1]) }
)
: ( sub { $oClient->move($_[0], $_[1], $bForce); }
, sub { $oClient->move1_1($_[0], undef, $_[1], $bForce) }
, sub { $oClient->move1_4($_[0], $_[1], $bForce) }
, sub { $oClient->move1_5($_[0], $_[1], $bForce, $bMoveAsChild
, $bMakeParents, $hRevProps) }
, sub { $oClient->move1_6($_[0], $_[1], $bForce, $bMoveAsChild
, $bMakeParents, $hRevProps) }
, sub { $oClient->move1_7($_[0], $_[1], $bMoveAsChild
, $bMakeParents, $hRevProps, $crCommit) }
);
for my $i (0..$#$aFrom) {
my $sFrom = $aFrom->[$i];
next unless defined($sFrom);
my $sTo = $aTo->[$i];
my $sTest = "$sName:move$VERSION_SUFFIXES[$i]($sFrom => $sTo)";
my $hFromStatus = $oClient->getStatus($sFrom);
my $bDeleteWhenScheduled = (-d $sFrom) ? 0 : 1;
okNotifyActions { $aMove[$i]->($sFrom, $sTo);
} $sTest, $aExpectedActions, 1;
next unless $bVerify;
okGetStatus("$sTest - verifying change in source status"
, $oClient, $sFrom, $DEL_STATUS);
is((-e $sFrom)?1:0, $bDeleteWhenScheduled?0:1
, "$sTest - verifiying removal of source");
okGetStatus("$sTest - verifying target status"
, $oClient, $sTo, $COPY_STATUS);
is((-e $sTo)?1:0, 1, "$sTest - verifiying existance of target");
}
return $aTo;
}
#--------------------------------------------------------------------
sub okNotifyActions(&$$;$) {
my ($cr, $sTest, $aExpectedActions, $bDieOnUnexpectedException)=@_;
local $Test::Builder::Level = $Test::Builder::Level + 1;
my $bOk=1;
my $sRefExpect=ref($aExpectedActions);
eval {
local $Test::Builder::Level = $Test::Builder::Level + 1;
@aNotifications=();
$cr->();
if ($sRefExpect eq 'ARRAY') {
if ($NOTIFYING) {
my @aActions
= map { $_->[$IDX_NOTIFY_ACTION] } @aNotifications;
$bOk=is_deeply(\@aActions, $aExpectedActions
, "$sTest - verifying actions")
or do {
$aExpectedActions= [ map {
$CLIENT_CLASS->getActionAsString($_)
} @$aExpectedActions ];
@aActions = map { $CLIENT_CLASS->getActionAsString($_)
} @aActions;
local $"='; ';
diag("\nGot actions= (@aActions)"
."\nExpected actions: (@$aExpectedActions)"
);
};
}
} else {
my $sError = 'exception expected but none thrown';
$bOk=fail("$sTest: $sError");
# failure to throw an exception may mean that an operation will
# commit when it wasn't expected to, thereby throwing off the rev
# counts.
die $sError if ($bDieOnUnexpectedException);
}
return 1;
} or do {
my $e=$@;
if ($sRefExpect eq 'ARRAY') {
$bOk=fail("$sTest: unexpected exception: $e");
if ($bDieOnUnexpectedException) {
BAIL_OUT("remaining tests not applicable due to "
."unexpected exception");
}
} elsif (defined($aExpectedActions) && ($aExpectedActions eq '')){
pass("$sTest: exception thrown");
} elsif (defined($aExpectedActions)) {
$bOk=like($e, $aExpectedActions, "$sTest: verifying exception");
} else {
$@=$e; die; #rethrow
}
};
return $bOk;
}
#--------------------------------------------------------------------
sub okPropdel {
my ($sName, $oClient, $aPaths, $aDelProps, $aParams
, $hRemaining, $hExpectedStatus, $aExpectedActions) = @_;
local $Test::Builder::Level = $Test::Builder::Level + 1;
$aExpectedActions=[] unless defined($aExpectedActions);
my $bVerify = ref($aExpectedActions) eq 'ARRAY' ?1:0;
$aParams=[] unless defined($aParams);
my ($crCommit, $iDepth, $bSkipChecks, $xBaseRev, $aChangeLists
, $hRevProp) = @$aParams;
my $bRecurse = !defined($iDepth) ? undef : ($iDepth? 1 : 0);
my $bMinimal = _isMinimal($aParams);
my @aPropdel = $bMinimal
? ( sub { $oClient->propdel($_[1], $_[0]) }
, sub { $oClient->propdel1_1($_[0],$_[1]) }
, sub { $oClient->propdel1_4($_[0],$_[1]) }
, sub { $oClient->propdel1_5($_[0],$_[1]) }
, sub { $oClient->propdel1_6($_[0],$_[1]) }
, sub { $oClient->propdel1_7($_[0],$_[1]) }
)
: ( sub { $oClient->propdel($_[1], $_[0], $bRecurse) }
, sub { $oClient->propdel1_1($_[0],$_[1], $bRecurse) }
, sub { $oClient->propdel1_4($_[0],$_[1], $bRecurse
, $bSkipChecks) }
, sub { $oClient->propdel1_5($_[0],$_[1], $iDepth
, $bSkipChecks, $xBaseRev, $aChangeLists, $hRevProp) }
, sub { $oClient->propdel1_6($_[0],$_[1], $iDepth
, $bSkipChecks, $xBaseRev, $aChangeLists, $hRevProp) }
, sub { $oClient->propdel1_7($_[0],$_[1], $iDepth
, $bSkipChecks, $xBaseRev, $aChangeLists, $hRevProp
, $crCommit) }
);
for my $i (0..$#$aPaths) {
my $sPath = $aPaths->[$i];
next unless defined($sPath);
my $sTest = "$sName:propdel$VERSION_SUFFIXES[$i]($sPath)";
foreach my $k (@$aDelProps) {
my $sSubtest = "$sTest: $k";
okNotifyActions { $aPropdel[$i]->($k, $sPath);
} $sSubtest, $aExpectedActions, 1;
}
okGetStatus("$sTest - verifying target status"
, $oClient, $sPath, $hExpectedStatus);
next unless $bVerify;
is_deeply($oClient->getPathProperties($sPath), $hRemaining
, "$sTest - verifying deletion of properties");
}
}
#--------------------------------------------------------------------
sub okPropertyHash {
my ($hGot, $hExpected, $sTest) = @_;
my $bOk=1;
# make sure $hGot and $hExpected are of the same type
if (!defined($hExpected)) {
if (!defined($hGot)) {
pass($sTest); # both undefined, nothing to do
return 1;
}
$bOk = 0;
} elsif (ref($hGot) ne 'HASH') {
$bOk = 0;
}
if (!$bOk) {
fail($sTest);
diag( "Got: ".(defined($hGot)?$hGot:'undef')."\n"
."Expected: ".(defined($hExpected)?$hExpected:'undef')
."\n");
return 0;
}
# don't include svn properties in extra properties
my @aExtra = grep {
(($_ =~ qr{^svn:}) || exists($hExpected->{$_})) ?0:1
} keys %$hGot;
if (@aExtra) {
fail($sTest);
if (scalar(@aExtra) == 1) {
diag("Got an unexpected property: @aExtra");
} else {
diag("Got unexpected properties: @aExtra");
}
return 0;
}
# find a mismatch and print out the rest of the keys
my @aGot;
my @aExpected=keys %$hExpected;
foreach my $k (keys %$hExpected) {
if (!exists($hGot->{$k})) {
fail($sTest);
diag( "Got : {$k}=>Does not exist\n"
."Expected: {$k}=>".$hExpected->{$k}."\n");
$bOk=0;
} else {
push @aGot, $k;
if ($bOk && ($hExpected->{$k} ne $hGot->{$k})) {
fail($sTest);
diag( "Got: {$k}=>".$hGot->{$k}."\n"
."Expected: {$k}=>".$hExpected->{$k}."\n");
$bOk=0;
}
}
}
if (!$bOk) {
diag("Got keys: (@aGot)\nExpected keys: (@aExpected)\n");
}
return $bOk;
}
#--------------------------------------------------------------------
sub okPropget {
my ($sName, $oClient, $xPaths, $aParams
, $iSetInRev, $hProps, $aExpectedActions) = @_;
# if expected actions is not a [], then it is an error class or
# regex for matching a string exception.
$aExpectedActions=[] unless defined($aExpectedActions);
my $bVerify = ref($aExpectedActions) eq 'ARRAY' ?1:0;
my ($aPaths, $xPeg, $xRev) = ref($xPaths) ? @$xPaths : ($xPaths);
my $bCommitted= defined($xPeg) && ($xPeg ne 'WORKING');
$aParams = [] unless defined($aParams);
my ($iDepth, $aChangeLists) = @$aParams;
my $bRecurse = !defined($iDepth) ? undef : ($iDepth? 1 : 0);
my $bMinimal = _isMinimal($aParams, $xPeg, $xRev);
my @aPropget = $bMinimal
? ( sub { $oClient->propget($_[0], $_[1]) }
, sub { $oClient->propget1_1($_[1], $_[0]) }
, sub { $oClient->propget1_4($_[1], $_[0]) }
, sub { $oClient->propget1_5($_[1], $_[0]) }
, sub { $oClient->propget1_6($_[1], $_[0]) }
, sub { $oClient->propget1_7($_[1], $_[0]) }
)
: ( sub { $oClient->propget($_[0], $_[1], $xPeg) }
, sub { $oClient->propget1_1($_[1], $_[0], $xPeg, $bRecurse) }
, sub { $oClient->propget1_4($_[1], $_[0], $xPeg, $xRev
, $bRecurse) }
, sub { $oClient->propget1_5($_[1], $_[0], $xPeg, $xRev
, $iDepth, $aChangeLists) }
, sub { $oClient->propget1_6($_[1], $_[0], $xPeg, $xRev
, $iDepth, $aChangeLists) }
, sub { $oClient->propget1_7($_[1], $_[0], $xPeg, $xRev
, $iDepth, $aChangeLists) }
);
for my $i (0..$#$aPaths) {
my $sPath = $aPaths->[$i];
next unless defined($sPath);
while (my ($k,$v) = each(%$hProps)) {
my $sTest
= "$sName:propget$VERSION_SUFFIXES[$i]($sPath@"
. (defined($xPeg)?$xPeg:'WORKING') .": $k=$v)";
my @aGot;
okNotifyActions { @aGot = $aPropget[$i]->($sPath, $k);
} $sTest, $aExpectedActions;
next if ! $bVerify;
my $sPegPath = $bCommitted
? $oClient->getRepositoryURL($sPath) : $sPath;
is($aGot[0]->{$sPegPath}, $v
, "$sTest - verifying value (locally)");
if ($IDX_SVN1_4 < $i) {
is($aGot[1], $iSetInRev
, "$sTest - verifying revision (locally)");
}
if ($bCommitted) {
okNotifyActions { @aGot = $aPropget[$i]->($sPegPath, $k);
} $sTest, $aExpectedActions;
next if ! $bVerify;
is($aGot[0]->{$sPegPath}, $v
, "$sTest - verifying value (remotely)");
if ($IDX_SVN1_4 < $i) {
is($aGot[1], $iSetInRev
, "$sTest - verifying revision (remotely)");
}
}
}
}
}
#--------------------------------------------------------------------
sub okProplist {
my ($sName, $oClient, $xPaths, $aParams
, $hNodes, $aExpectedActions) = @_;
# if expected actions is not a [], then it is an error class or
# regex for matching a string exception.
$aExpectedActions=[] unless defined($aExpectedActions);
my $bVerify = ref($aExpectedActions) eq 'ARRAY' ?1:0;
my ($aPaths, $xPeg, $xRev) = ref($xPaths) ? @$xPaths : ($xPaths);
my $bCommitted= defined($xPeg) && ($xPeg ne 'WORKING');
$aParams = [] unless defined($aParams);
my ($iDepth, $aChangeLists) = @$aParams;
my $bRecurse = !defined($iDepth) ? undef : ($iDepth? 1 : 0);
my $bMinimal = _isMinimal($aParams, $xPeg, $xRev);
my @aProplist = $bMinimal
? ( sub { $oClient->proplist($_[0]) }
, sub { $oClient->proplist1_1($_[0]) }
, sub { $oClient->proplist1_4($_[0]) }
, sub { $oClient->proplist1_5($_[0], $xPeg, $xRev, $iDepth
, $aChangeLists, $_[1]) }
, sub { $oClient->proplist1_6($_[0], $xPeg, $xRev, $iDepth
, $aChangeLists, $_[1]) }
, sub { $oClient->proplist1_7($_[0], $xPeg, $xRev, $iDepth
, $aChangeLists, $_[1]) }
)
: ( sub { $oClient->proplist($_[0], $xPeg, $bRecurse) }
, sub { $oClient->proplist1_1($_[0], $xPeg, $bRecurse) }
, sub { $oClient->proplist1_4($_[0], $xPeg, $xRev, $bRecurse) }
, sub { $oClient->proplist1_5($_[0], $xPeg, $xRev, $iDepth
, $aChangeLists, $_[1]) }
, sub { $oClient->proplist1_6($_[0], $xPeg, $xRev, $iDepth
, $aChangeLists, $_[1]) }
, sub { $oClient->proplist1_7($_[0], $xPeg, $xRev, $iDepth
, $aChangeLists, $_[1]) }
);
my %hGot;
my $crVisit = sub { $hGot{$_[0]} = $_[1]; };
for my $i (0..$#$aPaths) {
my $sPath = $aPaths->[$i];
next unless defined($sPath);
# proplist requires repository URL with historical revisions
# and working copy paths with working copy revisions
# $aPaths is the working copy path, so we convert it.
$sPath = $oClient->getRepositoryURL($sPath) if $bCommitted;
my $sTest = "$sName:proplist$VERSION_SUFFIXES[$i]($sPath)";
my $aNodes;
%hGot=();
okNotifyActions { $aNodes = $aProplist[$i]->($sPath, $crVisit);
} $sTest, $aExpectedActions;
next unless $bVerify;
if (($i <= $IDX_SVN1_4) && defined($aNodes) && scalar($aNodes)) {
%hGot = map { $_->node_name() => $_->prop_hash() } @$aNodes;
}
is_deeply($hGot{$sPath}, $hNodes
, "$sTest - verifying node properties (locally)");
}
}
#--------------------------------------------------------------------
sub okPropset {
my ($sName, $oClient, $aPaths, $hProps, $aParams
, $hExpectedStatus, $aExpectedActions) = @_;
$aExpectedActions=[] unless defined($aExpectedActions);
my $bVerify = ref($aExpectedActions) eq 'ARRAY' ?1:0;
$aParams = [] unless defined($aParams);
my ($crCommit, $iDepth, $bSkipChecks, $xBaseRev, $aChangeLists
, $hRevProp) = @$aParams;
my $bRecurse = !defined($iDepth) ? undef : ($iDepth? 1 : 0);
my $bMinimal = _isMinimal($aParams);
my @aPropset = $bMinimal
? ( sub { $oClient->propset($_[2], $_[0],$_[1]) }
, sub { $oClient->propset1_1($_[0],$_[1], $_[2]) }
, sub { $oClient->propset1_4($_[0],$_[1], $_[2]) }
, sub { $oClient->propset1_5($_[0],$_[1], $_[2]) }
, sub { $oClient->propset1_6($_[0],$_[1], $_[2]) }
, sub { $oClient->propset1_7($_[0],$_[1], $_[2]) }
)
: ( sub { $oClient->propset($_[2], $_[0],$_[1], $bRecurse) }
, sub { $oClient->propset1_1($_[0],$_[1], $_[2], $bRecurse) }
, sub { $oClient->propset1_4($_[0],$_[1], $_[2], $bRecurse
, $bSkipChecks) }
, sub { $oClient->propset1_5($_[0],$_[1], $_[2], $iDepth
, $bSkipChecks, $xBaseRev, $aChangeLists, $hRevProp) }
, sub { $oClient->propset1_6($_[0],$_[1], $_[2], $iDepth
, $bSkipChecks, $xBaseRev, $aChangeLists, $hRevProp) }
, sub { $oClient->propset1_7($_[0],$_[1], $_[2], $iDepth
, $bSkipChecks, $xBaseRev, $aChangeLists, $hRevProp
, $crCommit) }
);
for my $i (0..$#$aPaths) {
my $sPath = $aPaths->[$i];
next unless defined($sPath);
my $sTest = "$sName:propset$VERSION_SUFFIXES[$i]($sPath)";
while (my ($k,$v) = each(%$hProps)) {
my $sSubtest = "$sTest, $k=$v";
okNotifyActions { $aPropset[$i]->($k, $v, $sPath);
} $sSubtest, $aExpectedActions, 1;
next unless $bVerify;
is($oClient->getPathProperty($sPath, $k), $v
, "$sSubtest - verifying value");
}
okGetStatus($sTest, $oClient, $sPath, $hExpectedStatus);
}
}
#--------------------------------------------------------------------
sub okRelocate {
my ($sName, $oClient, $aWcs, $aToRepos, $aParams
, $aExpectedActions) = @_;
$aExpectedActions=[] unless defined($aExpectedActions);
$aParams = [] unless defined($aParams);
my ($bRecurse, $bIgnoreExternals) = @$aParams;
my $bMinimal = _isMinimal($aParams);
my @aRelocate = $bMinimal
? ( sub { $oClient->relocate($_[0], $_[1], $_[2]) }
, sub { $oClient->relocate1_1($_[0], $_[1], $_[2]) }
, sub { $oClient->relocate1_4($_[0], $_[1], $_[2]) }
, sub { $oClient->relocate1_5($_[0], $_[1], $_[2]) }
, sub { $oClient->relocate1_6($_[0], $_[1], $_[2]) }
, sub { $oClient->relocate1_7($_[0], $_[1], $_[2]) }
)
: ( sub { $oClient->relocate($_[0], $_[1], $_[2], $bRecurse) }
, sub { $oClient->relocate1_1($_[0], $_[1], $_[2], $bRecurse) }
, sub { $oClient->relocate1_4($_[0], $_[1], $_[2], $bRecurse) }
, sub { $oClient->relocate1_5($_[0], $_[1], $_[2], $bRecurse) }
, sub { $oClient->relocate1_6($_[0], $_[1], $_[2], $bRecurse) }
, sub { $oClient->relocate1_7($_[0], $_[1], $_[2]
, $bIgnoreExternals) }
);
for my $i (0..$#$aWcs) {
my $sPath = $aWcs->[$i]->getRoot();
next unless defined($sPath);
my $sTest = "$sName:relocate$VERSION_SUFFIXES[$i]($sPath)";
my $sFrom = $oClient->getRepositoryURL($sPath);
my $sTo = $aToRepos->[$i];
okNotifyActions { $aRelocate[$i]->($sPath, $sFrom, $sTo);
} $sTest, $aExpectedActions, 1;
is($oClient->getRepositoryURL($sPath), $sTo
, "$sTest - verifying repository path");
is($oClient->getRepositoryRootURL($sPath), $sTo
, "$sTest - verifying repository root");
}
}
#--------------------------------------------------------------------
sub okResolved {
my ($sName, $oClient, $aPaths, $aParams, $aExpectedActions) = @_;
$aParams=[] unless defined($aParams);
my ($bRecurse) = @$aParams;
my $bMinimal = _isMinimal($aParams);
my @aResolved = $bMinimal
? ( sub { $oClient->resolved($_[0]) }
, sub { $oClient->resolved1_1($_[0]) }
, sub { $oClient->resolved1_4($_[0]) }
, sub { $oClient->resolved1_5($_[0]) }
, sub { $oClient->resolved1_6($_[0]) }
, sub { $oClient->resolved1_7($_[0]) }
)
: ( sub { $oClient->resolved($_[0], $bRecurse) }
, sub { $oClient->resolved1_1($_[0], $bRecurse) }
, sub { $oClient->resolved1_4($_[0], $bRecurse) }
, sub { $oClient->resolved1_5($_[0], $bRecurse) }
, sub { $oClient->resolved1_6($_[0], $bRecurse) }
, sub { $oClient->resolved1_7($_[0], $bRecurse) }
);
for my $i (0..$#$aPaths) {
my $sPath = $aPaths->[$i];
next unless defined($sPath);
my $sTest = "$sName:resolved$VERSION_SUFFIXES[$i]($sPath)";
okNotifyActions { $aResolved[$i]->($sPath);
} $sTest, $aExpectedActions, 1;
}
}
#--------------------------------------------------------------------
sub okRevert {
my ($sName, $oClient, $aPaths, $aParams, $hExpectedStatus
, $bExists, $aExpectedActions) = @_;
$aExpectedActions=$REVERT_ACTIONS unless defined($aExpectedActions);
$aParams=[] unless defined($aParams);
my ($iDepth, $aChangeLists) = @$aParams;
my $bRecurse = !defined($iDepth) ? undef : ($iDepth? 1 : 0);
my $bMinimal = _isMinimal($aParams);
my @aRevert = $bMinimal
? ( sub { $oClient->revert($_[0]) }
, sub { $oClient->revert1_1($_[0]) }
, sub { $oClient->revert1_4($_[0]) }
, sub { $oClient->revert1_5($_[0]) }
, sub { $oClient->revert1_6($_[0]) }
, sub { $oClient->revert1_7($_[0]) }
)
: ( sub { $oClient->revert($_[0], $bRecurse) }
, sub { $oClient->revert1_1($_[0], $bRecurse) }
, sub { $oClient->revert1_4($_[0], $bRecurse) }
, sub { $oClient->revert1_5($_[0], $iDepth, $aChangeLists) }
, sub { $oClient->revert1_6($_[0], $iDepth, $aChangeLists) }
, sub { $oClient->revert1_7($_[0], $iDepth, $aChangeLists) }
);
for my $i (0..$#$aPaths) {
my $sPath = $aPaths->[$i];
next unless defined($sPath);
my $sTest = "$sName:revert$VERSION_SUFFIXES[$i]($sPath)";
okNotifyActions { $aRevert[$i]->($sPath);
} $sTest, $aExpectedActions, 1;
okGetStatus($sTest, $oClient, $sPath, $hExpectedStatus);
is((-e $sPath)?1:0, $bExists
, "$sTest - verifying "
.($bExists?'existance':'non-existance'));
}
}
#--------------------------------------------------------------------
sub okRevprop_delete {
my ($sName, $oClient, $xPaths, $hProps, $aParams
, $iSetInRev, $hRemaining, $aExpectedActions) = @_;
# if expected actions is not a [], then it is an error class or
# regex for matching a string exception.
$aExpectedActions=[] unless defined($aExpectedActions);
my $bVerify = ref($aExpectedActions) eq 'ARRAY' ?1:0;
my ($aPaths, $xPeg, $xRev) = ref($xPaths) ? @$xPaths : ($xPaths);
$aParams = [] unless defined($aParams);
my ($bForce) = @$aParams;
my $bMinimal = _isMinimal($aParams, $xPeg);
my @aRevprop_delete = $bMinimal
? ( sub { $oClient->revprop_delete($_[0], $_[1]) }
, sub { $oClient->revprop_delete1_1($_[1], $_[0]) }
, sub { $oClient->revprop_delete1_4($_[1], $_[0]) }
, sub { $oClient->revprop_delete1_5($_[1], $_[0]) }
, sub { $oClient->revprop_delete1_6($_[1], $_[2], $_[0]) }
, sub { $oClient->revprop_delete1_7($_[1], $_[2], $_[0]) }
)
: ( sub { $oClient->revprop_delete($_[0], $_[1], $xPeg, $bForce) }
, sub { $oClient->revprop_delete1_1($_[1]
, $_[0], $xPeg, $bForce) }
, sub { $oClient->revprop_delete1_4($_[1]
, $_[0], $xPeg, $bForce) }
, sub { $oClient->revprop_delete1_5($_[1]
, $_[0], $xPeg, $bForce) }
, sub { $oClient->revprop_delete1_6($_[1], $_[2]
, $_[0], $xPeg, $bForce) }
, sub { $oClient->revprop_delete1_7($_[1], $_[2]
, $_[0], $xPeg, $bForce) }
);
for my $i (0..$#$aPaths) {
my $sPath = $aPaths->[$i];
next unless defined($sPath);
my $sTest
= "$sName:revprop_delete$VERSION_SUFFIXES[$i]($sPath)";
while (my ($k,$v) = each(%$hProps)) {
my $sSubtest = "$sTest: $k=$v";
my $vOld = $oClient->revprop_get($sPath, $k, $xPeg);
my $iGotRev;
okNotifyActions {
$iGotRev = $aRevprop_delete[$i]->($sPath, $k, $vOld);
} $sSubtest, $aExpectedActions;
if ($bVerify) {
is($iGotRev, $iSetInRev
, "$sSubtest - verifying set-in-revsion");
}
}
if ($bVerify) {
my $hGot = $oClient->getRevisionProperties($sPath, $xPeg);
okPropertyHash($hGot, $hRemaining
, "$sTest - verifying deletion of properties");
}
}
}
#--------------------------------------------------------------------
sub okRevprop_get {
my ($sName, $oClient, $xPaths, $aParams
, $iSetInRev, $hProps, $aExpectedActions) = @_;
# if expected actions is not a [], then it is an error class or
# regex for matching a string exception.
$aExpectedActions=[] unless defined($aExpectedActions);
my $bVerify = ref($aExpectedActions) eq 'ARRAY' ?1:0;
$aParams = [] unless defined($aParams);
my ($aPaths, $xPeg, $xRev) = ref($xPaths) ? @$xPaths : ($xPaths);
$aParams = [] unless defined($aParams);
my $bMinimal = _isMinimal($aParams, $xPeg);
my @aRevprop_get = $bMinimal
?( sub { $oClient->revprop_get($_[0], $_[1]) }
, sub { $oClient->revprop_get1_1($_[1], $_[0]) }
, sub { $oClient->revprop_get1_4($_[1], $_[0]) }
, sub { $oClient->revprop_get1_5($_[1], $_[0]) }
, sub { $oClient->revprop_get1_6($_[1], $_[0]) }
, sub { $oClient->revprop_get1_7($_[1], $_[0]) }
)
: ( sub { $oClient->revprop_get($_[0], $_[1], $xPeg) }
, sub { $oClient->revprop_get1_1($_[1], $_[0], $xPeg) }
, sub { $oClient->revprop_get1_4($_[1], $_[0], $xPeg) }
, sub { $oClient->revprop_get1_5($_[1], $_[0], $xPeg) }
, sub { $oClient->revprop_get1_6($_[1], $_[0], $xPeg) }
, sub { $oClient->revprop_get1_7($_[1], $_[0], $xPeg) }
);
for my $i (0..$#$aPaths) {
my $sPath = $aPaths->[$i];
next unless defined($sPath);
while (my ($k,$v) = each(%$hProps)) {
my $sTest
= "$sName:revprop_get$VERSION_SUFFIXES[$i]($sPath: $k=$v)";
my @aGot;
okNotifyActions { @aGot = $aRevprop_get[$i]->($sPath, $k);
} $sTest, $aExpectedActions;
next unless $bVerify;
is($aGot[1], $iSetInRev, "$sTest - verifying revision");
is($aGot[0], $v, "$sTest - verifying value");
}
}
}
#--------------------------------------------------------------------
sub okRevprop_list {
my ($sName, $oClient, $xPaths, $aParams
, $iSetInRev, $hProps, $aExpectedActions) = @_;
# if expected actions is not a [], then it is an error class or
# regex for matching a string exception.
$aExpectedActions=[] unless defined($aExpectedActions);
my $bVerify = ref($aExpectedActions) eq 'ARRAY' ?1:0;
my ($aPaths, $xPeg, $xRev) = ref($xPaths) ? @$xPaths : ($xPaths);
$aParams = [] unless defined($aParams);
my $bMinimal = _isMinimal($aParams, $xPeg);
my @aRevprop_list = $bMinimal
? ( sub { $oClient->revprop_list($_[0]) }
, sub { $oClient->revprop_list1_1($_[0]) }
, sub { $oClient->revprop_list1_4($_[0]) }
, sub { $oClient->revprop_list1_5($_[0]) }
, sub { $oClient->revprop_list1_6($_[0]) }
, sub { $oClient->revprop_list1_7($_[0]) }
)
: ( sub { $oClient->revprop_list($_[0], $xPeg) }
, sub { $oClient->revprop_list1_1($_[0], $xPeg) }
, sub { $oClient->revprop_list1_4($_[0], $xPeg) }
, sub { $oClient->revprop_list1_5($_[0], $xPeg) }
, sub { $oClient->revprop_list1_6($_[0], $xPeg) }
, sub { $oClient->revprop_list1_7($_[0], $xPeg) }
);
for my $i (0..$#$aPaths) {
my $sPath = $aPaths->[$i];
next unless defined($sPath);
my $sTest = "$sName:revprop_list$VERSION_SUFFIXES[$i]($sPath)";
my @aGot;
okNotifyActions { @aGot = $aRevprop_list[$i]->($sPath);
} $sTest, $aExpectedActions;
next unless $bVerify;
okPropertyHash($aGot[0], $hProps
, "$sTest - verifying property-value list");
is($aGot[1], $iSetInRev, "$sTest - verifying set-in-revision");
}
}
#--------------------------------------------------------------------
sub okRevprop_set {
my ($sName, $oClient, $xPaths, $hProps, $aParams
, $iSetInRev, $hAllProps, $aExpectedActions) = @_;
# if expected actions is not a [], then it is an error class or
# regex for matching a string exception.
$aExpectedActions=[] unless defined($aExpectedActions);
my $bVerify = ref($aExpectedActions) eq 'ARRAY' ?1:0;
my ($aPaths, $xPeg, $xRev) = ref($xPaths) ? @$xPaths : ($xPaths);
$aParams = [] unless defined($aParams);
my ($bForce) = @$aParams;
my $bMinimal = _isMinimal($aParams, $xPeg, $xRev);
my @aRevprop_set = $bMinimal
? ( sub { $oClient->revprop_set($_[0], $_[1], $xPeg, $_[2]) }
, sub { $oClient->revprop_set1_1($_[1],$_[2], $_[0]) }
, sub { $oClient->revprop_set1_4($_[1],$_[2], $_[0]) }
, sub { $oClient->revprop_set1_5($_[1],$_[2], $_[0]) }
, sub { $oClient->revprop_set1_6($_[1],$_[2], $_[3], $_[0]) }
, sub { $oClient->revprop_set1_7($_[1],$_[2], $_[3], $_[0]) }
)
: ( sub { $oClient->revprop_set($_[0], $_[1], $xPeg, $_[2]
, $bForce) }
, sub { $oClient->revprop_set1_1($_[1],$_[2]
, $_[0], $xPeg, $bForce) }
, sub { $oClient->revprop_set1_4($_[1],$_[2]
, $_[0], $xPeg, $bForce) }
, sub { $oClient->revprop_set1_5($_[1],$_[2]
, $_[0], $xPeg, $bForce) }
, sub { $oClient->revprop_set1_6($_[1],$_[2], $_[3]
, $_[0], $xPeg, $bForce) }
, sub { $oClient->revprop_set1_7($_[1],$_[2], $_[3]
, $_[0], $xPeg, $bForce) }
);
for my $i (0..$#$aPaths) {
my $sPath = $aPaths->[$i];
next unless defined($sPath);
my $sTest = "$sName:revprop_set$VERSION_SUFFIXES[$i]($sPath)";
while (my ($k,$v) = each(%$hProps)) {
my $vOld = $oClient->revprop_get($sPath, $k, $xPeg);
my $sSubtest = "$sTest: $k=$v";
my $iGotRev;
okNotifyActions {
$iGotRev = $aRevprop_set[$i]->($sPath, $k, $v, $vOld);
} $sSubtest, $aExpectedActions;
next unless $bVerify;
is($iGotRev, $iSetInRev, "$sSubtest: verifying set revision");
}
next unless $bVerify;
my $hGot = $oClient->getRevisionProperties($sPath, $xPeg);
okPropertyHash($hGot, $hAllProps
, "$sTest - verifying property-value list");
}
}
#--------------------------------------------------------------------
sub okShift1($$$$) {
my ($sName, $crShift, $xArg1, $xExpected) = @_;
local $Test::Builder::Level = $Test::Builder::Level + 1;
return okShiftMany($sName, $crShift, [$xArg1], [$xExpected]);
}
#--------------------------------------------------------------------
sub okShiftMany($$$$;$) {
my ($sName, $crShift, $aArgs, $aExpected, $bOptional) = @_;
local $Test::Builder::Level = $Test::Builder::Level + 1;
my $aInput = [ $aArgs && scalar(@$aArgs) ? @$aArgs : undef
, 'STOP'
];
my $sCall = _makeCall($sName, $aInput);
is_deeply([ &$crShift($aInput) ], $aExpected, "$sCall - retval");
is_deeply($aInput, ['STOP'], "$sCall - remainder");
if ($bOptional) {
my $rEnd = \'STOP';
for (my $i=0; $i <= $#$aArgs; $i++) {
last if defined($aArgs->[$#$aArgs-$i]);
$aInput = $i > $#$aArgs
? [ $rEnd ] : [ @{$aArgs}[0..($#$aArgs-$i-1)], $rEnd ];
$sCall = _makeCall($sName, $aInput);
is_deeply([ &$crShift($aInput) ], $aExpected
, "$sCall - retval");
is_deeply($aInput, [$rEnd], "$sCall - remainder");
}
}
}
#--------------------------------------------------------------------
sub okStatus {
my ($sName, $oClient, $xPath, $aParams, $hStatus
, $aExpectedActions, $aOut) = @_;
$aExpectedActions = [] unless defined($aExpectedActions);
my $iVisitCount = defined($aOut) ? scalar(@$aOut) : 0;
my $sOut='';
if (defined($aOut)) {
foreach my $aLine (@$aOut) {
$sOut .= sprintf("%-11s %-11s %s\n", @$aLine);
}
}
# $xPath may be: $sPath
# [ $sPath, $xPeg, $xRev]
# [ $aPaths, $xPeg, $xRev]
my ($aPaths, $xPeg, $xRev) = ref($xPath) ? @$xPath : ($xPath);
$aPaths = [ $aPaths ] if ! ref($aPaths);
$aParams=[] unless defined($aParams);
my ($bRecurse, $bAll, $bUpdate, $bNoIgnore, $bSkipExternals
, $aChangeLists) = @$aParams;
my $bMinimal = _isMinimal($aParams, $xPeg, $xRev);
my $bOk=1;
my $sMsg='';
my @aVisits;
my $crVisit = sub {
my ($sWc, $oStatus, $oPool) = @_;
#Note: only 1.2+ API (status2) supports flag to indicate whether
#file is locked in the repository. The locked flag returned by
#locked() really should be frozen or interrupted. It refers to
#file that are "locked" because their modifications have only
#been partially stored in the repository.
my $iTextStatus = $oStatus->text_status();
my $iPropStatus = $oStatus->prop_status();
my $bInterrupted = $oStatus->locked();
push @aVisits, [$sWc, $iTextStatus, $iPropStatus, $bInterrupted];
if ($NOISY) {
my $oEntry = $oStatus->entry();
my $sEntry = '';
if ($oEntry) {
my $sName = $oEntry->name();
$sName = 'undef' unless defined($sName);
my $sUuid = $oEntry->uuid();
$sUuid = 'undef' unless defined($sUuid);
$sEntry = "name=" . $sName
. " rev=" . $oEntry->revision()
. " url=" . $oEntry->url()
. " repos=" . $oEntry->repos()
. " uuid=" . $sUuid
. " kind=" . $oEntry->kind()
. " schedule="
. $CLIENT_CLASS->getScheduledOpAsString($oEntry->schedule())
. " etc, etc, etc...";
};
print STDERR "status: <$sWc> entry=<$sEntry"
. "> text=<" . $CLIENT_CLASS->getStatusAsString($iTextStatus)
. "> props=<" . $CLIENT_CLASS->getStatusAsString($iPropStatus)
. "> interupted=<" . $bInterrupted
. "> copied=<" . $oStatus->copied()
. "> switched=<" . $oStatus->switched()
. "> repos text=<". $CLIENT_CLASS
->getStatusAsString($oStatus->repos_text_status())
. "> repo props=<" . $CLIENT_CLASS
->getStatusAsString($oStatus->repos_prop_status())
. ">\n";
}
return unless $bOk; # only capture errors once
if (!defined($sWc) || ref($sWc) || !length($sWc)) {
$bOk=0;
$sWc=defined($sWc) ? "'$sWc'" : 'undef';
$sMsg .= "path: expected non-empty string, got <$sWc>\n";
}
if (!defined($oStatus)
|| ref($oStatus) ne '_p_svn_client_status_t') {
$oStatus=defined($oStatus) ? "'$oStatus'" : 'undef';
$sMsg .= 'status object: expected reference to svn_status_t'
. ", got <$oStatus>\n";
}
if (!defined($oPool) || ref($oPool) ne '_p_apr_pool_t') {
$oPool=defined($oPool) ? "'$oPool'" : 'undef';
$sMsg .= 'pool object: expected reference to svn_pool_t'
. ", got <$oPool>\n";
}
};
my @aStatus = $bMinimal
? ( sub { $oClient->status($_[0], $crVisit); }
, sub { $oClient->status1_1($_[0], $crVisit); }
, sub { $oClient->status1_4($_[0], $crVisit); }
, sub { $oClient->status1_5($_[0], $crVisit); }
, sub { $oClient->status1_6($_[0], $crVisit); }
, sub { $oClient->status1_7($_[0], $xPeg, $bRecurse
, $bAll, $bUpdate, $bNoIgnore, $bSkipExternals
, $aChangeLists, $crVisit); }
)
: ( sub { $oClient->status($_[0], $crVisit, $bRecurse
, $bUpdate, $xPeg, $bAll, $bNoIgnore); }
, sub { $oClient->status1_1($_[0], $xPeg, $crVisit, $bRecurse
, $bAll, $bUpdate, $bNoIgnore); }
, sub { $oClient->status1_4($_[0], $xPeg, $crVisit, $bRecurse
, $bAll, $bUpdate, $bNoIgnore, $bSkipExternals); }
, sub { $oClient->status1_5($_[0], $xPeg, $crVisit, $bRecurse
, $bAll, $bUpdate, $bNoIgnore, $bSkipExternals
, $aChangeLists); }
, sub { $oClient->status1_6($_[0], $xPeg, $crVisit, $bRecurse
, $bAll, $bUpdate, $bNoIgnore, $bSkipExternals
, $aChangeLists); }
, sub { $oClient->status1_7($_[0], $xPeg, $bRecurse
, $bAll, $bUpdate, $bNoIgnore, $bSkipExternals
, $aChangeLists, $crVisit); }
);
for my $i (0..$#$aPaths) {
my $sPath = $aPaths->[$i];
next unless defined($sPath);
my $sTest = "$sName:status$VERSION_SUFFIXES[$i]($sPath)";
SKIP:
{
if ($SKIP_SWIG_BUGS && ($i == 2)) {
my $sBug ="status: svn_client_status2: visitor "
."thunk undefined in SWIG-Perl";
$SWIG_BINDING_BUGS{$sBug}++;
local $TODO = "SWIG binding bug: need to report\n\t$sBug";
skip $sTest, 3;
}
$bOk = 1;
$sMsg ='';
@aVisits=();
okNotifyActions { $aStatus[$i]->($sPath);
} $sTest, $aExpectedActions;
is(scalar(@aVisits), $iVisitCount
, "$sTest - verifying visit count");
ok($bOk, "$sTest - verifying callback parameters")
or diag($sMsg);
}
if (!defined($xPeg) || ($xPeg eq 'WORKING')) {
# getStatus()
okGetStatus($sTest, $oClient, $sPath, $hStatus);
# printStatus()
my $sBufOut='';
open(my $fhOut, '>', \$sBufOut);
$oClient->printStatus($sPath, $fhOut);
is($sBufOut, $sOut, "$sTest - verifying printStatus");
}
}
}
#--------------------------------------------------------------------
sub okSwitch {
my ($sName, $oClient, $aFrom, $xToRepos, $sBranch, $aParams
, $aExpectedActions) = @_;
$aExpectedActions=$UPDATE_ACTIONS unless defined($aExpectedActions);
my ($aToRepos, $xPeg, $xRev) = ref($xToRepos) eq 'ARRAY'
? @$xToRepos : ($xToRepos);
$aParams = [] unless defined($aParams);
my ($iDepth, $bDepthIsSticky, $bIgnoreExternals
, $bAllowUnversionedObstructions) = @$aParams;
my $bRecurse = !defined($iDepth) ? undef : ($iDepth? 1 : 0);
my $bMinimal = _isMinimal($aParams, $xPeg, $xRev);
my @aSwitch = $bMinimal
? ( sub { $oClient->switch($_[0], $_[1]) }
, sub { $oClient->switch1_1($_[0], $_[1]) }
, sub { $oClient->switch1_4($_[0], $_[1]) }
, sub { $oClient->switch1_5($_[0], $_[1]) }
, sub { $oClient->switch1_6($_[0], $_[1]) }
, sub { $oClient->switch1_7($_[0], $_[1]) }
)
: ( sub { $oClient->switch($_[0], $_[1], $xPeg, $bRecurse) }
, sub { $oClient->switch1_1($_[0], $_[1], $xPeg, $bRecurse) }
, sub { $oClient->switch1_4($_[0], $_[1], $xPeg, $bRecurse) }
, sub { $oClient->switch1_5($_[0], $_[1], $xPeg, $xRev
, $iDepth, $bDepthIsSticky, $bIgnoreExternals
, $bAllowUnversionedObstructions) }
, sub { $oClient->switch1_6($_[0], $_[1], $xPeg, $xRev
, $iDepth, $bDepthIsSticky, $bIgnoreExternals
, $bAllowUnversionedObstructions) }
, sub { $oClient->switch1_7($_[0], $_[1], $xPeg, $xRev
, $iDepth, $bDepthIsSticky, $bIgnoreExternals
, $bAllowUnversionedObstructions) }
);
for my $i (0..$#$aFrom) {
my $sFrom = $aFrom->[$i];
next unless defined($sFrom);
my $oTo = $aToRepos->[$i];
my $sTo = File::Spec->rel2abs($sBranch, $oTo->getRoot());
$sTo= URI::file->new($sTo)->canonical()->as_string();
my $sTest = "$sName:switch$VERSION_SUFFIXES[$i]($sFrom->$sTo)";
okNotifyActions { $aSwitch[$i]->($sFrom, $sTo);
} $sTest, $aExpectedActions, 1;
is($oClient->getRepositoryURL($sFrom), $sTo
, "$sTest - verifying repository path");
}
}
#--------------------------------------------------------------------
sub okUnlock {
my ($sName, $oClient, $aPaths, $aParams, $aExpectedActions) = @_;
$aExpectedActions = [] unless defined($aExpectedActions);
$aParams = [] unless defined($aParams);
my ($bBreakLock) = @$aParams;
my $bMinimal = _isMinimal($aParams);
my @aUnlock = $bMinimal
? ( sub { $oClient->unlock($_[0]) }
, sub { $oClient->unlock1_1($_[0]) }
, sub { $oClient->unlock1_4($_[0]) }
, sub { $oClient->unlock1_5($_[0]) }
, sub { $oClient->unlock1_6($_[0]) }
, sub { $oClient->unlock1_7($_[0]) }
)
: ( sub { $oClient->unlock($_[0], $bBreakLock) }
, sub { $oClient->unlock1_1($_[0], $bBreakLock) }
, sub { $oClient->unlock1_4($_[0], $bBreakLock) }
, sub { $oClient->unlock1_5($_[0], $bBreakLock) }
, sub { $oClient->unlock1_6($_[0], $bBreakLock) }
, sub { $oClient->unlock1_7($_[0], $bBreakLock) }
);
for my $i (0..$#$aPaths) {
my $sPath = $aPaths->[$i];
next unless defined($sPath);
my $sTest = "$sName:unlock$VERSION_SUFFIXES[$i]($sPath)";
okNotifyActions { $aUnlock[$i]->($sPath);
} $sTest, $aExpectedActions, 1;
is($oClient->isLocked($sPath), 0
, "$sName - verifying lock status");
}
}
#--------------------------------------------------------------------
sub okUpdate {
my ($sName, $oClient, $xPath, $aParams, $iExpectedRev
, $aExpectedActions) = @_;
$aExpectedActions = $UPDATE_ACTIONS
unless defined($aExpectedActions);
my $bVerify = ref($aExpectedActions) eq 'ARRAY' ?1:0;
# $xPath may be: $sPath
# [ $sPath, $xPeg, $xRev]
# [ $aPaths, $xPeg, $xRev]
my ($aPaths, $xPeg, $xRev) = ref($xPath) ? @$xPath : ($xPath);
$aPaths = [ $aPaths ] if ! ref($aPaths);
$aParams = [] unless defined($aParams);
my ($iDepth, $bDepthIsSticky, $bSkipExternals
, $bAllowUnversionedObstructions, $bMakeParents) = @$aParams;
my $bRecurse = !defined($iDepth) ? undef : ($iDepth? 1 : 0);
my $bMinimal = _isMinimal($aParams, $xPeg, $xRev);
my @aUpdate = $bMinimal
? ( sub { $oClient->update($_[0]) }
, sub { $oClient->update1_1($_[0]) }
, sub { $oClient->update1_4($_[0]); }
, sub { $oClient->update1_5($_[0]); }
, sub { $oClient->update1_6($_[0]); }
, sub { $oClient->update1_7($_[0]);}
)
: ( sub { $oClient->update($_[0], $xPeg, $bRecurse) }
, sub { $oClient->update1_1($_[0], $xPeg, $bRecurse
, $bSkipExternals) }
, sub { $oClient->update1_4($_[0], $xPeg, $iDepth
, $bDepthIsSticky, $bSkipExternals
, $bAllowUnversionedObstructions); }
, sub { $oClient->update1_5($_[0], $xPeg, $iDepth
, $bDepthIsSticky, $bSkipExternals
, $bAllowUnversionedObstructions); }
, sub { $oClient->update1_6($_[0], $xPeg, $iDepth
, $bDepthIsSticky, $bSkipExternals
, $bAllowUnversionedObstructions); }
, sub { $oClient->update1_7($_[0], $xPeg, $iDepth
, $bDepthIsSticky, $bSkipExternals
, $bAllowUnversionedObstructions, $bMakeParents);}
);
for my $i (0..$IDX_SVN1_4) {
my $sPath = $aPaths->[$i];
next unless defined($sPath);
my $sTest = "$sName:update$VERSION_SUFFIXES[$i]($sPath)";
my $iGotRev;
if ($SKIP_SWIG_BUGS && ($i == $IDX_SVN1_4)) {
my $sBug="update: svn_client_update2: parameter1 not "
."converted to return value by SWIG";
$SWIG_BINDING_BUGS{$sBug}++;
#local $TODO = "SWIG binding bug: need to report\n\t$sBug";
# use older update method, so that at least the update
# happens
okNotifyActions { $iGotRev = $aUpdate[$i-1]->($sPath);
} $sTest, $aExpectedActions;
} else {
okNotifyActions { $iGotRev = $aUpdate[$i]->($sPath);
} $sTest, $aExpectedActions;
}
next unless $bVerify;
is($iGotRev, $iExpectedRev, "$sTest - verifying revision");
}
my $aExpectedRevs = [ ($iExpectedRev) x scalar(@$aPaths) ];
for my $i (3..$#$aPaths) {
my $sPath = $aPaths->[$i];
next unless defined($sPath);
my $sTest = "$sName:update$VERSION_SUFFIXES[$i]($sPath)";
my $aRevs;
okNotifyActions { $aRevs = $aUpdate[$i]->($sPath);
} $sTest, $aExpectedActions;
next unless $bVerify;
is_deeply($aRevs, $aExpectedRevs, "$sTest - verifying revisions");
}
}
#--------------------------------------------------------------------
sub testAuthentication {
my ($sName, $oClient) = @_;
my $sTest="$sName: testAuthentication";
my $sSubtest;
my @aGot;
#--------------------------------------
# with undef
#--------------------------------------
@aGot=$oClient->configureAuthentication();
is_deeply(\@aGot, [$SVN::Friendly::Client::SILENT_AUTH_BATON,[]]
, "$sTest - setAuthentication(undef)")
or diag("got=(@aGot)\n");
#--------------------------------------
# with an authentication baton
#--------------------------------------
my $aProviders = [ SVN::Client::get_username_provider()
, SVN::Client::get_simple_provider() ];
my $oBaton = SVN::Core::auth_open($aProviders);
@aGot = $oClient->configureAuthentication($oBaton);
is_deeply( \@aGot, [ $oBaton, []], "$sTest: baton");
#--------------------------------------
# with a hash
#--------------------------------------
okAuthentication($sTest.': emptyHash'
, [$oClient->configureAuthentication({})],[]);
okAuthentication($sTest.': retries'
, [$oClient->configureAuthentication({retries=>10})],[]);
my $hAuth = {};
my $crUserName = sub { print "username"; };
my $crUserNamePw = sub { print "username_pw" };
my $crServer = sub { print "ssl_sever" };
my $crClient = sub { print "ssl_client"; };
my $crClientPw = sub { print "ssl_client_pw" };
$hAuth->{providers}
= [ $oClient->SSL_SERVER
, $oClient->SSL_CLIENT
, $oClient->SSL_CLIENT_PW
, $oClient->USERNAME
, $oClient->USERNAME_PW
];
$hAuth->{username} = [ $crUserName, undef];
$hAuth->{username_pw} = [ $crUserNamePw, 0];
$hAuth->{ssl_server} = [ $crServer, 1];
$hAuth->{ssl_client} = [ $crClient ];
$hAuth->{ssl_client_pw} = $crClientPw;
okAuthentication($sTest.': hash=prompted w/ custom order'
, [$oClient->configureAuthentication($hAuth)]
, [ $crServer, $crClient, $crClientPw
, $crUserName, $crUserNamePw]);
$hAuth->{simple} = $hAuth->{username_pw};
delete $hAuth->{username_pw};
okAuthentication($sTest.': hash=simple instead of username_pw'
, [$oClient->configureAuthentication($hAuth)]
, [ $crServer, $crClient, $crClientPw
, $crUserName, $crUserNamePw]);
#--------------------------------------
# with a provider array
#--------------------------------------
$aProviders
= [ SVN::Client::get_username_provider()
, SVN::Client::get_username_prompt_provider($crUserName,3) ];
okAuthentication("$sTest: array"
, [ $oClient->configureAuthentication($aProviders) ]
, [ $crUserName ]);
}
#--------------------------------------------------------------------
sub okAuthentication {
my ($sTest, $aGot, $aCallbacks) = @_;
is(ref($aGot->[0]), '_p_svn_auth_baton_t'
, "$sTest - verifying baton");
my @aGotCallbacks=map { $$_ } @{$aGot->[1]};
is_deeply(\@aGotCallbacks, $aCallbacks
, "$sTest - verifying callbacks");
}
#--------------------------------------------------------------------
sub testNewClient {
my ($sName, $aaParams, $hProperties) = @_;
my $sContext = 'testNewClient';
my $sClass = $TEST_CLASS;
my $oClient = testNew($sContext, $sName, $sClass
, $aaParams, $hProperties);
return $oClient;
}
#--------------------------------------------------------------------
sub testNotification {
my ($sName, $oClient) = @_;
my $sTest="$sName: testNotification";
my $sSubtest;
my $sPath = "a/b/c/foo.txt";
my @aActionParams= map { "arg$_" } (0..3);
my @aDefault;
my @aGroup;
my $iAdd;
my $crAdd = sub {
$iAdd++;
is_deeply(\@_
, [ $sPath, $SVN::Wc::Notify::Action::add, @aActionParams ]
,"$sSubtest: schedule add - verifying parameters" );
};
my $crDelete = sub {
is_deeply(\@_
, [ $sPath, $SVN::Wc::Notify::Action::delete, @aActionParams ]
,"$sSubtest: schedule delete - verifying parameters" );
};
my $crGroup = sub {
# omit action from test since it could be anything
# instead test after by caller who knows what was passed
push @aGroup, $_[1];
is_deeply([@_[0,2..$#_]], [ $sPath, @aActionParams ]
,"$sSubtest: group - verifying parameters" );
};
my $crDefault = sub {
# omit key, action from test since it could be anything
# instead test after by caller who knows what was passed
push @aDefault, [@_[0,2]];
is_deeply([@_[1,3..$#_]], [ $sPath, @aActionParams ]
, "$sSubtest: default: verifying parameters");
};
#---------------------------------------
# check defaulting mechanism
#---------------------------------------
my ($hNotify, $crNotify) = @_;
my @aForGroup
=($SVN::Wc::Notify::Action::commit_added
, $SVN::Wc::Notify::Action::commit_modified
, $SVN::Wc::Notify::Action::commit_deleted
, $SVN::Wc::Notify::Action::commit_replaced
, $SVN::Wc::Notify::Action::commit_postfix_txdelta
);
my @aTestActions
= ($SVN::Wc::Notify::Action::add
, $SVN::Wc::Notify::Action::copy
, $SVN::Wc::Notify::Action::delete
, @aForGroup
, $SVN::Wc::Notify::Action::resolved
);
$sSubtest="$sTest:handlingOfUndefAndHash";
@aDefault=();
@aGroup=();
$iAdd=0;
$hNotify = { default => $crDefault
, commit => $crGroup
, schedule =>
{$SVN::Wc::Notify::Action::add => $crAdd
, $SVN::Wc::Notify::Action::delete => undef
}
, resolved => undef
};
$crNotify = $oClient->configureNotification($hNotify);
$crNotify->($sPath, $_, @aActionParams) for (@aTestActions);
is($iAdd, 1, "$sSubtest - verifying per action call");
is_deeply(\@aGroup, \@aForGroup
, "$sSubtest - verifying group calls");
is_deeply(\@aDefault
, [['schedule', $SVN::Wc::Notify::Action::copy]
, ['schedule', $SVN::Wc::Notify::Action::delete]
, ['resolved',$SVN::Wc::Notify::Action::resolved]]
, "$sSubtest - verifying default calls");
#---------------------------------------
# check keys
#---------------------------------------
my @aScheduleTests
= ( $SVN::Wc::Notify::Action::add
, $SVN::Wc::Notify::Action::delete
, $SVN::Wc::Notify::Action::copy );
my @aRevertTests
= ( $SVN::Wc::Notify::Action::restore
, $SVN::Wc::Notify::Action::revert
, $SVN::Wc::Notify::Action::failed_revert);
my @aResolvedTests
= ( $SVN::Wc::Notify::Action::resolved );
my @aUpdateTests
= ( $SVN::Wc::Notify::Action::skip
, $SVN::Wc::Notify::Action::update_add
, $SVN::Wc::Notify::Action::update_delete
, $SVN::Wc::Notify::Action::update_update
, $SVN::Wc::Notify::Action::update_external
, $SVN::Wc::Notify::Action::update_completed );
my @aFollowTests
= ( $SVN::Wc::Notify::Action::status_external
, $SVN::Wc::Notify::Action::status_completed );
my @aCommitTests
= ( $SVN::Wc::Notify::Action::commit_added
, $SVN::Wc::Notify::Action::commit_deleted
, $SVN::Wc::Notify::Action::commit_modified
, $SVN::Wc::Notify::Action::commit_replaced
, $SVN::Wc::Notify::Action::commit_postfix_txdelta);
my @aRevpropTests;
my @aLockTests
= ( $SVN::Wc::Notify::Action::locked
, $SVN::Wc::Notify::Action::unlocked
, $SVN::Wc::Notify::Action::failed_lock
, $SVN::Wc::Notify::Action::failed_unlock );
my @aMergeTests;
my @aPatchTests;
my @aBlameTests
= ( $SVN::Wc::Notify::Action::blame_revision );
if (1 <= $SVN::Core::VER_MAJOR) {
if (5 <= $SVN::Core::VER_MINOR) {
push @aScheduleTests
, $SVN::Wc::Notify::Action::exists
, $SVN::Wc::Notify::Action::changelist_set
, $SVN::Wc::Notify::Action::changelist_clear
, $SVN::Wc::Notify::Action::changelist_moved;
push @aMergeTests
, $SVN::Wc::Notify::Action::merge_begin
, $SVN::Wc::Notify::Action::foreign_merge_begin;
push @aUpdateTests
, $SVN::Wc::Notify::Action::update_replace;
}
if (6 <= $SVN::Core::VER_MINOR) {
push @aScheduleTests
, $SVN::Wc::Notify::Action::property_added
, $SVN::Wc::Notify::Action::property_modified
, $SVN::Wc::Notify::Action::property_deleted
, $SVN::Wc::Notify::Action::property_deleted_nonexistant;
push @aRevpropTests
, $SVN::Wc::Notify::Action::revprop_set
, $SVN::Wc::Notify::Action::revprop_deleted;
push @aUpdateTests
, $SVN::Wc::Notify::Action::tree_conflict;
push @aMergeTests
, $SVN::Wc::Notify::Action::merge_completed;
push @aFollowTests
, $SVN::Wc::Notify::Action::failed_external;
}
if (7 <= $SVN::Core::VER_MINOR) {
push @aUpdateTests
, $SVN::Wc::Notify::Action::update_started
, $SVN::Wc::Notify::Action::update_obstruction
, $SVN::Wc::Notify::Action::update_external_removed
, $SVN::Wc::Notify::Action::update_add_deleted
, $SVN::Wc::Notify::Action::update_update_deleted
, $SVN::Wc::Notify::Action::upgraded_path;
push @aMergeTests
, $SVN::Wc::Notify::Action::merge_record_info
, $SVN::Wc::Notify::Action::merge_record_info_begin
, $SVN::Wc::Notify::Action::merge_elide_info;
push @aPatchTests
, $SVN::Wc::Notify::Action::patch
, $SVN::Wc::Notify::Action::patch_applied_hunk
, $SVN::Wc::Notify::Action::patch_rejected_hunk
, $SVN::Wc::Notify::Action::patch_hunk_already_applied;
push @aFollowTests
, $SVN::Wc::Notify::Action::url_redirect;
}
}
@aTestActions=(@aScheduleTests, @aRevertTests, @aResolvedTests
, @aUpdateTests, @aFollowTests, @aCommitTests
, @aRevpropTests, @aLockTests, @aMergeTests
, @aPatchTests, @aBlameTests);
$sSubtest = "$sTest: routing";
$hNotify = { default => $crDefault };
@aDefault=();
my @aSchedule;
$hNotify->{schedule} = sub { push @aSchedule, $_[1] };
my @aRevert;
$hNotify->{revert} = sub { push @aRevert, $_[1] };
my @aResolved;
$hNotify->{resolved} = sub { push @aResolved, $_[1] };
my @aLog;
$hNotify->{log} = sub { push @aLog, $_[1] };
my @aUpdate;
$hNotify->{update} = sub { push @aUpdate, $_[1] };
my @aFollow;
$hNotify->{follow} = sub { push @aFollow, $_[1] };
my @aCommit;
$hNotify->{commit} = sub { push @aCommit, $_[1] };
my @aBlame;
$hNotify->{blame} = sub { push @aBlame, $_[1] };
my @aLock;
$hNotify->{lock} = sub { push @aLock, $_[1] };
my @aMerge;
$hNotify->{merge} = sub { push @aMerge, $_[1] };
my @aRevprop;
$hNotify->{revprop} = sub { push @aRevprop, $_[1] };
my @aPatch;
$hNotify->{patch} = sub { push @aPatch, $_[1] };
$crNotify = $oClient->configureNotification($hNotify);
$crNotify->($sPath, $_, @aActionParams) for (@aTestActions);
is_deeply(\@aSchedule, \@aScheduleTests, "$sSubtest: schedule");
is_deeply(\@aRevert, \@aRevertTests, "$sSubtest: revert");
is_deeply(\@aResolved, \@aResolvedTests, "$sSubtest: resolved");
is_deeply(\@aUpdate, \@aUpdateTests, "$sSubtest: update");
is_deeply(\@aFollow, \@aFollowTests, "$sSubtest: follow");
is_deeply(\@aCommit, \@aCommitTests, "$sSubtest: commit");
is_deeply(\@aRevprop, \@aRevpropTests, "$sSubtest: revprop");
is_deeply(\@aLock, \@aLockTests, "$sSubtest: lock");
is_deeply(\@aMerge, \@aMergeTests, "$sSubtest: merge");
is_deeply(\@aPatch, \@aPatchTests, "$sSubtest: patch");
is_deeply(\@aBlame, \@aBlameTests, "$sSubtest: blame");
is_deeply(\@aDefault, [], "$sSubtest - verifying default calls")
or diag("got=(@{[map { qq{(@$_)} } @aDefault]})");
}
#--------------------------------------------------------------------
sub testWc {
my ($sName, $oClient, $bNotify) = @_;
my $oSandbox = $SANDBOX->makeChild();
my @aRepos = map {
my $sRepo = $oSandbox->getFullPathName("repo$_");
$REPO_CLASS->create($sRepo);
} @VERSION_SUFFIXES[0..$WC_LAST_IDX];
my @aRepoURLs = map {
URI::file->new($_->getRoot())->canonical()->as_string();
} @aRepos;
my @aMirrors = map {
my $sSuffix = $VERSION_SUFFIXES[$_];
my $sRepo = $oSandbox->getFullPathName("mirror$sSuffix");
$REPO_CLASS->create($sRepo, undef, undef, $aRepos[$_]->getUUID());
} (0..$WC_LAST_IDX);
my @aMirrorURLs = map {
URI::file->new($_->getRoot())->canonical()->as_string();
} @aMirrors;
my @aWc = map { $oSandbox->makeChild("wc$_")
} @VERSION_SUFFIXES[0..$WC_LAST_IDX];
my @aWcRoots = map { $_->getRoot() } @aWc;
my $iRev=0;
# -----------
# operate on working copy root
# ------------
$iRev = testWc_EmptyRoots($sName, $oClient, \@aWc, \@aWcRoots
, \@aRepos, \@aRepoURLs, \@aMirrorURLs);
# DEBUG - BEGIN
#$iRev = testWc_Branching($sName, $oClient, \@aRepos, $iRev
# , \@aWc, 'trunk', 'branch1');
#exit(1); #STOP_TESTING
# DEBUG - END
# ---------------------------------
# remote repository operations
# ---------------------------------
$iRev = testWc_RepoPathOps($sName, $oClient, \@aRepoURLs, $iRev
, 'testRemoteOps');
# ---------------------------------
# operate on a file inside the working copy
# ---------------------------------
$iRev = testWc_PathOps($sName, $oClient, \@aWc, $iRev, 1
, [ 'A.txt', 'Hello,World!' ], 'B_txt', \@aRepoURLs);
# ---------------------------------
# operate on a directory inside the working copy
# ---------------------------------
$iRev = testWc_PathOps($sName, $oClient, \@aWc, $iRev, 0
, 'A', 'B', \@aRepoURLs);
# ---------------------------------
# branch and merge
# ---------------------------------
$iRev = testWc_Branching($sName, $oClient, \@aRepos, $iRev
, \@aWc, 'trunk', 'branch1');
# ---------------------------------
# set and clear revision properties
# ---------------------------------
$iRev = testWc_Revprops($sName, $oClient, \@aRepoURLs, $iRev, 0);
$_->enableRevProps() for @aRepos;
$iRev = testWc_Revprops($sName, $oClient, \@aRepoURLs, $iRev, 1);
# ---------------------------------
# test directory listing
# ---------------------------------
my @aListing=qw(X.txt Y.txt Z.txt B1/ B1/XX.txt);
$iRev = testWc_Listing($sName, $oClient, \@aWc, $iRev
, 'A1', \@aListing);
# ---------------------------------
# test edit history
# ---------------------------------
$iRev = testWc_EditHistory($sName, $oClient, \@aWc, $iRev
, 'EditTest.txt');
# ---------------------------------
# test edit history
# ---------------------------------
$iRev = testWc_ImportExport($sName, $oClient, \@aRepoURLs, $iRev
, 'import1', \@aWc, $oSandbox->makeChild('exportTest'));
diag("\nTesting of <$sName> complete\n");
return;
}
#--------------------------------------------------------------------
sub testWc_Branching {
my ($sName, $oClient, $aRepos, $iRev, $aWc, $sTrunk, $sBranch) = @_;
my $aTrunk = okMkdir($sName, $oClient, $aWc, $sTrunk, []
=> $ADD_STATUS, $ADD_ACTIONS);
okCommit($sName, $oClient, $aTrunk, []
=> $NORMAL_STATUS, ++$iRev, $ADD_DIR_COMMIT_ACTIONS);
my $aBranch = okMkdir($sName, $oClient, $aWc, $sBranch,[]
=> $ADD_STATUS, $ADD_ACTIONS);
okCommit($sName, $oClient, $aBranch, []
=> $NORMAL_STATUS, ++$iRev, $ADD_DIR_COMMIT_ACTIONS);
#-------------------------
# Switch directory to a branch
#-------------------------
# make the directory that stores trunk hold fils from branch
# i.e. even though we are editing locally $aTrank, the commits are
# going to $sBranch in the repository
okSwitch($sName, $oClient, $aTrunk, [$aRepos], $sBranch, []
=> [ $SVN::Wc::Notify::Action::update_update, @$UPDATE_ACTIONS]);
my $aSounds = okAdd($sName, $oClient, $aWc
, [ "$sTrunk/Cow.sound", "Moooo\n" ], []
=> $ADD_STATUS, $ADD_ACTIONS);
okCommit($sName, $oClient, $aTrunk, []
=> $NORMAL_STATUS, ++$iRev, $ADD_FILE_COMMIT_ACTIONS);
#-------------------------
# Modify the file, then revert
#-------------------------
# add something to the end of the file so that diff with report
# something other than ''
$SANDBOX->appendToFile($_,"Brrrr") for @$aSounds;
okDiff($sName, $oClient, [$aSounds], undef, []
=> "Moooo\n+Brrrr", '');
okRevert($sName, $oClient, $aSounds,[] => $NORMAL_STATUS, 1);
okDiff($sName, $oClient, [$aSounds], undef, []
=> '', '');
# due to revert, no changes
okCommit($sName, $oClient, $aBranch, []
=> $NORMAL_STATUS, undef, []);
#-------------------------
# Switch directory back to trunk
#-------------------------
# Now switch $aTrunk back to $sTrunk
# we have a delete action because the branch has a file that is
# not in the trunk
okSwitch($sName, $oClient, $aTrunk, [$aRepos], $sTrunk, []
=> [ $SVN::Wc::Notify::Action::update_delete, @$UPDATE_ACTIONS]);
okAdd($sName, $oClient, $aWc, ["$sBranch/Cat.sound", "Meow\n"], []
=> $ADD_STATUS, $ADD_ACTIONS);
okCommit($sName, $oClient, $aBranch, []
=> $NORMAL_STATUS, ++$iRev, $ADD_FILE_COMMIT_ACTIONS);
# Merge should result in 2 files in the directory
my $aExpectedActions = isBeforeOrAtRelease(1,4)
? [ ($SVN::Wc::Notify::Action::update_add) x 2
, @$MERGE_ACTIONS
]
: [ $SVN::Wc::Notify::Action::merge_begin
, ($SVN::Wc::Notify::Action::update_add) x 2
, @$MERGE_ACTIONS
];
okMerge($sName, $oClient, [ $aTrunk ], [ $aBranch ], $aTrunk,[]
=> [qw(Cow.sound Cat.sound)], $aExpectedActions);
return $iRev;
}
#--------------------------------------------------------------------
sub testWc_EditHistory {
my ($sName, $oClient, $aWcs, $iRev, $sRelPath) = @_;
my $sFirstEdit="First edit\n";
my $sSecondEdit="Second edit\n";
my @aFullPaths;
#--------------------------------
# first edit
#--------------------------------
foreach my $oWcs (@$aWcs) {
my $sFullPath = $oWcs->addFile($sRelPath, $sFirstEdit);
$oClient->add($sFullPath);
$oClient->commit($sFullPath);
push @aFullPaths, $sFullPath;
}
$iRev++; # for commit in loop above
my $sContent = $sFirstEdit;
my $hExpectedInfo
= { last_changed_rev => $iRev
, kind => $SVN::Node::file
, lock => 0
};
my $sSubtest="$sName:firstEdit";
my $hProps = {};
okCat($sSubtest, $oClient, [\@aFullPaths], [] => $sContent);
okBlame($sSubtest, $oClient, [\@aFullPaths],[] => 1, $sContent);
# get props from both working copy and repository version
okPropget($sSubtest, $oClient, [\@aFullPaths], []
=> $iRev, $hProps);
okPropget($sSubtest, $oClient, [\@aFullPaths, 'HEAD'], []
=> $iRev, $hProps);
okProplist($sSubtest, $oClient, [\@aFullPaths], [] => undef);
okProplist($sSubtest, $oClient, [\@aFullPaths, 'HEAD'],[] => undef);
okInfo($sSubtest, $oClient, [\@aFullPaths], []
=> 1, $hExpectedInfo);
# run with both the $bChangedPaths flag set to true and false
okLog($sSubtest, $oClient, [\@aFullPaths ], []
=> 1, [('') x 1]);
okLog($sSubtest, $oClient, [\@aFullPaths ], [undef,undef,1]
=> 1, [('') x 1]);
#--------------------------------
# second edit
#--------------------------------
foreach my $i (0..$#$aWcs) {
my $oWcs = $aWcs->[$i];
my $sFullPath = $aFullPaths[$i];
$oWcs->appendToFile($sRelPath, $sSecondEdit);
$oClient->propset($sFullPath, 'X', 'lalala');
$oClient->propset($sFullPath, 'Y', 'yayaya');
$oClient->commit($sFullPath);
}
$iRev++; # for commit in loop above
$sSubtest="$sName:secondEdit";
$sContent .= $sSecondEdit;
$hExpectedInfo->{last_changed_rev} = $iRev;
$hProps = { X => 'lalala', Y => 'yayaya' };
okCat($sSubtest, $oClient, [\@aFullPaths], [] => $sContent);
okBlame($sSubtest, $oClient, [\@aFullPaths],[] => 2, $sContent);
# get props from both working copy and repository version
okPropget($sSubtest, $oClient, [\@aFullPaths], []
=> $iRev, $hProps);
okPropget($sSubtest, $oClient, [\@aFullPaths, 'HEAD'], []
=> $iRev, $hProps);
okProplist($sSubtest, $oClient, [\@aFullPaths], [] => $hProps);
okProplist($sSubtest, $oClient, [\@aFullPaths,'HEAD'],[]=> $hProps);
# info has 1 visit because it is per-path
okInfo($sSubtest, $oClient, [\@aFullPaths], []
=> 1, $hExpectedInfo);
# log has 2 bacuase it is per revision
okLog($sSubtest, $oClient, [\@aFullPaths], [undef,undef,1]
=> 2, [('') x 2]);
return $iRev;
}
#--------------------------------------------------------------------
sub testWc_EmptyRoots {
my ($sName, $oClient, $aWcs, $aWcRoots, $aRepos, $aRepoURLs
, $aMirrorURLs) = @_;
my $iRev = 0;
okCheckout($sName, $oClient, [ $aRepoURLs ], $aWcRoots, []
=> $aRepos, 0, $iRev);
for my $i (0..$#$aWcs) {
my $sWc = $aWcRoots->[$i];
my $sRepoURL = $aRepoURLs->[$i];
my $sTest = "$sName: getRepositoryRootURL($sWc)";
is($oClient->getRepositoryRootURL($sWc), $sRepoURL
, "$sTest - verifying repository root");
}
okRelocate($sName, $oClient, $aWcs, $aMirrorURLs, []);
okRelocate($sName, $oClient, $aWcs, $aRepoURLs, []);
okStatus($sName, $oClient, [ $aWcRoots ], []
=> $NORMAL_STATUS,[],[]);
okUpdate($sName, $oClient, [ $aWcRoots ], [] => 0);
okResolved($sName, $oClient, $aWcRoots, [] => []);
okCommit($sName, $oClient, $aWcRoots, []
=> $NORMAL_STATUS, undef, []);
okCleanup($sName, $oClient, $aWcRoots);
return $iRev;
}
#--------------------------------------------------------------------
sub testWc_ImportExport {
my ($sName, $oClient, $aRepoURIs, $iRev, $sBranch, $aWcs
, $oSandbox) = @_;
#--------------------------
# Import
#--------------------------
my $aBranches = okImport($sName, $oClient, $IMPORT_DIR, $aRepoURIs
, $sBranch, []
=> ++$iRev, $IMPORT_LISTING);
okList($sName, $oClient, [ $aBranches ], [], $IMPORT_LISTING);
#--------------------------
# Export from repository
#--------------------------
# can't export to an existing directory, so create a directory
# immediately under the sandbox root
my @aExport = map { $oSandbox->getFullPathName("Head$_")
} @VERSION_SUFFIXES[0..$WC_LAST_IDX];
okExport($sName, $oClient, [ $aBranches, 'HEAD' ], \@aExport, []
=> $IMPORT_LISTING);
#--------------------------
# Export from working copy
#--------------------------
my @aWcBranches;
foreach my $i (0..$#$aRepoURIs) {
my $sSource = $aBranches->[$i];
my $oWc = $aWcs->[$i];
my $sPath = $oWc->getFullPathName($sBranch);
$oClient->checkout($sSource, undef, $sPath);
#local $"="\n";
#print STDERR "\ndirectory exists? ", ((-d $sPath) ? 1 : 0)
# , "\nworking dir contents=@{$oWc->list(undef,1)}\n";
push @aWcBranches, $sPath;
}
@aExport = map { $oSandbox->getFullPathName("Working$_")
} @VERSION_SUFFIXES[0..$WC_LAST_IDX];
okExport($sName, $oClient, [ \@aWcBranches ], \@aExport, []
=> $IMPORT_LISTING);
return $iRev;
}
#--------------------------------------------------------------------
sub testWc_Listing {
my ($sName, $oClient, $aWcs, $iRev, $sDir, $aRelPaths
, $aListing)=@_;
$aListing = [ map { /^(.+)\/$/ ? $1 : $_ } @$aRelPaths ]
unless defined($aListing);
# populate the working copies
my @aListPaths;
my @ahFullPaths;
foreach my $oWcs (@$aWcs) {
my $sListPath = $oWcs->getFullPathName($sDir);
$oClient->mkdir($sListPath);
my $hFullPaths = $oWcs->addPaths($sDir, $aRelPaths);
$oClient->add($hFullPaths->{$_},0) foreach (@$aRelPaths);
$oClient->commit($oWcs->getRoot());
push @ahFullPaths, $hFullPaths;
push @aListPaths, $sListPath;
}
okList($sName, $oClient, [\@aListPaths], [], $aListing);
foreach my $i (0..$#$aWcs) {
# reverse sort to make sure we delete deepest paths first
$oClient->delete(reverse sort [values %{$ahFullPaths[$i]}]);
$oClient->commit($aListPaths[$i]);
}
okList($sName, $oClient, [\@aListPaths], [], []);
return $iRev + 2;
}
#--------------------------------------------------------------------
sub testWc_PathOps {
my ($sName, $oClient, $aWc, $iRev, $bFile, $xAdd, $sRelPath
, $aRepoURLs) = @_;
my $sCopyRelPath = "${sRelPath}_copy1";
my $sCopyRelPath2 = "${sRelPath}_copy2";
my $sMoveRelPath = "${sRelPath}_move1";
my $sMoveRelPath2 = "${sRelPath}_move2";
my $aExpectedActions;
# add a path (file or dir)
my $aPaths;
if ($bFile) {
#-----------------------------------
# test add with files
#-----------------------------------
$aPaths = okAdd($sName, $oClient, $aWc, $xAdd, []
=> $ADD_STATUS, $ADD_ACTIONS);
# reverts unschedules the add, but does not delete the file
okRevert($sName, $oClient, $aPaths, []
=> $UNVERSIONED_STATUS, 1);
okAdd("$sName-after revert", $oClient, $aPaths, undef, []
=> $ADD_STATUS, $ADD_ACTIONS);
okCommit($sName, $oClient, $aPaths, []
=> $NORMAL_STATUS, ++$iRev, $ADD_FILE_COMMIT_ACTIONS);
#-----------------------------------
# test lock, unlock
#-----------------------------------
okLock($sName, $oClient, $aPaths, ['---']
=> $LOCK_FILE_ACTIONS);
okUnlock($sName, $oClient, $aPaths, []
=> $UNLOCK_FILE_ACTIONS);
} else {
#-----------------------------------
# test mkdir, add with directories
#-----------------------------------
$aPaths = okMkdir($sName, $oClient, $aWc, $xAdd, []
=> $ADD_STATUS, $ADD_ACTIONS);
# reverts unschedules the add, but does not delete the directory
okRevert("$sName-after mkdir", $oClient, $aPaths, []
=> $UNVERSIONED_STATUS, 1);
# mkdir fails because directory already exists, but add will work
okMkdir("$sName-after mkdir+revert", $oClient, $aPaths, undef, []
=> $UNVERSIONED_STATUS, $SOME_STRING_EXCEPTION);
okAdd("$sName-after mkdir+revert", $oClient, $aPaths, undef, []
=> $ADD_STATUS, $ADD_ACTIONS);
# mkdir within a scheduled to be added directory is ok
my $aLocalX1 = okMkdir($sName, $oClient, $aWc, "$xAdd/X1", []
=> $ADD_STATUS, $ADD_ACTIONS);
okCommit("$sName - after mkdir+revert+mkdir"
, $oClient, $aPaths, []
=> $NORMAL_STATUS, ++$iRev, [(@$ADD_DIR_COMMIT_ACTIONS) x 2]);
#-----------------------------------
# test obstructing directory
#-----------------------------------
# create a directory in the repository that isn't yet in the
# working copy
my @aRemoteX2 = map {
_appendRelPathToURL($oClient->getRepositoryURL($_), 'X2');
} @$aPaths;
okMkdir($sName, $oClient, \@aRemoteX2, undef, []);
$iRev++; #remote copy auto commits
# add an obstructing directory
okAdd($sName, $oClient, $aWc, ["$xAdd/X2"],[]
=> $ADD_STATUS, $ADD_ACTIONS);
okUpdate("$sName - obstructed", $oClient, $aPaths, []
=> $iRev, $SOME_STRING_EXCEPTION);
okCommit("$sName - obstructed", $oClient, $aPaths, []
=> $NORMAL_STATUS, undef, $SOME_STRING_EXCEPTION);
# add a non-obstructing file so that we have something
# to test commit behavior with after we clean up the obstruction
okAdd($sName, $oClient, $aWc, ["$xAdd/X2.txt"],[]
=> $ADD_STATUS, $ADD_ACTIONS);
# to fix the problem it isn't enough to delete the file
# we also need to unschedule the add
for my $oWc (@$aWc) { $oWc->removePath("$xAdd/X2") }
okUpdate("$sName - obstructing file removed"
, $oClient, $aPaths, []
=> $iRev, $SOME_STRING_EXCEPTION);
okCommit("$sName - obstructing file removed"
, $oClient, $aPaths, []
=> $NORMAL_STATUS, undef, $SOME_STRING_EXCEPTION);
# unschedule the add and all is well
for my $oWc (@$aWc) {
$oClient->revert($oWc->getFullPathName("$xAdd/X2"));
}
okUpdate("$sName - obstructing file unscheduled"
, $oClient, [ $aPaths ], [] => $iRev
, [ $SVN::Wc::Notify::Action::update_add
, $SVN::Wc::Notify::Action::update_update
, @$UPDATE_ACTIONS ]);
okCommit("$sName - obstructing file unscheduled"
, $oClient, $aPaths, []
=> $NORMAL_STATUS, ++$iRev, $ADD_FILE_COMMIT_ACTIONS);
}
#-----------------------------------
# verify root URL for non-root path
#-----------------------------------
{
my $sPath = $aPaths->[0];
my $sRepoURL = $aRepoURLs->[0];
is($oClient->getRepositoryRootURL($sPath), $sRepoURL
, "getRepositoryRootURL: verifying repository root "
."for $sPath");
}
#-----------------------------------
# test wc copy
#-----------------------------------
my $aCopies = okCopy($sName, $oClient, [$aPaths], $aWc
, [$sCopyRelPath, $bFile],[]);
my $aUpdateActions= $bFile
? $UPDATE_ACTIONS
: [ $SVN::Wc::Notify::Action::update_update, @$UPDATE_ACTIONS ];
my $aCommitActions = $bFile
? $COPY_COMMIT_ACTIONS
: [ ($SVN::Wc::Notify::Action::commit_added) x 3
, @$COPY_COMMIT_ACTIONS];
my @aRoots = map { $_->getRoot() } @$aWc;
# Changes from 1.4 to 1.5
# * 1.5 allows copies of copies (it just adds them), 1.4 does not
# * 1.5 adds a svn:mergeinfo property on the copied file, 1.4 does not
# * 1.5 on copy has one add for each dir and parent (like update)
# rather than one add for each path added, as in 1.4
if (isBeforeOrAtRelease(1,4)) {
# copies of uncommitted adds are not allowed
okCopy("$sName - copy uncommitted add", $oClient, [$aCopies]
, $aWc, [ $sCopyRelPath2,$bFile ], [] => $SOME_STRING_EXCEPTION);
# the failed copy leaves the working copy in an inconsistent state
# we can't commit without cleanup
okUpdate("$sName - failed copy w/o cleanup", $oClient, [\@aRoots], []
=> $iRev, $SOME_STRING_EXCEPTION);
okCommit("$sName - failed copy w/o cleanup", $oClient, $aCopies, []
=> $NORMAL_STATUS, undef, $SOME_STRING_EXCEPTION);
# after cleanup all is well
# Note: commit works before update too
okCleanup("$sName - after failed copy", $oClient, \@aRoots);
# one update_update for each changed directory and for each
# of its parents
$aExpectedActions = $aUpdateActions;
okUpdate("$sName - update - failed copy w/ cleanup"
, $oClient,[\@aRoots], [] => $iRev, $aExpectedActions);
# Note: one add for the copied dir and each of its members
# (X1/ X2/ X2.txt)
$aExpectedActions = $bFile
? $COPY_COMMIT_ACTIONS
: [ ($SVN::Wc::Notify::Action::commit_added) x 3
, @$COPY_COMMIT_ACTIONS];
okCommit("$sName - commit - failed copy w/ cleanup", $oClient, $aCopies, []
=> $NORMAL_COPY_STATUS, ++$iRev, $aExpectedActions);
} else {
# one update_update for each changed directory and for each
# of its parents
$aExpectedActions = $aUpdateActions;
okUpdate("$sName - update after copy"
, $oClient,[\@aRoots], [] => $iRev, $aExpectedActions);
# Note: one add for dir and parent, like update
$aExpectedActions = $bFile
? $COPY_COMMIT_ACTIONS
: [ $SVN::Wc::Notify::Action::commit_added, @$COPY_COMMIT_ACTIONS];
okCommit("$sName - commit after copy", $oClient, $aCopies, []
=> $NORMAL_COPY_STATUS, ++$iRev, $aExpectedActions);
my $hProperties = $oClient->getPathProperties($aCopies->[0]);
#printf STDERR "path=%s: props=%s\n", $aCopies->[0]
# , "@{[map { $_.'='.$hProperties->{$_} } keys %$hProperties ]}";
}
#-----------------------------------
# test wc move
#-----------------------------------
# one add for the moved dir and a delete for each member of the
# moved directory (. X1/ X2/ X2.txt)
$aExpectedActions = $bFile
? $MOVE_ACTIONS
: [ $SVN::Wc::Notify::Action::add
, ($SVN::Wc::Notify::Action::delete) x 4
];
my $aMoved = okMove($sName, $oClient, $aCopies, $aWc
, [$sMoveRelPath,$bFile], []
, => $aExpectedActions);
my $aCommit = [ map { [$aCopies->[$_], $aMoved->[$_]]
} (0..$#$aCopies) ];
# changes from subversion 1.4 to 1.5
# - moves of uncommitted adds are allowed
if (isBeforeOrAtRelease(1,4)) {
okMove("$sName - move uncommitted move", $oClient, $aMoved
, $aWc, [ $sMoveRelPath2, $bFile ], []
=> $SOME_STRING_EXCEPTION);
okUpdate("$sName - failed move w/o cleanup"
, $oClient, \@aRoots, []
=> $iRev, $SOME_STRING_EXCEPTION);
okCommit("$sName - failed move w/o cleanup"
, $oClient, $aCommit, []
=> $NORMAL_COPY_STATUS, undef, $SOME_STRING_EXCEPTION);
# cleanup and all is well
# Note1: commit works after update too
okCleanup("$sName - after failed copy", $oClient, \@aRoots);
okCommit("$sName - failed move w/ cleanup", $oClient, $aCommit, []
=> [$NOT_FOUND_STATUS, $NORMAL_COPY_STATUS], ++$iRev
, $MOVE_COMMIT_ACTIONS);
okUpdate("$sName - failed move w/ cleanup", $oClient,[\@aRoots], []
=> $iRev, $UPDATE_ACTIONS);
} else {
okCommit("$sName - commit: move", $oClient, $aCommit, []
=> [$NOT_FOUND_STATUS, $NORMAL_COPY_STATUS], ++$iRev
, $MOVE_COMMIT_ACTIONS);
okUpdate("$sName - update: move", $oClient,[\@aRoots], []
=> $iRev, $UPDATE_ACTIONS);
}
#-----------------------------------
# test properties: add, set, delete
#-----------------------------------
# 1.5 adds the svn:mergeinfo property to copy/moved paths
my $hRemaining = isBeforeOrAtRelease(1,4)
? {} : { 'svn:mergeinfo' => '' };
my $hProps ={a=>10,b=>20};
my $aRevertActions = $bFile
? $REVERT_ACTIONS
: [ (@$REVERT_ACTIONS) x 4 ]; # for (. X1/ X2/ X2.txt )
$aCommitActions = $bFile
? $MOD_COMMIT_ACTIONS
: [ (@$MOD_COMMIT_ACTIONS) x 4 ]; # for (. X1/ X2/ X2.txt )
# add properties to a versioned path
okPropset("$sName - add props", $oClient, $aMoved, $hProps, []
=> $MOD_PROP_STATUS);
okRevert("$sName - revert add props", $oClient, $aMoved, []
=> $NORMAL_COPY_STATUS, 1, $aRevertActions);
okPropset("$sName - redo add props", $oClient, $aMoved, $hProps, []
=> $MOD_PROP_STATUS);
okCommit("$sName - commit add props", $oClient, $aMoved, []
=> $NORMAL_PROP_STATUS, ++$iRev, $aCommitActions);
# modify properties
$hProps->{a} = 111;
okPropset("$sName - mod props", $oClient, $aMoved, $hProps, []
=> $MOD_PROP_STATUS);
okRevert("$sName - revert mod props", $oClient, $aMoved, []
=> $NORMAL_PROP_STATUS, 1, $aRevertActions);
okPropset("$sName - redo mod props", $oClient, $aMoved, $hProps, []
=> $MOD_PROP_STATUS);
okCommit("$sName - commit mod props", $oClient, $aMoved, []
=> $NORMAL_PROP_STATUS, ++$iRev, $aCommitActions);
# remove properties
okPropdel("$sName - del props", $oClient, $aMoved
, [ keys %$hProps ], []
=> $hRemaining, $MOD_PROP_STATUS);
okRevert("$sName - revert del props", $oClient, $aMoved, []
=> $NORMAL_PROP_STATUS, 1, $aRevertActions);
okPropdel("$sName - redo del props", $oClient, $aMoved
, [ keys %$hProps ], []
=> $hRemaining, $MOD_PROP_STATUS);
okCommit("$sName - commit del props", $oClient, $aMoved, []
=> $NORMAL_COPY_STATUS, ++$iRev, $aCommitActions);
#-----------------------------------
# test delete
#-----------------------------------
# delete the moved copy
my $aDelActions = $bFile
? $DEL_ACTIONS
: [ (@$DEL_ACTIONS) x 4 ]; # for (. X1/ X2/ X2.txt )
okDelete("$sName - delete moved dir", $oClient, $aMoved, []
=> $DEL_STATUS, $aDelActions);
okRevert("$sName - revert delete moved dir", $oClient, $aMoved, []
=> $NORMAL_COPY_STATUS, 1, $aRevertActions);
okDelete("$sName - redo delete moved dir", $oClient, $aMoved, []
=> $DEL_STATUS, $aDelActions);
# not clear why but even for a populated directory there is only
# ONE delete action, not one for each (. X1/ X2/ X2.txt)
okCommit("$sName - commit del moved dir", $oClient, $aMoved, []
=> $NOT_FOUND_STATUS, ++$iRev, $DEL_COMMIT_ACTIONS);
return $iRev;
}
#--------------------------------------------------------------------
sub testWc_Revprops {
my ($sName, $oClient, $aPaths, $iRev
, $bEnabled, $hInitProps, $hProps) = @_;
if (!defined($bEnabled)) {
$bEnabled = 0;
}
if (!defined($hInitProps)) {
$hInitProps = {};
}
if (!defined($hProps)) {
$hProps = { a => "apple", b => "bananna" };
}
my ($hAll, $hRemaining, $aModActions);
if ($bEnabled) {
$hAll = { %$hInitProps, %$hProps };
$hRemaining = { map { $_ => $hAll->{$_} } keys %$hInitProps };
} else {
$aModActions = $SOME_STRING_EXCEPTION;
$hAll = $hInitProps;
$hRemaining = $hInitProps;
}
okRevprop_set($sName, $oClient, [$aPaths,$iRev], $hProps, []
=> $iRev, $hAll, $aModActions);
okRevprop_list($sName, $oClient, [$aPaths,$iRev],[]
=> $iRev, $hAll);
okRevprop_get($sName, $oClient, [$aPaths,$iRev],[]
=> $iRev, $hAll);
okRevprop_delete($sName, $oClient, [$aPaths,$iRev], $hProps, []
=> $iRev, $hRemaining, $aModActions);
return $iRev;
}
#--------------------------------------------------------------------
sub testWc_RepoPathOps {
my ($sName, $oClient, $aRepoURLs, $iRev, $sDir) = @_;
my $sDirFrom = $sDir.'_from';
my $sDirCopy = $sDir.'_copy';
my $hProps = { 'A' => 'apple', 'B' => 'bananna' };
my @aFrom = map { _appendRelPathToURL($_, $sDirFrom) } @$aRepoURLs;
okMkdir($sName, $oClient, \@aFrom, undef, []);
$iRev++;
my @aCopy = map { _appendRelPathToURL($_, $sDirCopy) } @$aRepoURLs;
okCopy($sName, $oClient, [\@aFrom, 'HEAD'], \@aCopy, undef, []);
$iRev++;
# remote setting of paths is not supported until
# $IDX_REMOTE_PROPSET
if ($IDX_REMOTE_PROPSET <= $WC_LAST_IDX) {
my $aPaths = _selectPaths(\@aCopy, $IDX_REMOTE_PROPSET);
okPropset($sName, $oClient, \@aCopy, $hProps, []);
$iRev++;
okPropdel($sName, $oClient, \@aCopy, $hProps, []);
$iRev++;
}
my @aDelete = map { [$aFrom[$_], $aCopy[$_] ] } (0..$#aFrom);
okDelete($sName, $oClient, \@aDelete, []);
$iRev++;
return $iRev;
}
#==================================================================
# Miscellenous tools
#==================================================================
sub _makeCall($$) {
my ($sName, $aArgs) = @_;
return "$sName("
. ($aArgs
? join(',', map { defined($_) ? $_ :'undef';} @$aArgs) : '')
. ')';
}
#==================================================================
# TEST PLAN
#==================================================================
testDefaults();
testClient_Local_NoAuth();
# skip version specific tests
SKIP: {
skip("Tests targetted at subversion 1.4, testing ".
$SVN::Core::VER_MAJOR.'.'.$SVN::Core::VER_MINOR, 112)
unless isBeforeOrAtRelease(1,4);
}
if ($NAG_REPORT_SWIG_BUGS && keys %SWIG_BINDING_BUGS) {
my $sMsg="SWIG binding bugs found: need to report";
$sMsg .= "\n\t$_" for keys %SWIG_BINDING_BUGS;
diag("\n\n$sMsg\n\n");
};