Skip to content

Commit 2e8b13a

Browse files
floriankraemerFlorian Krämer
andauthored
Increase Code Coverage (#18)
* Enhance TestClass with additional methods and corresponding tests for method signature validation - Added new methods to TestClass to cover various scenarios including max parameters, name mismatches, nullable types, class types, protected visibility, and valid method signatures. - Updated MethodSignatureMustMatchRuleTest to include tests for the new methods, ensuring proper validation of method signatures against defined patterns and visibility requirements. - Improved error reporting for parameter mismatches and added checks for new method scenarios. * Add TooManyArgumentsClass and related tests for argument validation - Introduced TooManyArgumentsClass with a valid method and two new classes: TooManyArgsService and TooManyArgsOther, each containing methods with excessive arguments. - Updated TooManyArgumentsRuleTest to include tests for the new classes, ensuring proper error reporting for methods exceeding the allowed argument limit. - Enhanced ClassMustBeReadonlyRuleTest with a test for valid readonly classes to prevent false positives. --------- Co-authored-by: Florian Krämer <f.kraemer@clipmyhorse.tv>
1 parent 229a0c0 commit 2e8b13a

12 files changed

+340
-21
lines changed
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace App\Controller;
6+
7+
readonly class ValidReadonlyController
8+
{
9+
// This class is already readonly, so no error should be reported
10+
}
11+
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
<?php
2+
3+
namespace App;
4+
5+
class MaxLineLengthMultipleLines // This line is exactly 95 characters long to test multiple violations in one file
6+
{
7+
public function methodWithMultipleVeryLongLinesThatExceedTheMaximumAllowedLengthOfEightyCharacters(): void
8+
{
9+
$variable = 'This is a short line';
10+
// All good here
11+
}
12+
}
13+

data/MethodSignatureMustMatch/TestClass.php

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
<?php
22

3+
class DummyClass
4+
{
5+
}
6+
37
class TestClass
48
{
59
public function testMethod(int $a)
@@ -13,4 +17,39 @@ public function testMethodNoType($x, string $y)
1317
public function testMethodWithWrongType(int $x, int $y)
1418
{
1519
}
20+
21+
// Test max parameters violation
22+
public function testMaxParams(int $a, string $b, int $c, string $d)
23+
{
24+
}
25+
26+
// Test parameter name pattern mismatch
27+
public function testNameMismatch(int $wrongName, string $anotherWrong)
28+
{
29+
}
30+
31+
// Test nullable types
32+
public function testNullableTypes(?int $nullableInt, ?string $nullableString)
33+
{
34+
}
35+
36+
// Test class types
37+
public function testClassTypes(DummyClass $dummy, string $name)
38+
{
39+
}
40+
41+
// Test protected visibility
42+
protected function testProtectedMethod(int $value)
43+
{
44+
}
45+
46+
// Test method without visibility requirement (should pass)
47+
public function testNoVisibilityReq(int $x)
48+
{
49+
}
50+
51+
// Test valid method matching all criteria
52+
public function testValidMethod(int $alpha, string $beta)
53+
{
54+
}
1655
}

data/TooManyArgumentsClass.php

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,4 +8,29 @@ public function methodWithTooManyArguments(int $arg1, int $arg2, int $arg3, int
88
{
99
// Method implementation
1010
}
11+
12+
public function validMethod(int $arg1, int $arg2): void
13+
{
14+
// Valid method with acceptable number of arguments
15+
}
16+
}
17+
18+
namespace App\Service;
19+
20+
class TooManyArgsService
21+
{
22+
public function methodWithTooManyArguments(int $a, int $b, int $c, int $d, int $e): void
23+
{
24+
// This should trigger error when pattern matches Service
25+
}
26+
}
27+
28+
namespace App\Other;
29+
30+
class TooManyArgsOther
31+
{
32+
public function methodWithTooManyArguments(int $a, int $b, int $c, int $d, int $e): void
33+
{
34+
// This should NOT trigger error when pattern doesn't match
35+
}
1136
}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Phauthentic\PHPStanRules\Tests\TestCases\Architecture;
6+
7+
use Phauthentic\PHPStanRules\Architecture\ClassMustBeFinalRule;
8+
use PHPStan\Testing\RuleTestCase;
9+
10+
/**
11+
* @extends RuleTestCase<ClassMustBeFinalRule>
12+
*/
13+
class ClassMustBeFinalRuleWithAbstractNotIgnoredTest extends RuleTestCase
14+
{
15+
protected function getRule(): \PHPStan\Rules\Rule
16+
{
17+
// Do NOT ignore abstract classes
18+
return new ClassMustBeFinalRule(
19+
patterns: ['/Service$/'],
20+
ignoreAbstractClasses: false
21+
);
22+
}
23+
24+
public function testConcreteClassMustBeFinal(): void
25+
{
26+
// Test that concrete (non-abstract) classes are checked when ignoreAbstractClasses is false
27+
// This ensures the flag doesn't prevent checking of regular classes
28+
$this->analyse([__DIR__ . '/../../../data/Service/MissingFinalRuleService.php'], [
29+
[
30+
'Class App\Service\MissingFinalRuleService must be final.',
31+
5,
32+
],
33+
]);
34+
}
35+
}
36+

tests/TestCases/Architecture/ClassMustBeReadonlyRuleTest.php

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,4 +34,10 @@ public function testRule(): void
3434
// the test fails, if the expected error does not occur,
3535
// or if there are other errors reported beside the expected one
3636
}
37+
38+
public function testValidReadonlyClass(): void
39+
{
40+
// Test that readonly classes don't trigger errors
41+
$this->analyse([__DIR__ . '/../../../data/Controller/ValidReadonlyController.php'], []);
42+
}
3743
}

