Просмотр исходного кода

Merge branch '2.2' into 2.9

# Conflicts:
#	composer.json
#	src/Fixer/Import/NoUnusedImportsFixer.php
#	tests/AutoReview/FixerFactoryTest.php
#	tests/AutoReview/ProjectCodeTest.php
#	tests/Test/AbstractIntegrationTestCase.php
#	tests/Test/IntegrationCaseFactory.php
Dariusz Ruminski 7 лет назад
Родитель
Сommit
6dfcde7e26

+ 2 - 1
.gitattributes

@@ -1,4 +1,4 @@
-# @TODO 3.0 replace following `tests/... exportignore` with single `tests/ export-ignore`
+# @TODO 3.0 replace following `tests/... export-ignore` with single `tests/ export-ignore`
 tests/**/*Test.php export-ignore
 tests/AbstractDoctrineAnnotationFixerTestCase.php export-ignore
 tests/Differ/AbstractDifferTestCase.php export-ignore
@@ -6,6 +6,7 @@ tests/Fixtures/ export-ignore
 tests/Linter/AbstractLinterTestCase.php export-ignore
 tests/Report/AbstractReporterTestCase.php export-ignore
 tests/Test/AbstractTransformerTestCase.php export-ignore
+tests/Test/InternalIntegrationCaseFactory.php export-ignore
 
 .appveyor.yml export-ignore
 .composer-require-checker.json export-ignore

+ 12 - 2
.travis.yml

@@ -38,8 +38,18 @@ jobs:
                 - export COMMIT_SCA_FILES=`git diff --name-only --diff-filter=ACMRTUXB $COMMIT_RANGE`
             script:
                 # @TODO remove at 3.0
-                - git archive -o /dev/null HEAD -v 2>&1 | grep tests | grep \.php | grep -v tests/TestCase.php | grep -v tests/Test/Assert/AssertTokensTrait.php | grep -v tests/Test/AbstractFixerTestCase.php | grep -v tests/Test/AbstractIntegrationTestCase.php | grep -v tests/Test/IntegrationCase.php | grep -v tests/Test/IntegrationCaseFactory.php && (echo "UNKNOWN FILES DETECTED" && travis_terminate 1) || echo "NO UNKNOWN FILES"
-
+                - |
+                  git archive -o /dev/null HEAD -v 2>&1 | grep tests | grep \.php \
+                    | grep -v tests/Test/AbstractFixerTestCase.php \
+                    | grep -v tests/Test/AbstractIntegrationCaseFactory.php \
+                    | grep -v tests/Test/AbstractIntegrationTestCase.php \
+                    | grep -v tests/Test/Assert/AssertTokensTrait.php \
+                    | grep -v tests/Test/IntegrationCase.php \
+                    | grep -v tests/Test/IntegrationCaseFactory.php \
+                    | grep -v tests/Test/IntegrationCaseFactoryInterface.php \
+                    | grep -v tests/Test/InternalIntegrationCaseFactory.php \
+                    | grep -v tests/TestCase.php \
+                    && (echo "UNKNOWN FILES DETECTED" && travis_terminate 1) || echo "NO UNKNOWN FILES"
                 - ./check_trailing_spaces.sh || travis_terminate 1
                 - if [ -n "$COMMIT_SCA_FILES" ]; then ./dev-tools/vendor/bin/phpmd `echo "$COMMIT_SCA_FILES" | grep -Ev "^(src/Resources|tests/Fixtures)" | xargs | sed 's/ /,/g'` text phpmd.xml || travis_terminate 1; fi
                 - ./dev-tools/vendor/bin/composer-require-checker check composer.json --config-file=.composer-require-checker.json

+ 3 - 0
composer.json

@@ -56,10 +56,13 @@
         "psr-4": { "PhpCsFixer\\": "src/" },
         "classmap": [
             "tests/Test/AbstractFixerTestCase.php",
+            "tests/Test/AbstractIntegrationCaseFactory.php",
             "tests/Test/AbstractIntegrationTestCase.php",
             "tests/Test/Assert/AssertTokensTrait.php",
             "tests/Test/IntegrationCase.php",
             "tests/Test/IntegrationCaseFactory.php",
+            "tests/Test/IntegrationCaseFactoryInterface.php",
+            "tests/Test/InternalIntegrationCaseFactory.php",
             "tests/TestCase.php"
         ]
     },

