Skip to content
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
11 changes: 11 additions & 0 deletions data/Controller/ValidReadonlyController.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<?php

declare(strict_types=1);

namespace App\Controller;

readonly class ValidReadonlyController
{
// This class is already readonly, so no error should be reported
}

13 changes: 13 additions & 0 deletions data/MaxLineLengthMultipleLines.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<?php

namespace App;

class MaxLineLengthMultipleLines // This line is exactly 95 characters long to test multiple violations in one file
{
public function methodWithMultipleVeryLongLinesThatExceedTheMaximumAllowedLengthOfEightyCharacters(): void
{
$variable = 'This is a short line';
// All good here
}
}

39 changes: 39 additions & 0 deletions data/MethodSignatureMustMatch/TestClass.php
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
<?php

class DummyClass
{
}

class TestClass
{
public function testMethod(int $a)
Expand All @@ -13,4 +17,39 @@ public function testMethodNoType($x, string $y)
public function testMethodWithWrongType(int $x, int $y)
{
}

// Test max parameters violation
public function testMaxParams(int $a, string $b, int $c, string $d)
{
}

// Test parameter name pattern mismatch
public function testNameMismatch(int $wrongName, string $anotherWrong)
{
}

// Test nullable types
public function testNullableTypes(?int $nullableInt, ?string $nullableString)
{
}

// Test class types
public function testClassTypes(DummyClass $dummy, string $name)
{
}

// Test protected visibility
protected function testProtectedMethod(int $value)
{
}

// Test method without visibility requirement (should pass)
public function testNoVisibilityReq(int $x)
{
}

// Test valid method matching all criteria
public function testValidMethod(int $alpha, string $beta)
{
}
}
25 changes: 25 additions & 0 deletions data/TooManyArgumentsClass.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,29 @@ public function methodWithTooManyArguments(int $arg1, int $arg2, int $arg3, int
{
// Method implementation
}

public function validMethod(int $arg1, int $arg2): void
{
// Valid method with acceptable number of arguments
}
}

namespace App\Service;

class TooManyArgsService
{
public function methodWithTooManyArguments(int $a, int $b, int $c, int $d, int $e): void
{
// This should trigger error when pattern matches Service
}
}

namespace App\Other;

class TooManyArgsOther
{
public function methodWithTooManyArguments(int $a, int $b, int $c, int $d, int $e): void
{
// This should NOT trigger error when pattern doesn't match
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
<?php

declare(strict_types=1);

namespace Phauthentic\PHPStanRules\Tests\TestCases\Architecture;

use Phauthentic\PHPStanRules\Architecture\ClassMustBeFinalRule;
use PHPStan\Testing\RuleTestCase;

/**
* @extends RuleTestCase<ClassMustBeFinalRule>
*/
class ClassMustBeFinalRuleWithAbstractNotIgnoredTest extends RuleTestCase
{
protected function getRule(): \PHPStan\Rules\Rule
{
// Do NOT ignore abstract classes
return new ClassMustBeFinalRule(
patterns: ['/Service$/'],
ignoreAbstractClasses: false
);
}

public function testConcreteClassMustBeFinal(): void
{
// Test that concrete (non-abstract) classes are checked when ignoreAbstractClasses is false
// This ensures the flag doesn't prevent checking of regular classes
$this->analyse([__DIR__ . '/../../../data/Service/MissingFinalRuleService.php'], [
[
'Class App\Service\MissingFinalRuleService must be final.',
5,
],
]);
}
}

6 changes: 6 additions & 0 deletions tests/TestCases/Architecture/ClassMustBeReadonlyRuleTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -34,4 +34,10 @@ public function testRule(): void
// the test fails, if the expected error does not occur,
// or if there are other errors reported beside the expected one
}

public function testValidReadonlyClass(): void
{
// Test that readonly classes don't trigger errors
$this->analyse([__DIR__ . '/../../../data/Controller/ValidReadonlyController.php'], []);
}
}
99 changes: 95 additions & 4 deletions tests/TestCases/Architecture/MethodSignatureMustMatchRuleTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,71 @@ protected function getRule(): Rule
],
'visibilityScope' => 'public',
],
[
'pattern' => '/^TestClass::testMaxParams$/',
'minParameters' => 1,
'maxParameters' => 2,
'signature' => [],
'visibilityScope' => 'public',
],
[
'pattern' => '/^TestClass::testNameMismatch$/',
'minParameters' => 2,
'maxParameters' => 2,
'signature' => [
['type' => 'int', 'pattern' => '/^param/'], // Name pattern doesn't match
['type' => 'string', 'pattern' => '/^param/'], // Name pattern doesn't match
],
'visibilityScope' => 'public',
],
[
'pattern' => '/^TestClass::testNullableTypes$/',
'minParameters' => 2,
'maxParameters' => 2,
'signature' => [
['type' => '?int', 'pattern' => '/^nullable/'],
['type' => '?string', 'pattern' => '/^nullable/'],
],
'visibilityScope' => 'public',
],
[
'pattern' => '/^TestClass::testClassTypes$/',
'minParameters' => 2,
'maxParameters' => 2,
'signature' => [
['type' => 'DummyClass', 'pattern' => '/^dummy/'],
['type' => 'string', 'pattern' => '/^name/'],
],
'visibilityScope' => 'public',
],
[
'pattern' => '/^TestClass::testProtectedMethod$/',
'minParameters' => 1,
'maxParameters' => 1,
'signature' => [
['type' => 'int', 'pattern' => '/^value/'],
],
'visibilityScope' => 'protected',
],
[
'pattern' => '/^TestClass::testNoVisibilityReq$/',
'minParameters' => 1,
'maxParameters' => 1,
'signature' => [
['type' => 'int', 'pattern' => '/^x/'],
],
// No visibilityScope specified
],
[
'pattern' => '/^TestClass::testValidMethod$/',
'minParameters' => 2,
'maxParameters' => 2,
'signature' => [
['type' => 'int', 'pattern' => '/^alpha/'],
['type' => 'string', 'pattern' => '/^beta/'],
],
'visibilityScope' => 'public',
],
]);
}

