Completed
Push — master ( 48aca5...a67d7c )
by Damian
16s queued 12s
created

testHomeNotVisibleInCMSBothConfigExact()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 14
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 1 Features 0
Metric Value
cc 1
eloc 9
c 1
b 1
f 0
nc 1
nop 0
dl 0
loc 14
rs 9.9666
1
<?php
2
3
namespace TractorCow\Fluent\Tests\Extension;
4
5
use Page;
0 ignored issues
show
Bug introduced by
The type Page was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
6
use SilverStripe\CMS\Forms\SiteTreeURLSegmentField;
0 ignored issues
show
Bug introduced by
The type SilverStripe\CMS\Forms\SiteTreeURLSegmentField was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
7
use SilverStripe\CMS\Model\SiteTree;
0 ignored issues
show
Bug introduced by
The type SilverStripe\CMS\Model\SiteTree was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
8
use SilverStripe\Control\Director;
9
use SilverStripe\Core\Config\Config;
10
use SilverStripe\Dev\SapphireTest;
11
use SilverStripe\Forms\CompositeField;
12
use SilverStripe\Forms\FieldList;
13
use SilverStripe\Forms\LiteralField;
14
use SilverStripe\ORM\ArrayList;
15
use SilverStripe\ORM\DataObject;
16
use SilverStripe\ORM\ValidationException;
17
use SilverStripe\Versioned\Versioned;
18
use TractorCow\Fluent\Extension\FluentDirectorExtension;
19
use TractorCow\Fluent\Extension\FluentExtension;
20
use TractorCow\Fluent\Extension\FluentSiteTreeExtension;
21
use TractorCow\Fluent\Extension\FluentVersionedExtension;
22
use TractorCow\Fluent\Model\Domain;
23
use TractorCow\Fluent\Model\Locale;
24
use TractorCow\Fluent\Model\RecordLocale;
25
use TractorCow\Fluent\State\FluentState;
26
27
// Skip if pages module not installed
28
if (!class_exists(SiteTree::class)) {
29
    return;
30
}
31
32
class FluentSiteTreeExtensionTest extends SapphireTest
33
{
34
    protected static $fixture_file = 'FluentSiteTreeExtensionTest.yml';
35
36
    protected static $required_extensions = [
37
        SiteTree::class => [
38
            FluentSiteTreeExtension::class,
39
        ],
40
    ];
41
42
    protected function setUp()
43
    {
44
        parent::setUp();
45
        Config::modify()
46
            ->set(Director::class, 'alternate_base_url', 'http://mocked')
47
            ->set(FluentDirectorExtension::class, 'disable_default_prefix', false);
48
49
        // Clear cache
50
        Locale::clearCached();
51
        Domain::clearCached();
52
        (new FluentVersionedExtension)->flushCache();
53
54
        FluentState::singleton()
55
            ->setLocale('de_DE')
56
            ->setIsDomainMode(false);
57
    }
58
59
    public function testGetLocaleInformation()
60
    {
61
        FluentState::singleton()->withState(function (FluentState $newState) {
62
            $newState
63
                ->setLocale('de_DE')
64
                ->setIsDomainMode(false);
65
66
            /** @var Page|FluentSiteTreeExtension $page */
67
            $page = $this->objFromFixture(Page::class, 'nz-page');
68
            $result = $page->LocaleInformation('en_NZ');
69
70
            $this->assertInstanceOf(RecordLocale::class, $result);
71
            $this->assertEquals('en_NZ', $result->getLocale());
72
            $this->assertEquals('en-nz', $result->getLocaleRFC1766());
73
            $this->assertEquals('en-nz', $result->getHrefLang());
74
            $this->assertEquals('English (New Zealand)', $result->getTitle());
75
            $this->assertEquals('English', $result->getLanguageNative());
76
            $this->assertEquals('en', $result->getLanguage());
77
            $this->assertEquals('/newzealand/a-page/', $result->getLink());
78
            $this->assertEquals('http://mocked/newzealand/a-page/', $result->getAbsoluteLink());
79
            $this->assertEquals('link', $result->getLinkingMode());
80
            $this->assertEquals('newzealand', $result->getURLSegment());
81
        });
82
    }
83
84
    public function testGetLocales()
85
    {
86
        FluentState::singleton()->withState(function (FluentState $newState) {
87
            $newState
88
                ->setLocale('de_DE')
89
                ->setIsDomainMode(false);
90
91
            /** @var Page|FluentSiteTreeExtension $page */
92
            $page = $this->objFromFixture(Page::class, 'nz-page');
93
            $result = $page->Locales();
94
95
            $this->assertInstanceOf(ArrayList::class, $result);
96
            $this->assertCount(6, $result);
97
            $this->assertListEquals([
98
                ['Locale' => 'en_NZ'],
99
                ['Locale' => 'de_DE'],
100
                ['Locale' => 'en_US'],
101
                ['Locale' => 'en_GB'],
102
                ['Locale' => 'es_ES'],
103
                ['Locale' => 'zh_CN'],
104
            ], $result);
0 ignored issues
show
Bug introduced by
$result of type TractorCow\Fluent\Model\RecordLocale[] is incompatible with the type SilverStripe\ORM\SS_List expected by parameter $list of SilverStripe\Dev\SapphireTest::assertListEquals(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

104
            ], /** @scrutinizer ignore-type */ $result);
Loading history...
105
        });
106
    }
