mirror of
https://github.com/silverstripe/silverstripe-framework
synced 2024-10-22 14:05:37 +02:00
357 lines
13 KiB
PHP
357 lines
13 KiB
PHP
<?php
|
|
|
|
namespace SilverStripe\Core\Tests;
|
|
|
|
use DateTime;
|
|
use Exception;
|
|
use ReflectionException;
|
|
use SilverStripe\Core\ClassInfo;
|
|
use SilverStripe\Core\Tests\ClassInfoTest\BaseClass;
|
|
use SilverStripe\Core\Tests\ClassInfoTest\BaseDataClass;
|
|
use SilverStripe\Core\Tests\ClassInfoTest\BaseObject;
|
|
use SilverStripe\Core\Tests\ClassInfoTest\ChildClass;
|
|
use SilverStripe\Core\Tests\ClassInfoTest\ExtendTest;
|
|
use SilverStripe\Core\Tests\ClassInfoTest\ExtendTest2;
|
|
use SilverStripe\Core\Tests\ClassInfoTest\ExtendTest3;
|
|
use SilverStripe\Core\Tests\ClassInfoTest\ExtensionTest1;
|
|
use SilverStripe\Core\Tests\ClassInfoTest\ExtensionTest2;
|
|
use SilverStripe\Core\Tests\ClassInfoTest\GrandChildClass;
|
|
use SilverStripe\Core\Tests\ClassInfoTest\HasFields;
|
|
use SilverStripe\Core\Tests\ClassInfoTest\HasMethod;
|
|
use SilverStripe\Core\Tests\ClassInfoTest\NoFields;
|
|
use SilverStripe\Core\Tests\ClassInfoTest\WithCustomTable;
|
|
use SilverStripe\Core\Tests\ClassInfoTest\WithRelation;
|
|
use SilverStripe\Dev\SapphireTest;
|
|
use SilverStripe\ORM\DataObject;
|
|
use SilverStripe\View\ViewableData;
|
|
|
|
class ClassInfoTest extends SapphireTest
|
|
{
|
|
|
|
protected static $extra_dataobjects = [
|
|
BaseClass::class,
|
|
BaseDataClass::class,
|
|
ChildClass::class,
|
|
GrandChildClass::class,
|
|
HasFields::class,
|
|
NoFields::class,
|
|
WithCustomTable::class,
|
|
WithRelation::class,
|
|
BaseObject::class,
|
|
ExtendTest::class,
|
|
ExtendTest2::class,
|
|
ExtendTest3::class,
|
|
];
|
|
|
|
protected function setUp(): void
|
|
{
|
|
parent::setUp();
|
|
ClassInfo::reset_db_cache();
|
|
}
|
|
|
|
public function testExists()
|
|
{
|
|
$this->assertTrue(ClassInfo::exists(ClassInfo::class));
|
|
$this->assertTrue(ClassInfo::exists('SilverStripe\\Core\\classinfo'));
|
|
$this->assertTrue(ClassInfo::exists('SilverStripe\\Core\\Tests\\ClassInfoTest'));
|
|
$this->assertTrue(ClassInfo::exists('SilverStripe\\Core\\Tests\\CLASSINFOTEST'));
|
|
$this->assertTrue(ClassInfo::exists('stdClass'));
|
|
$this->assertTrue(ClassInfo::exists('stdCLASS'));
|
|
$this->assertFalse(ClassInfo::exists('SomeNonExistantClass'));
|
|
}
|
|
|
|
public function testSubclassesFor()
|
|
{
|
|
$subclasses = [
|
|
'silverstripe\\core\\tests\\classinfotest\\baseclass' => BaseClass::class,
|
|
'silverstripe\\core\\tests\\classinfotest\\childclass' => ChildClass::class,
|
|
'silverstripe\\core\\tests\\classinfotest\\grandchildclass' => GrandChildClass::class,
|
|
];
|
|
$subclassesWithoutBase = [
|
|
'silverstripe\\core\\tests\\classinfotest\\childclass' => ChildClass::class,
|
|
'silverstripe\\core\\tests\\classinfotest\\grandchildclass' => GrandChildClass::class,
|
|
];
|
|
$this->assertEquals(
|
|
$subclasses,
|
|
ClassInfo::subclassesFor(BaseClass::class),
|
|
'ClassInfo::subclassesFor() returns only direct subclasses and doesnt include base class'
|
|
);
|
|
ClassInfo::reset_db_cache();
|
|
$this->assertEquals(
|
|
$subclasses,
|
|
ClassInfo::subclassesFor('silverstripe\\core\\tests\\classinfotest\\baseclass'),
|
|
'ClassInfo::subclassesFor() is acting in a case sensitive way when it should not'
|
|
);
|
|
ClassInfo::reset_db_cache();
|
|
$this->assertEquals(
|
|
$subclassesWithoutBase,
|
|
ClassInfo::subclassesFor('silverstripe\\core\\tests\\classinfotest\\baseclass', false)
|
|
);
|
|
}
|
|
|
|
public function testClassName()
|
|
{
|
|
$this->assertEquals(
|
|
ClassInfoTest::class,
|
|
ClassInfo::class_name($this)
|
|
);
|
|
$this->assertEquals(
|
|
ClassInfoTest::class,
|
|
ClassInfo::class_name('SilverStripe\\Core\\Tests\\ClassInfoTest')
|
|
);
|
|
$this->assertEquals(
|
|
ClassInfoTest::class,
|
|
ClassInfo::class_name('SilverStripe\\Core\\TESTS\\CLaSsInfOTEsT')
|
|
);
|
|
}
|
|
|
|
public function testNonClassName()
|
|
{
|
|
$this->expectException(Exception::class);
|
|
$this->expectExceptionMessageMatches('/Class "?IAmAClassThatDoesNotExist"? does not exist/');
|
|
$this->assertEquals('IAmAClassThatDoesNotExist', ClassInfo::class_name('IAmAClassThatDoesNotExist'));
|
|
}
|
|
|
|
public function testClassesForFolder()
|
|
{
|
|
$classes = ClassInfo::classes_for_folder(ltrim(FRAMEWORK_DIR . '/tests', '/'));
|
|
$this->assertArrayHasKey(
|
|
'silverstripe\\core\\tests\\classinfotest',
|
|
$classes,
|
|
'ClassInfo::classes_for_folder() returns classes matching the filename'
|
|
);
|
|
$this->assertContains(
|
|
ClassInfoTest::class,
|
|
$classes,
|
|
'ClassInfo::classes_for_folder() returns classes matching the filename'
|
|
);
|
|
$this->assertArrayHasKey(
|
|
'silverstripe\\core\\tests\\classinfotest\\baseclass',
|
|
$classes,
|
|
'ClassInfo::classes_for_folder() returns additional classes not matching the filename'
|
|
);
|
|
$this->assertContains(
|
|
BaseClass::class,
|
|
$classes,
|
|
'ClassInfo::classes_for_folder() returns additional classes not matching the filename'
|
|
);
|
|
}
|
|
|
|
/**
|
|
* @covers \SilverStripe\Core\ClassInfo::ancestry()
|
|
*/
|
|
public function testAncestry()
|
|
{
|
|
$ancestry = ClassInfo::ancestry(ChildClass::class);
|
|
$expect = [
|
|
'silverstripe\\view\\viewabledata' => ViewableData::class,
|
|
'silverstripe\\orm\\dataobject' => DataObject::class,
|
|
'silverstripe\\core\tests\classinfotest\\baseclass' => BaseClass::class,
|
|
'silverstripe\\core\tests\classinfotest\\childclass' => ChildClass::class,
|
|
];
|
|
$this->assertEquals($expect, $ancestry);
|
|
|
|
ClassInfo::reset_db_cache();
|
|
$this->assertEquals(
|
|
$expect,
|
|
ClassInfo::ancestry('silverstripe\\core\\tests\\classINFOtest\\Childclass')
|
|
);
|
|
|
|
ClassInfo::reset_db_cache();
|
|
$ancestry = ClassInfo::ancestry(ChildClass::class, true);
|
|
$this->assertEquals(
|
|
[
|
|
'silverstripe\\core\tests\classinfotest\\baseclass' => BaseClass::class
|
|
],
|
|
$ancestry,
|
|
'$tablesOnly option excludes memory-only inheritance classes'
|
|
);
|
|
}
|
|
|
|
/**
|
|
* @covers \SilverStripe\Core\ClassInfo::dataClassesFor()
|
|
*/
|
|
public function testDataClassesFor()
|
|
{
|
|
$expect = [
|
|
'silverstripe\\core\\tests\\classinfotest\\basedataclass' => BaseDataClass::class,
|
|
'silverstripe\\core\\tests\\classinfotest\\hasfields' => HasFields::class,
|
|
'silverstripe\\core\\tests\\classinfotest\\withrelation' => WithRelation::class,
|
|
'silverstripe\\core\\tests\\classinfotest\\withcustomtable' => WithCustomTable::class,
|
|
];
|
|
$classes = [
|
|
BaseDataClass::class,
|
|
NoFields::class,
|
|
HasFields::class,
|
|
];
|
|
|
|
ClassInfo::reset_db_cache();
|
|
$this->assertEquals($expect, ClassInfo::dataClassesFor($classes[0]));
|
|
ClassInfo::reset_db_cache();
|
|
$this->assertEquals($expect, ClassInfo::dataClassesFor(strtoupper($classes[0] ?? '')));
|
|
ClassInfo::reset_db_cache();
|
|
$this->assertEquals($expect, ClassInfo::dataClassesFor($classes[1]));
|
|
|
|
$expect = [
|
|
'silverstripe\\core\\tests\\classinfotest\\basedataclass' => BaseDataClass::class,
|
|
'silverstripe\\core\\tests\\classinfotest\\hasfields' => HasFields::class,
|
|
];
|
|
|
|
ClassInfo::reset_db_cache();
|
|
$this->assertEquals($expect, ClassInfo::dataClassesFor($classes[2]));
|
|
ClassInfo::reset_db_cache();
|
|
$this->assertEquals($expect, ClassInfo::dataClassesFor(strtolower($classes[2] ?? '')));
|
|
}
|
|
|
|
/**
|
|
* @covers \SilverStripe\Core\ClassInfo::classesWithExtension()
|
|
*/
|
|
public function testClassesWithExtensionUsingConfiguredExtensions()
|
|
{
|
|
$expect = [
|
|
'silverstripe\\core\\tests\\classinfotest\\extendtest' => ExtendTest::class,
|
|
'silverstripe\\core\\tests\\classinfotest\\extendtest2' => ExtendTest2::class,
|
|
'silverstripe\\core\\tests\\classinfotest\\extendtest3' => ExtendTest3::class,
|
|
];
|
|
$this->assertEquals(
|
|
$expect,
|
|
ClassInfo::classesWithExtension(ExtensionTest1::class, BaseObject::class),
|
|
'ClassInfo::testClassesWithExtension() returns class with extensions applied via class config'
|
|
);
|
|
|
|
$expect = [
|
|
'silverstripe\\core\\tests\\classinfotest\\extendtest' => ExtendTest::class,
|
|
'silverstripe\\core\\tests\\classinfotest\\extendtest2' => ExtendTest2::class,
|
|
'silverstripe\\core\\tests\\classinfotest\\extendtest3' => ExtendTest3::class,
|
|
];
|
|
$this->assertEquals(
|
|
$expect,
|
|
ClassInfo::classesWithExtension(ExtensionTest1::class, ExtendTest::class, true),
|
|
'ClassInfo::testClassesWithExtension() returns class with extensions applied via class config, including the base class'
|
|
);
|
|
}
|
|
|
|
/**
|
|
* @covers \SilverStripe\Core\ClassInfo::classesWithExtension()
|
|
*/
|
|
public function testClassesWithExtensionUsingDynamicallyAddedExtensions()
|
|
{
|
|
$this->assertEquals(
|
|
[],
|
|
ClassInfo::classesWithExtension(ExtensionTest2::class, BaseObject::class),
|
|
'ClassInfo::testClassesWithExtension() returns no classes for extension that hasn\'t been applied yet.'
|
|
);
|
|
|
|
ExtendTest::add_extension(ExtensionTest2::class);
|
|
|
|
$expect = [
|
|
'silverstripe\\core\\tests\\classinfotest\\extendtest2' => ExtendTest2::class,
|
|
'silverstripe\\core\\tests\\classinfotest\\extendtest3' => ExtendTest3::class,
|
|
];
|
|
$this->assertEquals(
|
|
$expect,
|
|
ClassInfo::classesWithExtension(ExtensionTest2::class, ExtendTest::class),
|
|
'ClassInfo::testClassesWithExtension() returns class with extra extension dynamically added'
|
|
);
|
|
}
|
|
|
|
/**
|
|
* @covers \SilverStripe\Core\ClassInfo::classesWithExtension()
|
|
*/
|
|
public function testClassesWithExtensionWithDynamicallyRemovedExtensions()
|
|
{
|
|
ExtendTest::remove_extension(ExtensionTest1::class);
|
|
|
|
$this->assertEquals(
|
|
[],
|
|
ClassInfo::classesWithExtension(ExtensionTest1::class, BaseObject::class),
|
|
'ClassInfo::testClassesWithExtension() returns no classes after an extension being removed'
|
|
);
|
|
}
|
|
|
|
/** @dataProvider provideHasMethodCases */
|
|
public function testHasMethod($object, $method, $output)
|
|
{
|
|
$this->assertEquals(
|
|
$output,
|
|
ClassInfo::hasMethod($object, $method)
|
|
);
|
|
}
|
|
|
|
public function provideHasMethodCases()
|
|
{
|
|
return [
|
|
'Basic object' => [
|
|
new DateTime(),
|
|
'format',
|
|
true,
|
|
],
|
|
'CustomMethod object' => [
|
|
new HasMethod(),
|
|
'example',
|
|
true,
|
|
],
|
|
'Class Name' => [
|
|
'DateTime',
|
|
'format',
|
|
true,
|
|
],
|
|
'FQCN' => [
|
|
'\DateTime',
|
|
'format',
|
|
true,
|
|
],
|
|
'Invalid FQCN' => [
|
|
'--GreatTime',
|
|
'format',
|
|
false,
|
|
],
|
|
'Integer' => [
|
|
1,
|
|
'format',
|
|
false,
|
|
],
|
|
'Array' => [
|
|
['\DateTime'],
|
|
'format',
|
|
false,
|
|
],
|
|
];
|
|
}
|
|
|
|
/** @dataProvider provideClassSpecCases */
|
|
public function testParseClassSpec($input, $output)
|
|
{
|
|
$this->assertEquals(
|
|
$output,
|
|
ClassInfo::parse_class_spec($input)
|
|
);
|
|
}
|
|
|
|
public function provideClassSpecCases()
|
|
{
|
|
return [
|
|
'Standard class' => [
|
|
'SimpleClass',
|
|
['SimpleClass', []],
|
|
],
|
|
'Namespaced class' => [
|
|
'Foo\\Bar\\NamespacedClass',
|
|
['Foo\\Bar\\NamespacedClass', []],
|
|
],
|
|
'Namespaced class with service name' => [
|
|
'Foo\\Bar\\NamespacedClass.withservicename',
|
|
['Foo\\Bar\\NamespacedClass.withservicename', []],
|
|
],
|
|
'Namespaced class with argument' => [
|
|
'Foo\\Bar\\NamespacedClass(["with-arg" => true])',
|
|
['Foo\\Bar\\NamespacedClass', [["with-arg" => true]]],
|
|
],
|
|
'Namespaced class with service name and argument' => [
|
|
'Foo\\Bar\\NamespacedClass.withmodifier(["and-arg" => true])',
|
|
['Foo\\Bar\\NamespacedClass.withmodifier', [["and-arg" => true]]],
|
|
],
|
|
];
|
|
}
|
|
}
|