#!/usr/bin/perl # Copyright (C) 2004, 2005 Alex Schroeder # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the # Free Software Foundation, Inc. # 59 Temple Place, Suite 330 # Boston, MA 02111-1307 USA use XML::LibXML; use Encode; # Import the functions package OddMuse; $RunCGI = 0; # don't print HTML on stdout $UseConfig = 0; # don't read module files do 'wiki.pl'; Init(); my ($passed, $failed) = (0, 0); my $resultfile = "/tmp/test-markup-result-$$"; my $redirect; undef $/; $| = 1; # no output buffering sub url_encode { my $str = shift; return '' unless $str; my @letters = split(//, $str); my @safe = ('a' .. 'z', 'A' .. 'Z', '0' .. '9', '-', '_', '.'); # shell metachars are unsafe foreach my $letter (@letters) { my $pattern = quotemeta($letter); if (not grep(/$pattern/, @safe)) { $letter = sprintf("%%%02x", ord($letter)); } } return join('', @letters); } print "* means that a page is being updated\n"; sub update_page { my ($id, $text, $summary, $minor, $admin, @rest) = @_; print '*'; my $pwd = $admin ? 'foo' : 'wrong'; $id = url_encode($id); $text = url_encode($text); $summary = url_encode($summary); $minor = $minor ? 'on' : 'off'; my $rest = join(' ', @rest); $redirect = `perl wiki.pl Save=1 title=$id summary=$summary recent_edit=$minor text=$text pwd=$pwd $rest`; $output = `perl wiki.pl action=browse id=$id`; # just in case a new page got created or NearMap or InterMap $IndexInit = 0; $NearInit = 0; $InterInit = 0; $RssInterwikiTranslateInit = 0; InitVariables(); return $output; } print "+ means that a page is being retrieved\n"; sub get_page { print '+'; open(F,"perl wiki.pl @_ |"); my $output = ; close F; return $output; } print ". means a test\n"; sub test_page { my $page = shift; my $printpage = 0; foreach my $str (@_) { print '.'; if ($page =~ /$str/) { $passed++; } else { $failed++; $printpage = 1; print "\nSimple Test: Did not find \"", $str, '"'; } } print "\n\nPage content:\n", $page, "\n" if $printpage; } sub test_page_negative { my $page = shift; my $printpage = 0; foreach my $str (@_) { print '.'; if ($page =~ /$str/) { $failed++; $printpage = 1; print "\nSimple negative Test: Found \"", $str, '"'; } else { $passed++; } } print "\n\nPage content:\n", $page, "\n" if $printpage; } sub get_text_via_xpath { my ($page, $test) = @_; $page =~ s/^.*?//s; # strip headers my $parser = XML::LibXML->new(); my $doc; eval { $doc = $parser->parse_html_string($page) }; if ($@) { print "Could not parse html: $@\n", $page, "\n\n"; $failed += 1; } else { print '.'; my $nodelist; eval { $nodelist = $doc->findnodes($test) }; if ($@) { $failed++; print "\nXPATH Test: failed to run $test: $@\n"; } elsif ($nodelist->size()) { $passed++; return $nodelist->string_value(); } else { $failed++; print "\nXPATH Test: No matches for $test\n"; $page =~ s/^.*?//s; # strip headers my $parser = XML::LibXML->new(); my $doc; eval { $doc = $parser->parse_html_string($page) }; if ($@) { print "Could not parse html: ", substr($page,0,100), "\n"; $failed += @tests; } else { foreach my $test (@tests) { print '.'; my $nodelist; eval { $nodelist = $doc->findnodes($test) }; if ($@) { $failed++; print "\nXPATH Test: failed to run $test: $@\n"; } elsif ($nodelist->size()) { $passed++; } else { $failed++; print "\nXPATH Test: No matches for $test\n"; $page =~ s/^.*?//s; # strip headers my $parser = XML::LibXML->new(); my $doc = $parser->parse_html_string($page); foreach my $test (@tests) { print '.'; my $nodelist = $doc->findnodes($test); if (not $nodelist->size()) { $passed++; } else { $failed++; $printpage = 1; print "\nXPATH Test: Unexpected matches for $test\n"; } } } sub apply_rules { my $input = shift; local *STDOUT; $output = ''; open(STDOUT, '>', \$output) or die "Can't open memory file: $!"; $FootnoteNumber = 0; ApplyRules(QuoteHtml($input), 1); return $output; } sub xpath_run_tests { # translate embedded newlines (other backslashes remain untouched) my %New; foreach (keys %Test) { $Test{$_} =~ s/\\n/\n/g; my $new = $Test{$_}; s/\\n/\n/g; $New{$_} = $new; } # Note that the order of tests is not specified! my $output; foreach my $input (keys %New) { my $output = apply_rules($input); xpath_test("
$output
", $New{$input}); } } sub test_match { my ($input, @tests) = @_; foreach my $str (@tests) { print '.'; my $output = apply_rules($str); if ($output =~ /$str/) { $passed++; } else { $failed++; $printpage = 1; print "\nNo matches for $str\n"; print "$input\n" if length($input) < 200; } } } sub run_tests { # translate embedded newlines (other backslashes remain untouched) my %New; foreach (keys %Test) { $Test{$_} =~ s/\\n/\n/g; my $new = $Test{$_}; s/\\n/\n/g; $New{$_} = $new; } # Note that the order of tests is not specified! foreach my $input (keys %New) { print '.'; my $output = apply_rules($input); if ($output eq $New{$input}) { $passed++; } else { $failed++; print "\n\n---- input:\n", $input, "\n---- output:\n", $output, "\n---- instead of:\n", $New{$input}, "\n----\n"; } } } sub remove_rule { my $rule = shift; my @list = (); my $found = 0; foreach my $item (@MyRules) { if ($item ne $rule) { push @list, $item; } else { $found = 1; } } die "Rule not found" unless $found; @MyRules = @list; } sub add_module { my $mod = shift; mkdir $ModuleDir unless -d $ModuleDir; my $dir = `/bin/pwd`; chop($dir); symlink("$dir/modules/$mod", "$ModuleDir/$mod") or die "Cannot symlink $mod: $!" unless -l "$ModuleDir/$mod"; do "$ModuleDir/$mod"; @MyRules = sort {$RuleOrder{$a} <=> $RuleOrder{$b}} @MyRules; } sub remove_module { my $mod = shift; mkdir $ModuleDir unless -d $ModuleDir; unlink("$ModuleDir/$mod") or die "Cannot unlink: $!"; } sub clear_pages { system('/bin/rm -rf /tmp/oddmuse'); die "Cannot remove /tmp/oddmuse!\n" if -e '/tmp/oddmuse'; mkdir '/tmp/oddmuse'; open(F,'>/tmp/oddmuse/config'); print F "\$AdminPass = 'foo';\n"; # this used to be the default in earlier CGI.pm versions print F "\$ScriptName = 'http://localhost/wiki.pl';\n"; print F "\$SurgeProtection = 0;\n"; close(F); $ScriptName = 'http://localhost/test.pl'; # different! $IndexInit = 0; %IndexHash = (); $InterSiteInit = 0; %InterSite = (); $NearSiteInit = 0; %NearSite = (); %NearSearch = (); } # Create temporary data directory as expected by the script my $str; goto $ARGV[0] if $ARGV[0]; $ENV{'REMOTE_ADDR'} = 'test-markup'; # -------------------- oldmajor: print '[oldmajor]'; clear_pages(); update_page('bla', 'one'); # oldmajor is undef, lastmajor is 1 test_page(get_page('action=browse id=bla diff=1'), 'No diff available', 'one'); update_page('bla', 'two', '', 1); # oldmajor is undef, lastmajor is 1 test_page(get_page('action=browse id=bla diff=2'), 'one', 'two'); update_page('bla', 'three'); # oldmajor is 1, lastmajor is 3 test_page(get_page('action=browse id=bla diff=1'), 'one', 'three'); test_page(get_page('action=browse id=bla diff=2'), 'two', 'three'); update_page('bla', 'four', '', 1); # oldmajor is 1, lastmajor is 3 test_page(get_page('action=browse id=bla diff=1'), 'one', 'four'); test_page(get_page('action=browse id=bla diff=2'), 'three', 'four'); update_page('bla', 'five'); # oldmajor is 3, lastmajor is 5 test_page(get_page('action=browse id=bla diff=1'), 'three', 'five'); test_page(get_page('action=browse id=bla diff=2'), 'four', 'five'); update_page('bla', 'six'); # oldmajor is 5, lastmajor is 6 test_page(get_page('action=browse id=bla diff=1'), 'five', 'six'); test_page(get_page('action=browse id=bla diff=2'), 'five', 'six'); # -------------------- pagenames: print '[pagenames]'; clear_pages(); update_page('.dotfile', 'old content', 'older summary'); update_page('.dotfile', 'some content', 'some summary'); test_page(get_page('.dotfile'), 'some content'); test_page(get_page('action=browse id=.dotfile revision=1'), 'old content'); test_page(get_page('action=history id=.dotfile'), 'older summary', 'some summary'); # -------------------- rollback: print '[rollback]'; clear_pages(); # old revisions update_page('InnocentPage', 'Innocent.', 'good guy zero'); update_page('NicePage', 'Friendly content.', 'good guy one'); update_page('OtherPage', 'Other cute content 1.', 'another good guy'); update_page('OtherPage', 'Other cute content 2.', 'another good guy'); update_page('OtherPage', 'Other cute content 3.', 'another good guy'); update_page('OtherPage', 'Other cute content 4.', 'another good guy'); update_page('OtherPage', 'Other cute content 5.', 'another good guy'); update_page('OtherPage', 'Other cute content 6.', 'another good guy'); update_page('OtherPage', 'Other cute content 7.', 'another good guy'); update_page('OtherPage', 'Other cute content 8.', 'another good guy'); update_page('OtherPage', 'Other cute content 9.', 'another good guy'); update_page('OtherPage', 'Other cute content 10.', 'another good guy'); update_page('OtherPage', 'Other cute content 11.', 'another good guy'); # good revisions -- need a different timestamp than the old revisions! sleep(1); update_page('InnocentPage', 'Lamb.', 'good guy zero'); update_page('OtherPage', 'Other cute content 12.', 'another good guy'); update_page('MinorPage', 'Dumdidu', 'tester'); # last good revision -- needs a different timestamp than the good revisions! sleep(1); update_page('NicePage', 'Nice content.', 'good guy two'); # bad revisions -- need a different timestamp than the last good revision! sleep(1); update_page('NicePage', 'Evil content.', 'vandal one'); update_page('OtherPage', 'Other evil content.', 'another vandal'); update_page('NicePage', 'Bad content.', 'vandal two'); update_page('EvilPage', 'Spam!', 'vandal three'); update_page('AnotherEvilPage', 'More Spam!', 'vandal four'); update_page('AnotherEvilPage', 'Still More Spam!', 'vandal five'); update_page('MinorPage', 'Ramtatam', 'tester', 1); test_page(get_page('NicePage'), 'Bad content'); test_page(get_page('InnocentPage'), 'Lamb'); $to = get_text_via_xpath(get_page('action=rc all=1 pwd=foo'), '//strong[text()="good guy two"]/preceding-sibling::a[@class="rollback"]/attribute::href'); $to =~ /action=rollback;to=([0-9]+)/; $to = $1; test_page(get_page("action=rollback to=$to"), 'restricted to administrators'); test_page(get_page("action=rollback to=$to pwd=foo"), 'Rolling back changes', 'NicePage rolled back', 'OtherPage rolled back'); test_page(get_page('NicePage'), 'Nice content'); test_page(get_page('OtherPage'), 'Other cute content 12'); test_page(get_page('EvilPage'), 'DeletedPage'); test_page(get_page('AnotherEvilPage'), 'DeletedPage'); test_page(get_page('InnocentPage'), 'Lamb'); my $rc = get_page('action=rc all=1 showedit=1 pwd=foo'); # check all revisions of NicePage in recent changes xpath_test($rc, '//li/span[@class="time"]/following-sibling::span[@class="new"][text()="new"]/following-sibling::a[@class="rollback"][text()="rollback"]/following-sibling::a[@class="revision"][@href="http://localhost/wiki.pl?action=browse;id=NicePage;revision=1"][text()="NicePage"]/following-sibling::span[@class="dash"]/following-sibling::strong[text()="good guy one"]', '//li/span[@class="time"]/following-sibling::a[@class="diff"][@href="http://localhost/wiki.pl?action=browse;diff=2;id=NicePage;diffrevision=2"][text()="diff"]/following-sibling::a[@class="rollback"][text()="rollback"]/following-sibling::a[@class="revision"][@href="http://localhost/wiki.pl?action=browse;id=NicePage;revision=2"][text()="NicePage"]/following-sibling::span[@class="dash"]/following-sibling::strong[text()="good guy two"]', '//li/span[@class="time"]/following-sibling::a[@class="diff"][@href="http://localhost/wiki.pl?action=browse;diff=2;id=NicePage;diffrevision=3"][text()="diff"]/following-sibling::a[@class="rollback"][text()="rollback"]/following-sibling::a[@class="revision"][@href="http://localhost/wiki.pl?action=browse;id=NicePage;revision=3"][text()="NicePage"]/following-sibling::span[@class="dash"]/following-sibling::strong[text()="vandal one"]', '//li/span[@class="time"]/following-sibling::a[@class="diff"][@href="http://localhost/wiki.pl?action=browse;diff=2;id=NicePage;diffrevision=4"][text()="diff"]/following-sibling::a[@class="rollback"]/following-sibling::a[@class="revision"][@href="http://localhost/wiki.pl?action=browse;id=NicePage;revision=4"][text()="NicePage"]/following-sibling::span[@class="dash"]/following-sibling::strong[text()="vandal two"]', '//li/span[@class="time"]/following-sibling::a[@class="diff"][@href="http://localhost/wiki.pl?action=browse;diff=2;id=NicePage"][text()="diff"]/following-sibling::a[@class="rollback"][text()="rollback"]/following-sibling::a[@class="revision"][@href="http://localhost/wiki.pl?action=browse;id=NicePage"][text()="NicePage"]/following-sibling::span[@class="dash"]/following-sibling::strong[contains(text(),"Rollback to")]', # check that the minor spam is reverted with a minor rollback '//li/span[@class="time"]/following-sibling::span[@class="new"][text()="new"]/following-sibling::a[@class="rollback"][text()="rollback"]/following-sibling::a[@class="revision"][@href="http://localhost/wiki.pl?action=browse;id=MinorPage;revision=1"][text()="MinorPage"]/following-sibling::span[@class="dash"]/following-sibling::strong[text()="tester"]', '//li/span[@class="time"]/following-sibling::a[@class="diff"][@href="http://localhost/wiki.pl?action=browse;diff=2;id=MinorPage;diffrevision=2"][text()="diff"]/following-sibling::a[@class="rollback"][text()="rollback"]/following-sibling::a[@class="revision"][@href="http://localhost/wiki.pl?action=browse;id=MinorPage;revision=2"][text()="MinorPage"]/following-sibling::span[@class="dash"]/following-sibling::strong[text()="tester"]/following-sibling::em[text()="(minor)"]', '//li/span[@class="time"]/following-sibling::a[@class="diff"][@href="http://localhost/wiki.pl?action=browse;diff=2;id=MinorPage"][text()="diff"]/following-sibling::a[@class="rollback"][text()="rollback"]/following-sibling::a[@class="revision"][@href="http://localhost/wiki.pl?action=browse;id=MinorPage"][text()="MinorPage"]/following-sibling::span[@class="dash"]/following-sibling::strong[contains(text(),"Rollback to")]/following-sibling::em[text()="(minor)"]', ); # -------------------- clusters: print '[clusters]'; AppendStringToFile($ConfigFile, "\$PageCluster = 'Cluster';\n"); update_page('ClusterIdea', 'This is just a page.', 'one'); update_page('ClusterIdea', "This is just a page.\nBut somebody has to do it.", 'two'); update_page('ClusterIdea', "This is just a page.\nNobody wants it.", 'three', 1); update_page('ClusterIdea', "MainPage\nThis is just a page.\nBut somebody has to do it.", 'four'); @Test = split('\n',<<'EOT'); Cluster.*MainPage EOT test_page(get_page('action=rc'), @Test); @Test = split('\n',<<'EOT'); Cluster.*MainPage ClusterIdea.*two ClusterIdea.*one EOT test_page(get_page('action=rc all=1'), @Test); @Test = split('\n',<<'EOT'); Cluster.*MainPage ClusterIdea.*three ClusterIdea.*two ClusterIdea.*one EOT test_page(get_page('action=rc all=1 showedit=1'), @Test); @Test = split('\n',<<'EOT'); Finally the main page Updates in the last [0-9]+ days diff.*ClusterIdea.*history.*four for.*MainPage.*only 1 day action=browse;id=MainPage;rcclusteronly=MainPage;days=1;all=0;showedit=0 EOT update_page('MainPage', 'Finally the main page.'); test_page(get_page('action=browse id=MainPage rcclusteronly=MainPage'), @Test); @Test = split('\n',<<'EOT'); Finally the main page Updates in the last [0-9]+ days diff.*ClusterIdea.*four for.*MainPage.*only 1 day EOT test_page(get_page('action=browse id=MainPage rcclusteronly=MainPage showedit=1'), (@Test, 'action=browse;id=MainPage;rcclusteronly=MainPage;days=1;all=0;showedit=1')); test_page(get_page('action=browse id=MainPage rcclusteronly=MainPage all=1'), (@Test, 'action=browse;id=MainPage;rcclusteronly=MainPage;days=1;all=1;showedit=0')); @Test = split('\n',<<'EOT'); Finally the main page Updates in the last [0-9]+ days diff.*ClusterIdea.*five diff.*ClusterIdea.*four for.*MainPage.*only 1 day action=browse;id=MainPage;rcclusteronly=MainPage;days=1;all=1;showedit=1 EOT update_page('ClusterIdea', "MainPage\nSomebody has to do it.", 'five', 1); test_page(get_page('action=browse id=MainPage rcclusteronly=MainPage all=1 showedit=1'), @Test); # -------------------- rss: print '[rss]'; # create simple config file use Cwd; $dir = cwd; $uri = "file://$dir"; # some xpath tests update_page('RSS', ""); $page = get_page('RSS'); xpath_test($page, Encode::encode_utf8('//a[@title="999"][@href="http://www.heise.de/tp/deutsch/inhalt/te/15886/1.html"][text()="Berufsverbot für Mediendesigner?"]')); @Test = split('\n',<<'EOT');
  • Experimentell bestätigt: http://www.heise.de/tp/deutsch/inhalt/lis/15882/1.html Clash im Internet? http://www.heise.de/tp/deutsch/special/med/15787/1.html Die Einheit der Umma gegen die jüdische Weltmacht http://www.heise.de/tp/deutsch/special/ost/15879/1.html Im Krieg mit dem Satan http://www.heise.de/tp/deutsch/inhalt/co/15880/1.html Der dritte Mann http://www.heise.de/tp/deutsch/inhalt/co/15876/1.html Leicht neben dem Ziel http://www.heise.de/tp/deutsch/inhalt/mein/15867/1.html Wale sollten Nordkorea meiden http://www.heise.de/tp/deutsch/inhalt/co/15878/1.html Afghanistan-Krieg und Irak-Besatzung haben al-Qaida gestärkt http://www.heise.de/tp/deutsch/inhalt/co/15874/1.html Der mit dem Dinosaurier tanzt http://www.heise.de/tp/deutsch/inhalt/lis/15863/1.html Terroranschlag überschattet das Genfer Abkommen http://www.heise.de/tp/deutsch/special/ost/15873/1.html "Barwatch" in Kanada http://www.heise.de/tp/deutsch/inhalt/te/15871/1.html Die Türken kommen! http://www.heise.de/tp/deutsch/special/irak/15870/1.html Neue Regelungen zur Telekommunikationsüberwachung http://www.heise.de/tp/deutsch/inhalt/te/15869/1.html Ein Lied vom Tod http://www.heise.de/tp/deutsch/inhalt/kino/15862/1.html EOT test_page($page, @Test); # RSS 2.0 update_page('RSS', ""); test_page(get_page('RSS'), join('(.|\n)*', # verify the *order* of things. 'href="http://www.flickr.com/photos/broccoli/867118/"', 'href="http://www.flickr.com/photos/broccoli/867075/"', 'href="http://www.flickr.com/photos/seuss/864332/"', 'href="http://www.flickr.com/photos/redking/851171/"', 'href="http://www.flickr.com/photos/redking/851168/"', 'href="http://www.flickr.com/photos/redking/851167/"', 'href="http://www.flickr.com/photos/redking/851166/"', 'href="http://www.flickr.com/photos/redking/851165/"', 'href="http://www.flickr.com/photos/bibo/844085/"', 'href="http://www.flickr.com/photos/theunholytrinity/867312/"'), join('(.|\n)*', 'title="2004-10-14 09:34:47 "', 'title="2004-10-14 09:28:11 "', 'title="2004-10-14 05:08:17 "', 'title="2004-10-13 10:00:34 "', 'title="2004-10-13 10:00:30 "', 'title="2004-10-13 10:00:27 "', 'title="2004-10-13 10:00:25 "', 'title="2004-10-13 10:00:22 "', 'title="2004-10-12 23:38:14 "', 'title="2004-10-10 10:09:06 "'), join('(.|\n)*', '>The Hydra<', '>The War On Hydra<', '>Nation Demolished<', '>Drummers<', '>Death<', '>Audio Terrorists<', '>Crowds<', '>Assholes<', '>iraq_saddam03<', '>brudermann<')); @Test = split('\n',<<'EOT'); Fania All Stars - Bamboleo http://www.audioscrobbler.com/music/Fania\+All\+Stars/_/Bamboleo EOT update_page('RSS', ""); test_page(get_page('RSS'), @Test); @Test = split('\n',<<'EOT'); PRNewswire: Texas Software Startup, Serenity Systems, Advises Business Users to Get Off Windows http://linuxtoday.com/story.php3\?sn=9443 LinuxPR: MyDesktop Launches Linux Software Section http://linuxtoday.com/story.php3\?sn=9442 LinuxPR: Franklin Institute Science Museum Chooses Linux http://linuxtoday.com/story.php3\?sn=9441 Yellow Dog Linux releases updated am-utils http://linuxtoday.com/story.php3\?sn=9440 LinuxPR: LinuxCare Adds Laser5 Linux To Roster of Supported Linux Distributions http://linuxtoday.com/story.php3\?sn=9439 EOT update_page('RSS', ""); test_page(get_page('RSS'), @Test); @Test = split('\n',<<'EOT'); Xskat 3.1 http://freshmeat.net/news/1999/09/01/936224942.html Java Test Driver 1.1 http://freshmeat.net/news/1999/09/01/936224907.html WaveLAN/IEEE driver 1.0.1 http://freshmeat.net/news/1999/09/01/936224545.html macfork 1.0 http://freshmeat.net/news/1999/09/01/936224336.html QScheme 0.2.2 http://freshmeat.net/news/1999/09/01/936223755.html CompuPic 4.6 build 1018 http://freshmeat.net/news/1999/09/01/936223729.html eXtace 1.1.16 http://freshmeat.net/news/1999/09/01/936223709.html GTC 0.3 http://freshmeat.net/news/1999/09/01/936223686.html RocketJSP 0.9c http://freshmeat.net/news/1999/09/01/936223646.html Majik 3D 0.0/M3 http://freshmeat.net/news/1999/09/01/936223622.html EOT update_page('RSS', ""); test_page(get_page('RSS'), @Test); @Test = split('\n',<<'EOT'); GTKeyboard 0.85 http://freshmeat.net/news/1999/06/21/930003829.html EOT update_page('RSS', ""); test_page(get_page('RSS'), @Test); # Note, cannot identify BayleShanks as author in the mb.rdf @Test = split('\n',<<'EOT'); MeatBall:LionKimbro 2003-10-24T22:49:33\+06:00 CommunityWiki:RecentNearChanges http://www.usemod.com/cgi-bin/mb.pl\?LionKimbro 2003-10-24T21:02:53\+00:00 unified rc for here and meatball \. \. \. \. AlexSchroeder http://www.emacswiki.org/cgi-bin/community\?action=browse;id=RecentNearChanges;revision=1 EOT update_page('RSS', ""); test_page(get_page('RSS'), @Test); # -------------------- redirection: print '[redirection]'; update_page('Miles_Davis', 'Featuring [[John Coltrane]]'); # plain link update_page('John_Coltrane', '#REDIRECT Coltrane'); # no redirect update_page('Sonny_Stitt', '#REDIRECT [[Stitt]]'); # redirect update_page('Keith_Jarret', 'Plays with [[Gary Peacock]]'); # link to perm. anchor update_page('Jack_DeJohnette', 'A friend of [::Gary Peacock]'); # define perm. anchor test_page(get_page('Miles_Davis'), ('Featuring', 'John Coltrane')); test_page(get_page('John_Coltrane'), ('#REDIRECT Coltrane')); test_page(get_page('Sonny_Stitt'), ('Status: 302', 'Location: .*wiki.pl\?action=browse;oldid=Sonny_Stitt;id=Stitt')); test_page(get_page('Keith_Jarret'), ('Plays with', 'wiki.pl/Jack_DeJohnette#Gary_Peacock', 'Keith Jarret', 'Gary Peacock')); test_page(get_page('Gary_Peacock'), ('Status: 302', 'Location: .*wiki.pl/Jack_DeJohnette#Gary_Peacock')); test_page(get_page('Jack_DeJohnette'), ('A friend of', 'Gary Peacock', 'name="Gary_Peacock"', 'class="definition"', 'title="Click to search for references to this permanent anchor"')); # -------------------- recent_changes: print '[recent changes]'; $host1 = 'tisch'; $host2 = 'stuhl'; $ENV{'REMOTE_ADDR'} = $host1; update_page('Mendacibombus', 'This is the place.', 'samba', 0, 0, ('username=berta')); update_page('Bombia', 'This is the time.', 'tango', 0, 0, ('username=alex')); $ENV{'REMOTE_ADDR'} = $host2; update_page('Confusibombus', 'This is order.', 'ballet', 1, 0, ('username=berta')); update_page('Mucidobombus', 'This is chaos.', 'tarantella', 0, 0, ('username=alex')); @Positives = split('\n',<<'EOT'); for time or place only Mendacibombus.*samba Bombia.*tango EOT @Negatives = split('\n',<<'EOT'); Confusibombus ballet Mucidobombus tarantella EOT $page = get_page('action=rc rcfilteronly=time%20or%20place'); test_page($page, @Positives); test_page_negative($page, @Negatives); @Positives = split('\n',<<'EOT'); Mucidobombus.*tarantella EOT @Negatives = split('\n',<<'EOT'); Mendacibombus samba Bombia tango Confusibombus ballet EOT $page = get_page('action=rc rcfilteronly=order%20or%20chaos'); test_page($page, @Positives); test_page_negative($page, @Negatives); @Positives = split('\n',<<'EOT'); EOT @Negatives = split('\n',<<'EOT'); Mucidobombus tarantella Mendacibombus samba Bombia tango Confusibombus ballet EOT $page = get_page('action=rc rcfilteronly=order%20and%20chaos'); test_page($page, @Positives); test_page_negative($page, @Negatives); @Positives = split('\n',<<'EOT'); Mendacibombus.*samba Bombia.*tango EOT @Negatives = split('\n',<<'EOT'); Mucidobombus tarantella Confusibombus ballet EOT $page = get_page('action=rc rchostonly=tisch'); test_page($page, @Positives); test_page_negative($page, @Negatives); @Positives = split('\n',<<'EOT'); Mucidobombus.*tarantella EOT @Negatives = split('\n',<<'EOT'); Confusibombus ballet Bombia tango Mendacibombus samba EOT $page = get_page('action=rc rchostonly=stuhl'); # no minor edits! test_page($page, @Positives); test_page_negative($page, @Negatives); @Positives = split('\n',<<'EOT'); Mucidobombus.*tarantella Confusibombus.*ballet EOT @Negatives = split('\n',<<'EOT'); Mendacibombus samba Bombia tango EOT $page = get_page('action=rc rchostonly=stuhl showedit=1'); # with minor edits! test_page($page, @Positives); test_page_negative($page, @Negatives); @Positives = split('\n',<<'EOT'); Mendacibombus.*samba EOT @Negatives = split('\n',<<'EOT'); Mucidobombus tarantella Bombia tango Confusibombus ballet EOT $page = get_page('action=rc rcuseronly=berta'); test_page($page, @Positives); test_page_negative($page, @Negatives); @Positives = qw(Mucidobombus.*tarantella Bombia.*tango); @Negatives = qw(Confusibombus ballet Mendacibombus samba); $page = get_page('action=rc rcuseronly=alex'); test_page($page, @Positives); test_page_negative($page, @Negatives); @Positives = qw(Bombia.*tango); @Negatives = qw(Mucidobombus tarantella Confusibombus ballet Mendacibombus samba); $page = get_page('action=rc rcidonly=Bombia'); test_page($page, @Positives); test_page_negative($page, @Negatives); # -------------------- conflicts: print '[conflicts]'; # Using the example files from the diff3 manual my $lao_file = q{The Way that can be told of is not the eternal Way; The name that can be named is not the eternal name. The Nameless is the origin of Heaven and Earth; The Named is the mother of all things. Therefore let there always be non-being, so we may see their subtlety, And let there always be being, so we may see their outcome. The two are the same, But after they are produced, they have different names. }; my $lao_file_1 = q{The Tao that can be told of is not the eternal Tao; The name that can be named is not the eternal name. The Nameless is the origin of Heaven and Earth; The Named is the mother of all things. Therefore let there always be non-being, so we may see their subtlety, And let there always be being, so we may see their outcome. The two are the same, But after they are produced, they have different names. }; my $lao_file_2 = q{The Way that can be told of is not the eternal Way; The name that can be named is not the eternal name. The Nameless is the origin of Heaven and Earth; The Named is the mother of all things. Therefore let there always be non-being, so we may see their simplicity, And let there always be being, so we may see the result. The two are the same, But after they are produced, they have different names. }; my $tzu_file = q{The Nameless is the origin of Heaven and Earth; The named is the mother of all things. Therefore let there always be non-being, so we may see their subtlety, And let there always be being, so we may see their outcome. The two are the same, But after they are produced, they have different names. They both may be called deep and profound. Deeper and more profound, The door of all subtleties! }; my $tao_file = q{The Way that can be told of is not the eternal Way; The name that can be named is not the eternal name. The Nameless is the origin of Heaven and Earth; The named is the mother of all things. Therefore let there always be non-being, so we may see their subtlety, And let there always be being, so we may see their result. The two are the same, But after they are produced, they have different names. -- The Way of Lao-Tzu, tr. Wing-tsit Chan }; clear_pages(); # simple edit $ENV{'REMOTE_ADDR'} = 'confusibombus'; test_page(update_page('ConflictTest', $lao_file), 'The Way that can be told of is not the eternal Way'); # edit from another address should result in conflict warning $ENV{'REMOTE_ADDR'} = 'megabombus'; test_page(update_page('ConflictTest', $tzu_file), 'The Nameless is the origin of Heaven and Earth'); # test cookie! test_page($redirect, map { UrlEncode($_); } ('This page was changed by somebody else', 'Please check whether you overwrote those changes')); # test normal merging -- first get oldtime, then do two conflicting edits # we need to wait at least a second after the last test in order to not # confuse oddmuse. sleep(2); update_page('ConflictTest', $lao_file); $_ = `perl wiki.pl action=edit id=ConflictTest`; /name="oldtime" value="([0-9]+)"/; my $oldtime = $1; sleep(2); $ENV{'REMOTE_ADDR'} = 'confusibombus'; update_page('ConflictTest', $lao_file_1); sleep(2); # merge success has lines from both lao_file_1 and lao_file_2 $ENV{'REMOTE_ADDR'} = 'megabombus'; test_page(update_page('ConflictTest', $lao_file_2, '', '', '', "oldtime=$oldtime"), 'The Tao that can be told of', # file 1 'The name that can be named', # both 'so we may see their simplicity'); # file 2 # test conflict during merging -- first get oldtime, then do two conflicting edits sleep(2); update_page('ConflictTest', $tzu_file); $_ = `perl wiki.pl action=edit id=ConflictTest`; /name="oldtime" value="([0-9]+)"/; $oldtime = $1; sleep(2); $ENV{'REMOTE_ADDR'} = 'confusibombus'; update_page('ConflictTest', $tao_file); sleep(2); $ENV{'REMOTE_ADDR'} = 'megabombus'; test_page(update_page('ConflictTest', $lao_file, '', '', '', "oldtime=$oldtime"), q{
    <<<<<<< ancestor
    =======
    The Way that can be told of is not the eternal Way;
    The name that can be named is not the eternal name.
    >>>>>>> other
    
    }, q{
    <<<<<<< you
    ||||||| ancestor
    They both may be called deep and profound.
    Deeper and more profound,
    The door of all subtleties!
    =======
    
      -- The Way of Lao-Tzu, tr. Wing-tsit Chan
    >>>>>>> other
    
    }); @Test = split('\n',<<'EOT'); This page was changed by somebody else The changes conflict EOT test_page($redirect, map { UrlEncode($_); } @Test); # test cookie! # test conflict during merging without merge! -- first get oldtime, then do two conflicting edits AppendStringToFile($ConfigFile, "\$ENV{'PATH'} = '';\n"); sleep(2); update_page('ConflictTest', $lao_file); $_ = `perl wiki.pl action=edit id=ConflictTest`; /name="oldtime" value="([0-9]+)"/; $oldtime = $1; sleep(2); $ENV{'REMOTE_ADDR'} = 'confusibombus'; update_page('ConflictTest', $lao_file_1); sleep(2); # merge not available -- must look for message $ENV{'REMOTE_ADDR'} = 'megabombus'; test_page(update_page('ConflictTest', $lao_file_2, '', '', '', "oldtime=$oldtime"), 'The Way that can be told of is not the eternal Way', # file 2 'so we may see their simplicity', # file 2 'so we may see the result'); # file 2 test_page($redirect, map { UrlEncode($_) } ('This page was changed by somebody else', 'Please check whether you overwrote those changes')); # test cookie! # -------------------- html_cache: print '[html cache]'; ### Maintenance with cache resetting clear_pages(); $str = 'This is a WikiLink.'; # this setting produces no link. AppendStringToFile($ConfigFile, "\$WikiLinks = 0;\n"); test_page(update_page('CacheTest', $str, '', 1), $str); # now change the setting, you still get no link because the cache has # not been updated. AppendStringToFile($ConfigFile, "\$WikiLinks = 1;\n"); test_page(get_page('CacheTest'), $str); # refresh the cache using the all action test_page(get_page('action=all cache=0 pwd=foo'), $str, 'Complete Content'); # now there is a link # This is a WikiLink\?. xpath_test(get_page('CacheTest'), '//a[@class="edit"][@title="Click to edit this page"][@href="http://localhost/wiki.pl?action=edit;id=WikiLink"][text()="?"]'); # -------------------- search_and_replace: print '[search and replace]'; clear_pages(); add_module('mac.pl'); # Test search update_page('SearchAndReplace', 'This is fooz and this is barz.', '', 1); $page = get_page('search=fooz'); test_page($page, '

    Search for: fooz

    ', '

    1 pages found.

    ', 'This is fooz and this is barz.'); xpath_test($page, '//span[@class="result"]/a[@class="local"][@href="http://localhost/wiki.pl/SearchAndReplace"][text()="SearchAndReplace"]'); # Make sure only admins can replace test_page(get_page('search=foo replace=bar'), 'This operation is restricted to administrators only...'); # Simple replace where the replacement pattern is found @Test = split('\n',<<'EOT');

    Replaced: fooz -> fuuz

    1 pages found.

    This is fuuz and this is barz. EOT test_page(get_page('search=fooz replace=fuuz pwd=foo'), @Test); # Replace with backreferences, where the replacement pattern is no longer found test_page(get_page('search=([a-z]%2b)z replace=x%241 pwd=foo'), '0 pages found'); test_page(get_page('SearchAndReplace'), 'This is xfuu and this is xbar.'); # Create an extra page that should not be found update_page('NegativeSearchTest', 'this page contains an ab'); update_page('NegativeSearchTestTwo', 'this page contains another ab'); test_page(get_page('search=xb replace=[xa]b pwd=foo'), '1 pages found'); # not two ab! test_page(get_page('SearchAndReplace'), 'This is xfuu and this is \[xa\]bar.'); # Handle quoting test_page(get_page('search=xfuu replace=/fuu/ pwd=foo'), '1 pages found'); # not two ab! test_page(get_page('SearchAndReplace'), 'This is /fuu/ and this is \[xa\]bar.'); test_page(get_page('search=/fuu/ replace={{fuu}} pwd=foo'), '1 pages found'); test_page(get_page('SearchAndReplace'), 'This is {{fuu}} and this is \[xa\]bar.'); ## Check headers especially the quoting of non-ASCII characters. $page = update_page("Alexander_Schröder", "Edit [[Alexander Schröder]]!"); xpath_test($page, Encode::encode_utf8('//h1/a[@title="Click to search for references to this page"][@href="http://localhost/wiki.pl?search=Alexander+Schr%c3%b6der"][text()="Alexander Schröder"]'), Encode::encode_utf8('//a[@class="local"][@href="http://localhost/wiki.pl/Alexander_Schr%c3%b6der"][text()="Alexander Schröder"]')); # -------------------- banning: print '[banning]'; clear_pages(); $localhost = 'confusibombus'; $ENV{'REMOTE_ADDR'} = $localhost; ## Edit banned hosts as a normal user should fail test_page(update_page('BannedHosts', "# Foo\n#Bar\n$localhost\n", 'banning me'), 'Describe the new page here'); ## Edit banned hosts as admin should succeed test_page(update_page('BannedHosts', "#Foo\n#Bar\n$localhost\n", 'banning me', 0, 1), "Foo", $localhost); ## Edit banned hosts as a normal user should fail test_page(update_page('BannedHosts', "Something else.", 'banning me'), "Foo", $localhost); ## Try to edit another page as a banned user test_page(update_page('BannedUser', 'This is a test which should fail.', 'banning test'), 'Describe the new page here'); ## Try to edit the same page as a banned user with admin password test_page(update_page('BannedUser', 'This is a test.', 'banning test', 0, 1), "This is a test"); ## Unbann myself again, testing the regexp test_page(update_page('BannedHosts', "#Foo\n#Bar\n", 'banning me', 0, 1), "Foo", "Bar"); ## Banning content @Test = split('\n',<<'EOT'); banned text wiki administrator matched See .*BannedContent.* for more information EOT update_page('BannedContent', "# cosa\nmafia\n#nostra\n", 'one banned word', 0, 1); test_page(update_page('CriminalPage', 'This is about http://mafia.example.com'), 'Describe the new page here'); test_page($redirect, @Test); test_page(update_page('CriminalPage', 'This is about http://nafia.example.com'), "This is about", "http://nafia.example.com"); test_page(update_page('CriminalPage', 'This is about the cosa nostra'), 'cosa nostra'); test_page(update_page('CriminalPage', 'This is about the mafia'), 'This is about the mafia'); # not in an url # -------------------- journal: print '[journal]'; ## Create diary pages update_page('2003-06-13', "Freitag"); update_page('2003-06-14', "Samstag"); update_page('2003-06-15', "Sonntag"); @Test = split('\n',<<'EOT'); This is my journal 2003-06-15 Sonntag 2003-06-14 Samstag EOT test_page(update_page('Summary', "This is my journal:\n\n"), @Test); test_page(update_page('2003-01-01', "This is my journal -- recursive:\n\n"), @Test); push @Test, 'journal'; test_page(update_page('2003-01-01', "This is my journal -- truly recursive:\n\n"), @Test); @Test = split('\n',<<'EOT'); 2003-06-15(.|\n)*2003-06-14 EOT test_page(update_page('Summary', "Counting down:\n\n"), @Test); @Test = split('\n',<<'EOT'); 2003-01-01(.|\n)*2003-06-13(.|\n)*2003-06-14 EOT test_page(update_page('Summary', "Counting up:\n\n"), @Test); # -------------------- revisions: print '[revisions]'; clear_pages(); ## Test revision and diff stuff update_page('KeptRevisions', 'first'); update_page('KeptRevisions', 'second'); update_page('KeptRevisions', 'third'); update_page('KeptRevisions', 'fourth', '', 1); update_page('KeptRevisions', 'fifth', '', 1); # Show the current revision test_page(get_page(KeptRevisions), 'KeptRevisions', 'fifth'); # Show the other revision test_page(get_page('action=browse revision=2 id=KeptRevisions'), 'Showing revision 2', 'second'); test_page(get_page('action=browse revision=1 id=KeptRevisions'), 'Showing revision 1', 'first'); # Show the current revision if an inexisting revision is asked for test_page(get_page('action=browse revision=9 id=KeptRevisions'), 'Revision 9 not available \(showing current revision instead\)', 'fifth'); # Show a major diff test_page(get_page('action=browse diff=1 id=KeptRevisions'), 'Difference \(from prior major revision\)', 'second', 'fifth'); # Show a minor diff test_page(get_page('action=browse diff=2 id=KeptRevisions'), 'Difference \(from prior minor revision\)', 'fourth', 'fifth'); # Show a diff from the history page comparing two specific revisions test_page(get_page('action=browse diff=1 revision=4 diffrevision=2 id=KeptRevisions'), 'Difference \(from revision 2 to revision 4\)', 'second', 'fourth'); # Show no difference update_page('KeptRevisions', 'second'); test_page(get_page('action=browse diff=1 revision=6 diffrevision=2 id=KeptRevisions'), 'Difference \(from revision 2 to revision 6\)', 'The two revisions are the same'); # -------------------- lock_on_creation: print '[lock on creation]'; ## Create a sample page, and test for regular expressions in the output $page = update_page('SandBox', 'This is a test.', 'first test'); test_page($page, 'SandBox', 'This is a test.'); xpath_test($page, '//h1/a[@title="Click to search for references to this page"][@href="http://localhost/wiki.pl?search=SandBox"][text()="SandBox"]'); ## Test RecentChanges @Test = split('\n',<<'EOT'); RecentChanges first test EOT test_page(get_page('action=rc'), @Test); ## Updated the page @Test = split('\n',<<'EOT'); RecentChanges This is another test. EOT test_page(update_page('SandBox', 'This is another test.', 'second test'), @Test); ## Test RecentChanges @Test = split('\n',<<'EOT'); RecentChanges second test EOT test_page(get_page('action=rc'), @Test); ## Attempt to create InterMap page as normal user @Test = split('\n',<<'EOT'); Describe the new page here EOT test_page(update_page('InterMap', " OddMuse http://www.emacswiki.org/cgi-bin/oddmuse.pl?\n", 'required'), @Test); ## Create InterMap page as admin @Test = split('\n',<<'EOT'); OddMuse http://www\.emacswiki\.org/cgi-bin/oddmuse\.pl PlanetMath http://planetmath\.org/encyclopedia/\%s\.html EOT test_page(update_page('InterMap', " OddMuse http://www.emacswiki.org/cgi-bin/oddmuse.pl?\n PlanetMath http://planetmath.org/encyclopedia/%s.html", 'required', 0, 1), @Test); ## Verify the InterMap stayed locked @Test = split('\n',<<'EOT'); OddMuse EOT test_page(update_page('InterMap', "All your edits are blong to us!\n", 'required'), @Test); # -------------------- despam_module: print '[despam module]'; clear_pages(); add_module('despam.pl'); update_page('HilariousPage', "Ordinary text."); update_page('HilariousPage', "Hilarious text."); update_page('HilariousPage', "Spam from http://example.com."); update_page('NoPage', "Spam from http://example.com."); update_page('OrdinaryPage', "Spam from http://example.com."); update_page('OrdinaryPage', "Ordinary text."); update_page('ExpiredPage', "Spam from http://example.com."); update_page('ExpiredPage', "More spam from http://example.com."); update_page('ExpiredPage', "Still more spam from http://example.com."); update_page('BannedContent', " example\\.com\n", 'required', 0, 1); unlink('/tmp/oddmuse/keep/E/ExpiredPage/1.kp') or die "Cannot delete kept revision: $!"; @Test = split('\n',<<'EOT'); HilariousPage.*Revert to revision 2 NoPage.*Marked as DeletedPage OrdinaryPage ExpiredPage.*Cannot find unspammed revision EOT test_page(get_page('action=despam'), @Test); test_page(get_page('ExpiredPage'), 'Still more spam'); test_page(get_page('OrdinaryPage'), 'Ordinary text'); test_page(get_page('NoPage'), 'DeletedPage'); test_page(get_page('HilariousPage'), 'Hilarious text'); test_page(get_page('BannedContent'), 'example\\\.com'); # -------------------- near: print '[near]'; clear_pages(); CreateDir($NearDir); WriteStringToFile("$NearDir/EmacsWiki", "AlexSchroeder\nFooBar\n"); update_page('InterMap', " EmacsWiki http://www.emacswiki.org/cgi-bin/wiki/%s\n", 'required', 0, 1); update_page('NearMap', " EmacsWiki" . " http://www.emacswiki.org/cgi-bin/emacs?action=index;raw=1" . " http://www.emacswiki.org/cgi-bin/emacs?search=%s;raw=1;near=0\n", 'required', 0, 1); xpath_test(update_page('FooBaz', "Try FooBar instead!\n"), '//a[@class="near"][@title="EmacsWiki"][@href="http://www.emacswiki.org/cgi-bin/wiki/FooBar"][text()="FooBar"]', '//div[@class="near"]/p/a[@class="local"][@href="http://localhost/wiki.pl/EditNearLinks"][text()="EditNearLinks"]/following-sibling::text()[string()=": "]/following-sibling::a[@class="edit"][@title="Click to edit this page"][@href="http://localhost/wiki.pl?action=edit;id=FooBar"][text()="FooBar"]'); xpath_test(update_page('FooBar', "Test by AlexSchroeder!\n"), '//div[@class="sister"]/p/a[@title="EmacsWiki:FooBar"][@href="http://www.emacswiki.org/cgi-bin/wiki/FooBar"]/img[@src="file:///tmp/oddmuse/EmacsWiki.png"][@alt="EmacsWiki:FooBar"]'); xpath_test(get_page('search=alexschroeder'), '//p[text()="Near pages:"]', '//a[@class="near"][@title="EmacsWiki"][@href="http://www.emacswiki.org/cgi-bin/wiki/AlexSchroeder"][text()="AlexSchroeder"]'); # -------------------- links: print '[links]'; clear_pages(); add_module('links.pl'); update_page('InterMap', " Oddmuse http://www.emacswiki.org/cgi-bin/oddmuse.pl?\n", 'required', 0, 1); update_page('a', 'Oddmuse:foo(no) [Oddmuse:bar] [Oddmuse:baz text] ' . '[Oddmuse:bar(no)] [Oddmuse:baz(no) text] ' . '[[Oddmuse:foo_(bar)]] [[[Oddmuse:foo (baz)]]] [[Oddmuse:foo (quux)|text]]'); $InterInit = 0; InitVariables(); @Test = map { quotemeta } split('\n',<<'EOT'); "a" -> "Oddmuse:foo" "a" -> "Oddmuse:bar" "a" -> "Oddmuse:baz" "a" -> "Oddmuse:foo_(bar)" "a" -> "Oddmuse:foo (baz)" "a" -> "Oddmuse:foo (quux)" EOT test_page_negative(get_page('action=links raw=1'), @Test); test_page(get_page('action=links raw=1 inter=1'), @Test); @Test = split('\n',<<'EOT'); //a[@class="local"][@href="http://localhost/wiki.pl/a"][text()="a"] //a[@class="inter"][@href="http://www.emacswiki.org/cgi-bin/oddmuse.pl?foo"]/span[@class="site"][text()="Oddmuse"]/following-sibling::text()[string()=":"]/following-sibling::span[@class="page"][text()="foo"] //a[@class="inter"][@href="http://www.emacswiki.org/cgi-bin/oddmuse.pl?bar"]/span[@class="site"][text()="Oddmuse"]/following-sibling::text()[string()=":"]/following-sibling::span[@class="page"][text()="bar"] //a[@class="inter"][@href="http://www.emacswiki.org/cgi-bin/oddmuse.pl?baz"]/span[@class="site"][text()="Oddmuse"]/following-sibling::text()[string()=":"]/following-sibling::span[@class="page"][text()="baz"] //a[@class="inter"][@href="http://www.emacswiki.org/cgi-bin/oddmuse.pl?foo_(bar)"]/span[@class="site"][text()="Oddmuse"]/following-sibling::text()[string()=":"]/following-sibling::span[@class="page"][text()="foo_(bar)"] EOT negative_xpath_test(get_page('action=links'), @Test); xpath_test(get_page('action=links inter=1'), @Test); AppendStringToFile($ConfigFile, "\$BracketWiki = 0;\n"); update_page('a', '[[b]] [[[c]]] [[d|e]] FooBar [FooBaz] [FooQuux fnord] '); @Test1 = split('\n',<<'EOT'); "a" -> "b" "a" -> "c" "a" -> "FooBar" "a" -> "FooBaz" "a" -> "FooQuux" EOT @Test2 = split('\n',<<'EOT'); "a" -> "d" EOT $page = get_page('action=links raw=1'); test_page($page, @Test1); test_page_negative($page, @Test2); AppendStringToFile($ConfigFile, "\$BracketWiki = 1;\n"); update_page('a', '[[b]] [[[c]]] [[d|e]] FooBar [FooBaz] [FooQuux fnord] ' . 'http://www.oddmuse.org/ [http://www.emacswiki.org/] ' . '[http://www.communitywiki.org/ cw]'); @Test1 = split('\n',<<'EOT'); "a" -> "b" "a" -> "c" "a" -> "d" "a" -> "FooBar" "a" -> "FooBaz" "a" -> "FooQuux" EOT @Test2 = split('\n',<<'EOT'); "a" -> "http://www.oddmuse.org/" "a" -> "http://www.emacswiki.org/" "a" -> "http://www.communitywiki.org/" EOT $page = get_page('action=links raw=1'); test_page($page, @Test1); test_page_negative($page, @Test2); $page = get_page('action=links raw=1 url=1'); test_page($page, @Test1, @Test2); $page = get_page('action=links raw=1 links=0 url=1'); test_page_negative($page, @Test1); test_page($page, @Test2); # -------------------- link_pattern: print '[link pattern]'; clear_pages(); $AllNetworkFiles = 1; update_page('HomePage', "This page exists."); update_page('InterMap', " Oddmuse http://www.emacswiki.org/cgi-bin/oddmuse.pl?\n PlanetMath http://planetmath.org/encyclopedia/%s.html", 'required', 0, 1); $InterInit = 0; InitVariables(); %Test = split('\n',<<'EOT'); file://home/foo/tutorial.pdf //a[@class="url"][@href="file://home/foo/tutorial.pdf"][text()="file://home/foo/tutorial.pdf"] file:///home/foo/tutorial.pdf //a[@class="url"][@href="file:///home/foo/tutorial.pdf"][text()="file:///home/foo/tutorial.pdf"] image inline: [[image:HomePage]] //a[@class="image"][@href="http://localhost/test.pl/HomePage"]/img[@class="upload"][@src="http://localhost/test.pl/download/HomePage"][@alt="HomePage"] image inline: [[image:OtherPage]] //a[@class="edit"][@title="Click to edit this page"][@href="http://localhost/test.pl?action=edit;id=OtherPage;upload=1"][text()="?"] traditional local link: HomePage //a[@class="local"][@href="http://localhost/test.pl/HomePage"][text()="HomePage"] traditional local link: OtherPage //a[@class="edit"][@title="Click to edit this page"][@href="http://localhost/test.pl?action=edit;id=OtherPage"][text()="?"] traditional local link with extra brackets: [HomePage] //a[@class="local number"][@title="HomePage"][@href="http://localhost/test.pl/HomePage"]/span/span[@class="bracket"][text()="["]/following-sibling::text()[string()="1"]/following-sibling::span[@class="bracket"][text()="]"] traditional local link with extra brackets: [OtherPage] //a[@class="edit"][@title="Click to edit this page"][@href="http://localhost/test.pl?action=edit;id=OtherPage"][text()="?"] traditional local link with other text: [HomePage homepage] //a[@class="local"][@href="http://localhost/test.pl/HomePage"][text()="HomePage"] traditional local link with other text: [OtherPage other page] //a[@class="edit"][@title="Click to edit this page"][@href="http://localhost/test.pl?action=edit;id=OtherPage"][text()="?"] free link: [[home page]] //a[@class="edit"][@title="Click to edit this page"][@href="http://localhost/test.pl?action=edit;id=home_page"][text()="?"] free link: [[other page]] //a[@class="edit"][@title="Click to edit this page"][@href="http://localhost/test.pl?action=edit;id=other_page"][text()="?"] free link with extra brackets: [[[home page]]] //a[@class="edit"][@title="Click to edit this page"][@href="http://localhost/test.pl?action=edit;id=home_page"][text()="?"] free link with extra brackets: [[[other page]]] //a[@class="edit"][@title="Click to edit this page"][@href="http://localhost/test.pl?action=edit;id=other_page"][text()="?"] free link with other text: [[home page|da homepage]] //text()[string()="free link with other text: [[home page|da homepage]]"] free link with other text: [[other page|da other homepage]] //text()[string()="free link with other text: [[other page|da other homepage]]"] URL: http://www.oddmuse.org/ //a[@class="url"][@href="http://www.oddmuse.org/"][text()="http://www.oddmuse.org/"] URL in text http://www.oddmuse.org/ like this //text()[string()="URL in text "]/following-sibling::a[@class="url"][@href="http://www.oddmuse.org/"][text()="http://www.oddmuse.org/"]/following-sibling::text()[string()=" like this"] URL in brackets: [http://www.oddmuse.org/] //a[@class="url number"][@href="http://www.oddmuse.org/"]/span/span[@class="bracket"][text()="["]/following-sibling::text()[string()="1"]/following-sibling::span[@class="bracket"][text()="]"] URL in brackets with other text: [http://www.oddmuse.org/ oddmuse] //a[@class="url outside"][@href="http://www.oddmuse.org/"][text()="oddmuse"] URL abbreviation: Oddmuse:Link_Pattern //a[@class="inter"][@href="http://www.emacswiki.org/cgi-bin/oddmuse.pl?Link_Pattern"]/span[@class="site"][text()="Oddmuse"]/following-sibling::text()[string()=":"]/following-sibling::span[@class="page"][text()="Link_Pattern"] URL abbreviation with extra brackets: [Oddmuse:Link_Pattern] //a[@class="inter number"][@href="http://www.emacswiki.org/cgi-bin/oddmuse.pl?Link_Pattern"]/span/span[@class="bracket"][text()="["]/following-sibling::text()[string()="1"]/following-sibling::span[@class="bracket"][text()="]"] URL abbreviation with other text: [Oddmuse:Link_Pattern link patterns] //a[@class="inter outside"][@href="http://www.emacswiki.org/cgi-bin/oddmuse.pl?Link_Pattern"][text()="link patterns"] URL abbreviation with meta characters: Oddmuse:Link+Pattern //a[@class="inter"][@href="http://www.emacswiki.org/cgi-bin/oddmuse.pl?Link+Pattern"]/span[@class="site"][text()="Oddmuse"]/following-sibling::text()[string()=":"]/following-sibling::span[@class="page"][text()="Link+Pattern"] URL abbreviation with meta characters and extra brackets: [Oddmuse:Link+Pattern] //a[@class="inter number"][@href="http://www.emacswiki.org/cgi-bin/oddmuse.pl?Link+Pattern"]/span/span[@class="bracket"][text()="["]/following-sibling::text()[string()="1"]/following-sibling::span[@class="bracket"][text()="]"] URL abbreviation with meta characters and other text: [Oddmuse:Link+Pattern link patterns] //a[@class="inter outside"][@href="http://www.emacswiki.org/cgi-bin/oddmuse.pl?Link+Pattern"][text()="link patterns"] free URL abbreviation: [[Oddmuse:Link Pattern]] //a[@class="inter"][@href="http://www.emacswiki.org/cgi-bin/oddmuse.pl?Link%20Pattern"]/span[@class="site"][text()="Oddmuse"]/following-sibling::text()[string()=":"]/following-sibling::span[@class="page"][text()="Link Pattern"] free URL abbreviation with extra brackets: [[[Oddmuse:Link Pattern]]] //a[@class="inter number"][@href="http://www.emacswiki.org/cgi-bin/oddmuse.pl?Link%20Pattern"]/span/span[@class="bracket"][text()="["]/following-sibling::text()[string()="1"]/following-sibling::span[@class="bracket"][text()="]"] free URL abbreviation with other text: [[Oddmuse:Link Pattern|link patterns]] //a[@class="inter outside"][@href="http://www.emacswiki.org/cgi-bin/oddmuse.pl?Link%20Pattern"][text()="link patterns"] free URL abbreviation with meta characters: [[Oddmuse:Link+Pattern]] //a[@class="inter"][@href="http://www.emacswiki.org/cgi-bin/oddmuse.pl?Link%2bPattern"]/span[@class="site"][text()="Oddmuse"]/following-sibling::text()[string()=":"]/following-sibling::span[@class="page"][text()="Link+Pattern"] free URL abbreviation with meta characters and extra brackets: [[[Oddmuse:Link+Pattern]]] //a[@class="inter number"][@href="http://www.emacswiki.org/cgi-bin/oddmuse.pl?Link%2bPattern"]/span/span[@class="bracket"][text()="["]/following-sibling::text()[string()="1"]/following-sibling::span[@class="bracket"][text()="]"] free URL abbreviation with meta characters and other text: [[Oddmuse:Link+Pattern|link patterns]] //a[@class="inter outside"][@href="http://www.emacswiki.org/cgi-bin/oddmuse.pl?Link%2bPattern"][text()="link patterns"] EOT xpath_run_tests(); $AllNetworkFiles = 0; $BracketWiki = 1; %Test = split('\n',<<'EOT'); traditional local link: HomePage //a[@class="local"][@href="http://localhost/test.pl/HomePage"][text()="HomePage"] traditional local link: OtherPage //a[@class="edit"][@title="Click to edit this page"][@href="http://localhost/test.pl?action=edit;id=OtherPage"][text()="?"] traditional local link with extra brackets: [HomePage] //a[@class="local number"][@title="HomePage"][@href="http://localhost/test.pl/HomePage"]/span/span[@class="bracket"][text()="["]/following-sibling::text()[string()="1"]/following-sibling::span[@class="bracket"][text()="]"] traditional local link with extra brackets: [OtherPage] //a[@class="edit"][@title="Click to edit this page"][@href="http://localhost/test.pl?action=edit;id=OtherPage"][text()="?"] traditional local link with other text: [HomePage homepage] //a[@class="local"][@href="http://localhost/test.pl/HomePage"][text()="homepage"] traditional local link with other text: [OtherPage other page] //a[@class="edit"][@title="Click to edit this page"][@href="http://localhost/test.pl?action=edit;id=OtherPage"][text()="?"] free link: [[home page]] //a[@class="edit"][@title="Click to edit this page"][@href="http://localhost/test.pl?action=edit;id=home_page"][text()="?"] free link: [[other page]] //a[@class="edit"][@title="Click to edit this page"][@href="http://localhost/test.pl?action=edit;id=other_page"][text()="?"] free link with extra brackets: [[[home page]]] //a[@class="edit"][@title="Click to edit this page"][@href="http://localhost/test.pl?action=edit;id=home_page"][text()="?"] free link with extra brackets: [[[other page]]] //a[@class="edit"][@title="Click to edit this page"][@href="http://localhost/test.pl?action=edit;id=other_page"][text()="?"] free link with other text: [[home page|da homepage]] //a[@class="edit"][@title="Click to edit this page"][@href="http://localhost/test.pl?action=edit;id=home_page"][text()="?"] free link with other text: [[other page|da other homepage]] //a[@class="edit"][@title="Click to edit this page"][@href="http://localhost/test.pl?action=edit;id=other_page"][text()="?"] URL: http://www.oddmuse.org/ //a[@class="url"][@href="http://www.oddmuse.org/"][text()="http://www.oddmuse.org/"] URL in brackets: [http://www.oddmuse.org/] //a[@class="url number"][@href="http://www.oddmuse.org/"]/span/span[@class="bracket"][text()="["]/following-sibling::text()[string()="1"]/following-sibling::span[@class="bracket"][text()="]"] URL in brackets with other text: [http://www.oddmuse.org/ oddmuse] //a[@class="url outside"][@href="http://www.oddmuse.org/"][text()="oddmuse"] URL abbreviation: Oddmuse:Link_Pattern //a[@class="inter"][@href="http://www.emacswiki.org/cgi-bin/oddmuse.pl?Link_Pattern"]/span[@class="site"][text()="Oddmuse"]/following-sibling::text()[string()=":"]/following-sibling::span[@class="page"][text()="Link_Pattern"] URL abbreviation with extra brackets: [Oddmuse:Link_Pattern] //a[@class="inter number"][@href="http://www.emacswiki.org/cgi-bin/oddmuse.pl?Link_Pattern"]/span/span[@class="bracket"][text()="["]/following-sibling::text()[string()="1"]/following-sibling::span[@class="bracket"][text()="]"] URL abbreviation with other text: [Oddmuse:Link_Pattern link patterns] //a[@class="inter outside"][@href="http://www.emacswiki.org/cgi-bin/oddmuse.pl?Link_Pattern"][text()="link patterns"] free URL abbreviation: [[Oddmuse:Link Pattern]] //a[@class="inter"][@href="http://www.emacswiki.org/cgi-bin/oddmuse.pl?Link%20Pattern"]/span[@class="site"][text()="Oddmuse"]/following-sibling::text()[string()=":"]/following-sibling::span[@class="page"][text()="Link Pattern"] free URL abbreviation with extra brackets: [[[Oddmuse:Link Pattern]]] //a[@class="inter number"][@href="http://www.emacswiki.org/cgi-bin/oddmuse.pl?Link%20Pattern"]/span/span[@class="bracket"][text()="["]/following-sibling::text()[string()="1"]/following-sibling::span[@class="bracket"][text()="]"] free URL abbreviation with other text: [[Oddmuse:Link Pattern|link pattern]] //a[@class="inter outside"][@href="http://www.emacswiki.org/cgi-bin/oddmuse.pl?Link%20Pattern"][text()="link pattern"] EOT xpath_run_tests(); $BracketWiki = 0; # -------------------- markup: print '[markup]'; clear_pages(); update_page('InterMap', " OddMuse http://www.emacswiki.org/cgi-bin/oddmuse.pl?\n PlanetMath http://planetmath.org/encyclopedia/%s.html", 'required', 0, 1); $InterInit = 0; InitVariables(); # non links $NetworkFile = 1; %Test = split('\n',<<'EOT'); do not eat 0 from text do not eat 0 from text ordinary text ordinary text paragraph\n\nparagraph paragraph

    paragraph

    * one\n*two
    • one *two
    * one\n\n*two
    • one

    *two

    * one\n** two
    • one
      • two
    * one\n** two\n*** three\n* four
    • one
      • two
        • three
    • four
    * one\n** two\n*** three\n* four\n** five\n* six
    • one
      • two
        • three
    • four
      • five
    • six
    * one\n* two\n** one and two\n** two and three\n* three
    • one
    • two
      • one and two
      • two and three
    • three
    * one and *\n* two and * more
    • one and *
    • two and * more
    Foo::Bar Foo::Bar !WikiLink WikiLink !foo !foo file:///home/foo/tutorial.pdf file:///home/foo/tutorial.pdf named entities: > named entities: > garbage: & garbage: & numbered entity: { numbered entity: { numbered hex entity: ģ numbered hex entity: ģ named entity: © named entity: © quoted named entity: &copy; quoted named entity: &copy; EOT run_tests(); test_page(update_page('entity', 'quoted named entity: &copy;'), 'quoted named entity: &copy;'); # links and other attributes containing attributes %Smilies = ('HAHA!' => '/pics/haha.png'); %Test = split('\n',<<'EOT'); HAHA! //img[@class="smiley"][@src="/pics/haha.png"][@alt="HAHA!"] WikiWord //a[@class="edit"][@title="Click to edit this page"][@href="http://localhost/test.pl?action=edit;id=WikiWord"][text()="?"] WikiWord: //a[@class="edit"][@title="Click to edit this page"][@href="http://localhost/test.pl?action=edit;id=WikiWord"][text()="?"]/following-sibling::text()[string()=":"] OddMuse //a[@class="edit"][@title="Click to edit this page"][@href="http://localhost/test.pl?action=edit;id=OddMuse"][text()="?"] OddMuse: //a[@class="edit"][@title="Click to edit this page"][@href="http://localhost/test.pl?action=edit;id=OddMuse"][text()="?"]/following-sibling::text()[string()=":"] OddMuse:test //a[@class="inter"][@href="http://www.emacswiki.org/cgi-bin/oddmuse.pl?test"]/span[@class="site"][text()="OddMuse"]/following-sibling::text()[string()=":"]/following-sibling::span[@class="page"][text()="test"] OddMuse:test: or not //a[@class="inter"][@href="http://www.emacswiki.org/cgi-bin/oddmuse.pl?test"]/span[@class="site"][text()="OddMuse"]/following-sibling::text()[string()=":"]/following-sibling::span[@class="page"][text()="test"] OddMuse:test, and foo //a[@class="inter"][@href="http://www.emacswiki.org/cgi-bin/oddmuse.pl?test"]/span[@class="site"][text()="OddMuse"]/following-sibling::text()[string()=":"]/following-sibling::span[@class="page"][text()="test"] PlanetMath:ZipfsLaw, and foo //a[@class="inter"][@href="http://planetmath.org/encyclopedia/ZipfsLaw.html"]/span[@class="site"][text()="PlanetMath"]/following-sibling::text()[string()=":"]/following-sibling::span[@class="page"][text()="ZipfsLaw"] [OddMuse:test] //a[@class="inter number"][@href="http://www.emacswiki.org/cgi-bin/oddmuse.pl?test"]/span/span[@class="bracket"][text()="["]/following-sibling::text()[string()="1"]/following-sibling::span[@class="bracket"][text()="]"] ![[Free Link]] //a[@class="edit"][@title="Click to edit this page"][@href="http://localhost/test.pl?action=edit;id=Free_Link"][text()="?"] http://www.emacswiki.org //a[@class="url"][@href="http://www.emacswiki.org"][text()="http://www.emacswiki.org"] //text()[string()="<"]/following-sibling::a[@class="url"][@href="http://www.emacswiki.org"][text()="http://www.emacswiki.org"]/following-sibling::text()[string()=">"] http://www.emacswiki.org/ //a[@class="url"][@href="http://www.emacswiki.org/"][text()="http://www.emacswiki.org/"] http://www.emacswiki.org. //a[@class="url"][@href="http://www.emacswiki.org"][text()="http://www.emacswiki.org"]/following-sibling::text()[string()="."] http://www.emacswiki.org, //a[@class="url"][@href="http://www.emacswiki.org"][text()="http://www.emacswiki.org"]/following-sibling::text()[string()=","] http://www.emacswiki.org; //a[@class="url"][@href="http://www.emacswiki.org"][text()="http://www.emacswiki.org"]/following-sibling::text()[string()=";"] http://www.emacswiki.org: //a[@class="url"][@href="http://www.emacswiki.org"][text()="http://www.emacswiki.org"]/following-sibling::text()[string()=":"] http://www.emacswiki.org? //a[@class="url"][@href="http://www.emacswiki.org"][text()="http://www.emacswiki.org"]/following-sibling::text()[string()="?"] http://www.emacswiki.org/? //a[@class="url"][@href="http://www.emacswiki.org/"][text()="http://www.emacswiki.org/"]/following-sibling::text()[string()="?"] http://www.emacswiki.org! //a[@class="url"][@href="http://www.emacswiki.org"][text()="http://www.emacswiki.org"]/following-sibling::text()[string()="!"] http://www.emacswiki.org' //a[@class="url"][@href="http://www.emacswiki.org"][text()="http://www.emacswiki.org"]/following-sibling::text()[string()="'"] http://www.emacswiki.org" //a[@class="url"][@href="http://www.emacswiki.org"][text()="http://www.emacswiki.org"]/following-sibling::text()[string()='"'] http://www.emacswiki.org! //a[@class="url"][@href="http://www.emacswiki.org"][text()="http://www.emacswiki.org"]/following-sibling::text()[string()="!"] http://www.emacswiki.org( //a[@class="url"][@href="http://www.emacswiki.org"][text()="http://www.emacswiki.org"]/following-sibling::text()[string()="("] http://www.emacswiki.org) //a[@class="url"][@href="http://www.emacswiki.org"][text()="http://www.emacswiki.org"]/following-sibling::text()[string()=")"] http://www.emacswiki.org& //a[@class="url"][@href="http://www.emacswiki.org"][text()="http://www.emacswiki.org"]/following-sibling::text()[string()="&"] http://www.emacswiki.org# //a[@class="url"][@href="http://www.emacswiki.org"][text()="http://www.emacswiki.org"]/following-sibling::text()[string()="#"] http://www.emacswiki.org% //a[@class="url"][@href="http://www.emacswiki.org"][text()="http://www.emacswiki.org"]/following-sibling::text()[string()="%"] [http://www.emacswiki.org] //a[@class="url number"][@href="http://www.emacswiki.org"]/span/span[@class="bracket"][text()="["]/following-sibling::text()[string()="1"]/following-sibling::span[@class="bracket"][text()="]"] [http://www.emacswiki.org] and [http://www.emacswiki.org] //a[@class="url number"][@href="http://www.emacswiki.org"]/span/span[@class="bracket"][text()="["]/following-sibling::text()[string()="1"]/following-sibling::span[@class="bracket"][text()="]"]/../../following-sibling::text()[string()=" and "]/following-sibling::a[@class="url number"][@href="http://www.emacswiki.org"]/span/span[@class="bracket"][text()="["]/following-sibling::text()[string()="2"]/following-sibling::span[@class="bracket"][text()="]"] [http://www.emacswiki.org], //a[@class="url number"][@href="http://www.emacswiki.org"]/span/span[@class="bracket"][text()="["]/following-sibling::text()[string()="1"]/following-sibling::span[@class="bracket"][text()="]"] [http://www.emacswiki.org and a label] //a[@class="url outside"][@href="http://www.emacswiki.org"][text()="and a label"] [file://home/foo/tutorial.pdf local link] //a[@class="url outside"][@href="file://home/foo/tutorial.pdf"][text()="local link"] file://home/foo/tutorial.pdf //a[@class="url"][@href="file://home/foo/tutorial.pdf"][text()="file://home/foo/tutorial.pdf"] mailto:alex@emacswiki.org //a[@class="url"][@href="mailto:alex@emacswiki.org"][text()="mailto:alex@emacswiki.org"] EOT xpath_run_tests(); $NetworkFile = 0; # -------------------- usemod_module: print '[usemod module]'; clear_pages(); do 'modules/usemod.pl'; InitVariables(); %Test = split('\n',<<'EOT'); * ''one\n** two
    • one
      • two
    # one\n# two
    1. one
    2. two
    * one\n# two
    • one
    1. two
    # one\n\n#two
    1. one

    #two

    # one\n# two\n## one and two\n## two and three\n# three
    1. one
    2. two
      1. one and two
      2. two and three
    3. three
    # one and #\n# two and # more
    1. one and #
    2. two and # more
    : one\n: two\n:: one and two\n:: two and three\n: three
    one
    two
    one and two
    two and three
    three
    : one and :)\n: two and :) more
    one and :)
    two and :) more
    : one\n\n:two
    one

    :two

    ; one:eins\n;two:zwei
    one
    eins ;two:zwei
    ; one:eins\n\n; two:zwei
    one
    eins
    two
    zwei
    ; a: b: c\n;; x: y: z
    a
    b: c
    x
    y: z
    * foo bold\n* bar
    • foo bold
    • bar </b>
    This is ''emphasized''. This is emphasized. This is '''strong'''. This is strong. This is ''longer emphasized'' text. This is longer emphasized text. This is '''longer strong''' text. This is longer strong text. This is '''''emphasized and bold''''' text. This is emphasized and bold text. This is ''emphasized '''and bold''''' text. This is emphasized and bold text. This is '''bold ''and emphasized''''' text. This is bold and emphasized text. This is ''emphasized text containing '''longer strong''' text''. This is emphasized text containing longer strong text. This is '''strong text containing ''emph'' text'''. This is strong text containing emph text. ||one||
    one
    ||one||
    one
    || one ''two'' ||
    one two
    || one two ||
    one two
    introduction\n\n||one||two||three||\n||||one two||three|| introduction
    onetwothree
    one twothree
    ||one||two||three||\n||||one two||three||\n\nfooter
    onetwothree
    one twothree

    footer

    ||one||two||three||\n||||one two||three||\n\nfooter
    onetwothree
    one twothree

    footer

    || one|| two|| three||\n|||| one two|| three||\n\nfooter
    onetwothree
    one twothree

    footer

    ||one ||two ||three ||\n||||one two ||three ||\n\nfooter
    one two three
    one two three

    footer

    || one || two || three ||\n|||| one two || three ||\n\nfooter
    one two three
    one two three

    footer

    introduction\n\n||one||two||three||\n||||one two||three||\n\nfooter introduction
    onetwothree
    one twothree

    footer

    source
     source
    source\n etc\n
     source\n etc
    source\n \n etc\n
     source\n \n etc
    source\n \n etc\n\nother
     source\n \n etc

    other

    = title =

    title

    ==title=

    title

    ========fnord=
    fnord
    == nada\nnada == == nada nada == == nada ==
     == nada ==
    ==[[Free Link]]==

    [[Free Link]]

    EOT run_tests(); remove_rule(\&UsemodRule); # -------------------- usemod_options: print '[usemod options]'; # some patterns use options in regular expressions with /o and need to be recompiled do 'modules/usemod.pl'; $UseModSpaceRequired = 0; $UseModMarkupInTitles = 1; InitVariables(); %Test = split('\n',<<'EOT'); *one\n**two
    • one
      • two
    #one\n##two
    1. one
      1. two
    :one\n:two\n::one and two\n::two and three\n:three
    one
    two
    one and two
    two and three
    three
    ;one:eins\n;two:zwei
    one
    eins
    two
    zwei
    =='''title'''==

    title

    1 \+ 1 = 2 1 \+ 1 = 2 EOT run_tests(); %Test = split('\n',<<'EOT'); ==[[Free Link]]== //h2/text()[string()="[Free Link]"]/following-sibling::a[@class="edit"][@title="Click to edit this page"][@href="http://localhost/test.pl?action=edit;id=Free_Link"][text()="?"] EOT xpath_run_tests(); $UseModSpaceRequired = 1; $UseModMarkupInTitles = 0; remove_rule(\&UsemodRule); # -------------------- markup_module: print '[markup module]'; do 'modules/usemod.pl'; do 'modules/markup.pl'; InitVariables(); %Test = split('\n',<<'EOT'); foo foo /foo/ foo 5km/h or 6km/h 5km/h or 6km/h /foo/ bar foo bar /foo bar 5/ foo bar 5 6/22/2004 6/22/2004 #!/bin/sh #!/bin/sh put it in ~/elisp/ put it in ~/elisp/ see /usr/bin/ see /usr/bin/ to /usr/local/share/perl/! to /usr/local/share/perl/! we shall laugh/cry/run around naked we shall laugh/cry/run around naked da *foo* da foo da *foo bar 6* da foo bar 6 _foo_ foo foo_bar_baz foo_bar_baz _foo bar 4_ foo bar 4 this -> that this → that and this... and this… foo---bar foo—bar foo -- bar foo – bar foo\n----\nbar foo

    bar

    foo ##bar+## baz foo bar+ baz foo %%bar+%% baz foo bar+ baz ##http://www.example.com## http://www.example.com %%http://www.example.com%% http://www.example.com and **this\nis!** me and this\nis! me and //this\nis!// me and this\nis! me and __this\nis!__ me and this\nis! me and ~~this\nis!~~ me and this\nis! me um\n{{{code}}} here um code here um\n{{{code\n\nmore code}}} here um code\n\nmore code here or //this// and\n//that// or this and that __ and 7000 chars xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx __ and 7000 chars xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx ______ ______ ____ and __ ____ and __ //// and // //// and // i think //the paragraph should be the limit\n\nright?// i think //the paragraph should be the limit

    right?//

    EOT run_tests(); remove_rule(\&UsemodRule); remove_rule(\&MarkupRule); # -------------------- setext_module: print '[setext module]'; clear_pages(); # link-all will confuse us do 'modules/setext.pl'; do 'modules/link-all.pl'; %Test = split('\n',<<'EOT'); foo foo ~foo~ foo da *foo* da *foo* da **foo** bar da foo bar da `_**foo**_` bar da **foo** bar _foo_ foo foo_bar_baz foo_bar_baz _foo_bar_ baz foo bar baz and\nfoo\n===\n\nmore\n and

    foo

    more

    and\n\nfoo\n===\n\nmore\n and

    foo

    more

    and\nfoo \n--- \n\nmore\n and

    foo

    more

    and\nfoo\n---\n\nmore\n and

    foo

    more

    EOT run_tests(); *GetGotoBar = *OldLinkAllGetGotoBar; remove_rule(\&SeTextRule); remove_rule(\&LinkAllRule); # -------------------- anchors_module: print '[anchors module]'; do 'modules/anchors.pl'; do 'modules/link-all.pl'; # check compatibility %Test = split('\n',<<'EOT'); This is a [:day for fun and laughter]. //a[@class="anchor"][@name="day_for_fun_and_laughter"] [[#day for fun and laughter]]. //a[@class="local anchor"][@href="#day_for_fun_and_laughter"][text()="day for fun and laughter"] [[2004-08-17#day for fun and laughter]]. //a[@class="local anchor"][@href="http://localhost/test.pl/2004-08-17#day_for_fun_and_laughter"][text()="2004-08-17#day for fun and laughter"] [[[#day for fun and laughter]]]. //text()[string()="["]/following-sibling::a[@class="local anchor"][@href="#day_for_fun_and_laughter"][text()="day for fun and laughter"]/following-sibling::text()[string()="]."] [[[2004-08-17#day for fun and laughter]]]. //a[@class="local anchor number"][@title="2004-08-17#day_for_fun_and_laughter"][@href="http://localhost/test.pl/2004-08-17#day_for_fun_and_laughter"]/span/span[@class="bracket"][text()="["]/following-sibling::text()[string()="1"]/following-sibling::span[@class="bracket"][text()="]"] EOT xpath_run_tests(); %Test = split('\n',<<'EOT'); [[#day for fun and laughter|boo]]. [[#day for fun and laughter|boo]]. [[2004-08-17#day for fun and laughter|boo]]. [[2004-08-17#day for fun and laughter|boo]]. EOT run_tests(); $BracketWiki = 1; %Test = split('\n',<<'EOT'); [[2004-08-17#day for fun and laughter|boo]]. //a[@class="local anchor"][@href="http://localhost/test.pl/2004-08-17#day_for_fun_and_laughter"][text()="boo"] EOT xpath_run_tests(); $BracketWiki = 0; remove_rule(\&AnchorsRule); remove_rule(\&LinkAllRule); # -------------------- link_all_module: print '[link-all module]'; clear_pages(); add_module('link-all.pl'); update_page('foo', 'link-all for bar'); xpath_test(get_page('action=browse define=1 id=foo'), '//a[@class="edit"][@title="Click to edit this page"][@href="http://localhost/wiki.pl?action=edit;id=bar"][text()="bar"]'); %Test = split('\n',<<'EOT'); testing foo. //a[@class="local"][@href="http://localhost/test.pl/foo"][text()="foo"] EOT xpath_run_tests(); *GetGotoBar = *OldLinkAllGetGotoBar; remove_rule(\&LinkAllRule); remove_module('link-all.pl'); # -------------------- image_module: print '[image module]'; do "modules/image.pl"; clear_pages(); update_page('bar', 'foo'); %Test = split('\n',<<'EOT'); [[image:foo]] //a[@class="edit"][@title="Click to edit this page"][@href="http://localhost/test.pl?action=edit;id=foo;upload=1"][text()="?"] [[image:bar]] //a[@class="image"][@href="http://localhost/test.pl/bar"]/img[@class="upload"][@src="http://localhost/test.pl/download/bar"][@alt="bar"] [[image:bar|alternative text]] //a[@class="image"][@href="http://localhost/test.pl/bar"]/img[@class="upload"][@src="http://localhost/test.pl/download/bar"][@alt="alternative text"] [[image/left:bar|alternative text]] //a[@class="image left"][@href="http://localhost/test.pl/bar"]/img[@class="upload"][@title="alternative text"][@src="http://localhost/test.pl/download/bar"][@alt="alternative text"] [[image:bar|alternative text|foo]] //a[@class="image"][@href="http://localhost/test.pl/foo"]/img[@class="upload"][@title="alternative text"][@src="http://localhost/test.pl/download/bar"][@alt="alternative text"] [[image/left:bar|alternative text|foo]] //a[@class="image left"][@href="http://localhost/test.pl/foo"]/img[@class="upload"][@title="alternative text"][@src="http://localhost/test.pl/download/bar"][@alt="alternative text"] [[image/left:bar|alternative text|http://www.foo.com/]] //a[@class="image left outside"][@href="http://www.foo.com/"]/img[@class="upload"][@title="alternative text"][@src="http://localhost/test.pl/download/bar"][@alt="alternative text"] EOT xpath_run_tests(); remove_rule(\&ImageSupportRule); # -------------------- subscriberc_module: print '[subscriberc module]'; # test together with link-all module add_module('subscriberc.pl'); %Test = split('\n',<<'EOT'); My subscribed pages: AlexSchroeder. My subscribed pages: AlexSchroeder. My subscribed pages: AlexSchroeder, [[LionKimbro]], [[Foo bar]]. My subscribed pages: AlexSchroeder, LionKimbro, Foo bar. My subscribed categories: CategoryDecisionMaking, CategoryBar. My subscribed categories: CategoryDecisionMaking, CategoryBar. My subscribed pages: AlexSchroeder, [[LionKimbro]], [[Foo bar]], categories: CategoryDecisionMaking. My subscribed pages: AlexSchroeder, LionKimbro, Foo bar, categories: CategoryDecisionMaking. EOT run_tests(); remove_rule(\&SubscribedRecentChangesRule); # -------------------- toc_module: print '[toc module]'; add_module('toc.pl'); add_module('usemod.pl'); InitVariables(); %Test = split('\n',<<'EOT'); == make honey ==\n\nMoo.\n

    make honey

    Moo.

    EOT run_tests(); test_page(update_page('toc', "bla\n" . "=one=\n" . "blarg\n" . "==two==\n" . "bla\n" . "==two==\n" . "mu."), quotemeta('
    1. one
      1. two
      2. two
    '), quotemeta('

    one

    '), quotemeta('

    two

    '), quotemeta('bla

    Contents

  • two
    1. three
  • two
  • '), quotemeta('

    two

    '), quotemeta('

    three

    ')); test_page(update_page('toc', "bla\n" . "\n" . "murks\n" . "==two=\n" . "bla\n" . "===three==\n" . "bla\n" . "=one=\n"), quotemeta('
    1. two
      1. three
    2. one
    '), quotemeta('

    two

    '), quotemeta('

    one

    '), quotemeta('bla

    Contents

    murks'),); remove_rule(\&UsemodRule); remove_rule(\&TocRule); # -------------------- comments: print '[comments]'; clear_pages(); AppendStringToFile($ConfigFile, "\$CommentsPrefix = 'Comments on ';\n"); get_page('title=Yadda', 'aftertext=This%20is%20my%20comment.', 'username=Alex'); test_page(get_page('Yadda'), 'Describe the new page'); get_page('title=Comments_on_Yadda', 'aftertext=This%20is%20my%20comment.', 'username=Alex'); test_page(get_page('Comments_on_Yadda'), 'This is my comment\.', '-- Alex'); get_page('title=Comments_on_Yadda', 'aftertext=This%20is%20another%20comment.', 'username=Alex', 'homepage=http%3a%2f%2fwww%2eoddmuse%2eorg%2f'); xpath_test(get_page('Comments_on_Yadda'), '//p[contains(text(),"This is my comment.")]', '//a[@class="url outside"][@href="http://www.oddmuse.org/"][text()="Alex"]'); # -------------------- headers: print '[headers in various modules]'; clear_pages(); # without portrait-support # nothing update_page('headers', "== no header ==\n\ntext\n"); test_page(get_page('headers'), '== no header =='); # usemod only add_module('usemod.pl'); update_page('headers', "== is header ==\n\ntext\n"); test_page(get_page('headers'), '

    is header

    '); remove_rule(\&UsemodRule); # toc only add_module('toc.pl'); update_page('headers', "== one ==\ntext\n== two ==\ntext\n== three ==\ntext\n"); test_page(get_page('headers'), '
  • one
  • ', '
  • two
  • ', '

    one

    ', '

    two

    ', ); remove_rule(\&TocRule); # headers only add_module('headers.pl'); update_page('headers', "is header\n=========\n\ntext\n"); test_page(get_page('headers'), '

    is header

    '); remove_rule(\&HeadersRule); # -------------------- print '[with portrait support]'; clear_pages(); add_module('portrait-support.pl'); # nothing update_page('headers', "[new]foo\n== no header ==\n\ntext\n"); test_page(get_page('headers'), '

    foo == no header ==

    text

    '); # usemod only add_module('usemod.pl'); update_page('headers', "[new]foo\n== is header ==\n\ntext\n"); test_page(get_page('headers'), '

    foo

    is header

    '); remove_rule(\&UsemodRule); # toc only add_module('toc.pl'); update_page('headers', "[new]foo\n== one ==\ntext\n== two ==\ntext\n== three ==\ntext\n"); test_page(get_page('headers'), '

    foo

    ', # default to before the header '

    Contents

      ', '
    1. one
    2. ', '
    3. two
    4. ', '
    5. three
    ', '

    one

    text

    ', '

    two

    ', ); remove_rule(\&TocRule); # headers only add_module('headers.pl'); update_page('headers', "[new]foo\nis header\n=========\n\ntext\n"); test_page(get_page('headers'), '

    foo

    is header

    '); remove_rule(\&HeadersRule); # portrait-support, toc, and usemod add_module('usemod.pl'); add_module('toc.pl'); update_page('headers', "[new]foo\n== one ==\ntext\n== two ==\ntext\n== three ==\ntext\n"); test_page(get_page('headers'), '
  • one
  • ', '
  • two
  • ', '

    foo

    ', '

    one

    ', '

    two

    ', ); remove_rule(\&UsemodRule); remove_rule(\&TocRule); *GetHeader = *OldTocGetHeader; remove_rule(\&PortraitSupportRule); *ApplyRules = *OldPortraitSupportApplyRules; # -------------------- hr: print '[hr in various modules]'; clear_pages(); # without portrait-support # nothing update_page('hr', "one\n----\ntwo\n"); test_page(get_page('hr'), 'one ---- two'); # usemod only add_module('usemod.pl'); update_page('hr', "one\n----\nthree\n"); test_page(get_page('hr'), '

    one


    three

    '); remove_rule(\&UsemodRule); # headers only add_module('headers.pl'); update_page('hr', "one\n----\ntwo\n"); test_page(get_page('hr'), '

    one

    two

    '); update_page('hr', "one\n\n----\nthree\n"); test_page(get_page('hr'), '

    one


    three

    '); remove_rule(\&HeadersRule); # -------------------- print '[with portrait support]'; clear_pages(); add_module('portrait-support.pl'); # just portrait-support update_page('hr', "[new]one\n----\ntwo\n"); test_page(get_page('hr'), '

    one


    two

    '); # usemod and portrait-support add_module('usemod.pl'); update_page('hr', "one\n----\nthree\n"); test_page(get_page('hr'), '

    one


    three

    '); unlink('/tmp/oddmuse/modules/usemod.pl') or die "Cannot unlink: $!"; remove_rule(\&UsemodRule); # headers and portrait-support add_module('headers.pl'); update_page('hr', "one\n----\ntwo\n"); test_page(get_page('hr'), '

    one

    two

    '); update_page('hr', "one\n\n----\nthree\n"); test_page(get_page('hr'), '

    one


    three

    '); unlink('/tmp/oddmuse/modules/headers.pl') or die "Cannot unlink: $!"; remove_rule(\&HeadersRule); remove_rule(\&PortraitSupportRule); *ApplyRules = *OldPortraitSupportApplyRules; # -------------------- calendar: print '[calendar]'; clear_pages(); my ($sec, $min, $hour, $mday, $mon, $year) = localtime($Now); $mon++; $year += 1900; my $year_next = $year +1; my $year_prev = $year -1; my $today = sprintf("%d-%02d-%02d", $year, $mon, $mday); $oday = $mday -1; $oday += 2 if $oday < 1; my $otherday = sprintf("%d-%02d-%02d", $year, $mon, $oday); add_module('calendar.pl'); xpath_test(get_page('action=calendar'), # yearly navigation '//div[@class="content cal year"]/p[@class="nav"]/a[@href="http://localhost/wiki.pl?action=calendar;year=' . $year_prev . '"][text()="Previous"]/following-sibling::text()[string()=" | "]/following-sibling::a[@href="http://localhost/wiki.pl?action=calendar;year=' . $year_next . '"][text()="Next"]', # monthly collection '//div[@class="cal month"]/pre/span[@class="title"]/a[@class="local collection month"][@href="http://localhost/wiki.pl?action=collect;match=' . sprintf("%d-%02d", $year, $mon) . '"]', # today day edit '//a[@class="edit today"][@href="http://localhost/wiki.pl?action=edit;id=' . $today . '"][normalize-space(text())="' . $mday . '"]', # other day edit '//a[@class="edit"][@href="http://localhost/wiki.pl?action=edit;id=' . $otherday . '"][normalize-space(text())="' . $oday . '"]', ); update_page($today, "yadda"); xpath_test(get_page('action=calendar'), # day exact match '//a[@class="local exact today"][@href="http://localhost/wiki.pl/' . $today . '"][normalize-space(text())="' . $mday . '"]'); update_page("${today}_more", "more yadda"); xpath_test(get_page('action=calendar'), # today exact match '//a[@class="local collection today"][@href="http://localhost/wiki.pl?action=collect;match=' . $today . '"][normalize-space(text())="' . $mday . '"]'); remove_rule(\&CalendarRule); *GetHeader = *OldCalendarGetHeader; # -------------------- crumbs: print '[crumbs]'; clear_pages(); AppendStringToFile($ConfigFile, "\$PageCluster = 'Cluster';\n"); add_module('crumbs.pl'); update_page("HomePage", "Has to do with [[Software]]."); update_page("Software", "[[HomePage]]\n\nCheck out [[Games]]."); update_page("Games", "[[Software]]\n\nThis is it."); xpath_test(get_page('Games'), '//p/span[@class="crumbs"]/a[@class="local"][@href="http://localhost/wiki.pl/HomePage"][text()="HomePage"]/following-sibling::text()[string()=" "]/following-sibling::a[@class="local"][@href="http://localhost/wiki.pl/Software"][text()="Software"]'); remove_rule(\&CrumbsRule); # -------------------- long_table: print '[long table]'; clear_pages(); add_module('tables-long.pl'); %Test = split('\n',<<'EOT'); \na=a\nb=b\na=one\nb=two
    ab
    onetwo
    \na=a\nb=b\na=one\nb=two\n----
    ab
    onetwo
    \na=a\nb=b\na=one\nb=two\n----\n\nDone.
    ab
    onetwo

    Done.

    Here is a table:\n\na=a\nb=b\na=one\ntwo\nand a half\nb=three\na=foo\nb=bar\n----\n\nDone.\n
    \nfoo=test\nbar=test as well\nfoo=what we test\n----\nthe end. Here is a table:
    ab
    one two and a halfthree
    foobar

    Done.

    testtest as well
    what we test

    the end.

    \na=a\nb=b\na=one\nb/2=odd\na=three
    ab
    oneodd
    three
    \na=a\nb=b\nc=c\na=one\nb/2=odd\nc=two\na=three\nc=four
    abc
    oneoddtwo
    threefour
    \na=a\nb=b\nc=c\na=one\nb=two\nc/2=numbers\na=three\n
    abc
    onetwonumbers
    three
    EOT run_tests(); remove_rule(\&TablesLongRule); # -------------------- tags: print '[tags]'; clear_pages(); add_module('tags.pl'); %Test = split('\n',<<'EOT'); [[tag:foo bar]] //a[@class="outside tag"][@title="Tag"][@href="http://technorati.com/tag/foo%20bar"][@rel="tag"][text()="foo bar"] [[tag:foo bar|mu muh!]] //a[@class="outside tag"][@title="Tag"][@href="http://technorati.com/tag/foo%20bar"][@rel="tag"][text()="mu muh!"] EOT xpath_run_tests(); remove_rule(\&TagsRule); # -------------------- moin: print '[moin]'; clear_pages(); add_module('moin.pl'); %Test = split('\n',<<'EOT'); foo[[BR]]bar //text()[string()="foo"]/following-sibling::br/following-sibling::text()[string()="bar"] ''foo'' //em[text()="foo"] '''bar''' //strong[text()="bar"] [[foo bar]] //a[@class="edit"][@title="Click to edit this page"][@href="http://localhost/test.pl?action=edit;id=foo_bar"][text()="?"] ["foo bar"] //a[@class="edit"][@title="Click to edit this page"][@href="http://localhost/test.pl?action=edit;id=foo_bar"][text()="?"] * one\n* two\n** two.one //ul/li[text()="one"]/following-sibling::li/text()[string()="two"]/following-sibling::ul/li[text()="two.one"] * one\n * two\n * two.one //ul/li[text()="one"]/following-sibling::li/text()[string()="two"]/following-sibling::ul/li[text()="two.one"] * one\n * one.one\n * two //ul/li/text()[string()="one"]/following-sibling::ul/li[text()="one.one"]/../../following-sibling::li[text()="two"] * one\n * one.one\n * two //ul/li/text()[string()="one"]/following-sibling::ul/li[text()="one.one"]/../../following-sibling::li[text()="two"] 1. one\n 1. two\n 1. two.one //ol/li[text()="one"]/following-sibling::li/text()[string()="two"]/following-sibling::ol/li[text()="two.one"] one\n one.one\n two //dl[@class="quote"]/dd/text()[normalize-space(string())="one"]/following-sibling::dl/dd[normalize-space(text())="one.one"]/../../following-sibling::dd[text()="two"] * one\n more\n * two\n more //ul/li[normalize-space(text())="one more"]/following-sibling::li[normalize-space(text())="two more"] * one\n more\n * two\n more //ul/li/text()[normalize-space(string())="one more"]/following-sibling::ul/li[normalize-space(text())="two more"] one\n more\n two\n more //dl[@class="quote"]/dd/text()[normalize-space(string())="one more"]/following-sibling::dl/dd[normalize-space(text())="two more"] {{{\n[[foo bar]]\n}}} //pre[@class="real"][text()="[[foo bar]]\n"] EOT xpath_run_tests(); remove_rule(\&MoinRule); # -------------------- sidebar: print '[sidebar]'; clear_pages(); add_module('sidebar.pl'); test_page(update_page('SideBar', 'mu'), ''); test_page(get_page('HomePage'), ''); print '[with forms]'; # + pagelock + forms add_module('forms.pl'); test_page(update_page('SideBar', '

    mu

    '), ''); xpath_test(get_page('action=pagelock id=SideBar set=1 pwd=foo'), '//p/text()[string()="Lock for "]/following-sibling::a[@href="http://localhost/wiki.pl/SideBar"][@class="local"][text()="SideBar"]/following-sibling::text()[string()=" created."]'); test_page(get_page('SideBar'), ''); # While rendering the SideBar as part of the HomePage, it should still # be considered "locked", and therefore the form should render # correctly. test_page(get_page('HomePage'), ''); # test_page(get_page('HomePage'), ''); get_page('action=pagelock id=SideBar set=0 pwd=foo'); remove_rule(\&FormsRule); print '[with toc]'; add_module('toc.pl'); AppendStringToFile($ConfigFile, "\$TocAutomatic = 0;\n"); update_page('SideBar', "bla\n\n" . "== mu ==\n\n" . "bla"); test_page(update_page('toc', "bla\n" . "\n" . "murks\n" . "==two=\n" . "bla\n" . "===three==\n" . "bla\n" . "=one=\n"), quotemeta('
    1. two
      1. three
    2. one
    '), quotemeta('

    two

    '), quotemeta('

    one

    '), quotemeta('bla

    Contents

    murks')); remove_rule(\&TocRule); *GetHeader = *OldSideBarGetHeader; # -------------------- localnames: print '[localnames]'; clear_pages(); add_module('localnames.pl'); xpath_test(update_page('LocalNames', '* [http://www.oddmuse.org/ OddMuse]'), '//ul/li/a[@class="url outside"][@href="http://www.oddmuse.org/"][text()="OddMuse"]'); InitVariables(); %Test = split('\n',<<'EOT'); [http://www.oddmuse.org/ OddMuse] //a[@class="url outside"][@href="http://www.oddmuse.org/"][text()="OddMuse"] OddMuse //a[@class="near"][@title="LocalNames"][@href="http://www.oddmuse.org/"][text()="OddMuse"] EOT xpath_run_tests(); # now check whether the integration with InitVariables works xpath_test(update_page('LocalNamesTest', 'OddMuse'), '//a[@class="near"][@title="LocalNames"][@href="http://www.oddmuse.org/"][text()="OddMuse"]'); # verify that automatic update is off by default xpath_test(update_page('LocalNamesTest', 'This is an [http://www.example.org/ Example].'), '//a[@class="url outside"][@href="http://www.example.org/"][text()="Example"]'); negative_xpath_test(get_page('LocalNames'), '//ul/li/a[@class="url outside"][@href="http://www.example.org/"][text()="Example"]'); # check automatic update AppendStringToFile($ConfigFile, "\$LocalNamesCollect = 1;\n"); xpath_test(update_page('LocalNamesTest', 'This is an [http://www.example.com/ Example].'), '//a[@class="url outside"][@href="http://www.example.com/"][text()="Example"]'); xpath_test(get_page('LocalNames'), '//ul/li/a[@class="url outside"][@href="http://www.example.com/"][text()="Example"]'); $LocalNamesInit = 0; LocalNamesInit(); %Test = split('\n',<<'EOT'); OddMuse //a[@class="near"][@title="LocalNames"][@href="http://www.oddmuse.org/"][text()="OddMuse"] [[Example]] //a[@class="near"][@title="LocalNames"][@href="http://www.example.com/"][text()="Example"] EOT xpath_run_tests(); xpath_test(get_page('action=rc days=1 showedit=1'), '//a[@class="local"][text()="LocalNames"]/following-sibling::strong[text()="Local names defined on LocalNamesTest: Example"]'); # more definitions on one page update_page('LocalNamesTest', 'This is an [http://www.example.org/ Example] for [http://www.emacswiki.org EmacsWiki].'); xpath_test(get_page('action=rc days=1 showedit=1'), '//a[@class="local"][text()="LocalNames"]/following-sibling::strong[text()="Local names defined on LocalNamesTest: Example, and EmacsWiki"]'); update_page('LocalNamesTest', 'This is an [http://www.example.com/ Example] for [http://www.emacswiki.org/ EmacsWiki] and [http://communitywiki.org/ Community Wiki].'); xpath_test(get_page('action=rc days=1 showedit=1'), '//a[@class="local"][text()="LocalNames"]/following-sibling::strong[text()="Local names defined on LocalNamesTest: Example, EmacsWiki, and Community Wiki"]'); update_page('LocalNamesTest', 'This is [http://www.example.com/ one Example].'); xpath_test(get_page('LocalNames'), '//ul/li/a[@class="url outside"][@href="http://www.example.com/"][text()="one Example"]'); update_page('LocalNamesTest', 'This is [http://www.example.com/ one simple Example].'); negative_xpath_test(get_page('LocalNames'), '//ul/li/a[@class="url outside"][@href="http://www.example.com/"][text()="one simple Example"]'); AppendStringToFile($ConfigFile, "\$LocalNamesCollectMaxWords = 1;\n"); update_page('LocalNamesTest', 'This is [http://www.example.com/ Example one].'); negative_xpath_test(get_page('LocalNames'), '//ul/li/a[@class="url outside"][@href="http://www.example.com/"][text()="Example one"]'); *GetInterSiteUrl = *OldLocalNamesGetInterSiteUrl; # -------------------- config_page: print '[config page]'; clear_pages(); AppendStringToFile($ConfigFile, "\$ConfigPage = 'Config';\n"); xpath_test(update_page('Config', '@UserGotoBarPages = ("Foo", "Bar");', 'config', 0, 1), '//div[@class="header"]/span[@class="gotobar bar"]/a[@class="local"][text()="Foo"]/following-sibling::a[@class="local"][text()="Bar"]'); ### END OF TESTS end: print "\n"; print "$passed passed, $failed failed.\n";