107
108
    /**
109
     * Tests for url generation
110
     *
111
     * @return array list of tests with values:
112
     *  - domain (or false for non-domain mode)
113
     *  - locale
114
     *  - disable_default_prefix flag
115
     *  - page id
116
     *  - expected link
117
     */
118
    public function provideURLTests()
119
    {
120
        return [
121
            // Non-domain tests
122
            [null, 'de_DE', false, 'home', '/german/'],
123
            [null, 'de_DE', false, 'about', '/german/about-us/'],
124
            [null, 'de_DE', false, 'staff', '/german/about-us/my-staff/'],
125
            // Since de_DE is the only locale on the www.example.de domain, ensure that the locale
126
            // isn't unnecessarily added to the link.
127
            // In this case disable_default_prefix is ignored
128
            // See https://github.com/tractorcow/silverstripe-fluent/issues/75
129
            ['www.example.de', 'de_DE', false, 'home', '/'],
130
            ['www.example.de', 'de_DE', false, 'about', '/about-us/'],
131
            ['www.example.de', 'de_DE', false, 'staff', '/about-us/my-staff/'],
132
133
            // Test domains with multiple locales
134
            //  - es_ES non default locale
135
            ['www.example.com', 'es_ES', false, 'home', '/es_ES/'],
136
            ['www.example.com', 'es_ES', false, 'about', '/es_ES/about-us/'],
137
            ['www.example.com', 'es_ES', false, 'staff', '/es_ES/about-us/my-staff/'],
138
            //  - en_US default locale
139
            ['www.example.com', 'en_US', false, 'home', '/usa/'],
140
            ['www.example.com', 'en_US', false, 'about', '/usa/about-us/'],
141
            ['www.example.com', 'en_US', false, 'staff', '/usa/about-us/my-staff/'],
142
            //  - en_US default locale, but with disable_default_prefix on
143
            ['www.example.com', 'en_US', true, 'home', '/'],
144
            ['www.example.com', 'en_US', true, 'about', '/about-us/'],
145
            ['www.example.com', 'en_US', true, 'staff', '/about-us/my-staff/'],
146
147
            // Test cross-domain links include the opposing domain
148
            // - to default locale
149
            ['www.example.de', 'en_US', true, 'home', 'http://www.example.com/'],
150
            ['www.example.de', 'en_US', true, 'staff', 'http://www.example.com/about-us/my-staff/'],
151
            // - to non defalut locale
152
            ['www.example.de', 'es_ES', true, 'home', 'http://www.example.com/es_ES/'],
153
            ['www.example.de', 'es_ES', true, 'staff', 'http://www.example.com/es_ES/about-us/my-staff/'],
154
        ];
155
    }
