3 use vars qw(@ISA @EXPORT @EXPORT_OK);
5 @EXPORT = qw(base_url fetch_ok make_url skip make_ua);
6 @EXPORT_OK = qw(base_url make_ua fetch_url fetch_ok make_url skip
7 make_post check_form post_ok check_content follow_ok
8 follow_refresh_ok click_ok config test_actions);
9 use lib 'site/cgi-bin/modules';
12 my $conffile = $ENV{BSETEST} || 'install.cfg';
14 my $cfg = BSE::Cfg->new
16 path => "site/cgi-bin",
17 extra_file => $conffile,
25 $cfg->entryVar("site", "url");
29 $cfg->entryVar("site", "secureurl");
33 $cfg->entryVar("paths", "siteroot");
37 $cfg->entry("binaries", "mysql", "mysql");
41 $cfg->entry("db", "dsn");
45 $cfg->entry("db", "user");
49 $cfg->entry("db", "password");
53 $cfg->entry("db", "class", "BSE::DB::Mysql");
56 sub test_sessionclass {
57 $cfg->entry("basic", "session_class", "Apache::Session::Mysql");
61 $cfg->entry("paths", "perl", $^X);
69 require WWW::Mechanize;
70 require "HTTP/Cookies.pm";
71 my $ua = WWW::Mechanize->new(onerror => undef);
72 $ua->cookie_jar(HTTP::Cookies->new);
77 # in scalar context returns content
78 # in list context returns ($content, $code)
79 # $post is any data to be part of a post request
81 my ($ua, $url, $method, $post) = @_;
84 my $hdrs = HTTP::Headers->new;
85 $hdrs->header(Content_Length => length $post) if $post;
86 my $req = HTTP::Request->new($method, $url, $hdrs);
87 $req->content($post) if $post;
88 my $resp = $ua->request($req);
90 return ($resp->content(), $resp->code(), $resp->is_success,
91 $resp->headers_as_string());
94 return $resp->is_success() ? $resp->content() : undef;
99 my ($base, @data) = @_;
101 require "URI/Escape.pm";
103 while (my ($key, $value) = splice(@data, 0, 2)) {
104 push(@pairs, "$key=".URI::uri_escape($value));
106 return $base."?".join("&",@pairs);
110 my ($content, $note, $match) = @_;
111 my $tb = Test::Builder->new;
112 local $Test::Builder::Level = $Test::Builder::Level + 1;
114 return $tb->like($content, qr/$match/s, "$note: match");
118 my ($content, $code, $ok, $headers,
119 $note, $match, $headmatch) = @_;
121 my $tb = Test::Builder->new;
122 local $Test::Builder::Level = $Test::Builder::Level + 1;
125 $tb->ok($ok, "$note: fetch ($code)");
130 $count++ if $headmatch;
131 $ok or skip("$note: fetch failed", $count) if $count;
133 unless ($tb->like($content, qr/$match/s, "$note: match")) {
134 #print "# wanted /$match/ got:\n";
135 #my $copy = $content;
137 #$copy .= "\n" unless $copy =~ /\n\z/;
143 unless ($tb->like($headers, qr/$headmatch/s, "$note: headmatch")) {
144 #print "# wanted /$headmatch/ got:\n";
145 #my $copy = $headers;
147 #$copy .= "\n" unless $copy =~ /\n\z/;
155 return ($content, $code, $good, $headers);
158 return $good ? $content : undef;
165 require "URI/Escape.pm";
167 while (my ($key, $value) = splice(@data, 0, 2)) {
168 push(@pairs, "$key=".URI::Escape::uri_escape($value));
170 return join("&",@pairs);
174 my ($ua, $note, $url, $data, $match, $headmatch) = @_;
176 $data = make_post(@$data) if ref $data;
178 my ($content, $code, $ok, $headers) = fetch_url($ua, $url, POST=>$data);
180 return _check_fetch($content, $code, $ok, $headers,
181 $note, $match, $headmatch)
185 my ($ua, $note, $url, $match, $headmatch) = @_;
187 my $resp = $ua->get($url);
188 my $ok = $resp->is_success;
189 return _check_fetch($ua->{content}, $ua->{status}, $ok,
190 $ua->{res}->headers_as_string, $note,
195 my ($ua, $note, $link, $match, $headmatch) = @_;
199 my $resp = $ua->follow_link(%$link);
200 $ok = $resp->is_success;
203 $ok = $ua->follow_link(text_regex => qr/\Q$link/);
206 return _check_fetch($ua->{content}, $ua->{status}, $ok,
207 $ua->{res}->headers_as_string, $note,
211 sub follow_refresh_ok {
212 my ($ua, $note, $match, $headmatch) = @_;
216 ++$headmatch if $headmatch;
217 my $refresh = $ua->response->header('Refresh');
218 if (ok($refresh, "$note - refresh header")) {
220 if ($refresh =~ /^\s*\d+\s*;\s*url=\"([^\"]+)\"/
221 or $refresh =~ /^\s*\d+\s*;\s*url\s*=\s*(\S+)/) {
223 $url = URI->new_abs($url, $ua->uri);
228 print "# refresh to $url\n";
229 fetch_ok($ua, "$note - fetch", $url);
232 skip("$note - skipped, not a refresh", $skip);
237 my ($ua, $note, $name, $match, $headmatch) = @_;
239 local $Test::Builder::Level = $Test::Builder::Level + 1;
240 my $tb = Test::Builder->new;
242 my $ok = $tb->ok($ua->click($name), "$note - click");
243 return _check_fetch($ua->{content}, $ua->{status}, $ok,
244 $ua->{res}->headers_as_string, $note,
249 my ($content, $note, %checks) = @_;
251 require 'HTML/Parser.pm';
252 require 'HTML/Entities.pm';
259 my $checked_sel_value;
263 my $tb = Test::Builder->new;
264 local $Test::Builder::Level = $Test::Builder::Level + 1;
269 $saved .= $t if $keep;
273 my ($tagname, $attr) = @_;
275 if ($tagname eq 'input') {
276 my $name = $attr->{name};
277 if ($name && $todo{$name}) {
278 $tb->ok(1, "$note - $name - field is present");
279 $values{$name} = $attr->{$name};
280 if (defined $todo{$name}[0]) {
281 my $cvalue = $checks{$name}[0];
282 my $fvalue = $attr->{value};
283 if (defined $fvalue) {
284 $tb->ok($cvalue eq $fvalue, "$note - $name - comparing values");
287 $tb->ok(0, "$note - $name - value is not present");
290 if (defined $todo{$name}[1]) {
291 my $ttype = $todo{$name}[1];
292 my $ftype = $attr->{type};
293 if (defined $ftype) {
294 $tb->ok($ttype eq $ftype, "$note - $name - comparing types");
297 $tb->ok(0, "$note - $name - type not present");
303 elsif ($tagname eq 'select') {
304 $selname = $attr->{name};
306 if ($todo{$selname}) {
307 $tb->ok(1, "$note - $selname - field is present");
309 if (defined $todo{$selname}[1]) {
310 $checked_sel_value = 0;
311 my $ttype = $todo{$selname}[1];
312 $tb->ok ($ttype eq 'select', "$note - $selname - checking type (select)");
316 elsif ($tagname eq 'option' && $inselect) {
317 unless (exists $attr->{value}) {
318 print "# warning - option in select $selname missing value\n";
320 if (exists $attr->{selected}) {
321 $checked_sel_value = 1;
322 $values{$selname} = $attr->{value};
323 if (defined $todo{$selname}[0]) {
324 my $fvalue = $attr->{value};
325 my $tvalue = $todo{$selname}[0];
326 if (defined $fvalue) {
327 $tb->ok($fvalue eq $tvalue, "$note - $selname - checking value ($fvalue vs $tvalue)");
330 $tb->ok(0, "$note - $selname - no value supplied");
335 elsif ($tagname eq 'textarea') {
336 $textname = $attr->{name};
345 if ($tagname eq 'select' && $inselect) {
346 if (!$checked_sel_value) {
347 $tb->ok(0, "$note - $selname - no value selected");
349 delete $todo{$selname};
351 elsif ($tagname eq 'textarea') {
353 if ($todo{$textname}) {
354 my $fvalue = HTML::Entities::decode_entities($saved);
355 $values{$textname} = $fvalue;
356 $tb->ok(1, "$note - $textname - field exists");
357 if (defined $todo{$textname}[0]) {
358 my $tvalue = $todo{$textname}[0];
359 $tb->ok($tvalue eq $fvalue, "$note - $textname - checking value($tvalue vs $fvalue)");
361 if (defined $todo{$textname}[1]) {
362 $tb->ok ($todo{$textname}[1] eq 'textarea',
363 "$note - $textname - check field type");
365 delete $todo{$textname};
369 my $p = HTML::Parser->new( text_h => [ $text, "dtext" ],
370 start_h => [ $start, "tagname, attr" ],
371 end_h => [ $end, "tagname" ]);
374 for my $name (keys %todo) {
375 $tb->ok(0, "$note - $name - field doesn't exist");
377 ++$count if defined $todo{$name}[0];
378 ++$count if defined $todo{$name}[1];
380 skip("$note - $name - no field", $count) if $count;
387 # test that all actions have methods for a given dispatcher class
391 my $tb = Test::Builder->new;
392 local $Test::Builder::Level = $Test::Builder::Level + 1;
394 my $obj = $class->new;
395 my $actions = $obj->actions;
397 for my $action (sort keys %$actions) {
398 my $method = "req_$action";
399 unless ($obj->can($method)) {
403 $tb->ok(!@bad, "check all actions have a method for $class");
404 print STDERR "No method found for $class action $_\n" for @bad;