Skip to content

Commit 3c49e19

Browse files
author
Gianluca Arbezzano
committed
Merge pull request #2 from tomphp/feature/testing
Add idea for acceptance testing
2 parents 8eb5678 + d7efbc7 commit 3c49e19

File tree

12 files changed

+1090
-1
lines changed

12 files changed

+1090
-1
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
tests/*.expect
22
tests/*.result
3+
tests/.test_fs
34
build/
45
vendor/
56
phpctags

composer.json

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,5 +13,10 @@
1313
"autoload": {
1414
"classmap": ["PHPCtags.class.php"]
1515
},
16+
"autoload-dev": {
17+
"psr-4": {
18+
"tests\\PHPCTags\\": "tests/"
19+
}
20+
},
1621
"bin": ["phpctags"]
1722
}

composer.lock

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 265 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,265 @@
1+
<?php
2+
3+
namespace tests\PHPCTags\Acceptance;
4+
5+
use Exception;
6+
use PHPUnit_Framework_TestCase;
7+
use RecursiveDirectoryIterator;
8+
use RecursiveIteratorIterator;
9+
10+
abstract class AcceptanceTestCase extends PHPUnit_Framework_TestCase
11+
{
12+
const FORMAT = "<name>\t<file>\t/^<line content>$/;\"\t<short kind>\tline:<line number>\t<scope>\t<access>";
13+
14+
const KIND_TRAIT = 't';
15+
const KIND_CLASS = 'c';
16+
const KIND_METHOD = 'm';
17+
const KIND_FUNCTION = 'f';
18+
const KIND_PROPERTY = 'p';
19+
const KIND_CONSTANT = 'd';
20+
const KIND_VARIABLE = 'v';
21+
const KIND_INTERFACE = 'i';
22+
const KIND_NAMESPACE = 'n';
23+
24+
/**
25+
* @var string
26+
*/
27+
private $testDir;
28+
29+
/**
30+
* @var string
31+
*/
32+
private $tagsFileContent;
33+
34+
protected function setUp()
35+
{
36+
$this->testDir = __DIR__ . '/../.test_fs';
37+
38+
if (!file_exists($this->testDir)) {
39+
mkdir($this->testDir);
40+
}
41+
42+
$this->testDir = realpath($this->testDir);
43+
44+
$this->emptyTestDir();
45+
}
46+
47+
/**
48+
* @param string $filename
49+
* @param string $content
50+
*
51+
* @return void
52+
*/
53+
protected function givenSourceFile($filename, $content)
54+
{
55+
$filename = $this->testDir . DIRECTORY_SEPARATOR . $filename;
56+
57+
file_put_contents($filename, $content);
58+
}
59+
60+
/**
61+
* @return void
62+
*/
63+
protected function runPHPCtags()
64+
{
65+
$entryPoint = realpath(__DIR__ . '/../../bootstrap.php');
66+
67+
exec("php \"$entryPoint\" --recurse=yes -f - {$this->testDir}", $output);
68+
69+
$this->tagsFileContent = $output;
70+
}
71+
72+
/**
73+
* @param string $patterns
74+
*
75+
* @return void
76+
*/
77+
protected function runPHPCtagsWithExcludes(array $patterns)
78+
{
79+
$entryPoint = realpath(__DIR__ . '/../../bootstrap.php');
80+
81+
$excludes = implode(
82+
' ',
83+
array_map(function ($pattern) {
84+
return '--exclude=\'' . $pattern . '\'';
85+
}, $patterns)
86+
);
87+
88+
exec("php \"$entryPoint\" --recurse=yes -f - $excludes {$this->testDir}", $output);
89+
90+
$this->tagsFileContent = $output;
91+
}
92+
93+
/**
94+
* @return void
95+
*/
96+
protected function assertTagsFileHeaderIsCorrect()
97+
{
98+
$expectedHeader = array(
99+
"!_TAG_FILE_FORMAT\t2\t/extended format; --format=1 will not append ;\" to lines/",
100+
"!_TAG_FILE_SORTED\t1\t/0=unsorted, 1=sorted, 2=foldcase/",
101+
"!_TAG_PROGRAM_AUTHOR\ttechlivezheng\t/techlivezheng@gmail.com/",
102+
"!_TAG_PROGRAM_NAME\tphpctags\t//",
103+
"!_TAG_PROGRAM_URL\thttps://github.com/techlivezheng/phpctags\t/official site/",
104+
"!_TAG_PROGRAM_VERSION\t0.5.1\t//",
105+
);
106+
107+
$realHeader = array_splice($this->tagsFileContent, 0, count($expectedHeader));
108+
109+
$this->assertEquals($expectedHeader, $realHeader, 'Tags file header is incorrect');
110+
}
111+
112+
/**
113+
* @return void
114+
*/
115+
protected function assertNumberOfTagsInTagsFileIs($count)
116+
{
117+
$this->assertCount(
118+
$count,
119+
$this->tagsFileContent,
120+
'Tags file contains the wrong number of tags'
121+
);
122+
}
123+
124+
/**
125+
* @param string $filename
126+
* @param string $name
127+
* @param string $kind
128+
* @param int $line
129+
* @param string $scope
130+
* @param string $access
131+
*
132+
* @return void
133+
*/
134+
protected function assertTagsFileContainsTag(
135+
$filename,
136+
$name,
137+
$kind,
138+
$line,
139+
$scope = '',
140+
$access = ''
141+
) {
142+
$this->assertContains(
143+
$this->createTagLine($filename, $name, $kind, $line, $scope, $access),
144+
$this->tagsFileContent,
145+
"Tag file content:\n" . print_r($this->tagsFileContent, true)
146+
);
147+
}
148+
149+
150+
/**
151+
* @param string $filename
152+
*
153+
* @return void
154+
*/
155+
public function assertTagsFileContainsNoTagsFromFile($filename)
156+
{
157+
$filename = $this->testDir . DIRECTORY_SEPARATOR . $filename;
158+
159+
$tags = array_filter(
160+
$this->tagsFileContent,
161+
function ($line) use ($filename) {
162+
$fields = explode("\t", $line);
163+
164+
return $fields[1] === $filename;
165+
}
166+
);
167+
168+
$this->assertEmpty($tags, "Tags for $filename were found in tag file.");
169+
}
170+
171+
/**
172+
* @return void
173+
*/
174+
private function emptyTestDir()
175+
{
176+
if (empty($this->testDir)) {
177+
throw \RuntimeException('Test directory does not exist');
178+
}
179+
180+
$files = new RecursiveIteratorIterator(
181+
new RecursiveDirectoryIterator(
182+
$this->testDir,
183+
RecursiveDirectoryIterator::SKIP_DOTS
184+
),
185+
RecursiveIteratorIterator::CHILD_FIRST
186+
);
187+
188+
foreach ($files as $fileinfo) {
189+
if ($fileinfo->isDir()) {
190+
rmdir($fileinfo->getRealPath());
191+
} else {
192+
unlink($fileinfo->getRealPath());
193+
}
194+
}
195+
}
196+
197+
/**
198+
* @param string $filename
199+
* @param string $name
200+
* @param string $kind
201+
* @param int $line
202+
* @param string $scope
203+
* @param string $access
204+
*
205+
* @return string
206+
*/
207+
private function createTagLine($filename, $name, $kind, $line, $scope, $access)
208+
{
209+
$kinds = array(
210+
self::KIND_TRAIT => 'trait',
211+
self::KIND_CLASS => 'class',
212+
self::KIND_METHOD => 'method',
213+
self::KIND_FUNCTION => 'function',
214+
self::KIND_PROPERTY => 'property',
215+
self::KIND_CONSTANT => 'constant',
216+
self::KIND_VARIABLE => 'variable',
217+
self::KIND_INTERFACE => 'interface',
218+
self::KIND_NAMESPACE => 'namespace',
219+
);
220+
221+
if(!empty($access)) {
222+
$access = 'access:' . $access;
223+
}
224+
225+
$patterns = array(
226+
'/<name>/',
227+
'/<file>/',
228+
'/<line content>/',
229+
'/<short kind>/',
230+
'/<full kind>/',
231+
'/<line number>/',
232+
'/<scope>/',
233+
'/<access>/'
234+
);
235+
236+
$replacements = array(
237+
$name,
238+
$this->testDir . DIRECTORY_SEPARATOR . $filename,
239+
$this->getSourceFileLineContent($filename, $line),
240+
$kind,
241+
$kinds[$kind],
242+
$line,
243+
$scope,
244+
$access
245+
);
246+
247+
$line = preg_replace($patterns, $replacements, self::FORMAT);
248+
249+
return rtrim($line, "\t");
250+
}
251+
252+
/**
253+
* @param string $filename
254+
* @param int $line
255+
*
256+
* @return string
257+
*/
258+
private function getSourceFileLineContent($filename, $line)
259+
{
260+
$filename = $this->testDir . DIRECTORY_SEPARATOR . $filename;
261+
$line--;
262+
263+
return rtrim(file($filename)[$line], PHP_EOL);
264+
}
265+
}

0 commit comments

Comments
 (0)