+ 1 - 1
src/Fixer/Phpdoc/PhpdocNoUselessInheritdocFixer.php

@@ -45,7 +45,7 @@ final class PhpdocNoUselessInheritdocFixer extends AbstractFixer
      */
     public function getPriority()
     {
-        // Should run before NoEmptyPhpdocFixer, PhpdocInlineTagFixer and NoTrailingWhitespaceInCommentFixer
+        // Should run before NoEmptyPhpdocFixer, NoTrailingWhitespaceInCommentFixer
         // and after PhpdocToCommentFixer.
         return 6;
     }

+ 0 - 2
tests/AutoReview/FixerFactoryTest.php

@@ -160,7 +160,6 @@ final class FixerFactoryTest extends TestCase
             [$fixers['phpdoc_no_package'], $fixers['phpdoc_trim']],
             [$fixers['phpdoc_no_useless_inheritdoc'], $fixers['no_empty_phpdoc']],
             [$fixers['phpdoc_no_useless_inheritdoc'], $fixers['no_trailing_whitespace_in_comment']],
-            [$fixers['phpdoc_no_useless_inheritdoc'], $fixers['phpdoc_inline_tag']],
             [$fixers['phpdoc_order'], $fixers['phpdoc_separation']],
             [$fixers['phpdoc_order'], $fixers['phpdoc_trim']],
             [$fixers['phpdoc_separation'], $fixers['phpdoc_trim']],
@@ -179,7 +178,6 @@ final class FixerFactoryTest extends TestCase
             [$fixers['single_import_per_statement'], $fixers['no_multiline_whitespace_before_semicolons']],
             [$fixers['single_import_per_statement'], $fixers['no_singleline_whitespace_before_semicolons']],
             [$fixers['single_import_per_statement'], $fixers['no_unused_imports']],
-            [$fixers['single_import_per_statement'], $fixers['ordered_imports']],
             [$fixers['single_import_per_statement'], $fixers['space_after_semicolon']],
             [$fixers['standardize_not_equals'], $fixers['binary_operator_spaces']],
             [$fixers['strict_comparison'], $fixers['binary_operator_spaces']],

+ 0 - 0
tests/Fixtures/Integration/priority/phpdoc_no_useless_inheritdoc,phpdoc_inline_tag.test → tests/Fixtures/Integration/misc/phpdoc_no_useless_inheritdoc,phpdoc_inline_tag.test


+ 0 - 0
tests/Fixtures/Integration/priority/single_import_per_statement,ordered_imports.test → tests/Fixtures/Integration/misc/single_import_per_statement,ordered_imports.test


+ 45 - 0
tests/IntegrationTest.php

@@ -13,6 +13,8 @@
 namespace PhpCsFixer\Tests;
 
 use PhpCsFixer\Tests\Test\AbstractIntegrationTestCase;
+use PhpCsFixer\Tests\Test\IntegrationCase;
+use PhpCsFixer\Tests\Test\InternalIntegrationCaseFactory;
 
 /**
  * Test that parses and runs the fixture '*.test' files found in '/Fixtures/Integration'.
@@ -40,4 +42,47 @@ final class IntegrationTest extends AbstractIntegrationTestCase
     {
         return self::getFixturesDir().DIRECTORY_SEPARATOR.'.tmp.php';
     }
+
+    /**
+     * {@inheritdoc}
+     */
+    protected static function createIntegrationCaseFactory()
+    {
+        return new InternalIntegrationCaseFactory();
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    protected static function assertRevertedOrderFixing(IntegrationCase $case, $fixedInputCode, $fixedInputCodeWithReversedFixers)
+    {
+        parent::assertRevertedOrderFixing($case, $fixedInputCode, $fixedInputCodeWithReversedFixers);
+
+        $settings = $case->getSettings();
+
+        if (!isset($settings['isExplicitPriorityCheck'])) {
+            static::markTestIncomplete('Missing `isExplicitPriorityCheck` extension setting.');
+        }
+
+        if ($settings['isExplicitPriorityCheck']) {
+            if ($fixedInputCode === $fixedInputCodeWithReversedFixers) {
+                if (in_array($case->getFileName(), [
+                    'priority/braces,indentation_type,no_break_comment.test',
+                    'priority/standardize_not_equals,binary_operator_spaces.test',
+                ], true)) {
+                    static::markTestIncomplete(sprintf(
+                        'Integration test `%s` was defined as explicit priority test, but no priority conflict was detected.'
+                        ."\n".'Either integration test needs to be extended, or test moved from `priority` to `misc`.'
+                        ."\n".'Bud don\'t do it blindly - it deserves investigation!',
+                        $case->getFileName()
+                    ));
+                }
+            }
+
+            static::assertTrue(
+                $fixedInputCode !== $fixedInputCodeWithReversedFixers,
+                sprintf('Test "%s" in "%s" is expected to be priority check.', $case->getTitle(), $case->getFileName())
+            );
+        }
+    }
 }

