From 7226d7fab6e3e10566892f5a2222d57de3266eae Mon Sep 17 00:00:00 2001 From: Michal Kleiner Date: Sat, 25 Sep 2021 00:17:25 +1200 Subject: [PATCH] ENH Add tests for Hierarchy extension when applied to a subclass --- tests/php/Forms/TreeDropdownFieldTest.php | 70 ++++++++++++++++++- tests/php/Forms/TreeDropdownFieldTest.yml | 26 +++++++ tests/php/ORM/HierarchyTest.php | 39 +++++++++++ tests/php/ORM/HierarchyTest.yml | 17 +++++ .../HierarchyOnSubclassTestObject.php | 30 ++++++++ .../HierarchyOnSubclassTestSubObject.php | 18 +++++ 6 files changed, 199 insertions(+), 1 deletion(-) create mode 100644 tests/php/ORM/HierarchyTest/HierarchyOnSubclassTestObject.php create mode 100644 tests/php/ORM/HierarchyTest/HierarchyOnSubclassTestSubObject.php diff --git a/tests/php/Forms/TreeDropdownFieldTest.php b/tests/php/Forms/TreeDropdownFieldTest.php index ec349fa0b..17de5c8d3 100644 --- a/tests/php/Forms/TreeDropdownFieldTest.php +++ b/tests/php/Forms/TreeDropdownFieldTest.php @@ -12,6 +12,8 @@ use SilverStripe\Forms\FieldList; use SilverStripe\Forms\Form; use SilverStripe\Forms\TreeDropdownField; use SilverStripe\ORM\DataObject; +use SilverStripe\ORM\Tests\HierarchyTest\HierarchyOnSubclassTestObject; +use SilverStripe\ORM\Tests\HierarchyTest\HierarchyOnSubclassTestSubObject; use SilverStripe\ORM\Tests\HierarchyTest\TestObject; class TreeDropdownFieldTest extends SapphireTest @@ -20,7 +22,9 @@ class TreeDropdownFieldTest extends SapphireTest protected static $fixture_file = 'TreeDropdownFieldTest.yml'; protected static $extra_dataobjects = [ - TestObject::class + TestObject::class, + HierarchyOnSubclassTestObject::class, + HierarchyOnSubclassTestSubObject::class, ]; public function testSchemaStateDefaults() @@ -137,6 +141,37 @@ class TreeDropdownFieldTest extends SapphireTest $this->assertEquals($expectedNodeIDs, $actualNodeIDs); } + public function testTreeSearchJsonFlatlistWithLowNodeThresholdUsingSubObject() + { + // Initialise our TreeDropDownField + $field = new TreeDropdownField('TestTree', 'Test tree - Hierarchy on subclass', HierarchyOnSubclassTestSubObject::class); + $field->config()->set('node_threshold_total', 2); + + // Search for all Test object matching our criteria + $request = new HTTPRequest( + 'GET', + 'url', + ['search' => 'SubObject', 'format' => 'json', 'flatList' => '1'] + ); + $request->setSession(new Session([])); + $response = $field->tree($request); + $tree = json_decode($response->getBody(), true); + $actualNodeIDs = array_column($tree['children'], 'id'); + + // Get the list of expected node IDs from the YML Fixture + $expectedNodeIDs = array_map( + function ($key) { + return $this->objFromFixture(HierarchyOnSubclassTestSubObject::class, $key)->ID; + }, + ['four', 'fourB', 'fourA2'] // Those are the identifiers of the object we expect our search to find + ); + + sort($actualNodeIDs); + sort($expectedNodeIDs); + + $this->assertEquals($expectedNodeIDs, $actualNodeIDs); + } + public function testTreeSearch() { $field = new TreeDropdownField('TestTree', 'Test tree', Folder::class); @@ -233,6 +268,39 @@ class TreeDropdownFieldTest extends SapphireTest ); } + public function testTreeSearchUsingSubObject() + { + $field = new TreeDropdownField('TestTree', 'Test tree', HierarchyOnSubclassTestSubObject::class); + + // case-insensitive search against keyword 'SubObject' for objects that have Hierarchy extension + // applied to a class that doesn't directly inherit from DataObject + $request = new HTTPRequest('GET', 'url', ['search' => 'SubObject']); + $request->setSession(new Session([])); + $response = $field->tree($request); + $tree = $response->getBody(); + + $subObject1 = $this->objFromFixture(HierarchyOnSubclassTestSubObject::class, 'four'); + $subObject1ChildB = $this->objFromFixture(HierarchyOnSubclassTestSubObject::class, 'fourB'); + + $parser = new CSSContentParser($tree); + $cssPath = 'ul.tree li#selector-TestTree-' . $subObject1->ID . ' li#selector-TestTree-' . $subObject1ChildB->ID . ' a'; + $firstResult = $parser->getBySelector($cssPath); + $this->assertEquals( + $subObject1ChildB->Name, + (string)$firstResult[0], + $subObject1ChildB->Name . ' is found, nested under ' . $subObject1->Name + ); + + // other objects which don't contain the keyword 'SubObject' are not returned in search results + $subObject2 = $this->objFromFixture(HierarchyOnSubclassTestSubObject::class, 'five'); + $cssPath = 'ul.tree li#selector-TestTree-' . $subObject2->ID . ' a'; + $noResult = $parser->getBySelector($cssPath); + $this->assertEmpty( + $noResult, + $subObject2 . ' is not found' + ); + } + public function testReadonly() { $field = new TreeDropdownField('TestTree', 'Test tree', File::class); diff --git a/tests/php/Forms/TreeDropdownFieldTest.yml b/tests/php/Forms/TreeDropdownFieldTest.yml index 2207cc300..66ced1fc9 100644 --- a/tests/php/Forms/TreeDropdownFieldTest.yml +++ b/tests/php/Forms/TreeDropdownFieldTest.yml @@ -62,3 +62,29 @@ SilverStripe\ORM\Tests\HierarchyTest\TestObject: ParentID: =>SilverStripe\ORM\Tests\HierarchyTest\TestObject.twoA three: Title: Three MatchSearchCriteria +SilverStripe\ORM\Tests\HierarchyTest\HierarchyOnSubclassTestSubObject: + four: + Title: Four SubObject + fourA: + Parent: =>SilverStripe\ORM\Tests\HierarchyTest\HierarchyOnSubclassTestSubObject.four + Title: Child A of Four + fourB: + Parent: =>SilverStripe\ORM\Tests\HierarchyTest\HierarchyOnSubclassTestSubObject.four + Title: Child B of Four SubObject + fourA1: + Parent: =>SilverStripe\ORM\Tests\HierarchyTest\HierarchyOnSubclassTestSubObject.fourA + Title: Child 1 of Child A of Four + fourA2: + Parent: =>SilverStripe\ORM\Tests\HierarchyTest\HierarchyOnSubclassTestSubObject.fourA + Title: Child 2 of Child A of Four SubObject + fourB1: + Parent: =>SilverStripe\ORM\Tests\HierarchyTest\HierarchyOnSubclassTestSubObject.fourB + Title: Child 1 of Child B of Four + fourB2: + Parent: =>SilverStripe\ORM\Tests\HierarchyTest\HierarchyOnSubclassTestSubObject.fourB + Title: Child 2 of Child B of Four + fourB3: + Parent: =>SilverStripe\ORM\Tests\HierarchyTest\HierarchyOnSubclassTestSubObject.fourB + Title: Child 3 of Child B of Four + five: + Title: Five diff --git a/tests/php/ORM/HierarchyTest.php b/tests/php/ORM/HierarchyTest.php index f4b859d99..f22a313ad 100644 --- a/tests/php/ORM/HierarchyTest.php +++ b/tests/php/ORM/HierarchyTest.php @@ -14,6 +14,8 @@ class HierarchyTest extends SapphireTest HierarchyTest\TestObject::class, HierarchyTest\HideTestObject::class, HierarchyTest\HideTestSubObject::class, + HierarchyTest\HierarchyOnSubclassTestObject::class, + HierarchyTest\HierarchyOnSubclassTestSubObject::class, ]; public static function getExtraDataObjects() @@ -145,6 +147,43 @@ class HierarchyTest extends SapphireTest ); } + public function testNumChildrenHierarchyOnSubclass() + { + /** @var HierarchyTest\HierarchyOnSubclassTestObject $obj5 */ + $obj5 = $this->objFromFixture(HierarchyTest\HierarchyOnSubclassTestObject::class, 'obj5'); + + $this->assertFalse( + $obj5->hasMethod('numChildren'), + 'numChildren() cannot be called on object without Hierarchy extension' + ); + + /** @var HierarchyTest\HierarchyOnSubclassTestSubObject $obj5a */ + $obj5a = $this->objFromFixture(HierarchyTest\HierarchyOnSubclassTestSubObject::class, 'obj5a'); + /** @var HierarchyTest\HierarchyOnSubclassTestSubObject $obj5b */ + $obj5b = $this->objFromFixture(HierarchyTest\HierarchyOnSubclassTestSubObject::class, 'obj5b'); + + $this->assertEquals(2, $obj5a->numChildren()); + $this->assertEquals(1, $obj5b->numChildren()); + + $obj5bChild2 = new HierarchyTest\HierarchyOnSubclassTestSubObject(); + $obj5bChild2->ParentID = $obj5b->ID; + $obj5bChild2->write(); + $this->assertEquals( + $obj5b->numChildren(false), + 2, + 'numChildren() caching can be disabled through method parameter' + ); + $obj5bChild3 = new HierarchyTest\HierarchyOnSubclassTestSubObject(); + $obj5bChild3->ParentID = $obj5b->ID; + $obj5bChild3->write(); + $obj5b->flushCache(); + $this->assertEquals( + $obj5b->numChildren(), + 3, + 'numChildren() caching can be disabled by flushCache()' + ); + } + public function testLoadDescendantIDListIntoArray() { /** @var HierarchyTest\TestObject $obj2 */ diff --git a/tests/php/ORM/HierarchyTest.yml b/tests/php/ORM/HierarchyTest.yml index cd2e66576..a8a9d8c3b 100644 --- a/tests/php/ORM/HierarchyTest.yml +++ b/tests/php/ORM/HierarchyTest.yml @@ -53,3 +53,20 @@ SilverStripe\ORM\Tests\HierarchyTest\HideTestObject: SilverStripe\ORM\Tests\HierarchyTest\HideTestSubObject: obj4b: Parent: =>SilverStripe\ORM\Tests\HierarchyTest\HideTestObject.obj4 +SilverStripe\ORM\Tests\HierarchyTest\HierarchyOnSubclassTestObject: + obj5: + Title: Obj 5 +SilverStripe\ORM\Tests\HierarchyTest\HierarchyOnSubclassTestSubObject: + obj5a: + Title: Obj 5a + obj5b: + Title: Obj 5b + obj5aa: + Parent: =>SilverStripe\ORM\Tests\HierarchyTest\HierarchyOnSubclassTestSubObject.obj5a + Title: Obj 5aa + obj5ab: + Parent: =>SilverStripe\ORM\Tests\HierarchyTest\HierarchyOnSubclassTestSubObject.obj5a + Title: Obj 5ab + obj5ba: + Parent: =>SilverStripe\ORM\Tests\HierarchyTest\HierarchyOnSubclassTestSubObject.obj5b + Title: Obj 5ba diff --git a/tests/php/ORM/HierarchyTest/HierarchyOnSubclassTestObject.php b/tests/php/ORM/HierarchyTest/HierarchyOnSubclassTestObject.php new file mode 100644 index 000000000..48dfdd9a1 --- /dev/null +++ b/tests/php/ORM/HierarchyTest/HierarchyOnSubclassTestObject.php @@ -0,0 +1,30 @@ + 'Varchar' + ]; + + private static $extensions = [ + Versioned::class, + ]; + + private static $default_sort = 'Title ASC'; + + public function cmstreeclasses() + { + return $this->markingClasses(); + } +} diff --git a/tests/php/ORM/HierarchyTest/HierarchyOnSubclassTestSubObject.php b/tests/php/ORM/HierarchyTest/HierarchyOnSubclassTestSubObject.php new file mode 100644 index 000000000..427474942 --- /dev/null +++ b/tests/php/ORM/HierarchyTest/HierarchyOnSubclassTestSubObject.php @@ -0,0 +1,18 @@ +