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$
  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 tmpl code settings
  85.      */
  86.     const KW_DOCTEST_TMPL_CODE = 'tmpl-code';
  87.  
  88.  
  89.     /**
  90.      * Keyword for the doctest expected result
  91.      */
  92.     const KW_DOCTEST_EXPECTS = 'expects';
  93.  
  94.     /**
  95.      * Keyword for the doctest expected file
  96.      */
  97.     const KW_DOCTEST_EXPECTS_FILE = 'expects-file';
  98.  
  99.     /**
  100.      * Keyword for the clean part
  101.      */
  102.     const KW_DOCTEST_CLEAN = 'clean';
  103.  
  104.     /**
  105.      * Keyword for the setup part
  106.      */
  107.     const KW_DOCTEST_SETUP = 'setup';
  108.  
  109.     // }}}
  110.     // State constants {{{
  111.  
  112.     /**
  113.      * State after parsing a doctest line.
  114.      */
  115.     const STATE_DOCTEST = 1;
  116.  
  117.     /**
  118.      * State after parsing flags.
  119.      */
  120.     const STATE_FLAGS = 2;
  121.  
  122.     /**
  123.      * State after parsing a skip condition line.
  124.      */
  125.     const STATE_SKIP_IF = 3;
  126.  
  127.     /**
  128.      * State after parsing a ini-set line.
  129.      */
  130.     const STATE_INI_SET = 4;
  131.  
  132.     /**
  133.      * State after parsing expects line.
  134.      */
  135.     const STATE_EXPECTS = 5;
  136.  
  137.     /**
  138.      * State after parsing expects-file line.
  139.      */
  140.     const STATE_EXPECTS_FILE = 6;
  141.  
  142.     /**
  143.      * State after parsing code line.
  144.      */
  145.     const STATE_CODE = 7;
  146.  
  147.     /**
  148.      * State after parsing clean line.
  149.      */
  150.     const STATE_CLEAN = 8;
  151.  
  152.     /**
  153.      * State after parsing setup line.
  154.      */
  155.     const STATE_SETUP = 9;
  156.  
  157.     /**
  158.      * State after parsing tmpl code.
  159.      */
  160.     const STATE_TMPL_CODE = 10;
  161.  
  162.  
  163.  
  164.     // }}}
  165.     // Properties {{{
  166.  
  167.     /**
  168.      * Current state of the parser, null or one of the STATE_*  constants.
  169.      *
  170.      * @var int $_state 
  171.      * @access private
  172.      */
  173.     private $_state = null;
  174.  
  175.     /**
  176.      * Testing_DocTest_TestCase instance.
  177.      *
  178.      * @var object $_testCase 
  179.      * @access private
  180.      */
  181.     private $_testCase = null;
  182.  
  183.  
  184.     // }}}
  185.     // setShellOptions() {{{
  186.  
  187.     /**
  188.      * set command line options
  189.      *
  190.      * @param array $options an array of command line options
  191.      *
  192.      * @access public
  193.      * @return array 
  194.      */
  195.     public function setShellOptions(array $options)
  196.     {
  197.         $this->_shellOptions = $options;
  198.     }
  199.  
  200.     // }}}
  201.     // parse() {{{
  202.  
  203.     /**
  204. /**
  205.      * Parse the files passed and return an array of Testing_DocTest_TestSuite
  206.      * instances.
  207.      *
  208.      * @param array $files an array of file pathes
  209.      *
  210.      * @access public
  211.      * @return array 
  212.      */
  213.     public function parse(array $files)
  214.     {
  215.         $ret = array();
  216.         $kw  = preg_quote(self::KW_DOCTEST_NAME'/')    '|'
  217.              . preg_quote(self::KW_DOCTEST_FLAGS'/')   '|'
  218.              . preg_quote(self::KW_DOCTEST_SKIP_IF'/''|'
  219.              . preg_quote(self::KW_DOCTEST_INI_SET'/''|'
  220.              . preg_quote(self::KW_DOCTEST_SETUP'/')   '|'
  221.              . preg_quote(self::KW_DOCTEST_TMPL_CODE'/''|'
  222.              . preg_quote(self::KW_DOCTEST_CLEAN'/')   '|'
  223.              . preg_quote(self::KW_DOCTEST_EXPECTS'/''|'
  224.              . preg_quote(self::KW_DOCTEST_EXPECTS_FILE'/');
  225.         foreach ($files as $file{
  226.             $testCaseArray $this->_parseFile($file);
  227.             $suite         = false;
  228.             foreach ($testCaseArray as $testCaseData{
  229.                 // split raw code into lines
  230.                 $docblocs $this->_extractCodeBlocs($testCaseData['docComment']);
  231.                 // build our suite
  232.                 if (!empty($docblocs&& false == $suite{
  233.                     $suite       = new Testing_DocTest_TestSuite();
  234.                     $suite->name = $file
  235.                 }
  236.                 foreach ($docblocs as $docbloc{
  237.                     $this->_testCase        = new Testing_DocTest_TestCase();
  238.                     $this->_testCase->_shellOptions = $this->_shellOptions;
  239.                     $this->_testCase->file  = $file;
  240.                     $this->_testCase->level = $testCaseData['level'];
  241.                     $this->_testCase->name  = $testCaseData['name'];
  242.                     // split string into an array of lines
  243.                     $lines preg_split('/(\n|\r\n)/'$docbloc);
  244.                     try {
  245.                         foreach ($lines as $i=>$l{
  246.                             // remove spaces and * at the beginning
  247.                             $l preg_replace('/^\s*\*\s?/'''$l);
  248.                             $p preg_quote(self::SYNTAX_PREFIX'/');
  249.                             if (preg_match("/^\s*$p\s?($kw):\s*(.*)$/"$l$m)) {
  250.                                 //First doctest line number
  251.                                 $this->_testCase->lineNumber = $testCaseData['line'];
  252.     
  253.                                 switch ($m[1]{
  254.                                 case self::KW_DOCTEST_NAME:
  255.                                     $this->_handleDoctestLine($m[2]);
  256.                                     break;
  257.                                 case self::KW_DOCTEST_FLAGS:
  258.                                     $this->_handleFlagsLine($m[2]);
  259.                                     break;
  260.                                 case self::KW_DOCTEST_SKIP_IF:
  261.                                     $this->_handleFlagsLine($m[2]);
  262.                                     break;
  263.                                 case self::KW_DOCTEST_INI_SET:
  264.                                     $this->_handleIniSetLine($m[2]);
  265.                                     break;
  266.                                 case self::KW_DOCTEST_EXPECTS:
  267.                                     $this->_handleExpectsLine($m[2]);
  268.                                     break;
  269.                                 case self::KW_DOCTEST_EXPECTS_FILE:
  270.                                     $this->_handleExpectsFileLine($m[2]);
  271.                                     break;
  272.                                 case self::KW_DOCTEST_CLEAN:
  273.                                     $this->_handleCleanLine($m[2]);
  274.                                     break;
  275.                                 case self::KW_DOCTEST_SETUP:
  276.                                     $this->_handleSetupLine($m[2]);
  277.                                     break;
  278.                                 case self::KW_DOCTEST_TMPL_CODE: 
  279.                                     $this->_handleTmplCode($m[2]);
  280.                                     break;
  281.                                 }
  282.                             else if (preg_match('/^\s*'.$p.'\s?(.*)$/'$l$m)) {
  283.                                 $this->_handleLineContinuation($m[1]);
  284.                             else {
  285.                                 if (trim($l!= ''{
  286.                                     $this->_handleCodeLine($l);
  287.                                 }
  288.                             }
  289.                         }
  290.                     
  291.                     catchTesting_DocTest_Exception $e {
  292.                         $this->_testCase->parsingError = $e->getMessage();
  293.                     }
  294.                     // trim last eol
  295.                     $this->_testCase->expectedValue  
  296.                         = substr($this->_testCase->expectedValue0-1);
  297.                     // reset state
  298.                     $this->_state = null;
  299.                     // append the test case
  300.                     $suite->addTestCase($this->_testCase);
  301.                 }
  302.             }
  303.             if ($suite{
  304.                 $ret[$suite;
  305.             }
  306.  
  307.  
  308.         }
  309.         return $ret;
  310.     }
  311.  
  312.     // }}}
  313.     // _parseFile() {{{
  314.  
  315.     /**
  316.      * Parse the file $file and return an array of Testing_DocTest_TestCase
  317.      * instances.
  318.      *
  319.      * @param string $file path to the file to parse.
  320.      *
  321.      * @access private
  322.      * @return array 
  323.      */
  324.     private function _parseFile($file)
  325.     {
  326.         $return = array();
  327.         $tokens $this->_tokenize($file);
  328.         if (false === $tokens{
  329.             // return an empty array
  330.             return $return;
  331.         }
  332.         $curlyLevel  = -1;
  333.         $curlyOpen   = -1;
  334.         $className   = null;
  335.         $insideQuote = false;
  336.         $insideClass = false;
  337.         while (false !== ($item each($tokens))) {
  338.             // memoize curly level in order to detect if we are inside a class
  339.             if (is_string($item['value'])) {
  340.                 if (!$insideQuote{
  341.                     if ($item['value'== '{'{
  342.                         $curlyLevel++;
  343.                     else if ($item['value'== '}' 
  344.                         && --$curlyLevel == $curlyOpen
  345.                     {
  346.                         // curly is the close curly of current class
  347.                         $insideClass = false;
  348.                     }
  349.                 }
  350.                 if ($item['value'== '"'{
  351.                     $insideQuote !$insideQuote;
  352.                 }
  353.                 continue;
  354.             }
  355.             list($id$token$line$item['value'];
  356.             // skip all tokens but doc comments
  357.             if ($id !== T_DOC_COMMENT{
  358.                 continue;
  359.             }
  360.             // find next token
  361.             $ids  = array(T_CLASST_FUNCTIONT_DOC_COMMENT);
  362.             $next $this->_findNextToken($ids$tokens);
  363.             /*
  364.             if (false === $next && !empty($return)) {
  365.                 break;
  366.             }
  367.             */
  368.             // build Testing_DocTest_TestCase instance
  369.             $ret               = array();
  370.             $ret['docComment'$token;
  371.             $ret['line']       $line;
  372.             $ret['file']       $file;
  373.             if (false === $next || T_DOC_COMMENT === $next[0]{
  374.                 $ret['name']  'test';
  375.                 $ret['level''file level';
  376.             else {
  377.                 $nToken $this->_findNextToken(T_STRING$tokens);
  378.                 if (false === $nToken{
  379.                     continue;
  380.                 }
  381.                 if ($next[0=== T_CLASS{
  382.                     $insideClass  = true;
  383.                     $curlyOpen    $curlyLevel;
  384.                     $ret['name']  $nToken[1];
  385.                     $className    $nToken[1];
  386.                     $ret['level''class';
  387.                 else if ($insideClass{
  388.                     $ret['name']  $className '::' $nToken[1];
  389.                     $ret['level''method';
  390.                 else {
  391.                     $ret['name']  $nToken[1];
  392.                     $ret['level''function';
  393.                 }
  394.             }
  395.             $return[$ret;
  396.         }
  397.         return $return;
  398.     }
  399.  
  400.     // }}}
  401.     // _tokenize() {{{
  402.  
  403.     /**
  404.      * Tokenize the file $file into an array of tokens using the builtin php
  405.      * tokenizer extension. Before tokenizing the method check that the file
  406.      * contains at least a doctest.
  407.      *
  408.      * @param string $file the file to parse.
  409.      *
  410.      * @access private
  411.      * @return array array of tokens
  412.      */
  413.     private function _tokenize($file)
  414.     
  415.         $data file_get_contents($file);
  416.         // speed improvement, don't bother tokenizing file if it does not 
  417.         // contain any doctest
  418.         if (false === strstr($dataself::KW_DOCTEST_EXPECTS)) {
  419.             return array();
  420.         }
  421.         return token_get_all($data);
  422.     }
  423.  
  424.     // }}}
  425.     // _findNextToken() {{{
  426.  
  427.     /**
  428.      * Find the next token matching the id $id and return it or return false if
  429.      * no matching token is found.
  430.      *
  431.      * @param mixed $id      id or array of ids the token must match
  432.      * @param array &$tokens tokens array passed by reference
  433.      *
  434.      * @access private
  435.      * @return array array of tokens
  436.      */
  437.     private function _findNextToken($id&$tokens)
  438.     
  439.         $next current($tokens);
  440.         while ($next !== false{
  441.             if (!is_string($next)) {
  442.                 if (is_int($id&& $next[0=== $id{
  443.                     return $next;
  444.                 }
  445.                 if (is_array($id&& in_array($next[0]$id)) {
  446.                     return $next;
  447.                 }
  448.             }
  449.             // move to next token
  450.             $next next($tokens);
  451.         }
  452.         return false;
  453.     }
  454.  
  455.     // }}}
  456.     // _extractCodeBlocs() {{{
  457.  
  458.     /**
  459.      * Extract all <code></code> blocs in the given raw docstring.
  460.      *
  461.      * @param string $docstring raw docstring
  462.      *
  463.      * @access private
  464.      * @return array an array of code blocs strings.
  465.      */
  466.     private function _extractCodeBlocs($docstring)
  467.     {
  468.         $ret = array();
  469.         // extract <code></code> blocks, we use preg_match_all because there 
  470.         // could be more than one code block by docstring
  471.         $rx '/<code>[\s\*]*(<[\?\%](php)?)?\s*' 
  472.             . '(.*?)\s*([\?\%]>)?[\s\*]*<\/code>/si';
  473.         preg_match_all($rx$docstring$tokens);
  474.         if (isset($tokens[3]&& is_array($tokens[3])) {
  475.             foreach ($tokens[3as $i => $token{
  476.                 if ($this->_hasStandaloneDoctest($token)) {
  477.                     $testfile_contents $this->_handleStandaloneDoctest($token);
  478.                     if ($testfile_contents !== false{
  479.                         // replace the current doctest code with the contents
  480.                         // of the external included file
  481.                         $token $testfile_contents;
  482.                     }
  483.                 }
  484.                 if (!$this->_hasDocTest($token)) {
  485.                     // not a doctest
  486.                     continue;
  487.                 }
  488.                 $ret[$token;
  489.             }
  490.         }
  491.         return $ret;
  492.     }
  493.  
  494.     // }}}
  495.     // _hasStandaloneDoctest() {{{
  496.  
  497.     /**
  498.      * Return true if the string data provided contains an external doctest file.
  499.      *
  500.      * @param string $data The docstring data
  501.      *
  502.      * @return boolean 
  503.      */
  504.     private function _hasStandaloneDoctest($data)
  505.     {
  506.         $p preg_quote(self::SYNTAX_PREFIX'/');
  507.         $k preg_quote(self::KW_DOCTEST_FILE'/');
  508.         return preg_match("/$p\s?$k/m"$data);
  509.     }
  510.  
  511.     // }}}
  512.     // _hasDocTest() {{{
  513.  
  514.     /**
  515.      * Return true if the string data provided contains a doctest.
  516.      *
  517.      * @param string $data string data
  518.      *
  519.      * @access private
  520.      * @return boolean 
  521.      */
  522.     private function _hasDocTest($data)
  523.     {
  524.         $p preg_quote(self::SYNTAX_PREFIX'/');
  525.         $k preg_quote(self::KW_DOCTEST_EXPECTS'/');
  526.         return preg_match("/$p\s?$k/m"$data);
  527.     }
  528.  
  529.     // }}}
  530.     // _handleStandaloneDoctest() {{{
  531.  
  532.     /**
  533.      * Return the contents of the external doctest file.
  534.      *
  535.      * @param string $docbloc The docstring data
  536.      *
  537.      * @return mixed boolean or string
  538.      */
  539.     private function _handleStandaloneDoctest($docbloc)
  540.     {
  541.         $p     preg_quote(self::SYNTAX_PREFIX'/');
  542.         $k     preg_quote(self::KW_DOCTEST_FILE'/');
  543.         $lines preg_split('/(\n|\r\n)/'$docbloc);
  544.  
  545.         foreach ($lines as $i => $l{
  546.             $l preg_replace('/^\s*\*\s?/'''$l);
  547.             $p preg_quote(self::SYNTAX_PREFIX'/');
  548.             if (preg_match("/^\s*$p\s?($k):\s*(.*)$/"$l$matches)) {
  549.                 $f trim($matches[2]);
  550.                 if (false === ($contents @file_get_contents(realpath($f)))) {
  551.                     throw new Testing_DocTest_Exception(
  552.                         "Unable to read standalone doctest file \"$f\""
  553.                     );
  554.                 }
  555.                 // remove the php tags
  556.                 $rx '/(<[\?\%](php)?)?(.*?)([\?\%]>)?/si';
  557.                 return preg_replace($rx'\3'$contents);
  558.             }
  559.         }
  560.         return false;
  561.             
  562.     }
  563.  
  564.     // }}}
  565.     // _handleDoctestLine() {{{
  566.  
  567.     /**
  568.      * Parse the doctest line provided.
  569.      *
  570.      * @param string $line the line of code to parse
  571.      *
  572.      * @access private
  573.      * @return void 
  574.      * @throws Testing_DocTest_Exception
  575.      */
  576.     private function _handleDoctestLine($line)
  577.     {
  578.         $states = array(nullself::STATE_FLAGSself::STATE_DOCTEST,
  579.             self::STATE_SKIP_IFself::STATE_INI_SETself::STATE_TMPL_CODE);
  580.         if (!in_array($this->_state$states)) {
  581.             throw new Testing_DocTest_Exception("Unexpected doctest line: $line");
  582.         }
  583.         $this->_testCase->altname .= $line;
  584.         $this->_state              = self::STATE_DOCTEST;
  585.     }
  586.  
  587.     // }}}
  588.     // _handleFlagsLine() {{{
  589.  
  590.     /**
  591.      * Parse the flag line provided.
  592.      *
  593.      * @param string $line The flag line to parse
  594.      *
  595.      * @access private
  596.      * @return void 
  597.      * @throws Testing_DocTest_Exception
  598.      */
  599.     private function _handleFlagsLine($line)
  600.     {
  601.         $states = array(nullself::STATE_FLAGSself::STATE_DOCTEST,
  602.             self::STATE_SKIP_IFself::STATE_INI_SETself::STATE_TMPL_CODE);
  603.         if (!in_array($this->_state$states)) {
  604.             throw new Testing_DocTest_Exception("Unexpected flags line: $line");
  605.         }
  606.         $flags explode(','$line);
  607.         foreach ($flags as $flag{
  608.             $const 'Testing_DocTest::FLAG_' strtoupper(trim($flag));
  609.             if (defined($const)) {
  610.                 $this->_testCase->flags |= constant($const);
  611.             }
  612.         }
  613.         $this->_state = self::STATE_FLAGS;
  614.     }
  615.  
  616.     // }}}
  617.     // _handleExpectsLine() {{{
  618.  
  619.     /**
  620.      * Parse the expects line provided.
  621.      *
  622.      * @param string $line the expects line to parse
  623.      *
  624.      * @access private
  625.      * @return void 
  626.      * @throws Testing_DocTest_Exception
  627.      */
  628.     private function _handleExpectsLine($line)
  629.     {
  630.         $states = array(self::STATE_CODEself::STATE_EXPECTS,
  631.             self::STATE_SETUP);
  632.         if (!in_array($this->_state$states)) {
  633.             throw new Exception("unexpected expects line: $line");
  634.         }
  635.         $this->_testCase->expectedValue .= $line;
  636.         // handle line continuation
  637.         if (substr(trim($line)-1!== '\\'{
  638.             $this->_testCase->expectedValue .= "\n";
  639.         else {
  640.             $this->_testCase->expectedValue 
  641.                 = trim($this->_testCase->expectedValue'\\');
  642.         }
  643.         $this->_state = self::STATE_EXPECTS;
  644.     }
  645.  
  646.     // }}}
  647.     // _handleExpectsFileLine() {{{
  648.  
  649.     /**
  650.      * Parse the expects-file line provided.
  651.      *
  652.      * @param string $line the expects-file line to parse
  653.      *
  654.      * @access private
  655.      * @return void 
  656.      * @throws Testing_DocTest_Exception
  657.      */
  658.     private function _handleExpectsFileLine($line)
  659.     {
  660.         $states = array(self::STATE_CODEself::STATE_EXPECTS_FILE,
  661.             self::STATE_SETUP);
  662.         if (!in_array($this->_state$states)) {
  663.             throw new Exception("unexpected expects-file line: $line");
  664.         }
  665.         $f realpath(trim($line));
  666.         if (false === ($contents @file_get_contents($f))) {
  667.             throw new Testing_DocTest_Exception("Unable to read expects file $f");
  668.         }
  669.         $this->_testCase->expectedValue = $contents;
  670.         $this->_state                   = self::STATE_EXPECTS_FILE;
  671.     }
  672.  
  673.     // }}}
  674.     // _handleCodeLine() {{{
  675.  
  676.     /**
  677.      * Parse the code line provided.
  678.      *
  679.      * @param string $line the code line to parse
  680.      *
  681.      * @access private
  682.      * @return void 
  683.      * @throws Testing_DocTest_Exception
  684.      */
  685.     private function _handleCodeLine($line)
  686.     {
  687.         $states = array(self::STATE_EXPECTSself::STATE_EXPECTS_FILE,
  688.             self::STATE_CLEAN);
  689.         if (in_array($this->_state$states)) {
  690.             throw new Testing_DocTest_Exception("Unexpected code line: $line");
  691.         }
  692.         $this->_testCase->code .= rtrim($line"\n";
  693.         $this->_state           = self::STATE_CODE;
  694.     }
  695.  
  696.     // }}}
  697.     // _handleSkipIfLine() {{{
  698.  
  699.     /**
  700.      * Parse the skip-if line provided.
  701.      *
  702.      * @param string $line the skip-if line to parse
  703.      *
  704.      * @access private
  705.      * @return void 
  706.      * @throws Testing_DocTest_Exception
  707.      */
  708.     private function _handleSkipIfLine($line)
  709.     {
  710.         $states = array(nullself::STATE_FLAGSself::STATE_DOCTEST,
  711.             self::STATE_SKIP_IFself::STATE_INI_SETself::STATE_TMPL_CODE);
  712.         if (!in_array($this->_state$states)) {
  713.             throw new Testing_DocTest_Exception("Unexpected skip-if line: $line");
  714.         }
  715.         $this->_testCase->skipIfCode .= rtrim($line"\n";
  716.         $this->_state                 = self::STATE_SKIP_IF;
  717.     }
  718.  
  719.     // }}}
  720.     // _handleIniSetLine() {{{
  721.  
  722.     /**
  723.      * Parse the ini-set line provided.
  724.      *
  725.      * @param string $line the ini-set line to parse
  726.      *
  727.      * @access private
  728.      * @return void 
  729.      * @throws Testing_DocTest_Exception
  730.      */
  731.     private function _handleIniSetLine($line)
  732.     {
  733.         $states = array(nullself::STATE_FLAGSself::STATE_DOCTEST,
  734.             self::STATE_SKIP_IFself::STATE_INI_SETself::STATE_TMPL_CODE);
  735.         if (!in_array($this->_state$states)) {
  736.             throw new Testing_DocTest_Exception("Unexpected ini-set line: $line");
  737.         }
  738.         $a explode('='trim($line));
  739.         if (count($a!= 2{
  740.             throw new Testing_DocTest_Exception("Malformed ini-set line: $line");
  741.         }
  742.         $this->_testCase->iniSettings[$a[0]] $a[1];
  743.         $this->_state                        = self::STATE_INI_SET;
  744.     }
  745.  
  746.     // }}}
  747.     // _handleTmplCode() {{{
  748.  
  749.     /**
  750.      * Parse the tmpl-code line provided.
  751.      *
  752.      * @param string $line the ini-set line to parse
  753.      *
  754.      * @access private
  755.      * @return void 
  756.      * @throws Testing_DocTest_Exception
  757.      */
  758.     private function _handleTmplCode($line)
  759.     {
  760.         $states = array(nullself::STATE_FLAGSself::STATE_DOCTEST,
  761.             self::STATE_SKIP_IFself::STATE_INI_SETself::STATE_TMPL_CODE);
  762.         if (!in_array($this->_state$states)) {
  763.             throw new Testing_DocTest_Exception("Unexpected tmpl-code line: $line");
  764.         }
  765.         $tmplfile trim($line);
  766.         if (!file_exists($tmplfile)) {
  767.             throw new Testing_DocTest_Exception(
  768.                 "Malformed tmpl-code line: 
  769.                 $line (File not exists)"
  770.             );
  771.         }
  772.         $this->_testCase->tmplCode=$tmplfile;
  773.         $this->_state                        = self::STATE_TMPL_CODE;
  774.     }
  775.  
  776.     // }}}
  777.     // _handleCleanLine() {{{
  778.  
  779.     /**
  780.      * Parse the clean line provided.
  781.      *
  782.      * @param string $line the clean line to parse
  783.      *
  784.      * @access private
  785.      * @return void 
  786.      * @throws Testing_DocTest_Exception
  787.      */
  788.     private function _handleCleanLine($line)
  789.     {
  790.         $states = array(self::STATE_EXPECTSself::STATE_EXPECTS_FILE,
  791.             self::STATE_CLEAN);
  792.         if (!in_array($this->_state$states)) {
  793.             throw new Testing_DocTest_Exception("Unexpected clean line: $line");
  794.         }
  795.         $this->_testCase->cleanCode .= rtrim($line"\n";
  796.         $this->_state                = self::STATE_CLEAN;
  797.     }
  798.  
  799.     // }}}
  800.     // _handleSetupLine() {{{
  801.  
  802.     /**
  803.      * Parse the setup line provided.
  804.      *
  805.      * @param string $line the setup line to parse
  806.      *
  807.      * @access private
  808.      * @return void 
  809.      * @throws Testing_DocTest_Exception
  810.      */
  811.     private function _handleSetupLine($line)
  812.     {
  813.         $states = array(self::STATE_CODEself::STATE_EXPECTS,
  814.             self::STATE_EXPECTS_FILEself::STATE_CLEAN);
  815.         if (in_array($this->_state$states)) {
  816.             throw new Testing_DocTest_Exception("Unexpected setup line: $line");
  817.         }
  818.         $this->_testCase->setupCode .= rtrim($line"\n";
  819.         $this->_state                = self::STATE_SETUP;
  820.     }
  821.  
  822.     // }}}
  823.     // _handleLineContinuation() {{{
  824.  
  825.     /**
  826.      * Parse a line continuation.
  827.      *
  828.      * @param string $line the line to parse
  829.      *
  830.      * @access private
  831.      * @return void 
  832.      */
  833.     private function _handleLineContinuation($line)
  834.     {
  835.         switch ($this->_state{
  836.         case self::STATE_EXPECTS:
  837.             $this->_handleExpectsLine($line);
  838.             break;
  839.         case self::STATE_FLAGS:
  840.             $this->_handleFlagsLine($line);
  841.             break;
  842.         case self::STATE_DOCTEST:
  843.             $this->_handleDoctestLine($line);
  844.             break;
  845.         case self::STATE_SKIP_IF:
  846.             $this->_handleSkipIfLine($line);
  847.             break;
  848.         case self::STATE_INI_SET:
  849.             $this->_handleIniSetLine($line);
  850.             break;
  851.         case self::STATE_CLEAN:
  852.             $this->_handleCleanLine($line);
  853.             break;
  854.         case self::STATE_SETUP:
  855.             $this->_handleSetupLine($line);
  856.             break;
  857.         case self::STATE_TMPL_CODE;
  858.             $this->_handleTmplCode($line);
  859.             break;
  860.         }
  861.     }
  862.  
  863.     // }}}
  864. }

Documentation generated on Thu, 17 Jan 2013 10:30:04 +0000 by phpDocumentor 1.4.3. PEAR Logo Copyright © PHP Group 2004.