Webylon 3.1 API Docs
  • Package
  • Class
  • Tree
  • Deprecated
  • Download
Version: current
  • 3.2
  • 3.1

Packages

  • auth
  • Booking
  • cart
    • shipping
    • steppedcheckout
  • Catalog
  • cms
    • assets
    • batchaction
    • batchactions
    • bulkloading
    • comments
    • content
    • core
    • export
    • newsletter
    • publishers
    • reports
    • security
    • tasks
  • Dashboard
  • DataObjectManager
  • event
  • faq
  • forms
    • actions
    • core
    • fields-basic
    • fields-dataless
    • fields-datetime
    • fields-files
    • fields-formatted
    • fields-formattedinput
    • fields-relational
    • fields-structural
    • transformations
    • validators
  • googlesitemaps
  • guestbook
  • installer
  • newsletter
  • None
  • photo
    • gallery
  • PHP
  • polls
  • recaptcha
  • sapphire
    • api
    • bulkloading
    • control
    • core
    • cron
    • dev
    • email
    • fields-formattedinput
    • filesystem
    • formatters
    • forms
    • i18n
    • integration
    • misc
    • model
    • parsers
    • search
    • security
    • tasks
    • testing
    • tools
    • validation
    • view
    • widgets
  • seo
    • open
      • graph
  • sfDateTimePlugin
  • spamprotection
  • stealth
    • captha
  • subsites
  • userform
    • pagetypes
  • userforms
  • webylon
  • widgets

Classes

  • CliTestReporter
  • FunctionalTest
  • InstallerTest
  • JSTestRunner
  • PHPUnit_Framework_TestCase
  • SapphireTest
  • SapphireTestReporter
  • SapphireTestSuite
  • TestRunner
  • TestSession
  • TestSession_STResponseWrapper
  • TestViewer

Interfaces

  • TestOnly

