Skip to content

Commit 6b50cc8

Browse files
committed
Merge pull request #104 from WordPoints/develop
2.3.0
2 parents b1ad6e8 + c97c464 commit 6b50cc8

6 files changed

Lines changed: 333 additions & 3 deletions

File tree

CHANGELOG.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,18 @@ All notable changes to this project will be documented in this file.
44
This project adheres to [Semantic Versioning](http://semver.org/).
55
And as you can see, we [keep a CHANGELOG](http://keepachangelog.com/).
66

7+
## [2.3.0] - 2015-11-09
8+
### Added
9+
- `WordPoints.PHPUnit.MissingCovers` sniff to flag tests missing `@covers`
10+
annotations (#74).
11+
- `Squiz.Scope.MethodScope` and `Squiz.WhiteSpace.ScopeKeywordSpacing` sniffs (#101).
12+
13+
### Removed
14+
- `WordPress.VIP.RestrictedFunctions.custom_role` error (#102).
15+
16+
### Fixed
17+
- `xmllint` sniffing when multiple XML files are present (#103).
18+
719
## [2.2.0] - 2015-10-30
820
### Added
921
- `WordPoints.PHP.RequiredParentMethodCall` sniff to flag missing calls to
@@ -157,6 +169,7 @@ automatically installed if there is a config file for it. #23
157169
- Initial code.
158170

159171
[Unreleased]: https://github.com/WordPoints/dev-lib/compare/master...develop
172+
[2.3.0]: https://github.com/WordPoints/dev-lib/compare/2.2.0...2.3.0
160173
[2.2.0]: https://github.com/WordPoints/dev-lib/compare/2.1.1...2.2.0
161174
[2.1.1]: https://github.com/WordPoints/dev-lib/compare/2.1.0...2.1.1
162175
[2.1.0]: https://github.com/WordPoints/dev-lib/compare/2.0.4...2.1.0

bin/functions.sh

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ wpdl-codesniff-xmllint() {
6464
local files=$(find "${CODESNIFF_PATH[@]}" -type f \( -name '*.xml' -o -name '*.xml.dist' \))
6565

6666
if [ ${#files[@]} != 0 ]; then
67-
xmllint --noout "${files[@]}"
67+
xmllint --noout ${files[@]}
6868
fi
6969
}
7070

@@ -161,4 +161,4 @@ wpdl-phpunit-ms-network-ajax() {
161161
WORDPOINTS_NETWORK_ACTIVE=1 WP_MULTISITE=1 wpdl-test-phpunit ajax ms-network
162162
}
163163

164-
# EOF
164+
# EOF
Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
<?php
2+
3+
/**
4+
* WordPoints PHPUnit Missing Covers Sniff class.
5+
*
6+
* @package WordPoints_Dev_Lib
7+
* @since 2.3.0
8+
*/
9+
10+
/**
11+
* Sniff for missing @covers annotations on PHPUnit tests.
12+
*
13+
* @since 2.3.0
14+
*/
15+
class WordPoints_Sniffs_PHPUnit_MissingCoversSniff implements PHP_CodeSniffer_Sniff {
16+
17+
/**
18+
* @since 2.3.0
19+
*/
20+
public function register() {
21+
return array( T_CLASS, T_FUNCTION );
22+
}
23+
24+
/**
25+
* @since 2.3.0
26+
*/
27+
public function process( PHP_CodeSniffer_File $phpcsFile, $stackPtr ) {
28+
29+
$tokens = $phpcsFile->getTokens();
30+
31+
$is_class = ! $is_function = T_FUNCTION === $tokens[ $stackPtr ]['code'];
32+
33+
$scope_closer = $tokens[ $stackPtr ]['scope_closer'];
34+
35+
if ( $is_function ) {
36+
37+
$function_name = $phpcsFile->getDeclarationName( $stackPtr );
38+
39+
// If this isn't a test method, we don't need to check it.
40+
if ( 'test' !== substr( $function_name, 0, 4 ) ) {
41+
return $scope_closer;
42+
}
43+
44+
$class = $phpcsFile->getCondition( $stackPtr, T_CLASS );
45+
46+
// If it isn't in a class, we don't need to check it.
47+
if ( ! $class ) {
48+
return $scope_closer;
49+
}
50+
}
51+
52+
// Find the previous token (excluding scope modifiers and whitespace).
53+
$exclude = PHP_CodeSniffer_Tokens::$methodPrefixes;
54+
$exclude[] = T_WHITESPACE;
55+
56+
$comment_closer = $phpcsFile->findPrevious( $exclude, $stackPtr - 1, 0, $exclude );
57+
58+
// If the token isn't the close of a doc comment, there is no doc comment for
59+
// this item, and therefore no annotations.
60+
if ( T_DOC_COMMENT_CLOSE_TAG !== $tokens[ $comment_closer ]['code'] ) {
61+
62+
if ( $is_function ) {
63+
64+
$phpcsFile->addError(
65+
'Missing PHPUnit code coverage annotation.'
66+
, $stackPtr
67+
, 'NoDocComment'
68+
);
69+
70+
return $scope_closer;
71+
}
72+
73+
return null;
74+
}
75+
76+
// Now check if the docblock contains the required annotations.
77+
$comment_opener = $tokens[ $comment_closer ]['comment_opener'];
78+
79+
$has_annotation = false;
80+
81+
foreach ( $tokens[ $comment_opener ]['comment_tags'] as $tag ) {
82+
83+
$tag_name = $tokens[ $tag ]['content'];
84+
85+
if ( '@covers' === $tag_name || '@coversNothing' === $tag_name ) {
86+
$has_annotation = true;
87+
break;
88+
}
89+
}
90+
91+
if ( ! $has_annotation ) {
92+
93+
if ( $is_class ) {
94+
95+
// Classes don't have to have the annotation, so this is OK. However,
96+
// each method will have to have it.
97+
return null;
98+
99+
} elseif ( $is_function ) {
100+
101+
$phpcsFile->addError(
102+
'Missing PHPUnit code coverage annotation.'
103+
, $stackPtr
104+
, 'MissingAnnotation'
105+
);
106+
}
107+
}
108+
109+
// We skip to the end of the class/function. If we're in a class and we're
110+
// still here, we found the annotation, so we don't need to check each
111+
// method. If we're in a function, we don't need to test any sub-functions
112+
// either, since they won't be test methods.
113+
return $scope_closer;
114+
115+
} // public function process()
116+
117+
} // class WordPoints_Sniffs_PHPUnit_MissingCoversSniff
118+
119+
// EOF
Lines changed: 151 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,151 @@
1+
<?php
2+
3+
/**
4+
* Class Has_Annotation
5+
*
6+
* @since 1.0.0
7+
*
8+
* @covers Something
9+
*/
10+
class Has_Annotation {
11+
12+
/**
13+
* A test.
14+
*
15+
* @since 1.0.0
16+
*
17+
* @covers Something::tt
18+
*/
19+
public function test_has_annotation() {} // OK
20+
21+
/**
22+
* A test.
23+
*
24+
* @since 1.0.0
25+
*
26+
* @coversNothing
27+
*/
28+
public function test_has_nothing_annotation() {} // OK
29+
30+
/**
31+
* A test.
32+
*
33+
* @since 1.0.0
34+
*/
35+
public function test_no_annotation() {} // OK
36+
37+
public function test_no_doc_comment() {} // OK
38+
public function not_a_test() {} // OK
39+
}
40+
41+
/**
42+
* Class Has_Nothing_Annotation
43+
*
44+
* @since 1.0.0
45+
*
46+
* @coversNothing
47+
*/
48+
class Has_Nothing_Annotation {
49+
50+
/**
51+
* A test.
52+
*
53+
* @since 1.0.0
54+
*
55+
* @covers Something::tt
56+
*/
57+
public function test_has_annotation() {} // OK
58+
59+
/**
60+
* A test.
61+
*
62+
* @since 1.0.0
63+
*
64+
* @coversNothing
65+
*/
66+
public function test_has_nothing_annotation() {} // OK
67+
68+
/**
69+
* A test.
70+
*
71+
* @since 1.0.0
72+
*/
73+
public function test_no_annotation() {} // OK
74+
75+
public function test_no_doc_comment() {} // OK
76+
public function not_a_test() {} // OK
77+
}
78+
79+
/**
80+
* Class Has_No_Annotation
81+
*
82+
* @since 1.0.0
83+
*/
84+
class Has_No_Annotation {
85+
86+
/**
87+
* A test.
88+
*
89+
* @since 1.0.0
90+
*
91+
* @covers Something::tt
92+
*/
93+
public function test_has_annotation() {} // OK
94+
95+
/**
96+
* A test.
97+
*
98+
* @since 1.0.0
99+
*
100+
* @coversNothing
101+
*/
102+
public function test_has_nothing_annotation() {} // OK
103+
104+
/**
105+
* A test.
106+
*
107+
* @since 1.0.0
108+
*/
109+
public function test_no_annotation() {} // Bad
110+
111+
public function test_no_doc_comment() {} // Bad
112+
public function not_a_test() {} // OK
113+
}
114+
115+
class Has_No_Doc_Comment {
116+
117+
/**
118+
* A test.
119+
*
120+
* @since 1.0.0
121+
*
122+
* @covers Something::tt
123+
*/
124+
public function test_has_annotation() {} // OK
125+
126+
/**
127+
* A test.
128+
*
129+
* @since 1.0.0
130+
*
131+
* @coversNothing
132+
*/
133+
public function test_has_nothing_annotation() {} // OK
134+
135+
/**
136+
* A test.
137+
*
138+
* @since 1.0.0
139+
*/
140+
public function test_no_annotation() {} // Bad
141+
142+
public function test_no_doc_comment() {} // Bad
143+
public function not_a_test() {} // OK
144+
}
145+
146+
/**
147+
* Not a test.
148+
*
149+
* @since 1.0.0
150+
*/
151+
function test_not_in_class() {} // OK
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
<?php
2+
3+
/**
4+
* Unit test class for the missing covers sniff.
5+
*
6+
* @package WordPoints_Dev_Lib\Tests
7+
* @since 2.3.0
8+
*/
9+
10+
/**
11+
* Unit test class for the missing covers sniff.
12+
*
13+
* @since 2.3.0
14+
*/
15+
class WordPoints_Tests_PHPUnit_MissingCoversUnitTest extends AbstractSniffUnitTest {
16+
17+
/**
18+
* @since 2.3.0
19+
*/
20+
public function getErrorList() {
21+
22+
return array(
23+
109 => 1,
24+
111 => 1,
25+
140 => 1,
26+
142 => 1,
27+
);
28+
}
29+
30+
/**
31+
* @since 2.3.0
32+
*/
33+
public function getWarningList() {
34+
return array();
35+
}
36+
}
37+
38+
// EOF

phpcs/WordPoints/ruleset.xml

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030

3131
<rule ref="WordPress-VIP">
3232
<exclude name="WordPress.VIP.RestrictedFunctions.switch_to_blog" />
33+
<exclude name="WordPress.VIP.RestrictedFunctions.custom_role" />
3334
<exclude name="WordPress.VIP.SuperGlobalInputUsage" />
3435
<exclude name="WordPress.VIP.DirectDatabaseQuery.SchemaChange" />
3536
<exclude name="WordPress.VIP.DirectDatabaseQuery.DirectQuery" />
@@ -92,7 +93,15 @@
9293
<rule ref="WordPress.WP.PreparedSQL">
9394
<exclude-pattern>/tests/*</exclude-pattern>
9495
</rule>
96+
97+
<rule ref="WordPoints.PHPUnit.MissingCovers">
98+
<exclude-pattern>^((?!(.*/MissingCoversUnitTest\.inc$|/tests/phpunit/tests/.*)))</exclude-pattern>
99+
</rule>
95100

96-
<exclude-pattern>/vendor/*,/dev-lib/*</exclude-pattern>
101+
<rule ref="Squiz.Scope.MethodScope"/>
102+
<rule ref="Squiz.WhiteSpace.ScopeKeywordSpacing"/>
103+
104+
<exclude-pattern>/vendor/*</exclude-pattern>
105+
<exclude-pattern>/dev-lib/*</exclude-pattern>
97106

98107
</ruleset>

0 commit comments

Comments
 (0)