Completed
Pull Request — master (#107)
by Simon
02:05 queued 35s
created

DataObjectAnnotatorTest::testTwoClassesInOneFile()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 12
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Importance

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