Testing_DocTest
[ class tree: Testing_DocTest ] [ index: Testing_DocTest ] [ all elements ]

Source for file Default.php

Documentation is available at Default.php

  1. <?php
  2.  
  3. /* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
  4.  
  5. /**
  6.  * This file is part of the PEAR Testing_DocTest package.
  7.  *
  8.  * PHP version 5
  9.  *
  10.  * LICENSE: This source file is subject to the MIT license that is available
  11.  * through the world-wide-web at the following URI:
  12.  * http://opensource.org/licenses/mit-license.php
  13.  *
  14.  * @category  Testing
  15.  * @package   Testing_DocTest
  16.  * @author    David JEAN LOUIS <izimobil@gmail.com>
  17.  * @copyright 2008 David JEAN LOUIS
  18.  * @license   http://opensource.org/licenses/mit-license.php MIT License
  19.  * @version   CVS: $Id: Default.php,v 1.2 2009/03/01 10:14:15 izi Exp $
  20.  * @link      http://pear.php.net/package/Testing_DocTest
  21.  * @since     File available since release 0.1.0
  22.  * @filesource
  23.  */
  24.  
  25. /**
  26.  * Required file.
  27.  */
  28. require_once 'Testing/DocTest/ParserInterface.php';
  29. require_once 'Testing/DocTest/TestSuite.php';
  30. require_once 'Testing/DocTest/TestCase.php';
  31.  
  32. /**
  33.  * DocTest Parser default class.
  34.  * Important note: this class will be refactored soon so do not rely on it yet
  35.  * if you want to subclass or customize Testing_DocTest.
  36.  *
  37.  * @category  Testing
  38.  * @package   Testing_DocTest
  39.  * @author    David JEAN LOUIS <izimobil@gmail.com>
  40.  * @copyright 2008 David JEAN LOUIS
  41.  * @license   http://opensource.org/licenses/mit-license.php MIT License
  42.  * @version   Release: 0.3.1
  43.  * @link      http://pear.php.net/package/Testing_DocTest
  44.  * @since     Class available since release 0.1.0
  45.  */
  46. class Testing_DocTest_Parser_Default implements Testing_DocTest_ParserInterface
  47. {
  48.     // doctest syntax prefix {{{
  49.  
  50.     /**
  51.      * Doctest syntax prefix default is a standard php inline comment: '//'
  52.      */
  53.     const SYNTAX_PREFIX = '//';
  54.  
  55.     // }}}
  56.     // Keywords constants {{{
  57.  
  58.     /**
  59.      * Keyword for the name of the external doctest file
  60.      */
  61.     const KW_DOCTEST_FILE = 'test-file';
  62.     
  63.     /**
  64.      * Keyword for the name of the doctest
  65.      */
  66.     const KW_DOCTEST_NAME = 'doctest';
  67.  
  68.     /**
  69.      * Keyword for the doctest flags
  70.      */
  71.     const KW_DOCTEST_FLAGS = 'flags';
  72.  
  73.     /**
  74.      * Keyword for the skip condition
  75.      */
  76.     const KW_DOCTEST_SKIP_IF = 'skip-if';
  77.  
  78.     /**
  79.      * Keyword for the ini settings
  80.      */
  81.     const KW_DOCTEST_INI_SET = 'ini-set';
  82.  
  83.     /**
  84.      * Keyword for the doctest expected result
  85.      */
  86.     const KW_DOCTEST_EXPECTS = 'expects';
  87.  
  88.     /**
  89.      * Keyword for the doctest expected file
  90.      */
  91.     const KW_DOCTEST_EXPECTS_FILE = 'expects-file';
  92.  
  93.     /**
  94.      * Keyword for the clean part
  95.      */
  96.     const KW_DOCTEST_CLEAN = 'clean';
  97.  
  98.     // }}}
  99.     // State constants {{{
  100.  
  101.     /**
  102.      * State after parsing a doctest line.
  103.      */
  104.     const STATE_DOCTEST = 1;
  105.  
  106.     /**
  107.      * State after parsing flags.
  108.      */
  109.     const STATE_FLAGS = 2;
  110.  
  111.     /**
  112.      * State after parsing a skip condition line.
  113.      */
  114.     const STATE_SKIP_IF = 3;
  115.  
  116.     /**
  117.      * State after parsing a ini-set line.
  118.      */
  119.     const STATE_INI_SET = 4;
  120.  
  121.     /**
  122.      * State after parsing expects line.
  123.      */
  124.     const STATE_EXPECTS = 5;
  125.  
  126.     /**
  127.      * State after parsing expects-file line.
  128.      */
  129.     const STATE_EXPECTS_FILE = 6;
  130.  
  131.     /**
  132.      * State after parsing code line.
  133.      */
  134.     const STATE_CODE = 7;
  135.  
  136.     /**
  137.      * State after parsing clean line.
  138.      */
  139.     const STATE_CLEAN = 8;
  140.  
  141.     // }}}
  142.     // Properties {{{
  143.  
  144.     /**
  145.      * Current state of the parser, null or one of the STATE_*  constants.
  146.      *
  147.      * @var int $_state 
  148.      * @access private
  149.      */
  150.     private $_state = null;
  151.  
  152.     /**
  153.      * Testing_DocTest_TestCase instance.
  154.      *
  155.      * @var object $_testCase 
  156.      * @access private
  157.      */
  158.     private $_testCase = null;
  159.  
  160.     // }}}
  161.     // parse() {{{
  162.  
  163.     /**
  164.      * Parse the files passed and return an array of Testing_DocTest_TestSuite
  165.      * instances.
  166.      *
  167.      * @param array $files an array of file pathes
  168.      *
  169.      * @access public
  170.      * @return array 
  171.      */
  172.     public function parse(array $files)
  173.     {
  174.         $ret = array();
  175.         $kw  = preg_quote(self::KW_DOCTEST_NAME'/')    '|'
  176.              . preg_quote(self::KW_DOCTEST_FLAGS'/')   '|'
  177.              . preg_quote(self::KW_DOCTEST_SKIP_IF'/''|'
  178.              . preg_quote(self::KW_DOCTEST_INI_SET'/''|'
  179.              . preg_quote(self::KW_DOCTEST_CLEAN'/')   '|'
  180.              . preg_quote(self::KW_DOCTEST_EXPECTS'/''|'
  181.              . preg_quote(self::KW_DOCTEST_EXPECTS_FILE'/');
  182.         foreach ($files as $file{
  183.             $testCaseArray $this->_parseFile($file);
  184.             $suite         = false;
  185.             foreach ($testCaseArray as $testCaseData{
  186.                 // split raw code into lines
  187.                 $docblocs $this->_extractCodeBlocs($testCaseData['docComment']);
  188.                 // build our suite
  189.                 if (!empty($docblocs&& false == $suite{
  190.                     $suite       = new Testing_DocTest_TestSuite();
  191.                     $suite->name = $file
  192.                 }
  193.                 foreach ($docblocs as $docbloc{
  194.                     $this->_testCase        = new Testing_DocTest_TestCase();
  195.                     $this->_testCase->file  = $file;
  196.                     $this->_testCase->level = $testCaseData['level'];
  197.                     $this->_testCase->name  = $testCaseData['name'];
  198.                     // split string into an array of lines
  199.                     $lines preg_split('/(\n|\r\n)/'$docbloc);
  200.                     foreach ($lines as $i=>$l{
  201.                         // remove spaces and * at the beginning
  202.                         $l preg_replace('/^\s*\*\s?/'''$l);
  203.                         $p preg_quote(self::SYNTAX_PREFIX'/');
  204.                         if (preg_match("/^\s*$p\s?($kw):\s*(.*)$/"$l$m)) {
  205.                             switch ($m[1]{
  206.                             case self::KW_DOCTEST_NAME:
  207.                                 $this->_handleDoctestLine($m[2]);
  208.                                 break;
  209.                             case self::KW_DOCTEST_FLAGS:
  210.                                 $this->_handleFlagsLine($m[2]);
  211.                                 break;
  212.                             case self::KW_DOCTEST_SKIP_IF:
  213.                                 $this->_handleFlagsLine($m[2]);
  214.                                 break;
  215.                             case self::KW_DOCTEST_INI_SET:
  216.                                 $this->_handleIniSetLine($m[2]);
  217.                                 break;
  218.                             case self::KW_DOCTEST_EXPECTS:
  219.                                 $this->_handleExpectsLine($m[2]);
  220.                                 break;
  221.                             case self::KW_DOCTEST_EXPECTS_FILE:
  222.                                 $this->_handleExpectsFileLine($m[2]);
  223.                                 break;
  224.                             case self::KW_DOCTEST_CLEAN:
  225.                                 $this->_handleCleanLine($m[2]);
  226.                             }
  227.                         else if (preg_match('/^\s*'.$p.'\s?(.*)$/'$l$m)) {
  228.                             $this->_handleLineContinuation($m[1]);
  229.                         else {
  230.                             if (trim($l!= ''{
  231.                                 $this->_handleCodeLine($l);
  232.                             }
  233.                         }
  234.                     }
  235.                 
  236.                     // trim last eol
  237.                     $this->_testCase->expectedValue =
  238.                         substr($this->_testCase->expectedValue0-1);
  239.                     // reset state
  240.                     $this->_state = null;
  241.                     // append the test case
  242.                     $suite->addTestCase($this->_testCase);
  243.                 }
  244.             }
  245.             if ($suite{
  246.                 $ret[$suite;
  247.             }
  248.         }
  249.         return $ret;
  250.     }
  251.  
  252.     // }}}
  253.     // _parseFile() {{{
  254.  
  255.     /**
  256.      * Parse the file $file and return an array of Testing_DocTest_TestCase
  257.      * instances.
  258.      *
  259.      * @param string $file path to the file to parse.
  260.      *
  261.      * @access private
  262.      * @return array 
  263.      */
  264.     private function _parseFile($file)
  265.     {
  266.         $return = array();
  267.         $tokens $this->_tokenize($file);
  268.         if (false === $tokens{
  269.             // return an empty array
  270.             return $return;
  271.         }
  272.         $curlyLevel = -1;
  273.         $curlyOpen  = -1;
  274.         $className  = null;
  275.         $inClass    = false;
  276.         while (false !== ($item each($tokens))) {
  277.             // memoize curly level in order to detect if we are inside a class
  278.             if (is_string($item['value'])) {
  279.                 if ($item['value'== '{'{
  280.                     $curlyLevel++;
  281.                 else if ($item['value'== '}' && --$curlyLevel == $curlyOpen{
  282.                     // curly is the close curly of current class
  283.                     $inClass = false;
  284.                 }
  285.                 continue;
  286.             }
  287.             list($id$token$line$item['value'];
  288.             // skip all tokens but doc comments
  289.             if ($id !== T_DOC_COMMENT{
  290.                 continue;
  291.             }
  292.             // find next token
  293.             $ids  = array(T_CLASST_FUNCTIONT_DOC_COMMENT);
  294.             $next $this->_findNextToken($ids$tokens);
  295.             if (false === $next && !empty($return)) {
  296.                 break;
  297.             }
  298.             // build Testing_DocTest_TestCase instance
  299.             $ret               = array();
  300.             $ret['docComment'$token;
  301.             $ret['file']       $file;
  302.             if (false === $next || T_DOC_COMMENT === $next[0]{
  303.                 $ret['name']  'test';
  304.                 $ret['level''file level';
  305.             else {
  306.                 $nToken $this->_findNextToken(T_STRING$tokens);
  307.                 if (false === $nToken{
  308.                     continue;
  309.                 }
  310.                 if ($next[0=== T_CLASS{
  311.                     $inClass      = true;
  312.                     $curlyOpen    $curlyLevel;
  313.                     $ret['name']  $nToken[1];
  314.                     $className    $nToken[1];
  315.                     $ret['level''class';
  316.                 else if ($inClass{
  317.                     $ret['name']  $className '::' $nToken[1];
  318.                     $ret['level''method';
  319.                 else {
  320.                     $ret['name']  $nToken[1];
  321.                     $ret['level''function';
  322.                 }
  323.             }
  324.             $return[$ret;
  325.         }
  326.         return $return;
  327.     }
  328.  
  329.     // }}}
  330.     // _tokenize() {{{
  331.  
  332.     /**
  333.      * Tokenize the file $file into an array of tokens using the builtin php
  334.      * tokenizer extension. Before tokenizing the method check that the file
  335.      * contains at least a doctest.
  336.      *
  337.      * @param string $file the file to parse.
  338.      *
  339.      * @access private
  340.      * @return array array of tokens
  341.      */
  342.     private function _tokenize($file)
  343.     
  344.         $data file_get_contents($file);
  345.         // speed improvement, don't bother tokenizing file if it does not 
  346.         // contain any doctest
  347.         if (false === strstr($dataself::KW_DOCTEST_EXPECTS)) {
  348.             return array();
  349.         }
  350.         return token_get_all($data);
  351.     }
  352.  
  353.     // }}}
  354.     // _findNextToken() {{{
  355.  
  356.     /**
  357.      * Find the next token matching the id $id and return it or return false if
  358.      * no matching token is found.
  359.      *
  360.      * @param mixed $id      id or array of ids the token must match
  361.      * @param array &$tokens tokens array passed by reference
  362.      *
  363.      * @access private
  364.      * @return array array of tokens
  365.      */
  366.     private function _findNextToken($id&$tokens)
  367.     
  368.         $next current($tokens);
  369.         while ($next !== false{
  370.             if (!is_string($next)) {
  371.                 if (is_int($id&& $next[0=== $id{
  372.                     return $next;
  373.                 }
  374.                 if (is_array($id&& in_array($next[0]$id)) {
  375.                     return $next;
  376.                 }
  377.             }
  378.             // move to next token
  379.             $next next($tokens);
  380.         }
  381.         return false;
  382.     }
  383.  
  384.     // }}}
  385.     // _extractCodeBlocs() {{{
  386.  
  387.     /**
  388.      * Extract all <code></code> blocs in the given raw docstring.
  389.      *
  390.      * @param string $docstring raw docstring
  391.      *
  392.      * @access private
  393.      * @return array an array of code blocs strings.
  394.      */
  395.     private function _extractCodeBlocs($docstring)
  396.     {
  397.         $ret = array();
  398.         // extract <code></code> blocks, we use preg_match_all because there 
  399.         // could be more than one code block by docstring
  400.         $rx '/<code>[\s\*]*(<[\?\%](php)?)?\s*' 
  401.             . '(.*?)\s*([\?\%]>)?[\s\*]*<\/code>/si';
  402.         preg_match_all($rx$docstring$tokens);
  403.         if (isset($tokens[3]&& is_array($tokens[3])) {
  404.             foreach ($tokens[3as $i => $token{
  405.                 if ($this->_hasStandaloneDoctest($token)) {
  406.                     $testfile_contents $this->_handleStandaloneDoctest($token);
  407.                     if ($testfile_contents !== false{
  408.                         // replace the current doctest code with the contents
  409.                         // of the external included file
  410.                         $token $testfile_contents;
  411.                     }
  412.                 }
  413.                 if (!$this->_hasDocTest($token)) {
  414.                     // not a doctest
  415.                     continue;
  416.                 }
  417.                 $ret[$token;
  418.             }
  419.         }
  420.         return $ret;
  421.     }
  422.  
  423.     // }}}
  424.     // _hasStandaloneDoctest() {{{
  425.  
  426.     /**
  427.      * Return true if the string data provided contains an external doctest file.
  428.      *
  429.      * @param string $data The docstring data
  430.      *
  431.      * @return boolean 
  432.      */
  433.     private function _hasStandaloneDoctest($data)
  434.     {
  435.         $p preg_quote(self::SYNTAX_PREFIX'/');
  436.         $k preg_quote(self::KW_DOCTEST_FILE'/');
  437.         return preg_match("/$p\s?$k/m"$data);
  438.     }
  439.  
  440.     // }}}
  441.     // _hasDocTest() {{{
  442.  
  443.     /**
  444.      * Return true if the string data provided contains a doctest.
  445.      *
  446.      * @param string $data string data
  447.      *
  448.      * @access private
  449.      * @return boolean 
  450.      */
  451.     private function _hasDocTest($data)
  452.     {
  453.         $p preg_quote(self::SYNTAX_PREFIX'/');
  454.         $k preg_quote(self::KW_DOCTEST_EXPECTS'/');
  455.         return preg_match("/$p\s?$k/m"$data);
  456.     }
  457.  
  458.     // }}}
  459.     // _handleStandaloneDoctest() {{{
  460.  
  461.     /**
  462.      * Return the contents of the external doctest file.
  463.      *
  464.      * @param string $docbloc The docstring data
  465.      *
  466.      * @return mixed boolean or string
  467.      */
  468.     private function _handleStandaloneDoctest($docbloc)
  469.     {
  470.         $p     preg_quote(self::SYNTAX_PREFIX'/');
  471.         $k     preg_quote(self::KW_DOCTEST_FILE'/');
  472.         $lines preg_split('/(\n|\r\n)/'$docbloc);
  473.  
  474.         foreach ($lines as $i => $l{
  475.             $l preg_replace('/^\s*\*\s?/'''$l);
  476.             $p preg_quote(self::SYNTAX_PREFIX'/');
  477.             if (preg_match("/^\s*$p\s?($k):\s*(.*)$/"$l$matches)) {
  478.                 $f trim($matches[2]);
  479.                 if (false === ($contents @file_get_contents(realpath($f)))) {
  480.                     throw new Testing_DocTest_Exception(
  481.                         "Unable to read standalone doctest file \"$f\""
  482.                     );
  483.                 }
  484.                 // remove the php tags
  485.                 $rx '/(<[\?\%](php)?)?(.*?)([\?\%]>)?/si';
  486.                 return preg_replace($rx'\3'$contents);
  487.             }
  488.         }
  489.         return false;
  490.             
  491.     }
  492.  
  493.     // }}}
  494.     // _handleDoctestLine() {{{
  495.  
  496.     /**
  497.      * Parse the doctest line provided.
  498.      *
  499.      * @param string $line the line of code to parse
  500.      *
  501.      * @access private
  502.      * @return void 
  503.      * @throws Testing_DocTest_Exception
  504.      */
  505.     private function _handleDoctestLine($line)
  506.     {
  507.         $states = array(nullself::STATE_FLAGSself::STATE_DOCTEST,
  508.             self::STATE_SKIP_IFself::STATE_INI_SET);
  509.         if (!in_array($this->_state$states)) {
  510.             throw new Testing_DocTest_Exception("Unexpected doctest line: $line");
  511.         }
  512.         $this->_testCase->altname .= $line;
  513.         $this->_state              = self::STATE_DOCTEST;
  514.     }
  515.  
  516.     // }}}
  517.     // _handleFlagsLine() {{{
  518.  
  519.     /**
  520.      * Parse the flag line provided.
  521.      *
  522.      * @param string $line The flag line to parse
  523.      *
  524.      * @access private
  525.      * @return void 
  526.      * @throws Testing_DocTest_Exception
  527.      */
  528.     private function _handleFlagsLine($line)
  529.     {
  530.         $states = array(nullself::STATE_FLAGSself::STATE_DOCTEST,
  531.             self::STATE_SKIP_IFself::STATE_INI_SET);
  532.         if (!in_array($this->_state$states)) {
  533.             throw new Testing_DocTest_Exception("Unexpected flags line: $line");
  534.         }
  535.         $flags explode(','$line);
  536.         foreach ($flags as $flag{
  537.             $const 'Testing_DocTest::FLAG_' strtoupper(trim($flag));
  538.             if (defined($const)) {
  539.                 $this->_testCase->flags |= constant($const);
  540.             }
  541.         }
  542.         $this->_state = self::STATE_FLAGS;
  543.     }
  544.  
  545.     // }}}
  546.     // _handleExpectsLine() {{{
  547.  
  548.     /**
  549.      * Parse the expects line provided.
  550.      *
  551.      * @param string $line the expects line to parse
  552.      *
  553.      * @access private
  554.      * @return void 
  555.      * @throws Testing_DocTest_Exception
  556.      */
  557.     private function _handleExpectsLine($line)
  558.     {
  559.         $states = array(self::STATE_CODEself::STATE_EXPECTS);
  560.         if (!in_array($this->_state$states)) {
  561.             throw new Exception("unexpected expects line: $line");
  562.         }
  563.         $this->_testCase->expectedValue .= $line;
  564.         // handle line continuation
  565.         if (substr(trim($line)-1!== '\\'{
  566.             $this->_testCase->expectedValue .= "\n";
  567.         else {
  568.             $this->_testCase->expectedValue = 
  569.                 trim($this->_testCase->expectedValue'\\');
  570.         }
  571.         $this->_state = self::STATE_EXPECTS;
  572.     }
  573.  
  574.     // }}}
  575.     // _handleExpectsFileLine() {{{
  576.  
  577.     /**
  578.      * Parse the expects-file line provided.
  579.      *
  580.      * @param string $line the expects-file line to parse
  581.      *
  582.      * @access private
  583.      * @return void 
  584.      * @throws Testing_DocTest_Exception
  585.      */
  586.     private function _handleExpectsFileLine($line)
  587.     {
  588.         $states = array(self::STATE_CODEself::STATE_EXPECTS_FILE);
  589.         if (!in_array($this->_state$states)) {
  590.             throw new Exception("unexpected expects-file line: $line");
  591.         }
  592.         $f realpath(trim($line));
  593.         if (false === ($contents @file_get_contents($f))) {
  594.             throw new Testing_DocTest_Exception("Unable to read expects file $f");
  595.         }
  596.         $this->_testCase->expectedValue = $contents;
  597.         $this->_state                   = self::STATE_EXPECTS_FILE;
  598.     }
  599.  
  600.     // }}}
  601.     // _handleCodeLine() {{{
  602.  
  603.     /**
  604.      * Parse the code line provided.
  605.      *
  606.      * @param string $line the code line to parse
  607.      *
  608.      * @access private
  609.      * @return void 
  610.      * @throws Testing_DocTest_Exception
  611.      */
  612.     private function _handleCodeLine($line)
  613.     {
  614.         $states = array(self::STATE_EXPECTSself::STATE_EXPECTS_FILE);
  615.         if (in_array($this->_state$states)) {
  616.             throw new Testing_DocTest_Exception("Unexpected code line: $line");
  617.         }
  618.         $this->_testCase->code .= rtrim($line"\n";
  619.         $this->_state           = self::STATE_CODE;
  620.     }
  621.  
  622.     // }}}
  623.     // _handleSkipIfLine() {{{
  624.  
  625.     /**
  626.      * Parse the skip-if line provided.
  627.      *
  628.      * @param string $line the skip-if line to parse
  629.      *
  630.      * @access private
  631.      * @return void 
  632.      * @throws Testing_DocTest_Exception
  633.      */
  634.     private function _handleSkipIfLine($line)
  635.     {
  636.         $states = array(nullself::STATE_FLAGSself::STATE_DOCTEST,
  637.             self::STATE_SKIP_IFself::STATE_INI_SET);
  638.         if (!in_array($this->_state$states)) {
  639.             throw new Testing_DocTest_Exception("Unexpected skip-if line: $line");
  640.         }
  641.         $this->_testCase->skipIfCode .= rtrim($line"\n";
  642.         $this->_state                 = self::STATE_SKIP_IF;
  643.     }
  644.  
  645.     // }}}
  646.     // _handleIniSetLine() {{{
  647.  
  648.     /**
  649.      * Parse the ini-set line provided.
  650.      *
  651.      * @param string $line the ini-set line to parse
  652.      *
  653.      * @access private
  654.      * @return void 
  655.      * @throws Testing_DocTest_Exception
  656.      */
  657.     private function _handleIniSetLine($line)
  658.     {
  659.         $states = array(nullself::STATE_FLAGSself::STATE_DOCTEST,
  660.             self::STATE_SKIP_IFself::STATE_INI_SET);
  661.         if (!in_array($this->_state$states)) {
  662.             throw new Testing_DocTest_Exception("Unexpected ini-set line: $line");
  663.         }
  664.         $a explode('='trim($line));
  665.         if (count($a!= 2{
  666.             throw new Testing_DocTest_Exception("Malformed ini-set line: $line");
  667.         }
  668.         $this->_testCase->iniSettings[$a[0]] $a[1];
  669.         $this->_state                        = self::STATE_INI_SET;
  670.     }
  671.  
  672.     // }}}
  673.     // _handleCleanLine() {{{
  674.  
  675.     /**
  676.      * Parse the clean line provided.
  677.      *
  678.      * @param string $line the clean line to parse
  679.      *
  680.      * @access private
  681.      * @return void 
  682.      * @throws Testing_DocTest_Exception
  683.      */
  684.     private function _handleCleanLine($line)
  685.     {
  686.         $states = array(self::STATE_EXPECTSself::STATE_EXPECTS_FILE,
  687.             self::STATE_CLEAN);
  688.         if (!in_array($this->_state$states)) {
  689.             throw new Testing_DocTest_Exception("Unexpected clean line: $line");
  690.         }
  691.         $this->_testCase->cleanCode .= rtrim($line"\n";
  692.         $this->_state                = self::STATE_CLEAN;
  693.     }
  694.  
  695.     // }}}
  696.     // _handleLineContinuation() {{{
  697.  
  698.     /**
  699.      * Parse a line continuation.
  700.      *
  701.      * @param string $line the line to parse
  702.      *
  703.      * @access private
  704.      * @return void 
  705.      */
  706.     private function _handleLineContinuation($line)
  707.     {
  708.         switch ($this->_state{
  709.         case self::STATE_EXPECTS:
  710.             $this->_handleExpectsLine($line);
  711.             break;
  712.         case self::STATE_FLAGS:
  713.             $this->_handleFlagsLine($line);
  714.             break;
  715.         case self::STATE_DOCTEST:
  716.             $this->_handleDoctestLine($line);
  717.             break;
  718.         case self::STATE_SKIP_IF:
  719.             $this->_handleSkipIfLine($line);
  720.             break;
  721.         case self::STATE_INI_SET:
  722.             $this->_handleIniSetLine($line);
  723.             break;
  724.         case self::STATE_CLEAN:
  725.             $this->_handleCleanLine($line);
  726.         }
  727.     }
  728.  
  729.     // }}}
  730. }

Documentation generated on Mon, 11 Mar 2019 15:31:47 -0400 by phpDocumentor 1.4.4. PEAR Logo Copyright © PHP Group 2004.