Completed
Push — renovate/slack-web-api-6.x ( 1d54b7...bfe495 )
by
unknown
193:23 queued 183:13
created

PHPUnitTestTrait::isTestFile()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
nc 2
nop 2
dl 0
loc 5
rs 10
c 0
b 0
f 0
1
<?php
2
/**
3
 * Hack around insufficiencies in MediaWiki\Sniffs\PHPUnit\PHPUnitTestTrait
4
 *
5
 * @package automattic/jetpack-codesniffer
6
 */
7
8
// phpcs:disable -- Better to keep close to upstream than to follow WP conventions.
9
10
namespace MediaWiki\Sniffs\PHPUnit;
11
12
use PHP_CodeSniffer\Files\File;
13
use PHP_CodeSniffer\Util\Tokens;
14
15
/**
16
 * Check if a class is a test class
17
 *
18
 * @license GPL-2.0-or-later
19
 */
20
trait PHPUnitTestTrait {
21
22
	/**
23
	 * Set of PHPUnit base classes, without leading backslash
24
	 * @var string[]
25
	 */
26
	private static $PHPUNIT_CLASSES = [
27
		// @phan-suppress-previous-line PhanReadOnlyPrivateProperty Traits cannot have constants
28
		'MediaWikiTestCase' => 'MediaWikiTestCase',
29
		'MediaWikiUnitTestCase' => 'MediaWikiUnitTestCase',
30
		'MediaWikiIntegrationTestCase' => 'MediaWikiIntegrationTestCase',
31
		'PHPUnit_Framework_TestCase' => 'PHPUnit_Framework_TestCase',
32
		// This class may be 'use'd, but checking for that would be complicated
33
		'PHPUnit\\Framework\\TestCase' => 'PHPUnit\\Framework\\TestCase',
34
		// HACK: Add WordPress classes
35
		'WP_UnitTestCase' => 'WP_UnitTestCase',
36
		'WP_UnitTestCase_Base' => 'WP_UnitTestCase_Base',
37
	];
38
39
	/**
40
	 * @param File $phpcsFile
41
	 * @param int|false $stackPtr
42
	 *
43
	 * @return bool
44
	 */
45
	private function isTestFile( File $phpcsFile, $stackPtr = false ) {
46
		$classToken = $this->getClassToken( $phpcsFile, $stackPtr ) ?:
47
			$phpcsFile->findNext( Tokens::$ooScopeTokens, 0 );
48
		return $this->isTestClass( $phpcsFile, $classToken );
49
	}
50
51
	/**
52
	 * @param File $phpcsFile
53
	 * @param int|false $classToken Must point at a T_CLASS token
54
	 *
55
	 * @return bool
56
	 */
57
	private function isTestClass( File $phpcsFile, $classToken ) {
58
		$tokens = $phpcsFile->getTokens();
59
		if ( !$classToken || $tokens[$classToken]['code'] !== T_CLASS ) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $classToken of type integer|false is loosely compared to false; this is ambiguous if the integer can be zero. You might want to explicitly use === null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For integer values, zero is a special case, in particular the following results might be unexpected:

0   == false // true
0   == null  // true
123 == false // false
123 == null  // false

// It is often better to use strict comparison
0 === false // false
0 === null  // false
Loading history...
60
			return false;
61
		}
62
63
		$extendedClass = ltrim( $phpcsFile->findExtendedClassName( $classToken ), '\\' );
64
		return array_key_exists( $extendedClass, self::$PHPUNIT_CLASSES ) ||
65
			(bool)preg_match(
66
				'/(?:Test(?:Case)?(?:Base)?|Suite)$/',
67
				$phpcsFile->getDeclarationName( $classToken )
68
			) ||
69
			// HACK: Add logic to look for extending anything ending in "TestCase"
70
			(bool)preg_match( '/(?:Test(?:Case)?(?:Base)?|Suite)$/', $extendedClass );
71
	}
72
73
	/**
74
	 * @param File $phpcsFile
75
	 * @param int $functionToken Token position of the function declaration
76
	 * @return bool
77
	 */
78
	private function isTestFunction( File $phpcsFile, $functionToken ) {
79
		return $this->isTestClass( $phpcsFile, $this->getClassToken( $phpcsFile, $functionToken ) )
80
			&& preg_match( '/^(?:test|provide)|Provider$/', $phpcsFile->getDeclarationName( $functionToken ) );
81
	}
82
83
	/**
84
	 * @param File $phpcsFile
85
	 * @param int|false $stackPtr Should point at the T_CLASS token or a token in the class
86
	 *
87
	 * @return int|false
88
	 */
89
	private function getClassToken( File $phpcsFile, $stackPtr ) {
90
		if ( !$stackPtr ) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $stackPtr of type integer|false is loosely compared to false; this is ambiguous if the integer can be zero. You might want to explicitly use === null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For integer values, zero is a special case, in particular the following results might be unexpected:

0   == false // true
0   == null  // true
123 == false // false
123 == null  // false

// It is often better to use strict comparison
0 === false // false
0 === null  // false
Loading history...
91
			return false;
92
		}
93
94
		$tokens = $phpcsFile->getTokens();
95
		if ( $tokens[$stackPtr]['code'] === T_CLASS ) {
96
			return $stackPtr;
97
		}
98
99
		foreach ( $tokens[$stackPtr]['conditions'] as $ptr => $type ) {
100
			if ( $type === T_CLASS ) {
101
				return $ptr;
102
			}
103
		}
104
105
		return false;
106
	}
107
108
}
109