Skip to content

Commit 75292f9

Browse files
authored
Merge pull request #69 from kasimi/validate-lang
Test for missing language files and keys
2 parents b05ccb0 + 5474cd3 commit 75292f9

File tree

7 files changed

+288
-0
lines changed

7 files changed

+288
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,164 @@
1+
<?php
2+
3+
/**
4+
*
5+
* EPV :: The phpBB Forum Extension Pre Validator.
6+
*
7+
* @copyright (c) 2017 phpBB Limited <https://www.phpbb.com>
8+
* @license GNU General Public License, version 2 (GPL-2.0)
9+
*
10+
*/
11+
12+
namespace Phpbb\Epv\Tests\Tests;
13+
14+
use Phpbb\Epv\Output\OutputInterface;
15+
use Phpbb\Epv\Tests\BaseTest;
16+
use PhpParser\Error;
17+
use PhpParser\Node\Expr\Array_;
18+
use PhpParser\Node\Expr\ArrayItem;
19+
use PhpParser\Node\Expr\Assign;
20+
use PhpParser\Node\Expr\FuncCall;
21+
use PhpParser\Node\Scalar\String_;
22+
use PhpParser\Parser;
23+
use PhpParser\ParserFactory;
24+
25+
class epv_test_validate_languages extends BaseTest
26+
{
27+
/**
28+
* @var Parser
29+
*/
30+
private $parser;
31+
32+
/**
33+
* @param bool $debug if debug is enabled
34+
* @param OutputInterface $output
35+
* @param string $basedir
36+
* @param string $namespace
37+
* @param boolean $titania
38+
* @param string $opendir
39+
*/
40+
public function __construct($debug, OutputInterface $output, $basedir, $namespace, $titania, $opendir)
41+
{
42+
parent::__construct($debug, $output, $basedir, $namespace, $titania, $opendir);
43+
44+
$this->directory = true;
45+
$this->parser = (new ParserFactory)->create(ParserFactory::PREFER_PHP7);
46+
}
47+
48+
/**
49+
* @param array $files
50+
*
51+
* @return void
52+
*/
53+
public function validateDirectory(array $files)
54+
{
55+
$langs = [];
56+
$expected_keys = [];
57+
$expected_files = [];
58+
59+
foreach ($files as $file)
60+
{
61+
if (preg_match('#^' . $this->basedir . 'language/([a-z_]+?)/(.+\.php)$#', $file, $matches) === 1)
62+
{
63+
$language = $matches[1]; // language, e.g. "en"
64+
$relative_filename = $matches[2]; // file name relative to language's base dir, e.g. "info_acp_ext.php"
65+
$expected_files[$relative_filename] = $relative_filename;
66+
67+
try
68+
{
69+
$keys = $this->load_language_keys($file);
70+
$langs[$language][$relative_filename] = $keys;
71+
72+
$lang_keys = isset($expected_keys[$relative_filename]) ? $expected_keys[$relative_filename] : [];
73+
$expected_keys[$relative_filename] = array_unique(array_merge($lang_keys, $keys));
74+
}
75+
catch (Error $e)
76+
{
77+
$this->output->addMessage(OutputInterface::FATAL, 'PHP parse error in file ' . $file->getSaveFilename() . '. Message: ' . $e->getMessage());
78+
}
79+
}
80+
}
81+
82+
foreach ($langs as $lang_name => $file_contents)
83+
{
84+
// Check for missing language files
85+
foreach (array_diff($expected_files, array_keys($file_contents)) as $missing_file)
86+
{
87+
$this->output->addMessage(OutputInterface::NOTICE, sprintf("Language %s is missing the language file %s", $lang_name, $missing_file));
88+
}
89+
90+
// Check for missing language keys
91+
foreach ($file_contents as $relative_filename => $present_keys)
92+
{
93+
foreach (array_diff($expected_keys[$relative_filename], $present_keys) as $missing_key)
94+
{
95+
$this->output->addMessage(OutputInterface::WARNING, sprintf("Language file %s/%s is missing the language key %s", $lang_name, $relative_filename, $missing_key));
96+
}
97+
}
98+
}
99+
}
100+
101+
/**
102+
* This method scans through all global-scoped calls to array_merge
103+
* and extracts all string keys of all array arguments.
104+
*
105+
* @param string $filename File name to a phpBB language file
106+
* @return array
107+
* @throws Error
108+
*/
109+
protected function load_language_keys($filename)
110+
{
111+
$contents = @file_get_contents($filename);
112+
113+
$keys = [];
114+
115+
$nodes = $this->parser->parse($contents);
116+
117+
foreach ($nodes as $node)
118+
{
119+
if ($node instanceof Assign && $node->expr instanceof FuncCall)
120+
{
121+
/** @var FuncCall $expr */
122+
$expr = $node->expr;
123+
124+
if ($expr->name->getFirst() === 'array_merge')
125+
{
126+
for ($i = 1; $i < sizeof($expr->args); $i++)
127+
{
128+
/** @var Array_ $array */
129+
$array = $expr->args[$i]->value;
130+
131+
if (!($array instanceof Array_))
132+
{
133+
throw new Error(sprintf('Expected argument %d of array_merge() to be %s, got %s', $i + 1, Array_::class, get_class($array)), $array->getLine());
134+
}
135+
136+
foreach ($array->items as $item)
137+
{
138+
/** @var ArrayItem $item */
139+
if ($item->key instanceof String_)
140+
{
141+
$keys[] = $item->key->value;
142+
}
143+
else
144+
{
145+
$this->output->addMessage(OutputInterface::NOTICE, 'Language key is not a string value in ' . substr($filename, strlen($this->basedir)) . ' on line ' . $item->key->getLine());
146+
}
147+
}
148+
}
149+
}
150+
}
151+
}
152+
153+
return $keys;
154+
}
155+
156+
/**
157+
*
158+
* @return String
159+
*/
160+
public function testName()
161+
{
162+
return 'Test languages';
163+
}
164+
}
+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
<?php
2+
3+
if (!defined('IN_PHPBB'))
4+
{
5+
exit;
6+
}
7+
8+
if (empty($lang) || !is_array($lang))
9+
{
10+
$lang = array();
11+
}
12+
13+
$lang = array_merge($lang, array(
14+
'C' => 'Third language string',
15+
));
+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
<?php
2+
3+
if (!defined('IN_PHPBB'))
4+
{
5+
exit;
6+
}
7+
8+
if (empty($lang) || !is_array($lang))
9+
{
10+
$lang = array();
11+
}
12+
13+
$lang = array_merge($lang, array(
14+
'A' => 'First language string',
15+
'B' => 'Second language string',
16+
));
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
<?php
2+
3+
if (!defined('IN_PHPBB'))
4+
{
5+
exit;
6+
}
7+
8+
if (empty($lang) || !is_array($lang))
9+
{
10+
$lang = array();
11+
}
12+
13+
$lang = array_merge($lang, array(), array(
14+
'C' => 'Third language string',
15+
));
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
<?php
2+
3+
if (!defined('IN_PHPBB'))
4+
{
5+
exit;
6+
}
7+
8+
if (empty($lang) || !is_array($lang))
9+
{
10+
$lang = array();
11+
}
12+
13+
$lang = array_merge($lang, array(
14+
'A' => 'First language string',
15+
));
16+
17+
$lang = array_merge($lang, array(
18+
'B' => 'Second language string',
19+
));
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
<?php
2+
3+
if (!defined('IN_PHPBB'))
4+
{
5+
exit;
6+
}
7+
8+
if (empty($lang) || !is_array($lang))
9+
{
10+
$lang = array();
11+
}
12+
13+
$lang = array_merge($lang, array(
14+
'A' => 'First language string',
15+
));

