Completed
Push — master ( d29470...ca3fa1 )
by Ingo
21s
created

testCollectFromNewTemplateSyntaxUsingParserSubclass()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 47
Code Lines 27

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 27
nc 1
nop 0
dl 0
loc 47
rs 9.0303
c 0
b 0
f 0
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
    protected 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
    protected 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
<%t SilverStripe\TestModule\i18nTestModule.INJECTIONS_10 "This string is namespaced" %>
90
SS;
91
        $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...
92
93
        $this->assertEquals(
94
            [
95
                'Test.SINGLEQUOTE' => 'Single Quote',
96
                'i18nTestModule.NEWMETHODSIG' => "New _t method signature test",
97
                'i18nTestModule.INJECTIONS_0' => "Hello {name} {greeting}, and {goodbye}",
98
                'i18nTestModule.INJECTIONS_1' => "Hello {name} {greeting}, and {goodbye}",
99
                'i18nTestModule.INJECTIONS_2' => [
100
                    'default' => "Hello {name} {greeting}",
101
                    'comment' => 'context (ignored)',
102
                ],
103
                'i18nTestModule.INJECTIONS_9' => [
104
                    'one' => 'An item',
105
                    'other' => '{count} items',
106
                    'comment' => 'Test Pluralisation'
107
                ],
108
                'SilverStripe\\TestModule\\i18nTestModule.INJECTIONS_10' => 'This string is namespaced'
109
            ],
110
            $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...
111
        );
112
113
        // Test warning is raised on empty default
114
        $c->setWarnOnEmptyDefault(true);
115
        $this->setExpectedException(
0 ignored issues
show
Deprecated Code introduced by
The method PHPUnit_Framework_TestCase::setExpectedException() has been deprecated with message: Method deprecated since Release 5.2.0; use expectException() instead

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
116
            PHPUnit_Framework_Error_Notice::class,
117
            'Missing localisation default for key i18nTestModule.INJECTIONS_3'
118
        );
119
        $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...
120
    }
121
122
    public function testCollectFromTemplateSimple()
123
    {
124
        $c = i18nTextCollector::create();
125
        $mymodule = ModuleLoader::instance()->getManifest()->getModule('i18ntestmodule');
126
127
        $html = <<<SS
128
<% _t('Test.SINGLEQUOTE','Single Quote'); %>
129
SS;
130
        $this->assertEquals(
131
            [ 'Test.SINGLEQUOTE' => 'Single Quote' ],
132
            $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 125 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...
133
        );
134
135
        $html = <<<SS
136
<% _t(  "Test.DOUBLEQUOTE", "Double Quote and Spaces"   ); %>
137
SS;
138
        $this->assertEquals(
139
            [ 'Test.DOUBLEQUOTE' => "Double Quote and Spaces" ],
140
            $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 125 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...
141
        );
142
143
        $html = <<<SS
144
<% _t("Test.NOSEMICOLON","No Semicolon") %>
145
SS;
146
        $this->assertEquals(
147
            [ 'Test.NOSEMICOLON' => "No Semicolon" ],
148
            $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 125 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...
149
        );
150
    }
151
152
    public function testCollectFromTemplateAdvanced()
153
    {
154
        $c = i18nTextCollector::create();
155
        $c->setWarnOnEmptyDefault(false);
156
        $mymodule = ModuleLoader::instance()->getManifest()->getModule('i18ntestmodule');
157
158
        $html = <<<SS
159
<% _t(
160
	'NEWLINES',
161
	'New Lines'
162
) %>
163
SS;
164
        $this->assertEquals(
165
            [ 'Test.NEWLINES' => "New Lines" ],
166
            $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 156 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...
167
        );
168
169
        $html = <<<SS
170
<% _t(
171
	'Test.PRIOANDCOMMENT',
172
	' Prio and Value with "Double Quotes"',
173
	'Comment with "Double Quotes"'
174
) %>
175
SS;
176
        $this->assertEquals(
177
            [ 'Test.PRIOANDCOMMENT' => [
178
                'default' => ' Prio and Value with "Double Quotes"',
179
                'comment' => 'Comment with "Double Quotes"',
180
            ]],
181
            $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 156 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...
182
        );
183
184
        $html = <<<SS
185
<% _t(
186
	'Test.PRIOANDCOMMENT',
187
	" Prio and Value with 'Single Quotes'",
188
189
	"Comment with 'Single Quotes'"
190
) %>
191
SS;
192
        $this->assertEquals(
193
            [ 'Test.PRIOANDCOMMENT' => [
194
                'default' => " Prio and Value with 'Single Quotes'",
195
                'comment' => "Comment with 'Single Quotes'",
196
            ]],
197
            $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 156 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...
198
        );
199
200
        // Test empty
201
        $html = <<<SS
202
<% _t('Test.PRIOANDCOMMENT') %>
203
SS;
204
        $this->assertEquals(
205
            [],
206
            $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 156 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...
207
        );
208
209
        // Test warning is raised on empty default
210
        $c->setWarnOnEmptyDefault(true);
211
        $this->setExpectedException(
0 ignored issues
show
Deprecated Code introduced by
The method PHPUnit_Framework_TestCase::setExpectedException() has been deprecated with message: Method deprecated since Release 5.2.0; use expectException() instead

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
212
            PHPUnit_Framework_Error_Notice::class,
213
            'Missing localisation default for key Test.PRIOANDCOMMENT'
214
        );
215
        $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 156 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...
216
    }
