TestCase.php 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215
  1. <?php
  2. declare(strict_types=1);
  3. namespace Luolongfei\Tests;
  4. use PHPUnit\Framework\TestCase as BaseTestCase;
  5. abstract class TestCase extends BaseTestCase
  6. {
  7. protected const FIXTURE_ENV_FILE = 'tests/fixtures/test.env';
  8. protected const ENV_KEYS = [
  9. 'ENV_FILE_VERSION',
  10. 'FREENOM_USERNAME',
  11. 'FREENOM_PASSWORD',
  12. 'MULTIPLE_ACCOUNTS',
  13. 'FREENOM_PROXY',
  14. 'MAIL_USERNAME',
  15. 'MAIL_PASSWORD',
  16. 'TO',
  17. 'MAIL_ENABLE',
  18. 'MAIL_HOST',
  19. 'MAIL_PORT',
  20. 'MAIL_ENCRYPTION',
  21. 'TELEGRAM_CHAT_ID',
  22. 'TELEGRAM_BOT_TOKEN',
  23. 'TELEGRAM_PROXY',
  24. 'CUSTOM_TELEGRAM_HOST',
  25. 'TELEGRAM_BOT_ENABLE',
  26. 'WECHAT_CORP_ID',
  27. 'WECHAT_CORP_SECRET',
  28. 'WECHAT_AGENT_ID',
  29. 'WECHAT_USER_ID',
  30. 'WECHAT_ENABLE',
  31. 'SCT_SEND_KEY',
  32. 'SCT_ENABLE',
  33. 'BARK_KEY',
  34. 'BARK_URL',
  35. 'BARK_IS_ARCHIVE',
  36. 'BARK_GROUP',
  37. 'BARK_LEVEL',
  38. 'BARK_ICON',
  39. 'BARK_JUMP_URL',
  40. 'BARK_SOUND',
  41. 'BARK_ENABLE',
  42. 'PUSHPLUS_KEY',
  43. 'PUSHPLUS_ENABLE',
  44. 'NOTICE_FREQ',
  45. 'VERIFY_SSL',
  46. 'DEBUG',
  47. 'NEW_VERSION_DETECTION',
  48. 'CUSTOM_LANGUAGE',
  49. 'SHOW_SERVER_INFO',
  50. 'MOSAIC_SENSITIVE_INFO',
  51. 'MAX_REQUEST_RETRY_COUNT',
  52. 'USE_OPEN_SOURCE_WAF_SOLVER_API',
  53. 'OPEN_SOURCE_WAF_SOLVER_URL',
  54. 'FF_SECRET_KEY',
  55. 'AWS_WAF_SOLVER_URL',
  56. ];
  57. protected function setUp(): void
  58. {
  59. parent::setUp();
  60. $this->resetStaticState();
  61. $this->loadFixtureEnv();
  62. }
  63. protected function tearDown(): void
  64. {
  65. $this->resetStaticState();
  66. parent::tearDown();
  67. }
  68. protected function loadFixtureEnv(array $overrides = []): void
  69. {
  70. foreach (self::ENV_KEYS as $key) {
  71. putenv($key);
  72. unset($_ENV[$key], $_SERVER[$key]);
  73. }
  74. $runtimeFile = ROOT_PATH . DS . 'tests' . DS . 'runtime' . DS . 'phpunit.env';
  75. $contents = (string) file_get_contents(ROOT_PATH . DS . self::FIXTURE_ENV_FILE);
  76. foreach ($overrides as $key => $value) {
  77. $contents .= sprintf("\n%s=%s", $key, $this->formatEnvValue($value));
  78. }
  79. file_put_contents($runtimeFile, trim($contents) . "\n");
  80. $this->resetStaticState();
  81. \Luolongfei\Libs\Env::getInstance()->init('tests/runtime/phpunit.env', true);
  82. }
  83. protected function setEnvValues(array $values): void
  84. {
  85. $this->loadFixtureEnv($values);
  86. }
  87. protected function makeWithoutConstructor(string $class): object
  88. {
  89. return (new \ReflectionClass($class))->newInstanceWithoutConstructor();
  90. }
  91. protected function newInstanceWithoutConstructor(string $class): object
  92. {
  93. return $this->makeWithoutConstructor($class);
  94. }
  95. protected function invokeMethod(object $object, string $method, array $args = [])
  96. {
  97. $reflection = new \ReflectionMethod($object, $method);
  98. return $reflection->invokeArgs($object, $args);
  99. }
  100. protected function setProperty(object|string $target, string $property, mixed $value): void
  101. {
  102. $reflection = new \ReflectionProperty($target, $property);
  103. $reflection->setValue(is_object($target) ? $target : null, $value);
  104. }
  105. protected function getProperty(object|string $target, string $property): mixed
  106. {
  107. $reflection = new \ReflectionProperty($target, $property);
  108. return $reflection->getValue(is_object($target) ? $target : null);
  109. }
  110. protected function createTempDir(string $name): string
  111. {
  112. $dir = ROOT_PATH . DS . 'tests' . DS . 'runtime' . DS . $name;
  113. if (is_dir($dir)) {
  114. $this->deleteDir($dir);
  115. }
  116. mkdir($dir, 0777, true);
  117. return $dir;
  118. }
  119. protected function resetProjectState(): void
  120. {
  121. $this->resetStaticState();
  122. }
  123. protected function seedBaseInstance(string $class, object $instance): void
  124. {
  125. $instances = $this->getProperty(\Luolongfei\Libs\Base::class, 'instances');
  126. $instances[$class] = $instance;
  127. $this->setProperty(\Luolongfei\Libs\Base::class, 'instances', $instances);
  128. }
  129. private function resetStaticState(): void
  130. {
  131. $this->setProperty(\Luolongfei\Libs\Base::class, 'instances', []);
  132. $this->setProperty(\Luolongfei\Libs\Log::class, 'loggerInstance', null);
  133. $this->setProperty(\Luolongfei\Libs\IP::class, 'ip', '');
  134. $this->setProperty(\Luolongfei\Libs\IP::class, 'loc', '');
  135. $this->setProperty(\Luolongfei\Libs\Message::class, 'notEnabledTips', true);
  136. foreach ([
  137. \Luolongfei\App\Console\Cron::class,
  138. \Luolongfei\App\Console\FreeNom::class,
  139. \Luolongfei\App\Console\GlobalValue::class,
  140. \Luolongfei\App\Console\MigrateEnvFile::class,
  141. \Luolongfei\App\Console\Upgrade::class,
  142. ] as $class) {
  143. $this->setProperty($class, 'instance', null);
  144. }
  145. }
  146. private function formatEnvValue(mixed $value): string
  147. {
  148. if (is_bool($value)) {
  149. return $value ? '1' : '0';
  150. }
  151. if ($value === null) {
  152. return "''";
  153. }
  154. if (is_numeric($value)) {
  155. return (string) $value;
  156. }
  157. return "'" . str_replace(['\\', "'"], ['\\\\', "\\'"], (string) $value) . "'";
  158. }
  159. private function deleteDir(string $dir): void
  160. {
  161. if (!is_dir($dir)) {
  162. return;
  163. }
  164. $items = scandir($dir) ?: [];
  165. foreach ($items as $item) {
  166. if ($item === '.' || $item === '..') {
  167. continue;
  168. }
  169. $path = $dir . DS . $item;
  170. if (is_dir($path)) {
  171. $this->deleteDir($path);
  172. continue;
  173. }
  174. unlink($path);
  175. }
  176. rmdir($dir);
  177. }
  178. }