diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/DataGenerator/Handlers/DataObjectHandlerTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/DataGenerator/Handlers/DataObjectHandlerTest.php index b77659aa2..d55f35247 100644 --- a/dev/tests/unit/Magento/FunctionalTestFramework/DataGenerator/Handlers/DataObjectHandlerTest.php +++ b/dev/tests/unit/Magento/FunctionalTestFramework/DataGenerator/Handlers/DataObjectHandlerTest.php @@ -30,41 +30,105 @@ class DataObjectHandlerTest extends MagentoTestCase 'value' => 'testValue' ] ] - ] + ], + 'EntityTwo' => [ + 'type' => 'testType', + 'extends' => 'EntityOne', + 'data' => [ + 0 => [ + 'key' => 'testKeyTwo', + 'value' => 'testValueTwo' + ] + ] + ], ] ]; - /** - * Set up everything required to mock DataObjectHander::getInstance() - * The first call to getInstance() uses these mocks to emulate the parser, initializing internal state - * according to the PARSER_OUTPUT value - */ - public static function setUpBeforeClass() - { - $mockDataProfileSchemaParser = AspectMock::double(DataProfileSchemaParser::class, [ - 'readDataProfiles' => self::PARSER_OUTPUT - ])->make(); - - $mockObjectManager = AspectMock::double(ObjectManager::class, [ - 'create' => $mockDataProfileSchemaParser - ])->make(); + const PARSER_OUTPUT_WITH_EXTEND = [ + 'entity' => [ + 'EntityOne' => [ + 'name' => 'EntityOne', + 'type' => 'testType', + 'data' => [ + 0 => [ + 'key' => 'testKey', + 'value' => 'testValue' + ] + ] + ], + 'EntityTwo' => [ + 'name' => 'EntityTwo', + 'type' => 'testType', + 'extends' => 'EntityOne', + 'data' => [ + 0 => [ + 'key' => 'testKeyTwo', + 'value' => 'testValueTwo' + ] + ], + ], + 'EntityThree' => [ + 'name' => 'EntityThree', + 'type' => 'testType', + 'extends' => 'EntityOne', + 'data' => [ + 0 => [ + 'key' => 'testKeyThree', + 'value' => 'testValueThree' + ] + ], + ] + ] + ]; - AspectMock::double(ObjectManagerFactory::class, [ - 'getObjectManager' => $mockObjectManager - ]); - } + const PARSER_OUTPUT_WITH_EXTEND_INVALID = [ + 'entity' => [ + 'EntityOne' => [ + 'name' => 'EntityOne', + 'type' => 'testType', + 'extends' => 'EntityOne', + 'data' => [ + 0 => [ + 'key' => 'testKey', + 'value' => 'testValue' + ] + ] + ], + 'EntityTwo' => [ + 'name' => 'EntityTwo', + 'type' => 'testType', + 'data' => [ + 0 => [ + 'key' => 'testKeyTwo', + 'value' => 'testValueTwo' + ] + ], + ], + 'EntityThree' => [ + 'name' => 'EntityThree', + 'type' => 'testType', + 'extends' => 'EntityThree', + 'data' => [ + 0 => [ + 'key' => 'testKeyThree', + 'value' => 'testValueThree' + ] + ], + ] + ] + ]; /** * getAllObjects should contain the expected data object */ public function testGetAllObjects() { - // Call the method under test + $this->setUpMockDataObjectHander(self::PARSER_OUTPUT); + // Call the method under test $actual = DataObjectHandler::getInstance()->getAllObjects(); // Assert - $expected = new EntityDataObject('EntityOne', 'testType', ['testkey' => 'testValue'], [], null, []); $this->assertArrayHasKey('EntityOne', $actual); $this->assertEquals($expected, $actual['EntityOne']); @@ -75,22 +139,134 @@ public function testGetAllObjects() */ public function testGetObject() { - // Call the method under test + $this->setUpMockDataObjectHander(self::PARSER_OUTPUT); + // Call the method under test $actual = DataObjectHandler::getInstance()->getObject('EntityOne'); // Assert - $expected = new EntityDataObject('EntityOne', 'testType', ['testkey' => 'testValue'], [], null, []); $this->assertEquals($expected, $actual); } /** - * getObject should return null if the data object does not exist + * getAllObjects should return the expected data object if it exists */ public function testGetObjectNull() { + $this->setUpMockDataObjectHander(self::PARSER_OUTPUT); + $actual = DataObjectHandler::getInstance()->getObject('h953u789h0g73t521'); // doesnt exist $this->assertNull($actual); } + + /** + * getAllObjects should contain the expected data object with extends + */ + public function testGetAllObjectsWithDataExtends() + { + $this->setUpMockDataObjectHander(self::PARSER_OUTPUT_WITH_EXTEND); + + // Call the method under test + $actual = DataObjectHandler::getInstance()->getAllObjects(); + + // Assert + $expected = new EntityDataObject( + 'EntityTwo', + 'testType', + ['testkey' => 'testValue', 'testkeytwo' => 'testValueTwo'], + [], + null, + [], + 'EntityOne' + ); + $this->assertArrayHasKey('EntityTwo', $actual); + $this->assertEquals($expected, $actual['EntityTwo']); + } + + /** + * getObject should return the expected data object with extended data if it exists + */ + public function testGetObjectWithDataExtends() + { + $this->setUpMockDataObjectHander(self::PARSER_OUTPUT_WITH_EXTEND); + + // Call the method under test + $actual = DataObjectHandler::getInstance()->getObject('EntityTwo'); + + // Assert + $expected = new EntityDataObject( + 'EntityTwo', + 'testType', + ['testkey' => 'testValue', 'testkeytwo' => 'testValueTwo'], + [], + null, + [], + 'EntityOne' + ); + $this->assertEquals($expected, $actual); + } + + /** + * getAllObjects should throw TestFrameworkException exception if some data extends itself + */ + public function testGetAllObjectsWithDataExtendsItself() + { + $this->setUpMockDataObjectHander(self::PARSER_OUTPUT_WITH_EXTEND_INVALID); + + $this->expectException(\Magento\FunctionalTestingFramework\Exceptions\TestFrameworkException::class); + $this->expectExceptionMessage( + "Mftf Data can not extend from itself: " + . self::PARSER_OUTPUT_WITH_EXTEND_INVALID['entity']['EntityOne']['name'] + ); + + // Call the method under test + DataObjectHandler::getInstance()->getAllObjects(); + } + + /** + * getObject should throw TestFrameworkException exception if requested data extends itself + */ + public function testGetObjectWithDataExtendsItself() + { + $this->setUpMockDataObjectHander(self::PARSER_OUTPUT_WITH_EXTEND_INVALID); + + $this->expectException(\Magento\FunctionalTestingFramework\Exceptions\TestFrameworkException::class); + $this->expectExceptionMessage( + "Mftf Data can not extend from itself: " + . self::PARSER_OUTPUT_WITH_EXTEND_INVALID['entity']['EntityOne']['name'] + ); + + // Call the method under test + DataObjectHandler::getInstance()->getObject( + self::PARSER_OUTPUT_WITH_EXTEND_INVALID['entity']['EntityOne']['name'] + ); + } + + /** + * Set up everything required to mock DataObjectHander::getInstance() + * The first call to getInstance() uses these mocks to emulate the parser, initializing internal state + * according to the PARSER_OUTPUT value + * + * @param array $entityDataArray + */ + private function setUpMockDataObjectHander($entityDataArray) + { + // Clear DataObjectHandler singleton if already set + $property = new \ReflectionProperty(DataObjectHandler::class, "INSTANCE"); + $property->setAccessible(true); + $property->setValue(null); + + $mockDataProfileSchemaParser = AspectMock::double(DataProfileSchemaParser::class, [ + 'readDataProfiles' => $entityDataArray + ])->make(); + + $mockObjectManager = AspectMock::double(ObjectManager::class, [ + 'create' => $mockDataProfileSchemaParser + ])->make(); + + AspectMock::double(ObjectManagerFactory::class, [ + 'getObjectManager' => $mockObjectManager + ]); + } } diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/Test/Handlers/ActionGroupObjectHandlerTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/Test/Handlers/ActionGroupObjectHandlerTest.php new file mode 100644 index 000000000..4a7c6101e --- /dev/null +++ b/dev/tests/unit/Magento/FunctionalTestFramework/Test/Handlers/ActionGroupObjectHandlerTest.php @@ -0,0 +1,98 @@ +withName($nameOne) + ->withExtendedAction($nameOne) + ->withAnnotations() + ->withFilename() + ->withActionObjects() + ->build(); + $this->setMockParserOutput(['actionGroups' => $actionGroupOne]); + + $handler = ActionGroupObjectHandler::getInstance(); + + $this->expectException(\Magento\FunctionalTestingFramework\Exceptions\TestFrameworkException::class); + $this->expectExceptionMessage("Mftf Action Group can not extend from itself: " . $nameOne); + $handler->getObject('actionGroupOne'); + } + + /** + * getAllObjects should throw exception if test extends from itself + * + * @throws \Exception + */ + public function testGetAllTestObjectsWithInvalidExtends() + { + // Set up action group data + $nameOne = 'actionGroupOne'; + $nameTwo = 'actionGroupTwo'; + $actionGroupOne = (new ActionGroupArrayBuilder()) + ->withName($nameOne) + ->withExtendedAction($nameOne) + ->withAnnotations() + ->withFilename() + ->withActionObjects() + ->build(); + $actionGroupTwo = (new ActionGroupArrayBuilder()) + ->withName($nameTwo) + ->withExtendedAction() + ->withAnnotations() + ->withFilename() + ->withActionObjects() + ->build(); + + $this->setMockParserOutput(['actionGroups' => array_merge($actionGroupOne, $actionGroupTwo)]); + + $handler = ActionGroupObjectHandler::getInstance(); + + $this->expectException(\Magento\FunctionalTestingFramework\Exceptions\TestFrameworkException::class); + $this->expectExceptionMessage("Mftf Action Group can not extend from itself: " . $nameOne); + $handler->getAllObjects(); + } + + /** + * Function used to set mock for parser return and force init method to run between tests. + * + * @param array $data + * @throws \Exception + */ + private function setMockParserOutput($data) + { + // Clear action group object handler value to inject parsed content + $property = new \ReflectionProperty(ActionGroupObjectHandler::class, 'instance'); + $property->setAccessible(true); + $property->setValue(null); + + $mockDataParser = AspectMock::double(ActionGroupDataParser::class, ['readActionGroupData' => $data])->make(); + $instance = AspectMock::double(ObjectManager::class, ['create' => $mockDataParser]) + ->make(); // bypass the private constructor + AspectMock::double(ObjectManagerFactory::class, ['getObjectManager' => $instance]); + } +} diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/Test/Handlers/TestObjectHandlerTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/Test/Handlers/TestObjectHandlerTest.php index 1dbeb50db..a94c41ae4 100644 --- a/dev/tests/unit/Magento/FunctionalTestFramework/Test/Handlers/TestObjectHandlerTest.php +++ b/dev/tests/unit/Magento/FunctionalTestFramework/Test/Handlers/TestObjectHandlerTest.php @@ -180,6 +180,68 @@ public function testGetTestWithModuleName() $this->assertEquals($moduleExpected, $moduleName); } + /** + * getObject should throw exception if test extends from itself + * + * @throws \Exception + */ + public function testGetTestObjectWithInvalidExtends() + { + // set up Test Data + $testOne = (new TestDataArrayBuilder()) + ->withName('testOne') + ->withTestReference('testOne') + ->withAnnotations() + ->withFailedHook() + ->withAfterHook() + ->withBeforeHook() + ->withTestActions() + ->build(); + $this->setMockParserOutput(['tests' => $testOne]); + + $toh = TestObjectHandler::getInstance(); + + $this->expectException(\Magento\FunctionalTestingFramework\Exceptions\TestFrameworkException::class); + $this->expectExceptionMessage("Mftf Test can not extend from itself: " . "testOne"); + + $toh->getObject('testOne'); + } + + /** + * getAllObjects should throw exception if test extends from itself + * + * @throws \Exception + */ + public function testGetAllTestObjectsWithInvalidExtends() + { + // set up Test Data + $testOne = (new TestDataArrayBuilder()) + ->withName('testOne') + ->withTestReference('testOne') + ->withAnnotations() + ->withFailedHook() + ->withAfterHook() + ->withBeforeHook() + ->withTestActions() + ->build(); + $testTwo = (new TestDataArrayBuilder()) + ->withName('testTwo') + ->withAnnotations() + ->withFailedHook() + ->withAfterHook() + ->withBeforeHook() + ->withTestActions() + ->build(); + + $this->setMockParserOutput(['tests' => array_merge($testOne, $testTwo)]); + + $toh = TestObjectHandler::getInstance(); + + $this->expectException(\Magento\FunctionalTestingFramework\Exceptions\TestFrameworkException::class); + $this->expectExceptionMessage("Mftf Test can not extend from itself: " . "testOne"); + $toh->getAllObjects(); + } + /** * Function used to set mock for parser return and force init method to run between tests. * diff --git a/dev/tests/unit/Magento/FunctionalTestFramework/Test/Util/ObjectExtensionUtilTest.php b/dev/tests/unit/Magento/FunctionalTestFramework/Test/Util/ObjectExtensionUtilTest.php index b023b16c7..ce184e564 100644 --- a/dev/tests/unit/Magento/FunctionalTestFramework/Test/Util/ObjectExtensionUtilTest.php +++ b/dev/tests/unit/Magento/FunctionalTestFramework/Test/Util/ObjectExtensionUtilTest.php @@ -263,7 +263,7 @@ public function testGenerateExtendedActionGroupNoParent() { $mockExtendedActionGroup = [ "nodeName" => "actionGroup", - "name" => "mockSimpleActionGroup", + "name" => "mockExtendedActionGroup", "filename" => "someFile", "extends" => "mockSimpleActionGroup", "commentHere" => [ @@ -281,7 +281,7 @@ public function testGenerateExtendedActionGroupNoParent() $this->setMockTestOutput(null, $mockActionGroupData); $this->expectExceptionMessage( - "Parent Action Group mockSimpleActionGroup not defined for Test " . $mockExtendedActionGroup['extends'] + "Parent Action Group mockSimpleActionGroup not defined for Test " . $mockExtendedActionGroup['name'] ); // parse and generate test object with mocked data @@ -309,7 +309,7 @@ public function testExtendingExtendedActionGroup() $mockExtendedActionGroup = [ "nodeName" => "actionGroup", - "name" => "mockSimpleActionGroup", + "name" => "mockExtendedActionGroup", "filename" => "someFile", "extends" => "mockSimpleActionGroup", ]; @@ -336,7 +336,7 @@ public function testExtendingExtendedActionGroup() 'error', "Cannot extend an action group that already extends another action group. " . $mockSimpleActionGroup['name'], - ['parent' => $mockSimpleActionGroup['name'], 'actionGroup' => $mockSimpleActionGroup['name']] + ['parent' => $mockSimpleActionGroup['name'], 'actionGroup' => $mockExtendedActionGroup['name']] ); throw $e; diff --git a/dev/tests/unit/Util/ActionGroupArrayBuilder.php b/dev/tests/unit/Util/ActionGroupArrayBuilder.php new file mode 100644 index 000000000..14877f4dd --- /dev/null +++ b/dev/tests/unit/Util/ActionGroupArrayBuilder.php @@ -0,0 +1,170 @@ +name = $name; + return $this; + } + + /** + * Setter for action group annotations + * + * @param array $annotations + * @return $this + */ + public function withAnnotations($annotations = []) + { + $this->annotations = $annotations; + return $this; + } + + /** + * Setter for action group arguments + * + * @param array $args + * @return $this + */ + public function withArguments($args = []) + { + $this->arguments = $args; + return $this; + } + + /** + * Setter for action group actions + * + * @param array $actionObjs + * @return $this + */ + public function withActionObjects($actionObjs = []) + { + if (!empty($actionObjs)) { + $this->actionObjects = $actionObjs; + } + return $this; + } + + /** + * Setter for action group extended action group name + * + * @param string $extendedActionGroup + * @return $this + */ + public function withExtendedAction($extendedActionGroup = null) + { + $this->extends = $extendedActionGroup; + return $this; + } + + /** + * Setter for action group filename + * + * @param string $filename + * @return $this + */ + public function withFilename($filename = '') + { + if (empty($filename)) { + $this->filename = "/magento2-functional-testing-framework/dev/tests/verification/" + . "TestModule/ActionGroup/BasicActionGroup.xml"; + } else { + $this->filename = $filename; + } + + return $this; + } + + /** + * ActionGroupArrayBuilder constructor + */ + public function __construct() + { + $this->actionObjects = [ + self::DEFAULT_ACTION_GROUP_KEY => [ + ActionObjectExtractor::NODE_NAME => 'testActionType', + ActionObjectExtractor::TEST_STEP_MERGE_KEY => self::DEFAULT_ACTION_GROUP_KEY, + ] + ]; + } + + /** + * Function which takes builder parameters and returns an action group array + * + * @return array + */ + public function build() + { + // Build and return action group array + return [$this->name => array_merge( + [ + ActionGroupObjectExtractor::NAME => $this->name, + ActionGroupObjectExtractor::ACTION_GROUP_ANNOTATIONS => $this->annotations, + ActionGroupObjectExtractor::ACTION_GROUP_ARGUMENTS => $this->arguments, + ActionGroupObjectExtractor::FILENAME => $this->filename, + ActionGroupObjectExtractor::EXTENDS_ACTION_GROUP => $this->extends + ], + $this->actionObjects + )]; + } +} diff --git a/src/Magento/FunctionalTestingFramework/DataGenerator/Handlers/DataObjectHandler.php b/src/Magento/FunctionalTestingFramework/DataGenerator/Handlers/DataObjectHandler.php index 7cc9e8a0e..95a2b8b93 100644 --- a/src/Magento/FunctionalTestingFramework/DataGenerator/Handlers/DataObjectHandler.php +++ b/src/Magento/FunctionalTestingFramework/DataGenerator/Handlers/DataObjectHandler.php @@ -8,6 +8,7 @@ use Magento\FunctionalTestingFramework\DataGenerator\Objects\EntityDataObject; use Magento\FunctionalTestingFramework\DataGenerator\Parsers\DataProfileSchemaParser; +use Magento\FunctionalTestingFramework\Exceptions\TestFrameworkException; use Magento\FunctionalTestingFramework\Exceptions\XmlException; use Magento\FunctionalTestingFramework\ObjectManager\ObjectHandlerInterface; use Magento\FunctionalTestingFramework\ObjectManagerFactory; @@ -272,10 +273,14 @@ private function processVarElements($entityData) * * @param EntityDataObject $dataObject * @return EntityDataObject + * @throws TestFrameworkException */ private function extendDataObject($dataObject) { if ($dataObject->getParentName() != null) { + if ($dataObject->getParentName() == $dataObject->getName()) { + throw new TestFrameworkException("Mftf Data can not extend from itself: " . $dataObject->getName()); + } return $this->extendUtil->extendEntity($dataObject); } return $dataObject; diff --git a/src/Magento/FunctionalTestingFramework/Test/Handlers/ActionGroupObjectHandler.php b/src/Magento/FunctionalTestingFramework/Test/Handlers/ActionGroupObjectHandler.php index 18a6402ea..131ae0a26 100644 --- a/src/Magento/FunctionalTestingFramework/Test/Handlers/ActionGroupObjectHandler.php +++ b/src/Magento/FunctionalTestingFramework/Test/Handlers/ActionGroupObjectHandler.php @@ -5,6 +5,7 @@ */ namespace Magento\FunctionalTestingFramework\Test\Handlers; +use Magento\FunctionalTestingFramework\Exceptions\TestFrameworkException; use Magento\FunctionalTestingFramework\ObjectManager\ObjectHandlerInterface; use Magento\FunctionalTestingFramework\ObjectManagerFactory; use Magento\FunctionalTestingFramework\Test\Objects\ActionGroupObject; @@ -124,10 +125,16 @@ private function initActionGroups() * * @param ActionGroupObject $actionGroupObject * @return ActionGroupObject + * @throws TestFrameworkException */ private function extendActionGroup($actionGroupObject): ActionGroupObject { if ($actionGroupObject->getParentName() !== null) { + if ($actionGroupObject->getParentName() == $actionGroupObject->getName()) { + throw new TestFrameworkException( + "Mftf Action Group can not extend from itself: " . $actionGroupObject->getName() + ); + } return $this->extendUtil->extendActionGroup($actionGroupObject); } return $actionGroupObject; diff --git a/src/Magento/FunctionalTestingFramework/Test/Handlers/TestObjectHandler.php b/src/Magento/FunctionalTestingFramework/Test/Handlers/TestObjectHandler.php index 1c0f7e2fc..a0d490df5 100644 --- a/src/Magento/FunctionalTestingFramework/Test/Handlers/TestObjectHandler.php +++ b/src/Magento/FunctionalTestingFramework/Test/Handlers/TestObjectHandler.php @@ -6,6 +6,7 @@ namespace Magento\FunctionalTestingFramework\Test\Handlers; use Magento\FunctionalTestingFramework\Exceptions\Collector\ExceptionCollector; +use Magento\FunctionalTestingFramework\Exceptions\TestFrameworkException; use Magento\FunctionalTestingFramework\Exceptions\TestReferenceException; use Magento\FunctionalTestingFramework\Exceptions\XmlException; use Magento\FunctionalTestingFramework\ObjectManager\ObjectHandlerInterface; @@ -160,10 +161,14 @@ private function initTestData() * * @param TestObject $testObject * @return TestObject + * @throws TestFrameworkException */ private function extendTest($testObject) { if ($testObject->getParentName() !== null) { + if ($testObject->getParentName() == $testObject->getName()) { + throw new TestFrameworkException("Mftf Test can not extend from itself: " . $testObject->getName()); + } return $this->extendUtil->extendTest($testObject); } return $testObject;