Passed
Pull Request — master (#107)
by Simon
02:01
created

testInversePlayerRelationOfTeam()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 21
Code Lines 15

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 15
nc 1
nop 0
dl 0
loc 21
rs 9.3142
c 0
b 0
f 0
1
<?php
2
3
namespace SilverLeague\IDEAnnotator\Tests;
4
5
use Page;
6
use PageController;
7
use PHPUnit_Framework_TestCase;
8
use RootTeam;
9
use SilverLeague\IDEAnnotator\DataObjectAnnotator;
10
use SilverLeague\IDEAnnotator\Extensions\Annotatable;
11
use SilverLeague\IDEAnnotator\Helpers\AnnotateClassInfo;
12
use SilverLeague\IDEAnnotator\Helpers\AnnotatePermissionChecker;
13
use SilverStripe\Control\Director;
14
use SilverStripe\Core\Config\Config;
15
use SilverStripe\Core\Injector\Injector;
16
use SilverStripe\Dev\SapphireTest;
17
use SilverStripe\ORM\DataObject;
18
19
/**
20
 * Class DataObjectAnnotatorTest
21
 *
22
 * Several tests to make sure the Annotator does it's job correctly
23
 *
24
 * @mixin PHPUnit_Framework_TestCase
25
 */
26
class DataObjectAnnotatorTest extends SapphireTest
27
{
28
29
    /**
30
     * @var MockDataObjectAnnotator
31
     */
32
    private $annotator;
33
34
    /**
35
     * @var AnnotatePermissionChecker $permissionChecker
36
     */
37
    private $permissionChecker;
38
39
    /**
40
     * Are we enabled?
41
     */
42
    public function testIsEnabled()
43
    {
44
        $this->assertTrue(DataObjectAnnotator::isEnabled());
45
    }
46
47
    /**
48
     * Test the expected classes show up in the Classes for Module
49
     */
50
    public function testGetClassesForModule()
51
    {
52
        $expectedClasses = [
53
            Team::class                          => Director::baseFolder() . DIRECTORY_SEPARATOR . 'ideannotator' . DIRECTORY_SEPARATOR . 'tests' . DIRECTORY_SEPARATOR . 'mock' . DIRECTORY_SEPARATOR . 'DataObjectAnnotatorTest_Team.php',
54
            TeamChanged::class                   => Director::baseFolder() . DIRECTORY_SEPARATOR . 'ideannotator' . DIRECTORY_SEPARATOR . 'tests' . DIRECTORY_SEPARATOR . 'mock' . DIRECTORY_SEPARATOR . 'DataObjectAnnotatorTest_TeamChanged.php',
55
            TeamComment::class                   => Director::baseFolder() . DIRECTORY_SEPARATOR . 'ideannotator' . DIRECTORY_SEPARATOR . 'tests' . DIRECTORY_SEPARATOR . 'mock' . DIRECTORY_SEPARATOR . 'DataObjectAnnotatorTest_TeamComment.php',
56
            DocBlockMockWithDocBlock::class      => Director::baseFolder() . DIRECTORY_SEPARATOR . 'ideannotator' . DIRECTORY_SEPARATOR . 'tests' . DIRECTORY_SEPARATOR . 'mock' . DIRECTORY_SEPARATOR . 'DocBlockMockWithDocBlock.php',
57
            OtherDocBlockMockWithDocBlock::class => Director::baseFolder() . DIRECTORY_SEPARATOR . 'ideannotator' . DIRECTORY_SEPARATOR . 'tests' . DIRECTORY_SEPARATOR . 'mock' . DIRECTORY_SEPARATOR . 'DocBlockMockWithDocBlock.php',
58
            DoubleDataObjectInOneFile1::class    => Director::baseFolder() . DIRECTORY_SEPARATOR . 'ideannotator' . DIRECTORY_SEPARATOR . 'tests' . DIRECTORY_SEPARATOR . 'mock' . DIRECTORY_SEPARATOR . 'DoubleDataObjectInOneFile.php',
59
            DoubleDataObjectInOneFile2::class    => Director::baseFolder() . DIRECTORY_SEPARATOR . 'ideannotator' . DIRECTORY_SEPARATOR . 'tests' . DIRECTORY_SEPARATOR . 'mock' . DIRECTORY_SEPARATOR . 'DoubleDataObjectInOneFile.php',
60
            SubTeam::class                       => Director::baseFolder() . DIRECTORY_SEPARATOR . 'ideannotator' . DIRECTORY_SEPARATOR . 'tests' . DIRECTORY_SEPARATOR . 'mock' . DIRECTORY_SEPARATOR . 'DataObjectAnnotatorTest_SubTeam.php',
61
            Player::class                        => Director::baseFolder() . DIRECTORY_SEPARATOR . 'ideannotator' . DIRECTORY_SEPARATOR . 'tests' . DIRECTORY_SEPARATOR . 'mock' . DIRECTORY_SEPARATOR . 'DataObjectAnnotatorTest_Player.php',
62
            Team_Extension::class                => Director::baseFolder() . DIRECTORY_SEPARATOR . 'ideannotator' . DIRECTORY_SEPARATOR . 'tests' . DIRECTORY_SEPARATOR . 'mock' . DIRECTORY_SEPARATOR . 'DataObjectAnnotatorTest_Team_Extension.php',
63
            Annotatable::class                   => Director::baseFolder() . DIRECTORY_SEPARATOR . 'ideannotator' . DIRECTORY_SEPARATOR . 'src' . DIRECTORY_SEPARATOR . 'Extensions' . DIRECTORY_SEPARATOR . 'Annotatable.php',
64
            AnnotatorPageTest_Extension::class   => Director::baseFolder() . DIRECTORY_SEPARATOR . 'ideannotator' . DIRECTORY_SEPARATOR . 'tests' . DIRECTORY_SEPARATOR . 'mock' . DIRECTORY_SEPARATOR . 'AnnotatorPageTest.php',
65
            RootTeam::class                      => Director::baseFolder() . DIRECTORY_SEPARATOR . 'ideannotator' . DIRECTORY_SEPARATOR . 'tests' . DIRECTORY_SEPARATOR . 'mock' . DIRECTORY_SEPARATOR . 'RootTeam.php',
66
            AnnotatorPageTest::class             => Director::baseFolder() . DIRECTORY_SEPARATOR . 'ideannotator' . DIRECTORY_SEPARATOR . 'tests' . DIRECTORY_SEPARATOR . 'mock' . DIRECTORY_SEPARATOR . 'AnnotatorPageTest.php',
67
            AnnotatorPageTestController::class   => Director::baseFolder() . DIRECTORY_SEPARATOR . 'ideannotator' . DIRECTORY_SEPARATOR . 'tests' . DIRECTORY_SEPARATOR . 'mock' . DIRECTORY_SEPARATOR . 'AnnotatorPageTest.php',
68
            TeamSupporter::class                 => Director::baseFolder() . DIRECTORY_SEPARATOR . 'ideannotator' . DIRECTORY_SEPARATOR . 'tests' . DIRECTORY_SEPARATOR . 'mock' . DIRECTORY_SEPARATOR . 'DataObjectAnnotatorTest_TeamSupporter.php',
69
        ];
70
        $classes = $this->annotator->getClassesForModule('silverleague/ideannotator');
71
        // Sort the array, so we don't get accidental errors due to manual ordering
72
        ksort($expectedClasses);
73
        ksort($classes);
74
        $this->assertEquals($expectedClasses, $classes);
75
    }
76
77
    /**
78
     * As below, as we don't want to actively change the mocks, so enable mysite
79
     */
80
    public function testAnnotateObject()
81
    {
82
        $this->assertFalse($this->annotator->annotateObject(DataObject::class));
83
84
        Config::modify()->set(DataObjectAnnotator::class, 'enabled_modules', ['ideannotator', 'mysite']);
85
        $this->assertTrue($this->annotator->annotateObject(PageController::class));
86
    }
87
88
    /**
89
     * Not testing existing modules, as it wil actively alter the mock files, so enable mysite
90
     */
91
    public function testAnnotateModule()
92
    {
93
        $noModule = $this->annotator->annotateModule('');
94
        $this->assertFalse($noModule);
95
        $noModule = $this->annotator->annotateModule('mysite');
96
        $this->assertFalse($noModule);
97
        // Enable 'mysite' for testing
98
        Config::modify()->set(DataObjectAnnotator::class, 'enabled_modules', ['ideannotator', 'mysite']);
99
100
        $module = $this->annotator->annotateModule('mysite');
101
        $this->assertTrue($module);
102
    }
103
104
    /**
105
     * Test if the correct annotations are generated
106
     * for all database fields, relations and extensions
107
     * and that the start and end tags are present
108
     */
109
    public function testFileContentWithAnnotations()
110
    {
111
        $classInfo = new AnnotateClassInfo(Team::class);
112
        $filePath = $classInfo->getClassFilePath();
113
114
        $content = $this->annotator->getGeneratedFileContent(file_get_contents($filePath), Team::class);
115
116
        // ClassName title
117
        $this->assertContains(' * Class \SilverLeague\IDEAnnotator\Tests\Team', $content);
118
119
        // database fields
120
        $this->assertContains('@property string $Title', $content);
121
        $this->assertContains('@property int $VisitCount', $content);
122
        $this->assertContains('@property float $Price', $content);
123
        $this->assertContains('@property string $Dude', $content);
124
        $this->assertContains('@property string $Dudette', $content);
125
126
        // has_one ID
127
        $this->assertContains('@property int $CaptainID', $content);
128
        // has_one relation
129
        $this->assertContains('@method \SilverLeague\IDEAnnotator\Tests\Player Captain()', $content);
130
        // has_many relation
131
        $this->assertContains(
132
            '@method \SilverStripe\ORM\DataList|\SilverLeague\IDEAnnotator\Tests\SubTeam[] SubTeams()',
133
            $content
134
        );
135
        // many_many relation
136
        $this->assertContains(
137
            '@method \SilverStripe\ORM\ManyManyList|\SilverLeague\IDEAnnotator\Tests\Player[] Players()',
138
            $content
139
        );
140
        $this->assertContains(
141
            '@method \SilverStripe\ORM\ManyManyList|\SilverLeague\IDEAnnotator\Tests\Player[] Reserves()',
142
            $content
143
        );
144
        $this->assertContains(
145
            '@method \SilverStripe\ORM\DataList|\SilverLeague\IDEAnnotator\Tests\TeamSupporter[] Supporters()',
146
            $content
147
        );
148
149
        // DataExtension
150
        $this->assertContains('@mixin \SilverLeague\IDEAnnotator\Tests\Team_Extension', $content);
151
    }
152
153
    /**
154
     * Test if the correct annotations are generated
155
     * for all database fields, relations and extensions
156
     * and that the start and end tags are present
157
     */
158
    public function testShortFileContentWithAnnotations()
159
    {
160
        Config::modify()->set(DataObjectAnnotator::class, 'use_short_name', true);
161
162
        $classInfo = new AnnotateClassInfo(Team::class);
163
        $filePath = $classInfo->getClassFilePath();
164
165
        $content = $this->annotator->getGeneratedFileContent(file_get_contents($filePath), Team::class);
166
167
        // database fields
168
        $this->assertContains('@property string $Title', $content);
169
        $this->assertContains('@property int $VisitCount', $content);
170
        $this->assertContains('@property float $Price', $content);
171
172
        // has_one ID
173
        $this->assertContains('@property int $CaptainID', $content);
174
        // has_one relation
175
        $this->assertContains('@method Player Captain()', $content);
176
        // has_many relation
177
        $this->assertContains(
178
            '@method DataList|SubTeam[] SubTeams()',
179
            $content
180
        );
181
        // many_many relation
182
        $this->assertContains(
183
            '@method ManyManyList|Player[] Players()',
184
            $content
185
        );
186
        $this->assertContains(
187
            '@method ManyManyList|Player[] Reserves()',
188
            $content
189
        );
190
        $this->assertContains(
191
            '@method DataList|TeamSupporter[] Supporters()',
192
            $content
193
        );
194
195
        // DataExtension
196
        $this->assertContains('@mixin Team_Extension', $content);
197
    }
198
199
    public function testInversePlayerRelationOfTeam()
200
    {
201
        $classInfo = new AnnotateClassInfo(Player::class);
202
        $filePath = $classInfo->getClassFilePath();
203
204
        $content = $this->annotator->getGeneratedFileContent(file_get_contents($filePath), Player::class);
205
206
        $this->assertContains('@property boolean $IsRetired', $content);
207
        $this->assertContains('@property string $ShirtNumber', $content);
208
        $this->assertContains('@property string $Shirt', $content);
209
        $this->assertContains('@property int $FavouriteTeamID', $content);
210
        $this->assertContains('@method \SilverLeague\IDEAnnotator\Tests\Team CaptainTeam()', $content);
211
        $this->assertContains('@method \SilverLeague\IDEAnnotator\Tests\Team FavouriteTeam()', $content);
212
213
        $this->assertContains(
214
            '@method \SilverStripe\ORM\ManyManyList|\SilverLeague\IDEAnnotator\Tests\Team[] TeamPlayer()',
215
            $content
216
        );
217
        $this->assertContains(
218
            '@method \SilverStripe\ORM\ManyManyList|\SilverLeague\IDEAnnotator\Tests\Team[] TeamReserve()',
219
            $content
220
        );
221
    }
222
223
    public function testDefaults()
224
    {
225
        $count = 0;
226
        DataObjectAnnotator::pushExtensionClass(Page::class);
227
        foreach (DataObjectAnnotator::getExtensionClasses() as $class) {
228
            if ($class === 'Page') {
229
                $count++;
230
            }
231
        }
232
        $this->assertEquals(1, $count);
233
    }
234
235
    public function testSetExtensionClasses()
236
    {
237
        $classes = DataObjectAnnotator::getExtensionClasses();
238
        $expected = [
239
            'SilverLeague\IDEAnnotator\Tests\AnnotatorPageTestController',
240
            'SilverLeague\IDEAnnotator\Tests\Team',
241
            'SilverStripe\Admin\LeftAndMain',
242
            'SilverStripe\Admin\ModalController',
243
            'SilverStripe\Assets\File',
244
            'SilverStripe\AssetAdmin\Forms\FileFormFactory',
245
            'SilverStripe\Assets\Shortcodes\FileShortcodeProvider',
246
            'SilverStripe\CMS\Controllers\ContentController',
247
            'SilverStripe\CMS\Controllers\ModelAsController',
248
            'SilverStripe\CMS\Model\SiteTree',
249
            'SilverStripe\Control\Controller',
250
            'SilverStripe\Dev\DevBuildController',
251
            'SilverStripe\Forms\Form',
252
            'SilverStripe\ORM\DataObject',
253
            'SilverStripe\Security\Group',
254
            'SilverStripe\Security\Member',
255
            'SilverStripe\Forms\GridField\GridFieldConfig_Base',
256
            'SilverStripe\Forms\GridField\GridFieldConfig_RecordEditor',
257
            'SilverStripe\Forms\GridField\GridFieldConfig_RelationEditor',
258
            'SilverStripe\Forms\GridField\GridFieldDetailForm',
259
            'SilverStripe\Forms\GridField\GridFieldPrintButton',
260
            'SilverStripe\ORM\FieldType\DBField',
261
            'SilverStripe\GraphQL\Scaffolding\Scaffolders\DataObjectScaffolder',
262
            'SilverStripe\GraphQL\Scaffolding\Scaffolders\SchemaScaffolder',
263
            'SilverStripe\GraphQL\Scaffolding\Scaffolders\CRUD\Read',
264
            'SilverStripe\GraphQL\Scaffolding\Scaffolders\CRUD\ReadOne',
265
        ];
266
        DataObjectAnnotator::setExtensionClasses($classes);
267
268
        $this->assertEquals($expected, DataObjectAnnotator::getExtensionClasses());
269
    }
270
271
    public function testShortInversePlayerRelationOfTeam()
272
    {
273
        Config::modify()->set(DataObjectAnnotator::class, 'use_short_name', true);
274
275
        $classInfo = new AnnotateClassInfo(Player::class);
276
        $filePath = $classInfo->getClassFilePath();
277
278
        $content = $this->annotator->getGeneratedFileContent(file_get_contents($filePath), Player::class);
279
280
        $this->assertContains('@property boolean $IsRetired', $content);
281
        $this->assertContains('@property string $ShirtNumber', $content);
282
        $this->assertContains('@property int $FavouriteTeamID', $content);
283
        $this->assertContains('@method Team FavouriteTeam()', $content);
284
285
        $this->assertContains(
286
            '@method ManyManyList|Team[] TeamPlayer()',
287
            $content
288
        );
289
        $this->assertContains(
290
            '@method ManyManyList|Team[] TeamReserve()',
291
            $content
292
        );
293
    }
294
295
    public function testExistingMethodsWillNotBeTagged()
296
    {
297
        $classInfo = new AnnotateClassInfo(Team::class);
298
        $filePath = $classInfo->getClassFilePath();
299
300
        $content = $this->annotator->getGeneratedFileContent(file_get_contents($filePath), Team::class);
301
        $this->assertNotContains(
302
            '@method \SilverStripe\ORM\ManyManyList|\SilverLeague\IDEAnnotator\Tests\SubTeam[] SecondarySubTeams()',
303
            $content
304
        );
305
    }
306
307
    public function testShortExistingMethodsWillNotBeTagged()
308
    {
309
        Config::modify()->set(DataObjectAnnotator::class, 'use_short_name', true);
310
311
        $classInfo = new AnnotateClassInfo(Team::class);
312
        $filePath = $classInfo->getClassFilePath();
313
314
        $content = $this->annotator->getGeneratedFileContent(file_get_contents($filePath), Team::class);
315
        $this->assertNotContains(
316
            '@method ManyManyList|SubTeam[] SecondarySubTeams()',
317
            $content
318
        );
319
    }
320
321
    /**
322
     * Test that multiple annotation runs won't generate ducplicate docblocks
323
     */
324
    public function testNothingHasChangedAfterSecondAnnotation()
325
    {
326
        $classInfo = new AnnotateClassInfo(Team::class);
327
        $filePath = $classInfo->getClassFilePath();
328
        $original = file_get_contents($filePath);
329
        $firstRun = $this->annotator->getGeneratedFileContent($original, Team::class);
330
        $secondRun = $this->annotator->getGeneratedFileContent($firstRun, Team::class);
331
        $this->assertEquals($firstRun, $secondRun);
332
    }
333
334
    /**
335
     * Test that root (non-namespaced) classes get annotated
336
     */
337
    public function testRootAnnotations()
338
    {
339
        $classInfo = new AnnotateClassInfo(RootTeam::class);
340
        $filePath = $classInfo->getClassFilePath();
341
        $run = $this->annotator->getGeneratedFileContent(file_get_contents($filePath), RootTeam::class);
342
        $this->assertContains('@property string $Title', $run);
343
    }
344
345
    /**
346
     * Test the generation of annotations for a DataExtension
347
     */
348
    public function testAnnotateDataExtension()
349
    {
350
        $classInfo = new AnnotateClassInfo(Team_Extension::class);
351
        $filePath = $classInfo->getClassFilePath();
352
        $original = file_get_contents($filePath);
353
        $annotated = $this->annotator->getGeneratedFileContent($original, Team_Extension::class);
354
355
        $this->assertContains(
356
            '@property \SilverLeague\IDEAnnotator\Tests\Team|\SilverLeague\IDEAnnotator\Tests\Team_Extension $owner',
357
            $annotated
358
        );
359
        $this->assertContains('@property string $ExtendedVarcharField', $annotated);
360
        $this->assertContains('@property int $ExtendedIntField', $annotated);
361
        $this->assertContains('@property int $ExtendedHasOneRelationshipID', $annotated);
362
        $this->assertContains(
363
            '@method \SilverLeague\IDEAnnotator\Tests\Player ExtendedHasOneRelationship()',
364
            $annotated
365
        );
366
    }
367
368
    /**
369
     * Test the generation of annotations for a DataExtension
370
     */
371
    public function testShortAnnotateDataExtension()
372
    {
373
        Config::modify()->set(DataObjectAnnotator::class, 'use_short_name', true);
374
375
        $classInfo = new AnnotateClassInfo(Team_Extension::class);
376
        $filePath = $classInfo->getClassFilePath();
377
        $original = file_get_contents($filePath);
378
        $annotated = $this->annotator->getGeneratedFileContent($original, Team_Extension::class);
379
380
        $this->assertContains(
381
            '@property Team|Team_Extension $owner',
382
            $annotated
383
        );
384
        $this->assertContains('@property string $ExtendedVarcharField', $annotated);
385
        $this->assertContains('@property int $ExtendedIntField', $annotated);
386
        $this->assertContains('@property int $ExtendedHasOneRelationshipID', $annotated);
387
        $this->assertContains(
388
            '@method Player ExtendedHasOneRelationship()',
389
            $annotated
390
        );
391
    }
392
393
    /**
394
     *
395
     */
396
    public function testTwoClassesInOneFile()
397
    {
398
        $classInfo = new AnnotateClassInfo(DoubleDataObjectInOneFile1::class);
399
        $filePath = $classInfo->getClassFilePath();
400
        $original = file_get_contents($filePath);
401
        $annotated = $this->annotator->getGeneratedFileContent($original, DoubleDataObjectInOneFile1::class);
402
403
        $this->assertContains('@property string $Title', $annotated);
404
405
        $annotated = $this->annotator->getGeneratedFileContent($annotated, DoubleDataObjectInOneFile2::class);
406
407
        $this->assertContains('@property string $Name', $annotated);
408
    }
409
410
    public function tearDown()
411
    {
412
        parent::tearDown();
413
    }
414
415
    /**
416
     * Setup Defaults
417
     */
418
    protected function setUp()
419
    {
420
        parent::setUp();
421
        Config::modify()->set(DataObjectAnnotator::class, 'use_short_name', false);
422
423
        Config::modify()->set(DataObjectAnnotator::class, 'enabled', true);
424
        Config::modify()->set(DataObjectAnnotator::class, 'enabled_modules', ['silverleague/ideannotator']);
425
426
        $this->annotator = Injector::inst()->get(MockDataObjectAnnotator::class);
427
        $this->permissionChecker = Injector::inst()->get(AnnotatePermissionChecker::class);
428
    }
429
}
430