Project

General

Profile

1
#!/usr/bin/env php
2
<?php
3

    
4
/*
5
 * This file is part of the Predis package.
6
 *
7
 * (c) Daniele Alessandri <suppakilla@gmail.com>
8
 *
9
 * For the full copyright and license information, please view the LICENSE
10
 * file that was distributed with this source code.
11
 */
12

    
13
// -------------------------------------------------------------------------- //
14
// This script can be used to automatically generate a file with the scheleton
15
// of a test case to test a Redis command by specifying the name of the class
16
// in the Predis\Command namespace (only classes in this namespace are valid).
17
// For example, to generate a test case for SET (which is represented by the
18
// Predis\Command\StringSet class):
19
//
20
//   $ ./bin/generate-command-test.php --class=StringSet
21
//
22
// Here is a list of optional arguments:
23
//
24
// --realm: each command has its own realm (commands that operate on strings,
25
// lists, sets and such) but while this realm is usually inferred from the name
26
// of the specified class, sometimes it can be useful to override it with a
27
// custom one.
28
//
29
// --output: write the generated test case to the specified path instead of
30
// the default one.
31
//
32
// --overwrite: pre-existing test files are not overwritten unless this option
33
// is explicitly specified.
34
// -------------------------------------------------------------------------- //
35

    
36
use Predis\Command\CommandInterface;
37
use Predis\Command\PrefixableCommandInterface;
38

    
39
class CommandTestCaseGenerator
40
{
41
    private $options;
42

    
43
    public function __construct(Array $options)
44
    {
45
        if (!isset($options['class'])) {
46
            throw new RuntimeException("Missing 'class' option.");
47
        }
48
        $this->options = $options;
49
    }
50

    
51
    public static function fromCommandLine()
52
    {
53
        $parameters = array(
54
            'c:'  => 'class:',
55
            'r::' => 'realm::',
56
            'o::' => 'output::',
57
            'x::' => 'overwrite::'
58
        );
59

    
60
        $getops = getopt(implode(array_keys($parameters)), $parameters);
61

    
62
        $options = array(
63
            'overwrite' => false,
64
            'tests' => __DIR__.'/../tests',
65
        );
66

    
67
        foreach ($getops as $option => $value) {
68
            switch ($option) {
69
                case 'c':
70
                case 'class':
71
                    $options['class'] = $value;
72
                    break;
73

    
74
                case 'r':
75
                case 'realm':
76
                    $options['realm'] = $value;
77
                    break;
78

    
79
                case 'o':
80
                case 'output':
81
                    $options['output'] = $value;
82
                    break;
83

    
84
                case 'x':
85
                case 'overwrite':
86
                    $options['overwrite'] = true;
87
                    break;
88
            }
89
        }
90

    
91
        if (!isset($options['class'])) {
92
            throw new RuntimeException("Missing 'class' option.");
93
        }
94

    
95
        $options['fqn'] = "Predis\\Command\\{$options['class']}";
96
        $options['path'] = "Predis/Command/{$options['class']}.php";
97

    
98
        $source = __DIR__.'/../lib/'.$options['path'];
99
        if (!file_exists($source)) {
100
            throw new RuntimeException("Cannot find class file for {$options['fqn']} in $source.");
101
        }
102

    
103
        if (!isset($options['output'])) {
104
            $options['output'] = sprintf("%s/%s", $options['tests'], str_replace('.php', 'Test.php', $options['path']));
105
        }
106

    
107
        return new self($options);
108
    }
109

    
110
    protected function getTestRealm()
111
    {
112
        if (isset($this->options['realm'])) {
113
            if (!$this->options['realm']) {
114
                throw new RuntimeException('Invalid value for realm has been sepcified (empty).');
115
            }
116
            return $this->options['realm'];
117
        }
118

    
119
        $fqnParts = explode('\\', $this->options['fqn']);
120
        $class = array_pop($fqnParts);
121
        list($realm,) = preg_split('/([[:upper:]][[:lower:]]+)/', $class, 2, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY);
122

    
123
        return strtolower($realm);
124
    }
125

    
126
    public function generate()
127
    {
128
        $reflection = new ReflectionClass($class = $this->options['fqn']);
129

    
130
        if (!$reflection->isInstantiable()) {
131
            throw new RuntimeException("Class $class must be instantiable, abstract classes or interfaces are not allowed.");
132
        }
133
        if (!$reflection->implementsInterface('Predis\Command\CommandInterface')) {
134
            throw new RuntimeException("Class $class must implement Predis\Command\CommandInterface.");
135
        }
136

    
137
        $instance = $reflection->newInstance();
138
        $buffer = $this->getTestCaseBuffer($instance);
139

    
140
        return $buffer;
141
    }
142

    
143
    public function save()
144
    {
145
        $options = $this->options;
146
        if (file_exists($options['output']) && !$options['overwrite']) {
147
            throw new RuntimeException("File {$options['output']} already exist. Specify the --overwrite option to overwrite the existing file.");
148
        }
149
        file_put_contents($options['output'], $this->generate());
150
    }
151

    
152
    protected function getTestCaseBuffer(CommandInterface $instance)
153
    {
154
        $id = $instance->getId();
155
        $fqn = get_class($instance);
156
        $fqnParts = explode('\\', $fqn);
157
        $class = array_pop($fqnParts) . "Test";
158
        $realm = $this->getTestRealm();
159

    
160
        $buffer =<<<PHP
161
<?php
162

    
163
/*
164
 * This file is part of the Predis package.
165
 *
166
 * (c) Daniele Alessandri <suppakilla@gmail.com>
167
 *
168
 * For the full copyright and license information, please view the LICENSE
169
 * file that was distributed with this source code.
170
 */
171

    
172
namespace Predis\Command;
173

    
174
/**
175
 * @group commands
176
 * @group realm-$realm
177
 */
178
class $class extends PredisCommandTestCase
179
{
180
    /**
181
     * {@inheritdoc}
182
     */
183
    protected function getExpectedCommand()
184
    {
185
        return '$fqn';
186
    }
187

    
188
    /**
189
     * {@inheritdoc}
190
     */
191
    protected function getExpectedId()
192
    {
193
        return '$id';
194
    }
195

    
196
    /**
197
     * @group disconnected
198
     */
199
    public function testFilterArguments()
200
    {
201
        \$this->markTestIncomplete('This test has not been implemented yet.');
202

    
203
        \$arguments = array(/* add arguments */);
204
        \$expected = array(/* add arguments */);
205

    
206
        \$command = \$this->getCommand();
207
        \$command->setArguments(\$arguments);
208

    
209
        \$this->assertSame(\$expected, \$command->getArguments());
210
    }
211

    
212
    /**
213
     * @group disconnected
214
     */
215
    public function testParseResponse()
216
    {
217
        \$this->markTestIncomplete('This test has not been implemented yet.');
218

    
219
        \$raw = null;
220
        \$expected = null;
221

    
222
        \$command = \$this->getCommand();
223

    
224
        \$this->assertSame(\$expected, \$command->parseResponse(\$raw));
225
    }
226

    
227
PHP;
228

    
229
        if ($instance instanceof PrefixableCommandInterface) {
230
            $buffer .=<<<PHP
231

    
232
    /**
233
     * @group disconnected
234
     */
235
    public function testPrefixKeys()
236
    {
237
        \$this->markTestIncomplete('This test has not been implemented yet.');
238

    
239
        \$arguments = array(/* add arguments */);
240
        \$expected = array(/* add arguments */);
241

    
242
        \$command = \$this->getCommandWithArgumentsArray(\$arguments);
243
        \$command->prefixKeys('prefix:');
244

    
245
        \$this->assertSame(\$expected, \$command->getArguments());
246
    }
247

    
248
    /**
249
     * @group disconnected
250
     */
251
    public function testPrefixKeysIgnoredOnEmptyArguments()
252
    {
253
        \$command = \$this->getCommand();
254
        \$command->prefixKeys('prefix:');
255

    
256
        \$this->assertSame(array(), \$command->getArguments());
257
    }
258

    
259
PHP;
260
        }
261

    
262
        return "$buffer}\n";
263
    }
264
}
265

    
266
// ------------------------------------------------------------------------- //
267

    
268
require __DIR__.'/../autoload.php';
269

    
270
$generator = CommandTestCaseGenerator::fromCommandLine();
271
$generator->save();
(1-1/4)