tests/TestCases/Architecture/MethodSignatureMustMatchRuleTest.php

Lines changed: 95 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,71 @@ protected function getRule(): Rule
4646
],
4747
'visibilityScope' => 'public',
4848
],
49+
[
50+
'pattern' => '/^TestClass::testMaxParams$/',
51+
'minParameters' => 1,
52+
'maxParameters' => 2,
53+
'signature' => [],
54+
'visibilityScope' => 'public',
55+
],
56+
[
57+
'pattern' => '/^TestClass::testNameMismatch$/',
58+
'minParameters' => 2,
59+
'maxParameters' => 2,
60+
'signature' => [
61+
['type' => 'int', 'pattern' => '/^param/'], // Name pattern doesn't match
62+
['type' => 'string', 'pattern' => '/^param/'], // Name pattern doesn't match
63+
],
64+
'visibilityScope' => 'public',
65+
],
66+
[
67+
'pattern' => '/^TestClass::testNullableTypes$/',
68+
'minParameters' => 2,
69+
'maxParameters' => 2,
70+
'signature' => [
71+
['type' => '?int', 'pattern' => '/^nullable/'],
72+
['type' => '?string', 'pattern' => '/^nullable/'],
73+
],
74+
'visibilityScope' => 'public',
75+
],
76+
[
77+
'pattern' => '/^TestClass::testClassTypes$/',
78+
'minParameters' => 2,
79+
'maxParameters' => 2,
80+
'signature' => [
81+
['type' => 'DummyClass', 'pattern' => '/^dummy/'],
82+
['type' => 'string', 'pattern' => '/^name/'],
83+
],
84+
'visibilityScope' => 'public',
85+
],
86+
[
87+
'pattern' => '/^TestClass::testProtectedMethod$/',
88+
'minParameters' => 1,
89+
'maxParameters' => 1,
90+
'signature' => [
91+
['type' => 'int', 'pattern' => '/^value/'],
92+
],
93+
'visibilityScope' => 'protected',
94+
],
95+
[
96+
'pattern' => '/^TestClass::testNoVisibilityReq$/',
97+
'minParameters' => 1,
98+
'maxParameters' => 1,
99+
'signature' => [
100+
['type' => 'int', 'pattern' => '/^x/'],
101+
],
102+
// No visibilityScope specified
103+
],
104+
[
105+
'pattern' => '/^TestClass::testValidMethod$/',
106+
'minParameters' => 2,
107+
'maxParameters' => 2,
108+
'signature' => [
109+
['type' => 'int', 'pattern' => '/^alpha/'],
110+
['type' => 'string', 'pattern' => '/^beta/'],
111+
],
112+
'visibilityScope' => 'public',
113+
],
49114
]);
50115
}
51116

