Overview

Namespaces

  • PHP
  • XSLTBenchmarking
    • Reports
    • RunnerConsole
    • TestsGenerator
    • TestsRunner

Classes

  • Runner
  • Overview
  • Namespace
  • Class
  • Tree
  • Todo
  1: <?php
  2: 
  3: /**
  4:  * XSLT Benchmarking
  5:  * @link https://github.com/masicek/XSLT-Benchmarking
  6:  * @author Viktor Mašíček <viktor@masicek.net>
  7:  * @license "New" BSD License
  8:  */
  9: 
 10: namespace XSLTBenchmarking\RunnerConsole;
 11: 
 12: require_once LIBS . '/PhpOptions/PhpOptions.min.php';
 13: require_once LIBS . '/PhpPath/PhpPath.min.php';
 14: 
 15: require_once ROOT . '/Factory.php';
 16: require_once ROOT . '/Microtime.php';
 17: require_once ROOT . '/Printer.php';
 18: 
 19: require_once ROOT . '/TestsGenerator/Generator.php';
 20: require_once ROOT . '/TestsGenerator/Templating/Templating.php';
 21: require_once ROOT . '/TestsGenerator/Params/Params.php';
 22: require_once ROOT . '/TestsGenerator/XmlGenerator/XmlGenerator.php';
 23: 
 24: require_once ROOT . '/TestsRunner/Runner.php';
 25: require_once ROOT . '/TestsRunner/Params/Params.php';
 26: require_once ROOT . '/TestsRunner/TestRunner.php';
 27: require_once ROOT . '/TestsRunner/Processors/Processor.php';
 28: require_once ROOT . '/TestsRunner/Processors/MemoryUsage/MemoryUsage.php';
 29: require_once ROOT . '/TestsRunner/Controlor.php';
 30: 
 31: require_once ROOT . '/Reports/Printer.php';
 32: require_once ROOT . '/Reports/Merger.php';
 33: require_once ROOT . '/Reports/Convertor/Convertor.php';
 34: 
 35: use XSLTBenchmarking\Reports\Convertor;
 36: use XSLTBenchmarking\Microtime;
 37: use XSLTBenchmarking\Printer;
 38: use PhpOptions\Options;
 39: use PhpOptions\Option;
 40: use PhpPath\P;
 41: 
 42: /**
 43:  * Class for runnig XSLT Benchmark from console
 44:  *
 45:  * @author Viktor Mašíček <viktor@masicek.net>
 46:  */
 47: class Runner
 48: {
 49: 
 50: 
 51:     /**
 52:      * Comman line options
 53:      *
 54:      * @var \PhpOptions\Options
 55:      */
 56:     private $options;
 57: 
 58: 
 59:     /**
 60:      * Factory class for making new objects
 61:      *
 62:      * @var \XSLTBenchmarking\Factory
 63:      */
 64:     private $factory;
 65: 
 66: 
 67:     // ---- RUNNING ----
 68: 
 69:     /**
 70:      * Setting the object.
 71:      *
 72:      * @param string $baseDir Base dir of expected set directories
 73:      */
 74:     public function __construct($baseDir)
 75:     {
 76:         $this->options = $this->defineOptions($baseDir);
 77:         $this->factory = new \XSLTBenchmarking\Factory();
 78:     }
 79: 
 80: 
 81:     /**
 82:      * Run XSLT Benchmarking
 83:      * - show help
 84:      * - generate tests
 85:      * - run tests
 86:      * - print reports
 87:      *
 88:      * @return void
 89:      */
 90:     public function run()
 91:     {
 92:         $options = $this->options;
 93: 
 94:         if ($options->get('Help'))
 95:         {// @codeCoverageIgnoreStart
 96:             fwrite(STDOUT, $options->getHelp());
 97:             return;
 98:         }// @codeCoverageIgnoreEnd
 99: 
100:         if ($options->get('Processors available'))
101:         {// @codeCoverageIgnoreStart
102:             $this->printAvailableProcessors();
103:             return;
104:         }// @codeCoverageIgnoreEnd
105: 
106:         // generating tests
107:         if ($options->get('Generate'))
108:         {
109:             $this->generateTests();
110:         }
111: 
112:         // run tests
113:         if ($options->get('Run'))
114:         {
115:             $this->runTests();
116:         }
117: 
118:         // merge reports
119:         if ($options->get('Merge reports'))
120:         {
121:             $this->mergeReports();
122:         }
123: 
124:         // convert reports
125:         if ($options->get('Convert reports'))
126:         {
127:             $this->convertReports();
128:         }
129:     }
130: 
131: 
132:     // ---- DEFINE COMMAND-LINE OPTIONS ----
133: 
134: 
135:     /**
136:      * Define excepted command-line options.
137:      *
138:      * @param string $baseDir Base dir of expected set directories
139:      *
140:      * @return \PhpOptions\Options
141:      */
142:     private function defineOptions($baseDir)
143:     {
144:         try {
145:             $options = new Options();
146: 
147:             // base settings of options
148:             $help = Option::make('Help')->description('Show this help');
149:             $options->add($help)->defaults('Help');
150: 
151:             $description = 'XSLT Benchmarking ' . VERSION . ' - Console Runner' . PHP_EOL;
152:             $description .= 'author: Viktor Masicek <viktor@masicek.net>';
153:             $options->description($description);
154: 
155:             $optionsList = array();
156: 
157:             // common
158:             $optionsList[] = Option::make('Verbose')->description('Print informations during running scrips');
159: 
160:             // directories
161:             $templates = $optionsList[] = Option::directory('Templates', $baseDir)
162:                 ->short()
163:                 ->value(FALSE)
164:                 ->defaults('../Data/TestsTemplates')
165:                 ->description('Directory containing templates for generating tests');
166:             $tests = $optionsList[] = Option::directory('Tests', $baseDir, 'makeDir')
167:                 ->short()
168:                 ->value(FALSE)
169:                 ->defaults('../Data/Tests')
170:                 ->description('Directory for generating tests');
171:             $reportsDir = $optionsList[] = Option::directory('Reports', $baseDir, 'makeDir')
172:                 ->short()
173:                 ->value(FALSE)
174:                 ->defaults('../Data/Reports')
175:                 ->description('Directory for reports of tests');
176:             $optionsList[] = Option::directory('Tmp', $baseDir, 'makeDir')
177:                 ->short()
178:                 ->value(FALSE)
179:                 ->defaults('../Tmp')
180:                 ->description('Temporary directory');
181: 
182: 
183:             // generating tests
184:             $optionsList[] = Option::make('Generate')->description('Generating tests from templates');
185:             // @HACK in PhpOption 2.0.0 use array of dirs
186:             $optionsList[] = Option::series('Templates dirs', ',')
187:                 ->short()
188:                 ->value(FALSE)
189:                 ->defaults(TRUE)
190:                 ->description(
191:                     'Subdirectories of director set by "' . $templates->getOptions() . '" ' .
192:                     'containing tests templates for generating, separated by character ",". ' .
193:                     'If this option is not set (or is set without value), ' .
194:                     'then all tests templates are selected ' .
195:                     '(all subdirectories are considered as tests templates).'
196:                 );
197: 
198: 
199:             // run tests
200:             $optionsList[] = Option::make('Run')->description('Run prepared tests');
201:             // @HACK in PhpOption 2.0.0 use array of dirs
202:             $optionsList[] = Option::series('Tests dirs', ',')
203:                 ->short()
204:                 ->value(FALSE)
205:                 ->defaults(TRUE)
206:                 ->description(
207:                     'Subdirectories of director set by "' . $tests->getOptions() . '" ' .
208:                     'containing tests for runnig, separated by character ",". ' .
209:                     'If this option is not set (or is set without value), ' .
210:                     'then all tests are selected ' .
211:                     '(all subdirectories are considered as tests).'
212:                 );
213: 
214:             // @HACK in PhpOption 2.0.0 use array of enum
215:             $processors = $optionsList[] = Option::series('Processors', ',')
216:                 ->value(FALSE)
217:                 ->defaults(TRUE)
218:                 ->description(
219:                     'List of tested processors. ' .
220:                     'If this option is not set (or is set without value), ' .
221:                     'then all available processors are tested.'
222:                 );
223: 
224:             $processorsExclude = $optionsList[] = Option::series('Processors exclude', ',')
225:                 ->short('e')
226:                 ->defaults(array())
227:                 ->description(
228:                     'List of tested processors, that we want exclude form tested processors.'
229:                 );
230: 
231:             $optionsList[] = Option::make('Processors available')
232:                 ->short('a')
233:                 ->description(
234:                     'Print list of short names of available processors (possible used in options "' . $processors->getOptions() . '" ' .
235:                     'and "' . $processorsExclude->getOptions() . '") and their kernels and full names.'
236:                 );
237: 
238:             $optionsList[] = Option::integer('Repeating', 'unsigned')
239:                 ->short()
240:                 ->defaults(1)
241:                 ->description('Number of repeatig for each test and processor.');
242: 
243:             // merge reports
244:             $orderReports = $optionsList[] = Option::enum('Order reports', 'asc,desc,set')
245:                 ->defaults('set')
246:                 ->description('Type of ordering for merge reports.');
247: 
248:             $optionsList[] = Option::series('Merge reports')
249:                 ->value(FALSE)
250:                 ->description(
251:                     'List of mergered reports in directory set by "' . $reportsDir->getOptions() . '". ' .
252:                     'If this option is set without value, ' .
253:                     'then all available reports (without suffix "-merge") are mergered. ' .
254:                     'Reports are mergered in set order or ordered by name ' .
255:                     'if option "' . $orderReports->getOptions() . '" is set.'
256:                 );
257: 
258:             // convert reports into set output
259:             $convertType = $optionsList[] = Option::enum('Convert type', 'html')
260:                 ->short()
261:                 ->defaults('html')
262:                 ->description('Type of report converting');
263: 
264:             // @HACK
265:             //$optionsList[] = Option::file('Convert reports', $baseDir)
266:             $optionsList[] = Option::make('Convert reports')
267:                 ->value(FALSE)
268:                 ->description(
269:                     'Convert set report of tests into selected output ' .
270:                     'set by "' . $convertType->getOptions() . '". ' .
271:                     'If file is not set, latest report in direcotry set by '.
272:                     '"' . $reportsDir->getOptions() . '" is converted. ' .
273:                     'In case of emty dir, report file have to be set. ' .
274:                     'Generated converted report are saved into directory set by "' . $reportsDir->getOptions() . '".'
275:                 );
276: 
277:             $options->add($optionsList);
278: 
279:             // dependences + groups
280:             $options->dependences('Generate', array(
281:                     'Templates',
282:                     'Templates dirs',
283:                     'Tests',
284:                     'Tmp'),
285:                 'Generating tests'
286:             );
287: 
288:             $options->dependences('Run', array(
289:                     'Tests',
290:                     'Tests dirs',
291:                     'Processors',
292:                     'Processors exclude',
293:                     'Repeating',
294:                     'Reports',
295:                     'Tmp')
296:             );
297:             $options->group('Runnig tests', array(
298:                     'Run',
299:                     'Tests',
300:                     'Tests dirs',
301:                     'Processors',
302:                     'Processors exclude',
303:                     'Processors available',
304:                     'Repeating',
305:                     'Reports',
306:                     'Tmp')
307:             );
308: 
309:             $options->group('Reporting', array(
310:                 'Merge reports',
311:                 'Order reports',
312:                 'Reports',
313:             ));
314: 
315:             $options->group('Converting', array(
316:                 'Convert reports',
317:                 'Convert type',
318:                 'Reports',
319:             ));
320: 
321:         } catch (\PhpOptions\UserBadCallException $e) {// @codeCoverageIgnoreStart
322:             Printer::info('ERROR: ' . $e->getMessage());
323:             die();
324:         }// @codeCoverageIgnoreEnd
325: 
326:         return $options;
327:     }
328: 
329: 
330:     // ---- PARTS OF RUNNING ----
331: 
332: 
333:     /**
334:      * Print available processors
335:      *
336:      * @codeCoverageIgnore
337:      *
338:      * @return void
339:      */
340:     private function printAvailableProcessors()
341:     {
342:         $tmpDir = $this->options->get('Tmp');
343:         $memoryUsage = new \XSLTBenchmarking\TestsRunner\MemoryUsage($tmpDir);
344:         $processor = new \XSLTBenchmarking\TestsRunner\Processor($tmpDir, $memoryUsage);
345:         $processorsDrivers = $processor->getAvailable();
346: 
347:         // get max lengtho of each parts
348:         $maxName = 0;
349:         $maxKernel = 0;
350:         foreach($processorsDrivers as $driverName => $processorDriver)
351:         {
352:             if (strlen($driverName) > $maxName)
353:             {
354:                 $maxName = strlen($driverName);
355:             }
356:             if (strlen($processorDriver->getKernel()) > $maxKernel)
357:             {
358:                 $maxKernel = strlen($processorDriver->getKernel());
359:             }
360:         }
361: 
362:         // print list
363:         Printer::header('Available processors');
364:         $name = str_pad('SHORT NAME', $maxName, ' ', STR_PAD_LEFT);
365:         $kernel = str_pad('KERNEL', $maxKernel, ' ', STR_PAD_LEFT);
366:         Printer::header($name . ' | ' . $kernel . ' | FULL NAME');
367:         foreach($processorsDrivers as $driverName => $processorDriver)
368:         {
369:             $name = str_pad($driverName, $maxName, ' ', STR_PAD_LEFT);
370:             $kernel = str_pad($processorDriver->getKernel(), $maxKernel, ' ', STR_PAD_LEFT);
371:             Printer::info($name . ' | ' . $kernel . ' | ' . $processorDriver->getFullName());
372:         }
373:     }
374: 
375: 
376:     /**
377:      * Generate tests from tests templates
378:      *
379:      * @return void
380:      */
381:     private function generateTests()
382:     {
383:         Printer::header('Generate Tests');
384: 
385:         $options = $this->options;
386:         $templatesDir = $options->get('Templates');
387:         $testsDir = $options->get('Tests');
388:         $tmpDir = $options->get('Tmp');
389: 
390:         $generator = new \XSLTBenchmarking\TestsGenerator\Generator(
391:             $this->factory,
392:             new \XSLTBenchmarking\TestsGenerator\Params(
393:                 new \XSLTBenchmarking\TestsGenerator\XmlGenerator($tmpDir),
394:                 $tmpDir),
395:             new \XSLTBenchmarking\TestsGenerator\Templating($tmpDir),
396:             new \XSLTBenchmarking\TestsRunner\Params(),
397:             $templatesDir,
398:             $testsDir
399:         );
400: 
401:         $templatesDirs = $options->get('Templates dirs');
402: 
403:         // generate all templates
404:         if ($templatesDirs === TRUE)
405:         {
406:             $templatesDirs = $this->getSubresources($templatesDir, 'directories');
407:         }
408: 
409:         if (count($templatesDirs) == 0)
410:         {
411:             Printer::info('No templateg for generating in "' . $templatesDir . '".');
412:             return;
413:         }
414: 
415:         foreach ($templatesDirs as $templateDir)
416:         {
417:             $generator->addTests($templateDir);
418:         }
419: 
420:         $start = Microtime::now();
421:         $testsNumber = $generator->generateAll($options->get('Verbose'));
422:         $end = Microtime::now();
423:         $length = Microtime::substract($end, $start);
424:         $length = Microtime::humanReadable($length);
425: 
426:         Printer::info('Tests generating lasted "' . $length . '". ' . $testsNumber . ' tests were generated from ' . count($templatesDirs) . ' temapltes into directory "' . $testsDir . '".');
427:     }
428: 
429: 
430:     /**
431:      * Run all tests
432:      *
433:      * @return void
434:      */
435:     private function runTests()
436:     {
437:         Printer::header('Run Tests');
438: 
439:         $options = $this->options;
440:         $testsDir = $options->get('Tests');
441:         $reportsDir = $options->get('Reports');
442:         $processors = $options->get('Processors');
443:         $processorsExclude = $options->get('Processors exclude');
444:         $repeating = $options->get('Repeating');
445:         $tmpDir = $options->get('Tmp');
446: 
447:         $memoryUsage = new \XSLTBenchmarking\TestsRunner\MemoryUsage($tmpDir);
448:         $processor = new \XSLTBenchmarking\TestsRunner\Processor($tmpDir, $memoryUsage);
449:         $runner = new \XSLTBenchmarking\TestsRunner\Runner(
450:             $this->factory,
451:             new \XSLTBenchmarking\TestsRunner\Params(),
452:             new \XSLTBenchmarking\TestsRunner\TestRunner(
453:                 $this->factory,
454:                 $processor,
455:                 $processors,
456:                 $processorsExclude,
457:                 $repeating,
458:                 new \XSLTBenchmarking\TestsRunner\Controlor(),
459:                 $tmpDir
460:             ),
461:             new \XSLTBenchmarking\Reports\Printer(
462:                 $reportsDir,
463:                 $processor->getInformations()
464:             ),
465:             $testsDir
466:         );
467: 
468:         $testsDirs = $options->get('Tests dirs');
469: 
470:         // generate all templates
471:         if ($testsDirs === TRUE)
472:         {
473:             $testsDirs = $this->getSubresources($testsDir, 'directories');
474:         }
475: 
476:         if (count($testsDirs) == 0)
477:         {
478:             Printer::info('No tests for running in "' . $testsDir . '".');
479:             return;
480:         }
481: 
482:         foreach ($testsDirs as $testDir)
483:         {
484:             $runner->addTest($testDir);
485:         }
486: 
487:         $start = Microtime::now();
488:         $reportFilePath = $runner->runAll($options->get('Verbose'));
489:         $end = Microtime::now();
490:         $length = Microtime::substract($end, $start);
491:         $length = Microtime::humanReadable($length);
492: 
493:         Printer::info('Tests runnig lasted "' . $length . '". Reports of tests are in "' . $reportFilePath . '".');
494:     }
495: 
496: 
497:     /**
498:      * Merge reports into one report file
499:      *
500:      * @return void
501:      */
502:     private function mergeReports()
503:     {
504:         Printer::header('Merge reports');
505: 
506:         $options = $this->options;
507:         $reportsDir = $options->get('Reports');
508:         $reportsFiles = $options->get('Merge reports');
509:         $orderType = $options->get('Order reports');
510: 
511:         // generate all templates
512:         if ($reportsFiles === TRUE || count($reportsFiles) == 0)
513:         {
514:             $reportsFiles = $this->getSubresources($reportsDir, 'files', '.xml');
515:             // exclude files with suffix '-merge'
516:             $reportsFiles = array_filter($reportsFiles, function ($item) {
517:                 return !preg_match('/-merge.xml$/', $item);
518:             });
519: 
520:             if (count($reportsFiles) == 0)
521:             {
522:                 Printer::info('No reports for merge in "' . $reportsDir . '".');
523:                 return;
524:             }
525:         }
526: 
527:         // order
528:         if ($orderType == 'asc' || $orderType == 'desc')
529:         {
530:             sort($reportsFiles);
531:         }
532:         if ($orderType == 'desc')
533:         {
534:             array_reverse($reportsFiles);
535:         }
536: 
537:         $merger = new \XSLTBenchmarking\Reports\Merger();
538: 
539:         foreach ($reportsFiles as $reportFile)
540:         {
541:             $merger->addReportFile(P::m($reportsDir, $reportFile));
542:         }
543: 
544:         $generatedReport = $merger->merge($reportsDir);
545: 
546:         Printer::info(count($reportsFiles) . ' resports were mergered into "' . $generatedReport . '".');
547:     }
548: 
549: 
550:     /**
551:      * Convert reports into another format
552:      *
553:      * @return void
554:      */
555:     private function convertReports()
556:     {
557:         Printer::header('Convert reports');
558: 
559:         $options = $this->options;
560:         $reportsDir = $options->get('Reports');
561:         $reportFile = $options->get('Convert reports');
562:         $convertType = $options->get('Convert type');
563:         $tmpDir = $options->get('Tmp');
564: 
565:         if ($reportFile === TRUE)
566:         {
567:             $latestFile = $this->latestFile($reportsDir, 'files', '.xml');
568:             if (!$latestFile)
569:             {
570:                 Printer::info('No reports for convert in "' . $reportsDir . '".');
571:                 return;
572:             }
573:             $reportFile = P::m($reportsDir, $latestFile);
574:         }
575: 
576:         $convertor = new Convertor($tmpDir);
577:         $convertor->setDriver($convertType);
578:         $generatedFile = $convertor->convert($reportFile, $reportsDir);
579: 
580:         Printer::info('"' . $generatedFile . '" was be converted from report file "' . $reportFile . '".');
581:     }
582: 
583: 
584:     // ---- HELPS FUNCTIONS ----
585: 
586: 
587:     /**
588:      * Return subdirectories and files names in set path
589:      *
590:      * @param string $path Directory that is scanned
591:      * @param string $type Type of returned resources ('files', 'directories', NULL = all)
592:      * @param string $suffix Required suffix of resources
593:      *
594:      * @return array
595:      */
596:     private function getSubresources($path, $type = NULL, $suffix = '')
597:     {
598:         $allResources = scandir($path);
599: 
600:         $dirs = array();
601:         foreach ($allResources as $resource)
602:         {
603:             if (in_array($resource, array('.', '..')))
604:             {
605:                 continue;
606:             }
607: 
608:             $fullPath = P::m($path, $resource);
609: 
610:             if ($type == 'directories' && !is_dir($fullPath))
611:             {
612:                 continue;
613:             }
614: 
615:             if ($type == 'files' && !is_file($fullPath))
616:             {
617:                 continue;
618:             }
619: 
620:             if ($suffix && !preg_match('/' . $suffix . '$/', $resource))
621:             {
622:                 continue;
623:             }
624: 
625:             $dirs[] = $resource;
626:         }
627: 
628:         return $dirs;
629:     }
630: 
631: 
632:     /**
633:      * Return lasted file in set directory.
634:      *
635:      * @param string $path Directory that is scanned
636:      * @param string $type Type of returned resources ('files', 'directories', NULL = all)
637:      * @param string $suffix Required suffix of resources
638:      *
639:      * @return string
640:      */
641:     private function latestFile($path, $type = NULL, $suffix = '')
642:     {
643:         $lastMod = 0;
644:         $lastModFile = '';
645:         foreach ($this->getSubresources($path, $type, $suffix) as $resource)
646:         {
647:             $fullPath = P::m($path, $resource);
648:             if (is_file($fullPath) && filectime($fullPath) > $lastMod)
649:             {
650:                 $lastMod = filectime($fullPath);
651:                 $lastModFile = $resource;
652:             }
653:         }
654: 
655:         return $lastModFile;
656:     }
657: 
658: 
659: }
660: 
XSTL Benchmarking API documentation generated by ApiGen.
Generated using the TokenReflection library.