/
Command.php
245 lines (214 loc) · 6.13 KB
/
Command.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
<?php
/**
*
* This file is part of the Aura project for PHP.
*
* @package Aura.Framework
*
* @license http://opensource.org/licenses/bsd-license.php BSD
*
*/
namespace Aura\Framework\Cli\MakeTest;
use Aura\Framework\Cli\AbstractCommand;
use Aura\Framework\System;
use Aura\Framework\Inflect;
use Aura\Framework\Exception\SourceNotFound;
use Aura\Framework\Exception\TestFileExists;
use Aura\Framework\Exception\TestFileNotCreated;
use Aura\Framework\Exception\TestFileNotMoved;
/**
*
* Using PHPUnit, creates a test file from an existing package source class
* and places it in the package tests directory.
*
* Usage is ...
*
* $ php package/Aura.Framework/cli/make-test {$FILE}
*
* ... where `$FILE` is a package file path, e.g.
* `package/Vendor.Package/src/Vendor/Package/Class.php`.
*
* @package Aura.Framework
*
*/
class Command extends AbstractCommand
{
/**
*
* A system object.
*
* @var System
*
*/
protected $system;
/**
*
* The `phpunit` executable path.
*
* @var string
*
*/
protected $phpunit;
/**
*
* The bootstrap file PHPUnit should load.
*
* @var string
*
*/
protected $bootstrap;
/**
*
* Sets a System object for this class.
*
* @param System $system The System object.
*
* @return void
*
*/
public function setSystem(System $system)
{
$this->system = $system;
}
/**
*
* Sets the phpunit executable.
*
* @param string $phpunit The phpunit executable path.
*
* @return void
*
*/
public function setPhpunit($phpunit)
{
$this->phpunit = $phpunit;
}
/**
*
* Sets the location of the bootstrap file.
*
* @param string $bootstrap The path to the bootstrap file.
*
*/
public function setBootstrap($bootstrap)
{
$this->bootstrap = $bootstrap;
}
/**
*
* Creates a test file from an existing package source class and places
* it in the package tests directory.
*
* @return void
*
*/
public function action()
{
// get the file for the source to be tested
if (! isset($this->params[0])) {
$this->stdio->errln('Please specify a package file path.');
return -1;
}
$source_file = $this->params[0];
// what test file will phpunit create?
$create_file = str_replace('.php', 'Test.php', $source_file);
if (is_readable($create_file)) {
// don't want to overwrite an existing file
throw new TestFileExists($create_file);
}
// what target file will we move it to?
$target_file = str_replace(
DIRECTORY_SEPARATOR . 'src' . DIRECTORY_SEPARATOR,
DIRECTORY_SEPARATOR . 'tests' . DIRECTORY_SEPARATOR,
$create_file
);
if (is_readable($target_file)) {
// don't want to overwrite an existing file
throw new TestFileExists($target_file);
}
// get the class name
$class = $this->getClass($source_file);
// create the phpunit command
$cmd = $this->phpunit;
if ($this->bootstrap) {
$cmd .= " --bootstrap {$this->bootstrap}";
}
$cmd .= " --skeleton-test '{$class}' {$source_file}";
exec($cmd);
// did it get created?
if (! is_readable($create_file)) {
throw new TestFileNotCreated("Not created: '{$create_file}'");
}
// make sure we have a directory for the new location
@mkdir(dirname($target_file), 0755, true);
// move it to the proper location
$ok = rename($create_file, $target_file);
if (! $ok) {
throw new TestFileNotMoved("Could not move from '{$create_file}' to '{$target_file}'");
}
// modify it in place
$skel = file_get_contents($target_file);
$skel = $this->modifySkeleton($skel);
file_put_contents($target_file, $skel);
// done!
$this->stdio->outln("Test file created at '{$target_file}'.");
}
/**
*
* Given a class specification, extract the vendor, package, and class
* names.
*
* @param string $spec The fully-qualified class specification.
*
* @return array A seqential array of vendor name, package name, and
* class name.
*
*/
protected function getClass($spec)
{
// incoming spec: package/Vendor.Package/src/Vendor/Package/Class.php
$real = realpath($spec);
if (! $real) {
throw new SourceNotFound($spec);
}
// strip off the "package/" dir prefix
$len = strlen($this->system->getPackagePath() . DIRECTORY_SEPARATOR);
$spec = substr($real, $len);
// this should leave us with, e.g., Vendor.Package/src/Vendor/Package/Class.php
// get the package name out
$part = explode(DIRECTORY_SEPARATOR, $spec);
// pull off the top part and turn into vendor and package
list($vendor, $package) = explode('.', array_shift($part));
// pull off 'src'
array_shift($part);
// turn the rest into the full class name, minus .php
$class = substr(implode('\\', $part), 0, -4);
return $class;
}
/**
*
* Given a test class skeleton from PHPUnit, modify it so that it works
* nicely within the Aura testing system.
*
* @param string $skel The PHPUnit test class skeleton.
*
* @return string The modified test skeleton.
*
*/
protected function modifySkeleton($skel)
{
$skel = preg_replace('/\n\nrequire_once.*\n/', '', $skel);
$skel = str_replace(
"function setUp()\n {",
"function setUp()\n {\n parent::setUp();",
$skel
);
$skel = str_replace(
"function tearDown()\n {",
"function tearDown()\n {\n parent::tearDown();",
$skel
);
$skel = preg_replace('/\?\>\n$/', '', $skel);
return $skel;
}
}