1<?php declare(strict_types=1); 2 3namespace PhpParser; 4 5class CodeTestParser { 6 public function parseTest($code, $chunksPerTest) { 7 $code = canonicalize($code); 8 9 // evaluate @@{expr}@@ expressions 10 $code = preg_replace_callback( 11 '/@@\{(.*?)\}@@/', 12 function ($matches) { 13 return eval('return ' . $matches[1] . ';'); 14 }, 15 $code 16 ); 17 18 // parse sections 19 $parts = preg_split("/\n-----(?:\n|$)/", $code); 20 21 // first part is the name 22 $name = array_shift($parts); 23 24 // multiple sections possible with always two forming a pair 25 $chunks = array_chunk($parts, $chunksPerTest); 26 $tests = []; 27 foreach ($chunks as $i => $chunk) { 28 $lastPart = array_pop($chunk); 29 list($lastPart, $mode) = $this->extractMode($lastPart); 30 $tests[] = [$mode, array_merge($chunk, [$lastPart])]; 31 } 32 33 return [$name, $tests]; 34 } 35 36 public function reconstructTest($name, array $tests) { 37 $result = $name; 38 foreach ($tests as list($mode, $parts)) { 39 $lastPart = array_pop($parts); 40 foreach ($parts as $part) { 41 $result .= "\n-----\n$part"; 42 } 43 44 $result .= "\n-----\n"; 45 if (null !== $mode) { 46 $result .= "!!$mode\n"; 47 } 48 $result .= $lastPart; 49 } 50 return $result . "\n"; 51 } 52 53 private function extractMode(string $expected): array { 54 $firstNewLine = strpos($expected, "\n"); 55 if (false === $firstNewLine) { 56 $firstNewLine = strlen($expected); 57 } 58 59 $firstLine = substr($expected, 0, $firstNewLine); 60 if (0 !== strpos($firstLine, '!!')) { 61 return [$expected, null]; 62 } 63 64 $expected = (string) substr($expected, $firstNewLine + 1); 65 return [$expected, substr($firstLine, 2)]; 66 } 67} 68