1
0
Fork 0
php-language-server/tests/Validation/ValidationTest.php

157 lines
5.9 KiB
PHP
Raw Normal View History

2017-03-15 21:10:29 +00:00
<?php
declare(strict_types = 1);
namespace LanguageServer\Tests;
use Exception;
2017-05-01 23:50:42 +00:00
use LanguageServer\Definition;
2017-03-15 21:10:29 +00:00
use LanguageServer\Index\Index;
use LanguageServer\ParserKind;
2017-03-15 21:10:29 +00:00
use LanguageServer\PhpDocument;
use LanguageServer\DefinitionResolver;
2017-05-01 23:50:42 +00:00
use phpDocumentor\Reflection\DocBlock;
2017-03-15 21:10:29 +00:00
use phpDocumentor\Reflection\DocBlockFactory;
use PHPUnit\Framework\TestCase;
use LanguageServer\ClientHandler;
use LanguageServer\Protocol\Message;
use AdvancedJsonRpc;
use RecursiveDirectoryIterator;
use RecursiveIteratorIterator;
use Sabre\Event\Loop;
use Microsoft\PhpParser;
2017-03-15 21:10:29 +00:00
class ValidationTest extends TestCase
{
2017-06-07 21:00:12 +00:00
public function validationTestProvider()
2017-05-25 18:39:42 +00:00
{
2017-03-15 21:10:29 +00:00
$testProviderArray = array();
$testCasesDir = realpath(__DIR__ . '/cases');
2017-05-01 23:50:42 +00:00
2017-06-07 21:00:12 +00:00
$iterator = new RecursiveDirectoryIterator($testCasesDir);
$disabled = json_decode(file_get_contents(__DIR__ . '/disabled.json'));
2017-03-15 21:10:29 +00:00
2017-06-07 21:00:12 +00:00
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()];
2017-03-15 21:10:29 +00:00
}
}
}
2017-03-15 21:10:29 +00:00
return $testProviderArray;
}
/**
2017-06-07 21:00:12 +00:00
* 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
2017-06-07 21:00:12 +00:00
* @dataProvider validationTestProvider
2017-05-01 23:50:42 +00:00
* @param $testCaseFile
*/
2017-06-07 21:00:12 +00:00
public function testDefinitionsAndReferences($testCaseFile)
2017-05-25 18:39:42 +00:00
{
$fileContents = file_get_contents($testCaseFile);
$actualValues = $this->getActualTestValues($testCaseFile, $fileContents);
$outputFile = getExpectedValuesFile($testCaseFile);
if (!file_exists($outputFile)) {
2017-05-15 23:47:42 +00:00
file_put_contents($outputFile, json_encode($actualValues, JSON_PRETTY_PRINT|JSON_UNESCAPED_SLASHES));
}
$expectedValues = (array)json_decode(file_get_contents($outputFile));
2017-05-01 23:50:42 +00:00
try {
$this->assertEquals($expectedValues['definitions'], $actualValues['definitions']);
try {
$this->assertArraySubset((array)$expectedValues['references'], (array)$actualValues['references'], false, 'references don\'t match.');
} catch (\Throwable $e) {
$this->assertEquals((array)$expectedValues['references'], (array)$actualValues['references'], 'references don\'t match.');
}
} catch (\Throwable $e) {
$outputFile = getExpectedValuesFile($testCaseFile);
2017-06-07 21:00:12 +00:00
file_put_contents($outputFile, json_encode($actualValues, JSON_PRETTY_PRINT|JSON_UNESCAPED_SLASHES));
throw $e;
2017-05-01 23:50:42 +00:00
}
}
2017-05-25 18:39:42 +00:00
private function getActualTestValues($filename, $fileContents): array
{
2017-05-01 23:50:42 +00:00
$index = new Index();
$parser = new PhpParser\Parser();
2017-05-01 23:50:42 +00:00
$docBlockFactory = DocBlockFactory::createInstance();
$definitionResolver = new DefinitionResolver($index);
2017-05-01 23:50:42 +00:00
$document = new PhpDocument($filename, $fileContents, $index, $parser, $docBlockFactory, $definitionResolver);
2017-06-06 23:46:08 +00:00
$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) {
2017-06-07 21:00:12 +00:00
$fixedPathRefs = array_map(function ($ref) use ($testCasesDir) {
return str_replace($testCasesDir, '.', $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) {
2017-06-07 21:00:12 +00:00
$def->symbolInformation->location->uri = str_replace($testCasesDir, '.', $def->symbolInformation->location->uri);
}
}
return $refsAndDefs;
2017-05-01 23:50:42 +00:00
}
/**
* @param $definitions Definition[]
2017-05-01 23:50:42 +00:00
* @return array|\array[]
*/
private function getTestValuesFromDefs($definitions): array
2017-05-01 23:50:42 +00:00
{
$propertyNames = get_class_vars(Definition::class);
2017-05-01 23:50:42 +00:00
$defsForAssert = [];
foreach ($definitions as $definition) {
$fqn = $definition->fqn;
2017-05-01 23:50:42 +00:00
foreach ($propertyNames as $propertyName => $value) {
2017-05-01 23:50:42 +00:00
if ($propertyName === 'symbolInformation') {
// Range is very often different - don't check it, for now
unset($definition->$propertyName->location->range);
2017-05-01 23:50:42 +00:00
} elseif ($propertyName === 'extends') {
$definition->$propertyName = $definition->$propertyName ?? [];
2017-05-15 23:47:42 +00:00
} elseif ($propertyName === 'type' && $definition->type !== null) {
// Class info is not captured by json_encode. It's important for 'type'.
2017-05-15 23:47:42 +00:00
$defsForAssert[$fqn]['type__class'] = get_class($definition->type);
}
$defsForAssert[$fqn][$propertyName] = $definition->$propertyName;
}
2017-05-01 23:50:42 +00:00
}
return $defsForAssert;
2017-05-01 23:50:42 +00:00
}
}
2017-05-25 18:39:42 +00:00
function getExpectedValuesFile($testCaseFile): string
{
return $testCaseFile . '.expected.json';
}