BuilderTest.php 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253
  1. <?php
  2. declare(strict_types=1);
  3. namespace SPC\Tests\builder;
  4. use PHPUnit\Framework\Attributes\DataProvider;
  5. use PHPUnit\Framework\TestCase;
  6. use SPC\builder\BuilderBase;
  7. use SPC\builder\BuilderProvider;
  8. use SPC\builder\Extension;
  9. use SPC\builder\LibraryBase;
  10. use SPC\exception\RuntimeException;
  11. use SPC\exception\WrongUsageException;
  12. use SPC\store\FileSystem;
  13. use SPC\util\CustomExt;
  14. use SPC\util\DependencyUtil;
  15. use Symfony\Component\Console\Input\ArgvInput;
  16. /**
  17. * @internal
  18. */
  19. class BuilderTest extends TestCase
  20. {
  21. private BuilderBase $builder;
  22. public static function setUpBeforeClass(): void
  23. {
  24. BuilderProvider::makeBuilderByInput(new ArgvInput());
  25. BuilderProvider::getBuilder();
  26. }
  27. public function setUp(): void
  28. {
  29. $this->builder = BuilderProvider::makeBuilderByInput(new ArgvInput());
  30. [$extensions, $libs] = DependencyUtil::getExtsAndLibs(['mbregex']);
  31. $this->builder->proveLibs($libs);
  32. CustomExt::loadCustomExt();
  33. foreach ($extensions as $extension) {
  34. $class = CustomExt::getExtClass($extension);
  35. $ext = new $class($extension, $this->builder);
  36. $this->builder->addExt($ext);
  37. }
  38. foreach ($this->builder->getExts() as $ext) {
  39. $ext->checkDependency();
  40. }
  41. }
  42. public function testMakeBuilderByInput(): void
  43. {
  44. $this->assertInstanceOf(BuilderBase::class, BuilderProvider::makeBuilderByInput(new ArgvInput()));
  45. $this->assertInstanceOf(BuilderBase::class, BuilderProvider::getBuilder());
  46. }
  47. public function testGetLibAndGetLibs()
  48. {
  49. $this->assertIsArray($this->builder->getLibs());
  50. $this->assertInstanceOf(LibraryBase::class, $this->builder->getLib('onig'));
  51. }
  52. public function testGetExtAndGetExts()
  53. {
  54. $this->assertIsArray($this->builder->getExts());
  55. $this->assertInstanceOf(Extension::class, $this->builder->getExt('mbregex'));
  56. }
  57. public function testHasCpp()
  58. {
  59. // mbregex doesn't have cpp
  60. $this->assertFalse($this->builder->hasCpp());
  61. }
  62. public function testMakeExtensionArgs()
  63. {
  64. $this->assertStringContainsString('--enable-mbstring', $this->builder->makeExtensionArgs());
  65. }
  66. public function testIsLibsOnly()
  67. {
  68. // mbregex is not libs only
  69. $this->assertFalse($this->builder->isLibsOnly());
  70. }
  71. public function testGetPHPVersionID()
  72. {
  73. if (file_exists(SOURCE_PATH . '/php-src/main/php_version.h')) {
  74. $file = SOURCE_PATH . '/php-src/main/php_version.h';
  75. $cnt = preg_match('/PHP_VERSION_ID (\d+)/m', file_get_contents($file), $match);
  76. if ($cnt !== 0) {
  77. $this->assertEquals(intval($match[1]), $this->builder->getPHPVersionID());
  78. } else {
  79. $this->expectException(RuntimeException::class);
  80. $this->builder->getPHPVersionID();
  81. }
  82. } else {
  83. $this->expectException(WrongUsageException::class);
  84. $this->builder->getPHPVersionID();
  85. }
  86. }
  87. public function testGetPHPVersion()
  88. {
  89. if (file_exists(SOURCE_PATH . '/php-src/main/php_version.h')) {
  90. $file = SOURCE_PATH . '/php-src/main/php_version.h';
  91. $cnt = preg_match('/PHP_VERSION "(\d+\.\d+\.\d+)"/', file_get_contents($file), $match);
  92. if ($cnt !== 0) {
  93. $this->assertEquals($match[1], $this->builder->getPHPVersion());
  94. } else {
  95. $this->expectException(RuntimeException::class);
  96. $this->builder->getPHPVersion();
  97. }
  98. } else {
  99. $this->expectException(WrongUsageException::class);
  100. $this->builder->getPHPVersion();
  101. }
  102. }
  103. public function testGetPHPVersionFromArchive()
  104. {
  105. $lock = file_exists(DOWNLOAD_PATH . '/.lock.json') ? file_get_contents(DOWNLOAD_PATH . '/.lock.json') : false;
  106. if ($lock === false) {
  107. $this->assertFalse($this->builder->getPHPVersionFromArchive());
  108. } else {
  109. $lock = json_decode($lock, true);
  110. $file = $lock['php-src']['filename'] ?? null;
  111. if ($file === null) {
  112. $this->assertFalse($this->builder->getPHPVersionFromArchive());
  113. } else {
  114. $cnt = preg_match('/php-(\d+\.\d+\.\d+)/', $file, $match);
  115. if ($cnt !== 0) {
  116. $this->assertEquals($match[1], $this->builder->getPHPVersionFromArchive());
  117. } else {
  118. $this->assertFalse($this->builder->getPHPVersionFromArchive());
  119. }
  120. }
  121. }
  122. }
  123. public function testGetMicroVersion()
  124. {
  125. $file = FileSystem::convertPath(SOURCE_PATH . '/php-src/sapi/micro/php_micro.h');
  126. if (!file_exists($file)) {
  127. $this->assertFalse($this->builder->getMicroVersion());
  128. } else {
  129. $content = file_get_contents($file);
  130. $ver = '';
  131. preg_match('/#define PHP_MICRO_VER_MAJ (\d)/m', $content, $match);
  132. $ver .= $match[1] . '.';
  133. preg_match('/#define PHP_MICRO_VER_MIN (\d)/m', $content, $match);
  134. $ver .= $match[1] . '.';
  135. preg_match('/#define PHP_MICRO_VER_PAT (\d)/m', $content, $match);
  136. $ver .= $match[1];
  137. $this->assertEquals($ver, $this->builder->getMicroVersion());
  138. }
  139. }
  140. public static function providerGetBuildTypeName(): array
  141. {
  142. return [
  143. [BUILD_TARGET_CLI, 'cli'],
  144. [BUILD_TARGET_FPM, 'fpm'],
  145. [BUILD_TARGET_MICRO, 'micro'],
  146. [BUILD_TARGET_EMBED, 'embed'],
  147. [BUILD_TARGET_ALL, 'cli, micro, fpm, embed'],
  148. [BUILD_TARGET_CLI | BUILD_TARGET_EMBED, 'cli, embed'],
  149. ];
  150. }
  151. /**
  152. * @dataProvider providerGetBuildTypeName
  153. */
  154. public function testGetBuildTypeName(int $target, string $name): void
  155. {
  156. $this->assertEquals($name, $this->builder->getBuildTypeName($target));
  157. }
  158. public function testGetOption()
  159. {
  160. // we cannot assure the option exists, so just tests default value
  161. $this->assertEquals('foo', $this->builder->getOption('bar', 'foo'));
  162. }
  163. public function testGetOptions()
  164. {
  165. $this->assertIsArray($this->builder->getOptions());
  166. }
  167. public function testSetOptionIfNotExist()
  168. {
  169. $this->assertEquals(null, $this->builder->getOption('bar'));
  170. $this->builder->setOptionIfNotExist('bar', 'foo');
  171. $this->assertEquals('foo', $this->builder->getOption('bar'));
  172. }
  173. public function testSetOption()
  174. {
  175. $this->assertEquals(null, $this->builder->getOption('bar'));
  176. $this->builder->setOption('bar', 'foo');
  177. $this->assertEquals('foo', $this->builder->getOption('bar'));
  178. }
  179. public function testGetEnvString()
  180. {
  181. $this->assertIsString($this->builder->getEnvString());
  182. putenv('TEST_SPC_BUILDER=foo');
  183. $this->assertStringContainsString('TEST_SPC_BUILDER=foo', $this->builder->getEnvString(['TEST_SPC_BUILDER']));
  184. }
  185. public function testValidateLibsAndExts()
  186. {
  187. $this->builder->validateLibsAndExts();
  188. $this->assertTrue(true);
  189. }
  190. public static function providerEmitPatchPoint(): array
  191. {
  192. return [
  193. ['before-libs-extract'],
  194. ['after-libs-extract'],
  195. ['before-php-extract'],
  196. ['after-php-extract'],
  197. ['before-micro-extract'],
  198. ['after-micro-extract'],
  199. ['before-exts-extract'],
  200. ['after-exts-extract'],
  201. ['before-php-buildconf'],
  202. ['before-php-configure'],
  203. ['before-php-make'],
  204. ['before-sanity-check'],
  205. ];
  206. }
  207. /**
  208. * @dataProvider providerEmitPatchPoint
  209. */
  210. public function testEmitPatchPoint(string $point)
  211. {
  212. $code = '<?php if (patch_point() === "' . $point . '") echo "GOOD:' . $point . '";';
  213. // emulate patch point
  214. $this->builder->setOption('with-added-patch', ['/tmp/patch-point.' . $point . '.php']);
  215. FileSystem::writeFile('/tmp/patch-point.' . $point . '.php', $code);
  216. $this->expectOutputString('GOOD:' . $point);
  217. $this->builder->emitPatchPoint($point);
  218. }
  219. public function testEmitPatchPointNotExists()
  220. {
  221. $this->expectOutputRegex('/failed to run/');
  222. $this->expectException(RuntimeException::class);
  223. $this->builder->setOption('with-added-patch', ['/tmp/patch-point.not_exsssists.php']);
  224. $this->builder->emitPatchPoint('not-exists');
  225. }
  226. }