tests/validate_languages_test.php

+44
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
<?php
2+
3+
/**
4+
*
5+
* EPV :: The phpBB Forum Extension Pre Validator.
6+
*
7+
* @copyright (c) 2017 phpBB Limited <https://www.phpbb.com>
8+
* @license GNU General Public License, version 2 (GPL-2.0)
9+
*
10+
*/
11+
12+
use Phpbb\Epv\Output\OutputInterface;
13+
use Phpbb\Epv\Tests\Tests\epv_test_validate_languages;
14+
15+
class validate_languages_test extends PHPUnit_Framework_TestCase
16+
{
17+
public static function setUpBeforeClass()
18+
{
19+
require_once('./tests/Mock/Output.php');
20+
}
21+
22+
public function test_languages() {
23+
/** @var OutputInterface|PHPUnit_Framework_MockObject_MockObject $output */
24+
$output = $this->getMock('Phpbb\Epv\Output\OutputInterface');
25+
26+
$output
27+
->expects($this->exactly(2))
28+
->method('addMessage')
29+
->withConsecutive(
30+
[OutputInterface::NOTICE, 'Language en_incomplete is missing the language file additional.php'],
31+
[OutputInterface::WARNING, 'Language file en_incomplete/common.php is missing the language key B']
32+
)
33+
;
34+
35+
$tester = new epv_test_validate_languages(false, $output, 'tests/testFiles/', 'epv/test', false, 'tests/testFiles/');
36+
$tester->validateDirectory([
37+
'tests/testFiles/language/en/common.php',
38+
'tests/testFiles/language/en/additional.php',
39+
'tests/testFiles/language/en_complete/common.php',
40+
'tests/testFiles/language/en_complete/additional.php',
41+
'tests/testFiles/language/en_incomplete/common.php',
42+
]);
43+
}
44+
}

0 commit comments

Comments
 (0)