PageRenderTime 42ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 0ms

/bin/generate-command-test.php

http://github.com/nrk/predis
PHP | 260 lines | 157 code | 44 blank | 59 comment | 9 complexity | 44b03de7a6e2880fa29adb03d6897175 MD5 | raw file
  1. #!/usr/bin/env php
  2. <?php
  3. /*
  4. * This file is part of the Predis package.
  5. *
  6. * (c) Daniele Alessandri <suppakilla@gmail.com>
  7. *
  8. * For the full copyright and license information, please view the LICENSE
  9. * file that was distributed with this source code.
  10. */
  11. // -------------------------------------------------------------------------- //
  12. // This script can be used to automatically generate a file with the scheleton
  13. // of a test case to test a Redis command by specifying the name of the class
  14. // in the Predis\Commands namespace (only classes in this namespace are valid).
  15. // For example, to generate a test case for SET (which is represented by the
  16. // Predis\Commands\StringSet class):
  17. //
  18. // $ ./bin/generate-command-test.php --class=StringSet
  19. //
  20. // Here is a list of optional arguments:
  21. //
  22. // --realm: each command has its own realm (commands that operate on strings,
  23. // lists, sets and such) but while this realm is usually inferred from the name
  24. // of the specified class, sometimes it can be useful to override it with a
  25. // custom one.
  26. //
  27. // --output: write the generated test case to the specified path instead of
  28. // the default one.
  29. //
  30. // --overwrite: pre-existing test files are not overwritten unless this option
  31. // is explicitly specified.
  32. // -------------------------------------------------------------------------- //
  33. use Predis\Commands\ICommand;
  34. use Predis\Commands\IPrefixable;
  35. class CommandTestCaseGenerator
  36. {
  37. private $options;
  38. public function __construct(Array $options)
  39. {
  40. if (!isset($options['class'])) {
  41. throw new RuntimeException("Missing 'class' option.");
  42. }
  43. $this->options = $options;
  44. }
  45. public static function fromCommandLine()
  46. {
  47. $parameters = array(
  48. 'c:' => 'class:',
  49. 'r::' => 'realm::',
  50. 'o::' => 'output::',
  51. 'x::' => 'overwrite::'
  52. );
  53. $getops = getopt(implode(array_keys($parameters)), $parameters);
  54. $options = array(
  55. 'overwrite' => false,
  56. 'tests' => __DIR__.'/../tests',
  57. );
  58. foreach ($getops as $option => $value) {
  59. switch ($option) {
  60. case 'c':
  61. case 'class':
  62. $options['class'] = $value;
  63. break;
  64. case 'r':
  65. case 'realm':
  66. $options['realm'] = $value;
  67. break;
  68. case 'o':
  69. case 'output':
  70. $options['output'] = $value;
  71. break;
  72. case 'x':
  73. case 'overwrite':
  74. $options['overwrite'] = true;
  75. break;
  76. }
  77. }
  78. if (!isset($options['class'])) {
  79. throw new RuntimeException("Missing 'class' option.");
  80. }
  81. $options['fqn'] = "Predis\\Commands\\{$options['class']}";
  82. $options['path'] = "Predis/Commands/{$options['class']}.php";
  83. $source = __DIR__.'/../lib/'.$options['path'];
  84. if (!file_exists($source)) {
  85. throw new RuntimeException("Cannot find class file for {$options['fqn']} in $source.");
  86. }
  87. if (!isset($options['output'])) {
  88. $options['output'] = sprintf("%s/%s", $options['tests'], str_replace('.php', 'Test.php', $options['path']));
  89. }
  90. return new self($options);
  91. }
  92. protected function getTestRealm()
  93. {
  94. if (isset($this->options['realm'])) {
  95. if (!$this->options['realm']) {
  96. throw new RuntimeException('Invalid value for realm has been sepcified (empty).');
  97. }
  98. return $this->options['realm'];
  99. }
  100. $class = array_pop(explode('\\', $this->options['fqn']));
  101. list($realm,) = preg_split('/([[:upper:]][[:lower:]]+)/', $class, 2, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY);
  102. return strtolower($realm);
  103. }
  104. public function generate()
  105. {
  106. $reflection = new ReflectionClass($class = $this->options['fqn']);
  107. if (!$reflection->isInstantiable()) {
  108. throw new RuntimeException("Class $class must be instantiable, abstract classes or interfaces are not allowed.");
  109. }
  110. if (!$reflection->implementsInterface('Predis\Commands\ICommand')) {
  111. throw new RuntimeException("Class $class must implement the Predis\Commands\ICommand interface.");
  112. }
  113. $instance = $reflection->newInstance();
  114. $buffer = $this->getTestCaseBuffer($instance);
  115. return $buffer;
  116. }
  117. public function save()
  118. {
  119. $options = $this->options;
  120. if (file_exists($options['output']) && !$options['overwrite']) {
  121. throw new RuntimeException("File {$options['output']} already exist. Specify the --overwrite option to overwrite the existing file.");
  122. }
  123. file_put_contents($options['output'], $this->generate());
  124. }
  125. protected function getTestCaseBuffer(ICommand $instance)
  126. {
  127. $id = $instance->getId();
  128. $fqn = get_class($instance);
  129. $class = array_pop(explode('\\', $fqn)) . "Test";
  130. $realm = $this->getTestRealm();
  131. $buffer =<<<PHP
  132. <?php
  133. /*
  134. * This file is part of the Predis package.
  135. *
  136. * (c) Daniele Alessandri <suppakilla@gmail.com>
  137. *
  138. * For the full copyright and license information, please view the LICENSE
  139. * file that was distributed with this source code.
  140. */
  141. namespace Predis\Commands;
  142. use \PHPUnit_Framework_TestCase as StandardTestCase;
  143. /**
  144. * @group commands
  145. * @group realm-$realm
  146. */
  147. class $class extends CommandTestCase
  148. {
  149. /**
  150. * {@inheritdoc}
  151. */
  152. protected function getExpectedCommand()
  153. {
  154. return '$fqn';
  155. }
  156. /**
  157. * {@inheritdoc}
  158. */
  159. protected function getExpectedId()
  160. {
  161. return '$id';
  162. }
  163. /**
  164. * @group disconnected
  165. */
  166. public function testFilterArguments()
  167. {
  168. \$this->markTestIncomplete('This test has not been implemented yet.');
  169. \$arguments = array(/* add arguments */);
  170. \$expected = array(/* add arguments */);
  171. \$command = \$this->getCommand();
  172. \$command->setArguments(\$arguments);
  173. \$this->assertSame(\$expected, \$command->getArguments());
  174. }
  175. /**
  176. * @group disconnected
  177. */
  178. public function testParseResponse()
  179. {
  180. \$this->markTestIncomplete('This test has not been implemented yet.');
  181. \$raw = null;
  182. \$expected = null;
  183. \$command = \$this->getCommand();
  184. \$this->assertSame(\$expected, \$command->parseResponse(\$raw));
  185. }
  186. PHP;
  187. if ($instance instanceof IPrefixable) {
  188. $buffer .=<<<PHP
  189. /**
  190. * @group disconnected
  191. */
  192. public function testPrefixKeys()
  193. {
  194. \$this->markTestIncomplete('This test has not been implemented yet.');
  195. \$arguments = array(/* add arguments */);
  196. \$expected = array(/* add arguments */);
  197. \$command = \$this->getCommandWithArgumentsArray(\$arguments);
  198. \$command->prefixKeys('prefix:');
  199. \$this->assertSame(\$expected, \$command->getArguments());
  200. }
  201. PHP;
  202. }
  203. return "$buffer}\n";
  204. }
  205. }
  206. // ------------------------------------------------------------------------- //
  207. require __DIR__.'/../autoload.php';
  208. $generator = CommandTestCaseGenerator::fromCommandLine();
  209. $generator->save();