1   ////////////////////////////////////////////////////////////////////////////////
2   // checkstyle: Checks Java source code for adherence to a set of rules.
3   // Copyright (C) 2001-2019 the original author or authors.
4   //
5   // This library is free software; you can redistribute it and/or
6   // modify it under the terms of the GNU Lesser General Public
7   // License as published by the Free Software Foundation; either
8   // version 2.1 of the License, or (at your option) any later version.
9   //
10  // This library is distributed in the hope that it will be useful,
11  // but WITHOUT ANY WARRANTY; without even the implied warranty of
12  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  // Lesser General Public License for more details.
14  //
15  // You should have received a copy of the GNU Lesser General Public
16  // License along with this library; if not, write to the Free Software
17  // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18  ////////////////////////////////////////////////////////////////////////////////
19  
20  package com.puppycrawl.tools.checkstyle.checks.imports;
21  
22  import static com.puppycrawl.tools.checkstyle.checks.imports.ImportOrderCheck.MSG_ORDERING;
23  import static com.puppycrawl.tools.checkstyle.checks.imports.ImportOrderCheck.MSG_SEPARATED_IN_GROUP;
24  import static com.puppycrawl.tools.checkstyle.checks.imports.ImportOrderCheck.MSG_SEPARATION;
25  import static org.junit.Assert.assertEquals;
26  import static org.junit.Assert.assertTrue;
27  import static org.junit.Assert.fail;
28  
29  import org.junit.Test;
30  
31  import antlr.CommonHiddenStreamToken;
32  import com.puppycrawl.tools.checkstyle.AbstractModuleTestSupport;
33  import com.puppycrawl.tools.checkstyle.DefaultConfiguration;
34  import com.puppycrawl.tools.checkstyle.api.CheckstyleException;
35  import com.puppycrawl.tools.checkstyle.api.DetailAST;
36  import com.puppycrawl.tools.checkstyle.api.TokenTypes;
37  import com.puppycrawl.tools.checkstyle.internal.utils.TestUtil;
38  import com.puppycrawl.tools.checkstyle.utils.CommonUtil;
39  
40  public class ImportOrderCheckTest extends AbstractModuleTestSupport {
41  
42      @Override
43      protected String getPackageLocation() {
44          return "com/puppycrawl/tools/checkstyle/checks/imports/importorder";
45      }
46  
47      /* Additional test for jacoco, since valueOf()
48       * is generated by javac and jacoco reports that
49       * valueOf() is uncovered.
50       */
51      @Test
52      public void testImportOrderOptionValueOf() {
53          final ImportOrderOption option = ImportOrderOption.valueOf("TOP");
54          assertEquals("Invalid valueOf result", ImportOrderOption.TOP, option);
55      }
56  
57      @Test
58      public void testDefault() throws Exception {
59          final DefaultConfiguration checkConfig =
60              createModuleConfig(ImportOrderCheck.class);
61          final String[] expected = {
62              "5: " + getCheckMessage(MSG_ORDERING, "java.awt.Dialog"),
63              "9: " + getCheckMessage(MSG_ORDERING, "javax.swing.JComponent"),
64              "11: " + getCheckMessage(MSG_ORDERING, "java.io.File"),
65              "13: " + getCheckMessage(MSG_ORDERING, "java.io.IOException"),
66              "18: " + getCheckMessage(MSG_SEPARATED_IN_GROUP,
67                      "sun.tools.util.ModifierFilter.ALL_ACCESS"),
68          };
69  
70          verify(checkConfig, getNonCompilablePath("InputImportOrder.java"), expected);
71      }
72  
73      @Test
74      public void testMultilineImport() throws Exception {
75          final DefaultConfiguration checkConfig = createModuleConfig(ImportOrderCheck.class);
76          final String[] expected = CommonUtil.EMPTY_STRING_ARRAY;
77  
78          verify(checkConfig, getNonCompilablePath("InputImportOrderMultiline.java"), expected);
79      }
80  
81      @Test
82      public void testGroups() throws Exception {
83          final DefaultConfiguration checkConfig = createModuleConfig(ImportOrderCheck.class);
84          checkConfig.addAttribute("groups", "java.awt");
85          checkConfig.addAttribute("groups", "javax.swing");
86          checkConfig.addAttribute("groups", "java.io");
87          final String[] expected = {
88              "5: " + getCheckMessage(MSG_ORDERING, "java.awt.Dialog"),
89              "13: " + getCheckMessage(MSG_ORDERING, "java.io.IOException"),
90              "16: " + getCheckMessage(MSG_ORDERING, "javax.swing.WindowConstants.*"),
91              "18: " + getCheckMessage(MSG_SEPARATED_IN_GROUP,
92                      "sun.tools.util.ModifierFilter.ALL_ACCESS"),
93          };
94  
95          verify(checkConfig, getNonCompilablePath("InputImportOrder.java"), expected);
96      }
97  
98      @Test
99      public void testGroupsRegexp() throws Exception {
100         final DefaultConfiguration checkConfig = createModuleConfig(ImportOrderCheck.class);
101         checkConfig.addAttribute("groups", "java, /^javax?\\.(awt|swing)\\./");
102         checkConfig.addAttribute("ordered", "false");
103         final String[] expected = {
104             "11: " + getCheckMessage(MSG_ORDERING, "java.io.File"),
105             "18: " + getCheckMessage(MSG_SEPARATED_IN_GROUP,
106                     "sun.tools.util.ModifierFilter.ALL_ACCESS"),
107         };
108 
109         verify(checkConfig, getNonCompilablePath("InputImportOrder.java"), expected);
110     }
111 
112     @Test
113     public void testSeparated() throws Exception {
114         final DefaultConfiguration checkConfig = createModuleConfig(ImportOrderCheck.class);
115         checkConfig.addAttribute("groups", "java.awt, javax.swing, java.io, java.util");
116         checkConfig.addAttribute("separated", "true");
117         checkConfig.addAttribute("ordered", "false");
118         final String[] expected = {
119             "9: " + getCheckMessage(MSG_SEPARATION, "javax.swing.JComponent"),
120             "11: " + getCheckMessage(MSG_SEPARATION, "java.io.File"),
121             "16: " + getCheckMessage(MSG_ORDERING, "javax.swing.WindowConstants.*"),
122         };
123 
124         verify(checkConfig, getNonCompilablePath("InputImportOrder.java"), expected);
125     }
126 
127     @Test
128     public void testStaticImportSeparated() throws Exception {
129         final DefaultConfiguration checkConfig = createModuleConfig(ImportOrderCheck.class);
130         checkConfig.addAttribute("groups", "java, org");
131         checkConfig.addAttribute("separated", "true");
132         checkConfig.addAttribute("ordered", "true");
133         checkConfig.addAttribute("option", "top");
134         final String[] expected = {
135             "5: " + getCheckMessage(MSG_SEPARATED_IN_GROUP, "java.lang.Math.cos"),
136             "7: " + getCheckMessage(MSG_SEPARATED_IN_GROUP, "org.junit.Assert.assertEquals"),
137         };
138 
139         verify(checkConfig, getPath("InputImportOrderStaticGroupSeparated.java"), expected);
140     }
141 
142     @Test
143     public void testNoGapBetweenStaticImports() throws Exception {
144         final DefaultConfiguration checkConfig = createModuleConfig(ImportOrderCheck.class);
145         checkConfig.addAttribute("groups", "java, javax, org");
146         checkConfig.addAttribute("separated", "true");
147         checkConfig.addAttribute("ordered", "true");
148         checkConfig.addAttribute("option", "bottom");
149         final String[] expected = CommonUtil.EMPTY_STRING_ARRAY;
150 
151         verify(checkConfig, getPath("InputImportOrderNoGapBetweenStaticImports.java"), expected);
152     }
153 
154     @Test
155     public void testSortStaticImportsAlphabeticallyFalse() throws Exception {
156         final DefaultConfiguration checkConfig = createModuleConfig(ImportOrderCheck.class);
157         checkConfig.addAttribute("groups", " java, javax, org");
158         checkConfig.addAttribute("separated", "true");
159         checkConfig.addAttribute("ordered", "true");
160         checkConfig.addAttribute("option", "top");
161         checkConfig.addAttribute("sortStaticImportsAlphabetically", "false");
162         final String[] expected = CommonUtil.EMPTY_STRING_ARRAY;
163 
164         verify(checkConfig, getPath("InputImportOrderSortStaticImportsAlphabetically.java"),
165             expected);
166     }
167 
168     @Test
169     public void testSortStaticImportsAlphabeticallyTrue() throws Exception {
170         final DefaultConfiguration checkConfig = createModuleConfig(ImportOrderCheck.class);
171         checkConfig.addAttribute("groups", "java, javax, org");
172         checkConfig.addAttribute("separated", "true");
173         checkConfig.addAttribute("ordered", "true");
174         checkConfig.addAttribute("option", "top");
175         checkConfig.addAttribute("sortStaticImportsAlphabetically", "true");
176         final String[] expected = {
177             "4: " + getCheckMessage(MSG_ORDERING,
178                 "javax.xml.transform.TransformerFactory.newInstance"),
179             "5: " + getCheckMessage(MSG_ORDERING, "java.lang.Math.cos"),
180             "6: " + getCheckMessage(MSG_ORDERING, "java.lang.Math.abs"),
181         };
182 
183         verify(checkConfig, getPath("InputImportOrderSortStaticImportsAlphabetically.java"),
184             expected);
185     }
186 
187     @Test
188     public void testCaseInsensitive() throws Exception {
189         final DefaultConfiguration checkConfig = createModuleConfig(ImportOrderCheck.class);
190         checkConfig.addAttribute("caseSensitive", "false");
191         final String[] expected = CommonUtil.EMPTY_STRING_ARRAY;
192 
193         verify(checkConfig, getPath("InputImportOrderCaseInsensitive.java"), expected);
194     }
195 
196     @Test
197     public void testContainerCaseInsensitive() throws Exception {
198         final DefaultConfiguration checkConfig = createModuleConfig(ImportOrderCheck.class);
199         checkConfig.addAttribute("option", "top");
200         checkConfig.addAttribute("caseSensitive", "false");
201         checkConfig.addAttribute("useContainerOrderingForStatic", "true");
202         final String[] expected = CommonUtil.EMPTY_STRING_ARRAY;
203 
204         verify(checkConfig, getNonCompilablePath("InputImportOrderEclipseStaticCaseSensitive.java"),
205             expected);
206     }
207 
208     @Test
209     public void testInvalidOption() throws Exception {
210         final DefaultConfiguration checkConfig =
211             createModuleConfig(ImportOrderCheck.class);
212         checkConfig.addAttribute("option", "invalid_option");
213 
214         try {
215             final String[] expected = CommonUtil.EMPTY_STRING_ARRAY;
216 
217             verify(checkConfig, getPath("InputImportOrder_Top.java"), expected);
218             fail("exception expected");
219         }
220         catch (CheckstyleException ex) {
221             assertEquals("Invalid exception message",
222                     "cannot initialize module com.puppycrawl.tools.checkstyle.TreeWalker - "
223                         + "cannot initialize module com.puppycrawl.tools.checkstyle.checks"
224                         + ".imports.ImportOrderCheck - "
225                         + "Cannot set property 'option' to 'invalid_option'",
226                     ex.getMessage());
227         }
228     }
229 
230     @Test
231     public void testTop() throws Exception {
232         final DefaultConfiguration checkConfig =
233             createModuleConfig(ImportOrderCheck.class);
234         checkConfig.addAttribute("option", "top");
235         final String[] expected = {
236             "7: " + getCheckMessage(MSG_SEPARATED_IN_GROUP, "java.awt.Button"),
237             "12: " + getCheckMessage(MSG_SEPARATED_IN_GROUP, "java.io.IOException"),
238             "15: " + getCheckMessage(MSG_SEPARATED_IN_GROUP, "javax.swing.JComponent"),
239             "18: " + getCheckMessage(MSG_SEPARATED_IN_GROUP, "java.io.File.*"),
240             "18: " + getCheckMessage(MSG_ORDERING, "java.io.File.*"),
241         };
242 
243         verify(checkConfig, getPath("InputImportOrder_Top.java"), expected);
244     }
245 
246     @Test
247     public void testAbove() throws Exception {
248         final DefaultConfiguration checkConfig =
249             createModuleConfig(ImportOrderCheck.class);
250         checkConfig.addAttribute("option", "above");
251         final String[] expected = {
252             "5: " + getCheckMessage(MSG_ORDERING, "java.awt.Button.ABORT"),
253             "8: " + getCheckMessage(MSG_ORDERING, "java.awt.Dialog"),
254             "13: " + getCheckMessage(MSG_ORDERING, "java.io.File"),
255             "13: " + getCheckMessage(MSG_SEPARATED_IN_GROUP, "java.io.File"),
256             "14: " + getCheckMessage(MSG_ORDERING, "java.io.File.createTempFile"),
257         };
258 
259         verify(checkConfig, getPath("InputImportOrder_Above.java"), expected);
260     }
261 
262     @Test
263     public void testInFlow() throws Exception {
264         final DefaultConfiguration checkConfig =
265             createModuleConfig(ImportOrderCheck.class);
266         checkConfig.addAttribute("option", "inflow");
267         final String[] expected = {
268             "6: " + getCheckMessage(MSG_ORDERING, "java.awt.Dialog"),
269             "9: " + getCheckMessage(MSG_SEPARATED_IN_GROUP, "javax.swing.JComponent"),
270             "11: " + getCheckMessage(MSG_ORDERING,
271                      "javax.swing.WindowConstants.DO_NOTHING_ON_CLOSE"),
272             "12: " + getCheckMessage(MSG_ORDERING, "javax.swing.WindowConstants.*"),
273             "13: " + getCheckMessage(MSG_ORDERING, "javax.swing.JTable"),
274             "15: " + getCheckMessage(MSG_ORDERING, "java.io.File.createTempFile"),
275             "15: " + getCheckMessage(MSG_SEPARATED_IN_GROUP, "java.io.File.createTempFile"),
276             "16: " + getCheckMessage(MSG_ORDERING, "java.io.File"),
277         };
278 
279         verify(checkConfig, getPath("InputImportOrder_InFlow.java"), expected);
280     }
281 
282     @Test
283     public void testUnder() throws Exception {
284         // is default (testDefault)
285         final DefaultConfiguration checkConfig =
286             createModuleConfig(ImportOrderCheck.class);
287         checkConfig.addAttribute("option", "under");
288         final String[] expected = {
289             "5: " + getCheckMessage(MSG_ORDERING, "java.awt.Dialog"),
290             "11: " + getCheckMessage(MSG_ORDERING, "java.awt.Button.ABORT"),
291             "13: " + getCheckMessage(MSG_SEPARATED_IN_GROUP, "java.io.File.createTempFile"),
292             "14: " + getCheckMessage(MSG_ORDERING, "java.io.File"),
293         };
294 
295         verify(checkConfig, getPath("InputImportOrder_Under.java"), expected);
296     }
297 
298     @Test
299     public void testBottom() throws Exception {
300         final DefaultConfiguration checkConfig =
301             createModuleConfig(ImportOrderCheck.class);
302         checkConfig.addAttribute("option", "bottom");
303         final String[] expected = {
304             "8: " + getCheckMessage(MSG_SEPARATED_IN_GROUP, "java.io.IOException"),
305             "11: " + getCheckMessage(MSG_SEPARATED_IN_GROUP, "javax.swing.JComponent"),
306             "14: " + getCheckMessage(MSG_SEPARATED_IN_GROUP, "java.io.File.*"),
307             "15: " + getCheckMessage(MSG_ORDERING, "java.io.File"),
308             "17: " + getCheckMessage(MSG_SEPARATED_IN_GROUP, "java.io.File.createTempFile"),
309             "21: " + getCheckMessage(MSG_ORDERING, "java.io.Reader"),
310             "21: " + getCheckMessage(MSG_SEPARATED_IN_GROUP, "java.io.Reader"),
311         };
312 
313         verify(checkConfig, getPath("InputImportOrder_Bottom.java"), expected);
314     }
315 
316     @Test
317     public void testGetGroupNumber() throws Exception {
318         final DefaultConfiguration checkConfig =
319             createModuleConfig(ImportOrderCheck.class);
320         checkConfig.addAttribute("groups", "/javax/, sun, /^java/, org, /java/");
321         final String[] expected = CommonUtil.EMPTY_STRING_ARRAY;
322 
323         verify(checkConfig,
324             getNonCompilablePath("InputImportOrderGetGroupNumber.java"), expected);
325     }
326 
327     @Test
328     public void testHonorsTokenProperty() throws Exception {
329         final DefaultConfiguration checkConfig =
330             createModuleConfig(ImportOrderCheck.class);
331         checkConfig.addAttribute("tokens", "IMPORT");
332         final String[] expected = {
333             "6: " + getCheckMessage(MSG_ORDERING, "java.awt.Button"),
334         };
335 
336         verify(checkConfig, getPath("InputImportOrder_HonorsTokensProperty.java"), expected);
337     }
338 
339     @Test
340     public void testWildcard() throws Exception {
341         final DefaultConfiguration checkConfig = createModuleConfig(ImportOrderCheck.class);
342         checkConfig.addAttribute("groups", "com,*,java");
343         final String[] expected = {
344             "9: " + getCheckMessage(MSG_ORDERING, "javax.crypto.Cipher"),
345         };
346 
347         verify(checkConfig, getPath("InputImportOrder_Wildcard.java"), expected);
348     }
349 
350     @Test
351     public void testWildcardUnspecified() throws Exception {
352         final DefaultConfiguration checkConfig = createModuleConfig(ImportOrderCheck.class);
353 
354         checkConfig.addAttribute("groups", "java,javax,org");
355         final String[] expected = {
356             "11: " + getCheckMessage(MSG_SEPARATED_IN_GROUP,
357                 "com.puppycrawl.tools.checkstyle.checks.imports.importorder.InputImportOrderBug"),
358         };
359 
360         verify(checkConfig, getPath("InputImportOrder_WildcardUnspecified.java"), expected);
361     }
362 
363     @Test
364     public void testNoFailureForRedundantImports() throws Exception {
365         final DefaultConfiguration checkConfig =
366             createModuleConfig(ImportOrderCheck.class);
367         final String[] expected = CommonUtil.EMPTY_STRING_ARRAY;
368         verify(checkConfig, getPath("InputImportOrder_NoFailureForRedundantImports.java"),
369             expected);
370     }
371 
372     @Test
373     public void testStaticGroupsAlphabeticalOrder() throws Exception {
374         final DefaultConfiguration checkConfig =
375             createModuleConfig(ImportOrderCheck.class);
376         checkConfig.addAttribute("option", "top");
377         checkConfig.addAttribute("groups", "org, java");
378         checkConfig.addAttribute("sortStaticImportsAlphabetically", "true");
379         final String[] expected = {
380             "6: " + getCheckMessage(MSG_SEPARATED_IN_GROUP, "org.*"),
381             "8: " + getCheckMessage(MSG_SEPARATED_IN_GROUP, "java.util.Set"),
382         };
383 
384         verify(checkConfig, getPath("InputImportOrderStaticGroupOrder.java"), expected);
385     }
386 
387     @Test
388     public void testStaticGroupsOrder() throws Exception {
389         final DefaultConfiguration checkConfig =
390             createModuleConfig(ImportOrderCheck.class);
391         checkConfig.addAttribute("option", "top");
392         checkConfig.addAttribute("groups", "org, java");
393         final String[] expected = {
394             "6: " + getCheckMessage(MSG_SEPARATED_IN_GROUP, "org.*"),
395             "8: " + getCheckMessage(MSG_SEPARATED_IN_GROUP, "java.util.Set"),
396         };
397         verify(checkConfig, getPath("InputImportOrderStaticGroupOrder.java"), expected);
398     }
399 
400     @Test
401     public void testStaticGroupsAlphabeticalOrderBottom() throws Exception {
402         final DefaultConfiguration checkConfig =
403             createModuleConfig(ImportOrderCheck.class);
404         checkConfig.addAttribute("option", "bottom");
405         checkConfig.addAttribute("groups", "org, java");
406         checkConfig.addAttribute("sortStaticImportsAlphabetically", "true");
407         final String[] expected = {
408             "5: " + getCheckMessage(MSG_SEPARATED_IN_GROUP, "java.util.Set"),
409             "7: " + getCheckMessage(MSG_SEPARATED_IN_GROUP, "java.lang.Math.PI"),
410         };
411         verify(checkConfig, getPath("InputImportOrderStaticGroupOrderBottom.java"), expected);
412     }
413 
414     @Test
415     public void testStaticGroupsAlphabeticalOrderBottomNegative() throws Exception {
416         final DefaultConfiguration checkConfig =
417             createModuleConfig(ImportOrderCheck.class);
418         checkConfig.addAttribute("option", "bottom");
419         checkConfig.addAttribute("groups", "org, java");
420         checkConfig.addAttribute("separated", "true");
421         checkConfig.addAttribute("sortStaticImportsAlphabetically", "true");
422         final String[] expected = {
423             "8: " + getCheckMessage(MSG_ORDERING, "java.util.Set"),
424         };
425         verify(checkConfig, getPath("InputImportOrderStaticGroupOrderBottom_Negative.java"),
426             expected);
427     }
428 
429     /** Tests that a non-static import after a static import correctly gives an
430      * error if order=bottom. */
431 
432     @Test
433     public void testStaticGroupsAlphabeticalOrderTopNegative() throws Exception {
434         final DefaultConfiguration checkConfig =
435             createModuleConfig(ImportOrderCheck.class);
436         checkConfig.addAttribute("option", "top");
437         checkConfig.addAttribute("groups", "org, java");
438         checkConfig.addAttribute("separated", "true");
439         checkConfig.addAttribute("sortStaticImportsAlphabetically", "true");
440         final String[] expected = {
441             "5: " + getCheckMessage(MSG_ORDERING, "java.lang.Math.PI"),
442         };
443         verify(checkConfig, getPath("InputImportOrderStaticGroupOrderBottom_Negative.java"),
444             expected);
445     }
446 
447     /** Tests that a non-static import before a static import correctly gives an
448      * error if order=top. */
449 
450     @Test
451     public void testStaticGroupsAlphabeticalOrderBottomNegative2() throws Exception {
452         final DefaultConfiguration checkConfig =
453             createModuleConfig(ImportOrderCheck.class);
454         checkConfig.addAttribute("option", "bottom");
455         checkConfig.addAttribute("groups", "org, java");
456         checkConfig.addAttribute("separated", "true");
457         checkConfig.addAttribute("sortStaticImportsAlphabetically", "true");
458         final String[] expected = {
459             "8: " + getCheckMessage(MSG_ORDERING, "java.util.Set"),
460         };
461         verify(checkConfig, getPath("InputImportOrderStaticGroupOrderBottom_Negative2.java"),
462             expected);
463     }
464 
465     @Test
466     public void testStaticGroupsOrderBottom() throws Exception {
467         final DefaultConfiguration checkConfig =
468             createModuleConfig(ImportOrderCheck.class);
469         checkConfig.addAttribute("option", "bottom");
470         checkConfig.addAttribute("groups", "org, java");
471         final String[] expected = {
472             "5: " + getCheckMessage(MSG_SEPARATED_IN_GROUP, "java.util.Set"),
473             "7: " + getCheckMessage(MSG_SEPARATED_IN_GROUP, "java.lang.Math.PI"),
474         };
475         verify(checkConfig, getPath("InputImportOrderStaticGroupOrderBottom.java"), expected);
476     }
477 
478     @Test
479     public void testImportReception() throws Exception {
480         final DefaultConfiguration checkConfig =
481                 createModuleConfig(ImportOrderCheck.class);
482         checkConfig.addAttribute("separated", "true");
483         checkConfig.addAttribute("groups", "java, javax");
484         final String[] expected = CommonUtil.EMPTY_STRING_ARRAY;
485         verify(checkConfig, getPath("InputImportOrderRepetition.java"), expected);
486     }
487 
488     @Test
489     public void testStaticImportReceptionTop() throws Exception {
490         final DefaultConfiguration checkConfig =
491                 createModuleConfig(ImportOrderCheck.class);
492         checkConfig.addAttribute("option", "top");
493         checkConfig.addAttribute("separated", "true");
494         checkConfig.addAttribute("groups", "java, org");
495         checkConfig.addAttribute("sortStaticImportsAlphabetically", "true");
496         final String[] expected = CommonUtil.EMPTY_STRING_ARRAY;
497         verify(checkConfig, getPath("InputImportOrderStaticRepetition.java"), expected);
498     }
499 
500     @Test
501     public void testStaticImportReception() throws Exception {
502         final DefaultConfiguration checkConfig =
503                 createModuleConfig(ImportOrderCheck.class);
504         checkConfig.addAttribute("separated", "true");
505         checkConfig.addAttribute("groups", "java, org");
506         final String[] expected = {
507             "4: " + getCheckMessage(MSG_SEPARATION, "org.antlr.v4.runtime.CommonToken.*"),
508             "7: " + getCheckMessage(MSG_ORDERING, "java.util.Set"),
509         };
510         verify(checkConfig, getPath("InputImportOrderStaticRepetition.java"), expected);
511     }
512 
513     @Test
514     public void testStaticGroupsOrderAbove() throws Exception {
515         final DefaultConfiguration checkConfig =
516             createModuleConfig(ImportOrderCheck.class);
517         checkConfig.addAttribute("option", "above");
518         checkConfig.addAttribute("groups", "org, java, sun");
519         checkConfig.addAttribute("sortStaticImportsAlphabetically", "true");
520         final String[] expected = {
521             "5: " + getCheckMessage(MSG_SEPARATED_IN_GROUP, "java.util.Set"),
522             "7: " + getCheckMessage(MSG_SEPARATED_IN_GROUP, "java.lang.Math.PI"),
523             "7: " + getCheckMessage(MSG_ORDERING, "java.lang.Math.PI"),
524             "8: " + getCheckMessage(MSG_ORDERING, "org.antlr.v4.runtime.Recognizer.EOF"),
525         };
526         verify(checkConfig, getPath("InputImportOrderStaticGroupOrderBottom.java"), expected);
527     }
528 
529     @Test
530     public void testStaticOnDemandGroupsOrder() throws Exception {
531         final DefaultConfiguration checkConfig =
532             createModuleConfig(ImportOrderCheck.class);
533         checkConfig.addAttribute("option", "top");
534         checkConfig.addAttribute("groups", "org, java");
535         final String[] expected = {
536             "6: " + getCheckMessage(MSG_SEPARATED_IN_GROUP, "org.*"),
537             "8: " + getCheckMessage(MSG_SEPARATED_IN_GROUP, "java.util.Set"),
538             "9: " + getCheckMessage(MSG_ORDERING, "org.junit.Test"),
539         };
540         verify(checkConfig, getPath("InputImportOrderStaticOnDemandGroupOrder.java"), expected);
541     }
542 
543     @Test
544     public void testStaticOnDemandGroupsAlphabeticalOrder() throws Exception {
545         final DefaultConfiguration checkConfig =
546             createModuleConfig(ImportOrderCheck.class);
547         checkConfig.addAttribute("option", "top");
548         checkConfig.addAttribute("groups", "org, java");
549         checkConfig.addAttribute("sortStaticImportsAlphabetically", "true");
550         final String[] expected = {
551             "6: " + getCheckMessage(MSG_SEPARATED_IN_GROUP, "org.*"),
552             "8: " + getCheckMessage(MSG_SEPARATED_IN_GROUP, "java.util.Set"),
553             "9: " + getCheckMessage(MSG_ORDERING, "org.junit.Test"),
554         };
555         verify(checkConfig, getPath("InputImportOrderStaticOnDemandGroupOrder.java"), expected);
556     }
557 
558     @Test
559     public void testStaticOnDemandGroupsOrderBottom() throws Exception {
560         final DefaultConfiguration checkConfig =
561             createModuleConfig(ImportOrderCheck.class);
562         checkConfig.addAttribute("option", "bottom");
563         checkConfig.addAttribute("groups", "org, java");
564         final String[] expected = {
565             "5: " + getCheckMessage(MSG_SEPARATED_IN_GROUP, "java.util.Set"),
566             "7: " + getCheckMessage(MSG_SEPARATED_IN_GROUP, "java.lang.Math.*"),
567         };
568         verify(checkConfig, getPath("InputImportOrderStaticOnDemandGroupOrderBottom.java"),
569             expected);
570     }
571 
572     @Test
573     public void testStaticOnDemandGroupsAlphabeticalOrderBottom() throws Exception {
574         final DefaultConfiguration checkConfig =
575             createModuleConfig(ImportOrderCheck.class);
576         checkConfig.addAttribute("option", "bottom");
577         checkConfig.addAttribute("groups", "org, java");
578         checkConfig.addAttribute("sortStaticImportsAlphabetically", "true");
579         final String[] expected = {
580             "5: " + getCheckMessage(MSG_SEPARATED_IN_GROUP, "java.util.Set"),
581             "7: " + getCheckMessage(MSG_SEPARATED_IN_GROUP, "java.lang.Math.*"),
582         };
583         verify(checkConfig, getPath("InputImportOrderStaticOnDemandGroupOrderBottom.java"),
584             expected);
585     }
586 
587     @Test
588     public void testStaticOnDemandGroupsOrderAbove() throws Exception {
589         final DefaultConfiguration checkConfig =
590             createModuleConfig(ImportOrderCheck.class);
591         checkConfig.addAttribute("option", "above");
592         checkConfig.addAttribute("groups", "org, java");
593         checkConfig.addAttribute("sortStaticImportsAlphabetically", "true");
594         final String[] expected = {
595             "5: " + getCheckMessage(MSG_SEPARATED_IN_GROUP, "java.util.Set"),
596             "7: " + getCheckMessage(MSG_SEPARATED_IN_GROUP, "java.lang.Math.*"),
597             "7: " + getCheckMessage(MSG_ORDERING, "java.lang.Math.*"),
598             "8: " + getCheckMessage(MSG_ORDERING, "org.antlr.v4.runtime.CommonToken.*"),
599         };
600         verify(checkConfig, getPath("InputImportOrderStaticOnDemandGroupOrderBottom.java"),
601             expected);
602     }
603 
604     @Test
605     public void testGroupWithSlashes() throws Exception {
606         final DefaultConfiguration checkConfig = createModuleConfig(ImportOrderCheck.class);
607         checkConfig.addAttribute("groups", "/^javax");
608 
609         try {
610             final String[] expected = CommonUtil.EMPTY_STRING_ARRAY;
611 
612             verify(checkConfig, getPath("InputImportOrder.java"), expected);
613             fail("exception expected");
614         }
615         catch (CheckstyleException ex) {
616             assertEquals("Invalid exception message",
617                     "cannot initialize module com.puppycrawl.tools.checkstyle.TreeWalker - "
618                         + "cannot initialize module com.puppycrawl.tools.checkstyle.checks"
619                         + ".imports.ImportOrderCheck - "
620                         + "Cannot set property 'groups' to '/^javax'",
621                     ex.getMessage());
622             assertEquals("Invalid exception message", "Invalid group: /^javax",
623                     ex.getCause().getCause().getCause().getCause().getMessage());
624         }
625     }
626 
627     @Test
628     public void testGroupWithDot() throws Exception {
629         final DefaultConfiguration checkConfig = createModuleConfig(ImportOrderCheck.class);
630         checkConfig.addAttribute("groups", "java.awt.");
631         final String[] expected = CommonUtil.EMPTY_STRING_ARRAY;
632 
633         verify(checkConfig, getPath("InputImportOrder_NoFailureForRedundantImports.java"),
634             expected);
635     }
636 
637     @Test
638     public void testMultiplePatternMatches() throws Exception {
639         final DefaultConfiguration checkConfig = createModuleConfig(ImportOrderCheck.class);
640         checkConfig.addAttribute("groups", "/java/,/rga/,/myO/,/org/,/organ./");
641         final String[] expected = {
642             "5: " + getCheckMessage(MSG_SEPARATED_IN_GROUP, "org.*"),
643         };
644 
645         verify(checkConfig, getNonCompilablePath("InputImportOrder_MultiplePatternMatches.java"),
646             expected);
647     }
648 
649     /**
650      * This test requires reflection to insert an unsupported option in the check to cover the
651      * exception that gets thrown when a unsupported option is used. The field has a value by
652      * default and the setter for the property will throw it's own exception when an unsupported
653      * option is given, so there is no other way to cover this code.
654      *
655      * @throws Exception if there is an error.
656      */
657     @Test
658     public void testVisitTokenSwitchReflection() throws Exception {
659         // Create mock ast
660         final DetailAST astImport = mockAST(TokenTypes.IMPORT, "import", "mockfile", 0, 0);
661         final DetailAST astIdent = mockAST(TokenTypes.IDENT, "myTestImport", "mockfile", 0, 0);
662         astImport.addChild(astIdent);
663         final DetailAST astSemi = mockAST(TokenTypes.SEMI, ";", "mockfile", 0, 0);
664         astIdent.addNextSibling(astSemi);
665 
666         // Set unsupported option
667         final ImportOrderCheck mock = new ImportOrderCheck();
668         TestUtil.getClassDeclaredField(ImportOrderCheck.class, "option").set(mock, null);
669 
670         // expecting IllegalStateException
671         try {
672             mock.visitToken(astImport);
673             fail("An exception is expected");
674         }
675         catch (IllegalStateException ex) {
676             assertTrue("invalid exception message", ex.getMessage().endsWith(": null"));
677         }
678     }
679 
680     /**
681      * Creates MOCK lexical token and returns AST node for this token.
682      * @param tokenType type of token
683      * @param tokenText text of token
684      * @param tokenFileName file name of token
685      * @param tokenRow token position in a file (row)
686      * @param tokenColumn token position in a file (column)
687      * @return AST node for the token
688      */
689     private static DetailAST mockAST(final int tokenType, final String tokenText,
690             final String tokenFileName, final int tokenRow, final int tokenColumn) {
691         final CommonHiddenStreamToken tokenImportSemi = new CommonHiddenStreamToken();
692         tokenImportSemi.setType(tokenType);
693         tokenImportSemi.setText(tokenText);
694         tokenImportSemi.setLine(tokenRow);
695         tokenImportSemi.setColumn(tokenColumn);
696         tokenImportSemi.setFilename(tokenFileName);
697         final DetailAST astSemi = new DetailAST();
698         astSemi.initialize(tokenImportSemi);
699         return astSemi;
700     }
701 
702     @Test
703     public void testEclipseDefaultPositive() throws Exception {
704         final DefaultConfiguration checkConfig = createModuleConfig(ImportOrderCheck.class);
705         checkConfig.addAttribute("groups", "java,javax,org,com");
706         checkConfig.addAttribute("ordered", "true");
707         checkConfig.addAttribute("separated", "true");
708         checkConfig.addAttribute("option", "top");
709         checkConfig.addAttribute("sortStaticImportsAlphabetically", "true");
710         final String[] expected = CommonUtil.EMPTY_STRING_ARRAY;
711 
712         verify(checkConfig,
713             getNonCompilablePath("InputImportOrder_EclipseDefaultPositive.java"), expected);
714     }
715 
716     @Test
717     public void testStaticImportEclipseRepetition() throws Exception {
718         final DefaultConfiguration checkConfig =
719             createModuleConfig(ImportOrderCheck.class);
720         checkConfig.addAttribute("option", "top");
721         checkConfig.addAttribute("separated", "true");
722         checkConfig.addAttribute("groups", "java, org");
723         checkConfig.addAttribute("sortStaticImportsAlphabetically", "true");
724         checkConfig.addAttribute("useContainerOrderingForStatic", "true");
725         final String[] expected = CommonUtil.EMPTY_STRING_ARRAY;
726         verify(checkConfig,
727             getNonCompilablePath("InputImportOrderEclipseStaticRepetition.java"), expected);
728     }
729 
730     @Test
731     public void testEclipseDefaultNegative() throws Exception {
732         final DefaultConfiguration checkConfig = createModuleConfig(ImportOrderCheck.class);
733         checkConfig.addAttribute("groups", "java,javax,org,com");
734         checkConfig.addAttribute("ordered", "true");
735         checkConfig.addAttribute("separated", "true");
736         checkConfig.addAttribute("option", "top");
737         checkConfig.addAttribute("sortStaticImportsAlphabetically", "true");
738         final String[] expected = {
739             "12: " + getCheckMessage(MSG_SEPARATION, "javax.swing.JComponent"),
740             "17: " + getCheckMessage(MSG_ORDERING, "org.junit.Test"),
741             };
742 
743         verify(checkConfig,
744             getNonCompilablePath("InputImportOrder_EclipseDefaultNegative.java"), expected);
745     }
746 
747     @Test
748     public void testUseContainerOrderingForStaticTrue() throws Exception {
749         final DefaultConfiguration checkConfig = createModuleConfig(ImportOrderCheck.class);
750         checkConfig.addAttribute("groups", "/^javax?\\./,org");
751         checkConfig.addAttribute("ordered", "true");
752         checkConfig.addAttribute("separated", "true");
753         checkConfig.addAttribute("option", "top");
754         checkConfig.addAttribute("caseSensitive", "false");
755         checkConfig.addAttribute("sortStaticImportsAlphabetically", "true");
756         checkConfig.addAttribute("useContainerOrderingForStatic", "true");
757         final String[] expected = CommonUtil.EMPTY_STRING_ARRAY;
758         verify(checkConfig, getNonCompilablePath("InputImportOrderEclipseStatic.java"), expected);
759     }
760 
761     @Test
762     public void testUseContainerOrderingForStaticFalse() throws Exception {
763         final DefaultConfiguration checkConfig = createModuleConfig(ImportOrderCheck.class);
764         checkConfig.addAttribute("groups", "/^javax?\\./,org");
765         checkConfig.addAttribute("ordered", "true");
766         checkConfig.addAttribute("separated", "true");
767         checkConfig.addAttribute("option", "top");
768         checkConfig.addAttribute("caseSensitive", "false");
769         checkConfig.addAttribute("sortStaticImportsAlphabetically", "true");
770         checkConfig.addAttribute("useContainerOrderingForStatic", "false");
771         final String[] expected = {
772             "6: " + getCheckMessage(MSG_ORDERING,
773                 "io.netty.handler.codec.http.HttpHeaders.Names.addDate"),
774         };
775         verify(checkConfig, getNonCompilablePath("InputImportOrderEclipseStatic.java"), expected);
776     }
777 
778     @Test
779     public void testUseContainerOrderingForStaticTrueCaseSensitive() throws Exception {
780         final DefaultConfiguration checkConfig = createModuleConfig(ImportOrderCheck.class);
781         checkConfig.addAttribute("groups", "/^javax?\\./,org");
782         checkConfig.addAttribute("ordered", "true");
783         checkConfig.addAttribute("separated", "true");
784         checkConfig.addAttribute("option", "top");
785         checkConfig.addAttribute("sortStaticImportsAlphabetically", "true");
786         checkConfig.addAttribute("useContainerOrderingForStatic", "true");
787         final String[] expected = {
788             "7: " + getCheckMessage(MSG_ORDERING,
789                 "io.netty.handler.codec.http.HttpHeaders.Names.DATE"),
790             };
791         verify(checkConfig, getNonCompilablePath("InputImportOrderEclipseStatic.java"), expected);
792     }
793 
794     @Test
795     public void testImportGroupsRedundantSeparatedInternally() throws Exception {
796         final DefaultConfiguration checkConfig = createModuleConfig(ImportOrderCheck.class);
797         checkConfig.addAttribute("groups", "/^javax\\./,com");
798         checkConfig.addAttribute("ordered", "true");
799         checkConfig.addAttribute("separated", "true");
800         checkConfig.addAttribute("option", "bottom");
801         final String[] expected = {
802             "5: " + getCheckMessage(MSG_SEPARATED_IN_GROUP, "org.*"),
803         };
804         verify(checkConfig, getNonCompilablePath("InputImportOrder_MultiplePatternMatches.java"),
805                 expected);
806     }
807 
808     @Test
809     public void testStaticGroupsAbove() throws Exception {
810         final DefaultConfiguration checkConfig = createModuleConfig(ImportOrderCheck.class);
811         checkConfig.addAttribute("groups", "");
812         checkConfig.addAttribute("staticGroups", "");
813         checkConfig.addAttribute("option", "above");
814         final String[] expected = CommonUtil.EMPTY_STRING_ARRAY;
815 
816         verify(checkConfig, getNonCompilablePath("InputImportOrderStaticGroupsAbove.java"),
817                 expected);
818     }
819 
820     @Test
821     public void testStaticGroupsBottom() throws Exception {
822         final DefaultConfiguration checkConfig = createModuleConfig(ImportOrderCheck.class);
823         checkConfig.addAttribute("groups", "org, java");
824         checkConfig.addAttribute("staticGroups", "java, org");
825         checkConfig.addAttribute("option", "bottom");
826         checkConfig.addAttribute("ordered", "true");
827         checkConfig.addAttribute("separated", "true");
828         checkConfig.addAttribute("sortStaticImportsAlphabetically", "true");
829         checkConfig.addAttribute("useContainerOrderingForStatic", "false");
830         final String[] expected = CommonUtil.EMPTY_STRING_ARRAY;
831 
832         verify(checkConfig, getNonCompilablePath("InputImportOrderStaticGroupsBottom.java"),
833                 expected);
834     }
835 
836     @Test
837     public void testStaticGroupsBottomSeparated() throws Exception {
838         final DefaultConfiguration checkConfig = createModuleConfig(ImportOrderCheck.class);
839         checkConfig.addAttribute("groups", "android,com,net,junit,org,java,javax");
840         checkConfig.addAttribute("staticGroups", "android,com,net,junit,org,java,javax");
841         checkConfig.addAttribute("option", "bottom");
842         checkConfig.addAttribute("ordered", "true");
843         checkConfig.addAttribute("sortStaticImportsAlphabetically", "true");
844         checkConfig.addAttribute("separated", "true");
845         checkConfig.addAttribute("separatedStaticGroups", "true");
846         checkConfig.addAttribute("useContainerOrderingForStatic", "false");
847         final String[] expected = CommonUtil.EMPTY_STRING_ARRAY;
848 
849         verify(checkConfig,
850             getNonCompilablePath("InputImportOrderStaticGroupsBottomSeparated.java"), expected);
851     }
852 
853     @Test
854     public void testStaticGroupsInflow() throws Exception {
855         final DefaultConfiguration checkConfig = createModuleConfig(ImportOrderCheck.class);
856         checkConfig.addAttribute("groups", "");
857         checkConfig.addAttribute("staticGroups", "");
858         checkConfig.addAttribute("option", "inflow");
859         final String[] expected = CommonUtil.EMPTY_STRING_ARRAY;
860 
861         verify(checkConfig, getNonCompilablePath("InputImportOrderStaticGroupsInflow.java"),
862                 expected);
863     }
864 
865     @Test
866     public void testStaticGroupsNegative() throws Exception {
867         final DefaultConfiguration checkConfig = createModuleConfig(ImportOrderCheck.class);
868         checkConfig.addAttribute("staticGroups", "org, java");
869         checkConfig.addAttribute("option", "top");
870         checkConfig.addAttribute("ordered", "true");
871         checkConfig.addAttribute("separated", "true");
872         checkConfig.addAttribute("sortStaticImportsAlphabetically", "true");
873         checkConfig.addAttribute("useContainerOrderingForStatic", "false");
874         final String[] expected = {
875             "16: " + getCheckMessage(MSG_ORDERING, "org.junit.Assert.fail"),
876             "18: " + getCheckMessage(MSG_ORDERING, "org.infinispan.test.TestingUtil.extract"),
877         };
878 
879         verify(checkConfig, getNonCompilablePath("InputImportOrderStaticGroupsNegative.java"),
880                 expected);
881     }
882 
883     @Test
884     public void testStaticGroupsTop() throws Exception {
885         final DefaultConfiguration checkConfig = createModuleConfig(ImportOrderCheck.class);
886         checkConfig.addAttribute("groups", "org, com, java, javax");
887         checkConfig.addAttribute("staticGroups", "org, com, java, javax");
888         checkConfig.addAttribute("option", "top");
889         checkConfig.addAttribute("ordered", "true");
890         checkConfig.addAttribute("separated", "true");
891         checkConfig.addAttribute("sortStaticImportsAlphabetically", "true");
892         checkConfig.addAttribute("useContainerOrderingForStatic", "false");
893         final String[] expected = CommonUtil.EMPTY_STRING_ARRAY;
894 
895         verify(checkConfig, getNonCompilablePath("InputImportOrderStaticGroupsTop.java"),
896                 expected);
897     }
898 
899     @Test
900     public void testStaticGroupsTopSeparated() throws Exception {
901         final DefaultConfiguration checkConfig = createModuleConfig(ImportOrderCheck.class);
902         checkConfig.addAttribute("groups", "android, androidx, java");
903         checkConfig.addAttribute("staticGroups", "android, androidx, java");
904         checkConfig.addAttribute("option", "top");
905         checkConfig.addAttribute("ordered", "true");
906         checkConfig.addAttribute("sortStaticImportsAlphabetically", "true");
907         checkConfig.addAttribute("separated", "false");
908         checkConfig.addAttribute("separatedStaticGroups", "true");
909         checkConfig.addAttribute("useContainerOrderingForStatic", "false");
910         final String[] expected = CommonUtil.EMPTY_STRING_ARRAY;
911 
912         verify(checkConfig, getNonCompilablePath("InputImportOrderStaticGroupsTopSeparated.java"),
913                 expected);
914     }
915 
916     @Test
917     public void testStaticGroupsUnordered() throws Exception {
918         final DefaultConfiguration checkConfig = createModuleConfig(ImportOrderCheck.class);
919         checkConfig.addAttribute("groups", "org, com, java");
920         checkConfig.addAttribute("staticGroups", "");
921         checkConfig.addAttribute("option", "top");
922         checkConfig.addAttribute("ordered", "true");
923         checkConfig.addAttribute("separated", "false");
924         checkConfig.addAttribute("sortStaticImportsAlphabetically", "false");
925         final String[] expected = CommonUtil.EMPTY_STRING_ARRAY;
926 
927         verify(checkConfig, getNonCompilablePath("InputImportOrderStaticGroupsUnordered.java"),
928                 expected);
929     }
930 
931 }