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