@@ -55,15 +120,15 @@ public function testRule(): void
55120
// Errors for testMethod (type checking enabled)
56121
[
57122
'Method TestClass::testMethod has 1 parameters, but at least 2 required.',
58-
5,
123+
9,
59124
],
60125
[
61126
'Method TestClass::testMethod is missing parameter #2 of type string.',
62-
5,
127+
9,
63128
],
64129
[
65130
'Method TestClass::testMethod must be private.',
66-
5,
131+
9,
67132
],
68133
// No errors for testMethodNoType since:
69134
// - First parameter has no type specified, so type checking is skipped
@@ -76,8 +141,34 @@ public function testRule(): void
76141
// - Second parameter has no type specified, so type checking is skipped
77142
[
78143
'Method TestClass::testMethodWithWrongType parameter #1 should be of type string, int given.',
79-
13,
144+
17,
145+
],
146+
147+
// Errors for testMaxParams - exceeds max parameters
148+
[
149+
'Method TestClass::testMaxParams has 4 parameters, but at most 2 allowed.',
150+
22,
151+
],
152+
153+
// Errors for testNameMismatch - parameter names don't match patterns
154+
[
155+
'Method TestClass::testNameMismatch parameter #1 name "wrongName" does not match pattern /^param/.',
156+
27,
157+
],
158+
[
159+
'Method TestClass::testNameMismatch parameter #2 name "anotherWrong" does not match pattern /^param/.',
160+
27,
80161
],
162+
163+
// No errors for testNullableTypes - nullable types should match correctly
164+
165+
// No errors for testClassTypes - class types should match correctly
166+
167+
// No errors for testProtectedMethod - protected visibility matches
168+
169+
// No errors for testNoVisibilityReq - no visibility requirement specified
170+
171+
// No errors for testValidMethod - everything matches correctly
81172
]);
82173
}
83174
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Phauthentic\PHPStanRules\Tests\TestCases\CleanCode;
6+
7+
use Phauthentic\PHPStanRules\CleanCode\MaxLineLengthRule;
8+
use PHPStan\Rules\Rule;
9+
use PHPStan\Testing\RuleTestCase;
10+
11+
/**
12+
* @extends RuleTestCase<MaxLineLengthRule>
13+
*/
14+
class MaxLineLengthRuleIgnoreUseTest extends RuleTestCase
15+
{
16+
protected function getRule(): Rule
17+
{
18+
// Ignore use statements (3rd parameter is true)
19+
return new MaxLineLengthRule(80, [], true);
20+
}
21+
22+
public function testUseStatementsAreIgnored(): void
23+
{
24+
// All use statements in this file are very long, but should be ignored
25+
$this->analyse([__DIR__ . '/../../../data/MaxLineLengthUseStatementsClass.php'], []);
26+
}
27+
}
28+

tests/TestCases/CleanCode/MaxLineLengthRuleTest.php

Lines changed: 7 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -28,28 +28,18 @@ public function testRule(): void
2828
]);
2929
}
3030

31-
public function testRuleWithExcludePatterns(): void
31+
public function testMultipleLongLinesInFile(): void
3232
{
33-
$rule = new MaxLineLengthRule(80, ['/.*Excluded.*/']);
34-
35-
$this->analyse([__DIR__ . '/../../../data/MaxLineLengthExcludedClass.php'], [
33+
// Test that multiple long lines in the same file are all detected
34+
$this->analyse([__DIR__ . '/../../../data/MaxLineLengthMultipleLines.php'], [
3635
[
37-
'Line 7 exceeds the maximum length of 80 characters (found 81 characters).',
38-
7,
36+
'Line 5 exceeds the maximum length of 80 characters (found 115 characters).',
37+
5,
3938
],
4039
[
41-
'Line 9 exceeds the maximum length of 80 characters (found 86 characters).',
42-
9,
40+
'Line 7 exceeds the maximum length of 80 characters (found 110 characters).',
41+
7,
4342
],
4443
]);
4544
}
46-
47-
48-
49-
public function testRuleWithIgnoreUseStatements(): void
50-
{
51-
$rule = new MaxLineLengthRule(80, [], true);
52-
53-
$this->analyse([__DIR__ . '/../../../data/MaxLineLengthUseStatementsClass.php'], []);
54-
}
5545
}
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Phauthentic\PHPStanRules\Tests\TestCases\CleanCode;
6+
7+
use Phauthentic\PHPStanRules\CleanCode\MaxLineLengthRule;
8+
use PHPStan\Rules\Rule;
9+
use PHPStan\Testing\RuleTestCase;
10+
11+
/**
12+
* @extends RuleTestCase<MaxLineLengthRule>
13+
*/
14+
class MaxLineLengthRuleWithExclusionTest extends RuleTestCase
15+
{
16+
protected function getRule(): Rule
17+
{
18+
// Exclude files matching "Excluded" in their path
19+
return new MaxLineLengthRule(80, ['/.*Excluded.*/']);
20+
}
21+
22+
public function testExcludedFileIsNotChecked(): void
23+
{
24+
// This file should be excluded, so no errors should be reported
25+
$this->analyse([__DIR__ . '/../../../data/MaxLineLengthExcludedClass.php'], []);
26+
}
27+
28+
public function testNonExcludedFileIsChecked(): void
29+
{
30+
// This file is NOT excluded, so errors should be reported
31+
$this->analyse([__DIR__ . '/../../../data/MaxLineLengthTestClass.php'], [
32+
[
33+
'Line 7 exceeds the maximum length of 80 characters (found 84 characters).',
34+
7,
35+
],
36+
]);
37+
}
38+
}
39+

0 commit comments

Comments
 (0)