217
218
219
    public function testCollectFromCodeSimple()
220
    {
221
        $c = i18nTextCollector::create();
222
        $mymodule = ModuleLoader::instance()->getManifest()->getModule('i18ntestmodule');
223
224
        $php = <<<PHP
225
_t('Test.SINGLEQUOTE','Single Quote');
226
PHP;
227
        $this->assertEquals(
228
            [ 'Test.SINGLEQUOTE' => 'Single Quote' ],
229
            $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 222 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...
230
        );
231
232
        $php = <<<PHP
233
_t(  "Test.DOUBLEQUOTE", "Double Quote and Spaces"   );
234
PHP;
235
        $this->assertEquals(
236
            [ 'Test.DOUBLEQUOTE' => "Double Quote and Spaces" ],
237
            $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 222 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...
238
        );
239
    }
240
241
    public function testCollectFromCodeAdvanced()
242
    {
243
        $c = i18nTextCollector::create();
244
        $mymodule = ModuleLoader::instance()->getManifest()->getModule('i18ntestmodule');
245
246
        $php = <<<PHP
247
_t(
248
	'Test.NEWLINES',
249
	'New Lines'
250
);
251
PHP;
252
        $this->assertEquals(
253
            [ 'Test.NEWLINES' => "New Lines" ],
254
            $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 244 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...
255
        );
256
257
        $php = <<<PHP
258
_t(
259
	'Test.PRIOANDCOMMENT',
260
	' Value with "Double Quotes"',
261
262
	'Comment with "Double Quotes"'
263
);
264
PHP;
265
        $this->assertEquals(
266
            [
267
                'Test.PRIOANDCOMMENT' => [
268
                    'default' => ' Value with "Double Quotes"',
269
                    'comment' => 'Comment with "Double Quotes"',
270
                ]
271
            ],
272
            $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 244 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...
273
        );
274
275
        $php = <<<PHP
276
_t(
277
	'Test.PRIOANDCOMMENT',
278
	" Value with 'Single Quotes'",
279
280
	"Comment with 'Single Quotes'"
281
);
282
PHP;
283
        $this->assertEquals(
284
            [ 'Test.PRIOANDCOMMENT' => [
285
                'default' => " Value with 'Single Quotes'",
286
                'comment' => "Comment with 'Single Quotes'"
287
            ] ],
288
            $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 244 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...
289
        );
290
291
        $php = <<<PHP
292
_t(
293
	'Test.PRIOANDCOMMENT',
294
	'Value with \'Escaped Single Quotes\''
295
);
296
PHP;
297
        $this->assertEquals(
298
            [ 'Test.PRIOANDCOMMENT' => "Value with 'Escaped Single Quotes'" ],
299
            $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 244 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...
300
        );
301
302
        $php = <<<PHP
303
_t(
304
	'Test.PRIOANDCOMMENT',
305
	"Doublequoted Value with 'Unescaped Single Quotes'"
306
	
307
	
308
);
309
PHP;
310
        $this->assertEquals(
311
            [ 'Test.PRIOANDCOMMENT' => "Doublequoted Value with 'Unescaped Single Quotes'"],
312
            $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 244 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...
313
        );
314
    }
315
316
    public function testCollectFromCodeNamespace()
317
    {
318
        $c = i18nTextCollector::create();
319
        $mymodule = ModuleLoader::instance()->getManifest()->getModule('i18ntestmodule');
320
        $php = <<<PHP
321
<?php
322
namespace SilverStripe\Framework\Core;
323
324
class MyClass extends Base implements SomeService {
325
    public function getNewLines() {
326
        return _t(
327
            __CLASS__.'.NEWLINES',
328
            'New Lines'
329
        );
330
    }
331
}
332
PHP;
333
        $this->assertEquals(
334
            [ 'SilverStripe\\Framework\\Core\\MyClass.NEWLINES' => "New Lines" ],
335
            $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 319 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...
336
        );
337
    }
