Completed
Push — 4 ( effe5c...887b7d )
by Sam
40s queued 20s
created

ClassInfoTest::provideClassSpecCases()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 22
Code Lines 16

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 16
c 1
b 0
f 0
nc 1
nop 0
dl 0
loc 22
rs 9.7333
1
<?php
2
3
namespace SilverStripe\Core\Tests;
4
5
use ReflectionException;
6
use SilverStripe\Core\ClassInfo;
7
use SilverStripe\Core\Tests\ClassInfoTest\BaseClass;
8
use SilverStripe\Core\Tests\ClassInfoTest\BaseDataClass;
9
use SilverStripe\Core\Tests\ClassInfoTest\BaseObject;
10
use SilverStripe\Core\Tests\ClassInfoTest\ChildClass;
11
use SilverStripe\Core\Tests\ClassInfoTest\ExtendTest;
12
use SilverStripe\Core\Tests\ClassInfoTest\ExtendTest2;
13
use SilverStripe\Core\Tests\ClassInfoTest\ExtendTest3;
14
use SilverStripe\Core\Tests\ClassInfoTest\ExtensionTest1;
15
use SilverStripe\Core\Tests\ClassInfoTest\ExtensionTest2;
16
use SilverStripe\Core\Tests\ClassInfoTest\GrandChildClass;
17
use SilverStripe\Core\Tests\ClassInfoTest\HasFields;
18
use SilverStripe\Core\Tests\ClassInfoTest\NoFields;
19
use SilverStripe\Core\Tests\ClassInfoTest\WithCustomTable;
20
use SilverStripe\Core\Tests\ClassInfoTest\WithRelation;
21
use SilverStripe\Dev\SapphireTest;
22
use SilverStripe\ORM\DataObject;
23
use SilverStripe\View\ViewableData;
24
25
class ClassInfoTest extends SapphireTest
26
{
27
28
    protected static $extra_dataobjects = [
29
        BaseClass::class,
30
        BaseDataClass::class,
31
        ChildClass::class,
32
        GrandChildClass::class,
33
        HasFields::class,
34
        NoFields::class,
35
        WithCustomTable::class,
36
        WithRelation::class,
37
        BaseObject::class,
38
        ExtendTest::class,
39
        ExtendTest2::class,
40
        ExtendTest3::class,
41
    ];
42
43
    protected function setUp()
44
    {
45
        parent::setUp();
46
        ClassInfo::reset_db_cache();
47
    }
48
49
    public function testExists()
50
    {
51
        $this->assertTrue(ClassInfo::exists(ClassInfo::class));
52
        $this->assertTrue(ClassInfo::exists('SilverStripe\\Core\\classinfo'));
53
        $this->assertTrue(ClassInfo::exists('SilverStripe\\Core\\Tests\\ClassInfoTest'));
54
        $this->assertTrue(ClassInfo::exists('SilverStripe\\Core\\Tests\\CLASSINFOTEST'));
55
        $this->assertTrue(ClassInfo::exists('stdClass'));
56
        $this->assertTrue(ClassInfo::exists('stdCLASS'));
57
        $this->assertFalse(ClassInfo::exists('SomeNonExistantClass'));
58
    }
59
60
    public function testSubclassesFor()
61
    {
62
        $subclasses = [
63
            'silverstripe\\core\\tests\\classinfotest\\baseclass' => BaseClass::class,
64
            'silverstripe\\core\\tests\\classinfotest\\childclass' => ChildClass::class,
65
            'silverstripe\\core\\tests\\classinfotest\\grandchildclass' => GrandChildClass::class,
66
        ];
67
        $subclassesWithoutBase = [
68
            'silverstripe\\core\\tests\\classinfotest\\childclass' => ChildClass::class,
69
            'silverstripe\\core\\tests\\classinfotest\\grandchildclass' => GrandChildClass::class,
70
        ];
71
        $this->assertEquals(
72
            $subclasses,
73
            ClassInfo::subclassesFor(BaseClass::class),
74
            'ClassInfo::subclassesFor() returns only direct subclasses and doesnt include base class'
75
        );
76
        ClassInfo::reset_db_cache();
77
        $this->assertEquals(
78
            $subclasses,
79
            ClassInfo::subclassesFor('silverstripe\\core\\tests\\classinfotest\\baseclass'),
80
            'ClassInfo::subclassesFor() is acting in a case sensitive way when it should not'
81
        );
82
        ClassInfo::reset_db_cache();
83
        $this->assertEquals(
84
            $subclassesWithoutBase,
85
            ClassInfo::subclassesFor('silverstripe\\core\\tests\\classinfotest\\baseclass', false)
86
        );
87
    }
88
89
    public function testClassName()
90
    {
91
        $this->assertEquals(
92
            ClassInfoTest::class,
93
            ClassInfo::class_name($this)
94
        );
95
        $this->assertEquals(
96
            ClassInfoTest::class,
97
            ClassInfo::class_name('SilverStripe\\Core\\Tests\\ClassInfoTest')
98
        );
99
        $this->assertEquals(
100
            ClassInfoTest::class,
101
            ClassInfo::class_name('SilverStripe\\Core\\TESTS\\CLaSsInfOTEsT')
102
        );
103
    }
104
105
    public function testNonClassName()
106
    {
107
        $this->expectException(ReflectionException::class);
108
        $this->expectExceptionMessageRegExp('/Class "?IAmAClassThatDoesNotExist"? does not exist/');
109
        $this->assertEquals('IAmAClassThatDoesNotExist', ClassInfo::class_name('IAmAClassThatDoesNotExist'));
110
    }
111
112
    public function testClassesForFolder()
113
    {
114
        $classes = ClassInfo::classes_for_folder(ltrim(FRAMEWORK_DIR . '/tests', '/'));
115
        $this->assertArrayHasKey(
116
            'silverstripe\\core\\tests\\classinfotest',
117
            $classes,
118
            'ClassInfo::classes_for_folder() returns classes matching the filename'
119
        );
120
        $this->assertContains(
121
            ClassInfoTest::class,
122
            $classes,
123
            'ClassInfo::classes_for_folder() returns classes matching the filename'
124
        );
125
        $this->assertArrayHasKey(
126
            'silverstripe\\core\\tests\\classinfotest\\baseclass',
127
            $classes,
128
            'ClassInfo::classes_for_folder() returns additional classes not matching the filename'
129
        );
130
        $this->assertContains(
131
            BaseClass::class,
132
            $classes,
133
            'ClassInfo::classes_for_folder() returns additional classes not matching the filename'
134
        );
135
    }
136
137
    /**
138
     * @covers \SilverStripe\Core\ClassInfo::ancestry()
139
     */
140
    public function testAncestry()
141
    {
142
        $ancestry = ClassInfo::ancestry(ChildClass::class);
143
        $expect = [
144
            'silverstripe\\view\\viewabledata' => ViewableData::class,
145
            'silverstripe\\orm\\dataobject' => DataObject::class,
146
            'silverstripe\\core\tests\classinfotest\\baseclass' => BaseClass::class,
147
            'silverstripe\\core\tests\classinfotest\\childclass' => ChildClass::class,
148
        ];
149
        $this->assertEquals($expect, $ancestry);
150
151
        ClassInfo::reset_db_cache();
152
        $this->assertEquals(
153
            $expect,
154
            ClassInfo::ancestry('silverstripe\\core\\tests\\classINFOtest\\Childclass')
155
        );
156
157
        ClassInfo::reset_db_cache();
158
        $ancestry = ClassInfo::ancestry(ChildClass::class, true);
159
        $this->assertEquals(
160
            [
161
                'silverstripe\\core\tests\classinfotest\\baseclass' => BaseClass::class
162
            ],
163
            $ancestry,
164
            '$tablesOnly option excludes memory-only inheritance classes'
165
        );
166
    }
167
168
    /**
169
     * @covers \SilverStripe\Core\ClassInfo::dataClassesFor()
170
     */
171
    public function testDataClassesFor()
172
    {
173
        $expect = [
174
            'silverstripe\\core\\tests\\classinfotest\\basedataclass' => BaseDataClass::class,
175
            'silverstripe\\core\\tests\\classinfotest\\hasfields' => HasFields::class,
176
            'silverstripe\\core\\tests\\classinfotest\\withrelation' => WithRelation::class,
177
            'silverstripe\\core\\tests\\classinfotest\\withcustomtable' => WithCustomTable::class,
178
        ];
179
        $classes = [
180
            BaseDataClass::class,
181
            NoFields::class,
182
            HasFields::class,
183
        ];
184
185
        ClassInfo::reset_db_cache();
186
        $this->assertEquals($expect, ClassInfo::dataClassesFor($classes[0]));
187
        ClassInfo::reset_db_cache();
188
        $this->assertEquals($expect, ClassInfo::dataClassesFor(strtoupper($classes[0])));
189
        ClassInfo::reset_db_cache();
190
        $this->assertEquals($expect, ClassInfo::dataClassesFor($classes[1]));
191
192
        $expect = [
193
            'silverstripe\\core\\tests\\classinfotest\\basedataclass' => BaseDataClass::class,
194
            'silverstripe\\core\\tests\\classinfotest\\hasfields' => HasFields::class,
195
        ];
196
197
        ClassInfo::reset_db_cache();
198
        $this->assertEquals($expect, ClassInfo::dataClassesFor($classes[2]));
199
        ClassInfo::reset_db_cache();
200
        $this->assertEquals($expect, ClassInfo::dataClassesFor(strtolower($classes[2])));
201
    }
202
203
    /**
204
     * @covers \SilverStripe\Core\ClassInfo::classesWithExtension()
205
     */
206
    public function testClassesWithExtensionUsingConfiguredExtensions()
207
    {
208
        $expect = [
209
            'silverstripe\\core\\tests\\classinfotest\\extendtest' => ExtendTest::class,
210
            'silverstripe\\core\\tests\\classinfotest\\extendtest2' => ExtendTest2::class,
211
            'silverstripe\\core\\tests\\classinfotest\\extendtest3' => ExtendTest3::class,
212
        ];
213
        $this->assertEquals(
214
            $expect,
215
            ClassInfo::classesWithExtension(ExtensionTest1::class, BaseObject::class),
216
            'ClassInfo::testClassesWithExtension() returns class with extensions applied via class config'
217
        );
218
219
        $expect = [
220
            'silverstripe\\core\\tests\\classinfotest\\extendtest' => ExtendTest::class,
221
            'silverstripe\\core\\tests\\classinfotest\\extendtest2' => ExtendTest2::class,
222
            'silverstripe\\core\\tests\\classinfotest\\extendtest3' => ExtendTest3::class,
223
        ];
224
        $this->assertEquals(
225
            $expect,
226
            ClassInfo::classesWithExtension(ExtensionTest1::class, ExtendTest::class, true),
227
            'ClassInfo::testClassesWithExtension() returns class with extensions applied via class config, including the base class'
228
        );
229
    }
230
231
    /**
232
     * @covers \SilverStripe\Core\ClassInfo::classesWithExtension()
233
     */
234
    public function testClassesWithExtensionUsingDynamicallyAddedExtensions()
235
    {
236
        $this->assertEquals(
237
            [],
238
            ClassInfo::classesWithExtension(ExtensionTest2::class, BaseObject::class),
239
            'ClassInfo::testClassesWithExtension() returns no classes for extension that hasn\'t been applied yet.'
240
        );
241
242
        ExtendTest::add_extension(ExtensionTest2::class);
243
244
        $expect = [
245
            'silverstripe\\core\\tests\\classinfotest\\extendtest2' => ExtendTest2::class,
246
            'silverstripe\\core\\tests\\classinfotest\\extendtest3' => ExtendTest3::class,
247
        ];
248
        $this->assertEquals(
249
            $expect,
250
            ClassInfo::classesWithExtension(ExtensionTest2::class, ExtendTest::class),
251
            'ClassInfo::testClassesWithExtension() returns class with extra extension dynamically added'
252
        );
253
    }
254
255
    /**
256
     * @covers \SilverStripe\Core\ClassInfo::classesWithExtension()
257
     */
258
    public function testClassesWithExtensionWithDynamicallyRemovedExtensions()
259
    {
260
        ExtendTest::remove_extension(ExtensionTest1::class);
261
262
        $this->assertEquals(
263
            [],
264
            ClassInfo::classesWithExtension(ExtensionTest1::class, BaseObject::class),
265
            'ClassInfo::testClassesWithExtension() returns no classes after an extension being removed'
266
        );
267
    }
268
269
    /**
270
     * @dataProvider provideClassSpecCases
271
     */
272
    public function testParseClassSpec($input, $output)
273
    {
274
        $this->assertEquals(
275
            $output,
276
            ClassInfo::parse_class_spec($input)
277
        );
278
    }
279
280
    public function provideClassSpecCases()
281
    {
282
        return [
283
            'Standard class' => [
284
                'SimpleClass',
285
                ['SimpleClass', []],
286
            ],
287
            'Namespaced class' => [
288
                'Foo\\Bar\\NamespacedClass',
289
                ['Foo\\Bar\\NamespacedClass', []],
290
            ],
291
            'Namespaced class with service name' => [
292
                'Foo\\Bar\\NamespacedClass.withservicename',
293
                ['Foo\\Bar\\NamespacedClass.withservicename', []],
294
            ],
295
            'Namespaced class with argument' => [
296
                'Foo\\Bar\\NamespacedClass(["with-arg" => true])',
297
                ['Foo\\Bar\\NamespacedClass', [["with-arg" => true]]],
298
            ],
299
            'Namespaced class with service name and argument' => [
300
                'Foo\\Bar\\NamespacedClass.withmodifier(["and-arg" => true])',
301
                ['Foo\\Bar\\NamespacedClass.withmodifier', [["and-arg" => true]]],
302
            ],
303
        ];
304
    }
305
}
306