AloFramework documentation
  • Namespace
  • Class
  • Tree
  • Deprecated
  • Todo
  • Download

Namespaces

  • Alo
    • Cache
    • Controller
    • Db
    • Exception
    • Session
    • Statics
    • Test
    • Validators
  • Controller
  • None
  • PHP

Classes

  • AbstractTester
  • ClassTester
  • FunctionTester
  1 <?php
  2 
  3    namespace Alo\Test;
  4 
  5    use Alo\Exception\TesterException as TE;
  6    use Alo\Statics\Format as F;
  7 
  8    if (!defined('GEN_START')) {
  9       http_response_code(404);
 10       die();
 11    }
 12 
 13    /**
 14     * The abstract tester class
 15     *
 16     * @author Art <a.molcanovas@gmail.com>
 17     * @package TestingSuite
 18     */
 19    abstract class AbstractTester {
 20 
 21       /**
 22        * The test queue
 23        *
 24        * @var array
 25        */
 26       protected $queue;
 27 
 28       /**
 29        * The test results
 30        *
 31        * @var array
 32        */
 33       protected $results;
 34 
 35       /**
 36        * Defines a parameter as "name"
 37        *
 38        * @var string
 39        */
 40       const P_NAME = 'name';
 41 
 42       /**
 43        * Defines a parameter as "arguments"
 44        *
 45        * @var string
 46        */
 47       const P_ARGS = 'args';
 48 
 49       /**
 50        * Defines a parameter as "expected outcome"
 51        *
 52        * @var string
 53        */
 54       const P_OUTCOME = 'outcome';
 55 
 56       /**
 57        * Defines a parameter as "type"
 58        *
 59        * @var string
 60        */
 61       const P_TYPE = 'type';
 62 
 63       /**
 64        * Defines a parameter as "definition"
 65        *
 66        * @var string
 67        */
 68       const P_DEFINITION = 'definition';
 69 
 70       /**
 71        * Defines a parameter as "passed"
 72        *
 73        * @var string
 74        */
 75       const P_PASSED = 'passed';
 76 
 77       /**
 78        * Defines the test type as "output test"
 79        *
 80        * @var string
 81        */
 82       const T_OUTPUT = 'output';
 83 
 84       /**
 85        * Defines the test type as "return test"
 86        *
 87        * @var string
 88        */
 89       const T_RETURN = 'return';
 90 
 91       /**
 92        * Defines an outcome as "method/function not callable"
 93        *
 94        * @var string
 95        */
 96       const O_NOT_CALLABLE = 'Not callable';
 97 
 98       /**
 99        * Defines a parameter as "start of test"
100        *
101        * @var string
102        */
103       const P_TEST_START = 'start';
104 
105       /**
106        * Defines a parameter as "end of test"
107        *
108        * @var string
109        */
110       const P_TEST_END = 'end';
111 
112       /**
113        * Defines a parameter as "test runtime"
114        *
115        * @var string
116        */
117       const P_TEST_RUNTIME = 'runtime';
118 
119       /**
120        * Instantiates the tester
121        *
122        * @author Art <a.molcanovas@gmail.com>
123        */
124       function __construct() {
125          $this->queue = $this->results = [];
126       }
127 
128       /**
129        * Runs the tests
130        *
131        * @author Art <a.molcanovas@gmail.com>
132        * @return array Test results
133        */
134       function runTests() {
135          foreach ($this->queue as $test) {
136             $this->runTest($test);
137          }
138 
139          return $this->results;
140       }
141 
142       /**
143        * Runs an individual test
144        *
145        * @author Art <a.molcanovas@gmail.com>
146        * @param array $test The test specs
147        * @return AbstractTester
148        */
149       protected function runTest(array $test) {
150          $callable = $this->getCallable($test[self::P_DEFINITION][self::P_NAME]);
151 
152          $add = [
153             self::P_DEFINITION => $test[self::P_DEFINITION],
154             self::P_TEST_START => microtime(true)
155          ];
156 
157          if (!is_callable($callable)) {
158             $add[self::P_PASSED] = false;
159             $add[self::P_OUTCOME] = self::O_NOT_CALLABLE;
160             $add[self::P_TEST_END] = microtime(true);
161          } else {
162             ob_start();
163             $call = call_user_func_array($callable, $test[self::P_DEFINITION][self::P_ARGS]);
164             $ob = ob_get_clean();
165             $add[self::P_TEST_END] = microtime(true);
166 
167             $add[self::P_OUTCOME] = $test[self::P_TYPE] == self::T_OUTPUT ? $ob : $call;
168             $add[self::P_PASSED] = $add[self::P_OUTCOME] == $test[self::P_DEFINITION][self::P_OUTCOME];
169          }
170 
171          $add[self::P_TEST_RUNTIME] = $add[self::P_TEST_END] - $add[self::P_TEST_START];
172          $this->results[] = $add;
173 
174          return $this;
175       }
176 
177       /**
178        * Returns the callable parameter for call_user_func_array()
179        *
180        * @author Art <a.molcanovas@gmail.com>
181        * @param string $name Function/method name
182        * @return array|string
183        */
184       abstract protected function getCallable($name);
185 
186       /**
187        * Adds a test for the output
188        *
189        * @author Art <a.molcanovas@gmail.com>
190        * @param string $type    The type of the test - see this class' T_* constants
191        * @param string $name    The method/function name
192        * @param mixed  $outcome The expected outcome
193        * @param array  $args    The arguments to pass on to the function/method
194        * @throws TE When the method/function name is invalid
195        * @return AbstractTester
196        */
197       protected function addGenericTest($type, $name, $outcome, array $args = []) {
198          if (!is_string($name)) {
199             throw new TE('The name must be a string!', TE::E_NAME_INVALID);
200          } else {
201             $this->queue[] = [
202                self::P_TYPE       => $type,
203                self::P_DEFINITION => [
204                   self::P_NAME    => $name,
205                   self::P_ARGS    => $args,
206                   self::P_OUTCOME => $outcome
207                ]
208             ];
209          }
210 
211          return $this;
212       }
213 
214       /**
215        * Adds a test for the output
216        *
217        * @author Art <a.molcanovas@gmail.com>
218        * @param string $name    The method/function name
219        * @param mixed  $outcome The expected outcome
220        * @param array  $args    The arguments to pass on to the function/method
221        * @return AbstractTester
222        */
223       function addOutputTest($name, $outcome, array $args = []) {
224          return $this->addGenericTest(self::T_OUTPUT, $name, $outcome, $args);
225       }
226 
227       /**
228        * Adds a test for the return value
229        *
230        * @author Art <a.molcanovas@gmail.com>
231        * @param string $name    The method/function name
232        * @param mixed  $outcome The expected outcome
233        * @param array  $args    The arguments to pass on to the function/method
234        * @return AbstractTester
235        */
236       function addReturnTest($name, $outcome, array $args = []) {
237          return $this->addGenericTest(self::T_RETURN, $name, $outcome, $args);
238       }
239 
240       /**
241        * Returns the common queue
242        *
243        * @return array
244        */
245       function getQueue() {
246          return $this->queue;
247       }
248 
249       /**
250        * Returns the testing results
251        *
252        * @author Art <a.molcanovas@gmail.com>
253        * @return array
254        */
255       function getResults() {
256          return $this->results;
257       }
258 
259       /**
260        * Returns the test results as plaintext
261        *
262        * @author Art <a.molcanovas@gmail.com>
263        * @return string
264        */
265       function toPlaintextString() {
266          $ret = "";
267 
268          foreach ($this->results as $r) {
269             $ret .= $r[self::P_DEFINITION][self::P_NAME] . "\n"
270                . "\tArgs:\t\t\t" . F::scalarOutput(array_shift($r[self::P_DEFINITION][self::P_ARGS])) . "\n";
271 
272             foreach ($r[self::P_DEFINITION][self::P_ARGS] as $arg) {
273                $ret .= "\t\t\t\t" . F::scalarOutput($arg) . "\n";
274             }
275 
276             $ret .= "\tExpected outcome:\t" . F::scalarOutput($r[self::P_DEFINITION][self::P_OUTCOME]) . "\n"
277                . "\tOutcome:\t\t" . F::scalarOutput($r[self::P_OUTCOME]) . "\n"
278                . "\tResult:\t\t\t" . ($r[self::P_PASSED] ? 'PASSED' : 'FAILED') . "\n"
279                . "\tStart time:\t\t" . \timestamp_precise($r[self::P_TEST_START]) . "\n"
280                . "\tEnd time:\t\t" . \timestamp_precise($r[self::P_TEST_END]) . "\n"
281                . "\tRuntime:\t\t" . (($r[self::P_TEST_END] - $r[self::P_TEST_START]) * 1000) . "ms\n\n";
282 
283          }
284 
285          return $ret;
286       }
287 
288       /**
289        * Returns the test results in an HTML table
290        *
291        * @author Art <a.molcanovas@gmail.com>
292        * @return string HTML code
293        */
294       function __toString() {
295          $ret = '<table border="1" style="background:#000;color:#fff" cellpadding="2">'
296             . '<thead>'
297             . '<tr>'
298             . '<th>Tested item</th>'
299             . '<th>Item args</th>'
300             . '<th>Expected outcome</th>'
301             . '<th>Outcome</th>'
302             . '<th>Result</th>'
303             . '<th>Start time</th>'
304             . '<th>End time</th>'
305             . '<th>Runtime</th>'
306             . '</tr>'
307             . '</thead>'
308             . '<tbody>';
309 
310          foreach ($this->results as $r) {
311             foreach ($r[self::P_DEFINITION][self::P_ARGS] as &$a) {
312                $a = '<span style="color:gold">' . F::scalarOutput($a) . '</span>';
313             }
314 
315             $ret .= '<tr>'
316                . '<td>' . $r[self::P_DEFINITION][self::P_NAME] . '</td>'
317                . '<td><ol style="margin:0;"><li>' . implode('</li><li>', $r[self::P_DEFINITION][self::P_ARGS]) . '</li></ol></td>'
318                . '<td><pre>' . F::scalarOutput($r[self::P_DEFINITION][self::P_OUTCOME]) . '</pre></td>'
319                . '<td><pre>' . F::scalarOutput($r[self::P_OUTCOME]) . '</pre></td>'
320                . '<td style="color:';
321 
322             if ($r[self::P_PASSED]) {
323                $ret .= 'lime">PASSED';
324             } else {
325                $ret .= 'red">FAILED';
326             }
327 
328             $ret .= '</td>'
329                . '<td>' . \timestamp_precise($r[self::P_TEST_START]) . '</td>'
330                . '<td>' . \timestamp_precise($r[self::P_TEST_END]) . '</td>'
331                . '<td>' . (($r[self::P_TEST_END] - $r[self::P_TEST_START]) * 1000) . 'ms</td>'
332                . '</tr>';
333          }
334 
335          return $ret . '</tbody></table>';
336       }
337    }
AloFramework documentation API documentation generated by ApiGen 2.8.0