HTML::Tested::Test


HTML-Tested documentation Contained in the HTML-Tested distribution.

Index


Code Index:

Register_Widget_Tester($widget_class, $tester_class)

Registers $tester_class as tester for $widget_class.


HTML-Tested documentation Contained in the HTML-Tested distribution.

use strict;
use warnings FATAL => 'all';

package HTML::Tested::Test;
use base 'Exporter';
use Data::Dumper;
use Text::Diff;
use Carp;

our @EXPORT_OK = qw(Register_Widget_Tester Stash_Mismatch Ensure_Value_To_Check);

sub Stash_Mismatch {
	my ($n, $res, $v) = @_;
	my $ret = sprintf("Mismatch at %s: got %s, expected %s",
				$n, defined($res) ? "\"$res\"" : "undef",
				defined($v) ? "\"$v\"" : "undef");
	goto OUT unless (defined($res) && defined($v)
		&& $res =~ /\n.*\n/ms && $v =~ /\n.*\n/ms);
	$ret .= ". The diff is\n" . diff(\$v, \$res);
OUT:
	return $ret;
}

sub Ensure_Value_To_Check {
	my ($r_stash, $name, $e_val, $errs) = @_;
	my $r_val = $r_stash->{$name};
	return if (!defined($r_val) && !defined($e_val));

	if (defined($r_val) xor defined($e_val)) {
		push @$errs, Stash_Mismatch($name, $r_val, $e_val);
		return;
	}
	return $r_val;
}

sub compare_stashes {
	my ($class, $e_root, $stash, $e_stash) = @_;
	return () if (!defined($stash) && !defined($e_stash));
	if (defined($stash) xor defined($e_stash)) {
		return ("Stash " . Dumper($stash)
				. "differ from "
				. "expected " . Dumper($e_stash));
	}
	return $class->_run_checks('stash', $e_root, $stash, $e_stash);
}

sub _run_checks {
	my ($class, $check, $e_root, $res, $e_stash) = @_;
	my $f = "check_$check";
	return map {
		$_->__ht_tester->$f($e_root, $_->name, $e_stash, $res);
	} @{ $e_root->Widgets_List };
}

sub compare_text_to_stash {
	my ($class, $e_root, $text, $e_stash) = @_;
	return $class->_run_checks('text', $e_root, $text, $e_stash);
}

my $_index = 0;

sub Make_Expected_Class {
	my ($target_class, $expected) = @_;
	my $package = "$target_class\::__HT_TESTER_" . $_index++;
	{ 
		no strict 'refs';
		push @{ *{ "$package\::ISA" } }, $target_class 
			unless @{ *{ "$package\::ISA" } };
	};
	my $wl = $target_class->Widgets_List;
	$package->Widgets_List([ grep {
		exists($expected->{ $_->name });
	} @$wl ]);
	return $package;
}

sub bless_unknown_widget {
	my ($class, $n, $v, $err) = @_;
	push @$err, "Unknown widget $n found in expected!";
	return $v;
}
	 
sub bless_from_tree_for_test {
	my ($class, $target, $expected, $err) = @_;
	my $res = {};
	my (@disabled, %e, @reverted, @sealed, @unsorted);
	while (my ($n, $v) = each %$expected) {
		my $rev = ($n =~ s/^HT_NO_//);
		my $sealed = ($n =~ s/^HT_SEALED_//);
		my $unsorted = ($n =~ s/^HT_UNSORTED_//);
		push @reverted, $n if $rev;
		push @sealed, $n if $sealed;
		push @unsorted, $n if $unsorted;
		$e{$n} = $v;
	}
	$expected = \%e;

	my $e_class = Make_Expected_Class($target, $expected);
	while (my ($n, $v) = each %$expected) {
		if (defined($v) && !ref($v) && $v eq 'HT_DISABLED') {
			push @disabled, $n;
			next;
		}
		my $wc = $e_class->ht_find_widget($n);
		$res->{$n} = $wc ?
			$wc->__ht_tester->bless_from_tree($wc, $v, $err)
			: $class->bless_unknown_widget($n, $v, $err);
	}
	my $e_root = bless($res, $e_class);
	$e_root->ht_set_widget_option($_, "is_disabled", 1) for @disabled;
	$e_root->{"__HT_REVERTED__$_"} = 1 for @reverted;
	$e_root->{"__HT_SEALED__$_"} = 1 for @sealed;
	$e_root->{"__HT_UNSORTED__$_"} = 1 for @unsorted;
	return $e_root;
}

sub do_comparison {
	my ($class, $compare, $obj_class, $stash, $expected) = @_;
	my $e_stash = {};
	my @res;
	my $e_root = $class->bless_from_tree_for_test($obj_class
			, $expected, \@res);
	$e_root->_ht_render_i($e_stash);

	push @res, $class->$compare($e_root, $stash, $e_stash);
	return @res;
}

sub check_stash { return shift()->do_comparison('compare_stashes', @_); }
sub check_text {
	return shift()->do_comparison('compare_text_to_stash', @_);
}

sub Register_Widget_Tester {
	my ($w_class, $t_class) = @_;
	no strict 'refs';
	*{ "$w_class\::__ht_tester" } = sub { return $t_class; };
}

sub _tree_to_param_fallback {
	my ($class, $n) = @_;
	confess "Unable to find widget for $n";
}

sub convert_tree_to_param {
	my ($class, $obj_class, $r, $tree, $parent_name) = @_;
	while (my ($n, $v) = each %$tree) {
		my $sealit = ($n =~ s/^HT_SEALED_//);
		my $wc = $obj_class->ht_find_widget($n);
		if ($wc) {
			$v = $wc->__ht_tester->convert_to_sealed($v) if $sealit;
			$wc->__ht_tester->convert_to_param($wc, $r, 
				$parent_name ? $parent_name . "__$n" : $n, $v);
		} else {
			$class->_tree_to_param_fallback($n);
		}
	}
}

my %_testers = qw(HTML::Tested::Value HTML::Tested::Test::Value
	HTML::Tested::Value::Upload HTML::Tested::Test::Upload
	HTML::Tested::Value::Radio HTML::Tested::Test::Radio
	HTML::Tested::List HTML::Tested::Test::List);
while (my ($n, $v) = each %_testers) {
	eval "use $n; use $v;";
	die "Unable to use $n or use $v" if $@;
	Register_Widget_Tester($n, $v);
}

1;