156
157
    /**
158
     * Test that URLS for pages are generated correctly
159
     *
160
     * @dataProvider provideURLTests
161
     * @param string $domain
162
     * @param string $locale
163
     * @param bool $prefixDisabled
164
     * @param string $pageName
165
     * @param string $url
166
     */
167
    public function testFluentURLs(?string $domain, string $locale, bool $prefixDisabled, string $pageName, string $url)
168
    {
169
        FluentState::singleton()->withState(
170
            function (FluentState $newState) use ($domain, $locale, $prefixDisabled, $pageName, $url) {
171
                $newState
172
                    ->setLocale($locale)
173
                    ->setDomain($domain)
174
                    ->setIsDomainMode(!empty($domain));
175
176
                // Set url generation option
177
                Config::modify()
178
                    ->set(FluentDirectorExtension::class, 'disable_default_prefix', $prefixDisabled);
179
180
                /** @var Page|FluentSiteTreeExtension $page */
181
                $page = $this->objFromFixture(Page::class, $pageName);
182
                $this->assertEquals($url, $page->Link());
0 ignored issues
show
Bug introduced by
The method Link() does not exist on TractorCow\Fluent\Extens...FluentSiteTreeExtension. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

182
                $this->assertEquals($url, $page->/** @scrutinizer ignore-call */ Link());

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
183
            }
184
        );
185
    }
186
187
    public function testUpdateStatusFlagsFluentInvisible()
188
    {
189
        /** @var Page|FluentSiteTreeExtension $page */
190
        $page = $this->objFromFixture(Page::class, 'home');
191
        $flags = $page->getStatusFlags();
0 ignored issues
show
Bug introduced by
The method getStatusFlags() does not exist on TractorCow\Fluent\Extens...FluentSiteTreeExtension. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

191
        /** @scrutinizer ignore-call */ 
192
        $flags = $page->getStatusFlags();

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
192
193
        $this->assertArrayHasKey('fluentinvisible', $flags);
194
    }
195
196
    public function testStatusMessageNotVisible()
197
    {
198
        FluentState::singleton()->withState(function (FluentState $newState) {
199
            $newState
200
                ->setLocale('en_NZ')
201
                ->setIsDomainMode(false);
202
203
            /** @var Page|FluentSiteTreeExtension $page */
204
            $page = $this->objFromFixture(Page::class, 'staff');
205
            $page->config()
0 ignored issues
show
Bug introduced by
The method config() does not exist on TractorCow\Fluent\Extens...FluentSiteTreeExtension. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

205
            $page->/** @scrutinizer ignore-call */ 
206
                   config()

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
206
                ->set('locale_published_status_message', true)
207
                ->set('frontend_publish_required', FluentExtension::INHERITANCE_MODE_EXACT);
208
209
            $fields = $page->getCMSFields();
0 ignored issues
show
Bug introduced by
The method getCMSFields() does not exist on TractorCow\Fluent\Extens...FluentSiteTreeExtension. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

209
            /** @scrutinizer ignore-call */ 
210
            $fields = $page->getCMSFields();

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
210
211
            /** @var LiteralField $statusMessage */
212
            $statusMessage = $fields->fieldByName('LocaleStatusMessage');
213
214
            $this->assertNotNull($statusMessage, 'Locale message was not added');
215
            $this->assertContains('This page will not be visible', $statusMessage->getContent());
216
        });
217
    }
218
219
    public function testStatusMessageUnknown()
220
    {
221
        FluentState::singleton()->withState(function (FluentState $newState) {
222
            $newState
223
                ->setLocale('en_NZ')
224
                ->setIsDomainMode(false);
225
226
            /** @var Page|FluentSiteTreeExtension $page */
227
            $page = $this->objFromFixture(Page::class, 'home');
228
            $page->config()
229
                ->set('locale_published_status_message', true)
230
                ->set('frontend_publish_required', FluentExtension::INHERITANCE_MODE_ANY);
231
232
            $fields = $page->getCMSFields();
233
234
            /** @var LiteralField $statusMessage */
235
            $statusMessage = $fields->fieldByName('LocaleStatusMessage');
236
237
            $this->assertNotNull($fields->fieldByName('LocaleStatusMessage'));
238
            $this->assertContains('No content is available for this page', $statusMessage->getContent());
239
        });
240
    }
