3 * base include file for SimpleTest
5 * @subpackage UnitTester
6 * @version $Id: expectation.php 2009 2011-04-28 08:57:25Z pp11 $
10 * include other SimpleTest class files
12 require_once(dirname(__FILE__
) . '/dumper.php');
13 require_once(dirname(__FILE__
) . '/compatibility.php');
17 * Assertion that can display failure information.
18 * Also includes various helper methods.
20 * @subpackage UnitTester
23 class SimpleExpectation
{
24 protected $dumper = false;
28 * Creates a dumper for displaying values and sets
30 * @param string $message Customised message on failure.
32 function __construct($message = '%s') {
33 $this->message
= $message;
37 * Tests the expectation. True if correct.
38 * @param mixed $compare Comparison value.
39 * @return boolean True if correct.
43 function test($compare) {
47 * Returns a human readable test message.
48 * @param mixed $compare Comparison value.
49 * @return string Description of success
54 function testMessage($compare) {
58 * Overlays the generated message onto the stored user
59 * message. An additional message can be interjected.
60 * @param mixed $compare Comparison value.
61 * @param SimpleDumper $dumper For formatting the results.
62 * @return string Description of success
66 function overlayMessage($compare, $dumper) {
67 $this->dumper
= $dumper;
68 return sprintf($this->message
, $this->testMessage($compare));
72 * Accessor for the dumper.
73 * @return SimpleDumper Current value dumper.
76 protected function getDumper() {
77 if (! $this->dumper
) {
78 $dumper = new SimpleDumper();
85 * Test to see if a value is an expectation object.
86 * A useful utility method.
87 * @param mixed $expectation Hopefully an Expectation
89 * @return boolean True if descended from
93 static function isExpectation($expectation) {
94 return is_object($expectation) &&
95 SimpleTestCompatibility
::isA($expectation, 'SimpleExpectation');
100 * A wildcard expectation always matches.
101 * @package SimpleTest
102 * @subpackage MockObjects
104 class AnythingExpectation
extends SimpleExpectation
{
107 * Tests the expectation. Always true.
108 * @param mixed $compare Ignored.
109 * @return boolean True.
112 function test($compare) {
117 * Returns a human readable test message.
118 * @param mixed $compare Comparison value.
119 * @return string Description of success
123 function testMessage($compare) {
124 $dumper = $this->getDumper();
125 return 'Anything always matches [' . $dumper->describeValue($compare) . ']';
130 * An expectation that never matches.
131 * @package SimpleTest
132 * @subpackage MockObjects
134 class FailedExpectation
extends SimpleExpectation
{
137 * Tests the expectation. Always false.
138 * @param mixed $compare Ignored.
139 * @return boolean True.
142 function test($compare) {
147 * Returns a human readable test message.
148 * @param mixed $compare Comparison value.
149 * @return string Description of failure.
152 function testMessage($compare) {
153 $dumper = $this->getDumper();
154 return 'Failed expectation never matches [' . $dumper->describeValue($compare) . ']';
159 * An expectation that passes on boolean true.
160 * @package SimpleTest
161 * @subpackage MockObjects
163 class TrueExpectation
extends SimpleExpectation
{
166 * Tests the expectation.
167 * @param mixed $compare Should be true.
168 * @return boolean True on match.
171 function test($compare) {
172 return (boolean
)$compare;
176 * Returns a human readable test message.
177 * @param mixed $compare Comparison value.
178 * @return string Description of success
182 function testMessage($compare) {
183 $dumper = $this->getDumper();
184 return 'Expected true, got [' . $dumper->describeValue($compare) . ']';
189 * An expectation that passes on boolean false.
190 * @package SimpleTest
191 * @subpackage MockObjects
193 class FalseExpectation
extends SimpleExpectation
{
196 * Tests the expectation.
197 * @param mixed $compare Should be false.
198 * @return boolean True on match.
201 function test($compare) {
202 return ! (boolean
)$compare;
206 * Returns a human readable test message.
207 * @param mixed $compare Comparison value.
208 * @return string Description of success
212 function testMessage($compare) {
213 $dumper = $this->getDumper();
214 return 'Expected false, got [' . $dumper->describeValue($compare) . ']';
220 * @package SimpleTest
221 * @subpackage UnitTester
223 class EqualExpectation
extends SimpleExpectation
{
227 * Sets the value to compare against.
228 * @param mixed $value Test value to match.
229 * @param string $message Customised message on failure.
232 function __construct($value, $message = '%s') {
233 parent
::__construct($message);
234 $this->value
= $value;
238 * Tests the expectation. True if it matches the
240 * @param mixed $compare Comparison value.
241 * @return boolean True if correct.
244 function test($compare) {
245 return (($this->value
== $compare) && ($compare == $this->value
));
249 * Returns a human readable test message.
250 * @param mixed $compare Comparison value.
251 * @return string Description of success
255 function testMessage($compare) {
256 if ($this->test($compare)) {
257 return "Equal expectation [" . $this->dumper
->describeValue($this->value
) . "]";
259 return "Equal expectation fails " .
260 $this->dumper
->describeDifference($this->value
, $compare);
265 * Accessor for comparison value.
266 * @return mixed Held value to compare with.
269 protected function getValue() {
275 * Test for inequality.
276 * @package SimpleTest
277 * @subpackage UnitTester
279 class NotEqualExpectation
extends EqualExpectation
{
282 * Sets the value to compare against.
283 * @param mixed $value Test value to match.
284 * @param string $message Customised message on failure.
287 function __construct($value, $message = '%s') {
288 parent
::__construct($value, $message);
292 * Tests the expectation. True if it differs from the
294 * @param mixed $compare Comparison value.
295 * @return boolean True if correct.
298 function test($compare) {
299 return ! parent
::test($compare);
303 * Returns a human readable test message.
304 * @param mixed $compare Comparison value.
305 * @return string Description of success
309 function testMessage($compare) {
310 $dumper = $this->getDumper();
311 if ($this->test($compare)) {
312 return "Not equal expectation passes " .
313 $dumper->describeDifference($this->getValue(), $compare);
315 return "Not equal expectation fails [" .
316 $dumper->describeValue($this->getValue()) .
323 * Test for being within a range.
324 * @package SimpleTest
325 * @subpackage UnitTester
327 class WithinMarginExpectation
extends SimpleExpectation
{
332 * Sets the value to compare against and the fuzziness of
333 * the match. Used for comparing floating point values.
334 * @param mixed $value Test value to match.
335 * @param mixed $margin Fuzziness of match.
336 * @param string $message Customised message on failure.
339 function __construct($value, $margin, $message = '%s') {
340 parent
::__construct($message);
341 $this->upper
= $value +
$margin;
342 $this->lower
= $value - $margin;
346 * Tests the expectation. True if it matches the
348 * @param mixed $compare Comparison value.
349 * @return boolean True if correct.
352 function test($compare) {
353 return (($compare <= $this->upper
) && ($compare >= $this->lower
));
357 * Returns a human readable test message.
358 * @param mixed $compare Comparison value.
359 * @return string Description of success
363 function testMessage($compare) {
364 if ($this->test($compare)) {
365 return $this->withinMessage($compare);
367 return $this->outsideMessage($compare);
372 * Creates a the message for being within the range.
373 * @param mixed $compare Value being tested.
376 protected function withinMessage($compare) {
377 return "Within expectation [" . $this->dumper
->describeValue($this->lower
) . "] and [" .
378 $this->dumper
->describeValue($this->upper
) . "]";
382 * Creates a the message for being within the range.
383 * @param mixed $compare Value being tested.
386 protected function outsideMessage($compare) {
387 if ($compare > $this->upper
) {
388 return "Outside expectation " .
389 $this->dumper
->describeDifference($compare, $this->upper
);
391 return "Outside expectation " .
392 $this->dumper
->describeDifference($compare, $this->lower
);
398 * Test for being outside of a range.
399 * @package SimpleTest
400 * @subpackage UnitTester
402 class OutsideMarginExpectation
extends WithinMarginExpectation
{
405 * Sets the value to compare against and the fuzziness of
406 * the match. Used for comparing floating point values.
407 * @param mixed $value Test value to not match.
408 * @param mixed $margin Fuzziness of match.
409 * @param string $message Customised message on failure.
412 function __construct($value, $margin, $message = '%s') {
413 parent
::__construct($value, $margin, $message);
417 * Tests the expectation. True if it matches the
419 * @param mixed $compare Comparison value.
420 * @return boolean True if correct.
423 function test($compare) {
424 return ! parent
::test($compare);
428 * Returns a human readable test message.
429 * @param mixed $compare Comparison value.
430 * @return string Description of success
434 function testMessage($compare) {
435 if (! $this->test($compare)) {
436 return $this->withinMessage($compare);
438 return $this->outsideMessage($compare);
444 * Test for reference.
445 * @package SimpleTest
446 * @subpackage UnitTester
448 class ReferenceExpectation
{
452 * Sets the reference value to compare against.
453 * @param mixed $value Test reference to match.
454 * @param string $message Customised message on failure.
457 function __construct(&$value, $message = '%s') {
458 $this->message
= $message;
459 $this->value
= &$value;
463 * Tests the expectation. True if it exactly
464 * references the held value.
465 * @param mixed $compare Comparison reference.
466 * @return boolean True if correct.
469 function test(&$compare) {
470 return SimpleTestCompatibility
::isReference($this->value
, $compare);
474 * Returns a human readable test message.
475 * @param mixed $compare Comparison value.
476 * @return string Description of success
480 function testMessage($compare) {
481 if ($this->test($compare)) {
482 return "Reference expectation [" . $this->dumper
->describeValue($this->value
) . "]";
484 return "Reference expectation fails " .
485 $this->dumper
->describeDifference($this->value
, $compare);
490 * Overlays the generated message onto the stored user
491 * message. An additional message can be interjected.
492 * @param mixed $compare Comparison value.
493 * @param SimpleDumper $dumper For formatting the results.
494 * @return string Description of success
498 function overlayMessage($compare, $dumper) {
499 $this->dumper
= $dumper;
500 return sprintf($this->message
, $this->testMessage($compare));
504 * Accessor for the dumper.
505 * @return SimpleDumper Current value dumper.
508 protected function getDumper() {
509 if (! $this->dumper
) {
510 $dumper = new SimpleDumper();
513 return $this->dumper
;
519 * @package SimpleTest
520 * @subpackage UnitTester
522 class IdenticalExpectation
extends EqualExpectation
{
525 * Sets the value to compare against.
526 * @param mixed $value Test value to match.
527 * @param string $message Customised message on failure.
530 function __construct($value, $message = '%s') {
531 parent
::__construct($value, $message);
535 * Tests the expectation. True if it exactly
536 * matches the held value.
537 * @param mixed $compare Comparison value.
538 * @return boolean True if correct.
541 function test($compare) {
542 return SimpleTestCompatibility
::isIdentical($this->getValue(), $compare);
546 * Returns a human readable test message.
547 * @param mixed $compare Comparison value.
548 * @return string Description of success
552 function testMessage($compare) {
553 $dumper = $this->getDumper();
554 if ($this->test($compare)) {
555 return "Identical expectation [" . $dumper->describeValue($this->getValue()) . "]";
557 return "Identical expectation [" . $dumper->describeValue($this->getValue()) .
559 $dumper->describeValue($compare) . "] " .
560 $dumper->describeDifference($this->getValue(), $compare, TYPE_MATTERS
);
566 * Test for non-identity.
567 * @package SimpleTest
568 * @subpackage UnitTester
570 class NotIdenticalExpectation
extends IdenticalExpectation
{
573 * Sets the value to compare against.
574 * @param mixed $value Test value to match.
575 * @param string $message Customised message on failure.
578 function __construct($value, $message = '%s') {
579 parent
::__construct($value, $message);
583 * Tests the expectation. True if it differs from the
585 * @param mixed $compare Comparison value.
586 * @return boolean True if correct.
589 function test($compare) {
590 return ! parent
::test($compare);
594 * Returns a human readable test message.
595 * @param mixed $compare Comparison value.
596 * @return string Description of success
600 function testMessage($compare) {
601 $dumper = $this->getDumper();
602 if ($this->test($compare)) {
603 return "Not identical expectation passes " .
604 $dumper->describeDifference($this->getValue(), $compare, TYPE_MATTERS
);
606 return "Not identical expectation [" . $dumper->describeValue($this->getValue()) . "] matches";
612 * Test for a pattern using Perl regex rules.
613 * @package SimpleTest
614 * @subpackage UnitTester
616 class PatternExpectation
extends SimpleExpectation
{
620 * Sets the value to compare against.
621 * @param string $pattern Pattern to search for.
622 * @param string $message Customised message on failure.
625 function __construct($pattern, $message = '%s') {
626 parent
::__construct($message);
627 $this->pattern
= $pattern;
631 * Accessor for the pattern.
632 * @return string Perl regex as string.
635 protected function getPattern() {
636 return $this->pattern
;
640 * Tests the expectation. True if the Perl regex
641 * matches the comparison value.
642 * @param string $compare Comparison value.
643 * @return boolean True if correct.
646 function test($compare) {
647 return (boolean
)preg_match($this->getPattern(), $compare);
651 * Returns a human readable test message.
652 * @param mixed $compare Comparison value.
653 * @return string Description of success
657 function testMessage($compare) {
658 if ($this->test($compare)) {
659 return $this->describePatternMatch($this->getPattern(), $compare);
661 $dumper = $this->getDumper();
662 return "Pattern [" . $this->getPattern() .
663 "] not detected in [" .
664 $dumper->describeValue($compare) . "]";
669 * Describes a pattern match including the string
670 * found and it's position.
671 * @param string $pattern Regex to match against.
672 * @param string $subject Subject to search.
675 protected function describePatternMatch($pattern, $subject) {
676 preg_match($pattern, $subject, $matches);
677 $position = strpos($subject, $matches[0]);
678 $dumper = $this->getDumper();
679 return "Pattern [$pattern] detected at character [$position] in [" .
680 $dumper->describeValue($subject) . "] as [" .
681 $matches[0] . "] in region [" .
682 $dumper->clipString($subject, 100, $position) . "]";
687 * Fail if a pattern is detected within the
689 * @package SimpleTest
690 * @subpackage UnitTester
692 class NoPatternExpectation
extends PatternExpectation
{
695 * Sets the reject pattern
696 * @param string $pattern Pattern to search for.
697 * @param string $message Customised message on failure.
700 function __construct($pattern, $message = '%s') {
701 parent
::__construct($pattern, $message);
705 * Tests the expectation. False if the Perl regex
706 * matches the comparison value.
707 * @param string $compare Comparison value.
708 * @return boolean True if correct.
711 function test($compare) {
712 return ! parent
::test($compare);
716 * Returns a human readable test message.
717 * @param string $compare Comparison value.
718 * @return string Description of success
722 function testMessage($compare) {
723 if ($this->test($compare)) {
724 $dumper = $this->getDumper();
725 return "Pattern [" . $this->getPattern() .
726 "] not detected in [" .
727 $dumper->describeValue($compare) . "]";
729 return $this->describePatternMatch($this->getPattern(), $compare);
735 * Tests either type or class name if it's an object.
736 * @package SimpleTest
737 * @subpackage UnitTester
739 class IsAExpectation
extends SimpleExpectation
{
743 * Sets the type to compare with.
744 * @param string $type Type or class name.
745 * @param string $message Customised message on failure.
748 function __construct($type, $message = '%s') {
749 parent
::__construct($message);
754 * Accessor for type to check against.
755 * @return string Type or class name.
758 protected function getType() {
763 * Tests the expectation. True if the type or
764 * class matches the string value.
765 * @param string $compare Comparison value.
766 * @return boolean True if correct.
769 function test($compare) {
770 if (is_object($compare)) {
771 return SimpleTestCompatibility
::isA($compare, $this->type
);
773 $function = 'is_'.$this->canonicalType($this->type
);
774 if (is_callable($function)) {
775 return $function($compare);
782 * Coerces type name into a is_*() match.
783 * @param string $type User type.
784 * @return string Simpler type.
787 protected function canonicalType($type) {
788 $type = strtolower($type);
789 $map = array('boolean' => 'bool');
790 if (isset($map[$type])) {
797 * Returns a human readable test message.
798 * @param mixed $compare Comparison value.
799 * @return string Description of success
803 function testMessage($compare) {
804 $dumper = $this->getDumper();
805 return "Value [" . $dumper->describeValue($compare) .
806 "] should be type [" . $this->type
. "]";
811 * Tests either type or class name if it's an object.
812 * Will succeed if the type does not match.
813 * @package SimpleTest
814 * @subpackage UnitTester
816 class NotAExpectation
extends IsAExpectation
{
820 * Sets the type to compare with.
821 * @param string $type Type or class name.
822 * @param string $message Customised message on failure.
825 function __construct($type, $message = '%s') {
826 parent
::__construct($type, $message);
830 * Tests the expectation. False if the type or
831 * class matches the string value.
832 * @param string $compare Comparison value.
833 * @return boolean True if different.
836 function test($compare) {
837 return ! parent
::test($compare);
841 * Returns a human readable test message.
842 * @param mixed $compare Comparison value.
843 * @return string Description of success
847 function testMessage($compare) {
848 $dumper = $this->getDumper();
849 return "Value [" . $dumper->describeValue($compare) .
850 "] should not be type [" . $this->getType() . "]";
855 * Tests for existance of a method in an object
856 * @package SimpleTest
857 * @subpackage UnitTester
859 class MethodExistsExpectation
extends SimpleExpectation
{
863 * Sets the value to compare against.
864 * @param string $method Method to check.
865 * @param string $message Customised message on failure.
868 function __construct($method, $message = '%s') {
869 parent
::__construct($message);
870 $this->method
= &$method;
874 * Tests the expectation. True if the method exists in the test object.
875 * @param string $compare Comparison method name.
876 * @return boolean True if correct.
878 function test($compare) {
879 return (boolean
)(is_object($compare) && method_exists($compare, $this->method
));
883 * Returns a human readable test message.
884 * @param mixed $compare Comparison value.
885 * @return string Description of success
888 function testMessage($compare) {
889 $dumper = $this->getDumper();
890 if (! is_object($compare)) {
891 return 'No method on non-object [' . $dumper->describeValue($compare) . ']';
893 $method = $this->method
;
894 return "Object [" . $dumper->describeValue($compare) .
895 "] should contain method [$method]";
900 * Compares an object member's value even if private.
901 * @package SimpleTest
902 * @subpackage UnitTester
904 class MemberExpectation
extends IdenticalExpectation
{
908 * Sets the value to compare against.
909 * @param string $method Method to check.
910 * @param string $message Customised message on failure.
913 function __construct($name, $expected) {
915 parent
::__construct($expected);
919 * Tests the expectation. True if the property value is identical.
920 * @param object $actual Comparison object.
921 * @return boolean True if identical.
923 function test($actual) {
924 if (! is_object($actual)) {
927 return parent
::test($this->getProperty($this->name
, $actual));
931 * Returns a human readable test message.
932 * @param mixed $compare Comparison value.
933 * @return string Description of success
936 function testMessage($actual) {
937 return parent
::testMessage($this->getProperty($this->name
, $actual));
941 * Extracts the member value even if private using reflection.
942 * @param string $name Property name.
943 * @param object $object Object to read.
944 * @return mixed Value of property.
946 private function getProperty($name, $object) {
947 $reflection = new ReflectionObject($object);
948 $property = $reflection->getProperty($name);
949 if (method_exists($property, 'setAccessible')) {
950 $property->setAccessible(true);
953 return $property->getValue($object);
954 } catch (ReflectionException
$e) {
955 return $this->getPrivatePropertyNoMatterWhat($name, $object);
960 * Extracts a private member's value when reflection won't play ball.
961 * @param string $name Property name.
962 * @param object $object Object to read.
963 * @return mixed Value of property.
965 private function getPrivatePropertyNoMatterWhat($name, $object) {
966 foreach ((array)$object as $mangled_name => $value) {
967 if ($this->unmangle($mangled_name) == $name) {
974 * Removes crud from property name after it's been converted
976 * @param string $mangled Name from array cast.
977 * @return string Cleaned up name.
979 function unmangle($mangled) {
980 $parts = preg_split('/[^a-zA-Z0-9_\x7f-\xff]+/', $mangled);
981 return array_pop($parts);