Skip to content

Commit 0331f7e

Browse files
committed
MQE-1676: Add a static-check that ensures action groups do not have unused arguments
1 parent e344c6f commit 0331f7e

File tree

3 files changed

+216
-2
lines changed

3 files changed

+216
-2
lines changed

src/Magento/FunctionalTestingFramework/StaticCheck/StaticChecksList.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ public function __construct(array $checks = [])
2929
{
3030
$this->checks = [
3131
'testDependencies' => new TestDependencyCheck(),
32+
'unusedArgumentsCheck' => new UnusedArgumentsCheck(),
3233
] + $checks;
3334
}
3435

Lines changed: 212 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,212 @@
1+
<?php
2+
/**
3+
* Copyright © Magento, Inc. All rights reserved.
4+
* See COPYING.txt for license details.
5+
*/
6+
7+
namespace Magento\FunctionalTestingFramework\StaticCheck;
8+
9+
use Magento\FunctionalTestingFramework\Config\MftfApplicationConfig;
10+
use Magento\FunctionalTestingFramework\Test\Handlers\ActionGroupObjectHandler;
11+
use Symfony\Component\Console\Input\InputInterface;
12+
use Exception;
13+
14+
/**
15+
* Class UnusedArgumentsCheck
16+
* @package Magento\FunctionalTestingFramework\StaticCheck
17+
* @SuppressWarnings(PHPMD.CouplingBetweenObjects)
18+
*/
19+
class UnusedArgumentsCheck implements StaticCheckInterface
20+
{
21+
22+
/**
23+
* Array containing all errors found after running the execute() function.
24+
* @var array
25+
*/
26+
private $errors = [];
27+
28+
/**
29+
* String representing the output summary found after running the execute() function.
30+
* @var string
31+
*/
32+
private $output;
33+
34+
/**
35+
* Checks unused arguments in action groups and prints out error to file.
36+
*
37+
* @param InputInterface $input
38+
* @return string
39+
* @throws Exception;
40+
*/
41+
public function execute(InputInterface $input)
42+
{
43+
MftfApplicationConfig::create(
44+
true,
45+
MftfApplicationConfig::UNIT_TEST_PHASE,
46+
false,
47+
MftfApplicationConfig::LEVEL_NONE,
48+
true
49+
);
50+
51+
$actionGroups = ActionGroupObjectHandler::getInstance()->initActionGroups();
52+
53+
$unusedArgumentList = $this->buildUnusedArgumentList($actionGroups);
54+
55+
$this->errors += $this->setErrorOutput($unusedArgumentList);
56+
57+
$this->output = $this->printErrorsToFile();
58+
59+
}
60+
61+
/**
62+
* Return array containing all errors found after running the execute() function.
63+
* @return array
64+
*/
65+
public function getErrors()
66+
{
67+
return $this->errors;
68+
}
69+
70+
/**
71+
* Return string of a short human readable result of the check. For example: "No unused arguments found."
72+
* @return string
73+
*/
74+
public function getOutput()
75+
{
76+
return $this->output;
77+
}
78+
79+
/**
80+
* Builds array of action groups => unused arguments
81+
* @param $actionGroups
82+
* @return array
83+
*/
84+
private function buildUnusedArgumentList($actionGroups) {
85+
86+
$actionGroupToArguments = [];
87+
88+
foreach ($actionGroups as $actionGroup) {
89+
$unusedArguments = $this->findUnusedArguments($actionGroup);
90+
if(!empty($unusedArguments)) {
91+
$actionGroupToArguments[$actionGroup->getFilename()][$actionGroup->getName()] = $unusedArguments;
92+
}
93+
}
94+
return $actionGroupToArguments;
95+
}
96+
97+
/**
98+
* Returns unused arguments in an action group.
99+
* @param $actionGroup
100+
* @return array
101+
*/
102+
private function findUnusedArguments($actionGroup) {
103+
104+
$unusedArguments = [];
105+
//extract all action attribute values
106+
$actionAttributeValues = $this->getAllActionAttributeValues($actionGroup);
107+
$argumentList = $actionGroup->getArguments();
108+
foreach ($argumentList as $argument) {
109+
$argumentName = $argument->getName();
110+
//pattern to match all argument references
111+
$pattern = '(.*\.*[\W]+(?<!\.)' . $argumentName . '[\W]+.*)';
112+
if (preg_grep($pattern, $actionAttributeValues)) {
113+
continue;
114+
}
115+
$unusedArguments[] = $argument->getName();
116+
}
117+
return $unusedArguments;
118+
}
119+
120+
/**
121+
* Returns array of all action attribute values in an action group.
122+
* @param $actionGroup
123+
* @return array
124+
*/
125+
private function getAllActionAttributeValues($actionGroup) {
126+
127+
$allAttributeValues = [];
128+
$actions = $actionGroup->getActions();
129+
foreach ($actions as $action) {
130+
$actionAttributeValues = $this->extractAttributeValues($action);
131+
$allAttributeValues = array_merge($allAttributeValues, $actionAttributeValues);
132+
}
133+
return array_unique($allAttributeValues);
134+
}
135+
136+
137+
/**
138+
* Builds and returns flattened attribute value list for an action.
139+
* @param $action
140+
* @return array
141+
*/
142+
private function extractAttributeValues($action) {
143+
144+
$flattenedAttributeValues = [];
145+
$actionAttributes = $action->getCustomActionAttributes();
146+
//check if action has nodes eg. expectedResult, actualResult and flatten array
147+
foreach ($actionAttributes as $attributeName => $attributeValue) {
148+
if (is_array($attributeValue)) {
149+
$flattenedAttributeValues = array_merge($flattenedAttributeValues, array_values($attributeValue));
150+
}
151+
else {
152+
$flattenedAttributeValues[] = $attributeValue;
153+
}
154+
}
155+
return $flattenedAttributeValues;
156+
}
157+
158+
/**
159+
* Builds and returns error output for unused arguments
160+
*
161+
* @param array $unusedArgumentList
162+
* @return mixed
163+
*/
164+
private function setErrorOutput($unusedArgumentList)
165+
{
166+
$testErrors = [];
167+
168+
if (!empty($unusedArgumentList)) {
169+
// Build error output
170+
foreach ($unusedArgumentList as $path => $actionGroupToArguments) {
171+
172+
$errorOutput = "\nFile \"{$path}\"";
173+
$errorOutput .= "\ncontains action group(s) with unused arguments.\n\t\t";
174+
175+
foreach ($actionGroupToArguments as $actionGroup => $arguments) {
176+
$errorOutput .= "\n\t {$actionGroup} has unused argument(s): " . implode(", ", $arguments);
177+
}
178+
$testErrors[$path][] = $errorOutput;
179+
}
180+
}
181+
return $testErrors;
182+
}
183+
184+
/**
185+
* Prints out given errors to file, and returns summary result string
186+
* @return string
187+
*/
188+
private function printErrorsToFile()
189+
{
190+
$errors = $this->getErrors();
191+
192+
if (empty($errors)) {
193+
return "No unused arguments found.";
194+
}
195+
196+
$outputPath = getcwd() . DIRECTORY_SEPARATOR . "mftf-arguments-checks.txt";
197+
$fileResource = fopen($outputPath, 'w');
198+
$header = "MFTF ActionGroup Arguments Check:\n";
199+
fwrite($fileResource, $header);
200+
201+
foreach ($errors as $test => $error) {
202+
fwrite($fileResource, $error[0] . PHP_EOL);
203+
}
204+
205+
fclose($fileResource);
206+
$errorCount = count($errors);
207+
$output = "Unused arguments found across {$errorCount} actionGroup(s). Error details output to {$outputPath}";
208+
209+
return $output;
210+
}
211+
212+
}

src/Magento/FunctionalTestingFramework/Test/Handlers/ActionGroupObjectHandler.php

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -99,10 +99,10 @@ public function getAllObjects(): array
9999
/**
100100
* Method which populates field array with objects from parsed action_group.xml
101101
*
102-
* @return void
102+
* @return array
103103
* @SuppressWarnings(PHPMD.UnusedPrivateMethod)
104104
*/
105-
private function initActionGroups()
105+
public function initActionGroups()
106106
{
107107
$actionGroupParser = ObjectManagerFactory::getObjectManager()->create(ActionGroupDataParser::class);
108108
$parsedActionGroups = $actionGroupParser->readActionGroupData();
@@ -118,6 +118,7 @@ private function initActionGroups()
118118
$this->actionGroups[$actionGroupName] =
119119
$actionGroupObjectExtractor->extractActionGroup($actionGroupData);
120120
}
121+
return $this->actionGroups;
121122
}
122123

123124
/**

0 commit comments

Comments
 (0)