diff --git a/.gitattributes b/.gitattributes index 5e686cf4..f8866dbb 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,5 +1,6 @@ /.github/ export-ignore /tests/ export-ignore +/tools/ export-ignore /.editorconfig export-ignore /.gitattributes export-ignore /.gitignore export-ignore diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index 1b95c247..d4b7c782 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -11,6 +11,8 @@ For details, take a look at the following workflow configuration files: ## Coding Standards +We are using [`ergebnis/composer-normalize`](https://github.com/ergebnis/composer-normalize) to normalize `composer.json`. + We are using [`yamllint`](https://github.com/adrienverge/yamllint) to enforce coding standards in YAML files. If you do not have `yamllint` installed yet, run @@ -21,13 +23,27 @@ $ brew install yamllint to install `yamllint`. +We are using [`friendsofphp/php-cs-fixer`](https://github.com/FriendsOfPHP/PHP-CS-Fixer) to enforce coding standards in PHP files. + Run ```sh $ make coding-standards ``` -to detect coding standard violations. +to automatically fix coding standard violations. + +## Static Code Analysis + +We are using [`vimeo/psalm`](https://github.com/vimeo/psalm) to statically analyze the code. + +Run + +```sh +$ make static-code-analysis +``` + +to run a static code analysis. ## Tests @@ -49,7 +65,7 @@ Run $ make ``` -to detect coding standard violations and run tests! +to enforce coding standards, run a static code analysis, and run tests! ## Help diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml index e47cb040..9fd01781 100644 --- a/.github/FUNDING.yml +++ b/.github/FUNDING.yml @@ -1 +1 @@ -patreon: "s_bergmann" +github: "sebastianbergmann" diff --git a/.github/settings.yml b/.github/settings.yml index c2c77ef0..fe17f8e9 100644 --- a/.github/settings.yml +++ b/.github/settings.yml @@ -14,10 +14,18 @@ branches: required_approving_review_count: 1 required_status_checks: contexts: - - "Coding Standards" + - "Code Coverage (7.4, highest)" + - "Coding Standards (7.1)" - "Tests (7.1, highest)" + - "Tests (7.1, lowest)" - "Tests (7.2, highest)" + - "Tests (7.2, lowest)" - "Tests (7.3, highest)" + - "Tests (7.3, lowest)" + - "Tests (7.4, highest)" + - "Tests (7.4, lowest)" + - "Tests (8.0, highest)" + - "Tests (8.0, lowest)" strict: false restrictions: null diff --git a/.github/workflows/integrate.yaml b/.github/workflows/integrate.yaml index 5b7e0c1d..266309ff 100644 --- a/.github/workflows/integrate.yaml +++ b/.github/workflows/integrate.yaml @@ -14,6 +14,11 @@ jobs: runs-on: "ubuntu-latest" + strategy: + matrix: + php-version: + - "7.1" + steps: - name: "Checkout" uses: "actions/checkout@v2.3.1" @@ -25,6 +30,115 @@ jobs: file_or_dir: "." strict: true + - name: "Install PHP with extensions" + uses: "shivammathur/setup-php@v2" + with: + coverage: "none" + extensions: "${{ env.PHP_EXTENSIONS }}" + php-version: "${{ matrix.php-version }}" + + - name: "Validate composer.json and composer.lock" + run: "composer validate --strict" + + - name: "Run ergebnis/composer-normalize" + run: "tools/composer-normalize --dry-run" + + - name: "Create cache directory for friendsofphp/php-cs-fixer" + run: "mkdir -p .build/php-cs-fixer" + + - name: "Cache cache directory for friendsofphp/php-cs-fixer" + uses: "actions/cache@v2" + with: + path: ".build/php-cs-fixer" + key: "php-${{ matrix.php-version }}-php-cs-fixer-${{ hashFiles('tools/php-cs-fixer') }}" + restore-keys: "php-${{ matrix.php-version }}-php-cs-fixer-" + + - name: "Run friendsofphp/php-cs-fixer" + run: "tools/php-cs-fixer fix --config=.php_cs --diff --diff-format=udiff --dry-run --verbose" + + static-code-analysis: + name: "Static Code Analysis" + + runs-on: "ubuntu-latest" + + strategy: + matrix: + php-version: + - "7.4" + + dependencies: + - "highest" + + steps: + - name: "Checkout" + uses: "actions/checkout@v2.3.1" + + - name: "Install PHP with extensions" + uses: "shivammathur/setup-php@v2" + with: + coverage: "none" + php-version: "${{ matrix.php-version }}" + + - name: "Determine composer cache directory" + id: "determine-composer-cache-directory" + run: "echo \"::set-output name=directory::$(composer config cache-dir)\"" + + - name: "Cache dependencies installed with composer" + uses: "actions/cache@v2" + with: + path: "${{ steps.determine-composer-cache-directory.outputs.directory }}" + key: "php-${{ matrix.php-version }}-composer-${{ matrix.dependencies }}-${{ hashFiles('composer.lock') }}" + restore-keys: "php-${{ matrix.php-version }}-composer-${{ matrix.dependencies }}-" + + - name: "Install lowest dependencies from composer.json" + if: "matrix.dependencies == 'lowest'" + run: "composer update --no-interaction --no-progress --no-suggest --prefer-lowest" + + - name: "Install locked dependencies from composer.lock" + if: "matrix.dependencies == 'locked'" + run: "composer install --no-interaction --no-progress --no-suggest" + + - name: "Install highest dependencies from composer.json" + if: "matrix.dependencies == 'highest'" + run: "composer update --no-interaction --no-progress --no-suggest" + + - name: "Create cache directory for vimeo/psalm" + run: "mkdir -p .build/psalm" + + - name: "Cache cache directory for vimeo/psalm" + uses: "actions/cache@v2" + with: + path: ".build/psalm" + key: "php-${{ matrix.php-version }}-psalm-${{ github.sha }}" + restore-keys: "php-${{ matrix.php-version }}-psalm-" + + - name: "Run vimeo/psalm" + run: "tools/psalm --config=psalm.xml --diff --diff-methods --shepherd --show-info=false --stats --threads=4" + + backward-compatibility: + name: "Backward Compatibility" + + runs-on: "ubuntu-latest" + + steps: + - name: "Checkout" + uses: "actions/checkout@v2.3.1" + with: + fetch-depth: 0 + + - name: "Fetch tags" + run: "git fetch --depth=1 origin +refs/tags/*:refs/tags/*" + + - name: "Install PHP with extensions" + uses: "shivammathur/setup-php@v2" + with: + php-version: "7.4" + coverage: "none" + extensions: "intl" + + - name: "Run roave/backward-compatibility-check" + run: "tools/roave-backward-compatibility-check --from=1.0.0" + tests: name: "Tests" @@ -36,8 +150,11 @@ jobs: - "7.1" - "7.2" - "7.3" + - "7.4" + - "8.0" dependencies: + - "lowest" - "highest" steps: @@ -76,12 +193,73 @@ jobs: - name: "Run tests with phpunit/phpunit" run: "vendor/bin/phpunit --configuration=phpunit.xml" + code-coverage: + name: "Code Coverage" + + runs-on: "ubuntu-latest" + + strategy: + matrix: + php-version: + - "7.4" + + dependencies: + - "highest" + + steps: + - name: "Checkout" + uses: "actions/checkout@v2.3.1" + + - name: "Install PHP with extensions" + uses: "shivammathur/setup-php@v2" + with: + coverage: "xdebug" + php-version: "${{ matrix.php-version }}" + + - name: "Determine composer cache directory" + id: "determine-composer-cache-directory" + run: "echo \"::set-output name=directory::$(composer config cache-dir)\"" + + - name: "Cache dependencies installed with composer" + uses: "actions/cache@v2" + with: + path: "${{ steps.determine-composer-cache-directory.outputs.directory }}" + key: "php-${{ matrix.php-version }}-composer-${{ matrix.dependencies }}-${{ hashFiles('composer.lock') }}" + restore-keys: "php-${{ matrix.php-version }}-composer-${{ matrix.dependencies }}-" + + - name: "Install lowest dependencies from composer.json" + if: "matrix.dependencies == 'lowest'" + run: "composer update --no-interaction --no-progress --no-suggest --prefer-lowest" + + - name: "Install locked dependencies from composer.lock" + if: "matrix.dependencies == 'locked'" + run: "composer install --no-interaction --no-progress --no-suggest" + + - name: "Install highest dependencies from composer.json" + if: "matrix.dependencies == 'highest'" + run: "composer update --no-interaction --no-progress --no-suggest" + + - name: "Dump Xdebug filter with phpunit/phpunit" + run: "vendor/bin/phpunit --configuration=test/Integration/phpunit.xml --dump-xdebug-filter=.build/phpunit/xdebug-filter.php" + + - name: "Collect code coverage with Xdebug and phpunit/phpunit" + run: "vendor/bin/phpunit --configuration=test/Integration/phpunit.xml --coverage-clover=.build/logs/clover.xml --prepend=.build/phpunit/xdebug-filter.php" + + - name: "Send code coverage report to Codecov.io" + env: + CODECOV_TOKEN: "${{ secrets.CODECOV_TOKEN }}" + run: "bash <(curl -s https://codecov.io/bash)" + merge: name: "Merge" runs-on: "ubuntu-latest" needs: + - "backward-compatibility" + - "code-coverage" + - "coding-standards" + - "static-code-analysis" - "tests" if: > diff --git a/.php_cs b/.php_cs new file mode 100644 index 00000000..1abc0858 --- /dev/null +++ b/.php_cs @@ -0,0 +1,214 @@ + + +For the full copyright and license information, please view the LICENSE +file that was distributed with this source code. +EOF; + +$finder = PhpCsFixer\Finder::create() + ->files() + ->in(__DIR__ . '/src') + ->in(__DIR__ . '/tests'); + +return PhpCsFixer\Config::create() + ->setCacheFile(__DIR__ . '/.build/php-cs-fixer/.php_cs.cache') + ->setFinder($finder) + ->setRiskyAllowed(true) + ->setRules([ + 'align_multiline_comment' => true, + 'array_indentation' => true, + 'array_syntax' => ['syntax' => 'short'], + 'binary_operator_spaces' => [ + 'operators' => [ + '=' => 'align', + '=>' => 'align', + ], + ], + 'blank_line_after_namespace' => true, + 'blank_line_before_statement' => [ + 'statements' => [ + 'break', + 'continue', + 'declare', + 'do', + 'for', + 'foreach', + 'if', + 'include', + 'include_once', + 'require', + 'require_once', + 'return', + 'switch', + 'throw', + 'try', + 'while', + 'yield', + ], + ], + 'braces' => true, + 'cast_spaces' => true, + 'class_attributes_separation' => ['elements' => ['const', 'method', 'property']], + 'combine_consecutive_issets' => true, + 'combine_consecutive_unsets' => true, + 'compact_nullable_typehint' => true, + 'concat_space' => ['spacing' => 'one'], + 'declare_equal_normalize' => ['space' => 'none'], + 'declare_strict_types' => true, + 'dir_constant' => true, + 'elseif' => true, + 'encoding' => true, + 'full_opening_tag' => true, + 'function_declaration' => true, + 'global_namespace_import' => [ + 'import_classes' => true, + 'import_constants' => true, + 'import_functions' => true, + ], + 'header_comment' => ['header' => $header, 'separate' => 'none'], + 'indentation_type' => true, + 'is_null' => true, + 'line_ending' => true, + 'list_syntax' => ['syntax' => 'short'], + 'logical_operators' => true, + 'lowercase_cast' => true, + 'lowercase_constants' => true, + 'lowercase_keywords' => true, + 'lowercase_static_reference' => true, + 'magic_constant_casing' => true, + 'method_argument_space' => ['ensure_fully_multiline' => true], + 'modernize_types_casting' => true, + 'multiline_comment_opening_closing' => true, + 'multiline_whitespace_before_semicolons' => true, + 'native_constant_invocation' => false, + 'native_function_casing' => false, + 'native_function_invocation' => false, + 'new_with_braces' => false, + 'no_alias_functions' => true, + 'no_alternative_syntax' => true, + 'no_blank_lines_after_class_opening' => true, + 'no_blank_lines_after_phpdoc' => true, + 'no_blank_lines_before_namespace' => true, + 'no_closing_tag' => true, + 'no_empty_comment' => true, + 'no_empty_phpdoc' => true, + 'no_empty_statement' => true, + 'no_extra_blank_lines' => true, + 'no_homoglyph_names' => true, + 'no_leading_import_slash' => true, + 'no_leading_namespace_whitespace' => true, + 'no_mixed_echo_print' => ['use' => 'print'], + 'no_multiline_whitespace_around_double_arrow' => true, + 'no_null_property_initialization' => true, + 'no_php4_constructor' => true, + 'no_short_bool_cast' => true, + 'no_short_echo_tag' => true, + 'no_singleline_whitespace_before_semicolons' => true, + 'no_spaces_after_function_name' => true, + 'no_spaces_inside_parenthesis' => true, + 'no_superfluous_elseif' => true, + 'no_superfluous_phpdoc_tags' => [ + 'allow_mixed' => true, + ], + 'no_trailing_comma_in_list_call' => true, + 'no_trailing_comma_in_singleline_array' => true, + 'no_trailing_whitespace' => true, + 'no_trailing_whitespace_in_comment' => true, + 'no_unneeded_control_parentheses' => true, + 'no_unneeded_curly_braces' => true, + 'no_unneeded_final_method' => true, + 'no_unreachable_default_argument_value' => true, + 'no_unset_on_property' => true, + 'no_unused_imports' => true, + 'no_useless_else' => true, + 'no_useless_return' => true, + 'no_whitespace_before_comma_in_array' => true, + 'no_whitespace_in_blank_line' => true, + 'non_printable_character' => true, + 'normalize_index_brace' => true, + 'object_operator_without_whitespace' => true, + 'ordered_class_elements' => [ + 'order' => [ + 'use_trait', + 'constant_public', + 'constant_protected', + 'constant_private', + 'property_public_static', + 'property_protected_static', + 'property_private_static', + 'property_public', + 'property_protected', + 'property_private', + 'method_public_static', + 'construct', + 'destruct', + 'magic', + 'phpunit', + 'method_public', + 'method_protected', + 'method_private', + 'method_protected_static', + 'method_private_static', + ], + ], + 'ordered_imports' => [ + 'imports_order' => [ + PhpCsFixer\Fixer\Import\OrderedImportsFixer::IMPORT_TYPE_CONST, + PhpCsFixer\Fixer\Import\OrderedImportsFixer::IMPORT_TYPE_FUNCTION, + PhpCsFixer\Fixer\Import\OrderedImportsFixer::IMPORT_TYPE_CLASS, + ] + ], + 'ordered_interfaces' => [ + 'direction' => 'ascend', + 'order' => 'alpha', + ], + 'phpdoc_add_missing_param_annotation' => false, + 'phpdoc_align' => true, + 'phpdoc_annotation_without_dot' => true, + 'phpdoc_indent' => true, + 'phpdoc_no_access' => true, + 'phpdoc_no_empty_return' => true, + 'phpdoc_no_package' => true, + 'phpdoc_order' => true, + 'phpdoc_return_self_reference' => true, + 'phpdoc_scalar' => true, + 'phpdoc_separation' => true, + 'phpdoc_single_line_var_spacing' => true, + 'phpdoc_summary' => true, + 'phpdoc_to_comment' => true, + 'phpdoc_trim' => true, + 'phpdoc_trim_consecutive_blank_line_separation' => true, + 'phpdoc_types' => ['groups' => ['simple', 'meta']], + 'phpdoc_types_order' => true, + 'phpdoc_var_without_name' => true, + 'pow_to_exponentiation' => true, + 'protected_to_private' => true, + 'return_assignment' => true, + 'return_type_declaration' => ['space_before' => 'none'], + 'self_accessor' => true, + 'semicolon_after_instruction' => true, + 'set_type_to_cast' => true, + 'short_scalar_cast' => true, + 'simplified_null_return' => false, + 'single_blank_line_at_eof' => true, + 'single_import_per_statement' => true, + 'single_line_after_imports' => true, + 'single_quote' => true, + 'standardize_not_equals' => true, + 'ternary_to_null_coalescing' => true, + 'trailing_comma_in_multiline_array' => true, + 'trim_array_spaces' => true, + 'unary_operator_spaces' => true, + 'visibility_required' => [ + 'elements' => [ + 'const', + 'method', + 'property', + ], + ], + 'void_return' => true, + 'whitespace_after_comma_in_array' => true, + ]); diff --git a/.php_cs.dist b/.php_cs.dist deleted file mode 100644 index 92146075..00000000 --- a/.php_cs.dist +++ /dev/null @@ -1,168 +0,0 @@ - - -For the full copyright and license information, please view the LICENSE -file that was distributed with this source code. -EOF; - -return PhpCsFixer\Config::create() - ->setRiskyAllowed(true) - ->setRules( - [ - 'array_syntax' => ['syntax' => 'short'], - 'binary_operator_spaces' => [ - 'operators' => [ - '=' => 'align', - '=>' => 'align', - ], - ], - 'blank_line_after_namespace' => true, - 'blank_line_before_statement' => [ - 'statements' => [ - 'break', - 'continue', - 'declare', - 'do', - 'for', - 'foreach', - 'if', - 'include', - 'include_once', - 'require', - 'require_once', - 'return', - 'switch', - 'throw', - 'try', - 'while', - 'yield', - ], - ], - 'braces' => true, - 'cast_spaces' => true, - 'class_attributes_separation' => ['elements' => ['method']], - 'compact_nullable_typehint' => true, - 'concat_space' => ['spacing' => 'one'], - 'declare_equal_normalize' => ['space' => 'none'], - 'declare_strict_types' => true, - 'dir_constant' => true, - 'elseif' => true, - 'encoding' => true, - 'full_opening_tag' => true, - 'function_declaration' => true, - 'header_comment' => ['header' => $header, 'separate' => 'none'], - 'indentation_type' => true, - 'line_ending' => true, - 'list_syntax' => ['syntax' => 'short'], - 'lowercase_cast' => true, - 'lowercase_constants' => true, - 'lowercase_keywords' => true, - 'magic_constant_casing' => true, - 'method_argument_space' => ['ensure_fully_multiline' => true], - 'modernize_types_casting' => true, - 'native_function_casing' => true, - 'native_function_invocation' => true, - 'no_alias_functions' => true, - 'no_blank_lines_after_class_opening' => true, - 'no_blank_lines_after_phpdoc' => true, - 'no_closing_tag' => true, - 'no_empty_comment' => true, - 'no_empty_phpdoc' => true, - 'no_empty_statement' => true, - 'no_extra_blank_lines' => true, - 'no_homoglyph_names' => true, - 'no_leading_import_slash' => true, - 'no_leading_namespace_whitespace' => true, - 'no_mixed_echo_print' => ['use' => 'print'], - 'no_null_property_initialization' => true, - 'no_short_bool_cast' => true, - 'no_short_echo_tag' => true, - 'no_singleline_whitespace_before_semicolons' => true, - 'no_spaces_after_function_name' => true, - 'no_spaces_inside_parenthesis' => true, - 'no_superfluous_elseif' => true, - 'no_trailing_comma_in_list_call' => true, - 'no_trailing_comma_in_singleline_array' => true, - 'no_trailing_whitespace' => true, - 'no_trailing_whitespace_in_comment' => true, - 'no_unneeded_control_parentheses' => true, - 'no_unneeded_curly_braces' => true, - 'no_unneeded_final_method' => true, - 'no_unreachable_default_argument_value' => true, - 'no_unused_imports' => true, - 'no_useless_else' => true, - 'no_whitespace_before_comma_in_array' => true, - 'no_whitespace_in_blank_line' => true, - 'non_printable_character' => true, - 'normalize_index_brace' => true, - 'object_operator_without_whitespace' => true, - 'ordered_class_elements' => [ - 'order' => [ - 'use_trait', - 'constant_public', - 'constant_protected', - 'constant_private', - 'property_public_static', - 'property_protected_static', - 'property_private_static', - 'property_public', - 'property_protected', - 'property_private', - 'method_public_static', - 'construct', - 'destruct', - 'magic', - 'phpunit', - 'method_public', - 'method_protected', - 'method_private', - 'method_protected_static', - 'method_private_static', - ], - ], - 'ordered_imports' => true, - 'phpdoc_add_missing_param_annotation' => true, - 'phpdoc_align' => true, - 'phpdoc_annotation_without_dot' => true, - 'phpdoc_indent' => true, - 'phpdoc_no_access' => true, - 'phpdoc_no_empty_return' => true, - 'phpdoc_no_package' => true, - 'phpdoc_order' => true, - 'phpdoc_return_self_reference' => true, - 'phpdoc_scalar' => true, - 'phpdoc_separation' => true, - 'phpdoc_single_line_var_spacing' => true, - 'phpdoc_to_comment' => true, - 'phpdoc_trim' => true, - 'phpdoc_types' => true, - 'phpdoc_types_order' => true, - 'phpdoc_var_without_name' => true, - 'pow_to_exponentiation' => true, - 'protected_to_private' => true, - 'return_type_declaration' => ['space_before' => 'none'], - 'self_accessor' => true, - 'short_scalar_cast' => true, - 'simplified_null_return' => true, - 'single_blank_line_at_eof' => true, - 'single_import_per_statement' => true, - 'single_line_after_imports' => true, - 'single_quote' => true, - 'standardize_not_equals' => true, - 'ternary_to_null_coalescing' => true, - 'trim_array_spaces' => true, - 'unary_operator_spaces' => true, - 'visibility_required' => true, - 'void_return' => true, - 'whitespace_after_comma_in_array' => true, - ] - ) - ->setFinder( - PhpCsFixer\Finder::create() - ->files() - ->in(__DIR__ . '/src') - ->in(__DIR__ . '/tests') - ); diff --git a/ChangeLog.md b/ChangeLog.md index 76ccd877..df68a730 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -2,6 +2,24 @@ All notable changes are documented in this file using the [Keep a CHANGELOG](http://keepachangelog.com/) principles. +## [4.0.2] - 2020-06-30 + +### Added + +* This component is now supported on PHP 8 + +## [4.0.1] - 2020-05-08 + +### Fixed + +* [#99](https://github.com/sebastianbergmann/diff/pull/99): Regression in unified diff output of identical strings + +## [4.0.0] - 2020-02-07 + +### Removed + +* Removed support for PHP 7.1 and PHP 7.2 + ## [3.0.2] - 2019-02-04 ### Changed @@ -28,24 +46,27 @@ All notable changes are documented in this file using the [Keep a CHANGELOG](htt ### Fixed -* Fixed [#70](https://github.com/sebastianbergmann/diff/issues/70): Diffing of arrays no longer works +* [#70](https://github.com/sebastianbergmann/diff/issues/70): Diffing of arrays no longer works ## [2.0.1] - 2017-08-03 ### Fixed -* Fixed [#66](https://github.com/sebastianbergmann/diff/pull/66): Restored backwards compatibility for PHPUnit 6.1.4, 6.2.0, 6.2.1, 6.2.2, and 6.2.3 +* [#66](https://github.com/sebastianbergmann/diff/pull/66): Restored backwards compatibility for PHPUnit 6.1.4, 6.2.0, 6.2.1, 6.2.2, and 6.2.3 ## [2.0.0] - 2017-07-11 [YANKED] ### Added -* Implemented [#64](https://github.com/sebastianbergmann/diff/pull/64): Show line numbers for chunks of a diff +* [#64](https://github.com/sebastianbergmann/diff/pull/64): Show line numbers for chunks of a diff ### Removed * This component is no longer supported on PHP 5.6 +[4.0.2]: https://github.com/sebastianbergmann/diff/compare/4.0.1...4.0.2 +[4.0.1]: https://github.com/sebastianbergmann/diff/compare/4.0.0...4.0.1 +[4.0.0]: https://github.com/sebastianbergmann/diff/compare/3.0.2...4.0.0 [3.0.2]: https://github.com/sebastianbergmann/diff/compare/3.0.1...3.0.2 [3.0.1]: https://github.com/sebastianbergmann/diff/compare/3.0.0...3.0.1 [3.0.0]: https://github.com/sebastianbergmann/diff/compare/2.0...3.0.0 diff --git a/LICENSE b/LICENSE index 3ad1d7c3..f22f31cf 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ sebastian/diff -Copyright (c) 2002-2019, Sebastian Bergmann . +Copyright (c) 2002-2020, Sebastian Bergmann . All rights reserved. Redistribution and use in source and binary forms, with or without diff --git a/Makefile b/Makefile index 2dbd71b4..7c156d39 100644 --- a/Makefile +++ b/Makefile @@ -1,9 +1,12 @@ .PHONY: it -it: coding-standards tests ## Runs the coding-standards and tests targets +it: coding-standards static-code-analysis tests ## Runs the coding-standards, static-code-analysis, and tests targets .PHONY: coding-standards -coding-standards: vendor ## Lints YAML files with yamllint +coding-standards: vendor ## Normalizes composer.json with ergebnis/composer-normalize, lints YAML files with yamllint and fixes code style issues with friendsofphp/php-cs-fixer + tools/composer-normalize yamllint -c .yamllint.yaml --strict . + mkdir -p .build/php-cs-fixer + tools/php-cs-fixer fix --config=.php_cs --diff --diff-format=udiff --verbose .PHONY: help help: ## Displays this list of targets with descriptions @@ -12,8 +15,15 @@ help: ## Displays this list of targets with descriptions .PHONY: tests tests: vendor ## Runs tests with phpunit/phpunit mkdir -p .build/phpunit + composer dump-autoload vendor/bin/phpunit --configuration=phpunit.xml +.PHONY: static-code-analysis +static-code-analysis: vendor ## Runs a static code analysis with vimeo/psalm + mkdir -p .build/psalm + composer dump-autoload + tools/psalm --config=psalm.xml --diff --diff-methods --show-info=false --stats --threads=4 + vendor: composer.json composer validate --strict composer install --no-interaction --no-progress --no-suggest diff --git a/README.md b/README.md index 194292c4..67921d16 100644 --- a/README.md +++ b/README.md @@ -4,6 +4,9 @@ [![Prune](https://github.com/localheinz/diff/workflows/Prune/badge.svg?branch=main)](https://github.com/localheinz/diff/actions) [![Release](https://github.com/localheinz/diff/workflows/Release/badge.svg?branch=main)](https://github.com/localheinz/diff/actions) +[![Code Coverage](https://codecov.io/gh/ergebnis/json-normalizer/branch/main/graph/badge.svg)](https://codecov.io/gh/ergebnis/json-normalizer) +[![Type Coverage](https://shepherd.dev/github/ergebnis/json-normalizer/coverage.svg)](https://shepherd.dev/github/ergebnis/json-normalizer) + [![Latest Stable Version](https://poser.pugx.org/localheinz/diff/v/stable)](https://packagist.org/packages/localheinz/diff) [![Total Downloads](https://poser.pugx.org/localheinz/diff/downloads)](https://packagist.org/packages/localheinz/diff) diff --git a/composer.json b/composer.json index 592e690c..ba2cc55c 100644 --- a/composer.json +++ b/composer.json @@ -1,8 +1,13 @@ { "name": "localheinz/diff", "description": "Fork of sebastian/diff for use with ergebnis/composer-normalize", - "keywords": ["diff", "udiff", "unidiff", "unified diff"], - "homepage": "https://github.com/sebastianbergmann/diff", + "keywords": [ + "diff", + "udiff", + "unidiff", + "unified diff" + ], + "homepage": "https://github.com/localheinz/diff", "license": "BSD-3-Clause", "authors": [ { @@ -15,11 +20,18 @@ } ], "require": { - "php": "^7.1" + "php": "^7.1 || ^8.0" }, "require-dev": { "phpunit/phpunit": "^7.5 || ^8.0", - "symfony/process": "^2 || ^3.3 || ^4" + "symfony/process": "^4.2 || ^5" + }, + "config": { + "optimize-autoloader": true, + "platform": { + "php": "7.1.33" + }, + "sort-packages": true }, "autoload": { "classmap": [ @@ -30,5 +42,6 @@ "classmap": [ "tests/" ] - } + }, + "prefer-stable": true } diff --git a/phive.xml b/phive.xml new file mode 100644 index 00000000..563fedfb --- /dev/null +++ b/phive.xml @@ -0,0 +1,7 @@ + + + + + + + diff --git a/psalm.xml b/psalm.xml new file mode 100644 index 00000000..047573a3 --- /dev/null +++ b/psalm.xml @@ -0,0 +1,55 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Chunk.php b/src/Chunk.php index 64e2c486..8cce2cd9 100644 --- a/src/Chunk.php +++ b/src/Chunk.php @@ -7,7 +7,6 @@ * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ - namespace Localheinz\Diff; final class Chunk diff --git a/src/Diff.php b/src/Diff.php index 0917574f..0eafa059 100644 --- a/src/Diff.php +++ b/src/Diff.php @@ -7,7 +7,6 @@ * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ - namespace Localheinz\Diff; final class Diff @@ -28,8 +27,6 @@ final class Diff private $chunks; /** - * @param string $from - * @param string $to * @param Chunk[] $chunks */ public function __construct(string $from, string $to, array $chunks = []) diff --git a/src/Differ.php b/src/Differ.php index 18c42f12..583d2da7 100644 --- a/src/Differ.php +++ b/src/Differ.php @@ -7,21 +7,42 @@ * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ - namespace Localheinz\Diff; +use const PHP_INT_SIZE; +use const PREG_SPLIT_DELIM_CAPTURE; +use const PREG_SPLIT_NO_EMPTY; +use function array_shift; +use function array_unshift; +use function array_values; +use function count; +use function current; +use function end; +use function get_class; +use function gettype; +use function is_array; +use function is_object; +use function is_string; +use function key; +use function min; +use function preg_split; +use function prev; +use function reset; +use function sprintf; +use function substr; use Localheinz\Diff\Output\DiffOutputBuilderInterface; use Localheinz\Diff\Output\UnifiedDiffOutputBuilder; -/** - * Diff implementation. - */ final class Differ { public const OLD = 0; + public const ADDED = 1; + public const REMOVED = 2; + public const DIFF_LINE_END_WARNING = 3; + public const NO_LINE_END_EOF_WARNING = 4; /** @@ -40,16 +61,16 @@ public function __construct($outputBuilder = null) $this->outputBuilder = $outputBuilder; } elseif (null === $outputBuilder) { $this->outputBuilder = new UnifiedDiffOutputBuilder; - } elseif (\is_string($outputBuilder)) { + } elseif (is_string($outputBuilder)) { // PHPUnit 6.1.4, 6.2.0, 6.2.1, 6.2.2, and 6.2.3 support // @see https://github.com/sebastianbergmann/phpunit/issues/2734#issuecomment-314514056 // @deprecated $this->outputBuilder = new UnifiedDiffOutputBuilder($outputBuilder); } else { throw new InvalidArgumentException( - \sprintf( + sprintf( 'Expected builder to be an instance of DiffOutputBuilderInterface, or a string, got %s.', - \is_object($outputBuilder) ? 'instance of "' . \get_class($outputBuilder) . '"' : \gettype($outputBuilder) . ' "' . $outputBuilder . '"' + is_object($outputBuilder) ? 'instance of "' . get_class($outputBuilder) . '"' : gettype($outputBuilder) . ' "' . $outputBuilder . '"' ) ); } @@ -58,11 +79,8 @@ public function __construct($outputBuilder = null) /** * Returns the diff between two arrays or strings as string. * - * @param array|string $from - * @param array|string $to - * @param null|LongestCommonSubsequenceCalculator $lcs - * - * @return string + * @param array|string $from + * @param array|string $to */ public function diff($from, $to, LongestCommonSubsequenceCalculator $lcs = null): string { @@ -89,20 +107,18 @@ public function diff($from, $to, LongestCommonSubsequenceCalculator $lcs = null) * @param array|string $from * @param array|string $to * @param LongestCommonSubsequenceCalculator $lcs - * - * @return array */ public function diffToArray($from, $to, LongestCommonSubsequenceCalculator $lcs = null): array { - if (\is_string($from)) { + if (is_string($from)) { $from = $this->splitStringByLines($from); - } elseif (!\is_array($from)) { + } elseif (!is_array($from)) { throw new InvalidArgumentException('"from" must be an array or string.'); } - if (\is_string($to)) { + if (is_string($to)) { $to = $this->splitStringByLines($to); - } elseif (!\is_array($to)) { + } elseif (!is_array($to)) { throw new InvalidArgumentException('"to" must be an array or string.'); } @@ -112,36 +128,36 @@ public function diffToArray($from, $to, LongestCommonSubsequenceCalculator $lcs $lcs = $this->selectLcsImplementation($from, $to); } - $common = $lcs->calculate(\array_values($from), \array_values($to)); + $common = $lcs->calculate(array_values($from), array_values($to)); $diff = []; foreach ($start as $token) { $diff[] = [$token, self::OLD]; } - \reset($from); - \reset($to); + reset($from); + reset($to); foreach ($common as $token) { - while (($fromToken = \reset($from)) !== $token) { - $diff[] = [\array_shift($from), self::REMOVED]; + while (($fromToken = reset($from)) !== $token) { + $diff[] = [array_shift($from), self::REMOVED]; } - while (($toToken = \reset($to)) !== $token) { - $diff[] = [\array_shift($to), self::ADDED]; + while (($toToken = reset($to)) !== $token) { + $diff[] = [array_shift($to), self::ADDED]; } $diff[] = [$token, self::OLD]; - \array_shift($from); - \array_shift($to); + array_shift($from); + array_shift($to); } - while (($token = \array_shift($from)) !== null) { + while (($token = array_shift($from)) !== null) { $diff[] = [$token, self::REMOVED]; } - while (($token = \array_shift($to)) !== null) { + while (($token = array_shift($to)) !== null) { $diff[] = [$token, self::ADDED]; } @@ -150,7 +166,7 @@ public function diffToArray($from, $to, LongestCommonSubsequenceCalculator $lcs } if ($this->detectUnmatchedLineEndings($diff)) { - \array_unshift($diff, ["#Warning: Strings contain different line endings!\n", self::DIFF_LINE_END_WARNING]); + array_unshift($diff, ["#Warning: Strings contain different line endings!\n", self::DIFF_LINE_END_WARNING]); } return $diff; @@ -159,13 +175,11 @@ public function diffToArray($from, $to, LongestCommonSubsequenceCalculator $lcs /** * Casts variable to string if it is not a string or array. * - * @param mixed $input - * * @return array|string */ private function normalizeDiffInput($input) { - if (!\is_array($input) && !\is_string($input)) { + if (!is_array($input) && !is_string($input)) { return (string) $input; } @@ -174,22 +188,12 @@ private function normalizeDiffInput($input) /** * Checks if input is string, if so it will split it line-by-line. - * - * @param string $input - * - * @return array */ private function splitStringByLines(string $input): array { - return \preg_split('/(.*\R)/', $input, -1, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY); + return preg_split('/(.*\R)/', $input, -1, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY); } - /** - * @param array $from - * @param array $to - * - * @return LongestCommonSubsequenceCalculator - */ private function selectLcsImplementation(array $from, array $to): LongestCommonSubsequenceCalculator { // We do not want to use the time-efficient implementation if its memory @@ -208,24 +212,17 @@ private function selectLcsImplementation(array $from, array $to): LongestCommonS /** * Calculates the estimated memory footprint for the DP-based method. * - * @param array $from - * @param array $to - * * @return float|int */ private function calculateEstimatedFootprint(array $from, array $to) { $itemSize = PHP_INT_SIZE === 4 ? 76 : 144; - return $itemSize * \min(\count($from), \count($to)) ** 2; + return $itemSize * min(count($from), count($to)) ** 2; } /** * Returns true if line ends don't match in a diff. - * - * @param array $diff - * - * @return bool */ private function detectUnmatchedLineEndings(array $diff): bool { @@ -267,11 +264,11 @@ private function detectUnmatchedLineEndings(array $diff): bool private function getLinebreak($line): string { - if (!\is_string($line)) { + if (!is_string($line)) { return ''; } - $lc = \substr($line, -1); + $lc = substr($line, -1); if ("\r" === $lc) { return "\r"; @@ -281,7 +278,7 @@ private function getLinebreak($line): string return ''; } - if ("\r\n" === \substr($line, -2)) { + if ("\r\n" === substr($line, -2)) { return "\r\n"; } @@ -293,10 +290,10 @@ private static function getArrayDiffParted(array &$from, array &$to): array $start = []; $end = []; - \reset($to); + reset($to); foreach ($from as $k => $v) { - $toK = \key($to); + $toK = key($to); if ($toK === $k && $v === $to[$k]) { $start[$k] = $v; @@ -307,19 +304,19 @@ private static function getArrayDiffParted(array &$from, array &$to): array } } - \end($from); - \end($to); + end($from); + end($to); do { - $fromK = \key($from); - $toK = \key($to); + $fromK = key($from); + $toK = key($to); - if (null === $fromK || null === $toK || \current($from) !== \current($to)) { + if (null === $fromK || null === $toK || current($from) !== current($to)) { break; } - \prev($from); - \prev($to); + prev($from); + prev($to); $end = [$fromK => $from[$fromK]] + $end; unset($from[$fromK], $to[$toK]); diff --git a/src/Exception/ConfigurationException.php b/src/Exception/ConfigurationException.php index 9497b941..ce7cacba 100644 --- a/src/Exception/ConfigurationException.php +++ b/src/Exception/ConfigurationException.php @@ -7,31 +7,29 @@ * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ - namespace Localheinz\Diff; +use function get_class; +use function gettype; +use function is_object; +use function sprintf; +use Exception; + final class ConfigurationException extends InvalidArgumentException { - /** - * @param string $option - * @param string $expected - * @param mixed $value - * @param int $code - * @param null|\Exception $previous - */ public function __construct( string $option, string $expected, $value, int $code = 0, - \Exception $previous = null + Exception $previous = null ) { parent::__construct( - \sprintf( + sprintf( 'Option "%s" must be %s, got "%s".', $option, $expected, - \is_object($value) ? \get_class($value) : (null === $value ? '' : \gettype($value) . '#' . $value) + is_object($value) ? get_class($value) : (null === $value ? '' : gettype($value) . '#' . $value) ), $code, $previous diff --git a/src/Exception/Exception.php b/src/Exception/Exception.php index 51ea1c9c..3f1c9ae7 100644 --- a/src/Exception/Exception.php +++ b/src/Exception/Exception.php @@ -7,7 +7,6 @@ * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ - namespace Localheinz\Diff; interface Exception diff --git a/src/Exception/InvalidArgumentException.php b/src/Exception/InvalidArgumentException.php index 90aa81b5..9cc78205 100644 --- a/src/Exception/InvalidArgumentException.php +++ b/src/Exception/InvalidArgumentException.php @@ -7,7 +7,6 @@ * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ - namespace Localheinz\Diff; class InvalidArgumentException extends \InvalidArgumentException implements Exception diff --git a/src/Line.php b/src/Line.php index 1918a476..66b12639 100644 --- a/src/Line.php +++ b/src/Line.php @@ -7,13 +7,14 @@ * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ - namespace Localheinz\Diff; final class Line { public const ADDED = 1; + public const REMOVED = 2; + public const UNCHANGED = 3; /** diff --git a/src/LongestCommonSubsequenceCalculator.php b/src/LongestCommonSubsequenceCalculator.php index f9732bc9..85bf7041 100644 --- a/src/LongestCommonSubsequenceCalculator.php +++ b/src/LongestCommonSubsequenceCalculator.php @@ -7,18 +7,12 @@ * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ - namespace Localheinz\Diff; interface LongestCommonSubsequenceCalculator { /** * Calculates the longest common subsequence of two arrays. - * - * @param array $from - * @param array $to - * - * @return array */ public function calculate(array $from, array $to): array; } diff --git a/src/MemoryEfficientLongestCommonSubsequenceCalculator.php b/src/MemoryEfficientLongestCommonSubsequenceCalculator.php index 30b1fcfc..673815f2 100644 --- a/src/MemoryEfficientLongestCommonSubsequenceCalculator.php +++ b/src/MemoryEfficientLongestCommonSubsequenceCalculator.php @@ -7,9 +7,16 @@ * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ - namespace Localheinz\Diff; +use function array_fill; +use function array_merge; +use function array_reverse; +use function array_slice; +use function count; +use function in_array; +use function max; + final class MemoryEfficientLongestCommonSubsequenceCalculator implements LongestCommonSubsequenceCalculator { /** @@ -17,15 +24,15 @@ final class MemoryEfficientLongestCommonSubsequenceCalculator implements Longest */ public function calculate(array $from, array $to): array { - $cFrom = \count($from); - $cTo = \count($to); + $cFrom = count($from); + $cTo = count($to); if ($cFrom === 0) { return []; } if ($cFrom === 1) { - if (\in_array($from[0], $to, true)) { + if (in_array($from[0], $to, true)) { return [$from[0]]; } @@ -33,10 +40,10 @@ public function calculate(array $from, array $to): array } $i = (int) ($cFrom / 2); - $fromStart = \array_slice($from, 0, $i); - $fromEnd = \array_slice($from, $i); + $fromStart = array_slice($from, 0, $i); + $fromEnd = array_slice($from, $i); $llB = $this->length($fromStart, $to); - $llE = $this->length(\array_reverse($fromEnd), \array_reverse($to)); + $llE = $this->length(array_reverse($fromEnd), array_reverse($to)); $jMax = 0; $max = 0; @@ -49,10 +56,10 @@ public function calculate(array $from, array $to): array } } - $toStart = \array_slice($to, 0, $jMax); - $toEnd = \array_slice($to, $jMax); + $toStart = array_slice($to, 0, $jMax); + $toEnd = array_slice($to, $jMax); - return \array_merge( + return array_merge( $this->calculate($fromStart, $toStart), $this->calculate($fromEnd, $toEnd) ); @@ -60,9 +67,9 @@ public function calculate(array $from, array $to): array private function length(array $from, array $to): array { - $current = \array_fill(0, \count($to) + 1, 0); - $cFrom = \count($from); - $cTo = \count($to); + $current = array_fill(0, count($to) + 1, 0); + $cFrom = count($from); + $cTo = count($to); for ($i = 0; $i < $cFrom; $i++) { $prev = $current; @@ -71,7 +78,7 @@ private function length(array $from, array $to): array if ($from[$i] === $to[$j]) { $current[$j + 1] = $prev[$j] + 1; } else { - $current[$j + 1] = \max($current[$j], $prev[$j + 1]); + $current[$j + 1] = max($current[$j], $prev[$j + 1]); } } } diff --git a/src/Output/AbstractChunkOutputBuilder.php b/src/Output/AbstractChunkOutputBuilder.php index 7b9188ed..1ca27e27 100644 --- a/src/Output/AbstractChunkOutputBuilder.php +++ b/src/Output/AbstractChunkOutputBuilder.php @@ -7,23 +7,19 @@ * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ - namespace Localheinz\Diff\Output; +use function count; + abstract class AbstractChunkOutputBuilder implements DiffOutputBuilderInterface { /** * Takes input of the diff array and returns the common parts. * Iterates through diff line by line. - * - * @param array $diff - * @param int $lineThreshold - * - * @return array */ protected function getCommonChunks(array $diff, int $lineThreshold = 5): array { - $diffSize = \count($diff); + $diffSize = count($diff); $capturing = false; $chunkStart = 0; $chunkSize = 0; diff --git a/src/Output/DiffOnlyOutputBuilder.php b/src/Output/DiffOnlyOutputBuilder.php index cf42be92..19af5242 100644 --- a/src/Output/DiffOnlyOutputBuilder.php +++ b/src/Output/DiffOnlyOutputBuilder.php @@ -7,9 +7,13 @@ * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ - namespace Localheinz\Diff\Output; +use function fclose; +use function fopen; +use function fwrite; +use function stream_get_contents; +use function substr; use Localheinz\Diff\Differ; /** @@ -30,38 +34,38 @@ public function __construct(string $header = "--- Original\n+++ New\n") public function getDiff(array $diff): string { - $buffer = \fopen('php://memory', 'r+b'); + $buffer = fopen('php://memory', 'r+b'); if ('' !== $this->header) { - \fwrite($buffer, $this->header); + fwrite($buffer, $this->header); - if ("\n" !== \substr($this->header, -1, 1)) { - \fwrite($buffer, "\n"); + if ("\n" !== substr($this->header, -1, 1)) { + fwrite($buffer, "\n"); } } foreach ($diff as $diffEntry) { if ($diffEntry[1] === Differ::ADDED) { - \fwrite($buffer, '+' . $diffEntry[0]); + fwrite($buffer, '+' . $diffEntry[0]); } elseif ($diffEntry[1] === Differ::REMOVED) { - \fwrite($buffer, '-' . $diffEntry[0]); + fwrite($buffer, '-' . $diffEntry[0]); } elseif ($diffEntry[1] === Differ::DIFF_LINE_END_WARNING) { - \fwrite($buffer, ' ' . $diffEntry[0]); + fwrite($buffer, ' ' . $diffEntry[0]); continue; // Warnings should not be tested for line break, it will always be there } else { /* Not changed (old) 0 */ continue; // we didn't write the non changs line, so do not add a line break either } - $lc = \substr($diffEntry[0], -1); + $lc = substr($diffEntry[0], -1); if ($lc !== "\n" && $lc !== "\r") { - \fwrite($buffer, "\n"); // \No newline at end of file + fwrite($buffer, "\n"); // \No newline at end of file } } - $diff = \stream_get_contents($buffer, -1, 0); - \fclose($buffer); + $diff = stream_get_contents($buffer, -1, 0); + fclose($buffer); return $diff; } diff --git a/src/Output/DiffOutputBuilderInterface.php b/src/Output/DiffOutputBuilderInterface.php index dfba8714..d8cc9c4e 100644 --- a/src/Output/DiffOutputBuilderInterface.php +++ b/src/Output/DiffOutputBuilderInterface.php @@ -7,7 +7,6 @@ * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ - namespace Localheinz\Diff\Output; /** diff --git a/src/Output/StrictUnifiedDiffOutputBuilder.php b/src/Output/StrictUnifiedDiffOutputBuilder.php index e14e1b0f..433f1b41 100644 --- a/src/Output/StrictUnifiedDiffOutputBuilder.php +++ b/src/Output/StrictUnifiedDiffOutputBuilder.php @@ -7,9 +7,22 @@ * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ - namespace Localheinz\Diff\Output; +use function array_merge; +use function array_splice; +use function count; +use function fclose; +use function fopen; +use function fwrite; +use function is_bool; +use function is_int; +use function is_string; +use function max; +use function min; +use function sprintf; +use function stream_get_contents; +use function substr; use Localheinz\Diff\ConfigurationException; use Localheinz\Diff\Differ; @@ -29,6 +42,7 @@ final class StrictUnifiedDiffOutputBuilder implements DiffOutputBuilderInterface 'toFile' => null, 'toFileDate' => null, ]; + /** * @var bool */ @@ -56,33 +70,26 @@ final class StrictUnifiedDiffOutputBuilder implements DiffOutputBuilderInterface public function __construct(array $options = []) { - $options = \array_merge(self::$default, $options); + $options = array_merge(self::$default, $options); - if (!\is_bool($options['collapseRanges'])) { + if (!is_bool($options['collapseRanges'])) { throw new ConfigurationException('collapseRanges', 'a bool', $options['collapseRanges']); } - if (!\is_int($options['contextLines']) || $options['contextLines'] < 0) { + if (!is_int($options['contextLines']) || $options['contextLines'] < 0) { throw new ConfigurationException('contextLines', 'an int >= 0', $options['contextLines']); } - if (!\is_int($options['commonLineThreshold']) || $options['commonLineThreshold'] <= 0) { + if (!is_int($options['commonLineThreshold']) || $options['commonLineThreshold'] <= 0) { throw new ConfigurationException('commonLineThreshold', 'an int > 0', $options['commonLineThreshold']); } - foreach (['fromFile', 'toFile'] as $option) { - if (!\is_string($options[$option])) { - throw new ConfigurationException($option, 'a string', $options[$option]); - } - } - - foreach (['fromFileDate', 'toFileDate'] as $option) { - if (null !== $options[$option] && !\is_string($options[$option])) { - throw new ConfigurationException($option, 'a string or ', $options[$option]); - } - } + $this->assertString($options, 'fromFile'); + $this->assertString($options, 'toFile'); + $this->assertStringOrNull($options, 'fromFileDate'); + $this->assertStringOrNull($options, 'toFileDate'); - $this->header = \sprintf( + $this->header = sprintf( "--- %s%s\n+++ %s%s\n", $options['fromFile'], null === $options['fromFileDate'] ? '' : "\t" . $options['fromFileDate'], @@ -97,48 +104,47 @@ public function __construct(array $options = []) public function getDiff(array $diff): string { - if (0 === \count($diff)) { + if (0 === count($diff)) { return ''; } $this->changed = false; - $buffer = \fopen('php://memory', 'r+b'); - \fwrite($buffer, $this->header); + $buffer = fopen('php://memory', 'r+b'); + fwrite($buffer, $this->header); $this->writeDiffHunks($buffer, $diff); if (!$this->changed) { - \fclose($buffer); + fclose($buffer); return ''; } - $diff = \stream_get_contents($buffer, -1, 0); + $diff = stream_get_contents($buffer, -1, 0); - \fclose($buffer); + fclose($buffer); // If the last char is not a linebreak: add it. // This might happen when both the `from` and `to` do not have a trailing linebreak - $last = \substr($diff, -1); + $last = substr($diff, -1); return "\n" !== $last && "\r" !== $last ? $diff . "\n" - : $diff - ; + : $diff; } private function writeDiffHunks($output, array $diff): void { // detect "No newline at end of file" and insert into `$diff` if needed - $upperLimit = \count($diff); + $upperLimit = count($diff); if (0 === $diff[$upperLimit - 1][1]) { - $lc = \substr($diff[$upperLimit - 1][0], -1); + $lc = substr($diff[$upperLimit - 1][0], -1); if ("\n" !== $lc) { - \array_splice($diff, $upperLimit, 0, [["\n\\ No newline at end of file\n", Differ::NO_LINE_END_EOF_WARNING]]); + array_splice($diff, $upperLimit, 0, [["\n\\ No newline at end of file\n", Differ::NO_LINE_END_EOF_WARNING]]); } } else { // search back for the last `+` and `-` line, @@ -148,13 +154,13 @@ private function writeDiffHunks($output, array $diff): void for ($i = $upperLimit - 1; $i >= 0; --$i) { if (isset($toFind[$diff[$i][1]])) { unset($toFind[$diff[$i][1]]); - $lc = \substr($diff[$i][0], -1); + $lc = substr($diff[$i][0], -1); if ("\n" !== $lc) { - \array_splice($diff, $i + 1, 0, [["\n\\ No newline at end of file\n", Differ::NO_LINE_END_EOF_WARNING]]); + array_splice($diff, $i + 1, 0, [["\n\\ No newline at end of file\n", Differ::NO_LINE_END_EOF_WARNING]]); } - if (!\count($toFind)) { + if (!count($toFind)) { break; } } @@ -163,11 +169,13 @@ private function writeDiffHunks($output, array $diff): void // write hunks to output buffer - $cutOff = \max($this->commonLineThreshold, $this->contextLines); + $cutOff = max($this->commonLineThreshold, $this->contextLines); $hunkCapture = false; $sameCount = $toRange = $fromRange = 0; $toStart = $fromStart = 1; + $i = 0; + /** @var int $i */ foreach ($diff as $i => $entry) { if (0 === $entry[1]) { // same if (false === $hunkCapture) { @@ -184,8 +192,7 @@ private function writeDiffHunks($output, array $diff): void if ($sameCount === $cutOff) { $contextStartOffset = ($hunkCapture - $this->contextLines) < 0 ? $hunkCapture - : $this->contextLines - ; + : $this->contextLines; // note: $contextEndOffset = $this->contextLines; // @@ -249,12 +256,11 @@ private function writeDiffHunks($output, array $diff): void $contextStartOffset = $hunkCapture - $this->contextLines < 0 ? $hunkCapture - : $this->contextLines - ; + : $this->contextLines; // prevent trying to write out more common lines than there are in the diff _and_ // do not write more than configured through the context lines - $contextEndOffset = \min($sameCount, $this->contextLines); + $contextEndOffset = min($sameCount, $this->contextLines); $fromRange -= $sameCount; $toRange -= $sameCount; @@ -281,32 +287,32 @@ private function writeHunk( int $toRange, $output ): void { - \fwrite($output, '@@ -' . $fromStart); + fwrite($output, '@@ -' . $fromStart); if (!$this->collapseRanges || 1 !== $fromRange) { - \fwrite($output, ',' . $fromRange); + fwrite($output, ',' . $fromRange); } - \fwrite($output, ' +' . $toStart); + fwrite($output, ' +' . $toStart); if (!$this->collapseRanges || 1 !== $toRange) { - \fwrite($output, ',' . $toRange); + fwrite($output, ',' . $toRange); } - \fwrite($output, " @@\n"); + fwrite($output, " @@\n"); for ($i = $diffStartIndex; $i < $diffEndIndex; ++$i) { if ($diff[$i][1] === Differ::ADDED) { $this->changed = true; - \fwrite($output, '+' . $diff[$i][0]); + fwrite($output, '+' . $diff[$i][0]); } elseif ($diff[$i][1] === Differ::REMOVED) { $this->changed = true; - \fwrite($output, '-' . $diff[$i][0]); + fwrite($output, '-' . $diff[$i][0]); } elseif ($diff[$i][1] === Differ::OLD) { - \fwrite($output, ' ' . $diff[$i][0]); + fwrite($output, ' ' . $diff[$i][0]); } elseif ($diff[$i][1] === Differ::NO_LINE_END_EOF_WARNING) { $this->changed = true; - \fwrite($output, $diff[$i][0]); + fwrite($output, $diff[$i][0]); } //} elseif ($diff[$i][1] === Differ::DIFF_LINE_END_WARNING) { // custom comment inserted by PHPUnit/diff package // skip @@ -315,4 +321,18 @@ private function writeHunk( //} } } + + private function assertString(array $options, string $option): void + { + if (!is_string($options[$option])) { + throw new ConfigurationException($option, 'a string', $options[$option]); + } + } + + private function assertStringOrNull(array $options, string $option): void + { + if (null !== $options[$option] && !is_string($options[$option])) { + throw new ConfigurationException($option, 'a string or ', $options[$option]); + } + } } diff --git a/src/Output/UnifiedDiffOutputBuilder.php b/src/Output/UnifiedDiffOutputBuilder.php index 7b609f3e..050fc251 100644 --- a/src/Output/UnifiedDiffOutputBuilder.php +++ b/src/Output/UnifiedDiffOutputBuilder.php @@ -7,9 +7,18 @@ * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ - namespace Localheinz\Diff\Output; +use function array_splice; +use function count; +use function fclose; +use function fopen; +use function fwrite; +use function max; +use function min; +use function stream_get_contents; +use function strlen; +use function substr; use Localheinz\Diff\Differ; /** @@ -50,45 +59,44 @@ public function __construct(string $header = "--- Original\n+++ New\n", bool $ad public function getDiff(array $diff): string { - $buffer = \fopen('php://memory', 'r+b'); + $buffer = fopen('php://memory', 'r+b'); if ('' !== $this->header) { - \fwrite($buffer, $this->header); + fwrite($buffer, $this->header); - if ("\n" !== \substr($this->header, -1, 1)) { - \fwrite($buffer, "\n"); + if ("\n" !== substr($this->header, -1, 1)) { + fwrite($buffer, "\n"); } } - if (0 !== \count($diff)) { + if (0 !== count($diff)) { $this->writeDiffHunks($buffer, $diff); } - $diff = \stream_get_contents($buffer, -1, 0); + $diff = stream_get_contents($buffer, -1, 0); - \fclose($buffer); + fclose($buffer); - // If the last char is not a linebreak: add it. + // If the diff is non-empty and last char is not a linebreak: add it. // This might happen when both the `from` and `to` do not have a trailing linebreak - $last = \substr($diff, -1); + $last = substr($diff, -1); - return "\n" !== $last && "\r" !== $last + return 0 !== strlen($diff) && "\n" !== $last && "\r" !== $last ? $diff . "\n" - : $diff - ; + : $diff; } private function writeDiffHunks($output, array $diff): void { // detect "No newline at end of file" and insert into `$diff` if needed - $upperLimit = \count($diff); + $upperLimit = count($diff); if (0 === $diff[$upperLimit - 1][1]) { - $lc = \substr($diff[$upperLimit - 1][0], -1); + $lc = substr($diff[$upperLimit - 1][0], -1); if ("\n" !== $lc) { - \array_splice($diff, $upperLimit, 0, [["\n\\ No newline at end of file\n", Differ::NO_LINE_END_EOF_WARNING]]); + array_splice($diff, $upperLimit, 0, [["\n\\ No newline at end of file\n", Differ::NO_LINE_END_EOF_WARNING]]); } } else { // search back for the last `+` and `-` line, @@ -98,13 +106,13 @@ private function writeDiffHunks($output, array $diff): void for ($i = $upperLimit - 1; $i >= 0; --$i) { if (isset($toFind[$diff[$i][1]])) { unset($toFind[$diff[$i][1]]); - $lc = \substr($diff[$i][0], -1); + $lc = substr($diff[$i][0], -1); if ("\n" !== $lc) { - \array_splice($diff, $i + 1, 0, [["\n\\ No newline at end of file\n", Differ::NO_LINE_END_EOF_WARNING]]); + array_splice($diff, $i + 1, 0, [["\n\\ No newline at end of file\n", Differ::NO_LINE_END_EOF_WARNING]]); } - if (!\count($toFind)) { + if (!count($toFind)) { break; } } @@ -113,11 +121,13 @@ private function writeDiffHunks($output, array $diff): void // write hunks to output buffer - $cutOff = \max($this->commonLineThreshold, $this->contextLines); + $cutOff = max($this->commonLineThreshold, $this->contextLines); $hunkCapture = false; $sameCount = $toRange = $fromRange = 0; $toStart = $fromStart = 1; + $i = 0; + /** @var int $i */ foreach ($diff as $i => $entry) { if (0 === $entry[1]) { // same if (false === $hunkCapture) { @@ -134,8 +144,7 @@ private function writeDiffHunks($output, array $diff): void if ($sameCount === $cutOff) { $contextStartOffset = ($hunkCapture - $this->contextLines) < 0 ? $hunkCapture - : $this->contextLines - ; + : $this->contextLines; // note: $contextEndOffset = $this->contextLines; // @@ -197,12 +206,11 @@ private function writeDiffHunks($output, array $diff): void $contextStartOffset = $hunkCapture - $this->contextLines < 0 ? $hunkCapture - : $this->contextLines - ; + : $this->contextLines; // prevent trying to write out more common lines than there are in the diff _and_ // do not write more than configured through the context lines - $contextEndOffset = \min($sameCount, $this->contextLines); + $contextEndOffset = min($sameCount, $this->contextLines); $fromRange -= $sameCount; $toRange -= $sameCount; @@ -230,34 +238,34 @@ private function writeHunk( $output ): void { if ($this->addLineNumbers) { - \fwrite($output, '@@ -' . $fromStart); + fwrite($output, '@@ -' . $fromStart); if (!$this->collapseRanges || 1 !== $fromRange) { - \fwrite($output, ',' . $fromRange); + fwrite($output, ',' . $fromRange); } - \fwrite($output, ' +' . $toStart); + fwrite($output, ' +' . $toStart); if (!$this->collapseRanges || 1 !== $toRange) { - \fwrite($output, ',' . $toRange); + fwrite($output, ',' . $toRange); } - \fwrite($output, " @@\n"); + fwrite($output, " @@\n"); } else { - \fwrite($output, "@@ @@\n"); + fwrite($output, "@@ @@\n"); } for ($i = $diffStartIndex; $i < $diffEndIndex; ++$i) { if ($diff[$i][1] === Differ::ADDED) { - \fwrite($output, '+' . $diff[$i][0]); + fwrite($output, '+' . $diff[$i][0]); } elseif ($diff[$i][1] === Differ::REMOVED) { - \fwrite($output, '-' . $diff[$i][0]); + fwrite($output, '-' . $diff[$i][0]); } elseif ($diff[$i][1] === Differ::OLD) { - \fwrite($output, ' ' . $diff[$i][0]); + fwrite($output, ' ' . $diff[$i][0]); } elseif ($diff[$i][1] === Differ::NO_LINE_END_EOF_WARNING) { - \fwrite($output, "\n"); // $diff[$i][0] + fwrite($output, "\n"); // $diff[$i][0] } else { /* Not changed (old) Differ::OLD or Warning Differ::DIFF_LINE_END_WARNING */ - \fwrite($output, ' ' . $diff[$i][0]); + fwrite($output, ' ' . $diff[$i][0]); } } } diff --git a/src/Parser.php b/src/Parser.php index 3a2bb3db..9974ec36 100644 --- a/src/Parser.php +++ b/src/Parser.php @@ -7,35 +7,38 @@ * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ - namespace Localheinz\Diff; +use function array_pop; +use function count; +use function max; +use function preg_match; +use function preg_split; + /** * Unified diff parser. */ final class Parser { /** - * @param string $string - * * @return Diff[] */ public function parse(string $string): array { - $lines = \preg_split('(\r\n|\r|\n)', $string); + $lines = preg_split('(\r\n|\r|\n)', $string); - if (!empty($lines) && $lines[\count($lines) - 1] === '') { - \array_pop($lines); + if (!empty($lines) && $lines[count($lines) - 1] === '') { + array_pop($lines); } - $lineCount = \count($lines); + $lineCount = count($lines); $diffs = []; $diff = null; $collected = []; for ($i = 0; $i < $lineCount; ++$i) { - if (\preg_match('(^---\\s+(?P\\S+))', $lines[$i], $fromMatch) && - \preg_match('(^\\+\\+\\+\\s+(?P\\S+))', $lines[$i + 1], $toMatch)) { + if (preg_match('(^---\\s+(?P\\S+))', $lines[$i], $fromMatch) && + preg_match('(^\\+\\+\\+\\s+(?P\\S+))', $lines[$i + 1], $toMatch)) { if ($diff !== null) { $this->parseFileDiff($diff, $collected); @@ -47,7 +50,7 @@ public function parse(string $string): array ++$i; } else { - if (\preg_match('/^(?:diff --git |index [\da-f\.]+|[+-]{3} [ab])/', $lines[$i])) { + if (preg_match('/^(?:diff --git |index [\da-f\.]+|[+-]{3} [ab])/', $lines[$i])) { continue; } @@ -55,7 +58,7 @@ public function parse(string $string): array } } - if ($diff !== null && \count($collected)) { + if ($diff !== null && count($collected)) { $this->parseFileDiff($diff, $collected); $diffs[] = $diff; @@ -66,16 +69,17 @@ public function parse(string $string): array private function parseFileDiff(Diff $diff, array $lines): void { - $chunks = []; - $chunk = null; + $chunks = []; + $chunk = null; + $diffLines = []; foreach ($lines as $line) { - if (\preg_match('/^@@\s+-(?P\d+)(?:,\s*(?P\d+))?\s+\+(?P\d+)(?:,\s*(?P\d+))?\s+@@/', $line, $match)) { + if (preg_match('/^@@\s+-(?P\d+)(?:,\s*(?P\d+))?\s+\+(?P\d+)(?:,\s*(?P\d+))?\s+@@/', $line, $match)) { $chunk = new Chunk( (int) $match['start'], - isset($match['startrange']) ? \max(1, (int) $match['startrange']) : 1, + isset($match['startrange']) ? max(1, (int) $match['startrange']) : 1, (int) $match['end'], - isset($match['endrange']) ? \max(1, (int) $match['endrange']) : 1 + isset($match['endrange']) ? max(1, (int) $match['endrange']) : 1 ); $chunks[] = $chunk; @@ -84,7 +88,7 @@ private function parseFileDiff(Diff $diff, array $lines): void continue; } - if (\preg_match('/^(?P[+ -])?(?P.*)/', $line, $match)) { + if (preg_match('/^(?P[+ -])?(?P.*)/', $line, $match)) { $type = Line::UNCHANGED; if ($match['type'] === '+') { diff --git a/src/TimeEfficientLongestCommonSubsequenceCalculator.php b/src/TimeEfficientLongestCommonSubsequenceCalculator.php index f740566c..6acd2769 100644 --- a/src/TimeEfficientLongestCommonSubsequenceCalculator.php +++ b/src/TimeEfficientLongestCommonSubsequenceCalculator.php @@ -7,9 +7,13 @@ * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ - namespace Localheinz\Diff; +use function array_reverse; +use function count; +use function max; +use SplFixedArray; + final class TimeEfficientLongestCommonSubsequenceCalculator implements LongestCommonSubsequenceCalculator { /** @@ -18,10 +22,10 @@ final class TimeEfficientLongestCommonSubsequenceCalculator implements LongestCo public function calculate(array $from, array $to): array { $common = []; - $fromLength = \count($from); - $toLength = \count($to); + $fromLength = count($from); + $toLength = count($to); $width = $fromLength + 1; - $matrix = new \SplFixedArray($width * ($toLength + 1)); + $matrix = new SplFixedArray($width * ($toLength + 1)); for ($i = 0; $i <= $fromLength; ++$i) { $matrix[$i] = 0; @@ -34,7 +38,7 @@ public function calculate(array $from, array $to): array for ($i = 1; $i <= $fromLength; ++$i) { for ($j = 1; $j <= $toLength; ++$j) { $o = ($j * $width) + $i; - $matrix[$o] = \max( + $matrix[$o] = max( $matrix[$o - 1], $matrix[$o - $width], $from[$i - 1] === $to[$j - 1] ? $matrix[$o - $width - 1] + 1 : 0 @@ -61,6 +65,6 @@ public function calculate(array $from, array $to): array } } - return \array_reverse($common); + return array_reverse($common); } } diff --git a/tests/ChunkTest.php b/tests/ChunkTest.php index f61f2e3f..18385cb3 100644 --- a/tests/ChunkTest.php +++ b/tests/ChunkTest.php @@ -7,15 +7,14 @@ * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ - namespace Localheinz\Diff; use PHPUnit\Framework\TestCase; /** - * @covers Localheinz\Diff\Chunk + * @covers \Localheinz\Diff\Chunk * - * @uses Localheinz\Diff\Line + * @uses \Localheinz\Diff\Line */ final class ChunkTest extends TestCase { diff --git a/tests/DiffTest.php b/tests/DiffTest.php index 4c0dfece..f85fe66d 100644 --- a/tests/DiffTest.php +++ b/tests/DiffTest.php @@ -7,15 +7,14 @@ * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ - namespace Localheinz\Diff; use PHPUnit\Framework\TestCase; /** - * @covers Localheinz\Diff\Diff + * @covers \Localheinz\Diff\Diff * - * @uses Localheinz\Diff\Chunk + * @uses \Localheinz\Diff\Chunk */ final class DiffTest extends TestCase { diff --git a/tests/DifferTest.php b/tests/DifferTest.php index c714dfe4..05ab9405 100644 --- a/tests/DifferTest.php +++ b/tests/DifferTest.php @@ -7,19 +7,20 @@ * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ - namespace Localheinz\Diff; use PHPUnit\Framework\TestCase; -use Localheinz\Diff\Output\UnifiedDiffOutputBuilder; +use ReflectionObject; +use SplFileInfo; +use stdClass; /** - * @covers Localheinz\Diff\Differ - * @covers Localheinz\Diff\Output\UnifiedDiffOutputBuilder + * @covers \Localheinz\Diff\Differ + * @covers \Localheinz\Diff\Output\UnifiedDiffOutputBuilder * - * @uses Localheinz\Diff\MemoryEfficientLongestCommonSubsequenceCalculator - * @uses Localheinz\Diff\TimeEfficientLongestCommonSubsequenceCalculator - * @uses Localheinz\Diff\Output\AbstractChunkOutputBuilder + * @uses \Localheinz\Diff\MemoryEfficientLongestCommonSubsequenceCalculator + * @uses \Localheinz\Diff\TimeEfficientLongestCommonSubsequenceCalculator + * @uses \Localheinz\Diff\Output\AbstractChunkOutputBuilder */ final class DifferTest extends TestCase { @@ -34,7 +35,6 @@ protected function setUp(): void } /** - * @param array $expected * @param array|string $from * @param array|string $to * @@ -46,10 +46,6 @@ public function testArrayRepresentationOfDiffCanBeRenderedUsingTimeEfficientLcsI } /** - * @param string $expected - * @param string $from - * @param string $to - * * @dataProvider textProvider */ public function testTextRepresentationOfDiffCanBeRenderedUsingTimeEfficientLcsImplementation(string $expected, string $from, string $to): void @@ -58,7 +54,6 @@ public function testTextRepresentationOfDiffCanBeRenderedUsingTimeEfficientLcsIm } /** - * @param array $expected * @param array|string $from * @param array|string $to * @@ -70,10 +65,6 @@ public function testArrayRepresentationOfDiffCanBeRenderedUsingMemoryEfficientLc } /** - * @param string $expected - * @param string $from - * @param string $to - * * @dataProvider textProvider */ public function testTextRepresentationOfDiffCanBeRenderedUsingMemoryEfficientLcsImplementation(string $expected, string $from, string $to): void @@ -296,7 +287,7 @@ public function textProvider(): array k EOF - , + , "a\nb\nc\nd\ne\nf\ng\nh\ni\nj\nk\n", "a\np\nc\nd\ne\nf\ng\nh\ni\nw\nk\n", ], @@ -312,7 +303,7 @@ public function textProvider(): array 3 EOF - , + , "A\n1\n2\n3\n4\n5\n6\n1\n1\n1\n1\n1\n1\n1\n1\n1\n1\n1\n1\n1\n1\n1\n", "B\n1\n2\n3\n4\n5\n6\n1\n1\n1\n1\n1\n1\n1\n1\n1\n1\n1\n1\n1\n1\n1\n", ], @@ -342,18 +333,15 @@ public function testDiffInvalidToType(): void $this->expectException(InvalidArgumentException::class); $this->expectExceptionMessageRegExp('#^"to" must be an array or string\.$#'); - $this->differ->diffToArray('', new \stdClass); + $this->differ->diffToArray('', new stdClass); } /** - * @param array $expected - * @param string $input - * * @dataProvider provideSplitStringByLinesCases */ public function testSplitStringByLines(array $expected, string $input): void { - $reflection = new \ReflectionObject($this->differ); + $reflection = new ReflectionObject($this->differ); $method = $reflection->getMethod('splitStringByLines'); $method->setAccessible(true); @@ -439,6 +427,6 @@ public function testConstructorInvalidArgObject(): void $this->expectException(InvalidArgumentException::class); $this->expectExceptionMessageRegExp('/^Expected builder to be an instance of DiffOutputBuilderInterface, or a string, got instance of "SplFileInfo"\.$/'); - new Differ(new \SplFileInfo(__FILE__)); + new Differ(new SplFileInfo(__FILE__)); } } diff --git a/tests/Exception/ConfigurationExceptionTest.php b/tests/Exception/ConfigurationExceptionTest.php index e7fa1f41..ce4f3eaf 100644 --- a/tests/Exception/ConfigurationExceptionTest.php +++ b/tests/Exception/ConfigurationExceptionTest.php @@ -7,13 +7,14 @@ * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ - namespace Localheinz\Diff; +use BadMethodCallException; use PHPUnit\Framework\TestCase; +use SplFileInfo; /** - * @covers Localheinz\Diff\ConfigurationException + * @covers \Localheinz\Diff\ConfigurationException */ final class ConfigurationExceptionTest extends TestCase { @@ -31,9 +32,9 @@ public function testConstruct(): void $e = new ConfigurationException( 'test', 'integer', - new \SplFileInfo(__FILE__), + new SplFileInfo(__FILE__), 789, - new \BadMethodCallException(__METHOD__) + new BadMethodCallException(__METHOD__) ); $this->assertSame('Option "test" must be integer, got "SplFileInfo".', $e->getMessage()); diff --git a/tests/Exception/InvalidArgumentExceptionTest.php b/tests/Exception/InvalidArgumentExceptionTest.php index 4a7a85a4..e1bf7087 100644 --- a/tests/Exception/InvalidArgumentExceptionTest.php +++ b/tests/Exception/InvalidArgumentExceptionTest.php @@ -7,19 +7,19 @@ * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ - namespace Localheinz\Diff; +use LogicException; use PHPUnit\Framework\TestCase; /** - * @covers Localheinz\Diff\InvalidArgumentException + * @covers \Localheinz\Diff\InvalidArgumentException */ final class InvalidArgumentExceptionTest extends TestCase { public function testInvalidArgumentException(): void { - $previousException = new \LogicException(); + $previousException = new LogicException(); $message = 'test'; $code = 123; diff --git a/tests/LineTest.php b/tests/LineTest.php index 88b2661d..9c7ca255 100644 --- a/tests/LineTest.php +++ b/tests/LineTest.php @@ -7,13 +7,12 @@ * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ - namespace Localheinz\Diff; use PHPUnit\Framework\TestCase; /** - * @covers Localheinz\Diff\Line + * @covers \Localheinz\Diff\Line */ final class LineTest extends TestCase { diff --git a/tests/LongestCommonSubsequenceTest.php b/tests/LongestCommonSubsequenceTest.php index deea9a35..db5923c4 100644 --- a/tests/LongestCommonSubsequenceTest.php +++ b/tests/LongestCommonSubsequenceTest.php @@ -7,9 +7,13 @@ * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ - namespace Localheinz\Diff; +use function array_reverse; +use function array_slice; +use function ini_get; +use function ini_set; +use function range; use PHPUnit\Framework\TestCase; /** @@ -34,15 +38,15 @@ abstract class LongestCommonSubsequenceTest extends TestCase protected function setUp(): void { - $this->memoryLimit = \ini_get('memory_limit'); - \ini_set('memory_limit', '-1'); + $this->memoryLimit = ini_get('memory_limit'); + ini_set('memory_limit', '-1'); $this->implementation = $this->createImplementation(); } protected function tearDown(): void { - \ini_set('memory_limit', $this->memoryLimit); + ini_set('memory_limit', $this->memoryLimit); } public function testBothEmpty(): void @@ -83,7 +87,7 @@ public function testIsStrictComparison(): void public function testEqualSequences(): void { foreach ($this->stress_sizes as $size) { - $range = \range(1, $size); + $range = range(1, $size); $from = $range; $to = $range; $common = $this->implementation->calculate($from, $to); @@ -105,8 +109,8 @@ public function testDistinctSequences(): void $this->assertSame([], $common); foreach ($this->stress_sizes as $size) { - $from = \range(1, $size); - $to = \range($size + 1, $size * 2); + $from = range(1, $size); + $to = range($size + 1, $size * 2); $common = $this->implementation->calculate($from, $to); $this->assertSame([], $common); } @@ -127,9 +131,9 @@ public function testCommonSubsequence(): void $this->assertSame($expected, $common); foreach ($this->stress_sizes as $size) { - $from = $size < 2 ? [1] : \range(1, $size + 1, 2); - $to = $size < 3 ? [1] : \range(1, $size + 1, 3); - $expected = $size < 6 ? [1] : \range(1, $size + 1, 6); + $from = $size < 2 ? [1] : range(1, $size + 1, 2); + $to = $size < 3 ? [1] : range(1, $size + 1, 3); + $expected = $size < 6 ? [1] : range(1, $size + 1, 6); $common = $this->implementation->calculate($from, $to); $this->assertSame($expected, $common); @@ -139,8 +143,8 @@ public function testCommonSubsequence(): void public function testSingleElementSubsequenceAtStart(): void { foreach ($this->stress_sizes as $size) { - $from = \range(1, $size); - $to = \array_slice($from, 0, 1); + $from = range(1, $size); + $to = array_slice($from, 0, 1); $common = $this->implementation->calculate($from, $to); $this->assertSame($to, $common); @@ -150,8 +154,8 @@ public function testSingleElementSubsequenceAtStart(): void public function testSingleElementSubsequenceAtMiddle(): void { foreach ($this->stress_sizes as $size) { - $from = \range(1, $size); - $to = \array_slice($from, (int) ($size / 2), 1); + $from = range(1, $size); + $to = array_slice($from, (int) ($size / 2), 1); $common = $this->implementation->calculate($from, $to); $this->assertSame($to, $common); @@ -161,8 +165,8 @@ public function testSingleElementSubsequenceAtMiddle(): void public function testSingleElementSubsequenceAtEnd(): void { foreach ($this->stress_sizes as $size) { - $from = \range(1, $size); - $to = \array_slice($from, $size - 1, 1); + $from = range(1, $size); + $to = array_slice($from, $size - 1, 1); $common = $this->implementation->calculate($from, $to); $this->assertSame($to, $common); @@ -178,8 +182,8 @@ public function testReversedSequences(): void $this->assertSame($expected, $common); foreach ($this->stress_sizes as $size) { - $from = \range(1, $size); - $to = \array_reverse($from); + $from = range(1, $size); + $to = array_reverse($from); $common = $this->implementation->calculate($from, $to); $this->assertSame([1], $common); @@ -194,8 +198,5 @@ public function testStrictTypeCalculate(): void $this->assertCount(0, $diff); } - /** - * @return LongestCommonSubsequenceCalculator - */ abstract protected function createImplementation(): LongestCommonSubsequenceCalculator; } diff --git a/tests/MemoryEfficientImplementationTest.php b/tests/MemoryEfficientImplementationTest.php index 1d7797f3..3fd133d3 100644 --- a/tests/MemoryEfficientImplementationTest.php +++ b/tests/MemoryEfficientImplementationTest.php @@ -7,11 +7,10 @@ * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ - namespace Localheinz\Diff; /** - * @covers Localheinz\Diff\MemoryEfficientLongestCommonSubsequenceCalculator + * @covers \Localheinz\Diff\MemoryEfficientLongestCommonSubsequenceCalculator */ final class MemoryEfficientImplementationTest extends LongestCommonSubsequenceTest { diff --git a/tests/Output/AbstractChunkOutputBuilderTest.php b/tests/Output/AbstractChunkOutputBuilderTest.php index 443d2a44..29454607 100644 --- a/tests/Output/AbstractChunkOutputBuilderTest.php +++ b/tests/Output/AbstractChunkOutputBuilderTest.php @@ -7,27 +7,21 @@ * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ - namespace Localheinz\Diff\Output; -use PHPUnit\Framework\TestCase; use Localheinz\Diff\Differ; +use PHPUnit\Framework\TestCase; /** - * @covers Localheinz\Diff\Output\AbstractChunkOutputBuilder + * @covers \Localheinz\Diff\Output\AbstractChunkOutputBuilder * - * @uses Localheinz\Diff\Differ - * @uses Localheinz\Diff\Output\UnifiedDiffOutputBuilder - * @uses Localheinz\Diff\TimeEfficientLongestCommonSubsequenceCalculator + * @uses \Localheinz\Diff\Differ + * @uses \Localheinz\Diff\Output\UnifiedDiffOutputBuilder + * @uses \Localheinz\Diff\TimeEfficientLongestCommonSubsequenceCalculator */ final class AbstractChunkOutputBuilderTest extends TestCase { /** - * @param array $expected - * @param string $from - * @param string $to - * @param int $lineThreshold - * * @dataProvider provideGetCommonChunks */ public function testGetCommonChunks(array $expected, string $from, string $to, int $lineThreshold = 5): void diff --git a/tests/Output/DiffOnlyOutputBuilderTest.php b/tests/Output/DiffOnlyOutputBuilderTest.php index 72f8e81c..9ff43a11 100644 --- a/tests/Output/DiffOnlyOutputBuilderTest.php +++ b/tests/Output/DiffOnlyOutputBuilderTest.php @@ -7,26 +7,20 @@ * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ - namespace Localheinz\Diff\Output; -use PHPUnit\Framework\TestCase; use Localheinz\Diff\Differ; +use PHPUnit\Framework\TestCase; /** - * @covers Localheinz\Diff\Output\DiffOnlyOutputBuilder + * @covers \Localheinz\Diff\Output\DiffOnlyOutputBuilder * - * @uses Localheinz\Diff\Differ - * @uses Localheinz\Diff\TimeEfficientLongestCommonSubsequenceCalculator + * @uses \Localheinz\Diff\Differ + * @uses \Localheinz\Diff\TimeEfficientLongestCommonSubsequenceCalculator */ final class DiffOnlyOutputBuilderTest extends TestCase { /** - * @param string $expected - * @param string $from - * @param string $to - * @param string $header - * * @dataProvider textForNoNonDiffLinesProvider */ public function testDiffDoNotShowNonDiffLines(string $expected, string $from, string $to, string $header = ''): void diff --git a/tests/Output/Integration/StrictUnifiedDiffOutputBuilderIntegrationTest.php b/tests/Output/Integration/StrictUnifiedDiffOutputBuilderIntegrationTest.php index 97a89f27..0bd1107c 100644 --- a/tests/Output/Integration/StrictUnifiedDiffOutputBuilderIntegrationTest.php +++ b/tests/Output/Integration/StrictUnifiedDiffOutputBuilderIntegrationTest.php @@ -7,21 +7,34 @@ * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ - namespace Localheinz\Diff\Output; -use PHPUnit\Framework\TestCase; +use const PREG_SPLIT_DELIM_CAPTURE; +use const PREG_SPLIT_NO_EMPTY; +use function file_put_contents; +use function implode; +use function is_dir; +use function preg_replace; +use function preg_split; +use function realpath; +use function sprintf; +use function unlink; use Localheinz\Diff\Differ; use Localheinz\Diff\Utils\FileUtils; use Localheinz\Diff\Utils\UnifiedDiffAssertTrait; +use PHPUnit\Framework\TestCase; +use RecursiveDirectoryIterator; +use RecursiveIteratorIterator; +use RuntimeException; +use SplFileInfo; use Symfony\Component\Process\Process; /** - * @covers Localheinz\Diff\Output\StrictUnifiedDiffOutputBuilder + * @covers \Localheinz\Diff\Output\StrictUnifiedDiffOutputBuilder * - * @uses Localheinz\Diff\Differ - * @uses Localheinz\Diff\TimeEfficientLongestCommonSubsequenceCalculator - * @uses Localheinz\Diff\MemoryEfficientLongestCommonSubsequenceCalculator + * @uses \Localheinz\Diff\Differ + * @uses \Localheinz\Diff\TimeEfficientLongestCommonSubsequenceCalculator + * @uses \Localheinz\Diff\MemoryEfficientLongestCommonSubsequenceCalculator * * @requires OS Linux */ @@ -39,13 +52,13 @@ final class StrictUnifiedDiffOutputBuilderIntegrationTest extends TestCase protected function setUp(): void { - $this->dir = \realpath(__DIR__ . '/../../fixtures/out') . '/'; + $this->dir = realpath(__DIR__ . '/../../fixtures/out') . '/'; $this->fileFrom = $this->dir . 'from.txt'; $this->fileTo = $this->dir . 'to.txt'; $this->filePatch = $this->dir . 'diff.patch'; - if (!\is_dir($this->dir)) { - throw new \RuntimeException('Integration test working directory not found.'); + if (!is_dir($this->dir)) { + throw new RuntimeException('Integration test working directory not found.'); } $this->cleanUpTempFiles(); @@ -57,16 +70,13 @@ protected function tearDown(): void } /** - * Integration test + * Integration test. * * - get a file pair * - create a `diff` between the files * - test applying the diff using `git apply` * - test applying the diff using `patch` * - * @param string $fileFrom - * @param string $fileTo - * * @dataProvider provideFilePairs */ public function testIntegrationUsingPHPFileInVendorGitApply(string $fileFrom, string $fileTo): void @@ -87,16 +97,13 @@ public function testIntegrationUsingPHPFileInVendorGitApply(string $fileFrom, st } /** - * Integration test + * Integration test. * * - get a file pair * - create a `diff` between the files * - test applying the diff using `git apply` * - test applying the diff using `patch` * - * @param string $fileFrom - * @param string $fileTo - * * @dataProvider provideFilePairs */ public function testIntegrationUsingPHPFileInVendorPatch(string $fileFrom, string $fileTo): void @@ -117,10 +124,6 @@ public function testIntegrationUsingPHPFileInVendorPatch(string $fileFrom, strin } /** - * @param string $expected - * @param string $from - * @param string $to - * * @dataProvider provideOutputBuildingCases * @dataProvider provideSample * @dataProvider provideBasicDiffGeneration @@ -131,10 +134,6 @@ public function testIntegrationOfUnitTestCasesGitApply(string $expected, string } /** - * @param string $expected - * @param string $from - * @param string $to - * * @dataProvider provideOutputBuildingCases * @dataProvider provideSample * @dataProvider provideBasicDiffGeneration @@ -163,18 +162,18 @@ public function provideFilePairs(): array { $cases = []; $fromFile = __FILE__; - $vendorDir = \realpath(__DIR__ . '/../../../vendor'); + $vendorDir = realpath(__DIR__ . '/../../../vendor'); - $fileIterator = new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($vendorDir, \RecursiveDirectoryIterator::SKIP_DOTS)); + $fileIterator = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($vendorDir, RecursiveDirectoryIterator::SKIP_DOTS)); - /** @var \SplFileInfo $file */ + /** @var SplFileInfo $file */ foreach ($fileIterator as $file) { if ('php' !== $file->getExtension()) { continue; } $toFile = $file->getPathname(); - $cases[\sprintf("Diff file:\n\"%s\"\nvs.\n\"%s\"\n", \realpath($fromFile), \realpath($toFile))] = [$fromFile, $toFile]; + $cases[sprintf("Diff file:\n\"%s\"\nvs.\n\"%s\"\n", realpath($fromFile), realpath($toFile))] = [$fromFile, $toFile]; $fromFile = $toFile; } @@ -184,10 +183,6 @@ public function provideFilePairs(): array /** * Compare diff create by builder and against one create by `diff` command. * - * @param string $diff - * @param string $from - * @param string $to - * * @dataProvider provideBasicDiffGeneration */ public function testIntegrationDiffOutputBuilderVersusDiffCommand(string $diff, string $from, string $to): void @@ -195,24 +190,31 @@ public function testIntegrationDiffOutputBuilderVersusDiffCommand(string $diff, $this->assertNotSame('', $diff); $this->assertValidUnifiedDiffFormat($diff); - $this->assertNotFalse(\file_put_contents($this->fileFrom, $from)); - $this->assertNotFalse(\file_put_contents($this->fileTo, $to)); + $this->assertNotFalse(file_put_contents($this->fileFrom, $from)); + $this->assertNotFalse(file_put_contents($this->fileTo, $to)); + + $p = Process::fromShellCommandline('diff -u $from $to'); + $p->run( + null, + [ + 'from' => $this->fileFrom, + 'to' => $this->fileTo, + ] + ); - $p = new Process(\sprintf('diff -u %s %s', \escapeshellarg($this->fileFrom), \escapeshellarg($this->fileTo))); - $p->run(); $this->assertSame(1, $p->getExitCode()); // note: Process assumes exit code 0 for `isSuccessful`, however `diff` uses the exit code `1` for success with diff $output = $p->getOutput(); - $diffLines = \preg_split('/(.*\R)/', $diff, -1, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY); - $diffLines[0] = \preg_replace('#^\-\-\- .*#', '--- /' . $this->fileFrom, $diffLines[0], 1); - $diffLines[1] = \preg_replace('#^\+\+\+ .*#', '+++ /' . $this->fileFrom, $diffLines[1], 1); - $diff = \implode('', $diffLines); + $diffLines = preg_split('/(.*\R)/', $diff, -1, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY); + $diffLines[0] = preg_replace('#^\-\-\- .*#', '--- /' . $this->fileFrom, $diffLines[0], 1); + $diffLines[1] = preg_replace('#^\+\+\+ .*#', '+++ /' . $this->fileFrom, $diffLines[1], 1); + $diff = implode('', $diffLines); - $outputLines = \preg_split('/(.*\R)/', $output, -1, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY); - $outputLines[0] = \preg_replace('#^\-\-\- .*#', '--- /' . $this->fileFrom, $outputLines[0], 1); - $outputLines[1] = \preg_replace('#^\+\+\+ .*#', '+++ /' . $this->fileFrom, $outputLines[1], 1); - $output = \implode('', $outputLines); + $outputLines = preg_split('/(.*\R)/', $output, -1, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY); + $outputLines[0] = preg_replace('#^\-\-\- .*#', '--- /' . $this->fileFrom, $outputLines[0], 1); + $outputLines[1] = preg_replace('#^\+\+\+ .*#', '+++ /' . $this->fileFrom, $outputLines[1], 1); + $output = implode('', $outputLines); $this->assertSame($diff, $output); } @@ -224,16 +226,17 @@ private function doIntegrationTestGitApply(string $diff, string $from, string $t $diff = self::setDiffFileHeader($diff, $this->fileFrom); - $this->assertNotFalse(\file_put_contents($this->fileFrom, $from)); - $this->assertNotFalse(\file_put_contents($this->filePatch, $diff)); + $this->assertNotFalse(file_put_contents($this->fileFrom, $from)); + $this->assertNotFalse(file_put_contents($this->filePatch, $diff)); - $p = new Process(\sprintf( - 'git --git-dir %s apply --check -v --unsafe-paths --ignore-whitespace %s', - \escapeshellarg($this->dir), - \escapeshellarg($this->filePatch) - )); - - $p->run(); + $p = Process::fromShellCommandline('git --git-dir $dir apply --check -v --unsafe-paths --ignore-whitespace $patch'); + $p->run( + null, + [ + 'dir' => $this->dir, + 'patch' => $this->filePatch, + ] + ); $this->assertProcessSuccessful($p); } @@ -245,24 +248,24 @@ private function doIntegrationTestPatch(string $diff, string $from, string $to): $diff = self::setDiffFileHeader($diff, $this->fileFrom); - $this->assertNotFalse(\file_put_contents($this->fileFrom, $from)); - $this->assertNotFalse(\file_put_contents($this->filePatch, $diff)); + $this->assertNotFalse(file_put_contents($this->fileFrom, $from)); + $this->assertNotFalse(file_put_contents($this->filePatch, $diff)); - $command = \sprintf( - 'patch -u --verbose --posix %s < %s', - \escapeshellarg($this->fileFrom), - \escapeshellarg($this->filePatch) + $p = Process::fromShellCommandline('patch -u --verbose --posix $from < $patch'); + $p->run( + null, + [ + 'from' => $this->fileFrom, + 'patch' => $this->filePatch, + ] ); - $p = new Process($command); - $p->run(); - $this->assertProcessSuccessful($p); $this->assertStringEqualsFile( $this->fileFrom, $to, - \sprintf('Patch command "%s".', $command) + sprintf('Patch command "%s".', $p->getCommandLine()) ); } @@ -270,7 +273,7 @@ private function assertProcessSuccessful(Process $p): void { $this->assertTrue( $p->isSuccessful(), - \sprintf( + sprintf( "Command exec. was not successful:\n\"%s\"\nOutput:\n\"%s\"\nStdErr:\n\"%s\"\nExit code %d.\n", $p->getCommandLine(), $p->getOutput(), @@ -282,19 +285,19 @@ private function assertProcessSuccessful(Process $p): void private function cleanUpTempFiles(): void { - @\unlink($this->fileFrom . '.orig'); - @\unlink($this->fileFrom . '.rej'); - @\unlink($this->fileFrom); - @\unlink($this->fileTo); - @\unlink($this->filePatch); + @unlink($this->fileFrom . '.orig'); + @unlink($this->fileFrom . '.rej'); + @unlink($this->fileFrom); + @unlink($this->fileTo); + @unlink($this->filePatch); } private static function setDiffFileHeader(string $diff, string $file): string { - $diffLines = \preg_split('/(.*\R)/', $diff, -1, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY); - $diffLines[0] = \preg_replace('#^\-\-\- .*#', '--- /' . $file, $diffLines[0], 1); - $diffLines[1] = \preg_replace('#^\+\+\+ .*#', '+++ /' . $file, $diffLines[1], 1); + $diffLines = preg_split('/(.*\R)/', $diff, -1, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY); + $diffLines[0] = preg_replace('#^\-\-\- .*#', '--- /' . $file, $diffLines[0], 1); + $diffLines[1] = preg_replace('#^\+\+\+ .*#', '+++ /' . $file, $diffLines[1], 1); - return \implode('', $diffLines); + return implode('', $diffLines); } } diff --git a/tests/Output/Integration/UnifiedDiffOutputBuilderIntegrationTest.php b/tests/Output/Integration/UnifiedDiffOutputBuilderIntegrationTest.php index 0d96c457..a1bfee6d 100644 --- a/tests/Output/Integration/UnifiedDiffOutputBuilderIntegrationTest.php +++ b/tests/Output/Integration/UnifiedDiffOutputBuilderIntegrationTest.php @@ -7,18 +7,30 @@ * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ - namespace Localheinz\Diff\Output; -use PHPUnit\Framework\TestCase; +use const ARRAY_FILTER_USE_KEY; +use const PREG_SPLIT_DELIM_CAPTURE; +use const PREG_SPLIT_NO_EMPTY; +use function array_filter; +use function file_put_contents; +use function implode; +use function is_string; +use function preg_replace; +use function preg_split; +use function realpath; +use function sprintf; +use function strpos; +use function unlink; use Localheinz\Diff\Utils\UnifiedDiffAssertTrait; +use PHPUnit\Framework\TestCase; use Symfony\Component\Process\Process; /** - * @covers Localheinz\Diff\Output\UnifiedDiffOutputBuilder + * @covers \Localheinz\Diff\Output\UnifiedDiffOutputBuilder * - * @uses Localheinz\Diff\Differ - * @uses Localheinz\Diff\TimeEfficientLongestCommonSubsequenceCalculator + * @uses \Localheinz\Diff\Differ + * @uses \Localheinz\Diff\TimeEfficientLongestCommonSubsequenceCalculator * * @requires OS Linux */ @@ -34,7 +46,7 @@ final class UnifiedDiffOutputBuilderIntegrationTest extends TestCase protected function setUp(): void { - $this->dir = \realpath(__DIR__ . '/../../fixtures/out/') . '/'; + $this->dir = realpath(__DIR__ . '/../../fixtures/out/') . '/'; $this->fileFrom = $this->dir . 'from.txt'; $this->filePatch = $this->dir . 'patch.txt'; @@ -48,10 +60,6 @@ protected function tearDown(): void /** * @dataProvider provideDiffWithLineNumbers - * - * @param mixed $expected - * @param mixed $from - * @param mixed $to */ public function testDiffWithLineNumbersPath($expected, $from, $to): void { @@ -60,10 +68,6 @@ public function testDiffWithLineNumbersPath($expected, $from, $to): void /** * @dataProvider provideDiffWithLineNumbers - * - * @param mixed $expected - * @param mixed $from - * @param mixed $to */ public function testDiffWithLineNumbersGitApply($expected, $from, $to): void { @@ -72,10 +76,10 @@ public function testDiffWithLineNumbersGitApply($expected, $from, $to): void public function provideDiffWithLineNumbers() { - return \array_filter( + return array_filter( UnifiedDiffOutputBuilderDataProvider::provideDiffWithLineNumbers(), static function ($key) { - return !\is_string($key) || false === \strpos($key, 'non_patch_compat'); + return !is_string($key) || false === strpos($key, 'non_patch_compat'); }, ARRAY_FILTER_USE_KEY ); @@ -88,24 +92,24 @@ private function doIntegrationTestPatch(string $diff, string $from, string $to): $diff = self::setDiffFileHeader($diff, $this->fileFrom); - $this->assertNotFalse(\file_put_contents($this->fileFrom, $from)); - $this->assertNotFalse(\file_put_contents($this->filePatch, $diff)); + $this->assertNotFalse(file_put_contents($this->fileFrom, $from)); + $this->assertNotFalse(file_put_contents($this->filePatch, $diff)); - $command = \sprintf( - 'patch -u --verbose --posix %s < %s', // --posix - \escapeshellarg($this->fileFrom), - \escapeshellarg($this->filePatch) + $p = Process::fromShellCommandline('patch -u --verbose --posix $from < $patch'); // --posix + $p->run( + null, + [ + 'from' => $this->fileFrom, + 'patch' => $this->filePatch, + ] ); - $p = new Process($command); - $p->run(); - $this->assertProcessSuccessful($p); $this->assertStringEqualsFile( $this->fileFrom, $to, - \sprintf('Patch command "%s".', $command) + sprintf('Patch command "%s".', $p->getCommandLine()) ); } @@ -116,18 +120,18 @@ private function doIntegrationTestGitApply(string $diff, string $from, string $t $diff = self::setDiffFileHeader($diff, $this->fileFrom); - $this->assertNotFalse(\file_put_contents($this->fileFrom, $from)); - $this->assertNotFalse(\file_put_contents($this->filePatch, $diff)); + $this->assertNotFalse(file_put_contents($this->fileFrom, $from)); + $this->assertNotFalse(file_put_contents($this->filePatch, $diff)); - $command = \sprintf( - 'git --git-dir %s apply --check -v --unsafe-paths --ignore-whitespace %s', - \escapeshellarg($this->dir), - \escapeshellarg($this->filePatch) + $p = Process::fromShellCommandline('git --git-dir $dir apply --check -v --unsafe-paths --ignore-whitespace $patch'); + $p->run( + null, + [ + 'dir' => $this->dir, + 'patch' => $this->filePatch, + ] ); - $p = new Process($command); - $p->run(); - $this->assertProcessSuccessful($p); } @@ -135,7 +139,7 @@ private function assertProcessSuccessful(Process $p): void { $this->assertTrue( $p->isSuccessful(), - \sprintf( + sprintf( "Command exec. was not successful:\n\"%s\"\nOutput:\n\"%s\"\nStdErr:\n\"%s\"\nExit code %d.\n", $p->getCommandLine(), $p->getOutput(), @@ -147,17 +151,17 @@ private function assertProcessSuccessful(Process $p): void private function cleanUpTempFiles(): void { - @\unlink($this->fileFrom . '.orig'); - @\unlink($this->fileFrom); - @\unlink($this->filePatch); + @unlink($this->fileFrom . '.orig'); + @unlink($this->fileFrom); + @unlink($this->filePatch); } private static function setDiffFileHeader(string $diff, string $file): string { - $diffLines = \preg_split('/(.*\R)/', $diff, -1, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY); - $diffLines[0] = \preg_replace('#^\-\-\- .*#', '--- /' . $file, $diffLines[0], 1); - $diffLines[1] = \preg_replace('#^\+\+\+ .*#', '+++ /' . $file, $diffLines[1], 1); + $diffLines = preg_split('/(.*\R)/', $diff, -1, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY); + $diffLines[0] = preg_replace('#^\-\-\- .*#', '--- /' . $file, $diffLines[0], 1); + $diffLines[1] = preg_replace('#^\+\+\+ .*#', '+++ /' . $file, $diffLines[1], 1); - return \implode('', $diffLines); + return implode('', $diffLines); } } diff --git a/tests/Output/StrictUnifiedDiffOutputBuilderDataProvider.php b/tests/Output/StrictUnifiedDiffOutputBuilderDataProvider.php index 22a359fc..8a3f0abf 100644 --- a/tests/Output/StrictUnifiedDiffOutputBuilderDataProvider.php +++ b/tests/Output/StrictUnifiedDiffOutputBuilderDataProvider.php @@ -7,7 +7,6 @@ * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ - namespace Localheinz\Diff\Output; final class StrictUnifiedDiffOutputBuilderDataProvider @@ -16,7 +15,7 @@ public static function provideOutputBuildingCases(): array { return [ [ -'--- input.txt + '--- input.txt +++ output.txt @@ -1,3 +1,4 @@ +b @@ -39,7 +38,7 @@ public static function provideOutputBuildingCases(): array ], ], [ -'--- ' . __FILE__ . "\t2017-10-02 17:38:11.586413675 +0100 + '--- ' . __FILE__ . "\t2017-10-02 17:38:11.586413675 +0100 +++ output1.txt\t2017-10-03 12:09:43.086719482 +0100 @@ -1,1 +1,1 @@ -B @@ -56,7 +55,7 @@ public static function provideOutputBuildingCases(): array ], ], [ -'--- input.txt + '--- input.txt +++ output.txt @@ -1 +1 @@ -B @@ -77,7 +76,7 @@ public static function provideSample(): array { return [ [ -'--- input.txt + '--- input.txt +++ output.txt @@ -1,6 +1,6 @@ 1 @@ -102,7 +101,7 @@ public static function provideBasicDiffGeneration(): array { return [ [ -"--- input.txt + "--- input.txt +++ output.txt @@ -1,2 +1 @@ -A @@ -113,7 +112,7 @@ public static function provideBasicDiffGeneration(): array "A\rB\n", ], [ -"--- input.txt + "--- input.txt +++ output.txt @@ -1 +1 @@ - @@ -124,7 +123,7 @@ public static function provideBasicDiffGeneration(): array "\r", ], [ -"--- input.txt + "--- input.txt +++ output.txt @@ -1 +1 @@ -\r @@ -135,7 +134,7 @@ public static function provideBasicDiffGeneration(): array "\n", ], [ -'--- input.txt + '--- input.txt +++ output.txt @@ -1,3 +1,3 @@ X @@ -147,7 +146,7 @@ public static function provideBasicDiffGeneration(): array "X\nA\nB\n", ], [ -'--- input.txt + '--- input.txt +++ output.txt @@ -1,3 +1,3 @@ X @@ -160,7 +159,7 @@ public static function provideBasicDiffGeneration(): array "X\nA\nB\n", ], [ -'--- input.txt + '--- input.txt +++ output.txt @@ -1,3 +1,3 @@ A @@ -173,7 +172,7 @@ public static function provideBasicDiffGeneration(): array "A\nA\nB", ], [ -'--- input.txt + '--- input.txt +++ output.txt @@ -1 +1 @@ -A diff --git a/tests/Output/StrictUnifiedDiffOutputBuilderTest.php b/tests/Output/StrictUnifiedDiffOutputBuilderTest.php index 2d3391a3..f1aa9de3 100644 --- a/tests/Output/StrictUnifiedDiffOutputBuilderTest.php +++ b/tests/Output/StrictUnifiedDiffOutputBuilderTest.php @@ -7,31 +7,31 @@ * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ - namespace Localheinz\Diff\Output; -use PHPUnit\Framework\TestCase; +use function array_merge; +use function preg_quote; +use function sprintf; +use function substr; +use function time; use Localheinz\Diff\ConfigurationException; use Localheinz\Diff\Differ; use Localheinz\Diff\Utils\UnifiedDiffAssertTrait; +use PHPUnit\Framework\TestCase; +use SplFileInfo; /** - * @covers Localheinz\Diff\Output\StrictUnifiedDiffOutputBuilder + * @covers \Localheinz\Diff\Output\StrictUnifiedDiffOutputBuilder * - * @uses Localheinz\Diff\Differ - * @uses Localheinz\Diff\TimeEfficientLongestCommonSubsequenceCalculator - * @uses Localheinz\Diff\ConfigurationException + * @uses \Localheinz\Diff\Differ + * @uses \Localheinz\Diff\TimeEfficientLongestCommonSubsequenceCalculator + * @uses \Localheinz\Diff\ConfigurationException */ final class StrictUnifiedDiffOutputBuilderTest extends TestCase { use UnifiedDiffAssertTrait; /** - * @param string $expected - * @param string $from - * @param string $to - * @param array $options - * * @dataProvider provideOutputBuildingCases */ public function testOutputBuilding(string $expected, string $from, string $to, array $options): void @@ -43,11 +43,6 @@ public function testOutputBuilding(string $expected, string $from, string $to, a } /** - * @param string $expected - * @param string $from - * @param string $to - * @param array $options - * * @dataProvider provideSample */ public function testSample(string $expected, string $from, string $to, array $options): void @@ -83,10 +78,6 @@ public function provideSample(): array } /** - * @param string $expected - * @param string $from - * @param string $to - * * @dataProvider provideBasicDiffGeneration */ public function testBasicDiffGeneration(string $expected, string $from, string $to): void @@ -106,16 +97,11 @@ public function provideBasicDiffGeneration(): array } /** - * @param string $expected - * @param string $from - * @param string $to - * @param array $config - * * @dataProvider provideConfiguredDiffGeneration */ public function testConfiguredDiffGeneration(string $expected, string $from, string $to, array $config = []): void { - $diff = $this->getDiffer(\array_merge([ + $diff = $this->getDiffer(array_merge([ 'fromFile' => 'input.txt', 'toFile' => 'output.txt', ], $config))->diff($from, $to); @@ -150,7 +136,7 @@ public function provideConfiguredDiffGeneration(): array "1\n", ], [ -'--- input.txt + '--- input.txt +++ output.txt @@ -4 +4 @@ -X @@ -163,7 +149,7 @@ public function provideConfiguredDiffGeneration(): array ], ], [ -'--- input.txt + '--- input.txt +++ output.txt @@ -3,3 +3,3 @@ 3 @@ -178,7 +164,7 @@ public function provideConfiguredDiffGeneration(): array ], ], [ -'--- input.txt + '--- input.txt +++ output.txt @@ -1,10 +1,10 @@ 1 @@ -200,7 +186,7 @@ public function provideConfiguredDiffGeneration(): array ], ], [ -'--- input.txt + '--- input.txt +++ output.txt @@ -1,0 +1,2 @@ + @@ -210,7 +196,7 @@ public function provideConfiguredDiffGeneration(): array "\nA\n", ], [ -'--- input.txt + '--- input.txt +++ output.txt @@ -1,2 +1,0 @@ - @@ -275,7 +261,7 @@ public function testReUseBuilder(): void $diff = $differ->diff("A\nB\n", "A\nX\n"); $this->assertSame( -'--- input.txt + '--- input.txt +++ output.txt @@ -1,2 +1,2 @@ A @@ -306,22 +292,19 @@ public function testEmptyDiff(): void } /** - * @param array $options - * @param string $message - * * @dataProvider provideInvalidConfiguration */ public function testInvalidConfiguration(array $options, string $message): void { $this->expectException(ConfigurationException::class); - $this->expectExceptionMessageRegExp(\sprintf('#^%s$#', \preg_quote($message, '#'))); + $this->expectExceptionMessageRegExp(sprintf('#^%s$#', preg_quote($message, '#'))); new StrictUnifiedDiffOutputBuilder($options); } public function provideInvalidConfiguration(): array { - $time = \time(); + $time = time(); return [ [ @@ -341,7 +324,7 @@ public function provideInvalidConfiguration(): array 'Option "commonLineThreshold" must be an int > 0, got "integer#0".', ], [ - ['fromFile' => new \SplFileInfo(__FILE__)], + ['fromFile' => new SplFileInfo(__FILE__)], 'Option "fromFile" must be a string, got "SplFileInfo".', ], [ @@ -371,11 +354,6 @@ public function provideInvalidConfiguration(): array } /** - * @param string $expected - * @param string $from - * @param string $to - * @param int $threshold - * * @dataProvider provideCommonLineThresholdCases */ public function testCommonLineThreshold(string $expected, string $from, string $to, int $threshold): void @@ -395,7 +373,7 @@ public function provideCommonLineThresholdCases(): array { return [ [ -'--- input.txt + '--- input.txt +++ output.txt @@ -2,3 +2,3 @@ -X @@ -412,7 +390,7 @@ public function provideCommonLineThresholdCases(): array 2, ], [ -'--- input.txt + '--- input.txt +++ output.txt @@ -2 +2 @@ -X @@ -429,12 +407,6 @@ public function provideCommonLineThresholdCases(): array } /** - * @param string $expected - * @param string $from - * @param string $to - * @param int $contextLines - * @param int $commonLineThreshold - * * @dataProvider provideContextLineConfigurationCases */ public function testContextLineConfiguration(string $expected, string $from, string $to, int $contextLines, int $commonLineThreshold = 6): void @@ -478,7 +450,7 @@ public function provideContextLineConfigurationCases(): array "A\nB\nX", "A\nB\nY", 1, -], + ], 'EOF 2' => [ "--- input.txt\n+++ output.txt\n@@ -1,3 +1,3 @@ A @@ -556,25 +528,25 @@ public function provideContextLineConfigurationCases(): array 'M no linebreak EOF .1' => [ "--- input.txt\n+++ output.txt\n@@ -1,14 +1,14 @@\n A\n B\n C\n D\n E\n F\n-X\n+Y\n G\n H\n I\n J\n K\n L\n-M\n+M\n\\ No newline at end of file\n", $from, - \substr($to, 0, -1), + substr($to, 0, -1), 7, ], 'M no linebreak EOF .2' => [ "--- input.txt\n+++ output.txt\n@@ -1,14 +1,14 @@\n A\n B\n C\n D\n E\n F\n-X\n+Y\n G\n H\n I\n J\n K\n L\n-M\n\\ No newline at end of file\n+M\n", - \substr($from, 0, -1), + substr($from, 0, -1), $to, 7, ], 'M no linebreak EOF .3' => [ "--- input.txt\n+++ output.txt\n@@ -1,14 +1,14 @@\n A\n B\n C\n D\n E\n F\n-X\n+Y\n G\n H\n I\n J\n K\n L\n M\n", - \substr($from, 0, -1), - \substr($to, 0, -1), + substr($from, 0, -1), + substr($to, 0, -1), 7, ], 'M no linebreak EOF .4' => [ "--- input.txt\n+++ output.txt\n@@ -1,14 +1,14 @@\n A\n B\n C\n D\n E\n F\n-X\n+Y\n G\n H\n I\n J\n K\n L\n M\n\\ No newline at end of file\n", - \substr($from, 0, -1), - \substr($to, 0, -1), + substr($from, 0, -1), + substr($to, 0, -1), 10000, 10000, ], @@ -674,10 +646,6 @@ public function provideContextLineConfigurationCases(): array /** * Returns a new instance of a Differ with a new instance of the class (DiffOutputBuilderInterface) under test. - * - * @param array $options - * - * @return Differ */ private function getDiffer(array $options = []): Differ { diff --git a/tests/Output/UnifiedDiffOutputBuilderDataProvider.php b/tests/Output/UnifiedDiffOutputBuilderDataProvider.php index af6748be..bea832cc 100644 --- a/tests/Output/UnifiedDiffOutputBuilderDataProvider.php +++ b/tests/Output/UnifiedDiffOutputBuilderDataProvider.php @@ -7,7 +7,6 @@ * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ - namespace Localheinz\Diff\Output; final class UnifiedDiffOutputBuilderDataProvider @@ -16,7 +15,7 @@ public static function provideDiffWithLineNumbers(): array { return [ 'diff line 1 non_patch_compat' => [ -'--- Original + '--- Original +++ New @@ -1 +1 @@ -AA @@ -26,7 +25,7 @@ public static function provideDiffWithLineNumbers(): array 'BA', ], 'diff line +1 non_patch_compat' => [ -'--- Original + '--- Original +++ New @@ -1 +1,2 @@ -AZ @@ -37,7 +36,7 @@ public static function provideDiffWithLineNumbers(): array "\nB", ], 'diff line -1 non_patch_compat' => [ -'--- Original + '--- Original +++ New @@ -1,2 +1 @@ - @@ -48,7 +47,7 @@ public static function provideDiffWithLineNumbers(): array 'B', ], 'II non_patch_compat' => [ -'--- Original + '--- Original +++ New @@ -1,4 +1,2 @@ - @@ -60,7 +59,7 @@ public static function provideDiffWithLineNumbers(): array "A\n1", ], 'diff last line II - no trailing linebreak non_patch_compat' => [ -'--- Original + '--- Original +++ New @@ -5,4 +5,4 @@ ' . ' @@ -82,15 +81,15 @@ public static function provideDiffWithLineNumbers(): array " [ -'--- Original + 'same non_patch_compat' => [ + '--- Original +++ New ', "AT\n", "AT\n", ], [ -'--- Original + '--- Original +++ New @@ -1,4 +1,4 @@ -b @@ -103,7 +102,7 @@ public static function provideDiffWithLineNumbers(): array "a\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n", ], 'diff line @1' => [ -'--- Original + '--- Original +++ New @@ -1,2 +1,2 @@ ' . ' @@ -114,7 +113,7 @@ public static function provideDiffWithLineNumbers(): array "\nB\n", ], 'same multiple lines' => [ -'--- Original + '--- Original +++ New @@ -1,4 +1,4 @@ ' . ' @@ -127,7 +126,7 @@ public static function provideDiffWithLineNumbers(): array "\n\nB\nC213", ], 'diff last line I' => [ -'--- Original + '--- Original +++ New @@ -5,4 +5,4 @@ ' . ' @@ -140,7 +139,7 @@ public static function provideDiffWithLineNumbers(): array "A\n\n\n\n\n\n\nB\n", ], 'diff line middle' => [ -'--- Original + '--- Original +++ New @@ -5,7 +5,7 @@ ' . ' @@ -156,7 +155,7 @@ public static function provideDiffWithLineNumbers(): array "A\n\n\n\n\n\n\nZ\n\n\n\n\n\n\nAY", ], 'diff last line III' => [ -'--- Original + '--- Original +++ New @@ -12,4 +12,4 @@ ' . ' @@ -169,7 +168,7 @@ public static function provideDiffWithLineNumbers(): array "A\n\n\n\n\n\n\nA\n\n\n\n\n\n\nB\n", ], [ -'--- Original + '--- Original +++ New @@ -1,8 +1,8 @@ A @@ -187,7 +186,7 @@ public static function provideDiffWithLineNumbers(): array "A\nB1\nD\nE\nEE\nF\nG1\nH", ], [ -'--- Original + '--- Original +++ New @@ -1,4 +1,5 @@ Z @@ -203,7 +202,7 @@ public static function provideDiffWithLineNumbers(): array +x j ', -'Z + 'Z a b c @@ -215,7 +214,7 @@ public static function provideDiffWithLineNumbers(): array i j ', -'Z + 'Z a b @@ -230,7 +229,7 @@ public static function provideDiffWithLineNumbers(): array ', ], [ -'--- Original + '--- Original +++ New @@ -1,7 +1,5 @@ - @@ -247,7 +246,7 @@ public static function provideDiffWithLineNumbers(): array "b\nA\nY\n\nA\n", ], [ -<<assertSame($expected, $differ->diff($from, $to)); @@ -87,4 +77,27 @@ public function provideDiffWithLineNumbers(): array { return UnifiedDiffOutputBuilderDataProvider::provideDiffWithLineNumbers(); } + + /** + * @dataProvider provideStringsThatAreTheSame + */ + public function testEmptyDiffProducesEmptyOutput(string $from, string $to): void + { + $differ = new Differ(new UnifiedDiffOutputBuilder('', false)); + + $output = $differ->diff($from, $to); + + $this->assertEmpty($output); + } + + public function provideStringsThatAreTheSame(): array + { + return [ + ['', ''], + ['a', 'a'], + ['these strings are the same', 'these strings are the same'], + ["\n", "\n"], + ["multi-line strings\nare the same", "multi-line strings\nare the same"], + ]; + } } diff --git a/tests/ParserTest.php b/tests/ParserTest.php index 3999c0fc..0da5ef77 100644 --- a/tests/ParserTest.php +++ b/tests/ParserTest.php @@ -7,18 +7,18 @@ * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ - namespace Localheinz\Diff; -use PHPUnit\Framework\TestCase; +use function unserialize; use Localheinz\Diff\Utils\FileUtils; +use PHPUnit\Framework\TestCase; /** - * @covers Localheinz\Diff\Parser + * @covers \Localheinz\Diff\Parser * - * @uses Localheinz\Diff\Chunk - * @uses Localheinz\Diff\Diff - * @uses Localheinz\Diff\Line + * @uses \Localheinz\Diff\Chunk + * @uses \Localheinz\Diff\Diff + * @uses \Localheinz\Diff\Line */ final class ParserTest extends TestCase { @@ -146,8 +146,7 @@ public function testParseDiffForMulitpleFiles(): void } /** - * @param string $diff - * @param Diff[] $expected + * @psalm-param list $expected * * @dataProvider diffProvider */ @@ -163,7 +162,7 @@ public function diffProvider(): array return [ [ "--- old.txt 2014-11-04 08:51:02.661868729 +0300\n+++ new.txt 2014-11-04 08:51:02.665868730 +0300\n@@ -1,3 +1,4 @@\n+2222111\n 1111111\n 1111111\n 1111111\n@@ -5,10 +6,8 @@\n 1111111\n 1111111\n 1111111\n +1121211\n 1111111\n -1111111\n -1111111\n -2222222\n 2222222\n 2222222\n 2222222\n@@ -17,5 +16,6 @@\n 2222222\n 2222222\n 2222222\n +2122212\n 2222222\n 2222222\n", - \unserialize(FileUtils::getFileContent(__DIR__ . '/fixtures/serialized_diff.bin')), + unserialize(FileUtils::getFileContent(__DIR__ . '/fixtures/serialized_diff.bin')), ], ]; } diff --git a/tests/TimeEfficientImplementationTest.php b/tests/TimeEfficientImplementationTest.php index 5eb36e15..add61c8c 100644 --- a/tests/TimeEfficientImplementationTest.php +++ b/tests/TimeEfficientImplementationTest.php @@ -7,11 +7,10 @@ * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ - namespace Localheinz\Diff; /** - * @covers Localheinz\Diff\TimeEfficientLongestCommonSubsequenceCalculator + * @covers \Localheinz\Diff\TimeEfficientLongestCommonSubsequenceCalculator */ final class TimeEfficientImplementationTest extends LongestCommonSubsequenceTest { diff --git a/tests/Utils/FileUtils.php b/tests/Utils/FileUtils.php index 335171f1..ca3a6b8b 100644 --- a/tests/Utils/FileUtils.php +++ b/tests/Utils/FileUtils.php @@ -7,19 +7,23 @@ * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ - namespace Localheinz\Diff\Utils; +use function error_get_last; +use function file_get_contents; +use function sprintf; +use RuntimeException; + final class FileUtils { public static function getFileContent(string $file): string { - $content = @\file_get_contents($file); + $content = @file_get_contents($file); if (false === $content) { - $error = \error_get_last(); + $error = error_get_last(); - throw new \RuntimeException(\sprintf( + throw new RuntimeException(sprintf( 'Failed to read content of file "%s".%s', $file, $error ? ' ' . $error['message'] : '' diff --git a/tests/Utils/UnifiedDiffAssertTrait.php b/tests/Utils/UnifiedDiffAssertTrait.php index 4518ec80..b36d7a08 100644 --- a/tests/Utils/UnifiedDiffAssertTrait.php +++ b/tests/Utils/UnifiedDiffAssertTrait.php @@ -7,15 +7,24 @@ * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ - namespace Localheinz\Diff\Utils; +use const PREG_SPLIT_DELIM_CAPTURE; +use const PREG_SPLIT_NO_EMPTY; +use function count; +use function preg_match; +use function preg_split; +use function sprintf; +use function strlen; +use function strpos; +use function substr; +use RuntimeException; +use UnexpectedValueException; + trait UnifiedDiffAssertTrait { /** - * @param string $diff - * - * @throws \UnexpectedValueException + * @throws UnexpectedValueException */ public function assertValidUnifiedDiffFormat(string $diff): void { @@ -26,14 +35,14 @@ public function assertValidUnifiedDiffFormat(string $diff): void } // test diff ends with a line break - $last = \substr($diff, -1); + $last = substr($diff, -1); if ("\n" !== $last && "\r" !== $last) { - throw new \UnexpectedValueException(\sprintf('Expected diff to end with a line break, got "%s".', $last)); + throw new UnexpectedValueException(sprintf('Expected diff to end with a line break, got "%s".', $last)); } - $lines = \preg_split('/(.*\R)/', $diff, -1, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY); - $lineCount = \count($lines); + $lines = preg_split('/(.*\R)/', $diff, -1, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY); + $lineCount = count($lines); $lineNumber = $diffLineFromNumber = $diffLineToNumber = 1; $fromStart = $fromTillOffset = $toStart = $toTillOffset = -1; $expectHunkHeader = true; @@ -43,9 +52,9 @@ public function assertValidUnifiedDiffFormat(string $diff): void $this->unifiedDiffAssertLinePrefix($lines[0], 'Line 1.'); $this->unifiedDiffAssertLinePrefix($lines[1], 'Line 2.'); - if ('---' === \substr($lines[0], 0, 3)) { - if ('+++' !== \substr($lines[1], 0, 3)) { - throw new \UnexpectedValueException(\sprintf("Line 1 indicates a header, so line 2 must start with \"+++\".\nLine 1: \"%s\"\nLine 2: \"%s\".", $lines[0], $lines[1])); + if ('---' === substr($lines[0], 0, 3)) { + if ('+++' !== substr($lines[1], 0, 3)) { + throw new UnexpectedValueException(sprintf("Line 1 indicates a header, so line 2 must start with \"+++\".\nLine 1: \"%s\"\nLine 2: \"%s\".", $lines[0], $lines[1])); } $this->unifiedDiffAssertHeaderLine($lines[0], '--- ', 'Line 1.'); @@ -61,33 +70,33 @@ public function assertValidUnifiedDiffFormat(string $diff): void // assert format of lines, get all hunks, test the line numbers for (; $lineNumber <= $lineCount; ++$lineNumber) { if ($diffClosed) { - throw new \UnexpectedValueException(\sprintf('Unexpected line as 2 "No newline" markers have found, ". Line %d.', $lineNumber)); + throw new UnexpectedValueException(sprintf('Unexpected line as 2 "No newline" markers have found, ". Line %d.', $lineNumber)); } $line = $lines[$lineNumber - 1]; // line numbers start by 1, array index at 0 - $type = $this->unifiedDiffAssertLinePrefix($line, \sprintf('Line %d.', $lineNumber)); + $type = $this->unifiedDiffAssertLinePrefix($line, sprintf('Line %d.', $lineNumber)); if ($expectHunkHeader && '@' !== $type && '\\' !== $type) { - throw new \UnexpectedValueException(\sprintf('Expected hunk start (\'@\'), got "%s". Line %d.', $type, $lineNumber)); + throw new UnexpectedValueException(sprintf('Expected hunk start (\'@\'), got "%s". Line %d.', $type, $lineNumber)); } if ('@' === $type) { if (!$expectHunkHeader) { - throw new \UnexpectedValueException(\sprintf('Unexpected hunk start (\'@\'). Line %d.', $lineNumber)); + throw new UnexpectedValueException(sprintf('Unexpected hunk start (\'@\'). Line %d.', $lineNumber)); } $previousHunkFromEnd = $fromStart + $fromTillOffset; $previousHunkTillEnd = $toStart + $toTillOffset; - [$fromStart, $fromTillOffset, $toStart, $toTillOffset] = $this->unifiedDiffAssertHunkHeader($line, \sprintf('Line %d.', $lineNumber)); + [$fromStart, $fromTillOffset, $toStart, $toTillOffset] = $this->unifiedDiffAssertHunkHeader($line, sprintf('Line %d.', $lineNumber)); // detect overlapping hunks if ($fromStart < $previousHunkFromEnd) { - throw new \UnexpectedValueException(\sprintf('Unexpected new hunk; "from" (\'-\') start overlaps previous hunk. Line %d.', $lineNumber)); + throw new UnexpectedValueException(sprintf('Unexpected new hunk; "from" (\'-\') start overlaps previous hunk. Line %d.', $lineNumber)); } if ($toStart < $previousHunkTillEnd) { - throw new \UnexpectedValueException(\sprintf('Unexpected new hunk; "to" (\'+\') start overlaps previous hunk. Line %d.', $lineNumber)); + throw new UnexpectedValueException(sprintf('Unexpected new hunk; "to" (\'+\') start overlaps previous hunk. Line %d.', $lineNumber)); } /* valid states; hunks touches against each other: @@ -104,73 +113,69 @@ public function assertValidUnifiedDiffFormat(string $diff): void if ('-' === $type) { if (isset($endOfLineTypes['-'])) { - throw new \UnexpectedValueException(\sprintf('Not expected from (\'-\'), already closed by "\\ No newline at end of file". Line %d.', $lineNumber)); + throw new UnexpectedValueException(sprintf('Not expected from (\'-\'), already closed by "\\ No newline at end of file". Line %d.', $lineNumber)); } ++$diffLineFromNumber; } elseif ('+' === $type) { if (isset($endOfLineTypes['+'])) { - throw new \UnexpectedValueException(\sprintf('Not expected to (\'+\'), already closed by "\\ No newline at end of file". Line %d.', $lineNumber)); + throw new UnexpectedValueException(sprintf('Not expected to (\'+\'), already closed by "\\ No newline at end of file". Line %d.', $lineNumber)); } ++$diffLineToNumber; } elseif (' ' === $type) { if (isset($endOfLineTypes['-'])) { - throw new \UnexpectedValueException(\sprintf('Not expected same (\' \'), \'-\' already closed by "\\ No newline at end of file". Line %d.', $lineNumber)); + throw new UnexpectedValueException(sprintf('Not expected same (\' \'), \'-\' already closed by "\\ No newline at end of file". Line %d.', $lineNumber)); } if (isset($endOfLineTypes['+'])) { - throw new \UnexpectedValueException(\sprintf('Not expected same (\' \'), \'+\' already closed by "\\ No newline at end of file". Line %d.', $lineNumber)); + throw new UnexpectedValueException(sprintf('Not expected same (\' \'), \'+\' already closed by "\\ No newline at end of file". Line %d.', $lineNumber)); } ++$diffLineFromNumber; ++$diffLineToNumber; } elseif ('\\' === $type) { if (!isset($lines[$lineNumber - 2])) { - throw new \UnexpectedValueException(\sprintf('Unexpected "\\ No newline at end of file", it must be preceded by \'+\' or \'-\' line. Line %d.', $lineNumber)); + throw new UnexpectedValueException(sprintf('Unexpected "\\ No newline at end of file", it must be preceded by \'+\' or \'-\' line. Line %d.', $lineNumber)); } - $previousType = $this->unifiedDiffAssertLinePrefix($lines[$lineNumber - 2], \sprintf('Preceding line of "\\ No newline at end of file" of unexpected format. Line %d.', $lineNumber)); + $previousType = $this->unifiedDiffAssertLinePrefix($lines[$lineNumber - 2], sprintf('Preceding line of "\\ No newline at end of file" of unexpected format. Line %d.', $lineNumber)); if (isset($endOfLineTypes[$previousType])) { - throw new \UnexpectedValueException(\sprintf('Unexpected "\\ No newline at end of file", "%s" was already closed. Line %d.', $type, $lineNumber)); + throw new UnexpectedValueException(sprintf('Unexpected "\\ No newline at end of file", "%s" was already closed. Line %d.', $type, $lineNumber)); } $endOfLineTypes[$previousType] = true; - $diffClosed = \count($endOfLineTypes) > 1; + $diffClosed = count($endOfLineTypes) > 1; } else { // internal state error - throw new \RuntimeException(\sprintf('Unexpected line type "%s" Line %d.', $type, $lineNumber)); + throw new RuntimeException(sprintf('Unexpected line type "%s" Line %d.', $type, $lineNumber)); } $expectHunkHeader = $diffLineFromNumber === ($fromStart + $fromTillOffset) - && $diffLineToNumber === ($toStart + $toTillOffset) - ; + && $diffLineToNumber === ($toStart + $toTillOffset); } if ( $diffLineFromNumber !== ($fromStart + $fromTillOffset) && $diffLineToNumber !== ($toStart + $toTillOffset) ) { - throw new \UnexpectedValueException(\sprintf('Unexpected EOF, number of lines in hunk "from" (\'-\')) and "to" (\'+\') mismatched. Line %d.', $lineNumber)); + throw new UnexpectedValueException(sprintf('Unexpected EOF, number of lines in hunk "from" (\'-\')) and "to" (\'+\') mismatched. Line %d.', $lineNumber)); } if ($diffLineFromNumber !== ($fromStart + $fromTillOffset)) { - throw new \UnexpectedValueException(\sprintf('Unexpected EOF, number of lines in hunk "from" (\'-\')) mismatched. Line %d.', $lineNumber)); + throw new UnexpectedValueException(sprintf('Unexpected EOF, number of lines in hunk "from" (\'-\')) mismatched. Line %d.', $lineNumber)); } if ($diffLineToNumber !== ($toStart + $toTillOffset)) { - throw new \UnexpectedValueException(\sprintf('Unexpected EOF, number of lines in hunk "to" (\'+\')) mismatched. Line %d.', $lineNumber)); + throw new UnexpectedValueException(sprintf('Unexpected EOF, number of lines in hunk "to" (\'+\')) mismatched. Line %d.', $lineNumber)); } $this->addToAssertionCount(1); } /** - * @param string $line - * @param string $message - * * @return string '+', '-', '@', ' ' or '\' */ private function unifiedDiffAssertLinePrefix(string $line, string $message): string @@ -186,49 +191,45 @@ private function unifiedDiffAssertLinePrefix(string $line, string $message): str return '\\'; } - throw new \UnexpectedValueException(\sprintf('Expected line to start with \'@\', \'-\' or \'+\', got "%s". %s', $line, $message)); + throw new UnexpectedValueException(sprintf('Expected line to start with \'@\', \'-\' or \'+\', got "%s". %s', $line, $message)); } private function unifiedDiffAssertStrLength(string $line, int $min, string $message): void { - $length = \strlen($line); + $length = strlen($line); if ($length < $min) { - throw new \UnexpectedValueException(\sprintf('Expected string length of minimal %d, got %d. %s', $min, $length, $message)); + throw new UnexpectedValueException(sprintf('Expected string length of minimal %d, got %d. %s', $min, $length, $message)); } } /** - * Assert valid unified diff header line + * Assert valid unified diff header line. * * Samples: * - "+++ from1.txt\t2017-08-24 19:51:29.383985722 +0200" * - "+++ from1.txt" - * - * @param string $line - * @param string $start - * @param string $message */ private function unifiedDiffAssertHeaderLine(string $line, string $start, string $message): void { - if (0 !== \strpos($line, $start)) { - throw new \UnexpectedValueException(\sprintf('Expected header line to start with "%s", got "%s". %s', $start . ' ', $line, $message)); + if (0 !== strpos($line, $start)) { + throw new UnexpectedValueException(sprintf('Expected header line to start with "%s", got "%s". %s', $start . ' ', $line, $message)); } // sample "+++ from1.txt\t2017-08-24 19:51:29.383985722 +0200\n" - $match = \preg_match( + $match = preg_match( "/^([^\t]*)(?:[\t]([\\S].*[\\S]))?\n$/", - \substr($line, 4), // 4 === string length of "+++ " / "--- " + substr($line, 4), // 4 === string length of "+++ " / "--- " $matches ); if (1 !== $match) { - throw new \UnexpectedValueException(\sprintf('Header line does not match expected pattern, got "%s". %s', $line, $message)); + throw new UnexpectedValueException(sprintf('Header line does not match expected pattern, got "%s". %s', $line, $message)); } // $file = $matches[1]; - if (\count($matches) > 2) { + if (count($matches) > 2) { $this->unifiedDiffAssertHeaderDate($matches[2], $message); } } @@ -236,30 +237,27 @@ private function unifiedDiffAssertHeaderLine(string $line, string $start, string private function unifiedDiffAssertHeaderDate(string $date, string $message): void { // sample "2017-08-24 19:51:29.383985722 +0200" - $match = \preg_match( + $match = preg_match( '/^([\d]{4})-([01]?[\d])-([0123]?[\d])(:? [\d]{1,2}:[\d]{1,2}(?::[\d]{1,2}(:?\.[\d]+)?)?(?: ([\+\-][\d]{4}))?)?$/', $date, $matches ); - if (1 !== $match || ($matchesCount = \count($matches)) < 4) { - throw new \UnexpectedValueException(\sprintf('Date of header line does not match expected pattern, got "%s". %s', $date, $message)); + if (1 !== $match || ($matchesCount = count($matches)) < 4) { + throw new UnexpectedValueException(sprintf('Date of header line does not match expected pattern, got "%s". %s', $date, $message)); } // [$full, $year, $month, $day, $time] = $matches; } /** - * @param string $line - * @param string $message - * * @return int[] */ private function unifiedDiffAssertHunkHeader(string $line, string $message): array { - if (1 !== \preg_match('#^@@ -([\d]+)((?:,[\d]+)?) \+([\d]+)((?:,[\d]+)?) @@\n$#', $line, $matches)) { - throw new \UnexpectedValueException( - \sprintf( + if (1 !== preg_match('#^@@ -([\d]+)((?:,[\d]+)?) \+([\d]+)((?:,[\d]+)?) @@\n$#', $line, $matches)) { + throw new UnexpectedValueException( + sprintf( 'Hunk header line does not match expected pattern, got "%s". %s', $line, $message @@ -269,9 +267,9 @@ private function unifiedDiffAssertHunkHeader(string $line, string $message): arr return [ (int) $matches[1], - empty($matches[2]) ? 1 : (int) \substr($matches[2], 1), + empty($matches[2]) ? 1 : (int) substr($matches[2], 1), (int) $matches[3], - empty($matches[4]) ? 1 : (int) \substr($matches[4], 1), + empty($matches[4]) ? 1 : (int) substr($matches[4], 1), ]; } } diff --git a/tests/Utils/UnifiedDiffAssertTraitIntegrationTest.php b/tests/Utils/UnifiedDiffAssertTraitIntegrationTest.php index 19d7e11c..3fdd7e2e 100644 --- a/tests/Utils/UnifiedDiffAssertTraitIntegrationTest.php +++ b/tests/Utils/UnifiedDiffAssertTraitIntegrationTest.php @@ -7,10 +7,18 @@ * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ - namespace Localheinz\Diff\Utils; +use function file_exists; +use function realpath; +use function sprintf; +use function strlen; +use function substr; +use function unlink; use PHPUnit\Framework\TestCase; +use RecursiveDirectoryIterator; +use RecursiveIteratorIterator; +use SplFileInfo; use Symfony\Component\Process\Process; /** @@ -37,23 +45,20 @@ protected function tearDown(): void } /** - * @param string $fileFrom - * @param string $fileTo - * * @dataProvider provideFilePairsCases */ public function testValidPatches(string $fileFrom, string $fileTo): void { - $command = \sprintf( - 'diff -u %s %s > %s', - \escapeshellarg(\realpath($fileFrom)), - \escapeshellarg(\realpath($fileTo)), - \escapeshellarg($this->filePatch) + $p = Process::fromShellCommandline('diff -u $from $to > $patch'); + $p->run( + null, + [ + 'from' => realpath($fileFrom), + 'to' => realpath($fileTo), + 'patch' => $this->filePatch, + ] ); - $p = new Process($command); - $p->run(); - $exitCode = $p->getExitCode(); if (0 === $exitCode) { @@ -66,9 +71,9 @@ public function testValidPatches(string $fileFrom, string $fileTo): void $this->assertSame( 1, // means `diff` found a diff between the files we gave it $exitCode, - \sprintf( + sprintf( "Command exec. was not successful:\n\"%s\"\nOutput:\n\"%s\"\nStdErr:\n\"%s\"\nExit code %d.\n", - $command, + $p->getCommandLine(), $p->getOutput(), $p->getErrorOutput(), $p->getExitCode() @@ -86,36 +91,36 @@ public function provideFilePairsCases(): array $cases = []; // created cases based on dedicated fixtures - $dir = \realpath(__DIR__ . '/../fixtures/UnifiedDiffAssertTraitIntegrationTest'); - $dirLength = \strlen($dir); + $dir = realpath(__DIR__ . '/../fixtures/UnifiedDiffAssertTraitIntegrationTest'); + $dirLength = strlen($dir); for ($i = 1;; ++$i) { - $fromFile = \sprintf('%s/%d_a.txt', $dir, $i); - $toFile = \sprintf('%s/%d_b.txt', $dir, $i); + $fromFile = sprintf('%s/%d_a.txt', $dir, $i); + $toFile = sprintf('%s/%d_b.txt', $dir, $i); - if (!\file_exists($fromFile)) { + if (!file_exists($fromFile)) { break; } $this->assertFileExists($toFile); - $cases[\sprintf("Diff file:\n\"%s\"\nvs.\n\"%s\"\n", \substr(\realpath($fromFile), $dirLength), \substr(\realpath($toFile), $dirLength))] = [$fromFile, $toFile]; + $cases[sprintf("Diff file:\n\"%s\"\nvs.\n\"%s\"\n", substr(realpath($fromFile), $dirLength), substr(realpath($toFile), $dirLength))] = [$fromFile, $toFile]; } // create cases based on PHP files within the vendor directory for integration testing - $dir = \realpath(__DIR__ . '/../../vendor'); - $dirLength = \strlen($dir); + $dir = realpath(__DIR__ . '/../../vendor'); + $dirLength = strlen($dir); - $fileIterator = new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($dir, \RecursiveDirectoryIterator::SKIP_DOTS)); + $fileIterator = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($dir, RecursiveDirectoryIterator::SKIP_DOTS)); $fromFile = __FILE__; - /** @var \SplFileInfo $file */ + /** @var SplFileInfo $file */ foreach ($fileIterator as $file) { if ('php' !== $file->getExtension()) { continue; } $toFile = $file->getPathname(); - $cases[\sprintf("Diff file:\n\"%s\"\nvs.\n\"%s\"\n", \substr(\realpath($fromFile), $dirLength), \substr(\realpath($toFile), $dirLength))] = [$fromFile, $toFile]; + $cases[sprintf("Diff file:\n\"%s\"\nvs.\n\"%s\"\n", substr(realpath($fromFile), $dirLength), substr(realpath($toFile), $dirLength))] = [$fromFile, $toFile]; $fromFile = $toFile; } @@ -124,6 +129,6 @@ public function provideFilePairsCases(): array private function cleanUpTempFiles(): void { - @\unlink($this->filePatch); + @unlink($this->filePatch); } } diff --git a/tests/Utils/UnifiedDiffAssertTraitTest.php b/tests/Utils/UnifiedDiffAssertTraitTest.php index 5c7d0aef..943d6fde 100644 --- a/tests/Utils/UnifiedDiffAssertTraitTest.php +++ b/tests/Utils/UnifiedDiffAssertTraitTest.php @@ -7,21 +7,21 @@ * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ - namespace Localheinz\Diff\Utils; +use function preg_quote; +use function sprintf; use PHPUnit\Framework\TestCase; +use UnexpectedValueException; /** - * @covers Localheinz\Diff\Utils\UnifiedDiffAssertTrait + * @covers \Localheinz\Diff\Utils\UnifiedDiffAssertTrait */ final class UnifiedDiffAssertTraitTest extends TestCase { use UnifiedDiffAssertTrait; /** - * @param string $diff - * * @dataProvider provideValidCases */ public function testValidCases(string $diff): void @@ -33,7 +33,7 @@ public function provideValidCases(): array { return [ [ -'--- Original + '--- Original +++ New @@ -8 +8 @@ -Z @@ -41,7 +41,7 @@ public function provideValidCases(): array ', ], [ -'--- Original + '--- Original +++ New @@ -8 +8 @@ -Z @@ -59,43 +59,43 @@ public function provideValidCases(): array public function testNoLinebreakEnd(): void { - $this->expectException(\UnexpectedValueException::class); - $this->expectExceptionMessageRegExp(\sprintf('#^%s$#', \preg_quote('Expected diff to end with a line break, got "C".', '#'))); + $this->expectException(UnexpectedValueException::class); + $this->expectExceptionMessageRegExp(sprintf('#^%s$#', preg_quote('Expected diff to end with a line break, got "C".', '#'))); $this->assertValidUnifiedDiffFormat("A\nB\nC"); } public function testInvalidStartWithoutHeader(): void { - $this->expectException(\UnexpectedValueException::class); - $this->expectExceptionMessageRegExp(\sprintf('#^%s$#', \preg_quote("Expected line to start with '@', '-' or '+', got \"A\n\". Line 1.", '#'))); + $this->expectException(UnexpectedValueException::class); + $this->expectExceptionMessageRegExp(sprintf('#^%s$#', preg_quote("Expected line to start with '@', '-' or '+', got \"A\n\". Line 1.", '#'))); $this->assertValidUnifiedDiffFormat("A\n"); } public function testInvalidStartHeader1(): void { - $this->expectException(\UnexpectedValueException::class); - $this->expectExceptionMessageRegExp(\sprintf('#^%s$#', \preg_quote("Line 1 indicates a header, so line 2 must start with \"+++\".\nLine 1: \"--- A\n\"\nLine 2: \"+ 1\n\".", '#'))); + $this->expectException(UnexpectedValueException::class); + $this->expectExceptionMessageRegExp(sprintf('#^%s$#', preg_quote("Line 1 indicates a header, so line 2 must start with \"+++\".\nLine 1: \"--- A\n\"\nLine 2: \"+ 1\n\".", '#'))); $this->assertValidUnifiedDiffFormat("--- A\n+ 1\n"); } public function testInvalidStartHeader2(): void { - $this->expectException(\UnexpectedValueException::class); - $this->expectExceptionMessageRegExp(\sprintf('#^%s$#', \preg_quote("Header line does not match expected pattern, got \"+++ file X\n\". Line 2.", '#'))); + $this->expectException(UnexpectedValueException::class); + $this->expectExceptionMessageRegExp(sprintf('#^%s$#', preg_quote("Header line does not match expected pattern, got \"+++ file X\n\". Line 2.", '#'))); $this->assertValidUnifiedDiffFormat("--- A\n+++ file\tX\n"); } public function testInvalidStartHeader3(): void { - $this->expectException(\UnexpectedValueException::class); - $this->expectExceptionMessageRegExp(\sprintf('#^%s$#', \preg_quote('Date of header line does not match expected pattern, got "[invalid date]". Line 1.', '#'))); + $this->expectException(UnexpectedValueException::class); + $this->expectExceptionMessageRegExp(sprintf('#^%s$#', preg_quote('Date of header line does not match expected pattern, got "[invalid date]". Line 1.', '#'))); $this->assertValidUnifiedDiffFormat( -"--- Original\t[invalid date] + "--- Original\t[invalid date] +++ New @@ -1,2 +1,2 @@ -A @@ -107,11 +107,11 @@ public function testInvalidStartHeader3(): void public function testInvalidStartHeader4(): void { - $this->expectException(\UnexpectedValueException::class); - $this->expectExceptionMessageRegExp(\sprintf('#^%s$#', \preg_quote("Expected header line to start with \"+++ \", got \"+++INVALID\n\". Line 2.", '#'))); + $this->expectException(UnexpectedValueException::class); + $this->expectExceptionMessageRegExp(sprintf('#^%s$#', preg_quote("Expected header line to start with \"+++ \", got \"+++INVALID\n\". Line 2.", '#'))); $this->assertValidUnifiedDiffFormat( -'--- Original + '--- Original +++INVALID @@ -1,2 +1,2 @@ -A @@ -123,11 +123,11 @@ public function testInvalidStartHeader4(): void public function testInvalidLine1(): void { - $this->expectException(\UnexpectedValueException::class); - $this->expectExceptionMessageRegExp(\sprintf('#^%s$#', \preg_quote("Expected line to start with '@', '-' or '+', got \"1\n\". Line 5.", '#'))); + $this->expectException(UnexpectedValueException::class); + $this->expectExceptionMessageRegExp(sprintf('#^%s$#', preg_quote("Expected line to start with '@', '-' or '+', got \"1\n\". Line 5.", '#'))); $this->assertValidUnifiedDiffFormat( -'--- Original + '--- Original +++ New @@ -8 +8 @@ -Z @@ -139,11 +139,11 @@ public function testInvalidLine1(): void public function testInvalidLine2(): void { - $this->expectException(\UnexpectedValueException::class); - $this->expectExceptionMessageRegExp(\sprintf('#^%s$#', \preg_quote('Expected string length of minimal 2, got 1. Line 4.', '#'))); + $this->expectException(UnexpectedValueException::class); + $this->expectExceptionMessageRegExp(sprintf('#^%s$#', preg_quote('Expected string length of minimal 2, got 1. Line 4.', '#'))); $this->assertValidUnifiedDiffFormat( -'--- Original + '--- Original +++ New @@ -8 +8 @@ @@ -154,11 +154,11 @@ public function testInvalidLine2(): void public function testHunkInvalidFormat(): void { - $this->expectException(\UnexpectedValueException::class); - $this->expectExceptionMessageRegExp(\sprintf('#^%s$#', \preg_quote("Hunk header line does not match expected pattern, got \"@@ INVALID -1,1 +1,1 @@\n\". Line 3.", '#'))); + $this->expectException(UnexpectedValueException::class); + $this->expectExceptionMessageRegExp(sprintf('#^%s$#', preg_quote("Hunk header line does not match expected pattern, got \"@@ INVALID -1,1 +1,1 @@\n\". Line 3.", '#'))); $this->assertValidUnifiedDiffFormat( -'--- Original + '--- Original +++ New @@ INVALID -1,1 +1,1 @@ -Z @@ -169,11 +169,11 @@ public function testHunkInvalidFormat(): void public function testHunkOverlapFrom(): void { - $this->expectException(\UnexpectedValueException::class); - $this->expectExceptionMessageRegExp(\sprintf('#^%s$#', \preg_quote('Unexpected new hunk; "from" (\'-\') start overlaps previous hunk. Line 6.', '#'))); + $this->expectException(UnexpectedValueException::class); + $this->expectExceptionMessageRegExp(sprintf('#^%s$#', preg_quote('Unexpected new hunk; "from" (\'-\') start overlaps previous hunk. Line 6.', '#'))); $this->assertValidUnifiedDiffFormat( -'--- Original + '--- Original +++ New @@ -8,1 +8,1 @@ -Z @@ -187,11 +187,11 @@ public function testHunkOverlapFrom(): void public function testHunkOverlapTo(): void { - $this->expectException(\UnexpectedValueException::class); - $this->expectExceptionMessageRegExp(\sprintf('#^%s$#', \preg_quote('Unexpected new hunk; "to" (\'+\') start overlaps previous hunk. Line 6.', '#'))); + $this->expectException(UnexpectedValueException::class); + $this->expectExceptionMessageRegExp(sprintf('#^%s$#', preg_quote('Unexpected new hunk; "to" (\'+\') start overlaps previous hunk. Line 6.', '#'))); $this->assertValidUnifiedDiffFormat( -'--- Original + '--- Original +++ New @@ -8,1 +8,1 @@ -Z @@ -205,11 +205,11 @@ public function testHunkOverlapTo(): void public function testExpectHunk1(): void { - $this->expectException(\UnexpectedValueException::class); - $this->expectExceptionMessageRegExp(\sprintf('#^%s$#', \preg_quote('Expected hunk start (\'@\'), got "+". Line 6.', '#'))); + $this->expectException(UnexpectedValueException::class); + $this->expectExceptionMessageRegExp(sprintf('#^%s$#', preg_quote('Expected hunk start (\'@\'), got "+". Line 6.', '#'))); $this->assertValidUnifiedDiffFormat( -'--- Original + '--- Original +++ New @@ -8 +8 @@ -Z @@ -221,11 +221,11 @@ public function testExpectHunk1(): void public function testExpectHunk2(): void { - $this->expectException(\UnexpectedValueException::class); - $this->expectExceptionMessageRegExp(\sprintf('#^%s$#', \preg_quote('Unexpected hunk start (\'@\'). Line 6.', '#'))); + $this->expectException(UnexpectedValueException::class); + $this->expectExceptionMessageRegExp(sprintf('#^%s$#', preg_quote('Unexpected hunk start (\'@\'). Line 6.', '#'))); $this->assertValidUnifiedDiffFormat( -'--- Original + '--- Original +++ New @@ -8,12 +8,12 @@ ' . ' @@ -237,11 +237,11 @@ public function testExpectHunk2(): void public function testMisplacedLineAfterComments1(): void { - $this->expectException(\UnexpectedValueException::class); - $this->expectExceptionMessageRegExp(\sprintf('#^%s$#', \preg_quote('Unexpected line as 2 "No newline" markers have found, ". Line 8.', '#'))); + $this->expectException(UnexpectedValueException::class); + $this->expectExceptionMessageRegExp(sprintf('#^%s$#', preg_quote('Unexpected line as 2 "No newline" markers have found, ". Line 8.', '#'))); $this->assertValidUnifiedDiffFormat( -'--- Original + '--- Original +++ New @@ -8 +8 @@ -Z @@ -255,11 +255,11 @@ public function testMisplacedLineAfterComments1(): void public function testMisplacedLineAfterComments2(): void { - $this->expectException(\UnexpectedValueException::class); - $this->expectExceptionMessageRegExp(\sprintf('#^%s$#', \preg_quote('Unexpected line as 2 "No newline" markers have found, ". Line 7.', '#'))); + $this->expectException(UnexpectedValueException::class); + $this->expectExceptionMessageRegExp(sprintf('#^%s$#', preg_quote('Unexpected line as 2 "No newline" markers have found, ". Line 7.', '#'))); $this->assertValidUnifiedDiffFormat( -'--- Original + '--- Original +++ New @@ -8 +8 @@ +U @@ -272,11 +272,11 @@ public function testMisplacedLineAfterComments2(): void public function testMisplacedLineAfterComments3(): void { - $this->expectException(\UnexpectedValueException::class); - $this->expectExceptionMessageRegExp(\sprintf('#^%s$#', \preg_quote('Unexpected line as 2 "No newline" markers have found, ". Line 7.', '#'))); + $this->expectException(UnexpectedValueException::class); + $this->expectExceptionMessageRegExp(sprintf('#^%s$#', preg_quote('Unexpected line as 2 "No newline" markers have found, ". Line 7.', '#'))); $this->assertValidUnifiedDiffFormat( -'--- Original + '--- Original +++ New @@ -8 +8 @@ +U @@ -289,22 +289,22 @@ public function testMisplacedLineAfterComments3(): void public function testMisplacedComment(): void { - $this->expectException(\UnexpectedValueException::class); - $this->expectExceptionMessageRegExp(\sprintf('#^%s$#', \preg_quote('Unexpected "\ No newline at end of file", it must be preceded by \'+\' or \'-\' line. Line 1.', '#'))); + $this->expectException(UnexpectedValueException::class); + $this->expectExceptionMessageRegExp(sprintf('#^%s$#', preg_quote('Unexpected "\ No newline at end of file", it must be preceded by \'+\' or \'-\' line. Line 1.', '#'))); $this->assertValidUnifiedDiffFormat( -'\ No newline at end of file + '\ No newline at end of file ' ); } public function testUnexpectedDuplicateNoNewLineEOF(): void { - $this->expectException(\UnexpectedValueException::class); - $this->expectExceptionMessageRegExp(\sprintf('#^%s$#', \preg_quote('Unexpected "\\ No newline at end of file", "\\" was already closed. Line 8.', '#'))); + $this->expectException(UnexpectedValueException::class); + $this->expectExceptionMessageRegExp(sprintf('#^%s$#', preg_quote('Unexpected "\\ No newline at end of file", "\\" was already closed. Line 8.', '#'))); $this->assertValidUnifiedDiffFormat( -'--- Original + '--- Original +++ New @@ -8,12 +8,12 @@ ' . ' @@ -318,11 +318,11 @@ public function testUnexpectedDuplicateNoNewLineEOF(): void public function testFromAfterClose(): void { - $this->expectException(\UnexpectedValueException::class); - $this->expectExceptionMessageRegExp(\sprintf('#^%s$#', \preg_quote('Not expected from (\'-\'), already closed by "\ No newline at end of file". Line 6.', '#'))); + $this->expectException(UnexpectedValueException::class); + $this->expectExceptionMessageRegExp(sprintf('#^%s$#', preg_quote('Not expected from (\'-\'), already closed by "\ No newline at end of file". Line 6.', '#'))); $this->assertValidUnifiedDiffFormat( -'--- Original + '--- Original +++ New @@ -8,12 +8,12 @@ -A @@ -335,8 +335,8 @@ public function testFromAfterClose(): void public function testSameAfterFromClose(): void { - $this->expectException(\UnexpectedValueException::class); - $this->expectExceptionMessageRegExp(\sprintf('#^%s$#', \preg_quote('Not expected same (\' \'), \'-\' already closed by "\ No newline at end of file". Line 6.', '#'))); + $this->expectException(UnexpectedValueException::class); + $this->expectExceptionMessageRegExp(sprintf('#^%s$#', preg_quote('Not expected same (\' \'), \'-\' already closed by "\ No newline at end of file". Line 6.', '#'))); $this->assertValidUnifiedDiffFormat( '--- Original @@ -352,8 +352,8 @@ public function testSameAfterFromClose(): void public function testToAfterClose(): void { - $this->expectException(\UnexpectedValueException::class); - $this->expectExceptionMessageRegExp(\sprintf('#^%s$#', \preg_quote('Not expected to (\'+\'), already closed by "\ No newline at end of file". Line 6.', '#'))); + $this->expectException(UnexpectedValueException::class); + $this->expectExceptionMessageRegExp(sprintf('#^%s$#', preg_quote('Not expected to (\'+\'), already closed by "\ No newline at end of file". Line 6.', '#'))); $this->assertValidUnifiedDiffFormat( '--- Original @@ -369,8 +369,8 @@ public function testToAfterClose(): void public function testSameAfterToClose(): void { - $this->expectException(\UnexpectedValueException::class); - $this->expectExceptionMessageRegExp(\sprintf('#^%s$#', \preg_quote('Not expected same (\' \'), \'+\' already closed by "\ No newline at end of file". Line 6.', '#'))); + $this->expectException(UnexpectedValueException::class); + $this->expectExceptionMessageRegExp(sprintf('#^%s$#', preg_quote('Not expected same (\' \'), \'+\' already closed by "\ No newline at end of file". Line 6.', '#'))); $this->assertValidUnifiedDiffFormat( '--- Original @@ -386,11 +386,11 @@ public function testSameAfterToClose(): void public function testUnexpectedEOFFromMissingLines(): void { - $this->expectException(\UnexpectedValueException::class); - $this->expectExceptionMessageRegExp(\sprintf('#^%s$#', \preg_quote('Unexpected EOF, number of lines in hunk "from" (\'-\')) mismatched. Line 7.', '#'))); + $this->expectException(UnexpectedValueException::class); + $this->expectExceptionMessageRegExp(sprintf('#^%s$#', preg_quote('Unexpected EOF, number of lines in hunk "from" (\'-\')) mismatched. Line 7.', '#'))); $this->assertValidUnifiedDiffFormat( -'--- Original + '--- Original +++ New @@ -8,19 +7,2 @@ -A @@ -402,11 +402,11 @@ public function testUnexpectedEOFFromMissingLines(): void public function testUnexpectedEOFToMissingLines(): void { - $this->expectException(\UnexpectedValueException::class); - $this->expectExceptionMessageRegExp(\sprintf('#^%s$#', \preg_quote('Unexpected EOF, number of lines in hunk "to" (\'+\')) mismatched. Line 7.', '#'))); + $this->expectException(UnexpectedValueException::class); + $this->expectExceptionMessageRegExp(sprintf('#^%s$#', preg_quote('Unexpected EOF, number of lines in hunk "to" (\'+\')) mismatched. Line 7.', '#'))); $this->assertValidUnifiedDiffFormat( -'--- Original + '--- Original +++ New @@ -8,2 +7,3 @@ -A @@ -418,11 +418,11 @@ public function testUnexpectedEOFToMissingLines(): void public function testUnexpectedEOFBothFromAndToMissingLines(): void { - $this->expectException(\UnexpectedValueException::class); - $this->expectExceptionMessageRegExp(\sprintf('#^%s$#', \preg_quote('Unexpected EOF, number of lines in hunk "from" (\'-\')) and "to" (\'+\') mismatched. Line 7.', '#'))); + $this->expectException(UnexpectedValueException::class); + $this->expectExceptionMessageRegExp(sprintf('#^%s$#', preg_quote('Unexpected EOF, number of lines in hunk "from" (\'-\')) and "to" (\'+\') mismatched. Line 7.', '#'))); $this->assertValidUnifiedDiffFormat( -'--- Original + '--- Original +++ New @@ -1,12 +1,14 @@ -A diff --git a/tools/composer-normalize b/tools/composer-normalize new file mode 100755 index 00000000..86188d64 Binary files /dev/null and b/tools/composer-normalize differ diff --git a/tools/php-cs-fixer b/tools/php-cs-fixer new file mode 100755 index 00000000..859a4c38 Binary files /dev/null and b/tools/php-cs-fixer differ diff --git a/tools/psalm b/tools/psalm new file mode 100755 index 00000000..81abe7e1 Binary files /dev/null and b/tools/psalm differ diff --git a/tools/roave-backward-compatibility-check b/tools/roave-backward-compatibility-check new file mode 100755 index 00000000..f6fc5ec0 Binary files /dev/null and b/tools/roave-backward-compatibility-check differ