summaryrefslogtreecommitdiff
path: root/t
diff options
context:
space:
mode:
authorJonas Smedegaard <dr@jones.dk>2010-08-27 10:01:58 +0200
committerJonas Smedegaard <dr@jones.dk>2010-08-27 10:01:58 +0200
commitf398ad035b973608d380c9939ea845d8e2a0cdc2 (patch)
tree1ba1a0c94e375ab8ed609eaa57a542c6b87de5a8 /t
parent958e5735c946263a111420fe47abe58782581e8c (diff)
parent6d213a0c739d5b34357b01a616f99197eeba6ad9 (diff)
Merge branch 'master' of git://git.ikiwiki.info
Diffstat (limited to 't')
-rwxr-xr-xt/add_depends.t70
-rwxr-xr-xt/basewiki_brokenlinks.t2
-rwxr-xr-xt/bazaar.t37
-rwxr-xr-xt/bestlink.t4
-rwxr-xr-xt/calculate_changed_links.t58
-rwxr-xr-xt/conflicts.t131
-rwxr-xr-xt/cvs.t88
-rwxr-xr-xt/file_pruned.t54
-rwxr-xr-xt/find_src_files.t97
-rwxr-xr-xt/git.t19
-rwxr-xr-xt/htmlize.t20
-rwxr-xr-xt/index.t41
-rwxr-xr-xt/mercurial.t18
-rwxr-xr-xt/openiduser.t9
-rwxr-xr-xt/pagespec_match.t56
-rwxr-xr-xt/pagespec_match_list.t174
-rwxr-xr-xt/pagespec_match_result.t84
-rwxr-xr-xt/pagespec_merge.t44
-rwxr-xr-xt/parentlinks.t1
-rwxr-xr-xt/permalink.t2
-rwxr-xr-xt/po.t20
-rwxr-xr-xt/preprocess.t12
-rwxr-xr-xt/svn.t13
-rwxr-xr-xt/tag.t39
-rwxr-xr-xt/template_syntax.t15
-rwxr-xr-xt/templates_documented.t14
-rwxr-xr-xt/yesno.t4
27 files changed, 1009 insertions, 117 deletions
diff --git a/t/add_depends.t b/t/add_depends.t
new file mode 100755
index 000000000..aa58fb0ff
--- /dev/null
+++ b/t/add_depends.t
@@ -0,0 +1,70 @@
+#!/usr/bin/perl
+use warnings;
+use strict;
+use Test::More tests => 40;
+
+BEGIN { use_ok("IkiWiki"); }
+%config=IkiWiki::defaultconfig();
+$config{srcdir}=$config{destdir}="/dev/null";
+IkiWiki::checkconfig();
+
+$pagesources{"foo$_"}="foo$_.mdwn" for 0..9;
+
+# avoids adding an unparseable pagespec
+ok(! add_depends("foo0", "foo and (bar"));
+ok(! add_depends("foo0", "foo another"));
+
+# simple and not-so-simple dependencies split
+ok(add_depends("foo0", "*"));
+ok(add_depends("foo0", "bar"));
+ok(add_depends("foo0", "BAZ"));
+ok(exists $IkiWiki::depends_simple{foo0}{"bar"});
+ok(exists $IkiWiki::depends_simple{foo0}{"baz"}); # lowercase
+ok(! exists $IkiWiki::depends_simple{foo0}{"*"});
+ok(! exists $IkiWiki::depends{foo0}{"bar"});
+ok(! exists $IkiWiki::depends{foo0}{"baz"});
+
+# default dependencies are content dependencies
+ok($IkiWiki::depends{foo0}{"*"} & $IkiWiki::DEPEND_CONTENT);
+ok(! ($IkiWiki::depends{foo0}{"*"} & ($IkiWiki::DEPEND_PRESENCE | $IkiWiki::DEPEND_LINKS)));
+ok($IkiWiki::depends_simple{foo0}{"bar"} & $IkiWiki::DEPEND_CONTENT);
+ok(! ($IkiWiki::depends_simple{foo0}{"bar"} & ($IkiWiki::DEPEND_PRESENCE | $IkiWiki::DEPEND_LINKS)));
+
+# adding other dep types standalone
+ok(add_depends("foo2", "*", deptype("presence")));
+ok(add_depends("foo2", "bar", deptype("links")));
+ok($IkiWiki::depends{foo2}{"*"} & $IkiWiki::DEPEND_PRESENCE);
+ok(! ($IkiWiki::depends{foo2}{"*"} & ($IkiWiki::DEPEND_CONTENT | $IkiWiki::DEPEND_LINKS)));
+ok($IkiWiki::depends_simple{foo2}{"bar"} & $IkiWiki::DEPEND_LINKS);
+ok(! ($IkiWiki::depends_simple{foo2}{"bar"} & ($IkiWiki::DEPEND_PRESENCE | $IkiWiki::DEPEND_CONTENT)));
+
+# adding combined dep types
+ok(add_depends("foo2", "baz", deptype("links", "presence")));
+ok($IkiWiki::depends_simple{foo2}{"baz"} & $IkiWiki::DEPEND_LINKS);
+ok($IkiWiki::depends_simple{foo2}{"baz"} & $IkiWiki::DEPEND_PRESENCE);
+ok(! ($IkiWiki::depends_simple{foo2}{"baz"} & $IkiWiki::DEPEND_CONTENT));
+
+# adding dep types to existing dependencies should merge the flags
+ok(add_depends("foo2", "baz"));
+ok($IkiWiki::depends_simple{foo2}{"baz"} & $IkiWiki::DEPEND_LINKS);
+ok($IkiWiki::depends_simple{foo2}{"baz"} & $IkiWiki::DEPEND_PRESENCE);
+ok(($IkiWiki::depends_simple{foo2}{"baz"} & $IkiWiki::DEPEND_CONTENT));
+ok(add_depends("foo2", "bar", deptype("presence"))); # had only links before
+ok($IkiWiki::depends_simple{foo2}{"bar"} & ($IkiWiki::DEPEND_LINKS | $IkiWiki::DEPEND_PRESENCE));
+ok(! ($IkiWiki::depends_simple{foo2}{"bar"} & $IkiWiki::DEPEND_CONTENT));
+ok(add_depends("foo0", "bar", deptype("links"))); # had only content before
+ok($IkiWiki::depends{foo0}{"*"} & ($IkiWiki::DEPEND_CONTENT | $IkiWiki::DEPEND_LINKS));
+ok(! ($IkiWiki::depends{foo0}{"*"} & $IkiWiki::DEPEND_PRESENCE));
+
+# content is the default if unknown types are entered
+ok(add_depends("foo9", "*", deptype("monkey")));
+ok($IkiWiki::depends{foo9}{"*"} & $IkiWiki::DEPEND_CONTENT);
+ok(! ($IkiWiki::depends{foo9}{"*"} & ($IkiWiki::DEPEND_PRESENCE | $IkiWiki::DEPEND_LINKS)));
+
+# Influences are added for dependencies involving links.
+$pagesources{"foo"}="foo.mdwn";
+$links{foo}=[qw{bar}];
+$pagesources{"bar"}="bar.mdwn";
+$links{bar}=[qw{}];
+ok(add_depends("foo", "link(bar) and backlink(meep)"));
+ok($IkiWiki::depends_simple{foo}{foo} == $IkiWiki::DEPEND_LINKS);
diff --git a/t/basewiki_brokenlinks.t b/t/basewiki_brokenlinks.t
index d74f64e36..74ddc61c5 100755
--- a/t/basewiki_brokenlinks.t
+++ b/t/basewiki_brokenlinks.t
@@ -8,7 +8,7 @@ ok(! system("make -s ikiwiki.out"));
ok(! system("make underlay_install DESTDIR=`pwd`/t/tmp/install PREFIX=/usr >/dev/null"));
foreach my $plugin ("", "listdirectives") {
- ok(! system("perl -I. ./ikiwiki.out -rebuild -plugin brokenlinks ".
+ ok(! system("LC_ALL=C perl -I. ./ikiwiki.out -rebuild -plugin brokenlinks ".
# always enabled because pages link to it conditionally,
# which brokenlinks cannot handle properly
"-plugin smiley ".
diff --git a/t/bazaar.t b/t/bazaar.t
index 2ca44a65e..cd840fbe1 100755
--- a/t/bazaar.t
+++ b/t/bazaar.t
@@ -6,13 +6,16 @@ BEGIN {
$dir = "/tmp/ikiwiki-test-bzr.$$";
my $bzr=`which bzr`;
chomp $bzr;
- if (! -x $bzr || ! mkdir($dir)) {
+ if (! -x $bzr) {
eval q{
- use Test::More skip_all => "bzr not available or could not make test dir"
+ use Test::More skip_all => "bzr not available"
}
}
+ if (! mkdir($dir)) {
+ die $@;
+ }
}
-use Test::More tests => 16;
+use Test::More tests => 17;
BEGIN { use_ok("IkiWiki"); }
@@ -24,11 +27,19 @@ IkiWiki::checkconfig();
system "bzr init $config{srcdir}";
+use CGI::Session;
+my $session=CGI::Session->new;
+$session->param("name", "Joe User");
+
# Web commit
my $test1 = readfile("t/test1.mdwn");
writefile('test1.mdwn', $config{srcdir}, $test1);
IkiWiki::rcs_add("test1.mdwn");
-IkiWiki::rcs_commit("test1.mdwn", "Added the first page", "moo", "Joe User");
+IkiWiki::rcs_commit(
+ file => "test1.mdwn",
+ message => "Added the first page",
+ token => "moo",
+ session => $session);
my @changes;
@changes = IkiWiki::rcs_recentchanges(3);
@@ -60,10 +71,16 @@ is($changes[1]{pages}[0]{"page"}, "test1");
my $ctime = IkiWiki::rcs_getctime("test2.mdwn");
ok($ctime >= time() - 20);
+my $mtime = IkiWiki::rcs_getmtime("test2.mdwn");
+ok($mtime >= time() - 20);
+
writefile('test3.mdwn', $config{srcdir}, $test1);
IkiWiki::rcs_add("test3.mdwn");
IkiWiki::rcs_rename("test3.mdwn", "test4.mdwn");
-IkiWiki::rcs_commit_staged("Added the 4th page", "moo", "Joe User");
+IkiWiki::rcs_commit_staged(
+ message => "Added the 4th page",
+ session => $session,
+);
@changes = IkiWiki::rcs_recentchanges(4);
@@ -72,7 +89,10 @@ is($changes[0]{pages}[0]{"page"}, "test4");
ok(mkdir($config{srcdir}."/newdir"));
IkiWiki::rcs_rename("test4.mdwn", "newdir/test5.mdwn");
-IkiWiki::rcs_commit_staged("Added the 5th page", "moo", "Joe User");
+IkiWiki::rcs_commit_staged(
+ message => "Added the 5th page",
+ session => $session,
+);
@changes = IkiWiki::rcs_recentchanges(4);
@@ -80,6 +100,9 @@ is($#changes, 3);
is($changes[0]{pages}[0]{"page"}, "newdir/test5");
IkiWiki::rcs_remove("newdir/test5.mdwn");
-IkiWiki::rcs_commit_staged("Remove the 5th page", "moo", "Joe User");
+IkiWiki::rcs_commit_staged(
+ message => "Remove the 5th page",
+ session => $session,
+);
system "rm -rf $dir";
diff --git a/t/bestlink.t b/t/bestlink.t
index 033b80d74..0020a05e2 100755
--- a/t/bestlink.t
+++ b/t/bestlink.t
@@ -11,11 +11,11 @@ sub test ($$$) {
my @existing_pages=@{shift()};
%IkiWiki::pagecase=();
- %links=();
+ %pagesources=();
$IkiWiki::config{userdir}="foouserdir";
foreach my $page (@existing_pages) {
$IkiWiki::pagecase{lc $page}=$page;
- $links{$page}=[];
+ $pagesources{$page}="$page.mdwn";
}
return bestlink($page, $link);
diff --git a/t/calculate_changed_links.t b/t/calculate_changed_links.t
new file mode 100755
index 000000000..bf6e2af45
--- /dev/null
+++ b/t/calculate_changed_links.t
@@ -0,0 +1,58 @@
+#!/usr/bin/perl
+package IkiWiki;
+
+use warnings;
+use strict;
+use Test::More tests => 5;
+
+BEGIN { use_ok("IkiWiki"); }
+BEGIN { use_ok("IkiWiki::Render"); }
+%config=IkiWiki::defaultconfig();
+$config{srcdir}=$config{destdir}="/dev/null";
+
+%oldrenderedfiles=%pagectime=();
+%pagesources=%pagemtime=%oldlinks=%links=%depends=%typedlinks=%oldtypedlinks=
+%destsources=%renderedfiles=%pagecase=%pagestate=();
+
+IkiWiki::checkconfig();
+
+foreach my $page (qw(tags/a tags/b Reorder Add Remove TypeAdd TypeRemove)) {
+ $pagesources{$page} = "$page.mdwn";
+ $pagemtime{$page} = $pagectime{$page} = 1000000;
+}
+
+$oldlinks{Reorder} = [qw{tags/a tags/b}];
+$links{Reorder} = [qw{tags/b tags/a}];
+
+$oldlinks{Add} = [qw{tags/b}];
+$links{Add} = [qw{tags/a tags/b}];
+
+$oldlinks{Remove} = [qw{tags/a}];
+$links{Remove} = [];
+
+$oldlinks{TypeAdd} = [qw{tags/a tags/b}];
+$links{TypeAdd} = [qw{tags/a tags/b}];
+# This causes TypeAdd to be rebuilt, but isn't a backlink change, so it doesn't
+# cause tags/b to be rebuilt.
+$oldtypedlinks{TypeAdd}{tag} = { "tags/a" => 1 };
+$typedlinks{TypeAdd}{tag} = { "tags/a" => 1, "tags/b" => 1 };
+
+$oldlinks{TypeRemove} = [qw{tags/a tags/b}];
+$links{TypeRemove} = [qw{tags/a tags/b}];
+# This causes TypeRemove to be rebuilt, but isn't a backlink change, so it
+# doesn't cause tags/b to be rebuilt.
+$oldtypedlinks{TypeRemove}{tag} = { "tags/a" => 1 };
+$typedlinks{TypeRemove}{tag} = { "tags/a" => 1, "tags/b" => 1 };
+
+my $oldlink_targets = calculate_old_links([keys %pagesources], []);
+is_deeply($oldlink_targets, {
+ Reorder => { "tags/a" => "tags/a", "tags/b" => "tags/b" },
+ Add => { "tags/b" => "tags/b" },
+ Remove => { "tags/a" => "tags/a" },
+ TypeAdd => { "tags/a" => "tags/a", "tags/b" => "tags/b" },
+ TypeRemove => { "tags/a" => "tags/a", "tags/b" => "tags/b" },
+ });
+my ($backlinkchanged, $linkchangers) = calculate_changed_links([keys %pagesources], [], $oldlink_targets);
+
+is_deeply($backlinkchanged, { "tags/a" => 1 });
+is_deeply($linkchangers, { add => 1, remove => 1, typeadd => 1, typeremove => 1 });
diff --git a/t/conflicts.t b/t/conflicts.t
new file mode 100755
index 000000000..d7e04d3ae
--- /dev/null
+++ b/t/conflicts.t
@@ -0,0 +1,131 @@
+#!/usr/bin/perl
+# Tests for bugs relating to conflicting files in the srcdir
+use warnings;
+use strict;
+use Test::More tests => 106;
+
+# setup
+my $srcdir="t/tmp/src";
+my $destdir="t/tmp/dest";
+ok(! system("make -s ikiwiki.out"));
+
+# runs ikiwiki to build test site
+sub runiki {
+ my $testdesc=shift;
+ ok((! system("perl -I. ./ikiwiki.out -plugin txt -plugin rawhtml -underlaydir=underlays/basewiki -set underlaydirbase=underlays -templatedir=templates $srcdir $destdir @_")),
+ $testdesc);
+}
+sub refreshiki {
+ runiki(shift);
+}
+sub setupiki {
+ ok(! system("rm -rf $srcdir/.ikiwiki $destdir"));
+ runiki(shift, "--rebuild");
+}
+sub newsrcdir {
+ ok(! system("rm -rf $srcdir $destdir"));
+ ok(! system("mkdir -p $srcdir"));
+}
+
+# At one point, changing the extension of the source file of a page caused
+# ikiwiki to fail.
+newsrcdir();
+ok(! system("touch $srcdir/foo.mdwn"));
+setupiki("initial setup");
+ok(! system("mv $srcdir/foo.mdwn $srcdir/foo.txt"));
+refreshiki("changed extension of source file of page");
+ok(! system("mv $srcdir/foo.txt $srcdir/foo.mdwn"));
+refreshiki("changed extension of source file of page 2");
+
+# Conflicting page sources is sorta undefined behavior,
+# but should not crash ikiwiki.
+# Added when refreshing
+ok(! system("touch $srcdir/foo.txt"));
+refreshiki("conflicting page sources in refresh");
+# Present during setup
+newsrcdir();
+ok(! system("touch $srcdir/foo.mdwn"));
+ok(! system("touch $srcdir/foo.txt"));
+setupiki("conflicting page sources in setup");
+
+# Page and non-page file with same pagename.
+newsrcdir();
+ok(! system("touch $srcdir/foo.mdwn"));
+ok(! system("touch $srcdir/foo"));
+setupiki("conflicting page and non-page in setup");
+newsrcdir();
+ok(! system("touch $srcdir/foo.mdwn"));
+setupiki("initial setup");
+ok(! system("touch $srcdir/foo"));
+refreshiki("conflicting page added (non-page already existing) in refresh");
+newsrcdir();
+ok(! system("touch $srcdir/foo"));
+setupiki("initial setup");
+ok(! system("touch $srcdir/foo.mdwn"));
+refreshiki("conflicting non-page added (page already existing) in refresh");
+
+# Page that renders to a file that is also a subdirectory holding another
+# file.
+newsrcdir();
+ok(! system("touch $srcdir/foo.mdwn"));
+ok(! system("mkdir -p $srcdir/foo/index.html"));
+ok(! system("touch $srcdir/foo/index.html/bar.mdwn"));
+setupiki("conflicting page file and subdirectory");
+newsrcdir();
+ok(! system("touch $srcdir/foo.mdwn"));
+ok(! system("mkdir -p $srcdir/foo/index.html"));
+ok(! system("touch $srcdir/foo/index.html/bar"));
+setupiki("conflicting page file and subdirectory 2");
+
+# Changing a page file into a non-page could also cause ikiwiki to fail.
+newsrcdir();
+ok(! system("touch $srcdir/foo.mdwn"));
+setupiki("initial setup");
+ok(! system("mv $srcdir/foo.mdwn $srcdir/foo"));
+refreshiki("page file turned into non-page");
+
+# Changing a non-page file into a page could also cause ikiwiki to fail.
+newsrcdir();
+ok(! system("touch $srcdir/foo"));
+setupiki("initial setup");
+ok(! system("mv $srcdir/foo $srcdir/foo.mdwn"));
+refreshiki("non-page file turned into page");
+
+# What if a page renders to the same html file that a rawhtml file provides?
+# Added when refreshing
+newsrcdir();
+ok(! system("touch $srcdir/foo.mdwn"));
+setupiki("initial setup");
+ok(! system("mkdir -p $srcdir/foo"));
+ok(! system("touch $srcdir/foo/index.html"));
+refreshiki("rawhtml file rendered same as existing page in refresh");
+# Moved when refreshing
+newsrcdir();
+ok(! system("touch $srcdir/foo.mdwn"));
+setupiki("initial setup");
+ok(! system("mkdir -p $srcdir/foo"));
+ok(! system("mv $srcdir/foo.mdwn $srcdir/foo/index.html"));
+refreshiki("existing page moved to rawhtml file in refresh");
+# Inverse added when refreshing
+newsrcdir();
+ok(! system("mkdir -p $srcdir/foo"));
+ok(! system("touch $srcdir/foo/index.html"));
+setupiki("initial setup");
+ok(! system("touch $srcdir/foo.mdwn"));
+refreshiki("page rendered same as existing rawhtml file in refresh");
+# Inverse moved when refreshing
+newsrcdir();
+ok(! system("mkdir -p $srcdir/foo"));
+ok(! system("touch $srcdir/foo/index.html"));
+setupiki("initial setup");
+ok(! system("mv $srcdir/foo/index.html $srcdir/foo.mdwn"));
+refreshiki("rawhtml file moved to page in refresh");
+# Present during setup
+newsrcdir();
+ok(! system("touch $srcdir/foo.mdwn"));
+ok(! system("mkdir -p $srcdir/foo"));
+ok(! system("touch $srcdir/foo/index.html"));
+setupiki("rawhtml file rendered same as existing page in setup");
+
+# cleanup
+ok(! system("rm -rf t/tmp"));
diff --git a/t/cvs.t b/t/cvs.t
new file mode 100755
index 000000000..5ed377ed5
--- /dev/null
+++ b/t/cvs.t
@@ -0,0 +1,88 @@
+#!/usr/bin/perl
+use warnings;
+use strict;
+my $dir;
+BEGIN {
+ $dir="/tmp/ikiwiki-test-cvs.$$";
+ my $cvs=`which cvs`;
+ chomp $cvs;
+ my $cvsps=`which cvsps`;
+ chomp $cvsps;
+ if (! -x $cvs || ! -x $cvsps) {
+ eval q{
+ use Test::More skip_all => "cvs or cvsps not available"
+ }
+ }
+ if (! mkdir($dir)) {
+ die $@;
+ }
+ foreach my $module ('File::ReadBackwards', 'File::MimeInfo') {
+ eval qq{use $module};
+ if ($@) {
+ eval qq{
+ use Test::More skip_all => "$module not available"
+ }
+ }
+ }
+}
+use Test::More tests => 12;
+
+BEGIN { use_ok("IkiWiki"); }
+
+%config=IkiWiki::defaultconfig();
+$config{rcs} = "cvs";
+$config{srcdir} = "$dir/src";
+$config{cvsrepo} = "$dir/repo";
+$config{cvspath} = "ikiwiki";
+IkiWiki::loadplugins();
+IkiWiki::checkconfig();
+
+my $cvsrepo = "$dir/repo";
+
+system "cvs -d $cvsrepo init >/dev/null";
+system "mkdir $dir/ikiwiki >/dev/null";
+system "cd $dir/ikiwiki && cvs -d $cvsrepo import -m import ikiwiki VENDOR RELEASE >/dev/null";
+system "rm -rf $dir/ikiwiki >/dev/null";
+system "cvs -d $cvsrepo co -d $config{srcdir} ikiwiki >/dev/null";
+
+# Web commit
+my $test1 = readfile("t/test1.mdwn");
+writefile('test1.mdwn', $config{srcdir}, $test1);
+IkiWiki::rcs_add("test1.mdwn");
+IkiWiki::rcs_commit(
+ files => "test1.mdwn",
+ message => "Added the first page",
+ token => "moo"
+);
+
+my @changes;
+@changes = IkiWiki::rcs_recentchanges(3);
+
+is($#changes, 0);
+is($changes[0]{message}[0]{"line"}, "Added the first page");
+is($changes[0]{pages}[0]{"page"}, "test1");
+
+# Manual commit
+my $message = "Added the second page";
+
+my $test2 = readfile("t/test2.mdwn");
+writefile('test2.mdwn', $config{srcdir}, $test2);
+system "cd $config{srcdir} && cvs add test2.mdwn >/dev/null 2>&1";
+system "cd $config{srcdir} && cvs commit -m \"$message\" test2.mdwn >/dev/null";
+
+@changes = IkiWiki::rcs_recentchanges(3);
+is($#changes, 1);
+is($changes[0]{message}[0]{"line"}, $message);
+is($changes[0]{pages}[0]{"page"}, "test2");
+is($changes[1]{pages}[0]{"page"}, "test1");
+
+# extra slashes in the path shouldn't break things
+$config{cvspath} = "/ikiwiki//";
+IkiWiki::checkconfig();
+@changes = IkiWiki::rcs_recentchanges(3);
+is($#changes, 1);
+is($changes[0]{message}[0]{"line"}, $message);
+is($changes[0]{pages}[0]{"page"}, "test2");
+is($changes[1]{pages}[0]{"page"}, "test1");
+
+system "rm -rf $dir";
diff --git a/t/file_pruned.t b/t/file_pruned.t
index 7d46c4b7f..34f366610 100755
--- a/t/file_pruned.t
+++ b/t/file_pruned.t
@@ -1,38 +1,40 @@
#!/usr/bin/perl
use warnings;
use strict;
-use Test::More tests => 24;
+use Test::More tests => 27;
BEGIN { use_ok("IkiWiki"); }
%config=IkiWiki::defaultconfig();
-ok(IkiWiki::file_pruned("src/.ikiwiki/", "src"));
-ok(IkiWiki::file_pruned("src/.ikiwiki/index", "src"));
-ok(IkiWiki::file_pruned("src/.svn", "src"));
-ok(IkiWiki::file_pruned("src/subdir/.svn", "src"));
-ok(IkiWiki::file_pruned("src/subdir/.svn/foo", "src"));
-ok(IkiWiki::file_pruned("src/.git", "src"));
-ok(IkiWiki::file_pruned("src/subdir/.git", "src"));
-ok(IkiWiki::file_pruned("src/subdir/.git/foo", "src"));
-ok(! IkiWiki::file_pruned("src/svn/fo", "src"));
-ok(! IkiWiki::file_pruned("src/git", "src"));
-ok(! IkiWiki::file_pruned("src/index.mdwn", "src"));
-ok(! IkiWiki::file_pruned("src/index.", "src"));
+ok(IkiWiki::file_pruned(".htaccess"));
+ok(IkiWiki::file_pruned(".ikiwiki/"));
+ok(IkiWiki::file_pruned(".ikiwiki/index"));
+ok(IkiWiki::file_pruned("CVS/foo"));
+ok(IkiWiki::file_pruned("subdir/CVS/foo"));
+ok(IkiWiki::file_pruned(".svn"));
+ok(IkiWiki::file_pruned("subdir/.svn"));
+ok(IkiWiki::file_pruned("subdir/.svn/foo"));
+ok(IkiWiki::file_pruned(".git"));
+ok(IkiWiki::file_pruned("subdir/.git"));
+ok(IkiWiki::file_pruned("subdir/.git/foo"));
+ok(! IkiWiki::file_pruned("svn/fo"));
+ok(! IkiWiki::file_pruned("git"));
+ok(! IkiWiki::file_pruned("index.mdwn"));
+ok(! IkiWiki::file_pruned("index."));
+ok(IkiWiki::file_pruned("."));
+ok(IkiWiki::file_pruned("./"));
-# these are ok because while the filename starts with ".", the canonpathed
-# version does not
-ok(! IkiWiki::file_pruned("src/.", "src"));
-ok(! IkiWiki::file_pruned("src/./", "src"));
+# absolute filenames are not allowed.
+ok(IkiWiki::file_pruned("/etc/passwd"));
+ok(IkiWiki::file_pruned("//etc/passwd"));
+ok(IkiWiki::file_pruned("/"));
+ok(IkiWiki::file_pruned("//"));
+ok(IkiWiki::file_pruned("///"));
-ok(IkiWiki::file_pruned("src/..", "src"));
-ok(IkiWiki::file_pruned("src/../", "src"));
-ok(IkiWiki::file_pruned("src/../", "src"));
-ok(! IkiWiki::file_pruned("src", "src"));
-ok(! IkiWiki::file_pruned("/.foo/src", "/.foo/src"));
-ok(IkiWiki::file_pruned("/.foo/src/.foo/src", "/.foo/src"));
-ok(! IkiWiki::file_pruned("/.foo/src/index.mdwn", "/.foo/src/index.mdwn"));
+ok(IkiWiki::file_pruned(".."));
+ok(IkiWiki::file_pruned("../"));
-ok(IkiWiki::file_pruned("x/y/foo.dpkg-tmp", "src"));
-ok(IkiWiki::file_pruned("x/y/foo.ikiwiki-new", "src"));
+ok(IkiWiki::file_pruned("y/foo.dpkg-tmp"));
+ok(IkiWiki::file_pruned("y/foo.ikiwiki-new"));
diff --git a/t/find_src_files.t b/t/find_src_files.t
new file mode 100755
index 000000000..a3742db75
--- /dev/null
+++ b/t/find_src_files.t
@@ -0,0 +1,97 @@
+#!/usr/bin/perl
+use warnings;
+use strict;
+use Test::More tests => 20;
+
+BEGIN { use_ok("IkiWiki"); }
+BEGIN { use_ok("IkiWiki::Render"); }
+
+%config=IkiWiki::defaultconfig();
+$config{srcdir}="t/tmp/srcdir";
+$config{underlaydir}="t/tmp/underlaydir";
+IkiWiki::checkconfig();
+
+sub cleanup {
+ ok(! system("rm -rf t/tmp"));
+}
+
+sub setup_underlay {
+ foreach my $file (@_) {
+ writefile($file, $config{underlaydir}, "test content");
+ }
+ return @_;
+}
+
+sub setup_srcdir {
+ foreach my $file (@_) {
+ writefile($file, $config{srcdir}, "test content");
+ }
+ return @_;
+}
+
+sub test_src_files {
+ my %expected=map { $_ => 1 } @{shift()}; # the input list may have dups
+ my $desc=shift;
+
+ close STDERR; # find_src_files prints warnings about bad files
+
+ my ($files, $pages)=IkiWiki::find_src_files();
+ is_deeply([sort @$files], [sort keys %expected], $desc);
+}
+
+cleanup();
+
+my @list=setup_underlay(qw{index.mdwn sandbox.mdwn smiley.png ikiwiki.mdwn ikiwiki/directive.mdwn ikiwiki/directive/foo.mdwn});
+push @list, setup_srcdir(qw{index.mdwn foo.mwdn icon.jpeg blog/archive/1/2/3/foo.mdwn blog/archive/1/2/4/bar.mdwn blog/archive.mdwn});
+test_src_files(\@list, "simple test");
+
+setup_srcdir(".badfile");
+test_src_files(\@list, "srcdir dotfile is skipped");
+
+setup_underlay(".badfile");
+test_src_files(\@list, "underlay dotfile is skipped");
+
+setup_srcdir(".ikiwiki/index");
+test_src_files(\@list, "srcdir dotdir is skipped");
+
+setup_underlay(".ikiwiki/index");
+test_src_files(\@list, "underlay dotdir is skipped");
+
+setup_srcdir("foo>.mdwn");
+test_src_files(\@list, "illegal srcdir filename skipped");
+
+setup_underlay("foo>.mdwn");
+test_src_files(\@list, "illegal underlay filename skipped");
+
+system("mkdir -p $config{srcdir}/empty");
+test_src_files(\@list, "empty srcdir directory ignored");
+
+system("mkdir -p $config{underlaydir}/empty");
+test_src_files(\@list, "empty underlay directory ignored");
+
+setup_underlay("bad.mdwn");
+system("ln -sf /etc/passwd $config{srcdir}/bad.mdwn");
+test_src_files(\@list, "underlaydir override attack foiled");
+
+system("ln -sf /etc/passwd $config{srcdir}/symlink.mdwn");
+test_src_files(\@list, "file symlink in srcdir skipped");
+
+system("ln -sf /etc/passwd $config{underlaydir}/symlink.mdwn");
+test_src_files(\@list, "file symlink in underlaydir skipped");
+
+system("ln -sf /etc/ $config{srcdir}/symdir");
+test_src_files(\@list, "dir symlink in srcdir skipped");
+
+system("ln -sf /etc/ $config{underlaydir}/symdir");
+test_src_files(\@list, "dir symlink in underlaydir skipped");
+
+system("ln -sf /etc/ $config{srcdir}/blog/symdir");
+test_src_files(\@list, "deep dir symlink in srcdir skipped");
+
+system("ln -sf /etc/ $config{underlaydir}/ikiwiki/symdir");
+test_src_files(\@list, "deep dir symlink in underlaydir skipped");
+
+
+
+
+cleanup();
diff --git a/t/git.t b/t/git.t
index f1c24b359..6d847dfb0 100755
--- a/t/git.t
+++ b/t/git.t
@@ -7,11 +7,14 @@ BEGIN {
$dir="/tmp/ikiwiki-test-git.$$";
my $git=`which git`;
chomp $git;
- if (! -x $git || ! mkdir($dir)) {
+ if (! -x $git) {
eval q{
- use Test::More skip_all => "git not available or could not make test dir"
+ use Test::More skip_all => "git not available"
}
}
+ if (! mkdir($dir)) {
+ die $@;
+ }
}
use Test::More tests => 18;
@@ -38,7 +41,11 @@ is($changes[0]{pages}[0]{"page"}, ".gitignore");
my $test1 = readfile("t/test1.mdwn");
writefile('test1.mdwn', $config{srcdir}, $test1);
IkiWiki::rcs_add("test1.mdwn");
-IkiWiki::rcs_commit("test1.mdwn", "Added the first page", "moo");
+IkiWiki::rcs_commit(
+ file => "test1.mdwn",
+ message => "Added the first page",
+ token => "moo",
+);
@changes = IkiWiki::rcs_recentchanges(3);
@@ -68,7 +75,7 @@ is($changes[1]{pages}[0]{"page"}, "test1");
writefile('test3.mdwn', $config{srcdir}, $test1);
IkiWiki::rcs_add("test3.mdwn");
IkiWiki::rcs_rename("test3.mdwn", "test4.mdwn");
-IkiWiki::rcs_commit_staged("Added the 4th page", "moo", "Joe User");
+IkiWiki::rcs_commit_staged(message => "Added the 4th page");
@changes = IkiWiki::rcs_recentchanges(4);
@@ -77,7 +84,7 @@ is($changes[0]{pages}[0]{"page"}, "test4");
ok(mkdir($config{srcdir}."/newdir"));
IkiWiki::rcs_rename("test4.mdwn", "newdir/test5.mdwn");
-IkiWiki::rcs_commit_staged("Added the 5th page", "moo", "Joe User");
+IkiWiki::rcs_commit_staged(message => "Added the 5th page");
@changes = IkiWiki::rcs_recentchanges(4);
@@ -85,6 +92,6 @@ is($#changes, 3);
is($changes[0]{pages}[0]{"page"}, "newdir/test5");
IkiWiki::rcs_remove("newdir/test5.mdwn");
-IkiWiki::rcs_commit_staged("Remove the 5th page", "moo", "Joe User");
+IkiWiki::rcs_commit_staged(message => "Remove the 5th page");
system "rm -rf $dir";
diff --git a/t/htmlize.t b/t/htmlize.t
index a7e7f8c39..a436748f9 100755
--- a/t/htmlize.t
+++ b/t/htmlize.t
@@ -1,7 +1,7 @@
#!/usr/bin/perl
use warnings;
use strict;
-use Test::More tests => 26;
+use Test::More tests => 32;
use Encode;
BEGIN { use_ok("IkiWiki"); }
@@ -68,3 +68,21 @@ is(IkiWiki::htmlize("foo", "foo", "mdwn",
is(IkiWiki::htmlize("foo", "foo", "mdwn",
q{<span class="foo">bar</span>}),
q{<span class="foo">bar</span>}, "class attribute allowed");
+is(IkiWiki::htmlize("foo", "foo", "mdwn",
+ q{<a href="aaa#foo">}),
+ q{<a href="aaa#foo">}, "simple anchor allowed");
+is(IkiWiki::htmlize("foo", "foo", "mdwn",
+ q{<a href="aaa#foo:bar">}),
+ q{<a href="aaa#foo:bar">}, "colon allowed in anchor");
+is(IkiWiki::htmlize("foo", "foo", "mdwn",
+ q{<a href="aaa?foo:bar">}),
+ q{<a href="aaa?foo:bar">}, "colon allowed in query string");
+is(IkiWiki::htmlize("foo", "foo", "mdwn",
+ q{<a href="foo:bar">}),
+ q{<a>}, "unknown protocol blocked");
+is(IkiWiki::htmlize("foo", "foo", "mdwn",
+ q{<a href="#foo">}),
+ q{<a href="#foo">}, "simple relative anchor allowed");
+is(IkiWiki::htmlize("foo", "foo", "mdwn",
+ q{<a href="#foo:bar">}),
+ q{<a href="#foo:bar">}, "colon in simple relative anchor allowed");
diff --git a/t/index.t b/t/index.t
index e79609902..392a167e9 100755
--- a/t/index.t
+++ b/t/index.t
@@ -4,7 +4,7 @@ use strict;
use IkiWiki;
package IkiWiki; # use internal variables
-use Test::More tests => 27;
+use Test::More tests => 31;
$config{wikistatedir}="/tmp/ikiwiki-test.$$";
system "rm -rf $config{wikistatedir}";
@@ -31,10 +31,11 @@ $renderedfiles{"bar"}=["bar.html", "bar.rss", "sparkline-foo.gif"];
$renderedfiles{"bar.png"}=["bar.png"];
$links{"Foo"}=["bar.png"];
$links{"bar"}=["Foo", "new-page"];
+$typedlinks{"bar"}={tag => {"Foo" => 1}};
$links{"bar.png"}=[];
-$depends{"Foo"}="";
-$depends{"bar"}="foo*";
-$depends{"bar.png"}="";
+$depends{"Foo"}={};
+$depends{"bar"}={"foo*" => 1};
+$depends{"bar.png"}={};
$pagestate{"bar"}{meta}{title}="a page about bar";
$pagestate{"bar"}{meta}{moo}="mooooo";
# only loaded plugins save state, so this should not be saved out
@@ -45,7 +46,7 @@ ok(-s "$config{wikistatedir}/indexdb", "index file created");
# Clear state.
%oldrenderedfiles=%pagectime=();
-%pagesources=%pagemtime=%oldlinks=%links=%depends=
+%pagesources=%pagemtime=%oldlinks=%links=%depends=%typedlinks=%oldtypedlinks=
%destsources=%renderedfiles=%pagecase=%pagestate=();
ok(loadindex(), "load index");
@@ -80,9 +81,9 @@ is_deeply(\%links, {
"bar.png" => [],
}, "%links loaded correctly");
is_deeply(\%depends, {
- Foo => "",
- bar => "foo*",
- "bar.png" => "",
+ Foo => {},
+ bar => {"foo*" => 1},
+ "bar.png" => {},
}, "%depends loaded correctly");
is_deeply(\%pagestate, {
bar => {
@@ -104,17 +105,26 @@ is_deeply(\%destsources, {
"sparkline-foo.gif" => "bar",
"bar.png" => "bar.png",
}, "%destsources generated correctly");
+is_deeply(\%typedlinks, {
+ bar => {tag => {"Foo" => 1}},
+}, "%typedlinks loaded correctly");
+is_deeply(\%oldtypedlinks, {
+ bar => {tag => {"Foo" => 1}},
+}, "%oldtypedlinks loaded correctly");
# Clear state.
%oldrenderedfiles=%pagectime=();
-%pagesources=%pagemtime=%oldlinks=%links=%depends=
+%pagesources=%pagemtime=%oldlinks=%links=%depends=%typedlinks=%oldtypedlinks=
%destsources=%renderedfiles=%pagecase=%pagestate=();
-# When state is loaded for a wiki rebuild, only ctime and oldrenderedfiles
-# are retained.
+# When state is loaded for a wiki rebuild, only ctime, oldrenderedfiles,
+# and pagesources are retained.
$config{rebuild}=1;
ok(loadindex(), "load index");
is_deeply(\%pagesources, {
+ Foo => "Foo.mdwn",
+ bar => "bar.mdwn",
+ "bar.png" => "bar.png",
}, "%pagesources loaded correctly");
is_deeply(\%pagemtime, {
}, "%pagemtime loaded correctly");
@@ -136,9 +146,16 @@ is_deeply(\%depends, {
}, "%depends loaded correctly");
is_deeply(\%pagestate, {
}, "%pagestate loaded correctly");
-is_deeply(\%pagecase, {
+is_deeply(\%pagecase, { # generated implicitly since pagesources is loaded
+ foo => "Foo",
+ bar => "bar",
+ "bar.png" => "bar.png"
}, "%pagecase generated correctly");
is_deeply(\%destsources, {
}, "%destsources generated correctly");
+is_deeply(\%typedlinks, {
+}, "%typedlinks cleared correctly");
+is_deeply(\%oldtypedlinks, {
+}, "%oldtypedlinks cleared correctly");
system "rm -rf $config{wikistatedir}";
diff --git a/t/mercurial.t b/t/mercurial.t
index 954b17526..4918fc76e 100755
--- a/t/mercurial.t
+++ b/t/mercurial.t
@@ -6,11 +6,14 @@ BEGIN {
$dir = "/tmp/ikiwiki-test-hg.$$";
my $hg=`which hg`;
chomp $hg;
- if (! -x $hg || ! mkdir($dir)) {
+ if (! -x $hg) {
eval q{
- use Test::More skip_all => "hg not available or could not make test dir"
+ use Test::More skip_all => "hg not available"
}
}
+ if (! mkdir($dir)) {
+ die $@;
+ }
}
use Test::More tests => 11;
@@ -22,13 +25,22 @@ $config{srcdir} = "$dir/repo";
IkiWiki::loadplugins();
IkiWiki::checkconfig();
+use CGI::Session;
+my $session=CGI::Session->new;
+$session->param("name", "Joe User");
+
system "hg init $config{srcdir}";
# Web commit
my $test1 = readfile("t/test1.mdwn");
writefile('test1.mdwn', $config{srcdir}, $test1);
IkiWiki::rcs_add("test1.mdwn");
-IkiWiki::rcs_commit("test1.mdwn", "Added the first page", "moo", "Joe User");
+IkiWiki::rcs_commit(
+ file => "test1.mdwn",
+ message => "Added the first page",
+ token => "moo",
+ session => $session,
+);
my @changes;
@changes = IkiWiki::rcs_recentchanges(3);
diff --git a/t/openiduser.t b/t/openiduser.t
index 52d879484..746090103 100755
--- a/t/openiduser.t
+++ b/t/openiduser.t
@@ -10,9 +10,9 @@ BEGIN {
eval q{use Test::More skip_all => "Net::OpenID::VerifiedIdentity not available"};
}
else {
- eval q{use Test::More tests => 9};
+ eval q{use Test::More tests => 11};
}
- use_ok("IkiWiki::Plugin::openid");
+ use_ok("IkiWiki");
}
# Some typical examples:
@@ -28,6 +28,11 @@ $^W=1;
is(IkiWiki::openiduser('http://yam655.livejournal.com/'), 'yam655 [livejournal.com]');
is(IkiWiki::openiduser('http://id.mayfirst.org/jamie/'), 'jamie [id.mayfirst.org]');
+# yahoo has an anchor in the url
+is(IkiWiki::openiduser('https://me.yahoo.com/joeyhess#35f22'), 'joeyhess [me.yahoo.com]');
+# google urls are horrendous, but the worst bit is after a ?, so can be dropped
+is(IkiWiki::openiduser('https://www.google.com/accounts/o8/id?id=AItOawm-ebiIfxbKD3KNa-Cu9LvvD9edMLW7BAo'), 'id [www.google.com/accounts/o8]');
+
# and some less typical ones taken from the ikiwiki commit history
is(IkiWiki::openiduser('http://thm.id.fedoraproject.org/'), 'thm [id.fedoraproject.org]');
diff --git a/t/pagespec_match.t b/t/pagespec_match.t
index 64408f489..97bcc969c 100755
--- a/t/pagespec_match.t
+++ b/t/pagespec_match.t
@@ -1,7 +1,7 @@
#!/usr/bin/perl
use warnings;
use strict;
-use Test::More tests => 54;
+use Test::More tests => 85;
BEGIN { use_ok("IkiWiki"); }
@@ -40,19 +40,47 @@ ok(! pagespec_match("foo", "foo and bar"), "foo and bar");
ok(pagespec_match("{f}oo", "{*}*"), "curly match");
ok(! pagespec_match("foo", "{*}*"), "curly !match");
+ok(pagespec_match("somepage", "user(frodo)", user => "frodo"));
+ok(pagespec_match("somepage", "user(frodo)", user => "Frodo"));
+ok(! pagespec_match("somepage", "user(frodo)", user => "Sam"));
+ok(pagespec_match("somepage", "user(*o)", user => "Bilbo"));
+ok(pagespec_match("somepage", "user(*o)", user => "frodo"));
+ok(! pagespec_match("somepage", "user(*o)", user => "Sam"));
+ok(pagespec_match("somepage", "user(http://*.myopenid.com/)", user => "http://foo.myopenid.com/"));
+ok(pagespec_match("somepage", "user(*://*)", user => "http://foo.myopenid.com/"));
+
# The link and backlink stuff needs this.
$config{userdir}="";
$links{foo}=[qw{bar baz}];
$links{bar}=[];
$links{baz}=[];
+$links{meh}=[];
$links{"bugs/foo"}=[qw{bugs/done}];
$links{"bugs/done"}=[];
$links{"bugs/bar"}=[qw{done}];
$links{"done"}=[];
+$links{"done"}=[];
$links{"examples/softwaresite/bugs/fails_to_frobnicate"}=[qw{done}];
$links{"examples/softwaresite/bugs/done"}=[];
$links{"ook"}=[qw{/blog/tags/foo}];
+foreach my $p (keys %links) {
+ $pagesources{$p}="$p.mdwn";
+}
+$pagesources{"foo.png"}="foo.png";
+$pagesources{"foo"}="foo.mdwn";
+$IkiWiki::hooks{htmlize}{mdwn}={};
+ok(pagespec_match("foo", "foo"), "simple");
+ok(! pagespec_match("foo", "bar"), "simple fail");
+ok(pagespec_match("foo", "foo"), "simple glob");
+ok(pagespec_match("foo", "f*"), "simple glob fail");
+ok(pagespec_match("foo", "page(foo)"), "page()");
+print pagespec_match("foo", "page(foo)")."\n";
+ok(! pagespec_match("foo", "page(bar)"), "page() fail");
+ok(! pagespec_match("foo.png", "page(foo.png)"), "page() fails on non-page");
+ok(! pagespec_match("foo.png", "page(foo*)"), "page() fails on non-page glob");
+ok(pagespec_match("foo", "page(foo)"), "page() glob");
+ok(pagespec_match("foo", "page(f*)"), "page() glob fail");
ok(pagespec_match("foo", "link(bar)"), "link");
ok(pagespec_match("foo", "link(ba?)"), "glob link");
ok(! pagespec_match("foo", "link(quux)"), "failed link");
@@ -69,6 +97,7 @@ ok(! pagespec_match("bar", ""), "empty pagespec should match nothing");
ok(! pagespec_match("bar", " "), "blank pagespec should match nothing");
ok(pagespec_match("ook", "link(blog/tags/foo)"), "link internal absolute success");
ok(pagespec_match("ook", "link(/blog/tags/foo)"), "link explicit absolute success");
+ok(pagespec_match("meh", "!link(done)"), "negated failing match is a success");
$IkiWiki::pagectime{foo}=1154532692; # Wed Aug 2 11:26 EDT 2006
$IkiWiki::pagectime{bar}=1154532695; # after
@@ -88,3 +117,28 @@ ok(! pagespec_match("foo", "no_such_function(foo)"), "foo");
my $ret=pagespec_match("foo", "(invalid");
ok(! $ret, "syntax error");
ok($ret =~ /syntax error/, "error message");
+
+$ret=pagespec_match("foo", "bar or foo");
+ok($ret, "simple match");
+is($ret, "foo matches foo", "stringified return");
+
+my $i=pagespec_match("foo", "link(bar)")->influences;
+is(join(",", keys %$i), 'foo', "link is influenced by the page with the link");
+$i=pagespec_match("bar", "backlink(foo)")->influences;
+is(join(",", keys %$i), 'foo', "backlink is influenced by the page with the link");
+$i=pagespec_match("bar", "backlink(foo)")->influences;
+is(join(",", keys %$i), 'foo', "backlink is influenced by the page with the link");
+$i=pagespec_match("bar", "created_before(foo)")->influences;
+is(join(",", keys %$i), 'foo', "created_before is influenced by the comparison page");
+$i=pagespec_match("bar", "created_after(foo)")->influences;
+is(join(",", keys %$i), 'foo', "created_after is influenced by the comparison page");
+$i=pagespec_match("foo", "link(baz) and created_after(bar)")->influences;
+is(join(",", sort keys %$i), 'bar,foo', "influences add up over AND");
+$i=pagespec_match("foo", "link(baz) and created_after(bar)")->influences;
+is(join(",", sort keys %$i), 'bar,foo', "influences add up over OR");
+$i=pagespec_match("foo", "!link(baz) and !created_after(bar)")->influences;
+is(join(",", sort keys %$i), 'bar,foo', "influences unaffected by negation");
+$i=pagespec_match("foo", "!link(baz) and !created_after(bar)")->influences;
+is(join(",", sort keys %$i), 'bar,foo', "influences unaffected by negation");
+$i=pagespec_match("meh", "!link(done)")->influences;
+is(join(",", sort keys %$i), 'meh', "a negated, failing link test is successful, so the page is a link influence");
diff --git a/t/pagespec_match_list.t b/t/pagespec_match_list.t
new file mode 100755
index 000000000..244ad9159
--- /dev/null
+++ b/t/pagespec_match_list.t
@@ -0,0 +1,174 @@
+#!/usr/bin/perl
+use warnings;
+use strict;
+use Test::More tests => 126;
+
+BEGIN { use_ok("IkiWiki"); }
+
+%config=IkiWiki::defaultconfig();
+$config{srcdir}=$config{destdir}="/dev/null";
+IkiWiki::checkconfig();
+
+{
+ package IkiWiki::SortSpec;
+
+ sub cmp_path { $a cmp $b }
+}
+
+%pagesources=(
+ foo => "foo.mdwn",
+ foo2 => "foo2.mdwn",
+ foo3 => "foo3.mdwn",
+ bar => "bar.mdwn",
+ "post/1" => "post/1.mdwn",
+ "post/2" => "post/2.mdwn",
+ "post/3" => "post/3.mdwn",
+);
+$IkiWiki::pagectime{foo} = 2;
+$IkiWiki::pagectime{foo2} = 2;
+$IkiWiki::pagectime{foo3} = 1;
+$IkiWiki::pagectime{foo4} = 1;
+$IkiWiki::pagectime{foo5} = 1;
+$IkiWiki::pagectime{bar} = 3;
+$IkiWiki::pagectime{"post/1"} = 6;
+$IkiWiki::pagectime{"post/2"} = 6;
+$IkiWiki::pagectime{"post/3"} = 6;
+$links{foo}=[qw{post/1 post/2}];
+$links{foo2}=[qw{bar}];
+$links{foo3}=[qw{bar}];
+
+is_deeply([pagespec_match_list("foo", "bar")], ["bar"]);
+is_deeply([sort(pagespec_match_list("foo", "* and !post/*"))], ["bar", "foo", "foo2", "foo3"]);
+is_deeply([sort(pagespec_match_list("foo", "post/*"))], ["post/1", "post/2", "post/3"]);
+is_deeply([pagespec_match_list("foo", "post/*", sort => "title")],
+ ["post/1", "post/2", "post/3"]);
+is_deeply([pagespec_match_list("foo", "post/*", sort => "title", reverse => 1)],
+ ["post/3", "post/2", "post/1"]);
+is_deeply([pagespec_match_list("foo", "post/*", sort => "title", num => 2)],
+ ["post/1", "post/2"]);
+is_deeply([pagespec_match_list("foo", "post/*", sort => "title", num => 50)],
+ ["post/1", "post/2", "post/3"]);
+is_deeply([pagespec_match_list("foo", "post/*", sort => "title", num => 50, reverse => 1)],
+ ["post/3", "post/2", "post/1"]);
+is_deeply([pagespec_match_list("foo", "post/*", sort => "title",
+ filter => sub { $_[0] =~ /3/}) ],
+ ["post/1", "post/2"]);
+is_deeply([pagespec_match_list("foo", "*", sort => "path", num => 2)],
+ ["bar", "foo"]);
+is_deeply([pagespec_match_list("foo", "foo* or bar*",
+ sort => "-age title")], # oldest first, break ties by title
+ ["foo3", "foo", "foo2", "bar"]);
+my $r=eval { pagespec_match_list("foo", "beep") };
+ok(eval { pagespec_match_list("foo", "beep") } == 0);
+ok(! $@, "does not fail with error when unable to match anything");
+eval { pagespec_match_list("foo", "this is not a legal pagespec!") };
+ok($@, "fails with error when pagespec bad");
+
+# A pagespec that requires page metadata should add influences
+# as an explicit dependency. In the case of a link, a links dependency.
+foreach my $spec ("* and link(bar)", "* or link(bar)") {
+ pagespec_match_list("foo2", $spec, deptype => deptype("presence"));
+ ok($IkiWiki::depends{foo2}{$spec} & $IkiWiki::DEPEND_PRESENCE);
+ ok(! ($IkiWiki::depends{foo2}{$spec} & ($IkiWiki::DEPEND_CONTENT | $IkiWiki::DEPEND_LINKS)));
+ ok($IkiWiki::depends_simple{foo2}{foo2} == $IkiWiki::DEPEND_LINKS);
+ %IkiWiki::depends_simple=();
+ %IkiWiki::depends=();
+ pagespec_match_list("foo3", $spec, deptype => deptype("links"));
+ ok($IkiWiki::depends{foo3}{$spec} & $IkiWiki::DEPEND_LINKS);
+ ok(! ($IkiWiki::depends{foo3}{$spec} & ($IkiWiki::DEPEND_CONTENT | $IkiWiki::DEPEND_PRESENCE)));
+ ok($IkiWiki::depends_simple{foo3}{foo3} == $IkiWiki::DEPEND_LINKS);
+ %IkiWiki::depends_simple=();
+ %IkiWiki::depends=();
+}
+
+# A link pagespec is influenced by the pages that currently contain the link.
+# It is not influced by pages that do not currently contain the link,
+# because if those pages were changed to contain it, regular dependency
+# handling would be triggered.
+foreach my $spec ("* and link(bar)", "link(bar)", "no_such_page or link(bar)") {
+ pagespec_match_list("foo2", $spec);
+ ok($IkiWiki::depends_simple{foo2}{foo2} == $IkiWiki::DEPEND_LINKS);
+ ok(! exists $IkiWiki::depends_simple{foo2}{foo}, $spec);
+ %IkiWiki::depends_simple=();
+ %IkiWiki::depends=();
+}
+
+# Oppositely, a pagespec that tests for pages that do not have a link
+# is not influenced by pages that currently contain the link, but
+# is instead influenced by pages that currently do not (but that
+# could be changed to have it).
+foreach my $spec ("* and !link(bar)", "* and !(!(!link(bar)))") {
+ pagespec_match_list("foo2", $spec);
+ ok(! exists $IkiWiki::depends_simple{foo2}{foo2});
+ ok($IkiWiki::depends_simple{foo2}{foo} == $IkiWiki::DEPEND_LINKS, $spec);
+ %IkiWiki::depends_simple=();
+ %IkiWiki::depends=();
+}
+
+# a pagespec with backlinks() will add as an influence the page with the links
+foreach my $spec ("bar or (backlink(foo) and !*.png)", "backlink(foo)", "!backlink(foo)") {
+ pagespec_match_list("foo2", $spec, deptype => deptype("presence"));
+ ok($IkiWiki::depends{foo2}{$spec} & $IkiWiki::DEPEND_PRESENCE);
+ ok(! ($IkiWiki::depends{foo2}{$spec} & ($IkiWiki::DEPEND_CONTENT | $IkiWiki::DEPEND_LINKS)));
+ ok($IkiWiki::depends_simple{foo2}{foo} == $IkiWiki::DEPEND_LINKS);
+ ok(! exists $IkiWiki::depends_simple{foo2}{foo2});
+ %IkiWiki::depends_simple=();
+ %IkiWiki::depends=();
+ pagespec_match_list("foo2", $spec, deptype => deptype("links"));
+ ok($IkiWiki::depends{foo2}{$spec} & $IkiWiki::DEPEND_LINKS);
+ ok(! ($IkiWiki::depends{foo2}{$spec} & ($IkiWiki::DEPEND_PRESENCE | $IkiWiki::DEPEND_CONTENT)));
+ ok($IkiWiki::depends_simple{foo2}{foo} == $IkiWiki::DEPEND_LINKS);
+ ok(! exists $IkiWiki::depends_simple{foo2}{foo2});
+ %IkiWiki::depends_simple=();
+ %IkiWiki::depends=();
+ pagespec_match_list("foo2", $spec, deptype => deptype("presence", "links"));
+ ok($IkiWiki::depends{foo2}{$spec} & $IkiWiki::DEPEND_PRESENCE);
+ ok($IkiWiki::depends{foo2}{$spec} & $IkiWiki::DEPEND_LINKS);
+ ok(! ($IkiWiki::depends{foo2}{$spec} & $IkiWiki::DEPEND_CONTENT));
+ ok($IkiWiki::depends_simple{foo2}{foo} == $IkiWiki::DEPEND_LINKS);
+ ok(! exists $IkiWiki::depends_simple{foo2}{foo2});
+ %IkiWiki::depends_simple=();
+ %IkiWiki::depends=();
+ pagespec_match_list("foo2", $spec);
+ ok($IkiWiki::depends{foo2}{$spec} & $IkiWiki::DEPEND_CONTENT);
+ ok(! ($IkiWiki::depends{foo2}{$spec} & ($IkiWiki::DEPEND_PRESENCE | $IkiWiki::DEPEND_LINKS)));
+ ok($IkiWiki::depends_simple{foo2}{foo} == $IkiWiki::DEPEND_LINKS);
+ %IkiWiki::depends_simple=();
+ %IkiWiki::depends=();
+}
+
+# Hard fails due to a glob, etc, will block influences of other anded terms.
+foreach my $spec ("nosuchpage and link(bar)", "link(bar) and nosuchpage",
+ "link(bar) and */Discussion", "*/Discussion and link(bar)",
+ "!foo2 and link(bar)", "link(bar) and !foo2") {
+ pagespec_match_list("foo2", $spec, deptype => deptype("presence"));
+ ok($IkiWiki::depends{foo2}{$spec} & $IkiWiki::DEPEND_PRESENCE);
+ ok(! ($IkiWiki::depends{foo2}{$spec} & ($IkiWiki::DEPEND_CONTENT | $IkiWiki::DEPEND_LINKS)));
+ ok(! exists $IkiWiki::depends_simple{foo2}{foo2}, "no influence from $spec");
+ %IkiWiki::depends_simple=();
+ %IkiWiki::depends=();
+}
+
+# A hard fail will not block influences of other ored terms.
+foreach my $spec ("nosuchpage or link(bar)", "link(bar) or nosuchpage",
+ "link(bar) or */Discussion", "*/Discussion or link(bar)",
+ "!foo2 or link(bar)", "link(bar) or !foo2",
+ "link(bar) or (!foo2 and !foo1)") {
+ pagespec_match_list("foo2", $spec, deptype => deptype("presence"));
+ ok($IkiWiki::depends{foo2}{$spec} & $IkiWiki::DEPEND_PRESENCE);
+ ok(! ($IkiWiki::depends{foo2}{$spec} & ($IkiWiki::DEPEND_CONTENT | $IkiWiki::DEPEND_LINKS)));
+ ok($IkiWiki::depends_simple{foo2}{foo2} == $IkiWiki::DEPEND_LINKS);
+ %IkiWiki::depends_simple=();
+ %IkiWiki::depends=();
+}
+
+my @ps;
+foreach my $p (100..500) {
+ $IkiWiki::pagectime{"p/$p"} = $p;
+ $pagesources{"p/$p"} = "p/$p.mdwn";
+ unshift @ps, "p/$p";
+}
+is_deeply([pagespec_match_list("foo", "p/*", sort => "age")],
+ [@ps]);
+is_deeply([pagespec_match_list("foo", "p/*", sort => "age", num => 20)],
+ [@ps[0..19]]);
diff --git a/t/pagespec_match_result.t b/t/pagespec_match_result.t
new file mode 100755
index 000000000..13fcdcad0
--- /dev/null
+++ b/t/pagespec_match_result.t
@@ -0,0 +1,84 @@
+#!/usr/bin/perl
+use warnings;
+use strict;
+use Test::More tests => 138;
+
+BEGIN { use_ok("IkiWiki"); }
+
+# Note that new objects have to be constructed freshly for each test, since
+# object states are mutated as they are combined.
+sub S { IkiWiki::SuccessReason->new("match", @_) }
+sub F { IkiWiki::FailReason->new("no match", @_) }
+sub E { IkiWiki::ErrorReason->new("error in matching", @_) }
+
+ok(S() eq "match");
+ok(F() eq "no match");
+ok(E() eq "error in matching");
+
+ok(S());
+ok(! F());
+ok(! E());
+
+ok(!(! S()));
+ok(!(!(! F)));
+ok(!(!(! E)));
+
+ok(S() | F());
+ok(F() | S());
+ok(!(F() | E()));
+ok(!(!S() | F() | E()));
+
+ok(S() & S() & S());
+ok(!(S() & E()));
+ok(!(S() & F()));
+ok(!(S() & F() & E()));
+ok(S() & (F() | F() | S()));
+
+# influence merging tests
+foreach my $test (
+ ['$s | $f' => 1], # OR merges
+ ['! $s | ! $f' => 1], # OR merges with negated terms too
+ ['!(!(!$s)) | $f' => 1],# OR merges with multiple negation too
+ ['$s | $f | E()' => 1], # OR merges, even though E() has no influences
+ ['$s | E() | $f' => 1], # ditto
+ ['E() | $s | $f' => 1], # ditto
+ ['!$s | !$f | E()' => 1],# negated terms also do not block merges
+ ['!$s | E() | $f' => 1],# ditto
+ ['E() | $s | !$f' => 1],# ditto
+ ['$s & $f' => 1], # AND merges if both items have influences
+ ['!$s & $f' => 1], # AND merges negated terms too
+ ['$s & !$f' => 1], # AND merges negated terms too
+ ['$s & $f & E()' => 0], # AND fails to merge since E() has no influences
+ ['$s & E() & $f' => 0], # ditto
+ ['E() & $s & $f' => 0], # ditto
+ ) {
+ my $op=$test->[0];
+ my $influence=$test->[1];
+
+ my $s=S(foo => 1, bar => 1);
+ is($s->influences->{foo}, 1);
+ is($s->influences->{bar}, 1);
+ my $f=F(bar => 2, baz => 1);
+ is($f->influences->{bar}, 2);
+ is($f->influences->{baz}, 1);
+ my $c = eval $op;
+ ok(ref $c);
+ if ($influence) {
+ is($c->influences->{foo}, 1, "foo ($op)");
+ is($c->influences->{bar}, (1 | 2), "bar ($op)");
+ is($c->influences->{baz}, 1, "baz ($op)");
+ }
+ else {
+ ok(! %{$c->influences}, "no influence for ($op)");
+ }
+}
+
+my $s=S(foo => 0, bar => 1);
+$s->influences(baz => 1);
+ok(! $s->influences->{foo}, "removed 0 influence");
+ok(! $s->influences->{bar}, "removed 1 influence");
+ok($s->influences->{baz}, "set influence");
+ok($s->influences_static);
+$s=S(foo => 0, bar => 1);
+$s->influences(baz => 1, "" => 1);
+ok(! $s->influences_static);
diff --git a/t/pagespec_merge.t b/t/pagespec_merge.t
deleted file mode 100755
index 9e38d5761..000000000
--- a/t/pagespec_merge.t
+++ /dev/null
@@ -1,44 +0,0 @@
-#!/usr/bin/perl
-use warnings;
-use strict;
-use Test::More tests => 25;
-
-BEGIN { use_ok("IkiWiki"); }
-
-sub same {
- my $a=shift;
- my $b=shift;
- my $match=shift;
-
- my $imatch=(pagespec_match($match, $a) ||
- pagespec_match($match, $b));
- my $cmatch=pagespec_match($match, IkiWiki::pagespec_merge($a, $b));
-
- return $imatch == $cmatch;
-}
-
-ok(same("foo", "bar", "foo"), "basic match 1");
-ok(same("foo", "bar", "bar"), "basic match 2");
-ok(same("foo", "bar", "foobar"), "basic failed match");
-ok(same("foo", "!bar", "foo"), "basic match with inversion");
-ok(same("foo", "!bar", "bar"), "basic failed match with inversion");
-ok(same("!foo", "bar", "foo"), "basic failed match with inversion 2");
-ok(same("!foo", "bar", "bar"), "basic match with inversion 2");
-ok(same("!foo", "!bar", "foo"), "double inversion failed match");
-ok(same("!foo", "!bar", "bar"), "double inversion failed match 2");
-ok(same("*", "!bar", "foo"), "glob+inversion match");
-ok(same("*", "!bar", "bar"), "matching glob and matching inversion");
-ok(same("* and !foo", "!bar", "bar"), "matching glob and matching inversion");
-ok(same("* and !foo", "!bar", "foo"), "matching glob with matching inversion and non-matching inversion");
-ok(same("* and !foo", "!foo", "foo"), "matching glob with matching inversion and matching inversion");
-ok(same("b??", "!b??", "bar"), "matching glob and matching inverted glob");
-ok(same("f?? !f??", "!bar", "bar"), "matching glob and matching inverted glob");
-ok(same("b??", "!b?z", "bar"), "matching glob and non-matching inverted glob");
-ok(same("f?? !f?z", "!bar", "bar"), "matching glob and non-matching inverted glob");
-ok(same("!foo bar baz", "!bar", "bar"), "matching list and matching inversion");
-ok(pagespec_match("foo/Discussion",
- IkiWiki::pagespec_merge("* and !*/Discussion", "*/Discussion")), "should match");
-ok(same("* and !*/Discussion", "*/Discussion", "foo/Discussion"), "Discussion merge 1");
-ok(same("*/Discussion", "* and !*/Discussion", "foo/Discussion"), "Discussion merge 2");
-ok(same("*/Discussion !*/bar", "*/bar !*/Discussion", "foo/Discussion"), "bidirectional merge 1");
-ok(same("*/Discussion !*/bar", "*/bar !*/Discussion", "foo/bar"), "bidirectional merge 2");
diff --git a/t/parentlinks.t b/t/parentlinks.t
index 593937a97..9b4654903 100755
--- a/t/parentlinks.t
+++ b/t/parentlinks.t
@@ -21,7 +21,6 @@ IkiWiki::checkconfig();
# Test data
$expected{'parentlinks'} =
{
- "" => [],
"ikiwiki" => [],
"ikiwiki/pagespec" =>
[ {depth => 0, height => 2, },
diff --git a/t/permalink.t b/t/permalink.t
index b49b98338..adb8648b4 100755
--- a/t/permalink.t
+++ b/t/permalink.t
@@ -5,7 +5,7 @@ use Test::More 'no_plan';
ok(! system("mkdir t/tmp"));
ok(! system("make -s ikiwiki.out"));
-ok(! system("perl -I. ./ikiwiki.out -plugin inline -url=http://example.com -cgiurl=http://example.com/ikiwiki.cgi -rss -atom -underlaydir=underlays/basewiki -templatedir=templates t/tinyblog t/tmp/out"));
+ok(! system("perl -I. ./ikiwiki.out -plugin inline -url=http://example.com -cgiurl=http://example.com/ikiwiki.cgi -rss -atom -underlaydir=underlays/basewiki -set underlaydirbase=underlays -templatedir=templates t/tinyblog t/tmp/out"));
# This guid should never, ever change, for any reason whatsoever!
my $guid="http://example.com/post/";
ok(length `grep '<guid>$guid</guid>' t/tmp/out/index.rss`);
diff --git a/t/po.t b/t/po.t
index b6885a37e..1cd18c317 100755
--- a/t/po.t
+++ b/t/po.t
@@ -17,7 +17,7 @@ BEGIN {
}
}
-use Test::More tests => 65;
+use Test::More tests => 68;
BEGIN { use_ok("IkiWiki"); }
@@ -31,6 +31,9 @@ my $dir = tempdir("ikiwiki-test-po.XXXXXXXXXX",
%config=IkiWiki::defaultconfig();
$config{srcdir} = "$dir/src";
$config{destdir} = "$dir/dst";
+$config{destdir} = "$dir/dst";
+$config{underlaydirbase} = "/dev/null";
+$config{underlaydir} = "/dev/null";
$config{discussion} = 0;
$config{po_master_language} = { code => 'en',
name => 'English'
@@ -42,8 +45,8 @@ $config{po_slave_languages} = {
$config{po_translatable_pages}='index or test1 or test2 or translatable';
$config{po_link_to}='negotiated';
IkiWiki::loadplugins();
-IkiWiki::checkconfig();
ok(IkiWiki::loadplugin('po'), "po plugin loaded");
+IkiWiki::checkconfig();
### seed %pagesources and %pagecase
$pagesources{'index'}='index.mdwn';
@@ -61,7 +64,7 @@ $pagesources{'translatable.fr'}='translatable.fr.po';
$pagesources{'translatable.es'}='translatable.es.po';
$pagesources{'nontranslatable'}='nontranslatable.mdwn';
foreach my $page (keys %pagesources) {
- $IkiWiki::pagecase{lc $page}=$page;
+ $IkiWiki::pagecase{lc $page}=$page;
}
### populate srcdir
@@ -91,6 +94,13 @@ ok(! IkiWiki::Plugin::po::istranslatable('test3'), "test3 is not translatable");
ok(! IkiWiki::Plugin::po::istranslation('test3'), "test3 is not a translation");
}
+### pofiles
+
+my @pofiles = IkiWiki::Plugin::po::pofiles(srcfile("index.mdwn"));
+ok( @pofiles, "pofiles is defined");
+ok( @pofiles == 2, "pofiles has correct size");
+is_deeply(\@pofiles, ["$config{srcdir}/index.es.po", "$config{srcdir}/index.fr.po"], "pofiles content is correct");
+
### links
require IkiWiki::Render;
@@ -122,8 +132,8 @@ $config{po_link_to}='current';
$msgprefix="links (po_link_to=current)";
refresh_n_scan('index.mdwn', 'translatable.mdwn', 'nontranslatable.mdwn');
is_deeply(\@{$links{'index'}}, ['translatable', 'nontranslatable'], "$msgprefix index");
-is_deeply(\@{$links{'index.es'}}, [ map bestlink('index.es', $_), ('translatable.es', 'nontranslatable')], "$msgprefix index.es");
-is_deeply(\@{$links{'index.fr'}}, [ map bestlink('index.fr', $_), ('translatable.fr', 'nontranslatable')], "$msgprefix index.fr");
+is_deeply(\@{$links{'index.es'}}, [ (map bestlink('index.es', $_), ('translatable.es', 'nontranslatable'))], "$msgprefix index.es");
+is_deeply(\@{$links{'index.fr'}}, [ (map bestlink('index.fr', $_), ('translatable.fr', 'nontranslatable'))], "$msgprefix index.fr");
is_deeply(\@{$links{'translatable'}}, [bestlink('translatable', 'nontranslatable')], "$msgprefix translatable");
is_deeply(\@{$links{'translatable.es'}}, ['nontranslatable'], "$msgprefix translatable.es");
is_deeply(\@{$links{'translatable.fr'}}, ['nontranslatable'], "$msgprefix translatable.fr");
diff --git a/t/preprocess.t b/t/preprocess.t
index e5026ed64..7bb9878d0 100755
--- a/t/preprocess.t
+++ b/t/preprocess.t
@@ -1,7 +1,7 @@
#!/usr/bin/perl
use warnings;
use strict;
-use Test::More tests => 21;
+use Test::More tests => 31;
BEGIN { use_ok("IkiWiki"); }
@@ -26,6 +26,16 @@ is(IkiWiki::preprocess("foo", "foo", "[[foo ]]", 0, 0), "foo()", "simple");
is(IkiWiki::preprocess("foo", "foo", "[[!foo ]]", 0, 0), "foo()", "prefixed");
is(IkiWiki::preprocess("foo", "foo", "[[!foo]]", 0, 0), "[[!foo]]", "prefixed, no space");
is(IkiWiki::preprocess("foo", "foo", "[[foo a=1]]", 0, 0), "foo(a => 1)");
+is(IkiWiki::preprocess("foo", "foo", q{[[foo a="1"]]}, 0, 0), "foo(a => 1)");
+is(IkiWiki::preprocess("foo", "foo", q{[[foo a="""1"""]]}, 0, 0), "foo(a => 1)");
+is(IkiWiki::preprocess("foo", "foo", q{[[foo a=""]]}, 0, 0), "foo(a)");
+is(IkiWiki::preprocess("foo", "foo", q{[[foo a="" b="1"]]}, 0, 0), "foo(a, b => 1)");
+is(IkiWiki::preprocess("foo", "foo", q{[[foo a=""""""]]}, 0, 0), "foo(a)");
+is(IkiWiki::preprocess("foo", "foo", q{[[foo a="""""" b="1"]]}, 0, 0), "foo(a, b => 1)");
+is(IkiWiki::preprocess("foo", "foo", q{[[foo a="""""" b="""1"""]]}, 0, 0), "foo(a, b => 1)");
+is(IkiWiki::preprocess("foo", "foo", q{[[foo a="""""" b=""""""]]}, 0, 0), "foo(a, b)");
+is(IkiWiki::preprocess("foo", "foo", q{[[foo a="" b=""""""]]}, 0, 0), "foo(a, b)");
+is(IkiWiki::preprocess("foo", "foo", q{[[foo a="" b="""1"""]]}, 0, 0), "foo(a, b => 1)");
is(IkiWiki::preprocess("foo", "foo", "[[foo a=\"1 2 3 4\"]]", 0, 0), "foo(a => 1 2 3 4)");
is(IkiWiki::preprocess("foo", "foo", "[[foo ]] then [[foo a=2]]", 0, 0),
"foo() then foo(a => 2)");
diff --git a/t/svn.t b/t/svn.t
index 5223b4409..cce8452a6 100755
--- a/t/svn.t
+++ b/t/svn.t
@@ -8,11 +8,14 @@ BEGIN {
chomp $svn;
my $svnadmin=`which svnadmin`;
chomp $svnadmin;
- if (! -x $svn || ! -x $svnadmin || ! mkdir($dir)) {
+ if (! -x $svn || ! -x $svnadmin) {
eval q{
- use Test::More skip_all => "svn not available or could not make test dir"
+ use Test::More skip_all => "svn or svnadmin not available"
}
}
+ if (! mkdir($dir)) {
+ die $@;
+ }
}
use Test::More tests => 12;
@@ -36,7 +39,11 @@ system "svn co file://$svnrepo/trunk $config{srcdir} >/dev/null";
my $test1 = readfile("t/test1.mdwn");
writefile('test1.mdwn', $config{srcdir}, $test1);
IkiWiki::rcs_add("test1.mdwn");
-IkiWiki::rcs_commit("test1.mdwn", "Added the first page", "moo");
+IkiWiki::rcs_commit(
+ file => "test1.mdwn",
+ message => "Added the first page",
+ token => "moo",
+);
my @changes;
@changes = IkiWiki::rcs_recentchanges(3);
diff --git a/t/tag.t b/t/tag.t
new file mode 100755
index 000000000..fe547d85b
--- /dev/null
+++ b/t/tag.t
@@ -0,0 +1,39 @@
+#!/usr/bin/perl
+package IkiWiki;
+
+use warnings;
+use strict;
+use Test::More tests => 7;
+
+BEGIN { use_ok("IkiWiki"); }
+BEGIN { use_ok("IkiWiki::Plugin::tag"); }
+
+ok(! system("rm -rf t/tmp; mkdir t/tmp"));
+
+$config{userdir} = "users";
+$config{tagbase} = "tags";
+
+%oldrenderedfiles=%pagectime=();
+%pagesources=%pagemtime=%oldlinks=%links=%depends=%typedlinks=%oldtypedlinks=
+%destsources=%renderedfiles=%pagecase=%pagestate=();
+
+foreach my $page (qw(tags/numbers tags/letters one two alpha beta)) {
+ $pagesources{$page} = "$page.mdwn";
+ $pagemtime{$page} = $pagectime{$page} = 1000000;
+}
+
+$links{one}=[qw(tags/numbers alpha tags/letters)];
+$links{two}=[qw(tags/numbers)];
+$links{alpha}=[qw(tags/letters one)];
+$links{beta}=[qw(tags/letters)];
+$typedlinks{one}={tag => {"tags/numbers" => 1 }};
+$typedlinks{two}={tag => {"tags/numbers" => 1 }};
+$typedlinks{alpha}={tag => {"tags/letters" => 1 }};
+$typedlinks{beta}={tag => {"tags/letters" => 1 }};
+
+ok(pagespec_match("one", "tagged(numbers)"));
+ok(!pagespec_match("two", "tagged(alpha)"));
+ok(pagespec_match("one", "link(tags/numbers)"));
+ok(pagespec_match("one", "link(alpha)"));
+
+1;
diff --git a/t/template_syntax.t b/t/template_syntax.t
new file mode 100755
index 000000000..1e156eed8
--- /dev/null
+++ b/t/template_syntax.t
@@ -0,0 +1,15 @@
+#!/usr/bin/perl
+use warnings;
+use strict;
+use Test::More;
+
+my @templates=glob("templates/*.tmpl"), glob("doc/templates/*.mdwn");
+plan(tests => 2*@templates);
+
+use HTML::Template;
+
+foreach my $template (@templates) {
+ my $obj=eval {HTML::Template->new(filename => $template)};
+ ok(! $@, $template." $@");
+ ok($obj, $template);
+}
diff --git a/t/templates_documented.t b/t/templates_documented.t
new file mode 100755
index 000000000..826c51d36
--- /dev/null
+++ b/t/templates_documented.t
@@ -0,0 +1,14 @@
+#!/usr/bin/perl
+use warnings;
+use strict;
+use Test::More 'no_plan';
+
+$/=undef;
+open(IN, "doc/templates.mdwn") || die "doc/templates.mdwn: $!";
+my $page=<IN>;
+close IN;
+
+foreach my $file (glob("templates/*.tmpl")) {
+ $file=~s/templates\///;
+ ok($page =~ /\Q$file\E/, "$file documented on doc/templates.mdwn");
+}
diff --git a/t/yesno.t b/t/yesno.t
index 60a8c071d..8770390a1 100755
--- a/t/yesno.t
+++ b/t/yesno.t
@@ -1,7 +1,7 @@
#!/usr/bin/perl
use warnings;
use strict;
-use Test::More tests => 10;
+use Test::More tests => 11;
BEGIN { use_ok("IkiWiki"); }
@@ -19,3 +19,5 @@ ok(IkiWiki::yesno("NO") == 0);
ok(IkiWiki::yesno("1") == 1);
ok(IkiWiki::yesno("0") == 0);
ok(IkiWiki::yesno("mooooooooooo") == 0);
+
+ok(IkiWiki::yesno(undef) == 0);