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

Documentation generated on Thu, 01 Oct 2009 20:56:04 -0500 by phpDocumentor 1.4.2