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