ZZZSearchFormTest   A
last analyzed

Complexity

Total Complexity 29

Size/Duplication

Total Lines 366
Duplicated Lines 0 %

Importance

Changes 2
Bugs 0 Features 0
Metric Value
eloc 208
c 2
b 0
f 0
dl 0
loc 366
rs 10
wmc 29

14 Methods

Rating   Name   Duplication   Size   Complexity  
A setUpBeforeClass() 0 10 1
A testDisabledShowInSearchFlagNotIncludedForSiteTree() 0 17 2
A setUp() 0 9 1
A waitUntilIndexingFinished() 0 5 2
A testPublishedPagesMatchedByTitle() 0 22 2
A testDoubleQuotesPublishedPagesMatchedByTitle() 0 23 2
A checkFulltextSupport() 0 12 4
A testPagesRestrictedToSpecificGroupNotIncluded() 0 40 2
A testUnpublishedPagesNotIncluded() 0 17 2
A testSearchFormTemplateCanBeChanged() 0 13 2
A testPagesRestrictedToLoggedinUsersNotIncluded() 0 30 2
A testInheritedRestrictedPagesNotIncluded() 0 30 1
A testDisabledShowInSearchFlagNotIncludedForFiles() 0 35 2
A testSearchTitleAndContentWithSpecialCharacters() 0 36 4
1
<?php
2
3
namespace SilverStripe\CMS\Tests\Search;
4
5
use SilverStripe\Assets\File;
6
use SilverStripe\CMS\Controllers\ContentController;
7
use SilverStripe\CMS\Controllers\ModelAsController;
8
use SilverStripe\CMS\Model\SiteTree;
9
use SilverStripe\CMS\Search\SearchForm;
10
use SilverStripe\Control\HTTPRequest;
11
use SilverStripe\Core\Config\Config;
12
use SilverStripe\Dev\FunctionalTest;
13
use SilverStripe\MSSQL\MSSQLDatabase;
0 ignored issues
show
Bug introduced by
The type SilverStripe\MSSQL\MSSQLDatabase 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...
14
use SilverStripe\ORM\DB;
15
use SilverStripe\ORM\Search\FulltextSearchable;
16
use SilverStripe\PostgreSQL\PostgreSQLDatabase;
0 ignored issues
show
Bug introduced by
The type SilverStripe\PostgreSQL\PostgreSQLDatabase 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...
17
use SilverStripe\Security\Member;
18
use SilverStripe\Security\Security;
19
use SilverStripe\Subsites\Extensions\SiteTreeSubsites;
0 ignored issues
show
Bug introduced by
The type SilverStripe\Subsites\Extensions\SiteTreeSubsites 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...
20
use SilverStripe\Versioned\Versioned;
21
use TractorCow\Fluent\Extension\FluentSiteTreeExtension;
0 ignored issues
show
Bug introduced by
The type TractorCow\Fluent\Extens...FluentSiteTreeExtension 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...
22
23
/**
24
 * @todo Fix unpublished pages check in testPublishedPagesMatchedByTitle()
25
 * @todo All tests run on unpublished pages at the moment, due to the searchform not distinguishing between them
26
 *
27
 * Because this manipulates the test database in severe ways, I've renamed the test to force it to run last...
28
 */
