1
2
3
4
5 package com.qulice.checkstyle;
6
7 import com.puppycrawl.tools.checkstyle.api.AbstractCheck;
8 import com.puppycrawl.tools.checkstyle.api.DetailAST;
9 import com.puppycrawl.tools.checkstyle.api.TokenTypes;
10 import java.util.regex.Pattern;
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33 public final class ProhibitFieldsInTestClassesCheck extends AbstractCheck {
34
35
36
37
38 private static final Pattern TESTS =
39 Pattern.compile(".*(Test|IT|ITCase)\\.java$");
40
41
42
43
44 private Pattern include;
45
46
47
48
49 public ProhibitFieldsInTestClassesCheck() {
50 this.include = ProhibitFieldsInTestClassesCheck.TESTS;
51 }
52
53
54
55
56
57
58 public void setIncludeFileNamePattern(final String regex) {
59 this.include = Pattern.compile(regex);
60 }
61
62 @Override
63 public int[] getDefaultTokens() {
64 return new int[] {
65 TokenTypes.VARIABLE_DEF,
66 };
67 }
68
69 @Override
70 public int[] getAcceptableTokens() {
71 return this.getDefaultTokens();
72 }
73
74 @Override
75 public int[] getRequiredTokens() {
76 return this.getDefaultTokens();
77 }
78
79 @Override
80 public void visitToken(final DetailAST ast) {
81 if (this.include.matcher(this.getFilePath()).find()
82 && ProhibitFieldsInTestClassesCheck.isUnannotatedInstanceField(ast)) {
83 final DetailAST name = ast.findFirstToken(TokenTypes.IDENT);
84 this.log(
85 name.getLineNo(),
86 String.format(
87 "Field \"%s\" is not allowed in a test class, move it into a test method or annotate it",
88 name.getText()
89 )
90 );
91 }
92 }
93
94 private static boolean isUnannotatedInstanceField(final DetailAST node) {
95 boolean flag = false;
96 final DetailAST parent = node.getParent();
97 if (parent != null && parent.getType() == TokenTypes.OBJBLOCK
98 && ProhibitFieldsInTestClassesCheck.isTopLevelType(parent.getParent())) {
99 final DetailAST modifiers = node.findFirstToken(TokenTypes.MODIFIERS);
100 flag = modifiers.findFirstToken(TokenTypes.LITERAL_STATIC) == null
101 && modifiers.findFirstToken(TokenTypes.ANNOTATION) == null;
102 }
103 return flag;
104 }
105
106 private static boolean isTopLevelType(final DetailAST type) {
107 return type != null
108 && ProhibitFieldsInTestClassesCheck.isTypeDef(type)
109 && ProhibitFieldsInTestClassesCheck.hasTopLevelParent(type);
110 }
111
112 private static boolean isTypeDef(final DetailAST type) {
113 final int kind = type.getType();
114 return kind == TokenTypes.CLASS_DEF
115 || kind == TokenTypes.ENUM_DEF
116 || kind == TokenTypes.RECORD_DEF
117 || kind == TokenTypes.INTERFACE_DEF;
118 }
119
120 private static boolean hasTopLevelParent(final DetailAST type) {
121 final DetailAST parent = type.getParent();
122 return parent != null
123 && parent.getType() != TokenTypes.OBJBLOCK
124 && parent.getType() != TokenTypes.LITERAL_NEW;
125 }
126 }