FixerFactoryTest.php 36 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710
  1. <?php
  2. declare(strict_types=1);
  3. /*
  4. * This file is part of PHP CS Fixer.
  5. *
  6. * (c) Fabien Potencier <fabien@symfony.com>
  7. * Dariusz Rumiński <dariusz.ruminski@gmail.com>
  8. *
  9. * This source file is subject to the MIT license that is bundled
  10. * with this source code in the file LICENSE.
  11. */
  12. namespace PhpCsFixer\Tests\AutoReview;
  13. use PhpCsFixer\Fixer\FixerInterface;
  14. use PhpCsFixer\FixerFactory;
  15. use PhpCsFixer\Tests\Test\IntegrationCaseFactory;
  16. use PhpCsFixer\Tests\TestCase;
  17. use Symfony\Component\Finder\SplFileInfo;
  18. /**
  19. * @author Dariusz Rumiński <dariusz.ruminski@gmail.com>
  20. *
  21. * @internal
  22. *
  23. * @coversNothing
  24. * @group auto-review
  25. * @group covers-nothing
  26. */
  27. final class FixerFactoryTest extends TestCase
  28. {
  29. public function testFixersPriorityEdgeFixers(): void
  30. {
  31. $factory = new FixerFactory();
  32. $factory->registerBuiltInFixers();
  33. $fixers = $factory->getFixers();
  34. foreach (self::getFixerWithFixedPosition() as $fixerName => $offset) {
  35. if ($offset < 0) {
  36. static::assertSame($fixerName, $fixers[\count($fixers) + $offset]->getName(), $fixerName);
  37. } else {
  38. static::assertSame($fixerName, $fixers[$offset]->getName(), $fixerName);
  39. }
  40. }
  41. }
  42. /**
  43. * @dataProvider provideFixersPriorityCases
  44. * @dataProvider provideFixersPrioritySpecialPhpdocCases
  45. */
  46. public function testFixersPriority(FixerInterface $first, FixerInterface $second): void
  47. {
  48. static::assertLessThan($first->getPriority(), $second->getPriority(), sprintf('"%s" should have less priority than "%s"', \get_class($second), \get_class($first)));
  49. }
  50. public function provideFixersPriorityCases(): array
  51. {
  52. $factory = new FixerFactory();
  53. $factory->registerBuiltInFixers();
  54. $fixers = [];
  55. foreach ($factory->getFixers() as $fixer) {
  56. $fixers[$fixer->getName()] = $fixer;
  57. }
  58. return [
  59. [$fixers['align_multiline_comment'], $fixers['phpdoc_trim_consecutive_blank_line_separation']],
  60. [$fixers['array_indentation'], $fixers['align_multiline_comment']],
  61. [$fixers['array_indentation'], $fixers['binary_operator_spaces']],
  62. [$fixers['array_syntax'], $fixers['binary_operator_spaces']],
  63. [$fixers['array_syntax'], $fixers['ternary_operator_spaces']],
  64. [$fixers['assign_null_coalescing_to_coalesce_equal'], $fixers['binary_operator_spaces']],
  65. [$fixers['assign_null_coalescing_to_coalesce_equal'], $fixers['no_whitespace_in_blank_line']],
  66. [$fixers['backtick_to_shell_exec'], $fixers['escape_implicit_backslashes']],
  67. [$fixers['backtick_to_shell_exec'], $fixers['explicit_string_variable']],
  68. [$fixers['backtick_to_shell_exec'], $fixers['native_function_invocation']],
  69. [$fixers['backtick_to_shell_exec'], $fixers['single_quote']],
  70. [$fixers['blank_line_after_opening_tag'], $fixers['no_blank_lines_before_namespace']],
  71. [$fixers['braces'], $fixers['array_indentation']],
  72. [$fixers['braces'], $fixers['method_argument_space']],
  73. [$fixers['braces'], $fixers['method_chaining_indentation']],
  74. [$fixers['class_attributes_separation'], $fixers['braces']],
  75. [$fixers['class_attributes_separation'], $fixers['indentation_type']],
  76. [$fixers['class_attributes_separation'], $fixers['no_extra_blank_lines']],
  77. [$fixers['class_definition'], $fixers['braces']],
  78. [$fixers['class_keyword_remove'], $fixers['no_unused_imports']],
  79. [$fixers['combine_consecutive_issets'], $fixers['multiline_whitespace_before_semicolons']],
  80. [$fixers['combine_consecutive_issets'], $fixers['no_singleline_whitespace_before_semicolons']],
  81. [$fixers['combine_consecutive_issets'], $fixers['no_spaces_inside_parenthesis']],
  82. [$fixers['combine_consecutive_issets'], $fixers['no_trailing_whitespace']],
  83. [$fixers['combine_consecutive_issets'], $fixers['no_whitespace_in_blank_line']],
  84. [$fixers['combine_consecutive_unsets'], $fixers['no_extra_blank_lines']],
  85. [$fixers['combine_consecutive_unsets'], $fixers['no_trailing_whitespace']],
  86. [$fixers['combine_consecutive_unsets'], $fixers['no_whitespace_in_blank_line']],
  87. [$fixers['combine_consecutive_unsets'], $fixers['space_after_semicolon']],
  88. [$fixers['combine_nested_dirname'], $fixers['method_argument_space']],
  89. [$fixers['combine_nested_dirname'], $fixers['no_spaces_inside_parenthesis']],
  90. [$fixers['declare_strict_types'], $fixers['blank_line_after_opening_tag']],
  91. [$fixers['declare_strict_types'], $fixers['declare_equal_normalize']],
  92. [$fixers['declare_strict_types'], $fixers['header_comment']],
  93. [$fixers['dir_constant'], $fixers['combine_nested_dirname']],
  94. [$fixers['doctrine_annotation_array_assignment'], $fixers['doctrine_annotation_spaces']],
  95. [$fixers['echo_tag_syntax'], $fixers['no_mixed_echo_print']],
  96. [$fixers['elseif'], $fixers['braces']],
  97. [$fixers['empty_loop_body'], $fixers['braces']],
  98. [$fixers['empty_loop_body'], $fixers['no_extra_blank_lines']],
  99. [$fixers['empty_loop_body'], $fixers['no_trailing_whitespace']],
  100. [$fixers['empty_loop_condition'], $fixers['no_extra_blank_lines']],
  101. [$fixers['empty_loop_condition'], $fixers['no_trailing_whitespace']],
  102. [$fixers['escape_implicit_backslashes'], $fixers['heredoc_to_nowdoc']],
  103. [$fixers['escape_implicit_backslashes'], $fixers['single_quote']],
  104. [$fixers['explicit_string_variable'], $fixers['simple_to_complex_string_variable']],
  105. [$fixers['final_internal_class'], $fixers['protected_to_private']],
  106. [$fixers['final_internal_class'], $fixers['self_static_accessor']],
  107. [$fixers['fully_qualified_strict_types'], $fixers['no_superfluous_phpdoc_tags']],
  108. [$fixers['function_declaration'], $fixers['method_argument_space']],
  109. [$fixers['function_to_constant'], $fixers['native_function_casing']],
  110. [$fixers['function_to_constant'], $fixers['no_extra_blank_lines']],
  111. [$fixers['function_to_constant'], $fixers['no_singleline_whitespace_before_semicolons']],
  112. [$fixers['function_to_constant'], $fixers['no_trailing_whitespace']],
  113. [$fixers['function_to_constant'], $fixers['no_whitespace_in_blank_line']],
  114. [$fixers['function_to_constant'], $fixers['self_static_accessor']],
  115. [$fixers['general_phpdoc_annotation_remove'], $fixers['no_empty_phpdoc']],
  116. [$fixers['general_phpdoc_annotation_remove'], $fixers['phpdoc_line_span']],
  117. [$fixers['general_phpdoc_annotation_remove'], $fixers['phpdoc_separation']],
  118. [$fixers['general_phpdoc_annotation_remove'], $fixers['phpdoc_trim']],
  119. [$fixers['general_phpdoc_tag_rename'], $fixers['phpdoc_add_missing_param_annotation']],
  120. [$fixers['get_class_to_class_keyword'], $fixers['multiline_whitespace_before_semicolons']],
  121. [$fixers['global_namespace_import'], $fixers['no_unused_imports']],
  122. [$fixers['global_namespace_import'], $fixers['ordered_imports']],
  123. [$fixers['header_comment'], $fixers['single_line_comment_style']],
  124. [$fixers['implode_call'], $fixers['method_argument_space']],
  125. [$fixers['indentation_type'], $fixers['phpdoc_indent']],
  126. [$fixers['is_null'], $fixers['yoda_style']],
  127. [$fixers['lambda_not_used_import'], $fixers['no_spaces_inside_parenthesis']],
  128. [$fixers['line_ending'], $fixers['braces']],
  129. [$fixers['list_syntax'], $fixers['binary_operator_spaces']],
  130. [$fixers['list_syntax'], $fixers['ternary_operator_spaces']],
  131. [$fixers['method_argument_space'], $fixers['array_indentation']],
  132. [$fixers['method_chaining_indentation'], $fixers['array_indentation']],
  133. [$fixers['method_chaining_indentation'], $fixers['method_argument_space']],
  134. [$fixers['modernize_strpos'], $fixers['binary_operator_spaces']],
  135. [$fixers['modernize_strpos'], $fixers['no_extra_blank_lines']],
  136. [$fixers['modernize_strpos'], $fixers['no_spaces_inside_parenthesis']],
  137. [$fixers['modernize_strpos'], $fixers['no_trailing_whitespace']],
  138. [$fixers['modernize_strpos'], $fixers['not_operator_with_space']],
  139. [$fixers['modernize_strpos'], $fixers['not_operator_with_successor_space']],
  140. [$fixers['modernize_strpos'], $fixers['php_unit_dedicate_assert']],
  141. [$fixers['modernize_strpos'], $fixers['single_space_after_construct']],
  142. [$fixers['multiline_whitespace_before_semicolons'], $fixers['space_after_semicolon']],
  143. [$fixers['native_constant_invocation'], $fixers['global_namespace_import']],
  144. [$fixers['native_function_invocation'], $fixers['global_namespace_import']],
  145. [$fixers['new_with_braces'], $fixers['class_definition']],
  146. [$fixers['no_alias_functions'], $fixers['implode_call']],
  147. [$fixers['no_alias_functions'], $fixers['php_unit_dedicate_assert']],
  148. [$fixers['no_alternative_syntax'], $fixers['braces']],
  149. [$fixers['no_alternative_syntax'], $fixers['elseif']],
  150. [$fixers['no_alternative_syntax'], $fixers['no_superfluous_elseif']],
  151. [$fixers['no_alternative_syntax'], $fixers['no_useless_else']],
  152. [$fixers['no_alternative_syntax'], $fixers['switch_continue_to_break']],
  153. [$fixers['no_blank_lines_after_phpdoc'], $fixers['header_comment']],
  154. [$fixers['no_empty_comment'], $fixers['no_extra_blank_lines']],
  155. [$fixers['no_empty_comment'], $fixers['no_trailing_whitespace']],
  156. [$fixers['no_empty_comment'], $fixers['no_whitespace_in_blank_line']],
  157. [$fixers['no_empty_phpdoc'], $fixers['no_extra_blank_lines']],
  158. [$fixers['no_empty_phpdoc'], $fixers['no_trailing_whitespace']],
  159. [$fixers['no_empty_phpdoc'], $fixers['no_whitespace_in_blank_line']],
  160. [$fixers['no_empty_statement'], $fixers['braces']],
  161. [$fixers['no_empty_statement'], $fixers['combine_consecutive_unsets']],
  162. [$fixers['no_empty_statement'], $fixers['empty_loop_body']],
  163. [$fixers['no_empty_statement'], $fixers['multiline_whitespace_before_semicolons']],
  164. [$fixers['no_empty_statement'], $fixers['no_extra_blank_lines']],
  165. [$fixers['no_empty_statement'], $fixers['no_singleline_whitespace_before_semicolons']],
  166. [$fixers['no_empty_statement'], $fixers['no_trailing_whitespace']],
  167. [$fixers['no_empty_statement'], $fixers['no_useless_else']],
  168. [$fixers['no_empty_statement'], $fixers['no_useless_return']],
  169. [$fixers['no_empty_statement'], $fixers['no_whitespace_in_blank_line']],
  170. [$fixers['no_empty_statement'], $fixers['return_assignment']],
  171. [$fixers['no_empty_statement'], $fixers['space_after_semicolon']],
  172. [$fixers['no_empty_statement'], $fixers['switch_case_semicolon_to_colon']],
  173. [$fixers['no_extra_blank_lines'], $fixers['blank_line_before_statement']],
  174. [$fixers['no_leading_import_slash'], $fixers['ordered_imports']],
  175. [$fixers['no_multiline_whitespace_around_double_arrow'], $fixers['binary_operator_spaces']],
  176. [$fixers['no_multiline_whitespace_around_double_arrow'], $fixers['method_argument_space']],
  177. [$fixers['no_multiline_whitespace_around_double_arrow'], $fixers['trailing_comma_in_multiline']],
  178. [$fixers['no_php4_constructor'], $fixers['ordered_class_elements']],
  179. [$fixers['no_short_bool_cast'], $fixers['cast_spaces']],
  180. [$fixers['no_spaces_after_function_name'], $fixers['function_to_constant']],
  181. [$fixers['no_spaces_after_function_name'], $fixers['get_class_to_class_keyword']],
  182. [$fixers['no_spaces_inside_parenthesis'], $fixers['function_to_constant']],
  183. [$fixers['no_spaces_inside_parenthesis'], $fixers['get_class_to_class_keyword']],
  184. [$fixers['no_spaces_inside_parenthesis'], $fixers['string_length_to_empty']],
  185. [$fixers['no_superfluous_elseif'], $fixers['simplified_if_return']],
  186. [$fixers['no_superfluous_phpdoc_tags'], $fixers['no_empty_phpdoc']],
  187. [$fixers['no_superfluous_phpdoc_tags'], $fixers['void_return']],
  188. [$fixers['no_unneeded_control_parentheses'], $fixers['no_trailing_whitespace']],
  189. [$fixers['no_unneeded_curly_braces'], $fixers['no_useless_else']],
  190. [$fixers['no_unneeded_curly_braces'], $fixers['no_useless_return']],
  191. [$fixers['no_unneeded_curly_braces'], $fixers['return_assignment']],
  192. [$fixers['no_unneeded_curly_braces'], $fixers['simplified_if_return']],
  193. [$fixers['no_unset_cast'], $fixers['binary_operator_spaces']],
  194. [$fixers['no_unset_on_property'], $fixers['combine_consecutive_unsets']],
  195. [$fixers['no_unused_imports'], $fixers['blank_line_after_namespace']],
  196. [$fixers['no_unused_imports'], $fixers['no_extra_blank_lines']],
  197. [$fixers['no_unused_imports'], $fixers['no_leading_import_slash']],
  198. [$fixers['no_unused_imports'], $fixers['single_line_after_imports']],
  199. [$fixers['no_useless_else'], $fixers['braces']],
  200. [$fixers['no_useless_else'], $fixers['combine_consecutive_unsets']],
  201. [$fixers['no_useless_else'], $fixers['no_break_comment']],
  202. [$fixers['no_useless_else'], $fixers['no_extra_blank_lines']],
  203. [$fixers['no_useless_else'], $fixers['no_trailing_whitespace']],
  204. [$fixers['no_useless_else'], $fixers['no_useless_return']],
  205. [$fixers['no_useless_else'], $fixers['no_whitespace_in_blank_line']],
  206. [$fixers['no_useless_else'], $fixers['simplified_if_return']],
  207. [$fixers['no_useless_return'], $fixers['blank_line_before_statement']],
  208. [$fixers['no_useless_return'], $fixers['no_extra_blank_lines']],
  209. [$fixers['no_useless_return'], $fixers['no_whitespace_in_blank_line']],
  210. [$fixers['no_useless_return'], $fixers['single_line_comment_style']],
  211. [$fixers['no_useless_sprintf'], $fixers['method_argument_space']],
  212. [$fixers['no_useless_sprintf'], $fixers['native_function_casing']],
  213. [$fixers['no_useless_sprintf'], $fixers['no_empty_statement']],
  214. [$fixers['no_useless_sprintf'], $fixers['no_extra_blank_lines']],
  215. [$fixers['no_useless_sprintf'], $fixers['no_spaces_inside_parenthesis']],
  216. [$fixers['nullable_type_declaration_for_default_null_value'], $fixers['no_unreachable_default_argument_value']],
  217. [$fixers['ordered_class_elements'], $fixers['class_attributes_separation']],
  218. [$fixers['ordered_class_elements'], $fixers['no_blank_lines_after_class_opening']],
  219. [$fixers['ordered_class_elements'], $fixers['space_after_semicolon']],
  220. [$fixers['php_unit_construct'], $fixers['php_unit_dedicate_assert']],
  221. [$fixers['php_unit_dedicate_assert'], $fixers['no_unused_imports']],
  222. [$fixers['php_unit_dedicate_assert'], $fixers['php_unit_dedicate_assert_internal_type']],
  223. [$fixers['php_unit_fqcn_annotation'], $fixers['no_unused_imports']],
  224. [$fixers['php_unit_fqcn_annotation'], $fixers['phpdoc_order_by_value']],
  225. [$fixers['php_unit_internal_class'], $fixers['final_internal_class']],
  226. [$fixers['php_unit_no_expectation_annotation'], $fixers['no_empty_phpdoc']],
  227. [$fixers['php_unit_no_expectation_annotation'], $fixers['php_unit_expectation']],
  228. [$fixers['php_unit_test_annotation'], $fixers['no_empty_phpdoc']],
  229. [$fixers['php_unit_test_annotation'], $fixers['php_unit_method_casing']],
  230. [$fixers['php_unit_test_annotation'], $fixers['phpdoc_trim']],
  231. [$fixers['php_unit_test_case_static_method_calls'], $fixers['self_static_accessor']],
  232. [$fixers['phpdoc_add_missing_param_annotation'], $fixers['no_empty_phpdoc']],
  233. [$fixers['phpdoc_add_missing_param_annotation'], $fixers['no_superfluous_phpdoc_tags']],
  234. [$fixers['phpdoc_add_missing_param_annotation'], $fixers['phpdoc_align']],
  235. [$fixers['phpdoc_add_missing_param_annotation'], $fixers['phpdoc_order']],
  236. [$fixers['phpdoc_annotation_without_dot'], $fixers['phpdoc_types']],
  237. [$fixers['phpdoc_annotation_without_dot'], $fixers['phpdoc_types_order']],
  238. [$fixers['phpdoc_line_span'], $fixers['no_superfluous_phpdoc_tags']],
  239. [$fixers['phpdoc_no_access'], $fixers['no_empty_phpdoc']],
  240. [$fixers['phpdoc_no_access'], $fixers['phpdoc_separation']],
  241. [$fixers['phpdoc_no_access'], $fixers['phpdoc_trim']],
  242. [$fixers['phpdoc_no_alias_tag'], $fixers['phpdoc_add_missing_param_annotation']],
  243. [$fixers['phpdoc_no_alias_tag'], $fixers['phpdoc_single_line_var_spacing']],
  244. [$fixers['phpdoc_no_empty_return'], $fixers['no_empty_phpdoc']],
  245. [$fixers['phpdoc_no_empty_return'], $fixers['phpdoc_order']],
  246. [$fixers['phpdoc_no_empty_return'], $fixers['phpdoc_separation']],
  247. [$fixers['phpdoc_no_empty_return'], $fixers['phpdoc_trim']],
  248. [$fixers['phpdoc_no_package'], $fixers['no_empty_phpdoc']],
  249. [$fixers['phpdoc_no_package'], $fixers['phpdoc_separation']],
  250. [$fixers['phpdoc_no_package'], $fixers['phpdoc_trim']],
  251. [$fixers['phpdoc_no_useless_inheritdoc'], $fixers['no_empty_phpdoc']],
  252. [$fixers['phpdoc_no_useless_inheritdoc'], $fixers['no_trailing_whitespace_in_comment']],
  253. [$fixers['phpdoc_order'], $fixers['phpdoc_separation']],
  254. [$fixers['phpdoc_order'], $fixers['phpdoc_trim']],
  255. [$fixers['phpdoc_return_self_reference'], $fixers['no_superfluous_phpdoc_tags']],
  256. [$fixers['phpdoc_scalar'], $fixers['phpdoc_to_return_type']],
  257. [$fixers['phpdoc_to_comment'], $fixers['no_empty_comment']],
  258. [$fixers['phpdoc_to_comment'], $fixers['phpdoc_no_useless_inheritdoc']],
  259. [$fixers['phpdoc_to_param_type'], $fixers['no_superfluous_phpdoc_tags']],
  260. [$fixers['phpdoc_to_property_type'], $fixers['no_superfluous_phpdoc_tags']],
  261. [$fixers['phpdoc_to_return_type'], $fixers['fully_qualified_strict_types']],
  262. [$fixers['phpdoc_to_return_type'], $fixers['no_superfluous_phpdoc_tags']],
  263. [$fixers['phpdoc_to_return_type'], $fixers['return_type_declaration']],
  264. [$fixers['phpdoc_types'], $fixers['phpdoc_to_return_type']],
  265. [$fixers['pow_to_exponentiation'], $fixers['binary_operator_spaces']],
  266. [$fixers['pow_to_exponentiation'], $fixers['method_argument_space']],
  267. [$fixers['pow_to_exponentiation'], $fixers['native_function_casing']],
  268. [$fixers['pow_to_exponentiation'], $fixers['no_spaces_after_function_name']],
  269. [$fixers['pow_to_exponentiation'], $fixers['no_spaces_inside_parenthesis']],
  270. [$fixers['protected_to_private'], $fixers['ordered_class_elements']],
  271. [$fixers['regular_callable_call'], $fixers['native_function_invocation']],
  272. [$fixers['return_assignment'], $fixers['blank_line_before_statement']],
  273. [$fixers['semicolon_after_instruction'], $fixers['simplified_if_return']],
  274. [$fixers['simplified_if_return'], $fixers['multiline_whitespace_before_semicolons']],
  275. [$fixers['simplified_if_return'], $fixers['no_singleline_whitespace_before_semicolons']],
  276. [$fixers['simplified_null_return'], $fixers['no_useless_return']],
  277. [$fixers['simplified_null_return'], $fixers['void_return']],
  278. [$fixers['single_class_element_per_statement'], $fixers['class_attributes_separation']],
  279. [$fixers['single_import_per_statement'], $fixers['multiline_whitespace_before_semicolons']],
  280. [$fixers['single_import_per_statement'], $fixers['no_leading_import_slash']],
  281. [$fixers['single_import_per_statement'], $fixers['no_singleline_whitespace_before_semicolons']],
  282. [$fixers['single_import_per_statement'], $fixers['no_unused_imports']],
  283. [$fixers['single_import_per_statement'], $fixers['space_after_semicolon']],
  284. [$fixers['single_line_throw'], $fixers['braces']],
  285. [$fixers['single_line_throw'], $fixers['concat_space']],
  286. [$fixers['single_space_after_construct'], $fixers['braces']],
  287. [$fixers['single_space_after_construct'], $fixers['function_declaration']],
  288. [$fixers['single_trait_insert_per_statement'], $fixers['braces']],
  289. [$fixers['single_trait_insert_per_statement'], $fixers['space_after_semicolon']],
  290. [$fixers['standardize_increment'], $fixers['increment_style']],
  291. [$fixers['standardize_not_equals'], $fixers['binary_operator_spaces']],
  292. [$fixers['strict_comparison'], $fixers['binary_operator_spaces']],
  293. [$fixers['strict_param'], $fixers['method_argument_space']],
  294. [$fixers['strict_param'], $fixers['native_function_invocation']],
  295. [$fixers['string_length_to_empty'], $fixers['no_extra_blank_lines']],
  296. [$fixers['string_length_to_empty'], $fixers['no_trailing_whitespace']],
  297. [$fixers['ternary_to_elvis_operator'], $fixers['no_trailing_whitespace']],
  298. [$fixers['ternary_to_elvis_operator'], $fixers['ternary_operator_spaces']],
  299. [$fixers['ternary_to_null_coalescing'], $fixers['assign_null_coalescing_to_coalesce_equal']],
  300. [$fixers['unary_operator_spaces'], $fixers['not_operator_with_space']],
  301. [$fixers['unary_operator_spaces'], $fixers['not_operator_with_successor_space']],
  302. [$fixers['void_return'], $fixers['phpdoc_no_empty_return']],
  303. [$fixers['void_return'], $fixers['return_type_declaration']],
  304. ];
  305. }
  306. public function provideFixersPrioritySpecialPhpdocCases(): array
  307. {
  308. $factory = new FixerFactory();
  309. $factory->registerBuiltInFixers();
  310. $fixers = [];
  311. foreach ($factory->getFixers() as $fixer) {
  312. $fixers[$fixer->getName()] = $fixer;
  313. }
  314. $cases = [];
  315. // Prepare bulk tests for phpdoc fixers to test that:
  316. // * `align_multiline_comment` is first
  317. // * `comment_to_phpdoc` is second
  318. // * `phpdoc_to_comment` is third
  319. // * `phpdoc_indent` is fourth
  320. // * `phpdoc_types` is fifth
  321. // * `phpdoc_scalar` is sixth
  322. // * `phpdoc_align` is last
  323. // Add these cases in test-order instead of alphabetical
  324. $cases[] = [$fixers['align_multiline_comment'], $fixers['comment_to_phpdoc']];
  325. $cases[] = [$fixers['comment_to_phpdoc'], $fixers['phpdoc_to_comment']];
  326. $cases[] = [$fixers['phpdoc_to_comment'], $fixers['phpdoc_indent']];
  327. $cases[] = [$fixers['phpdoc_indent'], $fixers['phpdoc_types']];
  328. $cases[] = [$fixers['phpdoc_types'], $fixers['phpdoc_scalar']];
  329. $docFixerNames = array_filter(
  330. array_keys($fixers),
  331. static function (string $name): bool {
  332. return str_contains($name, 'phpdoc');
  333. }
  334. );
  335. foreach ($docFixerNames as $docFixerName) {
  336. if (!\in_array($docFixerName, ['comment_to_phpdoc', 'phpdoc_to_comment', 'phpdoc_indent', 'phpdoc_types', 'phpdoc_scalar'], true)) {
  337. $cases[] = [$fixers['align_multiline_comment'], $fixers[$docFixerName]];
  338. $cases[] = [$fixers['comment_to_phpdoc'], $fixers[$docFixerName]];
  339. $cases[] = [$fixers['phpdoc_indent'], $fixers[$docFixerName]];
  340. $cases[] = [$fixers['phpdoc_to_comment'], $fixers[$docFixerName]];
  341. if ('phpdoc_annotation_without_dot' !== $docFixerName) {
  342. $cases[] = [$fixers['phpdoc_scalar'], $fixers[$docFixerName]];
  343. $cases[] = [$fixers['phpdoc_types'], $fixers[$docFixerName]];
  344. }
  345. }
  346. if ('phpdoc_align' !== $docFixerName) {
  347. $cases[] = [$fixers[$docFixerName], $fixers['phpdoc_align']];
  348. }
  349. }
  350. return $cases;
  351. }
  352. /**
  353. * @dataProvider provideFixersPriorityPairsHaveIntegrationTestCases
  354. */
  355. public function testFixersPriorityPairsHaveIntegrationTest(FixerInterface $first, FixerInterface $second): void
  356. {
  357. $integrationTestName = $this->generateIntegrationTestName($first, $second);
  358. $file = $this->getIntegrationPriorityDirectory().$integrationTestName;
  359. if (is_file($file)) {
  360. $description = sprintf('Integration of fixers: %s,%s.', $first->getName(), $second->getName());
  361. $integrationTestExists = true;
  362. } else {
  363. $file = $this->getIntegrationPriorityDirectory().$this->generateIntegrationTestName($second, $first);
  364. $description = sprintf('Integration of fixers: %s,%s.', $second->getName(), $first->getName());
  365. $integrationTestExists = is_file($file);
  366. }
  367. static::assertTrue($integrationTestExists, sprintf('There shall be an integration test "%s". How do you know that priority set up is good, if there is no integration test to check it?', $integrationTestName));
  368. $file = realpath($file);
  369. $factory = new IntegrationCaseFactory();
  370. $test = $factory->create(new SplFileInfo($file, './', __DIR__));
  371. $rules = $test->getRuleset()->getRules();
  372. $expected = [$first->getName(), $second->getName()];
  373. $actual = array_keys($rules);
  374. sort($expected);
  375. sort($actual);
  376. static::assertSame($description, $test->getTitle(), sprintf('Please fix the title in "%s".', $file));
  377. static::assertCount(2, $rules, sprintf('Only the two rules that are tested for priority should be in the ruleset of "%s".', $file));
  378. foreach ($rules as $name => $config) {
  379. static::assertNotFalse($config, sprintf('The rule "%s" in "%s" may not be disabled for the test.', $name, $file));
  380. }
  381. static::assertSame($expected, $actual, sprintf('The ruleset of "%s" must contain the rules for the priority test.', $file));
  382. }
  383. public function provideFixersPriorityPairsHaveIntegrationTestCases(): array
  384. {
  385. return array_filter(
  386. $this->provideFixersPriorityCases(),
  387. // ignore speed-up only priorities set up
  388. function (array $case): bool {
  389. return !\in_array(
  390. $this->generateIntegrationTestName($case[0], $case[1]),
  391. [
  392. 'function_to_constant,native_function_casing.test',
  393. 'no_unused_imports,no_leading_import_slash.test',
  394. 'pow_to_exponentiation,method_argument_space.test',
  395. 'pow_to_exponentiation,native_function_casing.test',
  396. 'pow_to_exponentiation,no_spaces_after_function_name.test',
  397. 'pow_to_exponentiation,no_spaces_inside_parenthesis.test',
  398. 'no_useless_sprintf,native_function_casing.test',
  399. ],
  400. true
  401. );
  402. }
  403. );
  404. }
  405. public function testPriorityIntegrationDirectoryOnlyContainsFiles(): void
  406. {
  407. foreach (new \DirectoryIterator($this->getIntegrationPriorityDirectory()) as $candidate) {
  408. if ($candidate->isDot()) {
  409. continue;
  410. }
  411. $fileName = $candidate->getFilename();
  412. static::assertTrue($candidate->isFile(), sprintf('Expected only files in the priority integration test directory, got "%s".', $fileName));
  413. static::assertFalse($candidate->isLink(), sprintf('No (sym)links expected the priority integration test directory, got "%s".', $fileName));
  414. }
  415. }
  416. /**
  417. * @dataProvider provideIntegrationTestFilesCases
  418. */
  419. public function testPriorityIntegrationTestFilesAreListedPriorityCases(string $fileName): void
  420. {
  421. static $priorityCases;
  422. if (null === $priorityCases) {
  423. $priorityCases = [];
  424. foreach ($this->provideFixersPriorityCases() as $priorityCase) {
  425. $fixerName = $priorityCase[0]->getName();
  426. if (!isset($priorityCases[$fixerName])) {
  427. $priorityCases[$fixerName] = [];
  428. }
  429. $priorityCases[$fixerName][$priorityCase[1]->getName()] = true;
  430. }
  431. ksort($priorityCases);
  432. }
  433. static::assertSame(
  434. 1,
  435. preg_match('#^([a-z][a-z0-9_]*),([a-z][a-z_]*)(?:_\d{1,3})?\.test(-(in|out)\.php)?$#', $fileName, $matches),
  436. sprintf('File with unexpected name "%s" in the priority integration test directory.', $fileName)
  437. );
  438. $fixerName1 = $matches[1];
  439. $fixerName2 = $matches[2];
  440. static::assertTrue(
  441. isset($priorityCases[$fixerName1][$fixerName2]),
  442. sprintf('Missing priority test entry for file "%s".', $fileName)
  443. );
  444. }
  445. public function provideIntegrationTestFilesCases(): array
  446. {
  447. $fileNames = [];
  448. foreach (new \DirectoryIterator($this->getIntegrationPriorityDirectory()) as $candidate) {
  449. if ($candidate->isDot()) {
  450. continue;
  451. }
  452. $fileNames[] = [$candidate->getFilename()];
  453. }
  454. sort($fileNames);
  455. return $fileNames;
  456. }
  457. public function testProvideFixersPriorityCasesAreSorted(): void
  458. {
  459. $cases = $this->provideFixersPriorityCases();
  460. $sorted = $cases;
  461. usort(
  462. $sorted,
  463. /**
  464. * @param array<FixerInterface> $priorityPair1
  465. * @param array<FixerInterface> $priorityPair2
  466. */
  467. static function (array $priorityPair1, array $priorityPair2): int {
  468. $fixer1 = $priorityPair1[0];
  469. $fixer2 = $priorityPair2[0];
  470. if ($fixer1->getName() === $fixer2->getName()) {
  471. $fixer1 = $priorityPair1[1];
  472. $fixer2 = $priorityPair2[1];
  473. }
  474. return strcmp($fixer1->getName(), $fixer2->getName());
  475. }
  476. );
  477. if ($sorted !== $cases) { // PHPUnit takes a very long time creating a diff view on the arrays
  478. $casesDescription = '';
  479. foreach ($cases as $pair) {
  480. $casesDescription .= sprintf("\n%s/%s", $pair[0]->getName(), $pair[1]->getName());
  481. }
  482. $sortedDescription = '';
  483. foreach ($sorted as $pair) {
  484. $sortedDescription .= sprintf("\n%s/%s", $pair[0]->getName(), $pair[1]->getName());
  485. }
  486. static::assertSame($sortedDescription, $casesDescription);
  487. } else {
  488. $this->addToAssertionCount(1);
  489. }
  490. }
  491. public function testFixerPriorityComment(): void
  492. {
  493. $cases = array_merge(
  494. $this->provideFixersPriorityCases(),
  495. $this->provideFixersPrioritySpecialPhpdocCases()
  496. );
  497. $map = [];
  498. foreach ($cases as $beforeAfter) {
  499. [$before, $after] = $beforeAfter;
  500. $beforeClass = \get_class($before);
  501. $afterClass = \get_class($after);
  502. $beforeName = substr($beforeClass, strrpos($beforeClass, '\\') + 1);
  503. $afterName = substr($afterClass, strrpos($afterClass, '\\') + 1);
  504. if (!isset($map[$beforeName])) {
  505. $map[$beforeName] = [
  506. 'before' => [],
  507. 'after' => [],
  508. 'class' => $beforeClass,
  509. ];
  510. }
  511. $map[$beforeName]['before'][] = $afterName;
  512. if (!isset($map[$afterName])) {
  513. $map[$afterName] = [
  514. 'before' => [],
  515. 'after' => [],
  516. 'class' => $afterClass,
  517. ];
  518. }
  519. $map[$afterName]['after'][] = $beforeName;
  520. }
  521. $fixersPhpDocIssues = [];
  522. foreach ($map as $fixerName => $priorityMap) {
  523. $expectedMessage = "/**\n * {@inheritdoc}\n *";
  524. if (\count($priorityMap['before']) > 0) {
  525. sort($priorityMap['before']);
  526. $expectedMessage .= sprintf("\n * Must run before %s.", implode(', ', $priorityMap['before']));
  527. }
  528. // @phpstan-ignore-next-line to avoid `Comparison operation ">" between int<1, max> and 0 is always true.`
  529. if (\count($priorityMap['after']) > 0) {
  530. sort($priorityMap['after']);
  531. $expectedMessage .= sprintf("\n * Must run after %s.", implode(', ', $priorityMap['after']));
  532. }
  533. $expectedMessage .= "\n */";
  534. $reflection = new \ReflectionClass($priorityMap['class']);
  535. $method = $reflection->getMethod('getPriority');
  536. $phpDoc = $method->getDocComment();
  537. if (false === $phpDoc) {
  538. $fixersPhpDocIssues[$fixerName] = sprintf("PHPDoc for %s::getPriority is missing.\nExpected:\n%s", $fixerName, $expectedMessage);
  539. continue;
  540. }
  541. if ($expectedMessage !== $phpDoc) {
  542. $fixersPhpDocIssues[$fixerName] = sprintf("PHPDoc for %s::getPriority is not as expected.\nExpected:\n%s", $fixerName, $expectedMessage);
  543. continue;
  544. }
  545. }
  546. if (0 === \count($fixersPhpDocIssues)) {
  547. $this->addToAssertionCount(1);
  548. } else {
  549. $message = sprintf("There are %d priority PHPDoc issues found.\n", \count($fixersPhpDocIssues));
  550. ksort($fixersPhpDocIssues);
  551. foreach ($fixersPhpDocIssues as $fixerName => $issue) {
  552. $message .= sprintf("\n--------------------------------------------------\n%s\n%s", $fixerName, $issue);
  553. }
  554. static::fail($message);
  555. }
  556. }
  557. public function testFixerWithNoneDefaultPriorityIsTested(): void
  558. {
  559. $factory = new FixerFactory();
  560. $factory->registerBuiltInFixers();
  561. $fixers = $factory->getFixers();
  562. $priorityTests = [];
  563. foreach (self::getFixerWithFixedPosition() as $fixerName => $offset) {
  564. $priorityTests[$fixerName] = true;
  565. }
  566. foreach ($this->provideFixersPriorityCases() as $pair) {
  567. [$first, $second] = $pair;
  568. $priorityTests[$first->getName()] = true;
  569. $priorityTests[$second->getName()] = true;
  570. }
  571. foreach ($this->provideFixersPrioritySpecialPhpdocCases() as $pair) {
  572. [$first, $second] = $pair;
  573. $priorityTests[$first->getName()] = true;
  574. $priorityTests[$second->getName()] = true;
  575. }
  576. $missing = [];
  577. foreach ($fixers as $fixer) {
  578. $priority = $fixer->getPriority();
  579. if (0 === $priority) {
  580. continue;
  581. }
  582. $name = $fixer->getName();
  583. if (!isset($priorityTests[$name])) {
  584. $missing[$name] = true;
  585. }
  586. }
  587. $knownIssues = [ // should only shrink
  588. 'final_class',
  589. 'psr_autoloading',
  590. 'single_blank_line_before_namespace',
  591. ];
  592. foreach ($knownIssues as $knownIssue) {
  593. if (isset($missing[$knownIssue])) {
  594. unset($missing[$knownIssue]);
  595. } else {
  596. static::fail(sprintf('No longer found known issue "%s", please update the set.', $knownIssue));
  597. }
  598. }
  599. static::assertEmpty($missing, 'Fixers without default priority and without priority tests: "'.implode('", "', array_keys($missing)).'."');
  600. }
  601. private static function getFixerWithFixedPosition(): array
  602. {
  603. return [
  604. 'encoding' => 0, // Expected "encoding" fixer to have the highest priority.
  605. 'full_opening_tag' => 1, // Expected "full_opening_tag" fixer has second-highest priority.
  606. 'single_blank_line_at_eof' => -1, // Expected "single_blank_line_at_eof" to have the lowest priority.
  607. ];
  608. }
  609. private function generateIntegrationTestName(FixerInterface $first, FixerInterface $second): string
  610. {
  611. return "{$first->getName()},{$second->getName()}.test";
  612. }
  613. private function getIntegrationPriorityDirectory(): string
  614. {
  615. return __DIR__.'/../Fixtures/Integration/priority/';
  616. }
  617. }