Overview

Packages

  • Jyxo_Beholder
  • Jyxo_Charset
  • Jyxo_Color
  • Jyxo_Css
  • Jyxo_ErrorHandling
  • Jyxo_FirePhp
  • Jyxo_Gettext
    • Parser
  • Jyxo_Html
  • Jyxo_Input
    • Chain
    • Filter
    • Validator
  • Jyxo_Mail
    • Email
    • Parser
    • Sender
  • Jyxo_Rpc
    • Json
    • Xml
  • Jyxo_Shell
  • Jyxo_SpamFilter
  • Jyxo_Spl
  • Jyxo_String
  • Jyxo_Svn
  • Jyxo_Time
  • Jyxo_Timer
  • Jyxo_Webdav
  • Jyxo_XmlReader
  • PHP

Classes

  • Jyxo_Beholder_Executor
  • Jyxo_Beholder_Result
  • Jyxo_Beholder_TestCase
  • Jyxo_Beholder_TestCase_FileSystem
  • Jyxo_Beholder_TestCase_HttpResponse
  • Jyxo_Beholder_TestCase_Imap
  • Jyxo_Beholder_TestCase_JsonRpc
  • Jyxo_Beholder_TestCase_Memcached
  • Jyxo_Beholder_TestCase_Mysql
  • Jyxo_Beholder_TestCase_Pgsql
  • Jyxo_Beholder_TestCase_PhpExtension
  • Jyxo_Beholder_TestCase_PhpVersion
  • Jyxo_Beholder_TestCase_PhpZend
  • Jyxo_Beholder_TestCase_Smtp
  • Jyxo_Beholder_TestCase_Webdav
  • Jyxo_Beholder_TestCase_XmlRpc
  • Overview
  • Package
  • Class
  • Tree
  • Deprecated
  1: <?php
  2: 
  3: /**
  4:  * Jyxo PHP Library
  5:  *
  6:  * LICENSE
  7:  *
  8:  * This source file is subject to the new BSD license that is bundled
  9:  * with this package in the file license.txt.
 10:  * It is also available through the world-wide-web at this URL:
 11:  * https://github.com/jyxo/php/blob/master/license.txt
 12:  */
 13: 
 14: /**
 15:  * Beholder test executor.
 16:  *
 17:  * Includes filtering and HTML output formatting.
 18:  *
 19:  * Tests are performed in random order but results are outputted in alphabetical order with the order they were performed.
 20:  *
 21:  * Example:
 22:  * <code>
 23:  * $beholder = new Jyxo_Beholder_Executor('Project', $_GET);
 24:  * $beholder->addTest('T1', new Project_Beholder_Test1('Test 1'));
 25:  * $beholder->addTest('T2', new Project_Beholder_Test2('Test 2'));
 26:  * $beholder->addTest('T3', new Project_Beholder_Test3Blah('Test 3 Blah'));
 27:  * $beholder->run();
 28:  * </code>
 29:  *
 30:  * @category Jyxo
 31:  * @package Jyxo_Beholder
 32:  * @copyright Copyright (c) 2005-2011 Jyxo, s.r.o.
 33:  * @license https://github.com/jyxo/php/blob/master/license.txt
 34:  * @author Jan Matoušek
 35:  * @author Jaroslav Hanslík
 36:  */
 37: class Jyxo_Beholder_Executor
 38: {
 39:     /**
 40:      * Plaintext output.
 41:      *
 42:      * @var string
 43:      */
 44:     const OUTPUT_TEXT = 't';
 45: 
 46:     /**
 47:      * HTML output.
 48:      *
 49:      * @var string
 50:      */
 51:     const OUTPUT_HTML = 'h';
 52: 
 53:     /**
 54:      * Output parameter.
 55:      *
 56:      * @var string
 57:      */
 58:     const PARAM_OUTPUT = 'o';
 59: 
 60:     /**
 61:      * Parameter for including tests.
 62:      *
 63:      * @var string
 64:      */
 65:     const PARAM_INCLUDE = 't';
 66: 
 67:     /**
 68:      * Parameter for excluding tests.
 69:      *
 70:      * @var string
 71:      */
 72:     const PARAM_EXCLUDE = 'nt';
 73: 
 74:     /**
 75:      * Project name.
 76:      *
 77:      * @var string
 78:      */
 79:     private $project = '';
 80: 
 81:     /**
 82:      * List of tests.
 83:      *
 84:      * @var array
 85:      */
 86:     private $tests = array();
 87: 
 88:     /**
 89:      * Filter for including tests.
 90:      *
 91:      * @var string
 92:      */
 93:     private $includeFilter = '*';
 94: 
 95:     /**
 96:      * Filter for excluding tests.
 97:      *
 98:      * @var string
 99:      */
100:     private $excludeFilter = '';
101: 
102:     /**
103:      * Output type.
104:      *
105:      * @var string
106:      */
107:     private $output = self::OUTPUT_HTML;
108: 
109:     /**
110:      * Constructor.
111:      *
112:      * @param string $project Project name
113:      * @param array $params Parameters; possible parameters are: include, exclude, output
114:      */
115:     public function __construct($project, array $params = array())
116:     {
117:         // Project name
118:         $this->project = (string) $project;
119: 
120:         // Filters
121:         if (!empty($params[self::PARAM_INCLUDE])) {
122:             $this->includeFilter = (string) $params[self::PARAM_INCLUDE];
123:         }
124:         if (!empty($params[self::PARAM_EXCLUDE])) {
125:             $this->excludeFilter = (string) $params[self::PARAM_EXCLUDE];
126:         }
127: 
128:         // Output type
129:         if (!empty($params[self::PARAM_OUTPUT])) {
130:             switch ($params[self::PARAM_OUTPUT]) {
131:                 // Plaintext
132:                 case self::OUTPUT_TEXT:
133:                     $this->output = self::OUTPUT_TEXT;
134:                     break;
135:                 // HTML
136:                 case self::OUTPUT_HTML:
137:                 default:
138:                     $this->output = self::OUTPUT_HTML;
139:                     break;
140:             }
141:         }
142:     }
143: 
144:     /**
145:      * Performs chosen tests and outputs results according to the selected output type.
146:      *
147:      * @return boolean Returns if all tests were successful
148:      */
149:     public function run()
150:     {
151:         // Filters tests
152:         foreach (array_keys($this->tests) as $ident) {
153:             if (!$this->includeTest($ident)) {
154:                 unset($this->tests[$ident]);
155:             }
156:         }
157: 
158:         // Shuffles them
159:         $idents = array_keys($this->tests);
160:         shuffle($idents);
161: 
162:         // Performs tests and gathers results
163:         $outputData = array();
164:         $order = 1;
165:         $allSucceeded = true;
166:         foreach ($idents as $ident) {
167:             // Runs a test
168:             $data = $this->runTest($ident);
169: 
170:             // Saves the overall status
171:             $allSucceeded = $allSucceeded && $data['result']->isSuccess();
172: 
173:             // Adds the text into the output
174:             $data['order'] = $order++;
175:             $outputData[] = $data;
176:         }
177: 
178:         // Sorts tests according to their identifiers
179:         $idents = array();
180:         foreach ($outputData as $key => $data) {
181:             $idents[$key] = $data['ident'];
182:         }
183:         array_multisort($idents, SORT_ASC, $outputData);
184: 
185:         // Outputs the header
186:         if ($allSucceeded) {
187:             header('HTTP/1.1 200 OK');
188:         } else {
189:             header('HTTP/1.1 500 Internal Server Error');
190:         }
191: 
192:         // Outputs the output :)
193:         switch ($this->output) {
194:             // Plaintext
195:             case self::OUTPUT_TEXT:
196:                 $this->writeText($allSucceeded, $outputData);
197:                 break;
198:             // HTML
199:             case self::OUTPUT_HTML:
200:             default:
201:                 $this->writeHtml($allSucceeded, $outputData);
202:                 break;
203:         }
204: 
205:         return $allSucceeded;
206:     }
207: 
208:     /**
209:      * Adds a test.
210:      *
211:      * @param string $ident Tests identifier
212:      * @param Jyxo_Beholder_TestCase $test Test instance
213:      * @return Jyxo_Beholder_Executor
214:      */
215:     public function addTest($ident, Jyxo_Beholder_TestCase $test)
216:     {
217:         $this->tests[(string) $ident] = $test;
218: 
219:         return $this;
220:     }
221: 
222:     /**
223:      * Runs a single test.
224:      *
225:      * @param string $ident Test identifier
226:      * @return array
227:      * @throws UnexpectedValueException If the test returned an unknown result value
228:      */
229:     private function runTest($ident)
230:     {
231:         // Runs the test
232:         $timer = Jyxo_Timer::start();
233:         $result = $this->tests[$ident]->run();
234:         if (!($result instanceof Jyxo_Beholder_Result)) {
235:             throw new UnexpectedValueException(sprintf('Result %s of the test %s is not a Jyxo_Beholder_Result instance.', $result, $ident));
236:         }
237: 
238:         // Returns result data
239:         return array(
240:             'ident' => $ident,
241:             'test' => $this->tests[$ident],
242:             'result' => $result,
243:             'duration' => Jyxo_Timer::stop($timer)
244:         );
245:     }
246: 
247:     /**
248:      * Checks if the given test will be performed according to the current filter settings.
249:      *
250:      * @param string $ident Test identifier
251:      * @return boolean
252:      */
253:     private function includeTest($ident)
254:     {
255:         // If the test is not among the allowed ones, return false
256:         $include = false;
257:         foreach (explode(',', $this->includeFilter) as $pattern) {
258:             if ($this->patternMatch($pattern, $ident)) {
259:                 // We cannot use "return true" because the test might be disabled later
260:                 $include = true;
261:             }
262:         }
263:         if (!$include) {
264:             return false;
265:         }
266: 
267:         // If the test is among the excluded ones, return false
268:         foreach (explode(',', $this->excludeFilter) as $pattern) {
269:             if ($this->patternMatch($pattern, $ident)) {
270:                 return false;
271:             }
272:         }
273: 
274:         // Included otherwise
275:         return true;
276:     }
277: 
278:     /**
279:      * Checks if the given string matches the given pattern.
280:      *
281:      * @param string $pattern Pattern
282:      * @param string $string String to be matched
283:      * @return boolean
284:      */
285:     private function patternMatch($pattern, $string)
286:     {
287:         return fnmatch($pattern, $string);
288:     }
289: 
290:     /**
291:      * Outputs results in HTML form.
292:      *
293:      * @param boolean $allSucceeded Have all tests been successful
294:      * @param array $outputData Test results
295:      */
296:     private function writeHtml($allSucceeded, array $outputData)
297:     {
298:         header('Content-Type: text/html; charset=utf-8');
299:         echo '<head>' . "\n";
300:         echo '<meta http-equiv="content-type" content="text/html; charset=utf-8" />' . "\n";
301:         echo '<title>Beholder for project ' . $this->project . '</title>' . "\n";
302:         echo '<style>' . "\n";
303:         echo '  body {font: 12px Verdana, Geneva, Arial, Helvetica, sans-serif;}' . "\n";
304:         echo '  table {font-size: small; border-collapse: collapse;}' . "\n";
305:         echo '  table th {border: 1px solid #000; background: #000; color: #fff;}' . "\n";
306:         echo '  table td {border: 1px solid #000; padding: .25em .5em;}' . "\n";
307:         echo '</style>' . "\n";
308:         echo '</head>' . "\n";
309:         echo '<body style="background-color: ' . ($allSucceeded ? '#ccffcc' : '#ffcccc') . '; width: 90%; height: 100%; padding: 1em; margin: 0;">' . "\n";
310:         echo '<h1>Beholder for project ' . $this->project . "</h1>\n";
311:         echo '<p>Tests included: ' . $this->includeFilter . "\n";
312:         echo '<br>Tests excluded: ' . $this->excludeFilter . "\n";
313:         echo '</p>' . "\n";
314:         echo '<table><tr><th>Run order</th><th>Duration</th><th>Ident</th><th>Status</th><th>Test name</th><th>Comment</th></tr>' . "\n";
315:         foreach ($outputData as $data) {
316:             echo sprintf('
317:                 <tr>
318:                     <td>%d</td>
319:                     <td>%.2fs</td>
320:                     <td>%s</td>
321:                     <td style="color: %s;">%s</td>
322:                     <td><b>%s</b></td>
323:                     <td><i>%s</i></td>
324:                 </tr>' . "\n",
325:                 $data['order'],
326:                 $data['duration'],
327:                 $data['ident'],
328:                 $data['result']->isSuccess() ? 'green' : 'red; font-weight: bold;', $data['result']->getStatusMessage(),
329:                 $data['test']->getDescription(),
330:                 $data['result']->getDescription()
331:             );
332:         }
333:         echo '</table>
334:             <h2>Parameters</h2>
335:                 <dl>
336:                 <dt>' . self::PARAM_INCLUDE . '</dt>
337:                 <dd>Tests to include, list of shell patterns separated by comma, default *</dd>
338:                 <dt>' . self::PARAM_EXCLUDE . '</dt>
339:                 <dd>Tests to exclude, empty by default</dd>
340:                 <dt>' . self::PARAM_OUTPUT . '</dt>
341:                 <dd>' . self::OUTPUT_HTML . ' = HTML output, ' . self::OUTPUT_TEXT . ' = text output</dd>
342:                 </dl>
343:             <p>Tests are included, then excluded.</p>
344:             <p><a href="?' . self::PARAM_INCLUDE . '=' . $this->includeFilter
345:                 . '&amp;' . self::PARAM_EXCLUDE . '=' . $this->excludeFilter
346:                 . '&amp;' . self::PARAM_OUTPUT . '=' . self::OUTPUT_TEXT . '">Text version</a></p>
347:             </body>' . "\n";
348:     }
349: 
350:     /**
351:      * Outputs results in plaintext.
352:      *
353:      * @param boolean $allSucceeded Have all tests been successful
354:      * @param array $outputData Test results
355:      */
356:     private function writeText($allSucceeded, array $outputData)
357:     {
358:         // HTML is sent on purpose
359:         header('Content-Type: text/html; charset=utf-8');
360:         echo '<pre>This is Beholder for project ' . $this->project . "\n";
361:         echo 'Tests included: ' . $this->includeFilter . "\n";
362:         echo 'Tests excluded: ' . $this->excludeFilter . "\n\n";
363:         echo '<a href="?' . self::PARAM_INCLUDE . '=' . $this->includeFilter
364:             . '&amp;' . self::PARAM_EXCLUDE . '=' . $this->excludeFilter
365:             . '&amp;' . self::PARAM_OUTPUT . '=' . self::OUTPUT_HTML . "\">Html version</a>\n\n";
366: 
367:         echo sprintf("%-9s %10s   %-10s %-7s  %-35s    %s\n",
368:             'Run Order', 'Duration', 'Ident', 'Status', 'Test Name', 'Description');
369:         foreach ($outputData as $data) {
370:             echo sprintf("%9d %9.2fs   %-10s %-7s  %-35s    %s\n",
371:                 $data['order'],
372:                 $data['duration'],
373:                 $data['ident'],
374:                 $data['result']->getStatusMessage(),
375:                 $data['test']->getDescription(),
376:                 $data['result']->getDescription());
377:         }
378: 
379:         if ($allSucceeded) {
380:             echo "\nJust a little prayer so we know we are allright.\n\n";
381: 
382:             for ($i = 0; $i < 5; $i++) {
383:                 echo 'Our Father in heaven,' . "\n";
384:                 echo 'hallowed be your name,' . "\n";
385:                 echo 'your kingdom come,' . "\n";
386:                 echo 'your will be done' . "\n";
387:                 echo 'on earth as it is in heaven.' . "\n";
388:                 echo 'Give us today our daily bread,' . "\n";
389:                 echo 'and forgive us the wrong we have done' . "\n";
390:                 echo 'as we forgive those who wrong us.' . "\n";
391:                 echo 'Subject us not to the trial' . "\n";
392:                 echo 'but deliver us from the evil one.' . "\n";
393:                 echo 'And make the ' . $this->project . " project work.\n";
394:                 echo 'Amen.' . "\n\n";
395:             }
396:         }
397:     }
398: }
399: 
Jyxo PHP Library API documentation generated by ApiGen 2.3.0