Completed
Pull Request — master (#6706)
by Damian
09:02
created

testCollectFromFilesystemAndWriteMasterTables()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 63
Code Lines 44

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 44
nc 1
nop 0
dl 0
loc 63
rs 9.4347
c 0
b 0
f 0

How to fix   Long Method   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
namespace SilverStripe\i18n\Tests;
4
5
use PHPUnit_Framework_Error_Notice;
6
use SilverStripe\Assets\Filesystem;
7
use SilverStripe\Core\Manifest\ModuleLoader;
8
use SilverStripe\Dev\SapphireTest;
9
use SilverStripe\i18n\i18n;
10
use SilverStripe\i18n\TextCollection\i18nTextCollector;
11
use SilverStripe\i18n\Messages\YamlWriter;
12
use SilverStripe\i18n\Tests\i18nTextCollectorTest\Collector;
13
14
class i18nTextCollectorTest extends SapphireTest
15
{
16
    use i18nTestManifest;
17
18
    /**
19
     * @var string
20
     */
21
    protected $alternateBaseSavePath = null;
22
23
    public function setUp()
24
    {
25
        parent::setUp();
26
        $this->setupManifest();
27
28
        $this->alternateBaseSavePath = TEMP_FOLDER . DIRECTORY_SEPARATOR . 'i18nTextCollectorTest_webroot';
29
        Filesystem::makeFolder($this->alternateBaseSavePath);
30
    }
31
32
    public function tearDown()
33
    {
34
        if (is_dir($this->alternateBaseSavePath)) {
35
            Filesystem::removeFolder($this->alternateBaseSavePath);
36
        }
37
38
        $this->tearDownManifest();
39
        parent::tearDown();
40
    }
41
42
    public function testConcatenationInEntityValues()
43
    {
44
        $c = i18nTextCollector::create();
45
        $module = ModuleLoader::instance()->getManifest()->getModule('i18ntestmodule');
46
47
        $php = <<<PHP
48
_t(
49
'Test.CONCATENATED',
50
'Line 1 and ' .
51
'Line \'2\' and ' .
52
'Line "3"',
53
54
'Comment'
55
);
56
57
_t(
58
'Test.CONCATENATED2',
59
"Line \"4\" and " .
60
"Line 5");
61
PHP;
62
        $this->assertEquals(
63
            array(
64
                'Test.CONCATENATED' => [
65
                    'default' => "Line 1 and Line '2' and Line \"3\"",
66
                    'comment' => 'Comment'
67
                ],
68
                'Test.CONCATENATED2' => "Line \"4\" and Line 5"
69
            ),
70
            $c->collectFromCode($php, null, $module)
0 ignored issues
show
Bug introduced by
It seems like $module defined by \SilverStripe\Core\Manif...odule('i18ntestmodule') on line 45 can be null; however, SilverStripe\i18n\TextCo...ctor::collectFromCode() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
71
        );
72
    }
73
74
    public function testCollectFromNewTemplateSyntaxUsingParserSubclass()
75
    {
76
        $c = i18nTextCollector::create();
77
        $c->setWarnOnEmptyDefault(false);
78
        $mymodule = ModuleLoader::instance()->getManifest()->getModule('i18ntestmodule');
79
80
        $html = <<<SS
81
        <% _t('Test.SINGLEQUOTE','Single Quote'); %>
82
<%t i18nTestModule.NEWMETHODSIG "New _t method signature test" %>
83
<%t i18nTestModule.INJECTIONS_0 "Hello {name} {greeting}, and {goodbye}" name="Mark" greeting="welcome" goodbye="bye" %>
84
<%t i18nTestModule.INJECTIONS_1 "Hello {name} {greeting}, and {goodbye}" name="Paul" greeting="welcome" goodbye="cya" %>
85
<%t i18nTestModule.INJECTIONS_2 "Hello {name} {greeting}" is "context (ignored)" name="Steffen" greeting="Wilkommen" %>
86
<%t i18nTestModule.INJECTIONS_3 name="Cat" greeting='meow' goodbye="meow" %>
87
<%t i18nTestModule.INJECTIONS_4 name=\$absoluteBaseURL greeting=\$get_locale goodbye="global calls" %>
88
<%t i18nTestModule.INJECTIONS_9 "An item|{count} items" is "Test Pluralisation" count=4 %>
89
SS;
90
        $c->collectFromTemplate($html, null, $mymodule);
0 ignored issues
show
Bug introduced by
It seems like $mymodule defined by \SilverStripe\Core\Manif...odule('i18ntestmodule') on line 78 can be null; however, SilverStripe\i18n\TextCo...::collectFromTemplate() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
91
92
        $this->assertEquals(
93
            [
94
                'Test.SINGLEQUOTE' => 'Single Quote',
95
                'i18nTestModule.NEWMETHODSIG' => "New _t method signature test",
96
                'i18nTestModule.INJECTIONS_0' => "Hello {name} {greeting}, and {goodbye}",
97
                'i18nTestModule.INJECTIONS_1' => "Hello {name} {greeting}, and {goodbye}",
98
                'i18nTestModule.INJECTIONS_2' => [
99
                    'default' => "Hello {name} {greeting}",
100
                    'comment' => 'context (ignored)',
101
                ],
102
                'i18nTestModule.INJECTIONS_9' => [
103
                    'one' => 'An item',
104
                    'other' => '{count} items',
105
                    'comment' => 'Test Pluralisation'
106
                ],
107
            ],
108
            $c->collectFromTemplate($html, null, $mymodule)
0 ignored issues
show
Bug introduced by
It seems like $mymodule defined by \SilverStripe\Core\Manif...odule('i18ntestmodule') on line 78 can be null; however, SilverStripe\i18n\TextCo...::collectFromTemplate() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
109
        );
110
111
        // Test warning is raised on empty default
112
        $c->setWarnOnEmptyDefault(true);
113
        $this->setExpectedException(
114
            PHPUnit_Framework_Error_Notice::class,
115
            'Missing localisation default for key i18nTestModule.INJECTIONS_3'
116
        );
117
        $c->collectFromTemplate($html, null, $mymodule);
0 ignored issues
show
Bug introduced by
It seems like $mymodule defined by \SilverStripe\Core\Manif...odule('i18ntestmodule') on line 78 can be null; however, SilverStripe\i18n\TextCo...::collectFromTemplate() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
118
    }
119
120
    public function testCollectFromTemplateSimple()
121
    {
122
        $c = i18nTextCollector::create();
123
        $mymodule = ModuleLoader::instance()->getManifest()->getModule('i18ntestmodule');
124
125
        $html = <<<SS
126
<% _t('Test.SINGLEQUOTE','Single Quote'); %>
127
SS;
128
        $this->assertEquals(
129
            [ 'Test.SINGLEQUOTE' => 'Single Quote' ],
130
            $c->collectFromTemplate($html, null, $mymodule)
0 ignored issues
show
Bug introduced by
It seems like $mymodule defined by \SilverStripe\Core\Manif...odule('i18ntestmodule') on line 123 can be null; however, SilverStripe\i18n\TextCo...::collectFromTemplate() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
131
        );
132
133
        $html = <<<SS
134
<% _t(  "Test.DOUBLEQUOTE", "Double Quote and Spaces"   ); %>
135
SS;
136
        $this->assertEquals(
137
            [ 'Test.DOUBLEQUOTE' => "Double Quote and Spaces" ],
138
            $c->collectFromTemplate($html, null, $mymodule)
0 ignored issues
show
Bug introduced by
It seems like $mymodule defined by \SilverStripe\Core\Manif...odule('i18ntestmodule') on line 123 can be null; however, SilverStripe\i18n\TextCo...::collectFromTemplate() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
139
        );
140
141
        $html = <<<SS
142
<% _t("Test.NOSEMICOLON","No Semicolon") %>
143
SS;
144
        $this->assertEquals(
145
            [ 'Test.NOSEMICOLON' => "No Semicolon" ],
146
            $c->collectFromTemplate($html, null, $mymodule)
0 ignored issues
show
Bug introduced by
It seems like $mymodule defined by \SilverStripe\Core\Manif...odule('i18ntestmodule') on line 123 can be null; however, SilverStripe\i18n\TextCo...::collectFromTemplate() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
147
        );
148
    }
149
150
    public function testCollectFromTemplateAdvanced()
151
    {
152
        $c = i18nTextCollector::create();
153
        $c->setWarnOnEmptyDefault(false);
154
        $mymodule = ModuleLoader::instance()->getManifest()->getModule('i18ntestmodule');
155
156
        $html = <<<SS
157
<% _t(
158
	'NEWLINES',
159
	'New Lines'
160
) %>
161
SS;
162
        $this->assertEquals(
163
            [ 'Test.NEWLINES' => "New Lines" ],
164
            $c->collectFromTemplate($html, 'Test', $mymodule)
0 ignored issues
show
Bug introduced by
It seems like $mymodule defined by \SilverStripe\Core\Manif...odule('i18ntestmodule') on line 154 can be null; however, SilverStripe\i18n\TextCo...::collectFromTemplate() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
165
        );
166
167
        $html = <<<SS
168
<% _t(
169
	'Test.PRIOANDCOMMENT',
170
	' Prio and Value with "Double Quotes"',
171
	'Comment with "Double Quotes"'
172
) %>
173
SS;
174
        $this->assertEquals(
175
            [ 'Test.PRIOANDCOMMENT' => [
176
                'default' => ' Prio and Value with "Double Quotes"',
177
                'comment' => 'Comment with "Double Quotes"',
178
            ]],
179
            $c->collectFromTemplate($html, 'Test', $mymodule)
0 ignored issues
show
Bug introduced by
It seems like $mymodule defined by \SilverStripe\Core\Manif...odule('i18ntestmodule') on line 154 can be null; however, SilverStripe\i18n\TextCo...::collectFromTemplate() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
180
        );
181
182
        $html = <<<SS
183
<% _t(
184
	'Test.PRIOANDCOMMENT',
185
	" Prio and Value with 'Single Quotes'",
186
187
	"Comment with 'Single Quotes'"
188
) %>
189
SS;
190
        $this->assertEquals(
191
            [ 'Test.PRIOANDCOMMENT' => [
192
                'default' => " Prio and Value with 'Single Quotes'",
193
                'comment' => "Comment with 'Single Quotes'",
194
            ]],
195
            $c->collectFromTemplate($html, 'Test', $mymodule)
0 ignored issues
show
Bug introduced by
It seems like $mymodule defined by \SilverStripe\Core\Manif...odule('i18ntestmodule') on line 154 can be null; however, SilverStripe\i18n\TextCo...::collectFromTemplate() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
196
        );
197
198
        // Test empty
199
        $html = <<<SS
200
<% _t('Test.PRIOANDCOMMENT') %>
201
SS;
202
        $this->assertEquals(
203
            [],
204
            $c->collectFromTemplate($html, null, $mymodule)
0 ignored issues
show
Bug introduced by
It seems like $mymodule defined by \SilverStripe\Core\Manif...odule('i18ntestmodule') on line 154 can be null; however, SilverStripe\i18n\TextCo...::collectFromTemplate() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
205
        );
206
207
        // Test warning is raised on empty default
208
        $c->setWarnOnEmptyDefault(true);
209
        $this->setExpectedException(
210
            PHPUnit_Framework_Error_Notice::class,
211
            'Missing localisation default for key Test.PRIOANDCOMMENT'
212
        );
213
        $c->collectFromTemplate($html, 'Test', $mymodule);
0 ignored issues
show
Bug introduced by
It seems like $mymodule defined by \SilverStripe\Core\Manif...odule('i18ntestmodule') on line 154 can be null; however, SilverStripe\i18n\TextCo...::collectFromTemplate() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
214
    }
215
216
217
    public function testCollectFromCodeSimple()
218
    {
219
        $c = i18nTextCollector::create();
220
        $mymodule = ModuleLoader::instance()->getManifest()->getModule('i18ntestmodule');
221
222
        $php = <<<PHP
223
_t('Test.SINGLEQUOTE','Single Quote');
224
PHP;
225
        $this->assertEquals(
226
            [ 'Test.SINGLEQUOTE' => 'Single Quote' ],
227
            $c->collectFromCode($php, null, $mymodule)
0 ignored issues
show
Bug introduced by
It seems like $mymodule defined by \SilverStripe\Core\Manif...odule('i18ntestmodule') on line 220 can be null; however, SilverStripe\i18n\TextCo...ctor::collectFromCode() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
228
        );
229
230
        $php = <<<PHP
231
_t(  "Test.DOUBLEQUOTE", "Double Quote and Spaces"   );
232
PHP;
233
        $this->assertEquals(
234
            [ 'Test.DOUBLEQUOTE' => "Double Quote and Spaces" ],
235
            $c->collectFromCode($php, null, $mymodule)
0 ignored issues
show
Bug introduced by
It seems like $mymodule defined by \SilverStripe\Core\Manif...odule('i18ntestmodule') on line 220 can be null; however, SilverStripe\i18n\TextCo...ctor::collectFromCode() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
236
        );
237
    }
238
239
    public function testCollectFromCodeAdvanced()
240
    {
241
        $c = i18nTextCollector::create();
242
        $mymodule = ModuleLoader::instance()->getManifest()->getModule('i18ntestmodule');
243
244
        $php = <<<PHP
245
_t(
246
	'Test.NEWLINES',
247
	'New Lines'
248
);
249
PHP;
250
        $this->assertEquals(
251
            [ 'Test.NEWLINES' => "New Lines" ],
252
            $c->collectFromCode($php, null, $mymodule)
0 ignored issues
show
Bug introduced by
It seems like $mymodule defined by \SilverStripe\Core\Manif...odule('i18ntestmodule') on line 242 can be null; however, SilverStripe\i18n\TextCo...ctor::collectFromCode() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
253
        );
254
255
        $php = <<<PHP
256
_t(
257
	'Test.PRIOANDCOMMENT',
258
	' Value with "Double Quotes"',
259
260
	'Comment with "Double Quotes"'
261
);
262
PHP;
263
        $this->assertEquals(
264
            [
265
                'Test.PRIOANDCOMMENT' => [
266
                    'default' => ' Value with "Double Quotes"',
267
                    'comment' => 'Comment with "Double Quotes"',
268
                ]
269
            ],
270
            $c->collectFromCode($php, null, $mymodule)
0 ignored issues
show
Bug introduced by
It seems like $mymodule defined by \SilverStripe\Core\Manif...odule('i18ntestmodule') on line 242 can be null; however, SilverStripe\i18n\TextCo...ctor::collectFromCode() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
271
        );
272
273
        $php = <<<PHP
274
_t(
275
	'Test.PRIOANDCOMMENT',
276
	" Value with 'Single Quotes'",
277
278
	"Comment with 'Single Quotes'"
279
);
280
PHP;
281
        $this->assertEquals(
282
            [ 'Test.PRIOANDCOMMENT' => [
283
                'default' => " Value with 'Single Quotes'",
284
                'comment' => "Comment with 'Single Quotes'"
285
            ] ],
286
            $c->collectFromCode($php, null, $mymodule)
0 ignored issues
show
Bug introduced by
It seems like $mymodule defined by \SilverStripe\Core\Manif...odule('i18ntestmodule') on line 242 can be null; however, SilverStripe\i18n\TextCo...ctor::collectFromCode() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
287
        );
288
289
        $php = <<<PHP
290
_t(
291
	'Test.PRIOANDCOMMENT',
292
	'Value with \'Escaped Single Quotes\''
293
);
294
PHP;
295
        $this->assertEquals(
296
            [ 'Test.PRIOANDCOMMENT' => "Value with 'Escaped Single Quotes'" ],
297
            $c->collectFromCode($php, null, $mymodule)
0 ignored issues
show
Bug introduced by
It seems like $mymodule defined by \SilverStripe\Core\Manif...odule('i18ntestmodule') on line 242 can be null; however, SilverStripe\i18n\TextCo...ctor::collectFromCode() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
298
        );
299
300
        $php = <<<PHP
301
_t(
302
	'Test.PRIOANDCOMMENT',
303
	"Doublequoted Value with 'Unescaped Single Quotes'"
304
	
305
	
306
);
307
PHP;
308
        $this->assertEquals(
309
            [ 'Test.PRIOANDCOMMENT' => "Doublequoted Value with 'Unescaped Single Quotes'"],
310
            $c->collectFromCode($php, null, $mymodule)
0 ignored issues
show
Bug introduced by
It seems like $mymodule defined by \SilverStripe\Core\Manif...odule('i18ntestmodule') on line 242 can be null; however, SilverStripe\i18n\TextCo...ctor::collectFromCode() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
311
        );
312
    }
313
314
    public function testCollectFromCodeNamespace()
315
    {
316
        $c = i18nTextCollector::create();
317
        $mymodule = ModuleLoader::instance()->getManifest()->getModule('i18ntestmodule');
318
        $php = <<<PHP
319
<?php
320
namespace SilverStripe\Framework\Core;
321
322
class MyClass extends Base implements SomeService {
323
    public function getNewLines() {
324
        return _t(
325
            __CLASS__.'.NEWLINES',
326
            'New Lines'
327
        );
328
    }
329
}
330
PHP;
331
        $this->assertEquals(
332
            [ 'SilverStripe\\Framework\\Core\\MyClass.NEWLINES' => "New Lines" ],
333
            $c->collectFromCode($php, null, $mymodule)
0 ignored issues
show
Bug introduced by
It seems like $mymodule defined by \SilverStripe\Core\Manif...odule('i18ntestmodule') on line 317 can be null; however, SilverStripe\i18n\TextCo...ctor::collectFromCode() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
334
        );
335
    }
336
337
338
    public function testNewlinesInEntityValues()
339
    {
340
        $c = i18nTextCollector::create();
341
        $mymodule = ModuleLoader::instance()->getManifest()->getModule('i18ntestmodule');
342
343
        $php = <<<PHP
344
_t(
345
'Test.NEWLINESINGLEQUOTE',
346
'Line 1
347
Line 2'
348
);
349
PHP;
350
351
        $eol = PHP_EOL;
352
        $this->assertEquals(
353
            [ 'Test.NEWLINESINGLEQUOTE' => "Line 1{$eol}Line 2" ],
354
            $c->collectFromCode($php, null, $mymodule)
0 ignored issues
show
Bug introduced by
It seems like $mymodule defined by \SilverStripe\Core\Manif...odule('i18ntestmodule') on line 341 can be null; however, SilverStripe\i18n\TextCo...ctor::collectFromCode() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
355
        );
356
357
        $php = <<<PHP
358
_t(
359
'Test.NEWLINEDOUBLEQUOTE',
360
"Line 1
361
Line 2"
362
);
363
PHP;
364
        $this->assertEquals(
365
            [ 'Test.NEWLINEDOUBLEQUOTE' => "Line 1{$eol}Line 2" ],
366
            $c->collectFromCode($php, null, $mymodule)
0 ignored issues
show
Bug introduced by
It seems like $mymodule defined by \SilverStripe\Core\Manif...odule('i18ntestmodule') on line 341 can be null; however, SilverStripe\i18n\TextCo...ctor::collectFromCode() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
367
        );
368
    }
369
370
    /**
371
     * Test extracting entities from the new _t method signature
372
     */
373
    public function testCollectFromCodeNewSignature()
374
    {
375
        $c = i18nTextCollector::create();
376
        $c->setWarnOnEmptyDefault(false); // Disable warnings for tests
377
        $mymodule = ModuleLoader::instance()->getManifest()->getModule('i18ntestmodule');
378
379
        $php = <<<PHP
380
_t('i18nTestModule.NEWMETHODSIG',"New _t method signature test");
381
_t('i18nTestModule.INJECTIONS2', "Hello {name} {greeting}. But it is late, {goodbye}",
382
	array("name"=>"Paul", "greeting"=>"good you are here", "goodbye"=>"see you"));
383
_t("i18nTestModule.INJECTIONS3", "Hello {name} {greeting}. But it is late, {goodbye}",
384
		"New context (this should be ignored)",
385
		array("name"=>"Steffen", "greeting"=>"willkommen", "goodbye"=>"wiedersehen"));
386
_t('i18nTestModule.INJECTIONS4', array("name"=>"Cat", "greeting"=>"meow", "goodbye"=>"meow"));
387
_t('i18nTestModule.INJECTIONS6', "Hello {name} {greeting}. But it is late, {goodbye}",
388
	["name"=>"Paul", "greeting"=>"good you are here", "goodbye"=>"see you"]);
389
_t("i18nTestModule.INJECTIONS7", "Hello {name} {greeting}. But it is late, {goodbye}",
390
		"New context (this should be ignored)",
391
		["name"=>"Steffen", "greeting"=>"willkommen", "goodbye"=>"wiedersehen"]);
392
_t('i18nTestModule.INJECTIONS8', ["name"=>"Cat", "greeting"=>"meow", "goodbye"=>"meow"]);
393
_t('i18nTestModule.INJECTIONS9', "An item|{count} items", ['count' => 4], "Test Pluralisation");
394
PHP;
395
396
        $collectedTranslatables = $c->collectFromCode($php, null, $mymodule);
0 ignored issues
show
Bug introduced by
It seems like $mymodule defined by \SilverStripe\Core\Manif...odule('i18ntestmodule') on line 377 can be null; however, SilverStripe\i18n\TextCo...ctor::collectFromCode() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
397
398
        $expectedArray = [
399
            'i18nTestModule.INJECTIONS2' => "Hello {name} {greeting}. But it is late, {goodbye}",
400
            'i18nTestModule.INJECTIONS3' => [
401
                'default' => "Hello {name} {greeting}. But it is late, {goodbye}",
402
                'comment' => 'New context (this should be ignored)'
403
            ],
404
            'i18nTestModule.INJECTIONS6' => "Hello {name} {greeting}. But it is late, {goodbye}",
405
            'i18nTestModule.INJECTIONS7' => [
406
                'default' => "Hello {name} {greeting}. But it is late, {goodbye}",
407
                'comment' => "New context (this should be ignored)",
408
            ],
409
            'i18nTestModule.INJECTIONS9' => [
410
                'one' => 'An item',
411
                'other' => '{count} items',
412
                'comment' => 'Test Pluralisation',
413
            ],
414
            'i18nTestModule.NEWMETHODSIG' => "New _t method signature test",
415
        ];
416
        $this->assertEquals($expectedArray, $collectedTranslatables);
417
418
        // Test warning is raised on empty default
419
        $this->setExpectedException(
420
            PHPUnit_Framework_Error_Notice::class,
421
            'Missing localisation default for key i18nTestModule.INJECTIONS4'
422
        );
423
        $php = <<<PHP
424
_t('i18nTestModule.INJECTIONS4', array("name"=>"Cat", "greeting"=>"meow", "goodbye"=>"meow"));
425
PHP;
426
        $c->setWarnOnEmptyDefault(true);
427
        $c->collectFromCode($php, null, $mymodule);
0 ignored issues
show
Bug introduced by
It seems like $mymodule defined by \SilverStripe\Core\Manif...odule('i18ntestmodule') on line 377 can be null; however, SilverStripe\i18n\TextCo...ctor::collectFromCode() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
428
    }
429
430
    public function testUncollectableCode()
431
    {
432
        $c = i18nTextCollector::create();
433
        $mymodule = ModuleLoader::instance()->getManifest()->getModule('i18ntestmodule');
434
435
        $php = <<<PHP
436
_t(static::class.'.KEY1', 'Default');
437
_t(self::class.'.KEY2', 'Default');
438
_t(__CLASS__.'.KEY3', 'Default');
439
_t('Collectable.KEY4', 'Default');
440
PHP;
441
442
        $collectedTranslatables = $c->collectFromCode($php, null, $mymodule);
0 ignored issues
show
Bug introduced by
It seems like $mymodule defined by \SilverStripe\Core\Manif...odule('i18ntestmodule') on line 433 can be null; however, SilverStripe\i18n\TextCo...ctor::collectFromCode() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
443
444
        // Only one item is collectable
445
        $expectedArray = [ 'Collectable.KEY4' => 'Default' ];
446
        $this->assertEquals($expectedArray, $collectedTranslatables);
447
    }
448
449
    public function testCollectFromIncludedTemplates()
450
    {
451
        $c = i18nTextCollector::create();
452
        $c->setWarnOnEmptyDefault(false); // Disable warnings for tests
453
        $mymodule = ModuleLoader::instance()->getManifest()->getModule('i18ntestmodule');
454
455
        $templateFilePath = $this->alternateBasePath . '/i18ntestmodule/templates/Layout/i18nTestModule.ss';
456
        $html = file_get_contents($templateFilePath);
457
        $matches = $c->collectFromTemplate($html, $templateFilePath, $mymodule);
0 ignored issues
show
Bug introduced by
It seems like $mymodule defined by \SilverStripe\Core\Manif...odule('i18ntestmodule') on line 453 can be null; however, SilverStripe\i18n\TextCo...::collectFromTemplate() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
458
459
        $this->assertArrayHasKey('i18nTestModule.ss.LAYOUTTEMPLATENONAMESPACE', $matches);
460
        $this->assertEquals(
461
            'Layout Template no namespace',
462
            $matches['i18nTestModule.ss.LAYOUTTEMPLATENONAMESPACE']
463
        );
464
        $this->assertArrayHasKey('i18nTestModule.ss.SPRINTFNONAMESPACE', $matches);
465
        $this->assertEquals(
466
            'My replacement no namespace: %s',
467
            $matches['i18nTestModule.ss.SPRINTFNONAMESPACE']
468
        );
469
        $this->assertArrayHasKey('i18nTestModule.LAYOUTTEMPLATE', $matches);
470
        $this->assertEquals(
471
            'Layout Template',
472
            $matches['i18nTestModule.LAYOUTTEMPLATE']
473
        );
474
        $this->assertArrayHasKey('i18nTestModule.SPRINTFNAMESPACE', $matches);
475
        $this->assertEquals(
476
            'My replacement: %s',
477
            $matches['i18nTestModule.SPRINTFNAMESPACE']
478
        );
479
480
        // Includes should not automatically inject translations into parent templates
481
        $this->assertArrayNotHasKey('i18nTestModule.WITHNAMESPACE', $matches);
482
        $this->assertArrayNotHasKey('i18nTestModuleInclude.ss.NONAMESPACE', $matches);
483
        $this->assertArrayNotHasKey('i18nTestModuleInclude.ss.SPRINTFINCLUDENAMESPACE', $matches);
484
        $this->assertArrayNotHasKey('i18nTestModuleInclude.ss.SPRINTFINCLUDENONAMESPACE', $matches);
485
    }
486
487
    public function testCollectMergesWithExisting()
488
    {
489
        $c = i18nTextCollector::create();
490
        $c->setWarnOnEmptyDefault(false);
491
        $c->setWriter(new YamlWriter());
492
        $c->basePath = $this->alternateBasePath;
493
        $c->baseSavePath = $this->alternateBaseSavePath;
494
495
        $entitiesByModule = $c->collect(null, true /* merge */);
496
        $this->assertArrayHasKey(
497
            'i18nTestModule.ENTITY',
498
            $entitiesByModule['i18ntestmodule'],
499
            'Retains existing entities'
500
        );
501
        $this->assertArrayHasKey(
502
            'i18nTestModule.NEWENTITY',
503
            $entitiesByModule['i18ntestmodule'],
504
            'Adds new entities'
505
        );
506
507
        // Test cross-module strings are set correctly
508
        $this->assertArrayHasKey(
509
            'i18nProviderClass.OTHER_MODULE',
510
            $entitiesByModule['i18ntestmodule']
511
        );
512
        $this->assertEquals(
513
            [
514
                'comment' => 'Test string in another module',
515
                'default' => 'i18ntestmodule string defined in i18nothermodule',
516
            ],
517
            $entitiesByModule['i18ntestmodule']['i18nProviderClass.OTHER_MODULE']
518
        );
519
    }
520
521
    public function testCollectFromFilesystemAndWriteMasterTables()
522
    {
523
        i18n::set_locale('en_US');  //set the locale to the US locale expected in the asserts
524
        i18n::config()->update('default_locale', 'en_US');
525
        i18n::config()->update('missing_default_warning', false);
526
527
        $c = i18nTextCollector::create();
528
        $c->setWarnOnEmptyDefault(false);
529
        $c->setWriter(new YamlWriter());
530
        $c->basePath = $this->alternateBasePath;
531
        $c->baseSavePath = $this->alternateBaseSavePath;
532
533
        $c->run();
534
535
        // i18ntestmodule
536
        $moduleLangFile = "{$this->alternateBaseSavePath}/i18ntestmodule/lang/" . $c->getDefaultLocale() . '.yml';
537
        $this->assertTrue(
538
            file_exists($moduleLangFile),
539
            'Master language file can be written to modules /lang folder'
540
        );
541
542
        $moduleLangFileContent = file_get_contents($moduleLangFile);
543
        $this->assertContains(
544
            "    ADDITION: Addition\n",
545
            $moduleLangFileContent
546
        );
547
        $this->assertContains(
548
            "    ENTITY: 'Entity with \"Double Quotes\"'\n",
549
            $moduleLangFileContent
550
        );
551
        $this->assertContains(
552
            "    MAINTEMPLATE: 'Main Template'\n",
553
            $moduleLangFileContent
554
        );
555
        $this->assertContains(
556
            "    OTHERENTITY: 'Other Entity'\n",
557
            $moduleLangFileContent
558
        );
559
        $this->assertContains(
560
            "    WITHNAMESPACE: 'Include Entity with Namespace'\n",
561
            $moduleLangFileContent
562
        );
563
        $this->assertContains(
564
            "    NONAMESPACE: 'Include Entity without Namespace'\n",
565
            $moduleLangFileContent
566
        );
567
568
        // i18nothermodule
569
        $otherModuleLangFile = "{$this->alternateBaseSavePath}/i18nothermodule/lang/" . $c->getDefaultLocale() . '.yml';
570
        $this->assertTrue(
571
            file_exists($otherModuleLangFile),
572
            'Master language file can be written to modules /lang folder'
573
        );
574
        $otherModuleLangFileContent = file_get_contents($otherModuleLangFile);
575
        $this->assertContains(
576
            "    ENTITY: 'Other Module Entity'\n",
577
            $otherModuleLangFileContent
578
        );
579
        $this->assertContains(
580
            "    MAINTEMPLATE: 'Main Template Other Module'\n",
581
            $otherModuleLangFileContent
582
        );
583
    }
584
585
    public function testCollectFromEntityProvidersInCustomObject()
586
    {
587
        // note: Disable _fakewebroot manifest for this test
588
        $this->popManifests();
589
590
        $c = i18nTextCollector::create();
591
592
        // Collect from MyObject.php
593
        $filePath = __DIR__ . '/i18nTest/MyObject.php';
594
        $matches = $c->collectFromEntityProviders($filePath);
595
        $this->assertEquals(
596
            [
597
                'SilverStripe\Admin\LeftAndMain.OTHER_TITLE' => [
598
                    'default' => 'Other title',
599
                    'module' => 'admin',
600
                ],
601
                'SilverStripe\i18n\Tests\i18nTest\MyObject.PLURALNAME' => 'My Objects',
602
                'SilverStripe\i18n\Tests\i18nTest\MyObject.PLURALS' => [
603
                    'one' => 'A My Object',
604
                    'other' => '{count} My Objects',
605
                ],
606
                'SilverStripe\i18n\Tests\i18nTest\MyObject.SINGULARNAME' => 'My Object',
607
            ],
608
            $matches
609
        );
610
    }
611
612
    public function testCollectFromEntityProvidersInWebRoot()
613
    {
614
        // Collect from i18nProviderClass
615
        $c = i18nTextCollector::create();
616
        $c->setWarnOnEmptyDefault(false);
617
        $c->setWriter(new YamlWriter());
618
        $c->basePath = $this->alternateBasePath;
619
        $c->baseSavePath = $this->alternateBaseSavePath;
620
        $entitiesByModule = $c->collect(null, false);
621
        $this->assertEquals(
622
            [
623
                'comment' => 'Plural forms for the test class',
624
                'one' => 'A class',
625
                'other' => '{count} classes',
626
            ],
627
            $entitiesByModule['i18nothermodule']['i18nProviderClass.PLURALS']
628
        );
629
        $this->assertEquals(
630
            'My Provider Class',
631
            $entitiesByModule['i18nothermodule']['i18nProviderClass.TITLE']
632
        );
633
        $this->assertEquals(
634
            [
635
                'comment' => 'Test string in another module',
636
                'default' => 'i18ntestmodule string defined in i18nothermodule',
637
            ],
638
            $entitiesByModule['i18ntestmodule']['i18nProviderClass.OTHER_MODULE']
639
        );
640
    }
641
642
    /**
643
     * Test that duplicate keys are resolved to the appropriate modules
644
     */
645
    public function testResolveDuplicates()
646
    {
647
        $collector = new Collector();
648
649
        // Dummy data as collected
650
        $data1 = [
651
            'i18ntestmodule' => [
652
                'i18nTestModule.PLURALNAME' => 'Data Objects',
653
                'i18nTestModule.SINGULARNAME' => 'Data Object',
654
            ],
655
            'mymodule' => [
656
                'i18nTestModule.PLURALNAME' => 'Ignored String',
657
                'i18nTestModule.STREETNAME' => 'Shortland Street',
658
            ],
659
        ];
660
        $expected = [
661
            'i18ntestmodule' => [
662
                'i18nTestModule.PLURALNAME' => 'Data Objects',
663
                'i18nTestModule.SINGULARNAME' => 'Data Object',
664
            ],
665
            'mymodule' => [
666
                // Removed PLURALNAME because this key doesn't exist in i18ntestmodule strings
667
                'i18nTestModule.STREETNAME' => 'Shortland Street'
668
            ]
669
        ];
670
671
        $resolved = $collector->resolveDuplicateConflicts_Test($data1);
672
        $this->assertEquals($expected, $resolved);
673
674
        // Test getConflicts
675
        $data2 = [
676
            'module1' => [
677
                'i18ntestmodule.ONE' => 'One',
678
                'i18ntestmodule.TWO' => 'Two',
679
                'i18ntestmodule.THREE' => 'Three',
680
            ],
681
            'module2' => [
682
                'i18ntestmodule.THREE' => 'Three',
683
            ],
684
            'module3' => [
685
                'i18ntestmodule.TWO' => 'Two',
686
                'i18ntestmodule.THREE' => 'Three',
687
            ],
688
        ];
689
        $conflictsA = $collector->getConflicts_Test($data2);
690
        sort($conflictsA);
691
        $this->assertEquals(
692
            array('i18ntestmodule.THREE', 'i18ntestmodule.TWO'),
693
            $conflictsA
694
        );
695
696
        // Removing module3 should remove a conflict
697
        unset($data2['module3']);
698
        $conflictsB = $collector->getConflicts_Test($data2);
699
        $this->assertEquals(
700
            array('i18ntestmodule.THREE'),
701
            $conflictsB
702
        );
703
    }
704
705
    /**
706
     * Test ability for textcollector to detect modules
707
     */
708
    public function testModuleDetection()
709
    {
710
        $collector = new Collector();
711
        $modules = ModuleLoader::instance()->getManifest()->getModules();
712
        $this->assertEquals(
713
            array(
714
                'i18nnonstandardmodule',
715
                'i18ntestmodule',
716
                'i18nothermodule'
717
            ),
718
            array_keys($modules)
719
        );
720
721
        $this->assertEquals('i18ntestmodule', $collector->findModuleForClass_Test('i18nTestNamespacedClass'));
722
        $this->assertEquals(
723
            'i18ntestmodule',
724
            $collector->findModuleForClass_Test('i18nTest\\i18nTestNamespacedClass')
725
        );
726
        $this->assertEquals('i18ntestmodule', $collector->findModuleForClass_Test('i18nTestSubModule'));
727
    }
728
729
    /**
730
     * Test that text collector can detect module file lists properly
731
     */
732
    public function testModuleFileList()
733
    {
734
        $collector = new Collector();
735
        $collector->basePath = $this->alternateBasePath;
736
        $collector->baseSavePath = $this->alternateBaseSavePath;
737
738
        // Non-standard modules can't be safely filtered, so just index everything
739
        $nonStandardFiles = $collector->getFileListForModule_Test('i18nnonstandardmodule');
740
        $nonStandardRoot = $this->alternateBasePath . '/i18nnonstandardmodule';
741
        $this->assertEquals(3, count($nonStandardFiles));
742
        $this->assertArrayHasKey("{$nonStandardRoot}/_config.php", $nonStandardFiles);
743
        $this->assertArrayHasKey("{$nonStandardRoot}/phpfile.php", $nonStandardFiles);
744
        $this->assertArrayHasKey("{$nonStandardRoot}/template.ss", $nonStandardFiles);
745
746
        // Normal module should have predictable dir structure
747
        $testFiles = $collector->getFileListForModule_Test('i18ntestmodule');
748
        $testRoot = $this->alternateBasePath . '/i18ntestmodule';
749
        $this->assertEquals(7, count($testFiles));
750
        // Code in code folder is detected
751
        $this->assertArrayHasKey("{$testRoot}/code/i18nTestModule.php", $testFiles);
752
        $this->assertArrayHasKey("{$testRoot}/code/subfolder/_config.php", $testFiles);
753
        $this->assertArrayHasKey("{$testRoot}/code/subfolder/i18nTestSubModule.php", $testFiles);
754
        $this->assertArrayHasKey("{$testRoot}/code/subfolder/i18nTestNamespacedClass.php", $testFiles);
755
        // Templates in templates folder is detected
756
        $this->assertArrayHasKey("{$testRoot}/templates/Includes/i18nTestModuleInclude.ss", $testFiles);
757
        $this->assertArrayHasKey("{$testRoot}/templates/Layout/i18nTestModule.ss", $testFiles);
758
        $this->assertArrayHasKey("{$testRoot}/templates/i18nTestModule.ss", $testFiles);
759
760
        // Standard modules with code in odd places should only have code in those directories detected
761
        $otherFiles = $collector->getFileListForModule_Test('i18nothermodule');
762
        $otherRoot = $this->alternateBasePath . '/i18nothermodule';
763
        $this->assertEquals(4, count($otherFiles));
764
        // Only detect well-behaved files
765
        $this->assertArrayHasKey("{$otherRoot}/code/i18nOtherModule.php", $otherFiles);
766
        $this->assertArrayHasKey("{$otherRoot}/code/i18nProviderClass.php", $otherFiles);
767
        $this->assertArrayHasKey("{$otherRoot}/code/i18nTestModuleDecorator.php", $otherFiles);
768
        $this->assertArrayHasKey("{$otherRoot}/templates/i18nOtherModule.ss", $otherFiles);
769
    }
770
}
771