Completed
Pull Request — master (#107)
by Simon
01:47
created

testAnnotateDataExtension()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 17
Code Lines 13

Duplication

Lines 0
Ratio 0 %

Importance

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