3 #==============================================================================
5 # File ID: dd2d5468-4cdb-11e6-bed9-02010e0a6634
7 # Test suite for git-testadd(1).
10 # ©opyleft 2016– Øyvind A. Holm <sunny@sunbase.org>
11 # License: GNU General Public License version 2 or later, see end of file for
13 #==============================================================================
19 use Test
::More
qw{no_plan
};
27 our $CMDB = "git-testadd";
28 our $CMD = "../$CMDB";
33 'git' => defined($ENV{'TESTADD_GIT'}) ?
$ENV{'TESTADD_GIT'} : 'git',
43 $progname =~ s/^.*\/(.*?)$/$1/;
44 our $VERSION = '0.0.0';
46 my %descriptions = ();
48 Getopt
::Long
::Configure
('bundling');
51 'all|a' => \
$Opt{'all'},
52 'git|g=s' => \
$Opt{'git'},
53 'help|h' => \
$Opt{'help'},
54 'quiet|q+' => \
$Opt{'quiet'},
55 'todo|t' => \
$Opt{'todo'},
56 'verbose|v+' => \
$Opt{'verbose'},
57 'version' => \
$Opt{'version'},
59 ) || die("$progname: Option error. Use -h for help.\n");
61 $Opt{'verbose'} -= $Opt{'quiet'};
62 $Opt{'help'} && usage
(0);
63 if ($Opt{'version'}) {
73 diag
(sprintf('========== Executing %s v%s ==========',
74 $progname, $VERSION));
76 if ($Opt{'todo'} && !$Opt{'all'}) {
77 ok
(1, "No todo tests here");
81 test_standard_options
();
84 diag
('Testing finished.');
89 sub test_standard_options
{
90 diag
('Testing -h (--help) option...');
95 'Option -h prints help screen');
97 diag
('Testing -v (--verbose) option...');
99 '/^\n\S+ \d+\.\d+\.\d+/s',
102 'Option -v with -h returns version number and help screen');
104 diag
('Testing --version option...');
105 likecmd
("$CMD --version",
106 '/^\S+ \d+\.\d+\.\d+/',
109 'Option --version returns version number');
115 test_executable() - Specify options and expected output to test. The expected
116 output is represented as special flags in a comma-separated list, all flags
117 must have a comme before and after them. Some flags expect "()" added to them,
118 with an optional value inside.
122 sub test_executable
{
123 my $toptmp = "tmp-git-testadd-t-$$-" . substr(rand, 2, 8);
124 my $repo = "$toptmp/repo";
126 diag
("Initialise Git repository");
127 ok
(! -d
$toptmp, "[toptmp] doesn't exist") ||
128 BAIL_OUT
("$toptmp already exists");
129 ok
(mkdir($toptmp), "mkdir [toptmp]");
130 cmd
("$Opt{'git'} init \"$repo\"", "$Opt{'git'} init [repo]");
131 ok
(-d
"$repo/.git", "[repo]/.git exists") ||
132 BAIL_OUT
("$repo/.git doesn't exist");
133 ok
(chdir($repo), "chdir [repo]");
136 test_options_without_commits
();
137 test_options_with_commits
();
139 diag
("Clean up files");
140 ok
(chdir("../.."), "chdir ../..");
141 $CMD =~ s/^\.\.\/\.\.\///;
142 ok
(-d
$repo, "[repo] exists") || BAIL_OUT
("$repo not found");
143 testcmd
("rm -rf \"$repo\"", "", "", 0, "rm -rf [repo]");
144 ok
(rmdir($toptmp), "rmdir [toptmp]");
147 sub test_options_without_commits
{
149 test_options
("No options",
150 ",rm(),clone(),cd(),cmd,", ",using(),nostaged,cmd,", 0,
154 test_options
("-l/--label",
155 ",rm(mylabel),clone(mylabel),cd(mylabel),cmd,",
156 ",using(mylabel),nostaged,cmd,", 0,
157 "-l mylabel", "--label mylabel");
159 diag
("-p/--pristine");
160 test_options
("-p/--pristine",
161 ",rm(),clone(),cd(),cmd,",
162 ",using(),unmodified,cmd,", 0,
166 test_options
("-r/--ref",
168 ",invalidref(nosuchrefmate),", 1,
169 "-r nosuchrefmate", "--ref nosuchrefmate");
171 diag
("-u/--unmodified");
172 test_options
("-u/--unmodified, missing destdir",
174 ",using(),notfound(),", 1,
175 "-u", "--unmodified");
178 sub test_options_with_commits
{
179 diag
("Add, commit and modify a new file");
180 commit_new_file
("file.txt");
181 is
(commit_log
("master"),
182 "1f935e2a5946e77df739c9d2f376af3778ddb71e Add file.txt\n",
183 "git log after file.txt was added");
184 cmd
("$Opt{'git'} branch first", "Create 'first' branch");
185 is
(commit_log
("first"),
186 "1f935e2a5946e77df739c9d2f376af3778ddb71e Add file.txt\n",
187 "'first' branch looks ok");
188 cmd
("echo New line >>file.txt", "Add new line to file.txt");
189 is
(file_data
("file.txt"), "This is file.txt\nNew line\n",
190 "New line was added to file.txt");
192 diag
("Test without staged changes");
193 test_options
("No options, no staged changes",
194 ",rm(),clone(),cd(),cmd,", ",using(),nostaged,cmd,", 0,
197 diag
("Test with staged changes");
198 cmd
("$Opt{'git'} add file.txt", "Add changes in file.txt to Git");
199 test_options
("No options, staged changes",
200 ",rm(),clone(),apply(),cd(),cmd,",
201 ",using(),applying,cmd,", 0, "");
204 test_options
("-l/--label, staged changes",
205 ",rm(mylabel),clone(mylabel),apply(mylabel)," .
207 ",using(mylabel),applying,cmd,", 0,
208 "-l mylabel", "--label mylabel");
210 diag
("-p/--pristine");
211 test_options
("-p/--pristine, staged changes",
212 ",rm(),clone(),cd(),cmd,",
213 ",using(),unmodified,cmd,", 0,
216 diag
("-u/--unmodified");
217 test_options
("-u/--unmodified, staged changes",
219 ",using(),notfound(),", 1,
220 "-u", "--unmodified");
223 cmd
("$Opt{'git'} commit -m 'Add line to file.txt'",
224 "Commit line addition to file.txt");
225 is
(commit_log
("master"),
226 "dec5ff4abeb9999e6e6989a549ccc95185e7dfab Add line to file.txt\n" .
227 "1f935e2a5946e77df739c9d2f376af3778ddb71e Add file.txt\n",
228 "git log is ok after line addition");
229 test_options
("-r/--ref",
231 ",invalidref(nosuchrefwc),", 1,
232 "-r nosuchrefwc", "--ref nosuchrefwc");
233 cmd
("echo Third line >>file.txt", "Add third line to file.txt");
234 cmd
("$Opt{'git'} add file.txt", "Stage third line in file.txt");
235 likecmd
("$CMD -r first echo yup",
237 o_err
(",using(),clone(),swnewbranch(first),applying" .
238 ",applyfailed(file.txt),"),
240 "-r first, apply should fail");
241 cmd
("$Opt{'git'} reset", "git reset");
242 cmd
("$Opt{'git'} checkout -f file.txt",
243 "Remove changes from file.txt");
244 create_file
("file2.txt", "This is file2.txt");
245 cmd
("$Opt{'git'} add file2.txt", "Stage file2.txt for addition");
246 likecmd
("$CMD -r first echo yup",
248 o_err
(",using(),clone(),swnewbranch(first),applying,cmd," .
251 "-r first, apply of file2.txt should succeed");
256 test_options() - Test the executable with the received options. Runs the
257 program with -n (--dry-run) and checks stdout, stderr and exit value.
262 my ($desc, $stdout, $stderr, $exitval, @opts) = @_;
264 for my $opt (@opts) {
265 my $spc = length($opt) ?
" " : "";
267 likecmd
("$CMD -n$spc$opt echo yup",
268 o_out
($stdout), o_err
($stderr), $exitval,
275 o_out() - Return string with expected stdout output. Parse contents of $flags,
276 a comma-separated list of flags with optional arguments in ().
285 if ($flags =~ /,rm\(([^\(\)]*)\),/) {
288 $val = length($val) ?
"-$val" : "";
289 $retval .= "rm -rf \\.testadd$val\\.tmp\\n";
291 if ($flags =~ /,clone\(([^\(\)]*)\),/) {
294 $val = length($val) ?
"-$val" : "";
295 $retval .= ".+ clone .+ \\.testadd$val\\.tmp\\n";
297 if ($flags =~ /,apply\(([^\(\)]*)\),/) {
300 $val = length($val) ?
"-$val" : "";
301 $retval .= "eval .+ diff --cached --binary " .
302 "--no-textconv \\| " .
303 "\\(cd \"\\.testadd$val\\.tmp\" \\&\\& " .
304 ".+ apply\\)\\n" . "";
306 if ($flags =~ /,cd\(([^\(\)]*)\),/) {
309 $val = length($val) ?
"-$val" : "";
310 $retval .= "cd \\.testadd$val\\.tmp\\/\\n";
312 if ($flags =~ /,cmd,/) {
313 $retval .= "eval echo yup\\n";
322 o_err() - Return string with expected stderr output. Parse contents of $flags,
323 a comma-separated list of flags with optional arguments in ().
332 if ($flags =~ /,using\(([^\(\)]*)\),/) {
335 $val = length($val) ?
"-$val" : "";
336 $retval .= "git-testadd: Using \"\\.testadd$val\\.tmp\" as " .
337 "destination directory\\n";
339 if ($flags =~ /,clone\(([^\(\)]*)\),/) {
342 $val = length($val) ?
"-$val" : "";
343 $retval .= "Cloning into " .
344 "\\'\\.testadd$val\\.tmp\\'\\.\\.\\.\\n" .
347 if ($flags =~ /,invalidref\(([^\(\)]*)\),/) {
350 $retval .= "fatal: Needed a single revision\\n" .
351 "git-testadd: $val: Invalid Git ref\\n";
353 if ($flags =~ /,notfound\(([^\(\)]*)\),/) {
356 $val = length($val) ?
"-$val" : "";
357 $retval .= "git-testadd: \\.testadd$val\\.tmp not found, " .
358 "-u\\/--unmodified needs it\\n";
360 if ($flags =~ /,swnewbranch\(([^\(\)]*)\),/) {
363 $retval .= "Switched to a new branch '$val'\\n";
365 if ($flags =~ /,applying,/) {
366 $retval .= "git-testadd: Applying staged changes\\n";
368 if ($flags =~ /,applyfailed\(([^\(\)]*)\),/) {
371 $retval .= "error: patch failed: $val:1\\n" .
372 "error: $val: patch does not apply\\n" .
373 "git-testadd: Could not apply patch\\n";
375 if ($flags =~ /,nostaged,/) {
376 $retval .= "git-testadd: No staged changes, running command " .
377 "with clean HEAD\\n";
379 if ($flags =~ /,unmodified,/) {
380 $retval .= "git-testadd: Running command with unmodified " .
383 if ($flags =~ /,cmd,/) {
385 $retval .= "git-testadd: Executing \"echo yup\" in .+\\n";
392 sub commit_new_file
{
395 ok
(!-e
$file, "$file doesn't exist");
396 create_file
($file, "This is $file\n");
397 cmd
("$Opt{'git'} add \"$file\"", "$Opt{'git'} add $file");
398 cmd
("$Opt{'git'} commit -m \"Add $file\"",
399 "$Opt{'git'} commit (add $file)");
407 "$Opt{'git'} log --format='%T %s' --topo-order $ref |") or
408 return "'$Opt{'git'} log' pipe error: $!\n";
418 my ($cmd, $desc) = @_;
420 likecmd
($cmd, '/.*/', '/.*/', 0, $desc);
424 my ($Cmd, $Exp_stdout, $Exp_stderr, $Exp_retval, $Desc) = @_;
425 defined($descriptions{$Desc}) &&
426 BAIL_OUT
("testcmd(): '$Desc' description is used twice");
427 $descriptions{$Desc} = 1;
429 my $cmd_outp_str = $Opt{'verbose'} >= 1 ?
"\"$Cmd\" - " : '';
430 my $Txt = join('', $cmd_outp_str, defined($Desc) ?
$Desc : '');
431 my $TMP_STDERR = "$CMDB-stderr.tmp";
434 if (defined($Exp_stderr)) {
435 $stderr_cmd = " 2>$TMP_STDERR";
437 $retval &= is
(`$Cmd$stderr_cmd`, $Exp_stdout, "$Txt (stdout)");
439 if (defined($Exp_stderr)) {
440 $retval &= is
(file_data
($TMP_STDERR),
441 $Exp_stderr, "$Txt (stderr)");
444 diag
("Warning: stderr not defined for '$Txt'");
446 $retval &= is
($ret_val >> 8, $Exp_retval, "$Txt (retval)");
452 my ($Cmd, $Exp_stdout, $Exp_stderr, $Exp_retval, $Desc) = @_;
453 defined($descriptions{$Desc}) &&
454 BAIL_OUT
("likecmd(): '$Desc' description is used twice");
455 $descriptions{$Desc} = 1;
457 my $cmd_outp_str = $Opt{'verbose'} >= 1 ?
"\"$Cmd\" - " : '';
458 my $Txt = join('', $cmd_outp_str, defined($Desc) ?
$Desc : '');
459 my $TMP_STDERR = "$CMDB-stderr.tmp";
462 if (defined($Exp_stderr)) {
463 $stderr_cmd = " 2>$TMP_STDERR";
465 $retval &= like
(`$Cmd$stderr_cmd`, $Exp_stdout, "$Txt (stdout)");
467 if (defined($Exp_stderr)) {
468 $retval &= like
(file_data
($TMP_STDERR),
469 $Exp_stderr, "$Txt (stderr)");
472 diag
("Warning: stderr not defined for '$Txt'");
474 $retval &= is
($ret_val >> 8, $Exp_retval, "$Txt (retval)");
480 # Return file content as a string
484 open(my $fp, '<', $File) or return undef;
492 # Create new file and fill it with data
493 my ($file, $text) = @_;
496 open(my $fp, ">$file") or return 0;
499 $retval = is
(file_data
($file), $text,
500 "$file was successfully created");
502 return $retval; # 0 if error, 1 if ok
506 # Print program version
507 print("$progname $VERSION\n");
512 # Send the help message to stdout
515 if ($Opt{'verbose'}) {
521 Usage: $progname [options]
523 Contains tests for the $CMDB(1) program.
528 Run all tests, also TODOs.
530 Specify alternative git executable to use. Used to execute the tests
531 with different git versions. This can also be set with the
532 TESTADD_GIT environment variable.
536 Be more quiet. Can be repeated to increase silence.
538 Run only the TODO tests.
540 Increase level of verbosity. Can be repeated.
542 Print version information.
549 # Print a status message to stderr based on verbosity level
550 my ($verbose_level, $Txt) = @_;
552 $verbose_level > $Opt{'verbose'} && return;
553 print(STDERR
"$progname: $Txt\n");
559 # This program is free software; you can redistribute it and/or modify it under
560 # the terms of the GNU General Public License as published by the Free Software
561 # Foundation; either version 2 of the License, or (at your option) any later
564 # This program is distributed in the hope that it will be useful, but WITHOUT
565 # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
566 # FOR A PARTICULAR PURPOSE.
567 # See the GNU General Public License for more details.
569 # You should have received a copy of the GNU General Public License along with
571 # If not, see L<http://www.gnu.org/licenses/>.
573 # vim: set ts=8 sw=8 sts=8 noet fo+=w tw=79 fenc=UTF-8 :