Passed
Push — master ( 2400b0...37a983 )
by Robbie
03:49
created

DataObjectAnnotatorTest::tearDown()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 1
nc 1
nop 0
dl 0
loc 3
rs 10
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\Core\Config\Config;
14
use SilverStripe\Core\Injector\Injector;
15
use SilverStripe\Core\Manifest\ModuleManifest;
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                          => realpath(__DIR__ . '/../mock/DataObjectAnnotatorTest_Team.php'),
54
            TeamChanged::class                   => realpath(__DIR__ . '/../mock/DataObjectAnnotatorTest_TeamChanged.php'),
55
            TeamComment::class                   => realpath(__DIR__ . '/../mock/DataObjectAnnotatorTest_TeamComment.php'),
56
            DocBlockMockWithDocBlock::class      => realpath(__DIR__ . '/../mock/DocBlockMockWithDocBlock.php'),
57
            OtherDocBlockMockWithDocBlock::class => realpath(__DIR__ . '/../mock/DocBlockMockWithDocBlock.php'),
58
            DoubleDataObjectInOneFile1::class    => realpath(__DIR__ . '/../mock/DoubleDataObjectInOneFile.php'),
59
            DoubleDataObjectInOneFile2::class    => realpath(__DIR__ . '/../mock/DoubleDataObjectInOneFile.php'),
60
            SubTeam::class                       => realpath(__DIR__ . '/../mock/DataObjectAnnotatorTest_SubTeam.php'),
61
            Player::class                        => realpath(__DIR__ . '/../mock/DataObjectAnnotatorTest_Player.php'),
62
            Team_Extension::class                => realpath(__DIR__ . '/../mock/DataObjectAnnotatorTest_Team_Extension.php'),
63
            Annotatable::class                   => realpath(__DIR__ . '/../../src/Extensions/Annotatable.php'),
64
            TestAnnotatorPage_Extension::class   => realpath(__DIR__ . '/../mock/TestAnnotatorPage.php'),
65
            RootTeam::class                      => realpath(__DIR__ . '/../mock/RootTeam.php'),
66
            TestAnnotatorPage::class             => realpath(__DIR__ . '/../mock/TestAnnotatorPage.php'),
67
            TestAnnotatorPageController::class   => realpath(__DIR__ . '/../mock/TestAnnotatorPage.php'),
68
            TeamSupporter::class                 => realpath(__DIR__ . '/../mock/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', 'app']);
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
        $projectName = ModuleManifest::config()->get('project');
96
        $noModule = $this->annotator->annotateModule($projectName);
97
        $this->assertFalse($noModule);
98
        // Enable 'mysite' (or 'app') for testing
99
        Config::modify()->set(DataObjectAnnotator::class, 'enabled_modules', [$projectName]);
100
101
        $module = $this->annotator->annotateModule($projectName);
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\ManyManyList|\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 ManyManyList|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
        $expected = [
239
            'SilverLeague\IDEAnnotator\Tests\TestAnnotatorPageController',
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\GridFieldDetailForm',
256
            'SilverStripe\Forms\GridField\GridFieldPrintButton',
257
            'SilverStripe\ORM\FieldType\DBField',
258
        ];
259
260
        // Instantiate - triggers extension class list generation
261
        new DataObjectAnnotator();
262
        $result = DataObjectAnnotator::getExtensionClasses();
263
        foreach ($expected as $expectedClass) {
264
            $this->assertContains($expectedClass, $result);
265
        }
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\SubTeam|\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 SubTeam|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
    /**
408
     * Setup Defaults
409
     */
410
    protected function setUp()
411
    {
412
        parent::setUp();
413
        Config::modify()->set(DataObjectAnnotator::class, 'use_short_name', false);
414
415
        Config::modify()->set(DataObjectAnnotator::class, 'enabled', true);
416
        Config::modify()->set(DataObjectAnnotator::class, 'enabled_modules', ['silverleague/ideannotator']);
417
418
        $this->annotator = Injector::inst()->get(MockDataObjectAnnotator::class);
419
        $this->permissionChecker = Injector::inst()->get(AnnotatePermissionChecker::class);
420
    }
421
}
422