/classes/test/generator.php

https://github.com/Hywan/atoum · PHP · 297 lines · 227 code · 70 blank · 0 comment · 11 complexity · f243b16b1e352df379125fd75ad5c31c MD5 · raw file

  1. <?php
  2. namespace mageekguy\atoum\test;
  3. use mageekguy\atoum;
  4. use mageekguy\atoum\fs\path;
  5. use mageekguy\atoum\template;
  6. class generator
  7. {
  8. protected $templatesDirectory = '';
  9. protected $testedClassesDirectory = null;
  10. protected $testedClassNamespace = null;
  11. protected $testClassesDirectory = null;
  12. protected $testClassNamespace = null;
  13. protected $testedClassPathExtractor = null;
  14. protected $fullyQualifiedTestClassNameExtractor = null;
  15. protected $fullyQualifiedTestedClassNameExtractor = null;
  16. protected $runnerPath = null;
  17. protected $templateParser = null;
  18. protected $pathFactory = null;
  19. protected $adapter = null;
  20. public function __construct()
  21. {
  22. $this
  23. ->setTemplatesDirectory()
  24. ->setTemplateParser()
  25. ->setPathFactory()
  26. ->setAdapter()
  27. ->setFullyQualifiedTestClassNameExtractor()
  28. ->setFullyQualifiedTestedClassNameExtractor()
  29. ->setTestedClassPathExtractor()
  30. ;
  31. }
  32. public function setTemplatesDirectory($directory = null)
  33. {
  34. $this->templatesDirectory = $directory ?: atoum\directory . DIRECTORY_SEPARATOR . 'resources' . DIRECTORY_SEPARATOR . 'templates' . DIRECTORY_SEPARATOR . 'test' . DIRECTORY_SEPARATOR . 'generator';
  35. return $this;
  36. }
  37. public function getTemplatesDirectory()
  38. {
  39. return $this->templatesDirectory;
  40. }
  41. public function setTestedClassesDirectory($directory)
  42. {
  43. $this->testedClassesDirectory = self::cleanDirectory($directory);
  44. return $this;
  45. }
  46. public function getTestedClassesDirectory()
  47. {
  48. return $this->testedClassesDirectory;
  49. }
  50. public function setTestClassesDirectory($directory)
  51. {
  52. $this->testClassesDirectory = self::cleanDirectory($directory);
  53. return $this;
  54. }
  55. public function getTestClassesDirectory()
  56. {
  57. return $this->testClassesDirectory;
  58. }
  59. public function setRunnerPath($path)
  60. {
  61. $this->runnerPath = $path;
  62. return $this;
  63. }
  64. public function getRunnerPath()
  65. {
  66. return $this->runnerPath;
  67. }
  68. public function setTemplateParser(template\parser $parser = null)
  69. {
  70. $this->templateParser = $parser ?: new template\parser();
  71. return $this;
  72. }
  73. public function getTemplateParser()
  74. {
  75. return $this->templateParser;
  76. }
  77. public function setPathFactory(path\factory $factory = null)
  78. {
  79. $this->pathFactory = $factory ?: new path\factory();
  80. return $this;
  81. }
  82. public function getPathFactory()
  83. {
  84. return $this->pathFactory;
  85. }
  86. public function setAdapter(atoum\adapter $adapter = null)
  87. {
  88. $this->adapter = $adapter ?: new atoum\adapter();
  89. return $this;
  90. }
  91. public function getAdapter()
  92. {
  93. return $this->adapter;
  94. }
  95. public function setTestedClassNamespace($namespace)
  96. {
  97. $this->testedClassNamespace = self::cleanNamespace($namespace);
  98. return $this;
  99. }
  100. public function getTestedClassNamespace()
  101. {
  102. return $this->testedClassNamespace;
  103. }
  104. public function setTestClassNamespace($namespace)
  105. {
  106. $this->testClassNamespace = self::cleanNamespace($namespace);
  107. return $this;
  108. }
  109. public function getTestClassNamespace()
  110. {
  111. return $this->testClassNamespace;
  112. }
  113. public function setFullyQualifiedTestClassNameExtractor(\closure $extractor = null)
  114. {
  115. $this->fullyQualifiedTestClassNameExtractor = $extractor ?: function ($generator, $relativeTestClassPath) {
  116. return $generator->getTestClassNamespace() . str_replace(DIRECTORY_SEPARATOR, '\\', substr($relativeTestClassPath, 0, -4));
  117. };
  118. return $this;
  119. }
  120. public function getFullyQualifiedTestClassNameExtractor()
  121. {
  122. return $this->fullyQualifiedTestClassNameExtractor;
  123. }
  124. public function setFullyQualifiedTestedClassNameExtractor(\closure $extractor = null)
  125. {
  126. $this->fullyQualifiedTestedClassNameExtractor = $extractor ?: function ($generator, $fullyQualifiedTestClassName) {
  127. return $generator->getTestedClassNamespace() . substr($fullyQualifiedTestClassName, strlen($generator->getTestClassNamespace()));
  128. };
  129. return $this;
  130. }
  131. public function getFullyQualifiedTestedClassNameExtractor()
  132. {
  133. return $this->fullyQualifiedTestedClassNameExtractor;
  134. }
  135. public function setTestedClassPathExtractor(\closure $extractor = null)
  136. {
  137. $this->testedClassPathExtractor = $extractor ?: function ($generator, $fullyQualifiedTestedClassName) {
  138. return $generator->getTestedClassesDirectory() . substr(str_replace('\\', DIRECTORY_SEPARATOR, $fullyQualifiedTestedClassName), strlen($generator->getTestedClassNamespace())) . '.php';
  139. };
  140. return $this;
  141. }
  142. public function getTestedClassPathExtractor()
  143. {
  144. return $this->testedClassPathExtractor;
  145. }
  146. public function generate($testClassPath)
  147. {
  148. if ($this->testedClassesDirectory === null) {
  149. throw new generator\exception('Tested classes directory is undefined');
  150. }
  151. if ($this->testClassesDirectory === null) {
  152. throw new generator\exception('Tests directory is undefined');
  153. }
  154. if ($this->testedClassNamespace === null) {
  155. throw new generator\exception('Tested class namespace is undefined');
  156. }
  157. if ($this->testClassNamespace === null) {
  158. throw new generator\exception('Test class namespace is undefined');
  159. }
  160. $testClassesDirectory = $this->pathFactory->build($this->testClassesDirectory);
  161. if ($testClassesDirectory->exists() === false) {
  162. throw new generator\exception('Test classes directory \'' . $testClassesDirectory . '\' does not exist');
  163. }
  164. $realTestClassesDirectory = $testClassesDirectory->getRealPath();
  165. $realTestClassPath = $this->pathFactory->build($testClassPath)->getRealPath();
  166. $realTestClassBaseDirectory = $realTestClassPath->getRealParentDirectoryPath();
  167. if ((string) $realTestClassesDirectory !== (string) $realTestClassBaseDirectory && $realTestClassBaseDirectory->isSubPathOf($realTestClassesDirectory) === false) {
  168. throw new generator\exception('Path \'' . $testClassPath . '\' is not in directory \'' . $this->testClassesDirectory . '\'');
  169. }
  170. $realTestClassRelativePath = substr($realTestClassPath->getRelativePathFrom($realTestClassesDirectory), 2);
  171. $fullyQualifiedTestClassName = call_user_func_array($this->fullyQualifiedTestClassNameExtractor, [$this, $realTestClassRelativePath]);
  172. $testClassTemplate = $this->templateParser->parseFile($this->templatesDirectory . DIRECTORY_SEPARATOR . 'testClass.php');
  173. $testClassTemplate->fullyQualifiedTestClassName = $fullyQualifiedTestClassName;
  174. $testClassTemplate->testClassName = self::getShortClassName($fullyQualifiedTestClassName);
  175. $testClassTemplate->testClassNamespace = self::getClassNamespace($fullyQualifiedTestClassName);
  176. if ($this->runnerPath !== null) {
  177. $runnerPath = $this->pathFactory->build($this->runnerPath);
  178. $relativeRunnerPath = $runnerPath->relativizeFrom($realTestClassBaseDirectory);
  179. $testClassTemplate->requireRunner->relativeRunnerPath = $relativeRunnerPath;
  180. $testClassTemplate->requireRunner->build();
  181. }
  182. $fullyQualifiedTestedClassName = call_user_func_array($this->fullyQualifiedTestedClassNameExtractor, [$this, $fullyQualifiedTestClassName]);
  183. if ($this->adapter->class_exists($fullyQualifiedTestedClassName) === false) {
  184. $testClassTemplate->testMethods->testMethod->methodName = '__construct';
  185. $testClassTemplate->testMethods->testMethod->methodName->build();
  186. $testClassTemplate->testMethods->testMethod->build();
  187. $testedClassPath = $this->pathFactory->build(call_user_func_array($this->testedClassPathExtractor, [$this, $fullyQualifiedTestedClassName]));
  188. $testedClassTemplate = $this->templateParser->parseFile($this->templatesDirectory . DIRECTORY_SEPARATOR . 'testedClass.php');
  189. $testedClassTemplate->testedClassName = self::getShortClassName($fullyQualifiedTestedClassName);
  190. $testedClassTemplate->testedClassNamespace = self::getClassNamespace($fullyQualifiedTestedClassName);
  191. $testedClassPath->putContents($testedClassTemplate->build());
  192. } else {
  193. $testedClass = new \reflectionClass($fullyQualifiedTestedClassName);
  194. foreach ($testedClass->getMethods(\reflectionMethod::IS_PUBLIC) as $publicMethod) {
  195. $testClassTemplate->testMethods->testMethod->methodName = $publicMethod->getName();
  196. $testClassTemplate->testMethods->testMethod->methodName->build();
  197. $testClassTemplate->testMethods->testMethod->build();
  198. }
  199. }
  200. $testClassTemplate->testMethods->build();
  201. $realTestClassPath->putContents($testClassTemplate->build());
  202. return $this;
  203. }
  204. protected function saveClassInFile($class, $file)
  205. {
  206. if (@$this->adapter->file_put_contents($file, $class) === false) {
  207. throw new generator\exception('Unable to write in file \'' . $file . '\'');
  208. }
  209. return $this;
  210. }
  211. protected static function cleanDirectory($path)
  212. {
  213. return rtrim($path, DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR;
  214. }
  215. protected static function cleanNamespace($namespace)
  216. {
  217. return trim($namespace, '\\') . '\\';
  218. }
  219. protected static function getShortClassName($fullyQualifiedClassName)
  220. {
  221. return basename(str_replace('\\', DIRECTORY_SEPARATOR, $fullyQualifiedClassName));
  222. }
  223. protected static function getClassNamespace($fullyQualifiedClassName)
  224. {
  225. return str_replace(DIRECTORY_SEPARATOR, '\\', dirname(str_replace('\\', DIRECTORY_SEPARATOR, $fullyQualifiedClassName)));
  226. }
  227. }