Skip to content

Commit ee19459

Browse files
committed
Test for missing language files and keys
1 parent b05ccb0 commit ee19459

File tree

7 files changed

+287
-0
lines changed

7 files changed

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