3 #=======================================================================
5 # File ID: a9a05f2e-4d60-11e2-8d2a-0016d364066c
7 # Test suite for datefn(1).
10 # ©opyleft 2012– Øyvind A. Holm <sunny@sunbase.org>
11 # License: GNU General Public License version 2 or later, see end of
12 # file for legal stuff.
13 #=======================================================================
19 use Test
::More
qw{no_plan
};
27 our $CMD_BASENAME = "datefn";
28 our $CMD = "../$CMD_BASENAME";
42 $progname =~ s/^.*\/(.*?)$/$1/;
43 our $VERSION = '0.0.0';
45 my %descriptions = ();
48 Getopt
::Long
::Configure
('bundling');
51 'all|a' => \
$Opt{'all'},
52 'help|h' => \
$Opt{'help'},
53 'quiet|q+' => \
$Opt{'quiet'},
54 'todo|t' => \
$Opt{'todo'},
55 'verbose|v+' => \
$Opt{'verbose'},
56 'version' => \
$Opt{'version'},
58 ) || die("$progname: Option error. Use -h for help.\n");
60 $Opt{'verbose'} -= $Opt{'quiet'};
61 $Opt{'help'} && usage
(0);
62 if ($Opt{'version'}) {
73 diag
(sprintf('========== Executing %s v%s ==========',
74 $progname, $VERSION));
76 my $exiftool_version = `exiftool -ver 2>/dev/null`;
77 if (defined($exiftool_version) && $exiftool_version =~ /^\d+\.\d+/) {
81 if ($Opt{'todo'} && !$Opt{'all'}) {
87 testcmd("$CMD command", # {{{
100 test_standard_options
();
104 my $topdir = "datefn-files";
107 my $newname = "20121224T002858Z.file.txt";
108 unlink($newname); # In case junk from earlier runs
109 untar
("file.tar.gz");
110 testcmd
("../$CMD file.txt",
111 "datefn: 'file.txt' renamed to '$newname'\n",
114 "Add date to file.txt",
118 "Sånn går now the days.\n",
119 "file.txt was properly renamed",
122 diag
('Testing --force option...');
123 untar
("file.tar.gz");
124 testcmd
("../$CMD file.txt",
126 "datefn: $newname: File already exists, use --force to overwrite\n",
128 "Don't overwrite file without --force",
131 testcmd
("../$CMD -f file.txt",
132 "datefn: 'file.txt' renamed to '$newname'\n",
135 "File is overwritten with --force",
138 testcmd
("../$CMD $newname",
140 "datefn: $newname: Filename already has date\n",
142 "Don't add date when there's already one there",
145 diag
("Testing --replace option...");
147 ok
(utime(1433116800, 1433116800, $newname), "Change mtime of $newname");
148 my $newname2 = "20150601T000000Z.file.txt";
149 unlink($newname2); # In case junk from earlier runs
150 testcmd
("../$CMD --replace $newname",
151 "datefn: '$newname' renamed to '$newname2'\n",
154 "Replace timestamp with new modification time",
157 file_data
($newname2),
158 "Sånn går now the days.\n",
159 "file.txt was renamed to new mtime with -r",
162 diag
('Testing --delete option...');
163 testcmd
("../$CMD --delete $newname2",
164 "datefn: '$newname2' renamed to 'file.txt'\n",
167 "Delete date with --delete",
170 testcmd
("../$CMD -d -v file.txt",
172 "datefn: Filename for file.txt is unchanged\n",
174 "Delete non-existing date with -d",
177 testcmd
("../$CMD -d -r -v file.txt",
179 "datefn: Cannot mix -d/--delete and -r/--replace options\n",
181 "-d and -r can't be mixed",
184 testcmd
("../$CMD -r -v file.txt",
185 "datefn: 'file.txt' renamed to '$newname2'\n",
188 "-r on file without date adds timestamp",
191 diag
("Check that it works with paths...");
194 testcmd
("$CMD -d datefn-files/$newname2",
195 "datefn: 'datefn-files/$newname2' renamed to " .
196 "'datefn-files/file.txt'\n",
199 "Delete date from parent directory",
202 testcmd
("$CMD datefn-files/file.txt",
203 "datefn: 'datefn-files/file.txt' renamed to " .
204 "'datefn-files/$newname2'\n",
207 "Re-add date from parent directory",
210 safe_chdir
("datefn-files");
212 ok
(unlink($newname2), "unlink $newname2");
214 diag
('Testing --git option...');
215 my $git_version = `git --version 2>/dev/null`;
216 if ($git_version =~ /^git version \d/) {
217 my $newname3 = "20150611T123129Z.file.txt";
218 untar
("repo.tar.gz");
220 ok
(-d
".git" && -f
"file.txt", "repo.tar.gz was properly unpacked");
221 unlink($newname3); # In case junk from earlier runs
222 testcmd
("../../$CMD --git file.txt",
223 "datefn: 'file.txt' renamed to '$newname3'\n",
224 "datefn: Executing \"git mv file.txt $newname3\"...\n",
226 "Use --git option in Git repository",
229 file_data
($newname3),
230 "This is the most amazing file.\n",
231 "file.txt was properly renamed",
233 testcmd
("git status --porcelain",
235 R file.txt -> $newname3
241 "File status looks ok in git",
243 testcmd
("../../$CMD -gd $newname3",
244 "datefn: '$newname3' renamed to 'file.txt'\n",
245 "datefn: Executing \"git mv $newname3 file.txt\"...\n",
247 "Use -d and -g option in Git repository",
250 file_data
("file.txt"),
251 "This is the most amazing file.\n",
252 "$newname3 was properly renamed",
254 testcmd
("git status --porcelain",
261 "File status in git is ok, changes to file.txt are gone",
263 testcmd
("LC_ALL=C ../../$CMD -g unknown.txt",
265 "datefn: Executing \"git mv unknown.txt " .
266 "20150611T141445Z.unknown.txt\"...\n" .
267 "fatal: not under version control, source=unknown.txt, " .
268 "destination=20150611T141445Z.unknown.txt\n" .
269 "datefn: unknown.txt: Cannot rename file to " .
270 "'20150611T141445Z.unknown.txt': No such file or directory\n",
272 "Use --git option on file unknown to Git",
275 testcmd
("rm -rf repo", "", "", 0, "Remove repo/");
276 ok
(!-e
"repo", "repo/ is gone");
278 diag
("Cannot find 'git' executable, skipping --git tests");
281 diag
('Testing --skew option...');
282 untar
("file.tar.gz");
283 testcmd
("../$CMD -s 86400 file.txt",
284 "datefn: 'file.txt' renamed to '20121225T002858Z.file.txt'\n",
287 "Test -s (--skew) with positive integer",
289 ok
(unlink('20121225T002858Z.file.txt'),
290 "unlink '20121225T002858Z.file.txt'");
292 untar
("file.tar.gz");
293 testcmd
("../$CMD --skew -86400 file.txt",
294 "datefn: 'file.txt' renamed to '20121223T002858Z.file.txt'\n",
297 "--skew with negative integer",
299 ok
(unlink('20121223T002858Z.file.txt'),
300 "unlink '20121223T002858Z.file.txt'");
302 # FIXME: Add tests for --bwf
307 if ($Opt{'all'} || $Opt{'todo'}) {
308 diag
('Running TODO tests...'); # {{{
313 # Insert TODO tests here.
319 diag
('Testing finished.');
324 sub test_standard_options
{
326 diag
('Testing -h (--help) option...');
328 '/ Show this help/i',
331 'Option -h prints help screen');
333 diag
('Testing -v (--verbose) option...');
335 '/^\n\S+ \d+\.\d+\.\d+/s',
338 'Option -v with -h returns version number and help screen');
340 diag
('Testing --version option...');
341 likecmd
("$CMD --version",
342 '/^\S+ \d+\.\d+\.\d+/',
345 'Option --version returns version number');
351 sub test_exif_option
{
353 my $testpic = "dsd_5330.jpg";
354 my $testdate = "20090706T213604Z";
355 my $tmpdir = "datefn-tmp";
357 diag
("Testing -e/--exif option...");
358 if (!$has_exiftool) {
359 diag
("exiftool(1) not found, skip tests");
363 safe_chdir
("datefn-files");
365 diag
("NOTICE: $tmpdir/ exists, deleting it.");
366 system("rm -rf \"$tmpdir\"");
368 ok
(mkdir($tmpdir), "mkdir $tmpdir");
369 ok
(copy_file
("small.$testpic", "$tmpdir/$testpic"),
370 "Copy small.$testpic to $tmpdir/$testpic");
371 for my $e (qw{ -e
--exif
}) {
372 diag
("Test $e option");
373 testcmd
("$CMD $e $tmpdir/$testpic",
374 "datefn: '$tmpdir/$testpic' renamed to " .
375 "'$tmpdir/$testdate.$testpic'\n",
378 "Use EXIF data from $tmpdir/$testpic ($e)");
379 ok
(-f
"$tmpdir/$testdate.$testpic",
380 "$tmpdir/$testdate.$testpic exists");
381 ok
(rename("$tmpdir/$testdate.$testpic", "$tmpdir/$testpic"),
382 "Remove timestamp from $testpic after $e");
383 testcmd
("$CMD $e -vv $tmpdir/$testpic",
384 "datefn: '$tmpdir/$testpic' renamed to " .
385 "'$tmpdir/$testdate.$testpic'\n",
387 "datefn: Curr = 'datefn-tmp/dsd_5330.jpg'\n",
388 "datefn: get_exif_data() found \" " .
389 "\"DateTimeOriginal\": \"2009:07:06 21:36:04\",\n",
391 "datefn: \$line after regexp: \"2009:07:06 21:36:04\"\n",
392 "datefn: exif_date(): \$retval before check = " .
393 "\"2009:07:06 21:36:04\"\n",
394 "datefn: exif_date() returns \"1246916164\"\n",
395 "datefn: start_date(datefn-tmp/dsd_5330.jpg) returns " .
399 "Use EXIF data from $tmpdir/$testpic ($e -vv)");
400 ok
(rename("$tmpdir/$testdate.$testpic", "$tmpdir/$testpic"),
401 "Remove timestamp from $testpic after $e -vv");
402 diag
("Test -s/--skew together with $e");
403 my $skewdate = "20090706T203604Z";
404 testcmd
("$CMD -n $e -s -3600 small.$testpic",
405 "datefn: 'small.$testpic' would be renamed to " .
406 "'$skewdate.small.$testpic'\n",
409 "Test --skew with EXIF data from small.$testpic ($e)");
410 diag
("Try to read EXIF from empty file");
411 testcmd
("$CMD -n $e empty",
415 "Try to read EXIF from empty file ($e)");
416 testcmd
("$CMD -n -v $e empty",
418 "$CMD_BASENAME: empty: No EXIF data found in file\n",
420 "Read EXIF from empty file, -v prints message ($e)");
421 diag
("Test -E/--exif-tag");
422 testcmd
("$CMD -n $e -E CreateDate small.$testpic",
423 "datefn: 'small.$testpic' would be renamed to " .
424 "'$testdate.small.$testpic'\n",
427 "Use timestamp from CreateDate EXIF tag ($e)");
428 testcmd
("$CMD -n $e -E PowerUpTime small.$testpic",
429 "datefn: 'small.$testpic' would be renamed to " .
430 "'20090515T164127Z.small.$testpic'\n",
433 "Use -E PowerUpTime ($e)");
434 testcmd
("$CMD -n $e --exif-tag PowerUpTime --skew 86400 " .
436 "datefn: 'small.$testpic' would be renamed to " .
437 "'20090516T164127Z.small.$testpic'\n",
440 "Use --skew together with --exif-tag PowerUpTime ($e)");
441 testcmd
("$CMD -n $e --exif-tag NotFound small.$testpic",
445 "Use non-existing EXIF tag with --exif-tag ($e)");
446 testcmd
("$CMD -nv $e -E NotFound small.$testpic",
448 "$CMD_BASENAME: small.$testpic: No EXIF data found in file\n",
450 "Non-existing EXIF tag with -E and -v ($e)");
452 ok
(unlink("$tmpdir/$testpic"), "Delete $tmpdir/$testpic");
453 ok
(rmdir($tmpdir), "Delete $tmpdir/");
459 sub test_local_option
{
461 my $testpic = "dsd_5330.jpg";
462 my $testdate = "20090706T213604Z";
463 my $tmpdir = "datefn-tmp";
464 my $orig_tz = $ENV{'TZ'};
468 'CET' => "20090706T193604Z",
469 'EST' => "20090707T023604Z",
470 'UTC' => "20090706T213604Z",
474 diag
("Test -l/--local option");
475 if (!$has_exiftool) {
476 diag
("exiftool(1) not found, skip tests");
480 safe_chdir
("datefn-files");
482 diag
("NOTICE: $tmpdir/ exists, deleting it.");
483 system("rm -rf \"$tmpdir\"");
485 ok
(mkdir($tmpdir), "mkdir $tmpdir");
486 ok
(copy_file
("small.$testpic", "$tmpdir/$testpic"),
487 "Copy small.$testpic to $tmpdir/$testpic");
488 for my $l (qw{ -l
--local }) {
489 diag
("Test $l option");
490 for my $tz (qw{ CET EST UTC
}) {
491 diag
("Use timezone $tz");
493 testcmd
("$CMD -e $l $tmpdir/$testpic",
494 "datefn: '$tmpdir/$testpic' renamed to " .
495 "'$tmpdir/$locdate{$tz}.$testpic'\n",
498 "Use EXIF data from $tmpdir/$testpic (TZ=$tz, $l)");
499 ok
(-f
"$tmpdir/$locdate{$tz}.$testpic",
500 "$tmpdir/$locdate{$tz}.$testpic exists");
501 ok
(rename("$tmpdir/$locdate{$tz}.$testpic", "$tmpdir/$testpic"),
502 "Remove timestamp from $testpic after $l");
505 ok
(unlink("$tmpdir/$testpic"), "Delete $tmpdir/$testpic");
506 ok
(rmdir($tmpdir), "rmdir $tmpdir/");
508 diag
("Test -l/--local on file mtimes");
509 untar
("file.tar.gz");
512 'CET' => '20121223T232858Z',
513 'EST' => '20121224T052858Z',
514 'UTC' => '20121224T002858Z',
517 for my $l (qw{ -l
--local }) {
518 for my $tz (qw{ CET EST UTC
}) {
519 diag
("timezone = $tz");
521 my $newname = "$locdate{$tz}.file.txt";
523 diag
("NOTICE: test_local_option(): $newname exists, "
527 testcmd
("$CMD $l file.txt",
528 "datefn: 'file.txt' renamed to '$newname'\n",
531 "Use mtime from file.txt with $l, tz = $tz",
533 ok
(-e
$newname, "$newname exists after $l and tz = $tz");
534 ok
(rename($newname, "file.txt"),
535 "Rename $newname back to file.txt");
538 $ENV{'TZ'} = $orig_tz;
546 my ($from, $to) = @_;
548 if (!open(From
, "<", $from)) {
549 diag
("copy_file(): $from: Cannot open file for read: $!");
552 if (!open(To
, ">", $to)) {
553 diag
("copy_file(): $to: Cannot open file for write: $!");
557 while (my $line = <From
>) {
571 ok
(chdir($dir), "chdir $dir") ||
572 BAIL_OUT
("$progname: Can't chdir to $dir, aborting");
581 likecmd
("tar xzf \"$fname\"", '/.*/', '/.*/', 0, "Untar $fname");
582 undef $descriptions{"Untar $fname"};
589 my ($Cmd, $Exp_stdout, $Exp_stderr, $Exp_retval, $Desc) = @_;
590 defined($descriptions{$Desc}) &&
591 BAIL_OUT
("testcmd(): '$Desc' description is used twice");
592 $descriptions{$Desc} = 1;
594 my $cmd_outp_str = $Opt{'verbose'} >= 1 ?
"\"$Cmd\" - " : '';
595 my $Txt = join('', $cmd_outp_str, defined($Desc) ?
$Desc : '');
596 my $TMP_STDERR = "$CMD_BASENAME-stderr.tmp";
599 if (defined($Exp_stderr)) {
600 $stderr_cmd = " 2>$TMP_STDERR";
602 $retval &= is
(`$Cmd$stderr_cmd`, $Exp_stdout, "$Txt (stdout)");
604 if (defined($Exp_stderr)) {
605 $retval &= is
(file_data
($TMP_STDERR), $Exp_stderr, "$Txt (stderr)");
608 diag
("Warning: stderr not defined for '$Txt'");
610 $retval &= is
($ret_val >> 8, $Exp_retval, "$Txt (retval)");
618 my ($Cmd, $Exp_stdout, $Exp_stderr, $Exp_retval, $Desc) = @_;
619 defined($descriptions{$Desc}) &&
620 BAIL_OUT
("likecmd(): '$Desc' description is used twice");
621 $descriptions{$Desc} = 1;
623 my $cmd_outp_str = $Opt{'verbose'} >= 1 ?
"\"$Cmd\" - " : '';
624 my $Txt = join('', $cmd_outp_str, defined($Desc) ?
$Desc : '');
625 my $TMP_STDERR = "$CMD_BASENAME-stderr.tmp";
628 if (defined($Exp_stderr)) {
629 $stderr_cmd = " 2>$TMP_STDERR";
631 $retval &= like
(`$Cmd$stderr_cmd`, $Exp_stdout, "$Txt (stdout)");
633 if (defined($Exp_stderr)) {
634 $retval &= like
(file_data
($TMP_STDERR), $Exp_stderr, "$Txt (stderr)");
637 diag
("Warning: stderr not defined for '$Txt'");
639 $retval &= is
($ret_val >> 8, $Exp_retval, "$Txt (retval)");
646 # Return file content as a string {{{
650 open(my $fp, '<', $File) or return undef;
659 # Print program version {{{
660 print("$progname $VERSION\n");
666 # Send the help message to stdout {{{
669 if ($Opt{'verbose'}) {
675 Usage: $progname [options]
677 Contains tests for the $CMD_BASENAME(1) program.
682 Run all tests, also TODOs.
686 Be more quiet. Can be repeated to increase silence.
688 Run only the TODO tests.
690 Increase level of verbosity. Can be repeated.
692 Print version information.
700 # Print a status message to stderr based on verbosity level {{{
701 my ($verbose_level, $Txt) = @_;
703 $verbose_level > $Opt{'verbose'} && return;
704 print(STDERR
"$progname: $Txt\n");
711 # This program is free software; you can redistribute it and/or modify
712 # it under the terms of the GNU General Public License as published by
713 # the Free Software Foundation; either version 2 of the License, or (at
714 # your option) any later version.
716 # This program is distributed in the hope that it will be useful, but
717 # WITHOUT ANY WARRANTY; without even the implied warranty of
718 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
719 # See the GNU General Public License for more details.
721 # You should have received a copy of the GNU General Public License
722 # along with this program.
723 # If not, see L<http://www.gnu.org/licenses/>.
725 # vim: set fenc=UTF-8 ft=perl fdm=marker ts=4 sw=4 sts=4 et fo+=w :