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

DataObjectAnnotatorTest::testAnnotateObject()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 6
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

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