Functions

  • hasPhpUnit
  1 <?php
  2 /**
  3  * Allows human reading of a test in a format suitable for agile documentation
  4  * @package sapphire
  5  * @subpackage testing
  6  */
  7 class TestViewer extends Controller {
  8     /**
  9      * Define a simple finite state machine.
 10      * Top keys are the state names.  'start' is the first state, and 'die' is the error state.
 11      * Inner keys are token names/codes.  The values are either a string, new state, or an array(new state, handler method).
 12      * The handler method will be passed the PHP token as an argument, and is expected to populate a property of the object.
 13      */
 14     static $fsm = array(
 15         'start' => array(
 16             T_CLASS => array('className','createClass'),
 17         ),
 18         'className' => array(
 19             T_STRING => array('classSpec', 'setClassName'),
 20         ),
 21         'classSpec' => array(
 22             '{' => 'classBody',
 23         ),
 24         'classBody' => array(
 25             T_FUNCTION => array('methodName','createMethod'),
 26             '}' => array('start', 'completeClass'),
 27         ),
 28         'methodName' => array(
 29             T_STRING => array('methodSpec', 'setMethodName'),
 30         ),
 31         'methodSpec' => array(
 32             '{' => 'methodBody',
 33         ),
 34         'methodBody' => array(
 35             '{' => array('!push','appendMethodContent'),
 36             '}' => array(
 37                 'hasstack' => array('!pop', 'appendMethodContent'),
 38                 'nostack' => array('classBody', 'completeMethod'),
 39             ),
 40             T_VARIABLE => array('variable', 'potentialMethodCall'),
 41             T_COMMENT => array('', 'appendMethodComment'),
 42             '*' => array('', 'appendMethodContent'),
 43         ),
 44         'variable' => array(
 45             T_OBJECT_OPERATOR => array('variableArrow', 'potentialMethodCall'),
 46             '*' => array('methodBody', 'appendMethodContent'),
 47         ),
 48         'variableArrow' => array(
 49             T_STRING => array('methodOrProperty', 'potentialMethodCall'),
 50             T_WHITESPACE => array('', 'potentialMethodCall'),
 51             '*' => array('methodBody', 'appendMethodContent'),
 52         ),
 53         'methodOrProperty' => array(
 54             '(' => array('methodCall', 'potentialMethodCall'),
 55             T_WHITESPACE => array('', 'potentialMethodCall'),
 56             '*' => array('methodBody', 'appendMethodContent'),
 57         ),
 58         'methodCall' => array(
 59             '(' => array('!push/nestedInMethodCall', 'potentialMethodCall'),
 60             ')' => array('methodBody', 'completeMethodCall'),
 61             '*' => array('', 'potentialMethodCall'),
 62         ),
 63         'nestedInMethodCall' => array(
 64             '(' => array('!push', 'potentialMethodCall'),
 65             ')' => array('!pop', 'potentialMethodCall'),
 66             '*' => array('', 'potentialMethodCall'),
 67         ),
 68     );
 69     
 70     function init() {
 71         parent::init();
 72         
 73         $canAccess = (Director::isDev() || Director::is_cli() || Permission::check("ADMIN"));
 74         if(!$canAccess) return Security::permissionFailure($this);
 75     }
 76 
 77     function createClass($token) {
 78         $this->currentClass = array();
 79     }
 80     function setClassName($token) {
 81         $this->currentClass['name'] = $token[1];
 82     }
 83     function completeClass($token) {
 84         $this->classes[] = $this->currentClass;
 85     }
 86     
 87     function createMethod($token) {
 88         $this->currentMethod = array();
 89         $this->currentMethod['content'] = "<pre>";
 90     }
 91     function setMethodName($token) {
 92         $this->currentMethod['name'] = $token[1];
 93     }
 94     function appendMethodComment($token) {
 95         if(substr($token[1],0,2) == '/*') {
 96             $comment = preg_replace('/^\/\*/','',$token[1]);
 97             $comment = preg_replace('/\*\/$/','',$comment);
 98             $comment = preg_replace('/\n[\t ]*\* */m',"\n",$comment);
 99             
100             $this->closeOffMethodContentPre();
101             $this->currentMethod['content'] .= "<p>$comment</p><pre>";
102         } else {
103             $this->currentMethod['content'] .= $this->renderToken($token);
104         }
105         
106     } 
107     function appendMethodContent($token) {
108         if($this->potentialMethodCall) {
109             $this->currentMethod['content'] .= $this->potentialMethodCall;
110             $this->potentialMethodCall = "";
111         }
112         $this->currentMethod['content'] .= $this->renderToken($token);
113     }
114     function completeMethod($token) {
115         $this->closeOffMethodContentPre();
116         $this->currentMethod['content'] = str_replace("\n\t\t","\n",$this->currentMethod['content']);
117         $this->currentClass['methods'][] = $this->currentMethod;
118     }
119     
120     protected $potentialMethodCall = "";
121     function potentialMethodCall($token) {
122         $this->potentialMethodCall .= $this->renderToken($token);
123     }
124     function completeMethodCall($token) {
125         $this->potentialMethodCall .= $this->renderToken($token);
126         if(strpos($this->potentialMethodCall, '-&gt;</span><span class="T_STRING">assert') !== false) {
127             $this->currentMethod['content'] .= "<strong>" . $this->potentialMethodCall . "</strong>";
128         } else {
129             $this->currentMethod['content'] .= $this->potentialMethodCall;
130         }
131         $this->potentialMethodCall = "";
132     }
133     
134     /**
135      * Finish the "pre" block in method content.
136      * Will remove whitespace and empty "pre" blocks
137      */
138     function closeOffMethodContentPre() {
139         $this->currentMethod['content'] = trim($this->currentMethod['content']);
140         if(substr($this->currentMethod['content'],-5) == '<pre>') $this->currentMethod['content'] = substr($this->currentMethod['content'], 0,-5);
141         else $this->currentMethod['content'] .= '</pre>';
142     }
143         
144     /**
145      * Render the given token as HTML
146      */
147     function renderToken($token) {
148         $tokenContent = htmlentities(is_array($token) ? $token[1] : $token);
149         $tokenName = is_array($token) ? token_name($token[0]) : 'T_PUNCTUATION';
150 
151         switch($tokenName) {
152             case "T_WHITESPACE":
153                 return $tokenContent;
154             default:
155                 return "<span class=\"$tokenName\">$tokenContent</span>";
156         }
157     }
158     
159     protected $classes = array();
160     protected $currentMethod, $currentClass;
161     
162     function Content() {
163         $className = $this->urlParams['ID'];
164         if($className && ClassInfo::exists($className)) {
165             return $this->testAnalysis(getClassFile($className));
166         } else {
167             $result = "<h1>View any of the following test classes</h1>";
168             $classes = ClassInfo::subclassesFor('SapphireTest');
169             ksort($classes);
170             foreach($classes as $className) {
171                 if($className == 'SapphireTest') continue;
172                 $result .= "<li><a href=\"TestViewer/show/$className\">$className</a></li>";
173             }
174             return $result;
175         }
176     }
177         
178     function testAnalysis($file) {
179         $content = file_get_contents($file);
180         $tokens = token_get_all($content);
181         
182         // Execute a finite-state-machine with a built-in state stack
183         // This FSM+stack gives us enough expressive power for simple PHP parsing
184         $state = "start";
185         $stateStack = array();
186         
187         //echo "<li>state $state";
188         foreach($tokens as $token) {
189             // Get token name - some tokens are arrays, some arent'
190             if(is_array($token)) $tokenName = $token[0]; else $tokenName = $token;
191             //echo "<li>token '$tokenName'";
192             
193             // Find the rule for that token in the current state
194             if(isset(self::$fsm[$state][$tokenName])) $rule = self::$fsm[$state][$tokenName];
195             else if(isset(self::$fsm[$state]['*'])) $rule = self::$fsm[$state]['*'];
196             else $rule = null;
197             
198             // Check to see if we have specified multiple rules depending on whether the stack is populated 
199             if(is_array($rule) && array_keys($rule) == array('hasstack', 'nostack')) {
200                 if($stateStack) $rule = $rule['hasstack'];
201                 else $rule = $rule = $rule['nostack'];
202             }
203             
204             if(is_array($rule)) {
205                 list($destState, $methodName) = $rule;
206                 $this->$methodName($token);
207             } else if($rule) {
208                 $destState = $rule;
209             } else {
210                 $destState = null;
211             }
212             //echo "<li>->state $destState";
213 
214             if(preg_match('/!(push|pop)(\/[a-zA-Z0-9]+)?/', $destState, $parts)) {
215                 $action = $parts[1];
216                 $argument = isset($parts[2]) ? substr($parts[2],1) : null;
217                 $destState = null;
218                 
219                 switch($action) {
220                     case "push":
221                         $stateStack[] = $state;
222                         if($argument) $destState = $argument;
223                         break;
224                     
225                     case "pop":
226                         if($stateStack) $destState = array_pop($stateStack);
227                         else if($argument) $destState = $argument;
228                         else user_error("State transition '!pop' was attempted with an empty state-stack and no default option specified.", E_USER_ERROR);
229                 }
230             }
231             
232             if($destState) $state = $destState;
233             if(!isset(self::$fsm[$state])) user_error("Transition to unrecognised state '$state'", E_USER_ERROR);
234         }
235         
236         $subclasses = ClassInfo::subclassesFor('SapphireTest');
237         foreach($this->classes as $classDef) {
238             if(in_array($classDef['name'], $subclasses)) {
239                 echo "<h1>$classDef[name]</h1>";
240                 if($classDef['methods']) foreach($classDef['methods'] as $method) {
241                     if(substr($method['name'],0,4) == 'test') {
242                         //$title = ucfirst(strtolower(preg_replace('/([a-z])([A-Z])/', '$1 $2', substr($method['name'], 4))));
243                         $title = $method['name'];
244 
245                         echo "<h2>$title</h2>";
246                         echo $method['content'];
247                     }
248                 }
249             }
250             
251         }
252     }
253 }
[Raise a SilverStripe Framework issue/bug](https://github.com/silverstripe/silverstripe-framework/issues/new)
- [Raise a SilverStripe CMS issue/bug](https://github.com/silverstripe/silverstripe-cms/issues/new)
- Please use the Silverstripe Forums to ask development related questions. -
Webylon 3.1 API Docs API documentation generated by ApiGen 2.8.0