Skip to content

MQE-2045: Upgrade script to remove unused arguments #696

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
May 8, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -12,17 +12,16 @@
use Symfony\Component\Finder\Finder;
use Exception;
use Magento\FunctionalTestingFramework\Util\Script\ScriptUtil;
use Symfony\Component\Finder\SplFileInfo;
use DOMElement;

/**
* Class ActionGroupArgumentsCheck
* @package Magento\FunctionalTestingFramework\StaticCheck
*/
class ActionGroupArgumentsCheck implements StaticCheckInterface
{
const ACTIONGROUP_XML_REGEX_PATTERN = '/<actionGroup\sname=(?: (?!<\/actionGroup>).)*/mxs';
const ACTIONGROUP_ARGUMENT_REGEX_PATTERN = '/<argument[^\/>]*name="([^"\']*)/mxs';
const ACTIONGROUP_NAME_REGEX_PATTERN = '/<actionGroup name=["\']([^\'"]*)/';

const ERROR_LOG_FILENAME = 'mftf-arguments-checks';
const ERROR_LOG_MESSAGE = 'MFTF Action Group Unused Arguments Check';

Expand Down Expand Up @@ -97,45 +96,62 @@ public function getOutput()
private function findErrorsInFileSet($files)
{
$actionGroupErrors = [];
/** @var SplFileInfo $filePath */
foreach ($files as $filePath) {
$contents = file_get_contents($filePath);
preg_match_all(self::ACTIONGROUP_XML_REGEX_PATTERN, $contents, $actionGroups);
$actionGroupToArguments = $this->buildUnusedArgumentList($actionGroups[0]);
$actionGroupErrors += $this->setErrorOutput($actionGroupToArguments, $filePath);
$actionGroupToArguments = [];
$contents = $filePath->getContents();
/** @var DOMElement $actionGroup */
$actionGroup = $this->getActionGroupDomElement($contents);
$arguments = $this->extractActionGroupArguments($actionGroup);
$unusedArguments = $this->findUnusedArguments($arguments, $contents);
if (!empty($unusedArguments)) {
$actionGroupToArguments[$actionGroup->getAttribute('name')] = $unusedArguments;
$actionGroupErrors += $this->setErrorOutput($actionGroupToArguments, $filePath);
}
}
return $actionGroupErrors;
}

/**
* Builds array of action group => unused arguments
* @param array $actionGroups
* @return array $actionGroupToArguments
* Extract actionGroup DomElement from xml file
* @param string $contents
* @return \DOMElement
*/
private function buildUnusedArgumentList($actionGroups)
public function getActionGroupDomElement($contents)
{
$actionGroupToArguments = [];
$domDocument = new \DOMDocument();
$domDocument->loadXML($contents);
return $domDocument->getElementsByTagName('actionGroup')[0];
}

foreach ($actionGroups as $actionGroupXml) {
preg_match(self::ACTIONGROUP_NAME_REGEX_PATTERN, $actionGroupXml, $actionGroupName);
$unusedArguments = $this->findUnusedArguments($actionGroupXml);
if (!empty($unusedArguments)) {
$actionGroupToArguments[$actionGroupName[1]] = $unusedArguments;
/**
* Get list of action group arguments declared in an action group
* @param \DOMElement $actionGroup
* @return array $arguments
*/
public function extractActionGroupArguments($actionGroup)
{
$arguments = [];
$argumentsNodes = $actionGroup->getElementsByTagName('arguments');
if ($argumentsNodes->length > 0) {
$argumentNodes = $argumentsNodes[0]->getElementsByTagName('argument');
foreach ($argumentNodes as $argumentNode) {
$arguments[] = $argumentNode->getAttribute('name');
}
}
return $actionGroupToArguments;
return $arguments;
}

/**
* Returns unused arguments in an action group
* @param string $actionGroupXml
* @param array $arguments
* @param string $contents
* @return array
*/
private function findUnusedArguments($actionGroupXml)
public function findUnusedArguments($arguments, $contents)
{
$unusedArguments = [];

preg_match_all(self::ACTIONGROUP_ARGUMENT_REGEX_PATTERN, $actionGroupXml, $arguments);
preg_match(self::ACTIONGROUP_NAME_REGEX_PATTERN, $actionGroupXml, $actionGroupName);
preg_match(self::ACTIONGROUP_NAME_REGEX_PATTERN, $contents, $actionGroupName);
$validActionGroup = false;
try {
$actionGroup = ActionGroupObjectHandler::getInstance()->getObject($actionGroupName[1]);
Expand All @@ -149,18 +165,18 @@ private function findUnusedArguments($actionGroupXml)
return $unusedArguments;
}

foreach ($arguments[1] as $argument) {
foreach ($arguments as $argument) {
//pattern to match all argument references
$patterns = [
'(\{{2}' . $argument . '(\.[a-zA-Z0-9_\[\]\(\).,\'\/ ]+)?}{2})',
'([(,\s\'$$]' . $argument . '(\.[a-zA-Z0-9_$\[\]]+)?[),\s\'])'
];
// matches entity references
if (preg_match($patterns[0], $actionGroupXml)) {
if (preg_match($patterns[0], $contents)) {
continue;
}
//matches parametrized references
if (preg_match($patterns[1], $actionGroupXml)) {
if (preg_match($patterns[1], $contents)) {
continue;
}
//for extending action groups, exclude arguments that are also defined in parent action group
Expand Down Expand Up @@ -196,8 +212,8 @@ private function isParentActionGroupArgument($argument, $actionGroup)
/**
* Builds and returns error output for violating references
*
* @param array $actionGroupToArguments
* @param string $path
* @param array $actionGroupToArguments
* @param SplFileInfo $path
* @return mixed
*/
private function setErrorOutput($actionGroupToArguments, $path)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
<?php
/**
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/

namespace Magento\FunctionalTestingFramework\Upgrade;

use Magento\FunctionalTestingFramework\StaticCheck\ActionGroupArgumentsCheck;
use Magento\FunctionalTestingFramework\Util\Script\ScriptUtil;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Filesystem\Filesystem;
use DOMElement;

/**
* Class RenameMetadataFiles
* @package Magento\FunctionalTestingFramework\Upgrade
*/
class RemoveUnusedArguments implements UpgradeInterface
{
const ARGUMENTS_BLOCK_REGEX_PATTERN = "/\s*<arguments.*\/arguments>/s";

/**
* Updates all actionGroup xml files
*
* @param InputInterface $input
* @param OutputInterface $output
* @return string
*/
public function execute(InputInterface $input, OutputInterface $output)
{
$scriptUtil = new ScriptUtil();
$testPaths[] = $input->getArgument('path');
if (empty($testPaths[0])) {
$testPaths = $scriptUtil->getAllModulePaths();
}
$xmlFiles = $scriptUtil->getModuleXmlFilesByScope($testPaths, 'ActionGroup');
$actionGroupsUpdated = 0;
$fileSystem = new Filesystem();
foreach ($xmlFiles as $file) {
$contents = $file->getContents();
$argumentsCheck = new ActionGroupArgumentsCheck();
/** @var DOMElement $actionGroup */
$actionGroup = $argumentsCheck->getActionGroupDomElement($contents);
$allArguments = $argumentsCheck->extractActionGroupArguments($actionGroup);
$unusedArguments = $argumentsCheck->findUnusedArguments($allArguments, $contents);
if (empty($unusedArguments)) {
continue;
}
//Remove <arguments> block if all arguments are unused
if (empty(array_diff($allArguments, $unusedArguments))) {
$contents = preg_replace(self::ARGUMENTS_BLOCK_REGEX_PATTERN, '', $contents);
} else {
foreach ($unusedArguments as $argument) {
$argumentRegexPattern = "/\s*<argument.*name\s*=\s*\"".$argument."\".*\/>/";
$contents = preg_replace($argumentRegexPattern, '', $contents);
}
}
$fileSystem->dumpFile($file->getRealPath(), $contents);
$actionGroupsUpdated++;
}
return "Removed unused action group arguments from {$actionGroupsUpdated} file(s).";
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ class UpgradeScriptList implements UpgradeScriptListInterface
public function __construct(array $scripts = [])
{
$this->scripts = [
'removeUnusedArguments' => new RemoveUnusedArguments(),
'upgradeTestSchema' => new UpdateTestSchemaPaths(),
'upgradeAssertionSchema' => new UpdateAssertionSchema(),
'renameMetadataFiles' => new RenameMetadataFiles(),
Expand Down