241
242
    public function testStatusMessageDrafted()
243
    {
244
        FluentState::singleton()->withState(function (FluentState $newState) {
245
            $newState
246
                ->setLocale('en_NZ')
247
                ->setIsDomainMode(false);
248
249
            /** @var Page|FluentSiteTreeExtension $page */
250
            $page = $this->objFromFixture(Page::class, 'home');
251
            $page->config()
252
                ->set('locale_published_status_message', true)
253
                ->set('frontend_publish_required', FluentExtension::INHERITANCE_MODE_ANY);
254
            $page->write();
0 ignored issues
show
Bug introduced by
The method write() does not exist on TractorCow\Fluent\Extens...FluentSiteTreeExtension. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

254
            $page->/** @scrutinizer ignore-call */ 
255
                   write();

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
255
256
            $fields = $page->getCMSFields();
257
258
            /** @var LiteralField $statusMessage */
259
            $statusMessage = $fields->fieldByName('LocaleStatusMessage');
260
261
            $this->assertNotNull($fields->fieldByName('LocaleStatusMessage'));
262
            $this->assertContains('A draft has been created for this locale', $statusMessage->getContent());
263
        });
264
    }
265
266
    public function testUpdateCMSActionsInherited()
267
    {
268
        /** @var Page|FluentSiteTreeExtension $page */
269
        $page = $this->objFromFixture(Page::class, 'home');
270
        $actions = $page->getCMSActions();
0 ignored issues
show
Bug introduced by
The method getCMSActions() does not exist on TractorCow\Fluent\Extens...FluentSiteTreeExtension. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

270
        /** @scrutinizer ignore-call */ 
271
        $actions = $page->getCMSActions();

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
271
272
        /** @var CompositeField $majorActions */
273
        $majorActions = $actions->fieldByName('MajorActions');
274
275
        $this->assertNotNull($majorActions);
276
277
        $actionSave = $majorActions->getChildren()->fieldByName('action_save_localised_copy');
0 ignored issues
show
Bug introduced by
Are you sure the assignment to $actionSave is correct as $majorActions->getChildr...n_save_localised_copy') targeting SilverStripe\Forms\FieldList::fieldByName() seems to always return null.

This check looks for function or method calls that always return null and whose return value is assigned to a variable.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
$object = $a->getObject();

The method getObject() can return nothing but null, so it makes no sense to assign that value to a variable.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
278
        $actionPublish = $majorActions->getChildren()->fieldByName('action_publish_localised_copy');
0 ignored issues
show
Bug introduced by
Are you sure the assignment to $actionPublish is correct as $majorActions->getChildr...ublish_localised_copy') targeting SilverStripe\Forms\FieldList::fieldByName() seems to always return null.

This check looks for function or method calls that always return null and whose return value is assigned to a variable.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
$object = $a->getObject();

The method getObject() can return nothing but null, so it makes no sense to assign that value to a variable.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
279
280
        $this->assertNotNull($actionSave);
281
        $this->assertNotNull($actionPublish);
282
283
        $this->assertEquals('Copy to draft', $actionSave->Title());
284
        $this->assertEquals('Copy & publish', $actionPublish->Title());
285
    }
286
287
    public function testUpdateCMSActionsDrafted()
