3 #=======================================================================
5 # File ID: 8f5fa76e-a802-11e5-bb87-fefdb24f8e10
7 # Test suite for filesynced(1).
10 # ©opyleft 2015– Ø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
};
28 our $CMD_BASENAME = "filesynced";
29 our $CMD = "../$CMD_BASENAME";
30 my $SQLITE = "sqlite3";
44 $progname =~ s/^.*\/(.*?)$/$1/;
45 our $VERSION = '0.0.0';
47 my %descriptions = ();
49 Getopt
::Long
::Configure
('bundling');
52 'all|a' => \
$Opt{'all'},
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'}) {
76 diag
(sprintf('========== Executing %s v%s ==========',
77 $progname, $VERSION));
79 if ($Opt{'todo'} && !$Opt{'all'}) {
85 testcmd("$CMD command", # {{{
98 diag
('Testing -h (--help) option...');
99 likecmd
("$CMD -h", # {{{
100 '/ Show this help/i',
103 'Option -h prints help screen',
107 diag
('Testing -v (--verbose) option...');
108 likecmd
("$CMD -h -v", # {{{
109 '/^\n\S+ \d+\.\d+\.\d+/s',
112 'Option -v with -h returns version number and help screen',
116 diag
('Testing --version option...');
117 likecmd
("$CMD --version", # {{{
118 '/^\S+ \d+\.\d+\.\d+/',
121 'Option --version returns version number',
126 my $syncfile = "$ENV{'HOME'}/bin/synced.sql";
128 diag
("$syncfile not found, skipping tests");
132 my $Tmptop = "tmp-filesynced-t-$$-" . substr(rand, 2, 8);
135 ok
(mkdir($Tmptop), "mkdir [Tmptop]");
136 ok
(chdir($Tmptop), "chdir [Tmptop]") || BAIL_OUT
();
137 likecmd
("$GIT init repo-fs-t", # {{{
141 "git init repo-fs-t",
145 ok
(-d
"repo-fs-t/.git", "repo-fs-t/.git exists") || BAIL_OUT
();
146 ok
(-d
"../$Tmptop", "We're in [Tmptop]") || BAIL_OUT
();
147 ok
(chdir("repo-fs-t"), "chdir repo-fs-t");
148 $CMD = "../../../$CMD_BASENAME";
149 ok
(-f
$CMD, "Executable is in place") || BAIL_OUT
();
150 testcmd
("$CMD -v", # No options, no database {{{
152 "filesynced: synced.sqlite: Sync database not found\n",
154 "No options, no database",
158 testcmd
("$CMD -l -v", # No database and -l {{{
160 "filesynced: synced.sqlite: Sync database not found\n",
162 "No database and -l",
167 chomp(my $sql_create_synced = <<END); # {{{
168 CREATE TABLE synced (
170 CONSTRAINT synced_file_length
171 CHECK (length(file) > 0)
178 CONSTRAINT synced_rev_length
179 CHECK (length(rev) = 40 OR rev = '')
182 CONSTRAINT synced_date_length
183 CHECK (date IS NULL OR length(date) = 19)
184 CONSTRAINT synced_date_valid
185 CHECK (date IS NULL OR datetime(date) IS NOT NULL)
189 chomp(my $sql_create_todo = <<END); # {{{
192 CONSTRAINT todo_file_length
193 CHECK(length(file) > 0)
198 CONSTRAINT todo_pri_range
199 CHECK(pri BETWEEN 1 AND 5)
205 testcmd
("$CMD --init", # {{{
209 "--init without options",
213 is
(sql_dump
("synced.sql"), <<END, "synced.sql is ok"); # {{{
219 likecmd
("$CMD --init", # {{{
221 '/\/repo-fs-t\/synced.sql already exists\n$/s',
223 "Refuse to --init when synced.sql exists",
227 testcmd
("sqlite3 synced.sqlite <synced.sql", '', '', 0, # {{{
228 "Create synced.sqlite from synced.sql");
231 ok
(unlink("synced.sql"), "Delete synced.sql");
232 likecmd
("$CMD --init", # {{{
234 '/\/repo-fs-t\/synced.sqlite: File already exists\n' .
235 'filesynced: No token received from filesynced --lock\n' .
238 "It also reacts negatively to the presence of synced.sqlite",
242 ok
(unlink("synced.sqlite"), "Delete synced.sqlite");
244 testcmd
("$CMD --init", # {{{
248 "Create synced.sql again with --init",
252 testcmd
("$CMD --lock >key.txt", "", "", 0, # {{{
253 "Use --lock, store key in key.txt",
257 my $realtoken = file_data
("key.txt");
258 likecmd
("$CMD --lock --timeout 0", # {{{
261 'filesynced --lock: .+\/repo-fs-t\/synced.sql\.lock: ' .
262 'Waiting for lockdir\.\.\.\n' .
263 'filesynced: Lock not aquired after 0 seconds, aborting\n' .
266 "Try to lock again, wimp gives up after 0 seconds",
270 like
($realtoken, # {{{
274 '20\d\d' . '[01]\d' . '\d\d' .
276 '[0-2]\d' . '[0-5]\d' . '[0-6]\d' .
288 testcmd
("$CMD --unlock", # {{{
290 "filesynced --unlock: Token mismatch\n",
292 "No argument to --unlock",
296 testcmd
("$CMD --unlock ''", # {{{
298 "filesynced --unlock: Token mismatch\n",
300 "--unlock receives empty string",
304 testcmd
("$CMD --unlock token_20141212T123456Z.1234." . ("2" x
40), # {{{
306 "filesynced --unlock: Token mismatch\n",
308 "--unlock token is wrong",
312 testcmd
("$CMD --unlock $realtoken", # {{{
316 "--unlock token is valid",
320 likecmd
("$CMD --lock", # {{{
324 "--lock, throw away the token",
328 testcmd
("$CMD --unlock -f", # {{{
332 "--unlock with -f (force)",
336 likecmd
("$CMD --lock", # {{{
340 "--lock again, throw away the token",
344 testcmd
("$CMD --force --unlock", # {{{
348 "--unlock with --force",
353 testcmd
("$CMD --add nonexisting.txt", # {{{
355 "filesynced: nonexisting.txt: File not found, no entries updated\n",
357 "Try to --add non-existing file",
361 ok
(create_file
("tmpfile.txt", "This is tmpfile.txt"),
362 "Create tmpfile.txt");
363 testcmd
("$CMD --add tmpfile.txt nonexisting.txt", # {{{
365 "filesynced: nonexisting.txt: File not found, no entries updated\n",
367 "Try to --add existing and non-existing file",
371 is
(sql_dump
("synced.sql"), # {{{
376 "tmpfile.txt is not added to synced.sql yet",
380 testcmd
("$CMD --add tmpfile.txt", # {{{
384 "Add tmpfile.txt with --add",
388 is
(sql_dump
("synced.sql"), # {{{
392 synced|tmpfile.txt|NULL|NULL|NULL
394 "tmpfile.txt is added to synced.sql",
398 likecmd
("$CMD --add tmpfile.txt", # {{{
400 '/filesynced: Cannot add "tmpfile\.txt" to the database, ' .
401 'no entries updated\n/s',
403 "Fail to add it again",
407 is
(sql_dump
("synced.sql"), # {{{
411 synced|tmpfile.txt|NULL|NULL|NULL
413 "There's only one tmpfile.txt in synced.sql",
417 ok
(!-d
"synced.sql.lock", "synced.sql.lock/ is gone");
419 testcmd
("$CMD --delete nonexisting.txt", # {{{
423 "--delete nonexisting.txt",
427 testcmd
("$CMD --delete tmpfile.txt", # {{{
429 "filesynced: Deleted tmpfile.txt from synced\n",
431 "--delete tmpfile.txt",
435 is
(sql_dump
("synced.sql"), # {{{
440 "tmpfile.txt is gone from synced.sql",
444 testcmd
("$CMD --add -t bash tmpfile.txt", # {{{
448 "Add tmpfile.txt again, now with -t bash",
452 is
(sql_dump
("synced.sql"), # {{{
456 synced|tmpfile.txt|Lib/std/bash|NULL|NULL
458 "tmpfile.txt is added to synced.sql with orig value",
463 create_file
("file1", "This is file1.\n");
464 testcmd
("git add file1", # {{{
472 likecmd
("git commit -m 'Add file1'", # {{{
473 '/^.+Add file1.+$/s',
480 testcmd
("$CMD --unsynced", # {{{
484 "file1 is not listed by --unsynced because " .
485 "it's not in synced.sql",
489 testcmd
("$CMD --add -t Lib/std/bash file1", # {{{
497 testcmd
("$CMD --unsynced", # {{{
501 "file1 is listed by --unsynced",
505 testcmd
("$CMD HEAD file1", # {{{
509 "Mark file1 as updated",
513 testcmd
("$CMD --unsynced", # {{{
517 "file1 should be gone from --unsynced now",
521 # diag("--valid-sha");
522 # FIXME: Create tests for --valid-sha. Have to set up some sync
524 testcmd
("$CMD --delete file1", # {{{
526 "filesynced: Deleted file1 from synced\n",
532 diag
("--create-index");
533 testcmd
("$CMD --create-index", # {{{
537 "Use with --create-index",
541 is
(sql_dump
("synced.sql"), # {{{
545 CREATE INDEX idx_synced_file ON synced (file);
546 CREATE INDEX idx_synced_orig ON synced (orig);
547 CREATE INDEX idx_synced_rev ON synced (rev);
548 synced|tmpfile.txt|Lib/std/bash|NULL|NULL
550 "synced.sql contains indexes",
556 ok
(chdir(".."), "chdir ..");
557 testcmd
("rm -rf repo-fs-t", '', '', 0, "Delete repo-fs-t/");
558 ok
(chdir(".."), "chdir ..");
559 ok
(rmdir($Tmptop), "rmdir [Tmptop]");
564 if ($Opt{'all'} || $Opt{'todo'}) {
565 diag
('Running TODO tests...'); # {{{
570 # Insert TODO tests here.
576 diag
('Testing finished.');
586 msg
(5, "sql(): db = '$db'");
587 local(*CHLD_IN
, *CHLD_OUT
, *CHLD_ERR
);
589 my $pid = open3
(*CHLD_IN
, *CHLD_OUT
, *CHLD_ERR
, $SQLITE, $db) or (
591 msg
(0, "sql(): open3() error: $!"),
592 return("sql() error"),
594 msg
(5, "sql(): sql = '$sql'");
595 print(CHLD_IN
"$sql\n") or msg
(0, "sql(): print CHLD_IN error: $!");
597 @retval = <CHLD_OUT
>;
598 msg
(5, "sql(): retval = '" . join('|', @retval) . "'");
599 my @child_stderr = <CHLD_ERR
>;
600 if (scalar(@child_stderr)) {
601 msg
(1, "$SQLITE error: " . join('', @child_stderr));
604 return(join('', @retval));
609 # Return contents of database file {{{
612 return sql
($File, <<END);
615 SELECT 'synced', * FROM synced;
623 my $db = "$File.sqlite";
626 is
(system("$SQLITE $db <$File"), 0, "Create $db from $File");
627 ok
(-f
$db, "$db exists");
628 $Txt = sqlite_dump
("$db");
629 ok
(unlink($db), "Delete $db");
637 my ($Cmd, $Exp_stdout, $Exp_stderr, $Exp_retval, $Desc) = @_;
638 defined($descriptions{$Desc}) &&
639 BAIL_OUT
("testcmd(): '$Desc' description is used twice");
640 $descriptions{$Desc} = 1;
642 my $cmd_outp_str = $Opt{'verbose'} >= 1 ?
"\"$Cmd\" - " : '';
643 my $Txt = join('', $cmd_outp_str, defined($Desc) ?
$Desc : '');
644 my $TMP_STDERR = "$CMD_BASENAME-stderr.tmp";
647 if (defined($Exp_stderr)) {
648 $stderr_cmd = " 2>$TMP_STDERR";
650 $retval &= is
(`$Cmd$stderr_cmd`, $Exp_stdout, "$Txt (stdout)");
652 if (defined($Exp_stderr)) {
653 $retval &= is
(file_data
($TMP_STDERR), $Exp_stderr, "$Txt (stderr)");
656 diag
("Warning: stderr not defined for '$Txt'");
658 $retval &= is
($ret_val >> 8, $Exp_retval, "$Txt (retval)");
666 my ($Cmd, $Exp_stdout, $Exp_stderr, $Exp_retval, $Desc) = @_;
667 defined($descriptions{$Desc}) &&
668 BAIL_OUT
("likecmd(): '$Desc' description is used twice");
669 $descriptions{$Desc} = 1;
671 my $cmd_outp_str = $Opt{'verbose'} >= 1 ?
"\"$Cmd\" - " : '';
672 my $Txt = join('', $cmd_outp_str, defined($Desc) ?
$Desc : '');
673 my $TMP_STDERR = "$CMD_BASENAME-stderr.tmp";
676 if (defined($Exp_stderr)) {
677 $stderr_cmd = " 2>$TMP_STDERR";
679 $retval &= like
(`$Cmd$stderr_cmd`, $Exp_stdout, "$Txt (stdout)");
681 if (defined($Exp_stderr)) {
682 $retval &= like
(file_data
($TMP_STDERR), $Exp_stderr, "$Txt (stderr)");
685 diag
("Warning: stderr not defined for '$Txt'");
687 $retval &= is
($ret_val >> 8, $Exp_retval, "$Txt (retval)");
694 # Return file content as a string {{{
698 open(my $fp, '<', $File) or return undef;
707 # Create new file and fill it with data {{{
708 my ($file, $text) = @_;
710 if (open(my $fp, ">$file")) {
716 "$file was successfully created",
719 return($retval); # 0 if error, 1 if ok
724 # Print program version {{{
725 print("$progname $VERSION\n");
731 # Send the help message to stdout {{{
734 if ($Opt{'verbose'}) {
740 Usage: $progname [options]
742 Contains tests for the $CMD_BASENAME(1) program.
747 Run all tests, also TODOs.
751 Be more quiet. Can be repeated to increase silence.
753 Run only the TODO tests.
755 Increase level of verbosity. Can be repeated.
757 Print version information.
765 # Print a status message to stderr based on verbosity level {{{
766 my ($verbose_level, $Txt) = @_;
768 $verbose_level > $Opt{'verbose'} && return;
769 print(STDERR
"$progname: $Txt\n");
776 # This program is free software; you can redistribute it and/or modify
777 # it under the terms of the GNU General Public License as published by
778 # the Free Software Foundation; either version 2 of the License, or (at
779 # your option) any later version.
781 # This program is distributed in the hope that it will be useful, but
782 # WITHOUT ANY WARRANTY; without even the implied warranty of
783 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
784 # See the GNU General Public License for more details.
786 # You should have received a copy of the GNU General Public License
787 # along with this program.
788 # If not, see L<http://www.gnu.org/licenses/>.
790 # vim: set fenc=UTF-8 ft=perl fdm=marker ts=4 sw=4 sts=4 et fo+=w :