+ 263 - 0
tests/Test/AbstractIntegrationCaseFactory.php

@@ -0,0 +1,263 @@
+<?php
+
+/*
+ * This file is part of PHP CS Fixer.
+ *
+ * (c) Fabien Potencier <fabien@symfony.com>
+ *     Dariusz Rumiński <dariusz.ruminski@gmail.com>
+ *
+ * This source file is subject to the MIT license that is bundled
+ * with this source code in the file LICENSE.
+ */
+
+namespace PhpCsFixer\Tests\Test;
+
+use PhpCsFixer\RuleSet;
+use Symfony\Component\Finder\SplFileInfo;
+
+/**
+ * @author Dariusz Rumiński <dariusz.ruminski@gmail.com>
+ *
+ * @internal
+ */
+abstract class AbstractIntegrationCaseFactory implements IntegrationCaseFactoryInterface
+{
+    /**
+     * @param SplFileInfo $file
+     *
+     * @return IntegrationCase
+     */
+    public function create(SplFileInfo $file)
+    {
+        try {
+            if (!preg_match(
+                '/^
+                            --TEST--           \r?\n(?<title>          .*?)
+                       \s   --RULESET--        \r?\n(?<ruleset>        .*?)
+                    (?:\s   --CONFIG--         \r?\n(?<config>         .*?))?
+                    (?:\s   --SETTINGS--       \r?\n(?<settings>       .*?))?
+                    (?:\s   --REQUIREMENTS--   \r?\n(?<requirements>   .*?))?
+                    (?:\s   --EXPECT--         \r?\n(?<expect>         .*?\r?\n*))?
+                    (?:\s   --INPUT--          \r?\n(?<input>          .*))?
+                $/sx',
+                $file->getContents(),
+                $match
+            )) {
+                throw new \InvalidArgumentException('File format is invalid.');
+            }
+
+            $match = array_merge(
+                [
+                    'config' => null,
+                    'settings' => null,
+                    'requirements' => null,
+                    'expect' => null,
+                    'input' => null,
+                ],
+                $match
+            );
+
+            return new IntegrationCase(
+                $file->getRelativePathname(),
+                $this->determineTitle($file, $match['title']),
+                $this->determineSettings($file, $match['settings']),
+                $this->determineRequirements($file, $match['requirements']),
+                $this->determineConfig($file, $match['config']),
+                $this->determineRuleset($file, $match['ruleset']),
+                $this->determineExpectedCode($file, $match['expect']),
+                $this->determineInputCode($file, $match['input'])
+            );
+        } catch (\InvalidArgumentException $e) {
+            throw new \InvalidArgumentException(
+                sprintf('%s Test file: "%s".', $e->getMessage(), $file->getRelativePathname()),
+                $e->getCode(),
+                $e
+            );
+        }
+    }
+
+    /**
+     * Parses the '--CONFIG--' block of a '.test' file.
+     *
+     * @param SplFileInfo $file
+     * @param string      $config
+     *
+     * @return array
+     */
+    protected function determineConfig(SplFileInfo $file, $config)
+    {
+        $parsed = $this->parseJson($config, [
+            'indent' => '    ',
+            'lineEnding' => "\n",
+        ]);
+
+        if (!is_string($parsed['indent'])) {
+            throw new \InvalidArgumentException(sprintf(
+                'Expected string value for "indent", got "%s".',
+                is_object($parsed['indent']) ? get_class($parsed['indent']) : gettype($parsed['indent']).'#'.$parsed['indent']
+            ));
+        }
+
+        if (!is_string($parsed['lineEnding'])) {
+            throw new \InvalidArgumentException(sprintf(
+                'Expected string value for "lineEnding", got "%s".',
+                is_object($parsed['lineEnding']) ? get_class($parsed['lineEnding']) : gettype($parsed['lineEnding']).'#'.$parsed['lineEnding']
+            ));
+        }
+
+        return $parsed;
+    }
+
+    /**
+     * Parses the '--REQUIREMENTS--' block of a '.test' file and determines requirements.
+     *
+     * @param SplFileInfo $file
+     * @param string      $config
+     *
+     * @return array
+     */
+    protected function determineRequirements(SplFileInfo $file, $config)
+    {
+        $parsed = $this->parseJson($config, [
+            'php' => PHP_VERSION_ID,
+        ]);
+
+        if (!is_int($parsed['php'])) {
+            throw new \InvalidArgumentException(sprintf(
+                'Expected int value like 50509 for "php", got "%s".',
+                is_object($parsed['php']) ? get_class($parsed['php']) : gettype($parsed['php']).'#'.$parsed['php']
+            ));
+        }
+
+        return $parsed;
+    }
+
+    /**
+     * Parses the '--RULESET--' block of a '.test' file and determines what fixers should be used.
+     *
+     * @param SplFileInfo $file
+     * @param string      $config
+     *
+     * @return RuleSet
+     */
+    protected function determineRuleset(SplFileInfo $file, $config)
+    {
+        return new RuleSet($this->parseJson($config));
+    }
+
+    /**
+     * Parses the '--TEST--' block of a '.test' file and determines title.
+     *
+     * @param SplFileInfo $file
+     * @param string      $config
+     *
+     * @return string
+     */
+    protected function determineTitle(SplFileInfo $file, $config)
+    {
+        return $config;
+    }
+
+    /**
+     * Parses the '--SETTINGS--' block of a '.test' file and determines settings.
+     *
+     * @param SplFileInfo $file
+     * @param string      $config
+     *
+     * @return array
+     */
+    protected function determineSettings(SplFileInfo $file, $config)
+    {
+        $parsed = $this->parseJson($config, [
+            'checkPriority' => true,
+        ]);
+
+        if (!is_bool($parsed['checkPriority'])) {
+            throw new \InvalidArgumentException(sprintf(
+                'Expected bool value for "checkPriority", got "%s".',
+                is_object($parsed['checkPriority']) ? get_class($parsed['checkPriority']) : gettype($parsed['checkPriority']).'#'.$parsed['checkPriority']
+            ));
+        }
+
+        return $parsed;
+    }
+
+    /**
+     * @param SplFileInfo $file
+     * @param null|string $code
+     *
+     * @return string
+     */
+    protected function determineExpectedCode(SplFileInfo $file, $code)
+    {
+        $code = $this->determineCode($file, $code, '-out.php');
+
+        if (null === $code) {
+            throw new \InvalidArgumentException('Missing expected code.');
+        }
+
+        return $code;
+    }
+
+    /**
+     * @param SplFileInfo $file
+     * @param null|string $code
+     *
+     * @return null|string
+     */
+    protected function determineInputCode(SplFileInfo $file, $code)
+    {
+        return $this->determineCode($file, $code, '-in.php');
+    }
+
+    /**
+     * @param SplFileInfo $file
+     * @param null|string $code
+     * @param string      $suffix
+     *
+     * @return null|string
+     */
+    private function determineCode(SplFileInfo $file, $code, $suffix)
+    {
+        if (null !== $code) {
+            return $code;
+        }
+
+        $candidateFile = new SplFileInfo($file->getPathname().$suffix, '', '');
+        if ($candidateFile->isFile()) {
+            return $candidateFile->getContents();
+        }
+    }
+
+    /**
+     * @param null|string $encoded
+     * @param null|array  $template
+     *
+     * @return array
+     */
+    private function parseJson($encoded, array $template = null)
+    {
+        // content is optional if template is provided
+        if (!$encoded && null !== $template) {
+            $decoded = [];
+        } else {
+            $decoded = json_decode($encoded, true);
+
+            if (JSON_ERROR_NONE !== json_last_error()) {
+                throw new \InvalidArgumentException(sprintf('Malformed JSON: "%s", error: "%s".', $encoded, json_last_error_msg()));
+            }
+        }
+
+        if (null !== $template) {
+            $decoded = array_merge(
+                $template,
+                array_intersect_key(
+                    $decoded,
+                    array_flip(array_keys($template))
+                )
+            );
+        }
+
+        return $decoded;
+    }
+}