288
    {
289
        /** @var Page|FluentSiteTreeExtension $page */
290
        $page = $this->objFromFixture(Page::class, 'about');
291
        // Make sure page is properly localised (including version records)
292
        $page->writeToStage(Versioned::DRAFT);
0 ignored issues
show
Bug introduced by
The method writeToStage() does not exist on TractorCow\Fluent\Extens...FluentSiteTreeExtension. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

292
        $page->/** @scrutinizer ignore-call */ 
293
               writeToStage(Versioned::DRAFT);

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
293
        $actions = $page->getCMSActions();
294
295
        /** @var CompositeField $majorActions */
296
        $majorActions = $actions->fieldByName('MajorActions');
297
298
        $this->assertNotNull($majorActions);
299
300
        $actionSave = $majorActions->getChildren()->fieldByName('action_save');
0 ignored issues
show
Bug introduced by
Are you sure the assignment to $actionSave is correct as $majorActions->getChildr...ldByName('action_save') targeting SilverStripe\Forms\FieldList::fieldByName() seems to always return null.

This check looks for function or method calls that always return null and whose return value is assigned to a variable.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
$object = $a->getObject();

The method getObject() can return nothing but null, so it makes no sense to assign that value to a variable.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
301
        $actionPublish = $majorActions->getChildren()->fieldByName('action_publish');
0 ignored issues
show
Bug introduced by
Are you sure the assignment to $actionPublish is correct as $majorActions->getChildr...yName('action_publish') targeting SilverStripe\Forms\FieldList::fieldByName() seems to always return null.

This check looks for function or method calls that always return null and whose return value is assigned to a variable.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
$object = $a->getObject();

The method getObject() can return nothing but null, so it makes no sense to assign that value to a variable.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
302
303
        $this->assertNotNull($actionSave);
304
        $this->assertNotNull($actionPublish);
305
306
        $this->assertEquals('Saved', $actionSave->Title());
307
        // The default value changed between SS 4.0 and 4.1 - assert it contains Publish instead of exact matching
308
        $this->assertContains('publish', strtolower($actionPublish->Title()));
309
    }
310
311
    /**
312
     * @param string $localeCode
313
     * @param string $fixture
314
     * @param string $expected
315
     * @dataProvider localePrefixUrlProvider
316
     */
317
    public function testAddLocalePrefixToUrlSegment(string $localeCode, string $fixture, string $expected)
318
    {
319
        FluentState::singleton()->withState(
320
            function (FluentState $newState) use ($localeCode, $fixture, $expected) {
321
                $newState
322
                    ->setLocale($localeCode)
323
                    ->setIsDomainMode(true);
324
325
                $fields = $this->objFromFixture(Page::class, $fixture)->getCMSFields();
326
327
                /** @var SiteTreeURLSegmentField $segmentField */
328
                $segmentField = $fields->fieldByName('Root.Main.URLSegment');
0 ignored issues
show
Bug introduced by
Are you sure the assignment to $segmentField is correct as $fields->fieldByName('Root.Main.URLSegment') targeting SilverStripe\Forms\FieldList::fieldByName() seems to always return null.

This check looks for function or method calls that always return null and whose return value is assigned to a variable.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
$object = $a->getObject();

The method getObject() can return nothing but null, so it makes no sense to assign that value to a variable.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
329
                $this->assertInstanceOf(SiteTreeURLSegmentField::class, $segmentField);
330
331
                $this->assertSame($expected, $segmentField->getURLPrefix());
332
            }
333
        );
334
    }
335
336
    public function testHomeVisibleOnFrontendBothConfigAny()
337
    {
338
        Config::modify()->set(DataObject::class, 'cms_localisation_required', FluentExtension::INHERITANCE_MODE_ANY);
339
        Config::modify()->set(DataObject::class, 'frontend_publish_required', FluentExtension::INHERITANCE_MODE_ANY);
340
341
        FluentState::singleton()->withState(function (FluentState $newState) {
342
            $newState
343
                ->setLocale('de_DE')
344
                ->setIsDomainMode(false)
345
                ->setIsFrontend(true);
346
347
            $page = Page::get()->filter('URLSegment', 'home')->first();
348
349
            $this->assertNotNull($page);
350
        });
351
    }
352
353
    public function testHomeVisibleOnFrontendOneConfigAny()
