-
Notifications
You must be signed in to change notification settings - Fork 186
/
Copy pathValidationTest.php
152 lines (126 loc) Β· 5.77 KB
/
ValidationTest.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
<?php
declare(strict_types = 1);
namespace LanguageServer\Tests;
use Exception;
use LanguageServer\Definition;
use LanguageServer\Index\Index;
use LanguageServer\PhpDocument;
use LanguageServer\DefinitionResolver;
use phpDocumentor\Reflection\DocBlock;
use phpDocumentor\Reflection\DocBlockFactory;
use PHPUnit\Framework\TestCase;
use LanguageServer\ClientHandler;
use LanguageServer\Message;
use AdvancedJsonRpc;
use RecursiveDirectoryIterator;
use RecursiveIteratorIterator;
use Sabre\Event\Loop;
use Microsoft\PhpParser;
class ValidationTest extends TestCase
{
public function validationTestProvider()
{
$testProviderArray = array();
$testCasesDir = realpath(__DIR__ . '/cases');
$iterator = new RecursiveDirectoryIterator($testCasesDir);
$disabled = json_decode(file_get_contents(__DIR__ . '/disabled.json'));
foreach (new RecursiveIteratorIterator($iterator) as $file) {
if (strpos(\strrev((string)$file), \strrev(".php")) === 0 && !\in_array(basename((string)$file), $disabled)) {
if ($file->getSize() < 100000) {
$testProviderArray[] = [$file->getPathname()];
}
}
}
return $testProviderArray;
}
/**
* This test loads the test cases specified in .php files under cases/ and looks at the whole set of
* Definitions and References produced. It reads the expected results from associated .json files
* and compares to the actual result. If they don't match, the test fails and it writes the new baseline
* to the .json file.
* @group validation
* @dataProvider validationTestProvider
* @param $testCaseFile
*/
public function testDefinitionsAndReferences($testCaseFile)
{
$fileContents = file_get_contents($testCaseFile);
$actualValues = $this->getActualTestValues($testCaseFile, $fileContents);
$outputFile = getExpectedValuesFile($testCaseFile);
if (!file_exists($outputFile)) {
file_put_contents($outputFile, json_encode($actualValues, JSON_PRETTY_PRINT|JSON_UNESCAPED_SLASHES));
}
$expectedValues = (array)json_decode(file_get_contents($outputFile));
try {
$this->assertEquals($expectedValues['definitions'], $actualValues['definitions']);
$this->assertEquals((array)$expectedValues['references'], (array)$actualValues['references'], sprintf('references match in "%s"', $outputFile));
} catch (\Throwable $e) {
$outputFile = getExpectedValuesFile($testCaseFile);
file_put_contents($outputFile, json_encode($actualValues, JSON_PRETTY_PRINT|JSON_UNESCAPED_SLASHES));
throw $e;
}
}
private function getActualTestValues($filename, $fileContents): array
{
$index = new Index();
$parser = new PhpParser\Parser();
$docBlockFactory = DocBlockFactory::createInstance();
$definitionResolver = new DefinitionResolver($index);
$document = new PhpDocument($filename, $fileContents, $index, $parser, $docBlockFactory, $definitionResolver);
$actualRefs = $index->getReferences();
$actualDefs = $this->getTestValuesFromDefs($document->getDefinitions());
// There's probably a more PHP-typical way to do this. Need to compare the objects parsed from json files
// to the real objects.
$refsAndDefs = array(
'references' => json_decode(json_encode($actualRefs)),
'definitions' => json_decode(json_encode($actualDefs))
);
// Turn references into relative paths
$testCasesDir = realpath(__DIR__ . '/cases');
foreach ($refsAndDefs['references'] as $key => $list) {
$fixedPathRefs = array_map(function ($ref) use ($testCasesDir) {
$ref = str_replace($testCasesDir, '.', $ref);
$ref = str_replace(DIRECTORY_SEPARATOR, '/', $ref);
return $ref;
}, $list);
$refsAndDefs['references']->$key = $fixedPathRefs;
}
// Turn def locations into relative paths
foreach ($refsAndDefs['definitions'] as $key => $def) {
if ($def !== null && $def->symbolInformation !== null &&
$def->symbolInformation->location !== null && $def->symbolInformation->location->uri !== null) {
$def->symbolInformation->location->uri = str_replace($testCasesDir, '.', $def->symbolInformation->location->uri);
$def->symbolInformation->location->uri = str_replace(DIRECTORY_SEPARATOR, '/', $def->symbolInformation->location->uri);
}
}
return $refsAndDefs;
}
/**
* @param $definitions Definition[]
* @return array|\array[]
*/
private function getTestValuesFromDefs($definitions): array
{
$propertyNames = get_class_vars(Definition::class);
$defsForAssert = [];
foreach ($definitions as $definition) {
$fqn = $definition->fqn;
foreach ($propertyNames as $propertyName => $value) {
if ($propertyName === 'symbolInformation') {
// Range is very often different - don't check it, for now
unset($definition->$propertyName->location->range);
} elseif ($propertyName === 'extends') {
$definition->$propertyName = $definition->$propertyName ?? [];
} elseif ($propertyName === 'type' && $definition->type !== null) {
$defsForAssert[$fqn]['type__tostring'] = (string)$definition->type;
}
$defsForAssert[$fqn][$propertyName] = $definition->$propertyName;
}
}
return $defsForAssert;
}
}
function getExpectedValuesFile($testCaseFile): string
{
return $testCaseFile . '.expected.json';
}