+ 38 - 20
tests/Test/AbstractIntegrationTestCase.php

@@ -144,7 +144,7 @@ abstract class AbstractIntegrationTestCase extends TestCase
             throw new \UnexpectedValueException(sprintf('Given fixture dir "%s" is not a directory.', $fixturesDir));
         }
 
-        $factory = new IntegrationCaseFactory();
+        $factory = static::createIntegrationCaseFactory();
         $tests = [];
 
         foreach (Finder::create()->files()->in($fixturesDir) as $file) {
@@ -160,6 +160,14 @@ abstract class AbstractIntegrationTestCase extends TestCase
         return $tests;
     }
 
+    /**
+     * @return IntegrationCaseFactoryInterface
+     */
+    protected static function createIntegrationCaseFactory()
+    {
+        return new IntegrationCaseFactory();
+    }
+
     /**
      * Returns the full path to directory which contains the tests.
      *
@@ -207,7 +215,7 @@ abstract class AbstractIntegrationTestCase extends TestCase
         }
 
         $errorsManager = new ErrorsManager();
-        $fixers = $this->createFixers($case);
+        $fixers = static::createFixers($case);
         $runner = new Runner(
             new \ArrayIterator([new \SplFileInfo($tmpFile)]),
             $fixers,
@@ -283,23 +291,7 @@ abstract class AbstractIntegrationTestCase extends TestCase
             $runner->fix();
             $fixedInputCodeWithReversedFixers = file_get_contents($tmpFile);
 
-            // If output is different depends on rules order - we need to verify that the rules are ordered by priority.
-            // If not, any order is valid.
-            if ($fixedInputCode !== $fixedInputCodeWithReversedFixers) {
-                $this->assertGreaterThan(
-                    1,
-                    count(array_unique(array_map(
-                        static function (FixerInterface $fixer) {
-                            return $fixer->getPriority();
-                        },
-                        $fixers
-                    ))),
-                    sprintf(
-                        'Rules priorities are not differential enough. If rules would be used in reverse order then final output would be different than the expected one. For that, different priorities must be set up for used rules to ensure stable order of them. In "%s".',
-                        $case->getFileName()
-                    )
-                );
-            }
+            $this->assertRevertedOrderFixing($case, $fixedInputCode, $fixedInputCodeWithReversedFixers);
         }
 
         // run the test again with the `expected` part, this should always stay the same
@@ -317,12 +309,38 @@ abstract class AbstractIntegrationTestCase extends TestCase
         );
     }
 
+    /**
+     * @param IntegrationCase $case
+     * @param string          $fixedInputCode
+     * @param string          $fixedInputCodeWithReversedFixers
+     */
+    protected static function assertRevertedOrderFixing(IntegrationCase $case, $fixedInputCode, $fixedInputCodeWithReversedFixers)
+    {
+        // If output is different depends on rules order - we need to verify that the rules are ordered by priority.
+        // If not, any order is valid.
+        if ($fixedInputCode !== $fixedInputCodeWithReversedFixers) {
+            static::assertGreaterThan(
+                1,
+                count(array_unique(array_map(
+                    static function (FixerInterface $fixer) {
+                        return $fixer->getPriority();
+                    },
+                    static::createFixers($case)
+                ))),
+                sprintf(
+                    'Rules priorities are not differential enough. If rules would be used in reverse order then final output would be different than the expected one. For that, different priorities must be set up for used rules to ensure stable order of them. In "%s".',
+                    $case->getFileName()
+                )
+            );
+        }
+    }
+
     /**
      * @param IntegrationCase $case
      *
      * @return FixerInterface[]
      */
-    private function createFixers(IntegrationCase $case)
+    private static function createFixers(IntegrationCase $case)
     {
         $config = $case->getConfig();
 

Некоторые файлы не были показаны из-за большого количества измененных файлов