std.t: create_file(): Use `>` as separate parameter in open()
[sunny256-utils.git] / tests / datefn.t
bloba25a1cf10fb7478a1e7957a557063303d8a11675
1 #!/usr/bin/env perl
3 #=======================================================================
4 # datefn.t
5 # File ID: a9a05f2e-4d60-11e2-8d2a-0016d364066c
7 # Test suite for datefn(1).
9 # Character set: UTF-8
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 #=======================================================================
15 use strict;
16 use warnings;
18 BEGIN {
19 use Test::More qw{no_plan};
20 # use_ok() goes here
23 use Getopt::Long;
25 local $| = 1;
27 our $CMD_BASENAME = "datefn";
28 our $CMD = "../$CMD_BASENAME";
30 our %Opt = (
32 'all' => 0,
33 'help' => 0,
34 'quiet' => 0,
35 'todo' => 0,
36 'verbose' => 0,
37 'version' => 0,
41 our $progname = $0;
42 $progname =~ s/^.*\/(.*?)$/$1/;
43 our $VERSION = '0.0.0';
45 my %descriptions = ();
46 my $has_exiftool = 0;
48 Getopt::Long::Configure('bundling');
49 GetOptions(
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'}) {
63 print_version();
64 exit(0);
67 exit(main());
69 sub main {
70 # {{{
71 my $Retval = 0;
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+/) {
78 $has_exiftool = 1;
81 if ($Opt{'todo'} && !$Opt{'all'}) {
82 goto todo_section;
85 =pod
87 testcmd("$CMD command", # {{{
88 <<'END',
89 [expected stdout]
90 END
91 '',
93 'description',
96 # }}}
98 =cut
100 test_standard_options();
101 test_exif_option();
102 test_local_option();
104 my $topdir = "datefn-files";
105 safe_chdir($topdir);
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",
117 file_data($newname),
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...");
192 safe_chdir("..");
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");
219 safe_chdir("repo");
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",
234 <<END,
235 R file.txt -> $newname3
236 ?? datefn-stderr.tmp
237 ?? unknown.txt
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",
255 <<END,
256 ?? datefn-stderr.tmp
257 ?? unknown.txt
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",
274 safe_chdir("..");
275 testcmd("rm -rf repo", "", "", 0, "Remove repo/");
276 ok(!-e "repo", "repo/ is gone");
277 } else {
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
304 todo_section:
307 if ($Opt{'all'} || $Opt{'todo'}) {
308 diag('Running TODO tests...'); # {{{
310 TODO: {
312 local $TODO = '';
313 # Insert TODO tests here.
316 # TODO tests }}}
319 diag('Testing finished.');
320 return $Retval;
321 # }}}
322 } # main()
324 sub test_standard_options {
325 # {{{
326 diag('Testing -h (--help) option...');
327 likecmd("$CMD -h",
328 '/ Show this help/i',
329 '/^$/',
331 'Option -h prints help screen');
333 diag('Testing -v (--verbose) option...');
334 likecmd("$CMD -hv",
335 '/^\n\S+ \d+\.\d+\.\d+/s',
336 '/^$/',
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+/',
343 '/^$/',
345 'Option --version returns version number');
347 return;
348 # }}}
351 sub test_exif_option {
352 # {{{
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");
360 return 1;
362 $CMD = "../$CMD";
363 safe_chdir("datefn-files");
364 if (-e $tmpdir) {
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",
386 join('',
387 "datefn: Curr = 'datefn-tmp/dsd_5330.jpg'\n",
388 "datefn: get_exif_data() found \" " .
389 "\"DateTimeOriginal\": \"2009:07:06 21:36:04\",\n",
390 "\"\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 " .
396 "'0'\n",
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 " .
435 "small.$testpic",
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/");
454 safe_chdir("..");
455 $CMD =~ s/^\.\.\///;
456 # }}}
459 sub test_local_option {
460 # {{{
461 my $testpic = "dsd_5330.jpg";
462 my $testdate = "20090706T213604Z";
463 my $tmpdir = "datefn-tmp";
464 my $orig_tz = $ENV{'TZ'};
466 my %locdate = (
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");
477 return 1;
479 $CMD = "../$CMD";
480 safe_chdir("datefn-files");
481 if (-e $tmpdir) {
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");
492 $ENV{'TZ'} = $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");
510 %locdate = (
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");
520 $ENV{'TZ'} = $tz;
521 my $newname = "$locdate{$tz}.file.txt";
522 if (-e $newname) {
523 diag("NOTICE: test_local_option(): $newname exists, "
524 . "deleting it");
525 unlink($newname);
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;
539 safe_chdir("..");
540 $CMD =~ s/^\.\.\///;
541 # }}}
544 sub copy_file {
545 # {{{
546 my ($from, $to) = @_;
548 if (!open(From, "<", $from)) {
549 diag("copy_file(): $from: Cannot open file for read: $!");
550 return 0;
552 if (!open(To, ">", $to)) {
553 diag("copy_file(): $to: Cannot open file for write: $!");
554 close(From);
555 return 0;
557 while (my $line = <From>) {
558 print(To $line);
560 close(To);
561 close(From);
563 return 1;
564 # }}}
567 sub safe_chdir {
568 # {{{
569 my $dir = shift;
571 ok(chdir($dir), "chdir $dir") ||
572 BAIL_OUT("$progname: Can't chdir to $dir, aborting");
573 return;
574 # }}}
577 sub untar {
578 # {{{
579 my $fname = shift;
581 likecmd("tar xzf \"$fname\"", '/.*/', '/.*/', 0, "Untar $fname");
582 undef $descriptions{"Untar $fname"};
583 return;
584 # }}}
587 sub testcmd {
588 # {{{
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;
593 my $stderr_cmd = '';
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";
597 my $retval = 1;
599 if (defined($Exp_stderr)) {
600 $stderr_cmd = " 2>$TMP_STDERR";
602 $retval &= is(`$Cmd$stderr_cmd`, $Exp_stdout, "$Txt (stdout)");
603 my $ret_val = $?;
604 if (defined($Exp_stderr)) {
605 $retval &= is(file_data($TMP_STDERR), $Exp_stderr, "$Txt (stderr)");
606 unlink($TMP_STDERR);
607 } else {
608 diag("Warning: stderr not defined for '$Txt'");
610 $retval &= is($ret_val >> 8, $Exp_retval, "$Txt (retval)");
612 return $retval;
613 # }}}
614 } # testcmd()
616 sub likecmd {
617 # {{{
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;
622 my $stderr_cmd = '';
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";
626 my $retval = 1;
628 if (defined($Exp_stderr)) {
629 $stderr_cmd = " 2>$TMP_STDERR";
631 $retval &= like(`$Cmd$stderr_cmd`, $Exp_stdout, "$Txt (stdout)");
632 my $ret_val = $?;
633 if (defined($Exp_stderr)) {
634 $retval &= like(file_data($TMP_STDERR), $Exp_stderr, "$Txt (stderr)");
635 unlink($TMP_STDERR);
636 } else {
637 diag("Warning: stderr not defined for '$Txt'");
639 $retval &= is($ret_val >> 8, $Exp_retval, "$Txt (retval)");
641 return $retval;
642 # }}}
643 } # likecmd()
645 sub file_data {
646 # Return file content as a string {{{
647 my $File = shift;
648 my $Txt;
650 open(my $fp, '<', $File) or return undef;
651 local $/ = undef;
652 $Txt = <$fp>;
653 close($fp);
654 return $Txt;
655 # }}}
656 } # file_data()
658 sub print_version {
659 # Print program version {{{
660 print("$progname $VERSION\n");
661 return;
662 # }}}
663 } # print_version()
665 sub usage {
666 # Send the help message to stdout {{{
667 my $Retval = shift;
669 if ($Opt{'verbose'}) {
670 print("\n");
671 print_version();
673 print(<<"END");
675 Usage: $progname [options]
677 Contains tests for the $CMD_BASENAME(1) program.
679 Options:
681 -a, --all
682 Run all tests, also TODOs.
683 -h, --help
684 Show this help.
685 -q, --quiet
686 Be more quiet. Can be repeated to increase silence.
687 -t, --todo
688 Run only the TODO tests.
689 -v, --verbose
690 Increase level of verbosity. Can be repeated.
691 --version
692 Print version information.
695 exit($Retval);
696 # }}}
697 } # usage()
699 sub msg {
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");
705 return;
706 # }}}
707 } # msg()
709 __END__
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 :