Completed
Pull Request — master (#106)
by
unknown
03:26
created

TagFieldTest   A

Complexity

Total Complexity 15

Size/Duplication

Total Lines 335
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
wmc 15
dl 0
loc 335
c 0
b 0
f 0
rs 10

15 Methods

Rating   Name   Duplication   Size   Complexity  
A testSaveEmptySource() 0 20 1
A testItSavesLinksToNewTagsOnExistingRecords() 0 12 1
A compareTagLists() 0 9 1
A testItSavesLinksToExistingTagsOnNewRecords() 0 13 1
A compareExpectedAndActualTags() 0 3 1
A testItSavesLinksToNewTagsOnNewRecords() 0 10 1
A getNewRequest() 0 6 1
A testItIgnoresNewTagsIfCannotCreate() 0 23 1
A testItDisplaysValuesFromRelations() 0 21 1
B testRestrictedSuggestions() 0 33 1
B testItSuggestsTags() 0 42 1
A testReadonlyTransformation() 0 5 1
A getNewTagFieldTestBlogPost() 0 5 1
B testSaveDuplicateTags() 0 34 1
A testItSavesLinksToExistingTagsOnExistingRecords() 0 12 1
1
<?php
2
3
namespace SilverStripe\TagField\Tests;
4
5
use SilverStripe\Control\HTTPRequest;
6
use SilverStripe\Dev\SapphireTest;
7
use SilverStripe\Dev\TestOnly;
8
use SilverStripe\Forms\FieldList;
9
use SilverStripe\Forms\Form;
10
use SilverStripe\ORM\ArrayList;
11
use SilverStripe\ORM\DataList;
12
use SilverStripe\ORM\DataObject;
13
use SilverStripe\TagField\ReadonlyTagField;
14
use SilverStripe\TagField\TagField;
15
use SilverStripe\TagField\Tests\Stub\TagFieldTestBlogPost;
16
use SilverStripe\TagField\Tests\Stub\TagFieldTestBlogTag;
17
use SilverStripe\TagField\Tests\Stub\TagFieldTestController;
18
use SilverStripe\View\ArrayData;
19
20
/**
21
 * @mixin PHPUnit_Framework_TestCase
22
 */
23
class TagFieldTest extends SapphireTest
24
{
25
    /**
26
     * @var string
27
     */
28
    protected static $fixture_file = 'TagFieldTest.yml';
29
30
    /**
31
     * @var array
32
     */
33
    protected static $extra_dataobjects = [
34
        TagFieldTestBlogTag::class,
35
        TagFieldTestBlogPost::class,
36
    ];
37
38
    public function testItSavesLinksToNewTagsOnNewRecords()
39
    {
40
        $record = $this->getNewTagFieldTestBlogPost('BlogPost1');
41
        $field = new TagField('Tags', '', new DataList(TagFieldTestBlogTag::class));
42
        $field->setValue(array('Tag3', 'Tag4'));
43
        $field->saveInto($record);
44
        $record->write();
45
        $this->compareExpectedAndActualTags(
46
            array('Tag3', 'Tag4'),
47
            $record
48
        );
49
    }
50
51
    /**
52
     * @param string $name
53
     *
54
     * @return TagFieldTestBlogPost
55
     */
56
    protected function getNewTagFieldTestBlogPost($name)
57
    {
58
        return $this->objFromFixture(
59
            TagFieldTestBlogPost::class,
60
            $name
61
        );
62
    }
63
64
    /**
65
     * @param array $expected
66
     * @param TagFieldTestBlogPost $record
67
     */
68
    protected function compareExpectedAndActualTags(array $expected, TagFieldTestBlogPost $record)
69
    {
70
        $this->compareTagLists($expected, $record->Tags());
0 ignored issues
show
Bug introduced by
The method Tags() does not exist on SilverStripe\TagField\Te...ub\TagFieldTestBlogPost. Since you implemented __call, consider adding a @method annotation. ( Ignorable by Annotation )

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

70
        $this->compareTagLists($expected, $record->/** @scrutinizer ignore-call */ Tags());
Loading history...
71
    }
72
73
    /**
74
     * Ensure a source of tags matches the given string tag names
75
     *
76
     * @param array $expected
77
     * @param DataList $actualSource
78
     */
79
    protected function compareTagLists(array $expected, DataList $actualSource)
80
    {
81
        $actual = array_values($actualSource->map('ID', 'Title')->toArray());
82
        sort($expected);
83
        sort($actual);
84
85
        $this->assertEquals(
86
            $expected,
87
            $actual
88
        );
89
    }
90
91
    public function testItSavesLinksToNewTagsOnExistingRecords()
92
    {
93
        $record = $this->getNewTagFieldTestBlogPost('BlogPost1');
94
        $record->write();
95
96
        $field = new TagField('Tags', '', new DataList(TagFieldTestBlogTag::class));
97
        $field->setValue(array('Tag3', 'Tag4'));
98
        $field->saveInto($record);
99
100
        $this->compareExpectedAndActualTags(
101
            array('Tag3', 'Tag4'),
102
            $record
103
        );
104
    }
105
106
    public function testItSavesLinksToExistingTagsOnNewRecords()
107
    {
108
        $record = $this->getNewTagFieldTestBlogPost('BlogPost1');
109
110
        $field = new TagField('Tags', '', new DataList(TagFieldTestBlogTag::class));
111
        $field->setValue(array('Tag1', 'Tag2'));
112
        $field->saveInto($record);
113
114
        $record->write();
115
116
        $this->compareExpectedAndActualTags(
117
            array('Tag1', 'Tag2'),
118
            $record
119
        );
120
    }
121
122
    public function testItSavesLinksToExistingTagsOnExistingRecords()
123
    {
124
        $record = $this->getNewTagFieldTestBlogPost('BlogPost1');
125
        $record->write();
126
127
        $field = new TagField('Tags', '', new DataList(TagFieldTestBlogTag::class));
128
        $field->setValue(array('Tag1', 'Tag2'));
129
        $field->saveInto($record);
130
131
        $this->compareExpectedAndActualTags(
132
            array('Tag1', 'Tag2'),
133
            $record
134
        );
135
    }
136
137
    /**
138
     * Ensure that {@see TagField::saveInto} respects existing tags
139
     */
140
    public function testSaveDuplicateTags()
141
    {
142
        $record = $this->getNewTagFieldTestBlogPost('BlogPost2');
143
        $record->write();
144
        $tag2ID = $this->idFromFixture(TagFieldTestBlogTag::class, 'Tag2');
145
146
        // Check tags before write
147
        $this->compareExpectedAndActualTags(
148
            array('Tag1', '222'),
149
            $record
150
        );
151
        $this->compareTagLists(
152
            array('Tag1', '222'),
153
            TagFieldTestBlogTag::get()
154
        );
155
        $this->assertContains($tag2ID, TagFieldTestBlogTag::get()->column('ID'));
156
157
        // Write new tags
158
        $field = new TagField('Tags', '', new DataList(TagFieldTestBlogTag::class));
159
        $field->setValue(array('222', 'Tag3'));
160
        $field->saveInto($record);
161
162
        // Check only one new tag was added
163
        $this->compareExpectedAndActualTags(
164
            array('222', 'Tag3'),
165
            $record
166
        );
167
168
        // Ensure that only one new dataobject was added and that tag2s id has not changed
169
        $this->compareTagLists(
170
            array('Tag1', '222', 'Tag3'),
171
            TagFieldTestBlogTag::get()
172
        );
173
        $this->assertContains($tag2ID, TagFieldTestBlogTag::get()->column('ID'));
174
    }
175
176
    public function testItSuggestsTags()
177
    {
178
        $field = new TagField('Tags', '', new DataList(TagFieldTestBlogTag::class));
179
180
        /**
181
         * Partial tag title match.
182
         */
183
        $request = $this->getNewRequest(array('term' => 'Tag'));
184
185
        $this->assertEquals(
186
            '{"items":[{"id":"Tag1","text":"Tag1"}]}',
187
            $field->suggest($request)->getBody()
188
        );
189
190
        /**
191
         * Exact tag title match.
192
         */
193
        $request = $this->getNewRequest(array('term' => '222'));
194
195
        $this->assertEquals(
196
            '{"items":[{"id":"222","text":"222"}]}',
197
            $field->suggest($request)->getBody()
198
        );
199
200
        /**
201
         * Case-insensitive tag title match.
202
         */
203
        $request = $this->getNewRequest(array('term' => 'TAG1'));
204
205
        $this->assertEquals(
206
            '{"items":[{"id":"Tag1","text":"Tag1"}]}',
207
            $field->suggest($request)->getBody()
208
        );
209
210
        /**
211
         * No tag title match.
212
         */
213
        $request = $this->getNewRequest(array('term' => 'unknown'));
214
215
        $this->assertEquals(
216
            '{"items":[]}',
217
            $field->suggest($request)->getBody()
218
        );
219
    }
220
221
    /**
222
     * Tests that TagField supports pre-filtered data sources
223
     */
224
    public function testRestrictedSuggestions()
225
    {
226
        $source = TagFieldTestBlogTag::get()->exclude('Title', 'Tag2');
227
        $field = new TagField('Tags', '', $source);
228
229
        /**
230
         * Partial tag title match.
231
         */
232
        $request = $this->getNewRequest(array('term' => 'Tag'));
233
234
        $this->assertEquals(
235
            '{"items":[{"id":"Tag1","text":"Tag1"}]}',
236
            $field->suggest($request)->getBody()
237
        );
238
239
        /**
240
         * Exact tag title match.
241
         */
242
        $request = $this->getNewRequest(array('term' => 'Tag1'));
243
244
        $this->assertEquals(
245
            '{"items":[{"id":"Tag1","text":"Tag1"}]}',
246
            $field->suggest($request)->getBody()
247
        );
248
249
        /**
250
         * Excluded item doesn't appear in matches
251
         */
252
        $request = $this->getNewRequest(array('term' => 'Tag2'));
253
254
        $this->assertEquals(
255
            '{"items":[]}',
256
            $field->suggest($request)->getBody()
257
        );
258
    }
259
260
    /**
261
     * @param array $parameters
262
     *
263
     * @return HTTPRequest
264
     */
265
    protected function getNewRequest(array $parameters)
266
    {
267
        return new HTTPRequest(
268
            'get',
269
            'TagFieldTestController/TagFieldTestForm/fields/Tags/suggest',
270
            $parameters
271
        );
272
    }
273
274
    public function testItDisplaysValuesFromRelations()
275
    {
276
        $record = $this->getNewTagFieldTestBlogPost('BlogPost1');
277
        $record->write();
278
279
        $form = new Form(
280
            new TagFieldTestController($record),
0 ignored issues
show
Unused Code introduced by
The call to SilverStripe\TagField\Te...ntroller::__construct() has too many arguments starting with $record. ( Ignorable by Annotation )

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

280
            /** @scrutinizer ignore-call */ 
281
            new TagFieldTestController($record),

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above.

Loading history...
281
            'Form',
282
            new FieldList(
283
                $field = new TagField('Tags', '', new DataList(TagFieldTestBlogTag::class))
284
            ),
285
            new FieldList()
286
        );
287
288
        $form->loadDataFrom(
289
            $this->objFromFixture(TagFieldTestBlogPost::class, 'BlogPost2')
290
        );
291
292
        $ids = TagFieldTestBlogTag::get()->column('Title');
293
294
        $this->assertEquals($field->Value(), $ids);
295
    }
296
297
    public function testItIgnoresNewTagsIfCannotCreate()
298
    {
299
        $this->markTestSkipped(
300
            'This test has not been updated yet.'
301
        );
302
303
        $record = new TagFieldTestBlogPost();
304
        $record->write();
305
306
        $tag = TagFieldTestBlogTag::get()->filter('Title', 'Tag1')->first();
307
308
        $field = new TagField('Tags', '', new DataList(TagFieldTestBlogTag::class), array($tag->Title, 'Tag3'));
309
        $field->setCanCreate(false);
310
        $field->saveInto($record);
311
312
        /**
313
         * @var TagFieldTestBlogPost $record
314
         */
315
        $record = DataObject::get_by_id(TagFieldTestBlogPost::class, $record->ID);
316
317
        $this->compareExpectedAndActualTags(
318
            array('Tag1'),
319
            $record
320
        );
321
    }
322
323
    /**
324
     * Test you can save without a source set
325
     */
326
    public function testSaveEmptySource()
327
    {
328
        $record = new TagFieldTestBlogPost();
329
        $record->write();
330
331
        // Clear database of tags
332
        TagFieldTestBlogTag::get()->removeAll();
333
334
        $field = new TagField('Tags', '', TagFieldTestBlogTag::get());
335
        $field->setValue(['New Tag']);
336
        $field->setCanCreate(true);
337
        $field->saveInto($record);
338
339
        $tag = TagFieldTestBlogTag::get()->first();
340
        $this->assertNotEmpty($tag);
341
        $this->assertEquals('New Tag', $tag->Title);
342
        $record = TagFieldTestBlogPost::get()->byID($record->ID);
343
        $this->assertEquals(
344
            $tag->ID,
345
            $record->Tags()->first()->ID
346
        );
347
    }
348
349
350
    /**
351
     * Test read only fields are returned
352
     */
353
    public function testReadonlyTransformation()
354
    {
355
        $field = new TagField('Tags', '', TagFieldTestBlogTag::get());
356
        $readOnlyField = $field->performReadonlyTransformation();
357
        $this->assertEquals(ReadonlyTagField::class, get_class($readOnlyField));
358
359
    }
360
}
361