338
339
340
    public function testNewlinesInEntityValues()
341
    {
342
        $c = i18nTextCollector::create();
343
        $mymodule = ModuleLoader::instance()->getManifest()->getModule('i18ntestmodule');
344
345
        $php = <<<PHP
346
_t(
347
'Test.NEWLINESINGLEQUOTE',
348
'Line 1
349
Line 2'
350
);
351
PHP;
352
353
        $eol = PHP_EOL;
354
        $this->assertEquals(
355
            [ 'Test.NEWLINESINGLEQUOTE' => "Line 1{$eol}Line 2" ],
356
            $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 343 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...
357
        );
358
359
        $php = <<<PHP
360
_t(
361
'Test.NEWLINEDOUBLEQUOTE',
362
"Line 1
363
Line 2"
364
);
365
PHP;
366
        $this->assertEquals(
367
            [ 'Test.NEWLINEDOUBLEQUOTE' => "Line 1{$eol}Line 2" ],
368
            $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 343 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...
369
        );
370
    }
371
372
    /**
373
     * Test extracting entities from the new _t method signature
374
     */
375
    public function testCollectFromCodeNewSignature()
376
    {
377
        $c = i18nTextCollector::create();
378
        $c->setWarnOnEmptyDefault(false); // Disable warnings for tests
379
        $mymodule = ModuleLoader::instance()->getManifest()->getModule('i18ntestmodule');
380
381
        $php = <<<PHP
382
_t('i18nTestModule.NEWMETHODSIG',"New _t method signature test");
383
_t('i18nTestModule.INJECTIONS2', "Hello {name} {greeting}. But it is late, {goodbye}",
384
	array("name"=>"Paul", "greeting"=>"good you are here", "goodbye"=>"see you"));
385
_t("i18nTestModule.INJECTIONS3", "Hello {name} {greeting}. But it is late, {goodbye}",
386
		"New context (this should be ignored)",
387
		array("name"=>"Steffen", "greeting"=>"willkommen", "goodbye"=>"wiedersehen"));
388
_t('i18nTestModule.INJECTIONS4', array("name"=>"Cat", "greeting"=>"meow", "goodbye"=>"meow"));
389
_t('i18nTestModule.INJECTIONS6', "Hello {name} {greeting}. But it is late, {goodbye}",
390
	["name"=>"Paul", "greeting"=>"good you are here", "goodbye"=>"see you"]);
391
_t("i18nTestModule.INJECTIONS7", "Hello {name} {greeting}. But it is late, {goodbye}",
392
		"New context (this should be ignored)",
393
		["name"=>"Steffen", "greeting"=>"willkommen", "goodbye"=>"wiedersehen"]);
394
_t('i18nTestModule.INJECTIONS8', ["name"=>"Cat", "greeting"=>"meow", "goodbye"=>"meow"]);
395
_t('i18nTestModule.INJECTIONS9', "An item|{count} items", ['count' => 4], "Test Pluralisation");
396
PHP;
397
398
        $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 379 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...
399
400
        $expectedArray = [
401
            'i18nTestModule.INJECTIONS2' => "Hello {name} {greeting}. But it is late, {goodbye}",
402
            'i18nTestModule.INJECTIONS3' => [
403
                'default' => "Hello {name} {greeting}. But it is late, {goodbye}",
404
                'comment' => 'New context (this should be ignored)'
405
            ],
406
            'i18nTestModule.INJECTIONS6' => "Hello {name} {greeting}. But it is late, {goodbye}",
407
            'i18nTestModule.INJECTIONS7' => [
408
                'default' => "Hello {name} {greeting}. But it is late, {goodbye}",
409
                'comment' => "New context (this should be ignored)",
410
            ],
411
            'i18nTestModule.INJECTIONS9' => [
412
                'one' => 'An item',
413
                'other' => '{count} items',
414
                'comment' => 'Test Pluralisation',
415
            ],
416
            'i18nTestModule.NEWMETHODSIG' => "New _t method signature test",
417
        ];
418
        $this->assertEquals($expectedArray, $collectedTranslatables);
419
420
        // Test warning is raised on empty default
421
        $this->setExpectedException(
0 ignored issues
show
Deprecated Code introduced by
The method PHPUnit_Framework_TestCase::setExpectedException() has been deprecated with message: Method deprecated since Release 5.2.0; use expectException() instead

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

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