Completed
Push — master ( d34b0d...4b6ea9 )
by Mark
24s queued 14s
created

ConsoleIntegrationTestTrait::cleanupConsoleTrait()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 8

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
nc 1
nop 0
dl 0
loc 8
rs 10
c 0
b 0
f 0
1
<?php
2
/**
3
 * CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
4
 * Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
5
 *
6
 * Licensed under The MIT License
7
 * For full copyright and license information, please see the LICENSE.txt
8
 * Redistributions of files must retain the above copyright notice
9
 *
10
 * @copyright     Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
11
 * @since         3.7.0
12
 * @license       http://www.opensource.org/licenses/mit-license.php MIT License
13
 */
14
namespace Cake\TestSuite;
15
16
use Cake\Console\CommandRunner;
17
use Cake\Console\ConsoleInput;
18
use Cake\Console\ConsoleIo;
19
use Cake\Console\Exception\StopException;
20
use Cake\Core\Configure;
21
use Cake\TestSuite\Constraint\Console\ContentsContain;
22
use Cake\TestSuite\Constraint\Console\ContentsContainRow;
23
use Cake\TestSuite\Constraint\Console\ContentsEmpty;
24
use Cake\TestSuite\Constraint\Console\ContentsNotContain;
25
use Cake\TestSuite\Constraint\Console\ContentsRegExp;
26
use Cake\TestSuite\Constraint\Console\ExitCode;
27
use Cake\TestSuite\Stub\ConsoleOutput;
28
29
/**
30
 * A test case class intended to make integration tests of cake console commands
31
 * easier.
32
 */
