* Dariusz Rumiński * * This source file is subject to the MIT license that is bundled * with this source code in the file LICENSE. */ namespace PhpCsFixer\Tests; use PhpCsFixer\Fixer\FixerInterface; use PhpCsFixer\Tokenizer\Token; use PhpCsFixer\Utils; use Symfony\Bridge\PhpUnit\ExpectDeprecationTrait; /** * @author Dariusz Rumiński * @author Graham Campbell * @author Odín del Río * * @internal * * @covers \PhpCsFixer\Utils */ final class UtilsTest extends TestCase { use ExpectDeprecationTrait; private $originalValueOfFutureMode; protected function setUp(): void { $this->originalValueOfFutureMode = getenv('PHP_CS_FIXER_FUTURE_MODE'); } protected function tearDown(): void { putenv("PHP_CS_FIXER_FUTURE_MODE={$this->originalValueOfFutureMode}"); } /** * @param string $expected Camel case string * * @dataProvider provideCamelCaseToUnderscoreCases */ public function testCamelCaseToUnderscore(string $expected, string $input = null): void { if (null !== $input) { static::assertSame($expected, Utils::camelCaseToUnderscore($input)); } static::assertSame($expected, Utils::camelCaseToUnderscore($expected)); } public function provideCamelCaseToUnderscoreCases(): array { return [ [ 'dollar_close_curly_braces', 'DollarCloseCurlyBraces', ], [ 'utf8_encoder_fixer', 'utf8EncoderFixer', ], [ 'terminated_with_number10', 'TerminatedWithNumber10', ], [ 'utf8_encoder_fixer', ], [ 'a', 'A', ], [ 'aa', 'AA', ], [ 'foo', 'FOO', ], [ 'foo_bar_baz', 'FooBarBAZ', ], [ 'foo_bar_baz', 'FooBARBaz', ], [ 'foo_bar_baz', 'FOOBarBaz', ], [ 'mr_t', 'MrT', ], [ 'voyage_éclair', 'VoyageÉclair', ], ]; } /** * @param array|string $input token prototype * * @dataProvider provideCalculateTrailingWhitespaceIndentCases */ public function testCalculateTrailingWhitespaceIndent(string $spaces, $input): void { $token = new Token($input); static::assertSame($spaces, Utils::calculateTrailingWhitespaceIndent($token)); } public function provideCalculateTrailingWhitespaceIndentCases(): array { return [ [' ', [T_WHITESPACE, "\n\n "]], [' ', [T_WHITESPACE, "\r\n\r\r\r "]], ["\t", [T_WHITESPACE, "\r\n\t"]], ['', [T_WHITESPACE, "\t\n\r"]], ['', [T_WHITESPACE, "\n"]], ['', ''], ]; } public function testCalculateTrailingWhitespaceIndentFail(): void { $this->expectException(\InvalidArgumentException::class); $this->expectExceptionMessage('The given token must be whitespace, got "T_STRING".'); $token = new Token([T_STRING, 'foo']); Utils::calculateTrailingWhitespaceIndent($token); } /** * @dataProvider provideStableSortCases */ public function testStableSort( array $expected, array $elements, callable $getComparableValueCallback, callable $compareValuesCallback ): void { static::assertSame( $expected, Utils::stableSort($elements, $getComparableValueCallback, $compareValuesCallback) ); } public function provideStableSortCases(): array { return [ [ ['a', 'b', 'c', 'd', 'e'], ['b', 'd', 'e', 'a', 'c'], static function ($element) { return $element; }, 'strcmp', ], [ ['b', 'd', 'e', 'a', 'c'], ['b', 'd', 'e', 'a', 'c'], static function (): string { return 'foo'; }, 'strcmp', ], [ ['b', 'd', 'e', 'a', 'c'], ['b', 'd', 'e', 'a', 'c'], static function ($element) { return $element; }, static function (): int { return 0; }, ], [ ['bar1', 'baz1', 'foo1', 'bar2', 'baz2', 'foo2'], ['foo1', 'foo2', 'bar1', 'bar2', 'baz1', 'baz2'], static function ($element) { return preg_replace('/([a-z]+)(\d+)/', '$2$1', $element); }, 'strcmp', ], ]; } public function testSortFixers(): void { $fixers = [ $this->createFixerDouble('f1', 0), $this->createFixerDouble('f2', -10), $this->createFixerDouble('f3', 10), $this->createFixerDouble('f4', -10), ]; static::assertSame( [ $fixers[2], $fixers[0], $fixers[1], $fixers[3], ], Utils::sortFixers($fixers) ); } public function testNaturalLanguageJoinWithBackticksThrowsInvalidArgumentExceptionForEmptyArray(): void { $this->expectException(\InvalidArgumentException::class); Utils::naturalLanguageJoinWithBackticks([]); } /** * @dataProvider provideNaturalLanguageJoinWithBackticksCases */ public function testNaturalLanguageJoinWithBackticks(string $joined, array $names): void { static::assertSame($joined, Utils::naturalLanguageJoinWithBackticks($names)); } public function provideNaturalLanguageJoinWithBackticksCases(): array { return [ [ '`a`', ['a'], ], [ '`a` and `b`', ['a', 'b'], ], [ '`a`, `b` and `c`', ['a', 'b', 'c'], ], ]; } /** * @group legacy */ public function testTriggerDeprecationWhenFutureModeIsOff(): void { putenv('PHP_CS_FIXER_FUTURE_MODE=0'); $message = __METHOD__.'::The message'; $this->expectDeprecation($message); Utils::triggerDeprecation(new \DomainException($message)); $triggered = Utils::getTriggeredDeprecations(); static::assertContains($message, $triggered); } public function testTriggerDeprecationWhenFutureModeIsOn(): void { putenv('PHP_CS_FIXER_FUTURE_MODE=1'); $message = __METHOD__.'::The message'; $exception = new \DomainException($message); $futureModeException = null; try { Utils::triggerDeprecation($exception); } catch (\Exception $futureModeException) { } static::assertInstanceOf(\RuntimeException::class, $futureModeException); static::assertSame($exception, $futureModeException->getPrevious()); $triggered = Utils::getTriggeredDeprecations(); static::assertNotContains($message, $triggered); } private function createFixerDouble(string $name, int $priority): FixerInterface { $fixer = $this->prophesize(FixerInterface::class); $fixer->getName()->willReturn($name); $fixer->getPriority()->willReturn($priority); return $fixer->reveal(); } }