create-command-test 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278
  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\Command 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\Command\Redis\StringSet class):
  17. //
  18. // $ ./bin/generate-command-test --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\Command\CommandInterface;
  34. use Predis\Command\PrefixableCommandInterface;
  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. if (!isset($options['realm'])) {
  44. throw new RuntimeException("Missing 'realm' option.");
  45. }
  46. $this->options = $options;
  47. }
  48. public static function fromCommandLine()
  49. {
  50. $parameters = array(
  51. 'c:' => 'class:',
  52. 'r::' => 'realm::',
  53. 'o::' => 'output::',
  54. 'x::' => 'overwrite::'
  55. );
  56. $getops = getopt(implode(array_keys($parameters)), $parameters);
  57. $options = array(
  58. 'overwrite' => false,
  59. 'tests' => __DIR__.'/../tests/Predis',
  60. );
  61. foreach ($getops as $option => $value) {
  62. switch ($option) {
  63. case 'c':
  64. case 'class':
  65. $options['class'] = $value;
  66. break;
  67. case 'r':
  68. case 'realm':
  69. $options['realm'] = $value;
  70. break;
  71. case 'o':
  72. case 'output':
  73. $options['output'] = $value;
  74. break;
  75. case 'x':
  76. case 'overwrite':
  77. $options['overwrite'] = true;
  78. break;
  79. }
  80. }
  81. if (!isset($options['class'])) {
  82. throw new RuntimeException("Missing 'class' option.");
  83. }
  84. if (!isset($options['realm'])) {
  85. throw new RuntimeException("Missing 'realm' option.");
  86. }
  87. $options['fqn'] = "Predis\\Command\\Redis\\{$options['class']}";
  88. $options['path'] = "Command/Redis/{$options['class']}.php";
  89. $source = __DIR__.'/../src/'.$options['path'];
  90. if (!file_exists($source)) {
  91. throw new RuntimeException("Cannot find class file for {$options['fqn']} in $source.");
  92. }
  93. if (!isset($options['output'])) {
  94. $options['output'] = sprintf("%s/%s", $options['tests'], str_replace('.php', '_Test.php', $options['path']));
  95. }
  96. return new self($options);
  97. }
  98. protected function getTestRealm()
  99. {
  100. if (empty($this->options['realm'])) {
  101. throw new RuntimeException('Invalid value for realm has been sepcified (empty).');
  102. }
  103. return $this->options['realm'];
  104. }
  105. public function generate()
  106. {
  107. $reflection = new ReflectionClass($class = $this->options['fqn']);
  108. if (!$reflection->isInstantiable()) {
  109. throw new RuntimeException("Class $class must be instantiable, abstract classes or interfaces are not allowed.");
  110. }
  111. if (!$reflection->implementsInterface('Predis\Command\CommandInterface')) {
  112. throw new RuntimeException("Class $class must implement Predis\Command\CommandInterface.");
  113. }
  114. /*
  115. * @var CommandInterface
  116. */
  117. $instance = $reflection->newInstance();
  118. $buffer = $this->getTestCaseBuffer($instance);
  119. return $buffer;
  120. }
  121. public function save()
  122. {
  123. $options = $this->options;
  124. if (file_exists($options['output']) && !$options['overwrite']) {
  125. throw new RuntimeException("File {$options['output']} already exist. Specify the --overwrite option to overwrite the existing file.");
  126. }
  127. file_put_contents($options['output'], $this->generate());
  128. }
  129. protected function getTestCaseBuffer(CommandInterface $instance)
  130. {
  131. $id = $instance->getId();
  132. $fqn = get_class($instance);
  133. $fqnParts = explode('\\', $fqn);
  134. $class = array_pop($fqnParts) . "Test";
  135. $realm = $this->getTestRealm();
  136. $buffer =<<<PHP
  137. <?php
  138. /*
  139. * This file is part of the Predis package.
  140. *
  141. * (c) Daniele Alessandri <suppakilla@gmail.com>
  142. *
  143. * For the full copyright and license information, please view the LICENSE
  144. * file that was distributed with this source code.
  145. */
  146. namespace Predis\Command\Redis;
  147. /**
  148. * @group commands
  149. * @group realm-$realm
  150. */
  151. class $class extends PredisCommandTestCase
  152. {
  153. /**
  154. * {@inheritdoc}
  155. */
  156. protected function getExpectedCommand()
  157. {
  158. return '$fqn';
  159. }
  160. /**
  161. * {@inheritdoc}
  162. */
  163. protected function getExpectedId()
  164. {
  165. return '$id';
  166. }
  167. /**
  168. * @group disconnected
  169. */
  170. public function testFilterArguments()
  171. {
  172. \$this->markTestIncomplete('This test has not been implemented yet.');
  173. \$arguments = array(/* add arguments */);
  174. \$expected = array(/* add arguments */);
  175. \$command = \$this->getCommand();
  176. \$command->setArguments(\$arguments);
  177. \$this->assertSame(\$expected, \$command->getArguments());
  178. }
  179. /**
  180. * @group disconnected
  181. */
  182. public function testParseResponse()
  183. {
  184. \$this->markTestIncomplete('This test has not been implemented yet.');
  185. \$raw = null;
  186. \$expected = null;
  187. \$command = \$this->getCommand();
  188. \$this->assertSame(\$expected, \$command->parseResponse(\$raw));
  189. }
  190. PHP;
  191. if ($instance instanceof PrefixableCommandInterface) {
  192. $buffer .=<<<PHP
  193. /**
  194. * @group disconnected
  195. */
  196. public function testPrefixKeys()
  197. {
  198. \$this->markTestIncomplete('This test has not been implemented yet.');
  199. \$arguments = array(/* add arguments */);
  200. \$expected = array(/* add arguments */);
  201. \$command = \$this->getCommandWithArgumentsArray(\$arguments);
  202. \$command->prefixKeys('prefix:');
  203. \$this->assertSame(\$expected, \$command->getArguments());
  204. }
  205. /**
  206. * @group disconnected
  207. */
  208. public function testPrefixKeysIgnoredOnEmptyArguments()
  209. {
  210. \$command = \$this->getCommand();
  211. \$command->prefixKeys('prefix:');
  212. \$this->assertSame(array(), \$command->getArguments());
  213. }
  214. PHP;
  215. }
  216. return "$buffer}\n";
  217. }
  218. }
  219. // ------------------------------------------------------------------------- //
  220. require __DIR__.'/../autoload.php';
  221. $generator = CommandTestCaseGenerator::fromCommandLine();
  222. $generator->save();