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