ConfigDouble.php 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221
  1. <?php
  2. /**
  3. * Config class for use in the tests.
  4. *
  5. * The Config class contains a number of static properties.
  6. * As the value of these static properties will be retained between instantiations of the class,
  7. * config values set in one test can influence the results for another test, which makes tests unstable.
  8. *
  9. * This class is a "double" of the Config class which prevents this from happening.
  10. * In _most_ cases, tests should be using this class instead of the "normal" Config,
  11. * with the exception of select tests for the Config class itself.
  12. *
  13. * @author Juliette Reinders Folmer <phpcs_nospam@adviesenzo.nl>
  14. * @copyright 2024 Juliette Reinders Folmer. All rights reserved.
  15. * @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence
  16. */
  17. namespace PHP_CodeSniffer\Tests;
  18. use PHP_CodeSniffer\Config;
  19. use ReflectionProperty;
  20. final class ConfigDouble extends Config
  21. {
  22. /**
  23. * Whether or not the setting of a standard should be skipped.
  24. *
  25. * @var boolean
  26. */
  27. private $skipSettingStandard = false;
  28. /**
  29. * Creates a clean Config object and populates it with command line values.
  30. *
  31. * @param array<string> $cliArgs An array of values gathered from CLI args.
  32. * @param bool $skipSettingStandard Whether to skip setting a standard to prevent
  33. * the Config class trying to auto-discover a ruleset file.
  34. * Should only be set to `true` for tests which actually test
  35. * the ruleset auto-discovery.
  36. * Note: there is no need to set this to `true` when a standard
  37. * is being passed via the `$cliArgs`. Those settings will always
  38. * be respected.
  39. * Defaults to `false`. Will result in the standard being set
  40. * to "PSR1" if not provided via `$cliArgs`.
  41. * @param bool $skipSettingReportWidth Whether to skip setting a report-width to prevent
  42. * the Config class trying to auto-discover the screen width.
  43. * Should only be set to `true` for tests which actually test
  44. * the screen width auto-discovery.
  45. * Note: there is no need to set this to `true` when a report-width
  46. * is being passed via the `$cliArgs`. Those settings will always
  47. * respected.
  48. * Defaults to `false`. Will result in the reportWidth being set
  49. * to "80" if not provided via `$cliArgs`.
  50. *
  51. * @return void
  52. */
  53. public function __construct(array $cliArgs=[], $skipSettingStandard=false, $skipSettingReportWidth=false)
  54. {
  55. $this->skipSettingStandard = $skipSettingStandard;
  56. $this->resetSelectProperties();
  57. $this->preventReadingCodeSnifferConfFile();
  58. parent::__construct($cliArgs);
  59. if ($skipSettingReportWidth !== true) {
  60. $this->preventAutoDiscoveryScreenWidth();
  61. }
  62. }//end __construct()
  63. /**
  64. * Ensures the static properties in the Config class are reset to their default values
  65. * when the ConfigDouble is no longer used.
  66. *
  67. * @return void
  68. */
  69. public function __destruct()
  70. {
  71. $this->setStaticConfigProperty('executablePaths', []);
  72. $this->setStaticConfigProperty('configData', null);
  73. $this->setStaticConfigProperty('configDataFile', null);
  74. }//end __destruct()
  75. /**
  76. * Sets the command line values and optionally prevents a file system search for a custom ruleset.
  77. *
  78. * @param array<string> $args An array of command line arguments to set.
  79. *
  80. * @return void
  81. */
  82. public function setCommandLineValues($args)
  83. {
  84. parent::setCommandLineValues($args);
  85. if ($this->skipSettingStandard !== true) {
  86. $this->preventSearchingForRuleset();
  87. }
  88. }//end setCommandLineValues()
  89. /**
  90. * Reset select properties on the Config class to their default values.
  91. *
  92. * @return void
  93. */
  94. private function resetSelectProperties()
  95. {
  96. $this->setStaticConfigProperty('executablePaths', []);
  97. }//end resetSelectProperties()
  98. /**
  99. * Prevent the values in a potentially available user-specific `CodeSniffer.conf` file
  100. * from influencing the tests.
  101. *
  102. * This also prevents some file system calls which can influence the test runtime.
  103. *
  104. * @return void
  105. */
  106. private function preventReadingCodeSnifferConfFile()
  107. {
  108. $this->setStaticConfigProperty('configData', []);
  109. $this->setStaticConfigProperty('configDataFile', '');
  110. }//end preventReadingCodeSnifferConfFile()
  111. /**
  112. * Prevent searching for a custom ruleset by setting a standard, but only if the test
  113. * being run doesn't set a standard itself.
  114. *
  115. * This also prevents some file system calls which can influence the test runtime.
  116. *
  117. * The standard being set is the smallest one available so the ruleset initialization
  118. * will be the fastest possible.
  119. *
  120. * @return void
  121. */
  122. private function preventSearchingForRuleset()
  123. {
  124. $overriddenDefaults = $this->getStaticConfigProperty('overriddenDefaults');
  125. if (isset($overriddenDefaults['standards']) === false) {
  126. $this->standards = ['PSR1'];
  127. $overriddenDefaults['standards'] = true;
  128. }
  129. self::setStaticConfigProperty('overriddenDefaults', $overriddenDefaults);
  130. }//end preventSearchingForRuleset()
  131. /**
  132. * Prevent a call to stty to figure out the screen width, but only if the test being run
  133. * doesn't set a report width itself.
  134. *
  135. * @return void
  136. */
  137. private function preventAutoDiscoveryScreenWidth()
  138. {
  139. $settings = $this->getSettings();
  140. if ($settings['reportWidth'] === 'auto') {
  141. $this->reportWidth = self::DEFAULT_REPORT_WIDTH;
  142. }
  143. }//end preventAutoDiscoveryScreenWidth()
  144. /**
  145. * Helper function to retrieve the value of a private static property on the Config class.
  146. *
  147. * @param string $name The name of the property to retrieve.
  148. *
  149. * @return mixed
  150. */
  151. private function getStaticConfigProperty($name)
  152. {
  153. $property = new ReflectionProperty('PHP_CodeSniffer\Config', $name);
  154. $property->setAccessible(true);
  155. if ($name === 'overriddenDefaults') {
  156. return $property->getValue($this);
  157. }
  158. return $property->getValue();
  159. }//end getStaticConfigProperty()
  160. /**
  161. * Helper function to set the value of a private static property on the Config class.
  162. *
  163. * @param string $name The name of the property to set.
  164. * @param mixed $value The value to set the property to.
  165. *
  166. * @return void
  167. */
  168. private function setStaticConfigProperty($name, $value)
  169. {
  170. $property = new ReflectionProperty('PHP_CodeSniffer\Config', $name);
  171. $property->setAccessible(true);
  172. if ($name === 'overriddenDefaults') {
  173. $property->setValue($this, $value);
  174. } else {
  175. $property->setValue(null, $value);
  176. }
  177. $property->setAccessible(false);
  178. }//end setStaticConfigProperty()
  179. }//end class