Skip to content

Commit 73a0928

Browse files
author
Volodymyr Kublytskyi
committed
MAGETWO-64523: Add static test on forbidden "final" keyword and eliminate it usage in code
- covered with unit test - applied code location rules - added copyright
1 parent d44e6f1 commit 73a0928

File tree

4 files changed

+136
-2
lines changed

4 files changed

+136
-2
lines changed

dev/tests/static/framework/Magento/CodeMessDetector/src/Rule/Design/FinalImplementation.php renamed to dev/tests/static/framework/Magento/CodeMessDetector/Rule/Design/FinalImplementation.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,4 +27,4 @@ public function apply(AbstractNode $node)
2727
$this->addViolation($node, [$node->getType(), $node->getFullQualifiedName()]);
2828
}
2929
}
30-
}
30+
}
Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
<?php
2+
/**
3+
* Copyright © 2013-2017 Magento, Inc. All rights reserved.
4+
* See COPYING.txt for license details.
5+
*/
6+
7+
namespace Magento\CodeMessDetector\Test\Unit\Rule\Design;
8+
9+
use PHPUnit_Framework_TestCase as TestCase;
10+
use PHPUnit_Framework_MockObject_MockObject as MockObject;
11+
use PHPUnit_Framework_MockObject_Matcher_InvokedRecorder as InvokedRecorder;
12+
use PHPUnit_Framework_MockObject_Builder_InvocationMocker as InvocationMocker;
13+
use Magento\CodeMessDetector\Rule\Design\FinalImplementation;
14+
use PHPMD\Report;
15+
use PHPMD\AbstractNode;
16+
use PHPMD\Node\ClassNode;
17+
use PHPMD\Node\MethodNode;
18+
use BadMethodCallException;
19+
20+
class FinalImplementationTest extends TestCase
21+
{
22+
/**
23+
* @param string $nodeType
24+
*
25+
* @dataProvider finalizableNodeTypesProvider
26+
*/
27+
public function testRuleNotAppliesToNotFinalFinalizable($nodeType)
28+
{
29+
$finalizableNode = $this->createFinalizableNodeMock($nodeType);
30+
$finalizableNode->method('isFinal')->willReturn(false);
31+
32+
$rule = new FinalImplementation();
33+
$this->expectsRuleViolation($rule, $this->never());
34+
$rule->apply($finalizableNode);
35+
}
36+
37+
/**
38+
* @param string $nodeType
39+
*
40+
* @dataProvider finalizableNodeTypesProvider
41+
*/
42+
public function testRuleAppliesToFinalFinalizable($nodeType)
43+
{
44+
$finalizableNode = $this->createFinalizableNodeMock($nodeType);
45+
$finalizableNode->method('isFinal')->willReturn(true);
46+
47+
$rule = new FinalImplementation();
48+
$this->expectsRuleViolation($rule, $this->once());
49+
$rule->apply($finalizableNode);
50+
}
51+
52+
/**
53+
* @param string $nodeType
54+
*
55+
* @dataProvider finalizableNodeTypesProvider
56+
*/
57+
public function testRuleVerifiesFinalizableNodes($nodeType)
58+
{
59+
$finalizableNode = $this->createFinalizableNodeMock($nodeType);
60+
61+
$finalizableNode->expects($this->atLeastOnce())
62+
->method('isFinal');
63+
64+
$rule = new FinalImplementation();
65+
$rule->apply($finalizableNode);
66+
}
67+
68+
/**
69+
* @expectedException BadMethodCallException
70+
*/
71+
public function testRuleFailsOnNotFinalizableNodes()
72+
{
73+
$someNode = $this->getMockBuilder(AbstractNode::class)
74+
->disableOriginalConstructor()
75+
->getMockForAbstractClass();
76+
77+
$rule = new FinalImplementation();
78+
$rule->apply($someNode);
79+
}
80+
81+
/**
82+
* "final" keyword may be applied only to classes and methods
83+
*
84+
* @return array
85+
*/
86+
public function finalizableNodeTypesProvider()
87+
{
88+
return [
89+
[ClassNode::class],
90+
[MethodNode::class],
91+
];
92+
}
93+
94+
/**
95+
* If node is finalizable it has "isFinal" magic PHP method
96+
*
97+
* @param string $nodeType
98+
* @return ClassNode|MethodNode|MockObject
99+
*/
100+
private function createFinalizableNodeMock($nodeType)
101+
{
102+
$finalizableNode = $this->getMockBuilder($nodeType)
103+
->disableOriginalConstructor()
104+
->disableProxyingToOriginalMethods()
105+
->setMethods([
106+
'isFinal',
107+
// disable name lookup from AST artifact
108+
'getNamespaceName',
109+
'getParentName',
110+
'getName',
111+
])
112+
->getMock();
113+
return $finalizableNode;
114+
}
115+
116+
/**
117+
* @param FinalImplementation $rule
118+
* @param InvokedRecorder $violationExpectation
119+
* @return InvocationMocker
120+
*/
121+
private function expectsRuleViolation(FinalImplementation $rule, InvokedRecorder $violationExpectation)
122+
{
123+
$report = $this->getMockBuilder(Report::class)->getMock();
124+
$invokation = $report->expects($violationExpectation)->method('addRuleViolation');
125+
$rule->setReport($report);
126+
return $invokation;
127+
}
128+
}

dev/tests/static/framework/Magento/CodeMessDetector/resources/rulesets/design.xml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,10 @@
11
<?xml version="1.0"?>
2+
<!--
3+
/**
4+
* Copyright © 2013-2017 Magento, Inc. All rights reserved.
5+
* See COPYING.txt for license details.
6+
*/
7+
-->
28
<ruleset name="Magento Specific Design Rules"
39
xmlns="http://pmd.sf.net/ruleset/1.0.0"
410
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

dev/tests/static/framework/autoload.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
$testsBaseDir . '/../integration/framework/Magento/TestFramework/',
1919
]
2020
);
21-
$autoloadWrapper->addPsr4('Magento\\CodeMessDetector\\', $testsBaseDir . '/framework/Magento/CodeMessDetector/src');
21+
$autoloadWrapper->addPsr4('Magento\\CodeMessDetector\\', $testsBaseDir . '/framework/Magento/CodeMessDetector');
2222

2323
$generatedCode = DirectoryList::getDefaultConfig()[DirectoryList::GENERATED_CODE][DirectoryList::PATH];
2424
$autoloadWrapper->addPsr4('Magento\\', $baseDir . '/' . $generatedCode . '/Magento/');

0 commit comments

Comments
 (0)