1: <?php
2:
3: 4: 5: 6: 7: 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: 44: 45: 46:
47: class Runner
48: {
49:
50:
51: 52: 53: 54: 55:
56: private $options;
57:
58:
59: 60: 61: 62: 63:
64: private $factory;
65:
66:
67:
68:
69: 70: 71: 72: 73:
74: public function __construct($baseDir)
75: {
76: $this->options = $this->defineOptions($baseDir);
77: $this->factory = new \XSLTBenchmarking\Factory();
78: }
79:
80:
81: 82: 83: 84: 85: 86: 87: 88: 89:
90: public function run()
91: {
92: $options = $this->options;
93:
94: if ($options->get('Help'))
95: {
96: fwrite(STDOUT, $options->getHelp());
97: return;
98: }
99:
100: if ($options->get('Processors available'))
101: {
102: $this->printAvailableProcessors();
103: return;
104: }
105:
106:
107: if ($options->get('Generate'))
108: {
109: $this->generateTests();
110: }
111:
112:
113: if ($options->get('Run'))
114: {
115: $this->runTests();
116: }
117:
118:
119: if ($options->get('Merge reports'))
120: {
121: $this->mergeReports();
122: }
123:
124:
125: if ($options->get('Convert reports'))
126: {
127: $this->convertReports();
128: }
129: }
130:
131:
132:
133:
134:
135: 136: 137: 138: 139: 140: 141:
142: private function defineOptions($baseDir)
143: {
144: try {
145: $options = new Options();
146:
147:
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:
158: $optionsList[] = Option::make('Verbose')->description('Print informations during running scrips');
159:
160:
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:
184: $optionsList[] = Option::make('Generate')->description('Generating tests from templates');
185:
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:
200: $optionsList[] = Option::make('Run')->description('Run prepared tests');
201:
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:
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:
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:
259: $convertType = $optionsList[] = Option::enum('Convert type', 'html')
260: ->short()
261: ->defaults('html')
262: ->description('Type of report converting');
263:
264:
265:
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:
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) {
322: Printer::info('ERROR: ' . $e->getMessage());
323: die();
324: }
325:
326: return $options;
327: }
328:
329:
330:
331:
332:
333: 334: 335: 336: 337: 338: 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:
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:
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: 378: 379: 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:
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: 432: 433: 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:
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: 499: 500: 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:
512: if ($reportsFiles === TRUE || count($reportsFiles) == 0)
513: {
514: $reportsFiles = $this->getSubresources($reportsDir, 'files', '.xml');
515:
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:
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: 552: 553: 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:
585:
586:
587: 588: 589: 590: 591: 592: 593: 594: 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: 634: 635: 636: 637: 638: 639: 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: