Source for file test_case.php

Documentation is available at test_case.php

  1. <?php
  2. /**
  3.  *  Base include file for SimpleTest
  4.  *  @package    SimpleTest
  5.  *  @subpackage UnitTester
  6.  *  @version    $Id: test_case.php 1726 2008-04-08 01:20:10Z lastcraft $
  7.  */
  8.  
  9. /**#@+
  10.  * Includes SimpleTest files and defined the root constant
  11.  * for dependent libraries.
  12.  */
  13. require_once(dirname(__FILE__'/invoker.php');
  14. require_once(dirname(__FILE__'/errors.php');
  15. require_once(dirname(__FILE__'/compatibility.php');
  16. require_once(dirname(__FILE__'/scorer.php');
  17. require_once(dirname(__FILE__'/expectation.php');
  18. require_once(dirname(__FILE__'/dumper.php');
  19. require_once(dirname(__FILE__'/simpletest.php');
  20. if (version_compare(phpversion()'5'>= 0{
  21.     require_once(dirname(__FILE__'/exceptions.php');
  22.     require_once(dirname(__FILE__'/reflection_php5.php');
  23. else {
  24.     require_once(dirname(__FILE__'/reflection_php4.php');
  25. }
  26. if (defined('SIMPLE_TEST')) {
  27.     /**
  28.      * @ignore
  29.      */
  30.     define('SIMPLE_TEST'dirname(__FILE__DIRECTORY_SEPARATOR);
  31. }
  32. /**#@-*/
  33.  
  34.  *    Basic test case. This is the smallest unit of a test
  35.  *    suite. It searches for
  36.  *    all methods that start with the the string "test" and
  37.  *    runs them. Working test cases extend this class.
  38.  *    @package      SimpleTest
  39.  *    @subpackage   UnitTester
  40.  */
  41. class SimpleTestCase {
  42.     var $_label = false;
  43.     var $_reporter;
  44.     var $_observers;
  45.     var $_should_skip = false;
  46.  
  47.     /**
  48.      *    Sets up the test with no display.
  49.      *    @param string $label    If no test name is given then
  50.      *                             the class name is used.
  51.      *    @access public
  52.      */
  53.     function SimpleTestCase($label false{
  54.         if ($label{
  55.             $this->_label = $label;
  56.         }
  57.     }
  58.  
  59.     /**
  60.      *    Accessor for the test name for subclasses.
  61.      *    @return string           Name of the test.
  62.      *    @access public
  63.      */
  64.     function getLabel({
  65.         return $this->_label ? $this->_label : get_class($this);
  66.     }
  67.  
  68.     /**
  69.      *    This is a placeholder for skipping tests. In this
  70.      *    method you place skipIf() and skipUnless() calls to
  71.      *    set the skipping state.
  72.      *    @access public
  73.      */
  74.     function skip({
  75.     }
  76.  
  77.     /**
  78.      *    Will issue a message to the reporter and tell the test
  79.      *    case to skip if the incoming flag is true.
  80.      *    @param string $should_skip    Condition causing the tests to be skipped.
  81.      *    @param string $message        Text of skip condition.
  82.      *    @access public
  83.      */
  84.     function skipIf($should_skip$message '%s'{
  85.         if ($should_skip && $this->_should_skip{
  86.             $this->_should_skip = true;
  87.             $message sprintf($message'Skipping [' get_class($this']');
  88.             $this->_reporter->paintSkip($message $this->getAssertionLine());
  89.         }
  90.     }
  91.  
  92.     /**
  93.      *    Will issue a message to the reporter and tell the test
  94.      *    case to skip if the incoming flag is false.
  95.      *    @param string $shouldnt_skip  Condition causing the tests to be run.
  96.      *    @param string $message        Text of skip condition.
  97.      *    @access public
  98.      */
  99.     function skipUnless($shouldnt_skip$message false{
  100.         $this->skipIf($shouldnt_skip$message);
  101.     }
  102.  
  103.     /**
  104.      *    Used to invoke the single tests.
  105.      *    @return SimpleInvoker        Individual test runner.
  106.      *    @access public
  107.      */
  108.     function &createInvoker({
  109.         $invoker &new SimpleErrorTrappingInvoker(new SimpleInvoker($this));
  110.         if (version_compare(phpversion()'5'>= 0{
  111.             $invoker &new SimpleExceptionTrappingInvoker($invoker);
  112.         }
  113.         return $invoker;
  114.     }
  115.  
  116.     /**
  117.      *    Uses reflection to run every method within itself
  118.      *    starting with the string "test" unless a method
  119.      *    is specified.
  120.      *    @param SimpleReporter $reporter    Current test reporter.
  121.      *    @return boolean                    True if all tests passed.
  122.      *    @access public
  123.      */
  124.     function run(&$reporter{
  125.         $context &SimpleTest::getContext();
  126.         $context->setTest($this);
  127.         $context->setReporter($reporter);
  128.         $this->_reporter = &$reporter;
  129.         $started false;
  130.         foreach ($this->getTests(as $method{
  131.             if ($reporter->shouldInvoke($this->getLabel()$method)) {
  132.                 $this->skip();
  133.                 if ($this->_should_skip{
  134.                     break;
  135.                 }
  136.                 if ($started{
  137.                     $reporter->paintCaseStart($this->getLabel());
  138.                     $started true;
  139.                 }
  140.                 $invoker &$this->_reporter->createInvoker($this->createInvoker());
  141.                 $invoker->before($method);
  142.                 $invoker->invoke($method);
  143.                 $invoker->after($method);
  144.             }
  145.         }
  146.         if ($started{
  147.             $reporter->paintCaseEnd($this->getLabel());
  148.         }
  149.         unset($this->_reporter);
  150.         return $reporter->getStatus();
  151.     }
  152.  
  153.     /**
  154.      *    Gets a list of test names. Normally that will
  155.      *    be all internal methods that start with the
  156.      *    name "test". This method should be overridden
  157.      *    if you want a different rule.
  158.      *    @return array        List of test names.
  159.      *    @access public
  160.      */
  161.     function getTests({
  162.         $methods array();
  163.         foreach (get_class_methods(get_class($this)) as $method{
  164.             if ($this->_isTest($method)) {
  165.                 $methods[$method;
  166.             }
  167.         }
  168.         return $methods;
  169.     }
  170.  
  171.     /**
  172.      *    Tests to see if the method is a test that should
  173.      *    be run. Currently any method that starts with 'test'
  174.      *    is a candidate unless it is the constructor.
  175.      *    @param string $method        Method name to try.
  176.      *    @return boolean              True if test method.
  177.      *    @access protected
  178.      */
  179.     function _isTest($method{
  180.         if (strtolower(substr($method04)) == 'test'{
  181.             return SimpleTestCompatibility::isA($thisstrtolower($method));
  182.         }
  183.         return false;
  184.     }
  185.  
  186.     /**
  187.      *    Announces the start of the test.
  188.      *    @param string $method    Test method just started.
  189.      *    @access public
  190.      */
  191.     function before($method{
  192.         $this->_reporter->paintMethodStart($method);
  193.         $this->_observers = array();
  194.     }
  195.  
  196.     /**
  197.      *    Sets up unit test wide variables at the start
  198.      *    of each test method. To be overridden in
  199.      *    actual user test cases.
  200.      *    @access public
  201.      */
  202.     function setUp({
  203.     }
  204.  
  205.     /**
  206.      *    Clears the data set in the setUp() method call.
  207.      *    To be overridden by the user in actual user test cases.
  208.      *    @access public
  209.      */
  210.     function tearDown({
  211.     }
  212.  
  213.     /**
  214.      *    Announces the end of the test. Includes private clean up.
  215.      *    @param string $method    Test method just finished.
  216.      *    @access public
  217.      */
  218.     function after($method{
  219.         for ($i 0$i count($this->_observers)$i++{
  220.             $this->_observers[$i]->atTestEnd($method$this);
  221.         }
  222.         $this->_reporter->paintMethodEnd($method);
  223.     }
  224.  
  225.     /**
  226.      *    Sets up an observer for the test end.
  227.      *    @param object $observer    Must have atTestEnd()
  228.      *                                method.
  229.      *    @access public
  230.      */
  231.     function tell(&$observer{
  232.         $this->_observers[&$observer;
  233.     }
  234.  
  235.     /**
  236.      *    @deprecated
  237.      */
  238.     function pass($message "Pass"{
  239.         if (isset($this->_reporter)) {
  240.             trigger_error('Can only make assertions within test methods');
  241.         }
  242.         $this->_reporter->paintPass(
  243.                 $message $this->getAssertionLine());
  244.         return true;
  245.     }
  246.  
  247.     /**
  248.      *    Sends a fail event with a message.
  249.      *    @param string $message        Message to send.
  250.      *    @access public
  251.      */
  252.     function fail($message "Fail"{
  253.         if (isset($this->_reporter)) {
  254.             trigger_error('Can only make assertions within test methods');
  255.         }
  256.         $this->_reporter->paintFail(
  257.                 $message $this->getAssertionLine());
  258.         return false;
  259.     }
  260.  
  261.     /**
  262.      *    Formats a PHP error and dispatches it to the
  263.      *    reporter.
  264.      *    @param integer $severity  PHP error code.
  265.      *    @param string $message    Text of error.
  266.      *    @param string $file       File error occoured in.
  267.      *    @param integer $line      Line number of error.
  268.      *    @access public
  269.      */
  270.     function error($severity$message$file$line{
  271.         if (isset($this->_reporter)) {
  272.             trigger_error('Can only make assertions within test methods');
  273.         }
  274.         $this->_reporter->paintError(
  275.                 "Unexpected PHP error [$message] severity [$severity] in [$file line $line]");
  276.     }
  277.  
  278.     /**
  279.      *    Formats an exception and dispatches it to the
  280.      *    reporter.
  281.      *    @param Exception $exception    Object thrown.
  282.      *    @access public
  283.      */
  284.     function exception($exception{
  285.         $this->_reporter->paintException($exception);
  286.     }
  287.  
  288.     /**
  289.      *    @deprecated
  290.      */
  291.     function signal($type&$payload{
  292.         if (isset($this->_reporter)) {
  293.             trigger_error('Can only make assertions within test methods');
  294.         }
  295.         $this->_reporter->paintSignal($type$payload);
  296.     }
  297.  
  298.     /**
  299.      *    Runs an expectation directly, for extending the
  300.      *    tests with new expectation classes.
  301.      *    @param SimpleExpectation $expectation  Expectation subclass.
  302.      *    @param mixed $compare               Value to compare.
  303.      *    @param string $message                 Message to display.
  304.      *    @return boolean                        True on pass
  305.      *    @access public
  306.      */
  307.     function assert(&$expectation$compare$message '%s'{
  308.         if ($expectation->test($compare)) {
  309.             return $this->pass(sprintf(
  310.                     $message,
  311.                     $expectation->overlayMessage($compare$this->_reporter->getDumper())));
  312.         else {
  313.             return $this->fail(sprintf(
  314.                     $message,
  315.                     $expectation->overlayMessage($compare$this->_reporter->getDumper())));
  316.         }
  317.     }
  318.  
  319.     /**
  320.      *    @deprecated
  321.      */
  322.     function assertExpectation(&$expectation$compare$message '%s'{
  323.         return $this->assert($expectation$compare$message);
  324.     }
  325.  
  326.     /**
  327.      *    Uses a stack trace to find the line of an assertion.
  328.      *    @return string           Line number of first assert*
  329.      *                              method embedded in format string.
  330.      *    @access public
  331.      */
  332.     function getAssertionLine({
  333.         $trace new SimpleStackTrace(array('assert''expect''pass''fail''skip'));
  334.         return $trace->traceMethod();
  335.     }
  336.  
  337.     /**
  338.      *    Sends a formatted dump of a variable to the
  339.      *    test suite for those emergency debugging
  340.      *    situations.
  341.      *    @param mixed $variable    Variable to display.
  342.      *    @param string $message    Message to display.
  343.      *    @return mixed             The original variable.
  344.      *    @access public
  345.      */
  346.     function dump($variable$message false{
  347.         $dumper $this->_reporter->getDumper();
  348.         $formatted $dumper->dump($variable);
  349.         if ($message{
  350.             $formatted $message "\n" $formatted;
  351.         }
  352.         $this->_reporter->paintFormattedMessage($formatted);
  353.         return $variable;
  354.     }
  355.  
  356.     /**
  357.      *    @deprecated
  358.      */
  359.     function sendMessage($message{
  360.         $this->_reporter->PaintMessage($message);
  361.     }
  362.  
  363.     /**
  364.      *    Accessor for the number of subtests including myelf.
  365.      *    @return integer           Number of test cases.
  366.      *    @access public
  367.      *    @static
  368.      */
  369.     function getSize({
  370.         return 1;
  371.     }
  372. }
  373.  
  374. /**
  375.  *  Helps to extract test cases automatically from a file.
  376.  */
  377.  
  378.     /**
  379.      *    Builds a test suite from a library of test cases.
  380.      *    The new suite is composed into this one.
  381.      *    @param string $test_file        File name of library with
  382.      *                                     test case classes.
  383.      *    @return TestSuite               The new test suite.
  384.      *    @access public
  385.      */
  386.     function &load($test_file{
  387.         $existing_classes get_declared_classes();
  388.         $existing_globals get_defined_vars();
  389.         include_once($test_file);
  390.         $new_globals get_defined_vars();
  391.         $this->_makeFileVariablesGlobal($existing_globals$new_globals);
  392.         $new_classes array_diff(get_declared_classes()$existing_classes);
  393.         if (empty($new_classes)) {
  394.             $new_classes $this->_scrapeClassesFromFile($test_file);
  395.         }
  396.         $classes $this->selectRunnableTests($new_classes);
  397.         $suite &$this->createSuiteFromClasses($test_file$classes);
  398.         return $suite;
  399.     }
  400.     
  401.     /**
  402.      *    Imports new variables into the global namespace.
  403.      *    @param hash $existing   Variables before the file was loaded.
  404.      *    @param hash $new        Variables after the file was loaded.
  405.      *    @access private
  406.      */
  407.     function _makeFileVariablesGlobal($existing$new{
  408.         $globals array_diff(array_keys($new)array_keys($existing));
  409.         foreach ($globals as $global{
  410.             $_GLOBALS[$global$new[$global];
  411.         }
  412.     }
  413.     
  414.     /**
  415.      *    Lookup classnames from file contents, in case the
  416.      *    file may have been included before.
  417.      *    Note: This is probably too clever by half. Figuring this
  418.      *    out after a failed test case is going to be tricky for us,
  419.      *    never mind the user. A test case should not be included
  420.      *    twice anyway.
  421.      *    @param string $test_file        File name with classes.
  422.      *    @access private
  423.      */
  424.     function _scrapeClassesFromFile($test_file{
  425.         preg_match_all('~^\s*class\s+(\w+)(\s+(extends|implements)\s+\w+)*\s*\{~mi',
  426.                         file_get_contents($test_file),
  427.                         $matches );
  428.         return $matches[1];
  429.     }
  430.  
  431.     /**
  432.      *    Calculates the incoming test cases. Skips abstract
  433.      *    and ignored classes.
  434.      *    @param array $candidates   Candidate classes.
  435.      *    @return array              New classes which are test
  436.      *                                cases that shouldn't be ignored.
  437.      *    @access public
  438.      */
  439.     function selectRunnableTests($candidates{
  440.         $classes array();
  441.         foreach ($candidates as $class{
  442.             if (TestSuite::getBaseTestCase($class)) {
  443.                 $reflection new SimpleReflection($class);
  444.                 if ($reflection->isAbstract()) {
  445.                     SimpleTest::ignore($class);
  446.                 else {
  447.                     $classes[$class;
  448.                 }
  449.             }
  450.         }
  451.         return $classes;
  452.     }
  453.  
  454.     /**
  455.      *    Builds a test suite from a class list.
  456.      *    @param string $title       Title of new group.
  457.      *    @param array $classes      Test classes.
  458.      *    @return TestSuite          Group loaded with the new
  459.      *                                test cases.
  460.      *    @access public
  461.      */
  462.     function &createSuiteFromClasses($title$classes{
  463.         if (count($classes== 0{
  464.             $suite &new BadTestSuite($title"No runnable test cases in [$title]");
  465.             return $suite;
  466.         }
  467.         SimpleTest::ignoreParentsIfIgnored($classes);
  468.         $suite &new TestSuite($title);
  469.         foreach ($classes as $class{
  470.             if (SimpleTest::isIgnored($class)) {
  471.                 $suite->addTestClass($class);
  472.             }
  473.         }
  474.         return $suite;
  475.     }
  476. }
  477.  
  478. /**
  479.  *    This is a composite test class for combining
  480.  *    test cases and other RunnableTest classes into
  481.  *    a group test.
  482.  *    @package      SimpleTest
  483.  *    @subpackage   UnitTester
  484.  */
  485. class TestSuite {
  486.     var $_label;
  487.     var $_test_cases;
  488.  
  489.     /**
  490.      *    Sets the name of the test suite.
  491.      *    @param string $label    Name sent at the start and end
  492.      *                             of the test.
  493.      *    @access public
  494.      */
  495.     function TestSuite($label false{
  496.         $this->_label = $label;
  497.         $this->_test_cases = array();
  498.     }
  499.  
  500.     /**
  501.      *    Accessor for the test name for subclasses. If the suite
  502.      *    wraps a single test case the label defaults to the name of that test.
  503.      *    @return string           Name of the test.
  504.      *    @access public
  505.      */
  506.     function getLabel({
  507.         if ($this->_label{
  508.             return ($this->getSize(== 1?
  509.                     get_class($this->_test_cases[0]get_class($this);
  510.         else {
  511.             return $this->_label;
  512.         }
  513.     }
  514.  
  515.     /**
  516.      *    @deprecated
  517.      */
  518.     function addTestCase(&$test_case{
  519.         $this->_test_cases[&$test_case;
  520.     }
  521.  
  522.     /**
  523.      *    @deprecated
  524.      */
  525.     function addTestClass($class{
  526.         if (TestSuite::getBaseTestCase($class== 'testsuite'{
  527.             $this->_test_cases[&new $class();
  528.         else {
  529.             $this->_test_cases[$class;
  530.         }
  531.     }
  532.  
  533.     /**
  534.      *    Adds a test into the suite by instance or class. The class will
  535.      *    be instantiated if it's a test suite.
  536.      *    @param SimpleTestCase $test_case  Suite or individual test
  537.      *                                       case implementing the
  538.      *                                       runnable test interface.
  539.      *    @access public
  540.      */
  541.     function add(&$test_case{
  542.         if (is_string($test_case)) {
  543.             $this->_test_cases[&$test_case;
  544.         elseif (TestSuite::getBaseTestCase($class== 'testsuite'{
  545.             $this->_test_cases[&new $class();
  546.         else {
  547.             $this->_test_cases[$class;
  548.         }
  549.     }
  550.  
  551.     /**
  552.      *    @deprecated
  553.      */
  554.     function addTestFile($test_file{
  555.         $this->addFile($test_file);
  556.     }
  557.  
  558.     /**
  559.      *    Builds a test suite from a library of test cases.
  560.      *    The new suite is composed into this one.
  561.      *    @param string $test_file        File name of library with
  562.      *                                     test case classes.
  563.      *    @access public
  564.      */
  565.     function addFile($test_file{
  566.         $extractor new SimpleFileLoader();
  567.         $this->add($extractor->load($test_file));
  568.     }
  569.  
  570.     /**
  571.      *    Delegates to a visiting collector to add test
  572.      *    files.
  573.      *    @param string $path                  Path to scan from.
  574.      *    @param SimpleCollector $collector    Directory scanner.
  575.      *    @access public
  576.      */
  577.     function collect($path&$collector{
  578.         $collector->collect($this$path);
  579.     }
  580.  
  581.     /**
  582.      *    Invokes run() on all of the held test cases, instantiating
  583.      *    them if necessary.
  584.      *    @param SimpleReporter $reporter    Current test reporter.
  585.      *    @access public
  586.      */
  587.     function run(&$reporter{
  588.         $reporter->paintGroupStart($this->getLabel()$this->getSize());
  589.         for ($i 0$count count($this->_test_cases)$i $count$i++{
  590.             if (is_string($this->_test_cases[$i])) {
  591.                 $class $this->_test_cases[$i];
  592.                 $test &new $class();
  593.                 $test->run($reporter);
  594.                 unset($test);
  595.             else {
  596.                 $this->_test_cases[$i]->run($reporter);
  597.             }
  598.         }
  599.         $reporter->paintGroupEnd($this->getLabel());
  600.         return $reporter->getStatus();
  601.     }
  602.  
  603.     /**
  604.      *    Number of contained test cases.
  605.      *    @return integer     Total count of cases in the group.
  606.      *    @access public
  607.      */
  608.     function getSize({
  609.         $count 0;
  610.         foreach ($this->_test_cases as $case{
  611.             if (is_string($case)) {
  612.                 if (SimpleTest::isIgnored($case)) {
  613.                     $count++;
  614.                 }
  615.             else {
  616.                 $count += $case->getSize();
  617.             }
  618.         }
  619.         return $count;
  620.     }
  621.  
  622.     /**
  623.      *    Test to see if a class is derived from the
  624.      *    SimpleTestCase class.
  625.      *    @param string $class     Class name.
  626.      *    @access public
  627.      *    @static
  628.      */
  629.     function getBaseTestCase($class{
  630.         while ($class get_parent_class($class)) {
  631.             $class strtolower($class);
  632.             if ($class == 'simpletestcase' || $class == 'testsuite'{
  633.                 return $class;
  634.             }
  635.         }
  636.         return false;
  637.     }
  638. }
  639.  
  640. /**
  641.  *    @package      SimpleTest
  642.  *    @subpackage   UnitTester
  643.  *    @deprecated
  644.  */
  645. class GroupTest extends TestSuite }
  646.  
  647. /**
  648.  *    This is a failing group test for when a test suite hasn't
  649.  *    loaded properly.
  650.  *    @package      SimpleTest
  651.  *    @subpackage   UnitTester
  652.  */
  653. class BadTestSuite {
  654.     var $_label;
  655.     var $_error;
  656.  
  657.     /**
  658.      *    Sets the name of the test suite and error message.
  659.      *    @param string $label    Name sent at the start and end
  660.      *                             of the test.
  661.      *    @access public
  662.      */
  663.     function BadTestSuite($label$error{
  664.         $this->_label = $label;
  665.         $this->_error = $error;
  666.     }
  667.  
  668.     /**
  669.      *    Accessor for the test name for subclasses.
  670.      *    @return string           Name of the test.
  671.      *    @access public
  672.      */
  673.     function getLabel({
  674.         return $this->_label;
  675.     }
  676.  
  677.     /**
  678.      *    Sends a single error to the reporter.
  679.      *    @param SimpleReporter $reporter    Current test reporter.
  680.      *    @access public
  681.      */
  682.     function run(&$reporter{
  683.         $reporter->paintGroupStart($this->getLabel()$this->getSize());
  684.         $reporter->paintFail('Bad TestSuite [' $this->getLabel(.
  685.                 '] with error [' $this->_error . ']');
  686.         $reporter->paintGroupEnd($this->getLabel());
  687.         return $reporter->getStatus();
  688.     }
  689.  
  690.     /**
  691.      *    Number of contained test cases. Always zero.
  692.      *    @return integer     Total count of cases in the group.
  693.      *    @access public
  694.      */
  695.     function getSize({
  696.         return 0;
  697.     }
  698. }
  699.  
  700. /**
  701.  *    @package      SimpleTest
  702.  *    @subpackage   UnitTester
  703.  *    @deprecated
  704.  */
  705. class BadGroupTest extends BadTestSuite }
  706. ?>

Documentation generated on Sun, 04 May 2008 09:22:18 -0500 by phpDocumentor 1.3.0