354
    {
355
        Config::modify()->set(DataObject::class, 'cms_localisation_required', FluentExtension::INHERITANCE_MODE_EXACT);
356
        Config::modify()->set(DataObject::class, 'frontend_publish_required', FluentExtension::INHERITANCE_MODE_ANY);
357
358
        FluentState::singleton()->withState(function (FluentState $newState) {
359
            $newState
360
                ->setLocale('de_DE')
361
                ->setIsDomainMode(false)
362
                ->setIsFrontend(true);
363
364
            $page = Page::get()->filter('URLSegment', 'home')->first();
365
366
            $this->assertNotNull($page);
367
        });
368
    }
369
370
    public function testHomeNotVisibleOnFrontendBothConfigExact()
371
    {
372
        Config::modify()->set(DataObject::class, 'cms_localisation_required', FluentExtension::INHERITANCE_MODE_EXACT);
373
        Config::modify()->set(DataObject::class, 'frontend_publish_required', FluentExtension::INHERITANCE_MODE_EXACT);
374
375
        FluentState::singleton()->withState(function (FluentState $newState) {
376
            $newState
377
                ->setLocale('de_DE')
378
                ->setIsDomainMode(false)
379
                ->setIsFrontend(true);
380
381
            $page = Page::get()->filter('URLSegment', 'home')->first();
382
383
            $this->assertNull($page);
384
        });
385
    }
386
387
    public function testHomeNotVisibleOnFrontendOneConfigExact()
388
    {
389
        Config::modify()->set(DataObject::class, 'cms_localisation_required', FluentExtension::INHERITANCE_MODE_ANY);
390
        Config::modify()->set(DataObject::class, 'frontend_publish_required', FluentExtension::INHERITANCE_MODE_EXACT);
391
392
        FluentState::singleton()->withState(function (FluentState $newState) {
393
            $newState
394
                ->setLocale('de_DE')
395
                ->setIsDomainMode(false)
396
                ->setIsFrontend(true);
397
398
            $page = Page::get()->filter('URLSegment', 'home')->first();
399
400
            $this->assertNull($page);
401
        });
402
    }
403
404
    public function testHomeVisibleInCMSBothConfigAny()
405
    {
406
        Config::modify()->set(DataObject::class, 'cms_localisation_required', FluentExtension::INHERITANCE_MODE_ANY);
407
        Config::modify()->set(DataObject::class, 'frontend_publish_required', FluentExtension::INHERITANCE_MODE_ANY);
408
409
        FluentState::singleton()->withState(function (FluentState $newState) {
410
            $newState
411
                ->setLocale('de_DE')
412
                ->setIsDomainMode(false)
413
                ->setIsFrontend(false);
414
415
            $page = Page::get()->filter('URLSegment', 'home')->first();
416
417
            $this->assertNotNull($page);
418
        });
419
    }
420
421
    public function testHomeVisibleInCMSOneConfigAny()
422
    {
423
        Config::modify()->set(DataObject::class, 'cms_localisation_required', FluentExtension::INHERITANCE_MODE_ANY);
424
        Config::modify()->set(DataObject::class, 'frontend_publish_required', FluentExtension::INHERITANCE_MODE_EXACT);
425
426
        FluentState::singleton()->withState(function (FluentState $newState) {
427
            $newState
428
                ->setLocale('de_DE')
429
                ->setIsDomainMode(false)
430
                ->setIsFrontend(false);
431
432
            $page = Page::get()->filter('URLSegment', 'home')->first();
433
434
            $this->assertNotNull($page);
435
        });
436
    }
437
438
    public function testHomeNotVisibleInCMSBothConfigExact()
439
    {
440
        Config::modify()->set(DataObject::class, 'cms_localisation_required', FluentExtension::INHERITANCE_MODE_EXACT);
441
        Config::modify()->set(DataObject::class, 'frontend_publish_required', FluentExtension::INHERITANCE_MODE_EXACT);
442
443
        FluentState::singleton()->withState(function (FluentState $newState) {
444
            $newState
445
                ->setLocale('de_DE')
446
                ->setIsDomainMode(false)
447
                ->setIsFrontend(false);
448
449
            $page = Page::get()->filter('URLSegment', 'home')->first();
450
451
            $this->assertNull($page);
452
        });
453
    }