33
trait ConsoleIntegrationTestTrait
34
{
35
    /**
36
     * Whether or not to use the CommandRunner
37
     *
38
     * @var bool
39
     */
40
    protected $_useCommandRunner = false;
41
42
    /**
43
     * Last exit code
44
     *
45
     * @var int|null
46
     */
47
    protected $_exitCode;
48
49
    /**
50
     * Console output stub
51
     *
52
     * @var \Cake\TestSuite\Stub\ConsoleOutput|\PHPUnit_Framework_MockObject_MockObject|null
53
     */
54
    protected $_out;
55
56
    /**
57
     * Console error output stub
58
     *
59
     * @var \Cake\TestSuite\Stub\ConsoleOutput|\PHPUnit_Framework_MockObject_MockObject|null
60
     */
61
    protected $_err;
62
63
    /**
64
     * Console input mock
65
     *
66
     * @var \Cake\Console\ConsoleInput|\PHPUnit_Framework_MockObject_MockObject|null
67
     */
68
    protected $_in;
69
70
    /**
71
     * Runs cli integration test
72
     *
73
     * @param string $command Command to run
74
     * @param array $input Input values to pass to an interactive shell
75
     * @return void
76
     */
77
    public function exec($command, array $input = [])
78
    {
79
        $runner = $this->makeRunner();
80
81
        $this->_out = new ConsoleOutput();
82
        $this->_err = new ConsoleOutput();
83
        $this->_in = $this->getMockBuilder(ConsoleInput::class)
0 ignored issues
show
Bug introduced by
It seems like getMockBuilder() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
84
            ->disableOriginalConstructor()
85
            ->setMethods(['read'])
86
            ->getMock();
87
88
        $i = 0;
89
        foreach ($input as $in) {
90
            $this->_in
91
                ->expects($this->at($i++))
0 ignored issues
show
Bug introduced by
It seems like at() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
92
                ->method('read')
93
                ->will($this->returnValue($in));
0 ignored issues
show
Bug introduced by
It seems like returnValue() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
94
        }
95
96
        $args = $this->commandStringToArgs("cake $command");
97
        $io = new ConsoleIo($this->_out, $this->_err, $this->_in);
98
99
        try {
100
            $this->_exitCode = $runner->run($args, $io);
101
        } catch (StopException $exception) {
102
            $this->_exitCode = $exception->getCode();
103
        }
104
    }
105
106
    /**
107
     * Cleans state to get ready for the next test
108
     *
109
     * @after
110
     * @return void
111
     */
112
    public function cleanupConsoleTrait()
113
    {
114
        $this->_exitCode = null;
115
        $this->_out = null;
116
        $this->_err = null;
117
        $this->_in = null;
118
        $this->_useCommandRunner = false;
119
    }
120
121
    /**
122
     * Set this test case to use the CommandRunner rather than the legacy
123
     * ShellDispatcher
124
     *
125
     * @return void
126
     */
127
    public function useCommandRunner()
128
    {
129
        $this->_useCommandRunner = true;
130
    }
131
132
    /**
133
     * Asserts shell exited with the expected code
134
     *
135
     * @param int $expected Expected exit code
136
     * @param string $message Failure message
137
     * @return void
138
     */
139
    public function assertExitCode($expected, $message = '')
140
    {
141
        $this->assertThat($expected, new ExitCode($this->_exitCode), $message);
0 ignored issues
show
Bug introduced by
It seems like assertThat() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
142
    }
143
144
    /**
145
     * Asserts that `stdout` is empty
146
     *
147
     * @param string $message The message to output when the assertion fails.
148
     * @return void
149
     */
150
    public function assertOutputEmpty($message = '')
151
    {
152
        $this->assertThat(null, new ContentsEmpty($this->_out->messages(), 'output'), $message);
0 ignored issues
show
Bug introduced by
It seems like assertThat() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
153
    }
154
155
    /**
156
     * Asserts `stdout` contains expected output
157
     *
158
     * @param string $expected Expected output
159
     * @param string $message Failure message
160
     * @return void
161
     */
162
    public function assertOutputContains($expected, $message = '')
163
    {
164
        $this->assertThat($expected, new ContentsContain($this->_out->messages(), 'output'), $message);
0 ignored issues
show
Bug introduced by
It seems like assertThat() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
165
    }
166
    /**
167
     * Asserts `stdout` does not contain expected output
168
     *
169
     * @param string $expected Expected output
170
     * @param string $message Failure message
171
     * @return void
172
     */
173
    public function assertOutputNotContains($expected, $message = '')
174
    {
175
        $this->assertThat($expected, new ContentsNotContain($this->_out->messages(), 'output'), $message);
0 ignored issues
show
Bug introduced by
It seems like assertThat() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
176
    }
177
178
    /**
179
     * Asserts `stdout` contains expected regexp
180
     *
181
     * @param string $pattern Expected pattern
182
     * @param string $message Failure message
183
     * @return void
184
     */
185
    public function assertOutputRegExp($pattern, $message = '')
186
    {
187
        $this->assertThat($pattern, new ContentsRegExp($this->_out->messages(), 'output'), $message);
0 ignored issues
show
Bug introduced by
It seems like assertThat() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
188
    }
189
190
    /**
191
     * Check that a row of cells exists in the output.
192
     *
193
     * @param array $row Row of cells to ensure exist in the output.
194
     * @param string $message Failure message.
195
     * @return void
196
     */
197
    protected function assertOutputContainsRow(array $row, $message = '')
198
    {
199
        $this->assertThat($row, new ContentsContainRow($this->_out->messages(), 'output'), $message);
0 ignored issues
show
Bug introduced by
It seems like assertThat() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
200
    }
201
202
    /**
203
     * Asserts `stderr` contains expected output
204
     *
205
     * @param string $expected Expected output
206
     * @param string $message Failure message
207
     * @return void
208
     */
209
    public function assertErrorContains($expected, $message = '')
210
    {
211
        $this->assertThat($expected, new ContentsContain($this->_err->messages(), 'error output'), $message);
0 ignored issues
show
Bug introduced by
It seems like assertThat() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
212
    }
213
214
    /**
215
     * Asserts `stderr` contains expected regexp
216
     *
217
     * @param string $pattern Expected pattern
218
     * @param string $message Failure message
219
     * @return void
220
     */
221
    public function assertErrorRegExp($pattern, $message = '')
222
    {
223
        $this->assertThat($pattern, new ContentsRegExp($this->_err->messages(), 'error output'), $message);
0 ignored issues
show
Bug introduced by
It seems like assertThat() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
224
    }
225
226
    /**
227
     * Asserts that `stderr` is empty
228
     *
229
     * @param string $message The message to output when the assertion fails.
230
     * @return void
231
     */
232
    public function assertErrorEmpty($message = '')
233
    {
234
        $this->assertThat(null, new ContentsEmpty($this->_err->messages(), 'error output'), $message);
0 ignored issues
show
Bug introduced by
It seems like assertThat() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
235
    }
236
237
    /**
238
     * Builds the appropriate command dispatcher
239
     *
240
     * @return CommandRunner|LegacyCommandRunner
241
     */
242
    protected function makeRunner()
243
    {
244
        if ($this->_useCommandRunner) {
245
            $applicationClassName = Configure::read('App.namespace') . '\Application';
246
247
            return new CommandRunner(new $applicationClassName(CONFIG));
248
        }
249
250
        return new LegacyCommandRunner();
251
    }
252
253
    /**
254
     * Creates an $argv array from a command string
255
     *
256
     * @param string $command Command string
257
     * @return array
258
     */
259
    protected function commandStringToArgs($command)
260
    {
261
        $charCount = strlen($command);
262
        $argv = [];
263
        $arg = '';
264
        $inDQuote = false;
265
        $inSQuote = false;
266
        for ($i = 0; $i < $charCount; $i++) {
267
            $char = substr($command, $i, 1);
268
269
            // end of argument
270
            if ($char === ' ' && !$inDQuote && !$inSQuote) {
271
                if (strlen($arg)) {
272
                    $argv[] = $arg;
273
                }
274
                $arg = '';
275
                continue;
276
            }
277
278
            // exiting single quote
279
            if ($inSQuote && $char === "'") {
280
                $inSQuote = false;
281
                continue;
282
            }
283
284
            // exiting double quote
285
            if ($inDQuote && $char === '"') {
286
                $inDQuote = false;
287
                continue;
288
            }
289
290
            // entering double quote
291
            if ($char === '"' && !$inSQuote) {
292
                $inDQuote = true;
293
                continue;
294
            }
295
296
            // entering single quote
297
            if ($char === "'" && !$inDQuote) {
298
                $inSQuote = true;
299
                continue;
300
            }
301
302
            $arg .= $char;
303
        }
304
        $argv[] = $arg;
305
306
        return $argv;
307
    }
308
}
309