Expand All @@ -55,15 +120,15 @@ public function testRule(): void
// Errors for testMethod (type checking enabled)
[
'Method TestClass::testMethod has 1 parameters, but at least 2 required.',
5,
9,
],
[
'Method TestClass::testMethod is missing parameter #2 of type string.',
5,
9,
],
[
'Method TestClass::testMethod must be private.',
5,
9,
],
// No errors for testMethodNoType since:
// - First parameter has no type specified, so type checking is skipped
Expand All @@ -76,8 +141,34 @@ public function testRule(): void
// - Second parameter has no type specified, so type checking is skipped
[
'Method TestClass::testMethodWithWrongType parameter #1 should be of type string, int given.',
13,
17,
],

// Errors for testMaxParams - exceeds max parameters
[
'Method TestClass::testMaxParams has 4 parameters, but at most 2 allowed.',
22,
],

// Errors for testNameMismatch - parameter names don't match patterns
[
'Method TestClass::testNameMismatch parameter #1 name "wrongName" does not match pattern /^param/.',
27,
],
[
'Method TestClass::testNameMismatch parameter #2 name "anotherWrong" does not match pattern /^param/.',
27,
],

// No errors for testNullableTypes - nullable types should match correctly

// No errors for testClassTypes - class types should match correctly

// No errors for testProtectedMethod - protected visibility matches

// No errors for testNoVisibilityReq - no visibility requirement specified

// No errors for testValidMethod - everything matches correctly
]);
}
}
28 changes: 28 additions & 0 deletions tests/TestCases/CleanCode/MaxLineLengthRuleIgnoreUseTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
<?php

declare(strict_types=1);

namespace Phauthentic\PHPStanRules\Tests\TestCases\CleanCode;

use Phauthentic\PHPStanRules\CleanCode\MaxLineLengthRule;
use PHPStan\Rules\Rule;
use PHPStan\Testing\RuleTestCase;

/**
* @extends RuleTestCase<MaxLineLengthRule>
*/
class MaxLineLengthRuleIgnoreUseTest extends RuleTestCase
{
protected function getRule(): Rule
{
// Ignore use statements (3rd parameter is true)
return new MaxLineLengthRule(80, [], true);
}

public function testUseStatementsAreIgnored(): void
{
// All use statements in this file are very long, but should be ignored
$this->analyse([__DIR__ . '/../../../data/MaxLineLengthUseStatementsClass.php'], []);
}
}

24 changes: 7 additions & 17 deletions tests/TestCases/CleanCode/MaxLineLengthRuleTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -28,28 +28,18 @@ public function testRule(): void
]);
}

public function testRuleWithExcludePatterns(): void
public function testMultipleLongLinesInFile(): void
{
$rule = new MaxLineLengthRule(80, ['/.*Excluded.*/']);

$this->analyse([__DIR__ . '/../../../data/MaxLineLengthExcludedClass.php'], [
// Test that multiple long lines in the same file are all detected
$this->analyse([__DIR__ . '/../../../data/MaxLineLengthMultipleLines.php'], [
[
'Line 7 exceeds the maximum length of 80 characters (found 81 characters).',
7,
'Line 5 exceeds the maximum length of 80 characters (found 115 characters).',
5,
],
[
'Line 9 exceeds the maximum length of 80 characters (found 86 characters).',
9,
'Line 7 exceeds the maximum length of 80 characters (found 110 characters).',
7,
],
]);
}



public function testRuleWithIgnoreUseStatements(): void
{
$rule = new MaxLineLengthRule(80, [], true);

$this->analyse([__DIR__ . '/../../../data/MaxLineLengthUseStatementsClass.php'], []);
}
}
39 changes: 39 additions & 0 deletions tests/TestCases/CleanCode/MaxLineLengthRuleWithExclusionTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
<?php

declare(strict_types=1);

namespace Phauthentic\PHPStanRules\Tests\TestCases\CleanCode;

use Phauthentic\PHPStanRules\CleanCode\MaxLineLengthRule;
use PHPStan\Rules\Rule;
use PHPStan\Testing\RuleTestCase;

/**
* @extends RuleTestCase<MaxLineLengthRule>
*/
class MaxLineLengthRuleWithExclusionTest extends RuleTestCase
{
protected function getRule(): Rule
{
// Exclude files matching "Excluded" in their path
return new MaxLineLengthRule(80, ['/.*Excluded.*/']);
}

public function testExcludedFileIsNotChecked(): void
{
// This file should be excluded, so no errors should be reported
$this->analyse([__DIR__ . '/../../../data/MaxLineLengthExcludedClass.php'], []);
}

public function testNonExcludedFileIsChecked(): void
{
// This file is NOT excluded, so errors should be reported
$this->analyse([__DIR__ . '/../../../data/MaxLineLengthTestClass.php'], [
[
'Line 7 exceeds the maximum length of 80 characters (found 84 characters).',
7,
],
]);
}
}

Loading