454
455
    public function testHomeNotVisibleInCMSOneConfigExact()
456
    {
457
        Config::modify()->set(DataObject::class, 'cms_localisation_required', FluentExtension::INHERITANCE_MODE_EXACT);
458
        Config::modify()->set(DataObject::class, 'frontend_publish_required', FluentExtension::INHERITANCE_MODE_ANY);
459
460
        FluentState::singleton()->withState(function (FluentState $newState) {
461
            $newState
462
                ->setLocale('de_DE')
463
                ->setIsDomainMode(false)
464
                ->setIsFrontend(false);
465
466
            $page = Page::get()->filter('URLSegment', 'home')->first();
467
468
            $this->assertNull($page);
469
        });
470
    }
471
472
    /**
473
     * @return array[]
474
     */
475
    public function localePrefixUrlProvider()
476
    {
477
        return [
478
            'locale_with_domain'            => ['en_US', 'about', 'http://www.example.com/usa/'],
479
            'locale_without_domain'         => ['zh_CN', 'about', 'http://mocked/zh_CN/'],
480
            'locale_alone_on_domain_nested' => ['de_DE', 'staff', 'http://www.example.de/about-us/'],
481
        ];
482
    }
483
484
    /**
485
     * @param string|bool $cmsMode
486
     * @param string|bool $frontendMode
487
     * @param bool $isFrontend
488
     * @param int $expected
489
     * @throws ValidationException
490
     * @dataProvider localeFallbackProvider
491
     */
492
    public function testPageVisibilityWithFallback($cmsMode, $frontendMode, bool $isFrontend, int $expected)
493
    {
494
        Config::modify()
495
            ->set(DataObject::class, 'cms_localisation_required', $cmsMode)
496
            ->set(DataObject::class, 'frontend_publish_required', $frontendMode);
497
498
        $pageId = FluentState::singleton()->withState(function (FluentState $state): int {
499
            $state
500
                ->setLocale('en_NZ')
501
                ->setIsDomainMode(false);
502
503
            // Intentionally avoiding fixtures as this is easier to maintain
504
            $page = Page::create();
505
            $page->Title = 'fallback-test';
506
            $page->URLSegment = 'fallback-test';
507
            $page->write();
508
            $page->publishRecursive();
509
510
            return $page->ID;
511
        });
512
513
        FluentState::singleton()->withState(function (FluentState $state) use ($isFrontend, $pageId, $expected) {
514
            $state
515
                ->setLocale('en_GB')
516
                ->setIsDomainMode(false)
517
                ->setIsFrontend($isFrontend);
518
519
            $this->assertCount($expected, Page::get()->byIDs([$pageId]));
520
        });
521
    }
522
523
    public function localeFallbackProvider(): array
524
    {
525
        return [
526
            'Frontend / no inheritance' => [
527
                FluentExtension::INHERITANCE_MODE_EXACT,
528
                FluentExtension::INHERITANCE_MODE_EXACT,
529
                true,
530
                0,
531
            ],
532
            'Frontend / fallback inheritance' => [
533
                FluentExtension::INHERITANCE_MODE_EXACT,
534
                FluentExtension::INHERITANCE_MODE_FALLBACK,
535
                true,
536
                1,
537
            ],
538
            'Frontend / no inheritance (legacy)' => [
539
                true,
540
                true,
541
                true,
542
                0,
543
            ],
544
            'CMS / no inheritance' => [
545
                FluentExtension::INHERITANCE_MODE_EXACT,
546
                FluentExtension::INHERITANCE_MODE_EXACT,
547
                false,
548
                0,
549
            ],
550
            'CMS / fallback inheritance' => [
551
                FluentExtension::INHERITANCE_MODE_FALLBACK,
552
                FluentExtension::INHERITANCE_MODE_EXACT,
553
                false,
554
                1,
555
            ],
556
            'CMS / no inheritance (legacy)' => [
557
                true,
558
                true,
559
                false,
560
                0,
561
            ],
562
        ];
563
    }
564
}
565