1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package com.puppycrawl.tools.checkstyle.api;
21
22 import static org.junit.Assert.assertArrayEquals;
23 import static org.junit.Assert.assertEquals;
24 import static org.junit.Assert.assertNull;
25 import static org.junit.Assert.assertTrue;
26 import static org.junit.Assert.fail;
27
28 import java.lang.reflect.Field;
29 import java.lang.reflect.InvocationTargetException;
30 import java.net.URI;
31 import java.util.Arrays;
32 import java.util.regex.Pattern;
33
34 import org.apache.commons.beanutils.ConversionException;
35 import org.apache.commons.beanutils.ConvertUtilsBean;
36 import org.apache.commons.beanutils.Converter;
37 import org.junit.Test;
38 import org.powermock.reflect.Whitebox;
39
40 import com.puppycrawl.tools.checkstyle.DefaultConfiguration;
41 import com.puppycrawl.tools.checkstyle.DefaultContext;
42 import com.puppycrawl.tools.checkstyle.checks.naming.AccessModifier;
43
44 public class AutomaticBeanTest {
45
46 @Test
47 public void testConfigureNoSuchAttribute() {
48 final TestBean testBean = new TestBean();
49 final DefaultConfiguration conf = new DefaultConfiguration("testConf");
50 conf.addAttribute("NonExistent", "doesn't matter");
51 try {
52 testBean.configure(conf);
53 fail("Exception is expected");
54 }
55 catch (CheckstyleException ex) {
56 assertNull("Exceptions cause should be null", ex.getCause());
57 assertEquals("Invalid exception message",
58 "Property 'NonExistent' does not exist, please check the documentation",
59 ex.getMessage());
60 }
61 }
62
63 @Test
64 public void testConfigureNoSuchAttribute2() {
65 final TestBean testBean = new TestBean();
66 final DefaultConfiguration conf = new DefaultConfiguration("testConf");
67 conf.addAttribute("privateField", "doesn't matter");
68 try {
69 testBean.configure(conf);
70 fail("Exception is expected");
71 }
72 catch (CheckstyleException ex) {
73 assertNull("Exceptions cause should be null", ex.getCause());
74 assertEquals("Invalid exception message",
75 "Property 'privateField' does not exist, please check the documentation",
76 ex.getMessage());
77 }
78 }
79
80 @Test
81 public void testSetupChildFromBaseClass() throws CheckstyleException {
82 final TestBean testBean = new TestBean();
83 testBean.configure(new DefaultConfiguration("bean config"));
84 testBean.setupChild(null);
85 try {
86 testBean.setupChild(new DefaultConfiguration("dummy"));
87 fail("Exception expected");
88 }
89 catch (CheckstyleException ex) {
90 final String expectedMessage = "dummy is not allowed as a child in bean config. "
91 + "Please review 'Parent Module' section for this Check"
92 + " in web documentation if Check is standard.";
93 assertEquals("Invalid exception message", expectedMessage, ex.getMessage());
94 }
95 }
96
97 @Test
98 public void testSetupInvalidChildFromBaseClass() throws Exception {
99 final TestBean testBean = new TestBean();
100 final DefaultConfiguration parentConf = new DefaultConfiguration("parentConf");
101 final DefaultConfiguration childConf = new DefaultConfiguration("childConf");
102 final Field field = AutomaticBean.class.getDeclaredField("configuration");
103 field.setAccessible(true);
104 field.set(testBean, parentConf);
105
106 try {
107 testBean.setupChild(childConf);
108 fail("expecting checkstyle exception");
109 }
110 catch (CheckstyleException ex) {
111 assertEquals("expected exception", "childConf is not allowed as a "
112 + "child in parentConf. Please review 'Parent Module' section "
113 + "for this Check in web documentation if Check is standard.",
114 ex.getMessage());
115 }
116 }
117
118 @Test
119 public void testContextualizeInvocationTargetException() {
120 final TestBean testBean = new TestBean();
121 final DefaultContext context = new DefaultContext();
122 context.add("exceptionalMethod", 123.0f);
123 try {
124 testBean.contextualize(context);
125 fail("InvocationTargetException is expected");
126 }
127 catch (CheckstyleException ex) {
128 final String expected = "Cannot set property ";
129 assertTrue("Invalid exception cause, should be: InvocationTargetException",
130 ex.getCause() instanceof InvocationTargetException);
131 assertTrue("Invalid exception message, should start with: " + expected,
132 ex.getMessage().startsWith(expected));
133 }
134 }
135
136 @Test
137 public void testContextualizeConversionException() {
138 final TestBean testBean = new TestBean();
139 final DefaultContext context = new DefaultContext();
140 context.add("val", "some string");
141 try {
142 testBean.contextualize(context);
143 fail("InvocationTargetException is expected");
144 }
145 catch (CheckstyleException ex) {
146 final String expected = "illegal value ";
147 assertTrue("Invalid exception cause, should be: ConversionException",
148 ex.getCause() instanceof ConversionException);
149 assertTrue("Invalid exception message, should start with: " + expected,
150 ex.getMessage().startsWith(expected));
151 }
152 }
153
154 @Test
155 public void testTestBean() {
156 final TestBean testBean = new TestBean();
157 testBean.setVal(0);
158 testBean.setWrong("wrongVal");
159 testBean.assignPrivateFieldSecretly(null);
160 try {
161 testBean.setExceptionalMethod("someValue");
162 fail("exception expected");
163 }
164 catch (IllegalStateException ex) {
165 assertEquals("Invalid exception message",
166 "null,wrongVal,0,someValue", ex.getMessage());
167 }
168 }
169
170 @Test
171 public void testRegisterIntegralTypes() throws Exception {
172 final ConvertUtilsBeanStub convertUtilsBean = new ConvertUtilsBeanStub();
173 Whitebox.invokeMethod(AutomaticBean.class, "registerIntegralTypes", convertUtilsBean);
174 assertEquals("Number of converters registered differs from expected",
175 81, convertUtilsBean.getRegisterCount());
176 }
177
178 @Test
179 public void testBeanConverters() throws Exception {
180 final ConverterBean bean = new ConverterBean();
181
182
183 bean.setStrings("BAD");
184 bean.setPattern(null);
185 bean.setSeverityLevel(null);
186 bean.setScope(null);
187 bean.setUri(null);
188 bean.setAccessModifiers(AccessModifier.PACKAGE);
189
190 final DefaultConfiguration config = new DefaultConfiguration("bean");
191 config.addAttribute("strings", "a, b, c");
192 config.addAttribute("pattern", ".*");
193 config.addAttribute("severityLevel", "error");
194 config.addAttribute("scope", "public");
195 config.addAttribute("uri", "http://github.com");
196 config.addAttribute("accessModifiers", "public, private");
197 bean.configure(config);
198
199 assertArrayEquals("invalid result", new String[] {"a", "b", "c"}, bean.strings);
200 assertEquals("invalid result", ".*", bean.pattern.pattern());
201 assertEquals("invalid result", SeverityLevel.ERROR, bean.severityLevel);
202 assertEquals("invalid result", Scope.PUBLIC, bean.scope);
203 assertEquals("invalid result", new URI("http://github.com"), bean.uri);
204 assertArrayEquals("invalid result",
205 new AccessModifier[] {AccessModifier.PUBLIC, AccessModifier.PRIVATE},
206 bean.accessModifiers);
207 }
208
209 @Test
210 public void testBeanConvertersUri2() throws Exception {
211 final ConverterBean bean = new ConverterBean();
212 final DefaultConfiguration config = new DefaultConfiguration("bean");
213 config.addAttribute("uri", "");
214 bean.configure(config);
215
216 assertNull("invalid result", bean.uri);
217 }
218
219 @Test
220 public void testBeanConvertersUri3() {
221 final ConverterBean bean = new ConverterBean();
222 final DefaultConfiguration config = new DefaultConfiguration("bean");
223 config.addAttribute("uri", "BAD");
224
225 try {
226 bean.configure(config);
227 fail("Exception is expected");
228 }
229 catch (CheckstyleException ex) {
230 assertEquals("Error message is not expected",
231 "illegal value 'BAD' for property 'uri'", ex.getMessage());
232 }
233 }
234
235 private static class ConvertUtilsBeanStub extends ConvertUtilsBean {
236
237 private int registerCount;
238
239 @Override
240 public void register(Converter converter, Class<?> clazz) {
241 super.register(converter, clazz);
242 if (converter != null) {
243 registerCount++;
244 }
245 }
246
247 public int getRegisterCount() {
248 return registerCount;
249 }
250
251 }
252
253 private static class TestBean extends AutomaticBean {
254
255 private String privateField;
256
257 private String wrong;
258
259 private int val;
260
261 public void setWrong(String wrong) {
262 this.wrong = wrong;
263 }
264
265 public void setVal(int val) {
266 this.val = val;
267 }
268
269 public void assignPrivateFieldSecretly(String input) {
270 privateField = input;
271 }
272
273 public void setExceptionalMethod(String value) {
274 throw new IllegalStateException(privateField + "," + wrong + "," + val + "," + value);
275 }
276
277 @Override
278 protected void finishLocalSetup() {
279
280 }
281
282 }
283
284
285
286
287 public static class ConverterBean extends AutomaticBean {
288
289 private String[] strings;
290 private Pattern pattern;
291 private SeverityLevel severityLevel;
292 private Scope scope;
293 private URI uri;
294 private AccessModifier[] accessModifiers;
295
296
297
298
299
300 public void setStrings(String... strings) {
301 this.strings = Arrays.copyOf(strings, strings.length);
302 }
303
304
305
306
307
308 public void setPattern(Pattern pattern) {
309 this.pattern = pattern;
310 }
311
312
313
314
315
316 public void setSeverityLevel(SeverityLevel severityLevel) {
317 this.severityLevel = severityLevel;
318 }
319
320
321
322
323
324 public void setScope(Scope scope) {
325 this.scope = scope;
326 }
327
328
329
330
331
332 public void setUri(URI uri) {
333 this.uri = uri;
334 }
335
336
337
338
339
340 public void setAccessModifiers(AccessModifier... accessModifiers) {
341 this.accessModifiers = Arrays.copyOf(accessModifiers, accessModifiers.length);
342 }
343
344 @Override
345 protected void finishLocalSetup() {
346
347 }
348
349 }
350
351 }