29
class ZZZSearchFormTest extends FunctionalTest
30
{
31
    protected static $fixture_file = 'SearchFormTest.yml';
32
33
    protected static $illegal_extensions = [
34
        SiteTree::class => [
35
            SiteTreeSubsites::class,
36
            FluentSiteTreeExtension::class,
37
        ],
38
    ];
39
40
    /**
41
     * @var ContentController
42
     */
43
    protected $mockController;
44
45
    public function waitUntilIndexingFinished()
46
    {
47
        $schema = DB::get_schema();
48
        if (method_exists($schema, 'waitUntilIndexingFinished')) {
49
            $schema->waitUntilIndexingFinished();
50
        }
51
    }
52
53
    public static function setUpBeforeClass() : void
54
    {
55
        // HACK Postgres doesn't refresh TSearch indexes when the schema changes after CREATE TABLE
56
        // MySQL will need a different table type
57
        static::$tempDB->kill();
58
        Config::modify();
59
        FulltextSearchable::enable();
60
        static::$tempDB->build();
61
        static::resetDBSchema(true);
62
        parent::setUpBeforeClass();
63
    }
64
65
    protected function setUp() : void
66
    {
67
        parent::setUp();
68
69
        /** @var Page $holderPage */
70
        $holderPage = $this->objFromFixture(SiteTree::class, 'searchformholder');
71
        $this->mockController = ModelAsController::controller_for($holderPage);
72
73
        $this->waitUntilIndexingFinished();
74
    }
75
76
    /**
77
     * @return Boolean
78
     */
79
    protected function checkFulltextSupport()
80
    {
81
        $conn = DB::get_conn();
82
        if (class_exists(MSSQLDatabase::class) && $conn instanceof MSSQLDatabase) {
83
            $supports = $conn->fullTextEnabled();
0 ignored issues
show
Bug introduced by
The method fullTextEnabled() does not exist on SilverStripe\ORM\Connect\Database. ( Ignorable by Annotation )

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

83
            /** @scrutinizer ignore-call */ 
84
            $supports = $conn->fullTextEnabled();

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...
84
        } else {
85
            $supports = true;
86
        }
87
        if (!$supports) {
88
            $this->markTestSkipped('Fulltext not supported by DB driver or setup');
89
        }
90
        return $supports;
91
    }
92
93
    /**
94
     * @skipUpgrade
95
     */
96
    public function testSearchFormTemplateCanBeChanged()
97
    {
98
        if (!$this->checkFulltextSupport()) {
99
            return;
100
        }
101
102
        $sf = new SearchForm($this->mockController);
103
104
        $sf->setTemplate('BlankPage');
105
106
        $this->assertStringContainsString(
107
            '<body class="SearchForm Form BlankPage">',
108
            $sf->forTemplate()
109
        );
110
    }
111
112
    /**
113
     * @skipUpgrade
114
     */
115
    public function testPublishedPagesMatchedByTitle()
116
    {
117
        if (!$this->checkFulltextSupport()) {
118
            return;
119
        }
120
121
        $request = new HTTPRequest('GET', 'search', ['Search' => 'publicPublishedPage']);
122
        $request->setSession($this->session());
123
        $this->mockController->setRequest($request);
124
        $sf = new SearchForm($this->mockController);
125
126
        /** @var SiteTree $publishedPage */
127
        $publishedPage = $this->objFromFixture(SiteTree::class, 'publicPublishedPage');
128
        $publishedPage->copyVersionToStage(Versioned::DRAFT, Versioned::LIVE);
129
130
        $this->waitUntilIndexingFinished();
131
132
        $results = $sf->getResults();
133
        $this->assertContains(
134
            $publishedPage->ID,
135
            $results->column('ID'),
136
            'Published pages are found by searchform'
137
        );
138
    }
139
140
    /**
141
     * @skipUpgrade
142
     */
143
    public function testDoubleQuotesPublishedPagesMatchedByTitle()
144
    {
145
        if (!$this->checkFulltextSupport()) {
146
            return;
147
        }
148
149
        $request = new HTTPRequest('GET', 'search', ['Search' => '"finding butterflies"']);
150
        $request->setSession($this->session());
151
        $this->mockController->setRequest($request);
152
        $sf = new SearchForm($this->mockController);
153
154
        /** @var SiteTree $publishedPage */
155
        $publishedPage = $this->objFromFixture(SiteTree::class, 'publicPublishedPage');
156
        $publishedPage->Title = "finding butterflies";
157
        $publishedPage->write();
158
        $publishedPage->copyVersionToStage(Versioned::DRAFT, Versioned::LIVE);
159
160
        $this->waitUntilIndexingFinished();
161
        $results = $sf->getResults();
162
        $this->assertContains(
163
            $publishedPage->ID,
164
            $results->column('ID'),
165
            'Published pages are found by searchform'
166
        );
167
    }
168
169
    /**
170
     * @skipUpgrade
171
     */
172
    public function testUnpublishedPagesNotIncluded()
173
    {
174
        if (!$this->checkFulltextSupport()) {
175
            return;
176
        }
177
178
        $request = new HTTPRequest('GET', 'search', ['Search' => 'publicUnpublishedPage']);
179
        $request->setSession($this->session());
180
        $this->mockController->setRequest($request);
181
        $sf = new SearchForm($this->mockController);
182
183
        $results = $sf->getResults();
184
        $unpublishedPage = $this->objFromFixture(SiteTree::class, 'publicUnpublishedPage');
185
        $this->assertNotContains(
186
            $unpublishedPage->ID,
187
            $results->column('ID'),
188
            'Unpublished pages are not found by searchform'
189
        );
190
    }
191
192
    public function testPagesRestrictedToLoggedinUsersNotIncluded()
193
    {
194
        if (!$this->checkFulltextSupport()) {
195
            return;
196
        }
197
198
        $request = new HTTPRequest('GET', 'search', ['Search' => 'restrictedViewLoggedInUsers']);
199
        $request->setSession($this->session());
200
        $this->mockController->setRequest($request);
201
        $sf = new SearchForm($this->mockController);
202
203
        /** @var SiteTree $page */
204
        $page = $this->objFromFixture(SiteTree::class, 'restrictedViewLoggedInUsers');
205
        $page->copyVersionToStage(Versioned::DRAFT, Versioned::LIVE);
206
        $results = $sf->getResults();
207
        $this->assertNotContains(
208
            $page->ID,
209
            $results->column('ID'),
210
            'Page with "Restrict to logged in users" doesnt show without valid login'
211
        );
212
213
        $member = $this->objFromFixture(Member::class, 'randomuser');
214
        Security::setCurrentUser($member);
215
        $results = $sf->getResults();
216
        $this->assertContains(
217
            $page->ID,
218
            $results->column('ID'),
219
            'Page with "Restrict to logged in users" shows if login is present'
220
        );
221
        Security::setCurrentUser(null);
222
    }
223
224
    public function testPagesRestrictedToSpecificGroupNotIncluded()
225
    {
226
        if (!$this->checkFulltextSupport()) {
227
            return;
228
        }
229
230
        $request = new HTTPRequest('GET', 'search', ['Search' => 'restrictedViewOnlyWebsiteUsers']);
231
        $request->setSession($this->session());
232
        $this->mockController->setRequest($request);
233
        $sf = new SearchForm($this->mockController);
234
235
        /** @var SiteTree $page */
236
        $page = $this->objFromFixture(SiteTree::class, 'restrictedViewOnlyWebsiteUsers');
237
        $page->copyVersionToStage(Versioned::DRAFT, Versioned::LIVE);
238
        $results = $sf->getResults();
239
        $this->assertNotContains(
240
            $page->ID,
241
            $results->column('ID'),
242
            'Page with "Restrict to these users" doesnt show without valid login'
243
        );
244
245
        $member = $this->objFromFixture(Member::class, 'randomuser');
246
        Security::setCurrentUser($member);
247
        $results = $sf->getResults();
248
        $this->assertNotContains(
249
            $page->ID,
250
            $results->column('ID'),
251
            'Page with "Restrict to these users" doesnt show if logged in user is not in the right group'
252
        );
253
        Security::setCurrentUser(null);
254
255
        $member = $this->objFromFixture(Member::class, 'websiteuser');
256
        Security::setCurrentUser($member);
257
        $results = $sf->getResults();
258
        $this->assertContains(
259
            $page->ID,
260
            $results->column('ID'),
261
            'Page with "Restrict to these users" shows if user in this group is logged in'
262
        );
263
        Security::setCurrentUser(null);
264
    }
265
266
    /**
267
     *
268
     */
269
    public function testInheritedRestrictedPagesNotIncluded()
270
    {
271
        $request = new HTTPRequest('GET', 'search', ['Search' => 'inheritRestrictedView']);
272
        $request->setSession($this->session());
273
        $this->mockController->setRequest($request);
274
        $sf = new SearchForm($this->mockController);
275
276
        /** @var SiteTree $parent */
277
        $parent = $this->objFromFixture(SiteTree::class, 'restrictedViewLoggedInUsers');
278
        $parent->copyVersionToStage(Versioned::DRAFT, Versioned::LIVE);
279
280
        /** @var SiteTree $page */
281
        $page = $this->objFromFixture(SiteTree::class, 'inheritRestrictedView');
282
        $page->copyVersionToStage(Versioned::DRAFT, Versioned::LIVE);
283
        $results = $sf->getResults();
284
        $this->assertNotContains(
285
            $page->ID,
286
            $results->column('ID'),
287
            'Page inheriting "Restrict to loggedin users" doesnt show without valid login'
288
        );
289
290
        $member = $this->objFromFixture(Member::class, 'websiteuser');
291
        Security::setCurrentUser($member);
292
        $results = $sf->getResults();
293
        $this->assertContains(
294
            $page->ID,
295
            $results->column('ID'),
296
            'Page inheriting "Restrict to loggedin users" shows if user in this group is logged in'
297
        );
298
        Security::setCurrentUser(null);
299
    }
300
301
    public function testDisabledShowInSearchFlagNotIncludedForSiteTree()
302
    {
303
        if (!$this->checkFulltextSupport()) {
304
            return;
305
        }
306
307
        $request = new HTTPRequest('GET', 'search', ['Search' => 'dontShowInSearchPage']);
308
        $request->setSession($this->session());
309
        $this->mockController->setRequest($request);
310
        $sf = new SearchForm($this->mockController);
311
312
        $page = $this->objFromFixture(SiteTree::class, 'dontShowInSearchPage');
313
        $results = $sf->getResults();
314
        $this->assertNotContains(
315
            $page->ID,
316
            $results->column('ID'),
317
            'Page with "Show in Search" disabled does not show'
318
        );
319
    }
320
321
    public function testDisabledShowInSearchFlagNotIncludedForFiles()
322
    {
323
        if (!$this->checkFulltextSupport()) {
324
            return;
325
        }
326
327
        $request = new HTTPRequest('GET', 'search', ['Search' => 'dontShowInSearchFile']);
328
        $request->setSession($this->session());
329
        $this->mockController->setRequest($request);
330
        $sf = new SearchForm($this->mockController);
331
332
        /** @var File $dontShowInSearchFile */
333
        $dontShowInSearchFile = $this->objFromFixture(File::class, 'dontShowInSearchFile');
334
        $dontShowInSearchFile->copyVersionToStage(Versioned::DRAFT, Versioned::LIVE);
335
        /** @var File $showInSearchFile */
336
        $showInSearchFile = $this->objFromFixture(File::class, 'showInSearchFile');
337
        $showInSearchFile->copyVersionToStage(Versioned::DRAFT, Versioned::LIVE);
338
339
        $results = $sf->getResults();
340
        $this->assertNotContains(
341
            $dontShowInSearchFile->ID,
342
            $results->column('ID'),
343
            'File with "Show in Search" disabled doesnt show'
344
        );
345
346
        // Check ShowInSearch=1 can be found
347
        $request = new HTTPRequest('GET', 'search', ['Search' => 'showInSearchFile']);
348
        $request->setSession($this->session());
349
        $this->mockController->setRequest($request);
350
        $sf = new SearchForm($this->mockController);
351
        $results = $sf->getResults();
352
        $this->assertContains(
353
            $showInSearchFile->ID,
354
            $results->column('ID'),
355
            'File with "Show in Search" enabled can be found'
356
        );
357
    }
358
359
    public function testSearchTitleAndContentWithSpecialCharacters()
360
    {
361
        if (!$this->checkFulltextSupport()) {
362
            return;
363
        }
364
365
        if (class_exists(PostgreSQLDatabase::class) && DB::get_conn() instanceof PostgreSQLDatabase) {
366
            $this->markTestSkipped("PostgreSQLDatabase doesn't support entity-encoded searches");
367
        }
368
369
        $request = new HTTPRequest('GET', 'search', ['Search' => 'Brötchen']);
370
        $request->setSession($this->session());
371
        $this->mockController->setRequest($request);
372
        $sf = new SearchForm($this->mockController);
373
374
        /** @var SiteTree $pageWithSpecialChars */
375
        $pageWithSpecialChars = $this->objFromFixture(SiteTree::class, 'pageWithSpecialChars');
376
        $pageWithSpecialChars->copyVersionToStage(Versioned::DRAFT, Versioned::LIVE);
377
378
        $results = $sf->getResults();
379
        $this->assertContains(
380
            $pageWithSpecialChars->ID,
381
            $results->column('ID'),
382
            'Published pages with umlauts in title are found'
383
        );
384
385
        // Check another word
386
        $request = new HTTPRequest('GET', 'search', ['Search' => 'Bäcker']);
387
        $request->setSession($this->session());
388
        $this->mockController->setRequest($request);
389
        $sf = new SearchForm($this->mockController);
390
        $results = $sf->getResults();
391
        $this->assertContains(
392
            $pageWithSpecialChars->ID,
393
            $results->column('ID'),
394
            'Published pages with htmlencoded umlauts in content are found'
395
        );
396
    }
397
}
398