Completed
Pull Request — master (#173)
by Robbie
01:58
created

SolrIndexTest::testSanitiseClassName()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 8
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
dl 0
loc 8
rs 9.4285
c 1
b 0
f 0
cc 1
eloc 5
nc 1
nop 0
1
<?php
2
3
namespace SilverStripe\FullTextSearch\Tests;
4
5
use SilverStripe\Core\Config\Config;
6
use SilverStripe\Core\Injector\Injector;
7
use SilverStripe\Core\Kernel;
8
use SilverStripe\Dev\SapphireTest;
9
use SilverStripe\FullTextSearch\Tests\SolrIndexTest\SolrIndexTest_AmbiguousRelationIndex;
10
use SilverStripe\FullTextSearch\Tests\SolrIndexTest\SolrIndexTest_AmbiguousRelationInheritedIndex;
11
use SilverStripe\FullTextSearch\Tests\SolrIndexTest\SolrIndexTest_FakeIndex;
12
use SilverStripe\FullTextSearch\Tests\SolrIndexTest\SolrIndexTest_FakeIndex2;
13
use SilverStripe\FullTextSearch\Tests\SolrIndexTest\SolrIndexTest_BoostedIndex;
14
use SilverStripe\FullTextSearch\Tests\SearchUpdaterTest\SearchUpdaterTest_Container;
15
use SilverStripe\FullTextSearch\Tests\SearchUpdaterTest\SearchUpdaterTest_HasOne;
16
use SilverStripe\FullTextSearch\Tests\SearchUpdaterTest\SearchUpdaterTest_HasMany;
17
use SilverStripe\FullTextSearch\Tests\SearchUpdaterTest\SearchUpdaterTest_ManyMany;
18
use SilverStripe\FullTextSearch\Tests\SearchUpdaterTest\SearchUpdaterTest_OtherContainer;
19
use SilverStripe\FullTextSearch\Search\Queries\SearchQuery;
20
use SilverStripe\FullTextSearch\Solr\Services\Solr3Service;
21
22
class SolrIndexTest extends SapphireTest
23
{
24 View Code Duplication
    public function testFieldDataHasOne()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
25
    {
26
        $index = new SolrIndexTest_FakeIndex();
27
        $data = $index->fieldData('HasOneObject.Field1');
28
29
        $data = $data[SearchUpdaterTest_Container::class . '_HasOneObject_Field1'];
30
31
        $this->assertEquals(SearchUpdaterTest_Container::class, $data['origin']);
32
        $this->assertEquals(SearchUpdaterTest_Container::class, $data['base']);
33
        $this->assertEquals(SearchUpdaterTest_HasOne::class, $data['class']);
34
    }
35
36 View Code Duplication
    public function testFieldDataHasMany()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
37
    {
38
        $index = new SolrIndexTest_FakeIndex();
39
        $data = $index->fieldData('HasManyObjects.Field1');
40
        $data = $data[SearchUpdaterTest_Container::class . '_HasManyObjects_Field1'];
41
42
        $this->assertEquals(SearchUpdaterTest_Container::class, $data['origin']);
43
        $this->assertEquals(SearchUpdaterTest_Container::class, $data['base']);
44
        $this->assertEquals(SearchUpdaterTest_HasMany::class, $data['class']);
45
    }
46
47 View Code Duplication
    public function testFieldDataManyMany()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
48
    {
49
        $index = new SolrIndexTest_FakeIndex();
50
        $data = $index->fieldData('ManyManyObjects.Field1');
51
        $data = $data[SearchUpdaterTest_Container::class . '_ManyManyObjects_Field1'];
52
53
        $this->assertEquals(SearchUpdaterTest_Container::class, $data['origin']);
54
        $this->assertEquals(SearchUpdaterTest_Container::class, $data['base']);
55
        $this->assertEquals(SearchUpdaterTest_ManyMany::class, $data['class']);
56
    }
57
58 View Code Duplication
    public function testFieldDataAmbiguousHasMany()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
59
    {
60
        $index = new SolrIndexTest_AmbiguousRelationIndex();
61
        $data = $index->fieldData('HasManyObjects.Field1');
62
63
        $this->assertArrayHasKey(SearchUpdaterTest_Container::class . '_HasManyObjects_Field1', $data);
64
        $this->assertArrayHasKey(SearchUpdaterTest_OtherContainer::class . '_HasManyObjects_Field1', $data);
65
66
        $dataContainer = $data[SearchUpdaterTest_Container::class . '_HasManyObjects_Field1'];
67
        $this->assertEquals(SearchUpdaterTest_Container::class, $dataContainer['origin']);
68
        $this->assertEquals(SearchUpdaterTest_Container::class, $dataContainer['base']);
69
        $this->assertEquals(SearchUpdaterTest_HasMany::class, $dataContainer['class']);
70
71
        $dataOtherContainer = $data[SearchUpdaterTest_OtherContainer::class . '_HasManyObjects_Field1'];
72
        $this->assertEquals(SearchUpdaterTest_OtherContainer::class, $dataOtherContainer['origin']);
73
        $this->assertEquals(SearchUpdaterTest_OtherContainer::class, $dataOtherContainer['base']);
74
        $this->assertEquals(SearchUpdaterTest_HasMany::class, $dataOtherContainer['class']);
75
    }
76
77 View Code Duplication
    public function testFieldDataAmbiguousManyMany()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
78
    {
79
        $index = new SolrIndexTest_AmbiguousRelationIndex();
80
        $data = $index->fieldData('ManyManyObjects.Field1');
81
82
        $this->assertArrayHasKey(SearchUpdaterTest_Container::class . '_ManyManyObjects_Field1', $data);
83
        $this->assertArrayHasKey(SearchUpdaterTest_OtherContainer::class . '_ManyManyObjects_Field1', $data);
84
85
        $dataContainer = $data[SearchUpdaterTest_Container::class . '_ManyManyObjects_Field1'];
86
        $this->assertEquals(SearchUpdaterTest_Container::class, $dataContainer['origin']);
87
        $this->assertEquals(SearchUpdaterTest_Container::class, $dataContainer['base']);
88
        $this->assertEquals(SearchUpdaterTest_ManyMany::class, $dataContainer['class']);
89
90
        $dataOtherContainer = $data[SearchUpdaterTest_OtherContainer::class . '_ManyManyObjects_Field1'];
91
        $this->assertEquals(SearchUpdaterTest_OtherContainer::class, $dataOtherContainer['origin']);
92
        $this->assertEquals(SearchUpdaterTest_OtherContainer::class, $dataOtherContainer['base']);
93
        $this->assertEquals(SearchUpdaterTest_ManyMany::class, $dataOtherContainer['class']);
94
    }
95
96 View Code Duplication
    public function testFieldDataAmbiguousManyManyInherited()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
97
    {
98
        $index = new SolrIndexTest_AmbiguousRelationInheritedIndex();
99
        $data = $index->fieldData('ManyManyObjects.Field1');
100
101
        $this->assertArrayHasKey(SearchUpdaterTest_Container::class . '_ManyManyObjects_Field1', $data);
102
        $this->assertArrayHasKey(SearchUpdaterTest_OtherContainer::class . '_ManyManyObjects_Field1', $data);
103
        $this->assertArrayNotHasKey(SearchUpdaterTest_ExtendedContainer::class . '_ManyManyObjects_Field1', $data);
104
105
        $dataContainer = $data[SearchUpdaterTest_Container::class . '_ManyManyObjects_Field1'];
106
        $this->assertEquals(SearchUpdaterTest_Container::class, $dataContainer['origin']);
107
        $this->assertEquals(SearchUpdaterTest_Container::class, $dataContainer['base']);
108
        $this->assertEquals(SearchUpdaterTest_ManyMany::class, $dataContainer['class']);
109
110
        $dataOtherContainer = $data[SearchUpdaterTest_OtherContainer::class . '_ManyManyObjects_Field1'];
111
        $this->assertEquals(SearchUpdaterTest_OtherContainer::class, $dataOtherContainer['origin']);
112
        $this->assertEquals(SearchUpdaterTest_OtherContainer::class, $dataOtherContainer['base']);
113
        $this->assertEquals(SearchUpdaterTest_ManyMany::class, $dataOtherContainer['class']);
114
    }
115
116
    /**
117
     * Test boosting on SearchQuery
118
     */
119
    public function testBoostedQuery()
120
    {
121
        /** @var Solr3Service|PHPUnit_Framework_MockObject_MockObject $serviceMock */
122
        $serviceMock = $this->getMockBuilder(Solr3Service::class)
123
            ->setMethods(['search'])
124
            ->getMock();
125
126
        $serviceMock->expects($this->once())
127
            ->method('search')
128
            ->with(
129
                $this->equalTo('+(Field1:term^1.5 OR HasOneObject_Field1:term^3)'),
130
                $this->anything(),
131
                $this->anything(),
132
                $this->anything(),
133
                $this->anything()
134
            )->willReturn($this->getFakeRawSolrResponse());
135
136
        $index = new SolrIndexTest_FakeIndex();
137
        $index->setService($serviceMock);
138
139
        $query = new SearchQuery();
140
        $query->search(
141
            'term',
142
            null,
143
            array('Field1' => 1.5, 'HasOneObject_Field1' => 3)
144
        );
145
        $index->search($query);
146
    }
147
148
    /**
149
     * Test boosting on field schema (via queried fields parameter)
150
     */
151
    public function testBoostedField()
152
    {
153
        /** @var Solr3Service|PHPUnit_Framework_MockObject_MockObject $serviceMock */
154
        $serviceMock = $this->getMockBuilder(Solr3Service::class)
155
            ->setMethods(['search'])
156
            ->getMock();
157
158
        $serviceMock->expects($this->once())
159
            ->method('search')
160
            ->with(
161
                $this->equalTo('+term'),
162
                $this->anything(),
163
                $this->anything(),
164
                $this->equalTo(['qf' => SearchUpdaterTest_Container::class . '_Field1^1.5 ' . SearchUpdaterTest_Container::class . '_Field2^2.1 _text',
165
                    'fq' => '+(_versionedstage:"" (*:* -_versionedstage:[* TO *]))']),
166
                $this->anything()
167
            )->willReturn($this->getFakeRawSolrResponse());
168
169
        $index = new SolrIndexTest_BoostedIndex();
170
        $index->setService($serviceMock);
171
172
        $query = new SearchQuery();
173
        $query->search('term');
174
        $index->search($query);
175
    }
176
177
    public function testHighlightQueryOnBoost()
178
    {
179
        /** @var SilverStripe\FullTextSearch\Solr\Services\Solr3Service|ObjectProphecy $serviceMock */
180
        $serviceMock = $this->getMockBuilder(Solr3Service::class)
181
            ->setMethods(['search'])
182
            ->getMock();
183
184
        $serviceMock->expects($this->exactly(2))
185
            ->method('search')
186
            ->withConsecutive(
187
                [
188
                    $this->equalTo('+(Field1:term^1.5 OR HasOneObject_Field1:term^3)'),
189
                    $this->anything(),
190
                    $this->anything(),
191
                    $this->logicalNot(
192
                        $this->arrayHasKey('hl.q')
193
                    ),
194
                    $this->anything()
195
                ],
196
                [
197
                    $this->equalTo('+(Field1:term^1.5 OR HasOneObject_Field1:term^3)'),
198
                    $this->anything(),
199
                    $this->anything(),
200
                    $this->arrayHasKey('hl.q'),
201
                    $this->anything()
202
                ]
203
            )->willReturn($this->getFakeRawSolrResponse());
204
205
        $index = new SolrIndexTest_FakeIndex();
206
        $index->setService($serviceMock);
207
208
        // Search without highlighting
209
        $query = new SearchQuery();
210
        $query->search(
211
            'term',
212
            null,
213
            array('Field1' => 1.5, 'HasOneObject_Field1' => 3)
214
        );
215
        $index->search($query);
216
217
        // Search with highlighting
218
        $query = new SearchQuery();
219
        $query->search(
220
            'term',
221
            null,
222
            array('Field1' => 1.5, 'HasOneObject_Field1' => 3)
223
        );
224
        $index->search($query, -1, -1, array('hl' => true));
225
    }
226
227
    public function testIndexExcludesNullValues()
228
    {
229
        /** @var Solr3Service|ObjectProphecy $serviceMock */
230
        $serviceMock = $this->createMock(Solr3Service::class);
231
        $index = new SolrIndexTest_FakeIndex();
232
        $index->setService($serviceMock);
233
        $obj = new SearchUpdaterTest_Container();
234
235
        $obj->Field1 = 'Field1 val';
0 ignored issues
show
Documentation introduced by
The property Field1 does not exist on object<SilverStripe\Full...hUpdaterTest_Container>. Since you implemented __set, maybe consider adding a @property annotation.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
236
        $obj->Field2 = null;
0 ignored issues
show
Documentation introduced by
The property Field2 does not exist on object<SilverStripe\Full...hUpdaterTest_Container>. Since you implemented __set, maybe consider adding a @property annotation.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
237
        $obj->MyDate = null;
0 ignored issues
show
Documentation introduced by
The property MyDate does not exist on object<SilverStripe\Full...hUpdaterTest_Container>. Since you implemented __set, maybe consider adding a @property annotation.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
238
        $docs = $index->add($obj);
239
        $value = $docs[0]->getField(SearchUpdaterTest_Container::class . '_Field1');
240
        $this->assertEquals('Field1 val', $value['value'], 'Writes non-NULL string fields');
241
        $value = $docs[0]->getField(SearchUpdaterTest_Container::class . '_Field2');
242
        $this->assertFalse($value, 'Ignores string fields if they are NULL');
243
        $value = $docs[0]->getField(SearchUpdaterTest_Container::class . '_MyDate');
244
        $this->assertFalse($value, 'Ignores date fields if they are NULL');
245
246
        $obj->MyDate = '2010-12-30';
0 ignored issues
show
Documentation introduced by
The property MyDate does not exist on object<SilverStripe\Full...hUpdaterTest_Container>. Since you implemented __set, maybe consider adding a @property annotation.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
247
        $docs = $index->add($obj);
248
        $value = $docs[0]->getField(SearchUpdaterTest_Container::class . '_MyDate');
249
        $this->assertEquals('2010-12-30T00:00:00Z', $value['value'], 'Writes non-NULL dates');
250
    }
251
252
    public function testAddFieldExtraOptions()
253
    {
254
        Injector::inst()->get(Kernel::class)->setEnvironment('live');
255
256
        $index = new SolrIndexTest_FakeIndex();
257
258
        $defs = simplexml_load_string('<fields>' . $index->getFieldDefinitions() . '</fields>');
259
        $defField1 = $defs->xpath('field[@name="' . SearchUpdaterTest_Container::class . '_Field1"]');
260
        $this->assertEquals((string)$defField1[0]['stored'], 'false');
261
262
        $index->addFilterField('Field1', null, array('stored' => 'true'));
263
        $defs = simplexml_load_string('<fields>' . $index->getFieldDefinitions() . '</fields>');
264
        $defField1 = $defs->xpath('field[@name="' . SearchUpdaterTest_Container::class . '_Field1"]');
265
        $this->assertEquals((string)$defField1[0]['stored'], 'true');
266
    }
267
268
    public function testAddAnalyzer()
269
    {
270
        $index = new SolrIndexTest_FakeIndex();
271
272
        $defs = simplexml_load_string('<fields>' . $index->getFieldDefinitions() . '</fields>');
273
        $defField1 = $defs->xpath('field[@name="' . SearchUpdaterTest_Container::class . '_Field1"]');
274
        $analyzers = $defField1[0]->analyzer;
275
        $this->assertFalse((bool)$analyzers);
276
277
        $index->addAnalyzer('Field1', 'charFilter', array('class' => 'solr.HTMLStripCharFilterFactory'));
278
        $defs = simplexml_load_string('<fields>' . $index->getFieldDefinitions() . '</fields>');
279
        $defField1 = $defs->xpath('field[@name="' . SearchUpdaterTest_Container::class . '_Field1"]');
280
        $analyzers = $defField1[0]->analyzer;
281
        $this->assertTrue((bool)$analyzers);
282
        $this->assertEquals('solr.HTMLStripCharFilterFactory', $analyzers[0]->charFilter[0]['class']);
283
    }
284
285
    public function testAddCopyField()
286
    {
287
        $index = new SolrIndexTest_FakeIndex();
288
        $index->addCopyField('sourceField', 'destField');
289
290
        $defs = simplexml_load_string('<fields>' . $index->getCopyFieldDefinitions() . '</fields>');
291
        $copyField = $defs->xpath('copyField');
292
293
        $this->assertEquals('sourceField', $copyField[0]['source']);
294
        $this->assertEquals('destField', $copyField[0]['dest']);
295
    }
296
297
    /**
298
     * Tests the setting of the 'stored' flag
299
     */
300
    public function testStoredFields()
301
    {
302
        // Test two fields
303
        $index = new SolrIndexTest_FakeIndex2();
304
        $index->addStoredField('Field1');
305
        $index->addFulltextField('Field2');
306
        $schema = $index->getFieldDefinitions();
307
        $this->assertContains(
308
            "<field name='" . SearchUpdaterTest_Container::class . "_Field1' type='text' indexed='true' stored='true'",
309
            $schema
310
        );
311
        $this->assertContains(
312
            "<field name='" . SearchUpdaterTest_Container::class . "_Field2' type='text' indexed='true' stored='false'",
313
            $schema
314
        );
315
316
        // Test with addAllFulltextFields
317
        $index2 = new SolrIndexTest_FakeIndex2();
318
        $index2->addAllFulltextFields();
319
        $index2->addStoredField('Field2');
320
        $schema2 = $index2->getFieldDefinitions();
321
        $this->assertContains(
322
            "<field name='" . SearchUpdaterTest_Container::class . "_Field1' type='text' indexed='true' stored='false'",
323
            $schema2
324
        );
325
        $this->assertContains(
326
            "<field name='" . SearchUpdaterTest_Container::class . "_Field2' type='text' indexed='true' stored='true'",
327
            $schema2
328
        );
329
    }
330
331
    public function testSanitiseClassName()
332
    {
333
        $index = new SolrIndexTest_FakeIndex2;
334
        $this->assertSame(
335
            'SilverStripe\\\\FullTextSearch\\\\Tests\\\\SolrIndexTest',
336
            $index->sanitiseClassName(static::class)
337
        );
338
    }
339
340
    protected function getFakeRawSolrResponse()
341
    {
342
        return new \Apache_Solr_Response(
343
            new \Apache_Solr_HttpTransport_Response(
344
                null,
345
                null,
346
                '{}'
347
            )
348
        );
349
    }
350
}
351