View Javadoc
1   ///////////////////////////////////////////////////////////////////////////////////////////////
2   // checkstyle: Checks Java source code and other text files for adherence to a set of rules.
3   // Copyright (C) 2001-2025 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;
21  
22  import static com.google.common.truth.Truth.assertWithMessage;
23  import static org.mockito.Mockito.mockConstruction;
24  import static org.mockito.Mockito.when;
25  
26  import java.io.File;
27  import java.nio.file.Files;
28  import java.nio.file.Path;
29  import java.util.ArrayList;
30  import java.util.Collection;
31  import java.util.Collections;
32  import java.util.List;
33  import java.util.Properties;
34  
35  import org.junit.jupiter.api.Test;
36  import org.mockito.MockedConstruction;
37  import org.xml.sax.InputSource;
38  import org.xml.sax.SAXException;
39  
40  import com.puppycrawl.tools.checkstyle.ConfigurationLoader.IgnoredModulesOptions;
41  import com.puppycrawl.tools.checkstyle.api.CheckstyleException;
42  import com.puppycrawl.tools.checkstyle.api.Configuration;
43  import com.puppycrawl.tools.checkstyle.internal.utils.TestUtil;
44  
45  /**
46   * Unit test for ConfigurationLoader.
47   */
48  public class ConfigurationLoaderTest extends AbstractPathTestSupport {
49  
50      @Override
51      protected String getPackageLocation() {
52          return "com/puppycrawl/tools/checkstyle/configurationloader";
53      }
54  
55      private Configuration loadConfiguration(String name) throws Exception {
56          return loadConfiguration(name, new Properties());
57      }
58  
59      private Configuration loadConfiguration(
60          String name, Properties props) throws Exception {
61          final String fName = getPath(name);
62  
63          return ConfigurationLoader.loadConfiguration(fName, new PropertiesExpander(props));
64      }
65  
66      private static Object getInternalLoaderInstance(PropertyResolver resolver)
67               throws Exception {
68  
69          final ConfigurationLoader loader = TestUtil.instantiate(ConfigurationLoader.class,
70                  resolver, false, ThreadModeSettings.SINGLE_THREAD_MODE_INSTANCE);
71  
72          return TestUtil.getInternalState(loader, "saxHandler", Object.class);
73      }
74  
75      private static String invokeReplacePropertiesMethod(
76              Object internalLoader, String value, String defaultValue)
77              throws ReflectiveOperationException {
78          return TestUtil.invokeMethod(internalLoader, "replaceProperties", value, defaultValue);
79      }
80  
81      private static void invokeParsePropertyStringMethod(
82              Object internalLoader,
83              String value,
84              Collection<String> fragments,
85              Collection<String> propertyRefs)
86              throws ReflectiveOperationException {
87          TestUtil.invokeMethod(
88                  internalLoader, "parsePropertyString", value, fragments, propertyRefs);
89      }
90  
91      @Test
92      public void testReplacePropertiesNoReplace() throws Exception {
93          final String[] testValues = {"", "a", "$a", "{a",
94                                       "{a}", "a}", "$a}", "$", "a$b", };
95          final Properties props = initProperties();
96          final Object internalLoader = getInternalLoaderInstance(new PropertiesExpander(props));
97  
98          for (String testValue : testValues) {
99              final String value = invokeReplacePropertiesMethod(internalLoader, testValue, null);
100             assertWithMessage("\"" + testValue + "\"")
101                 .that(testValue)
102                 .isEqualTo(value);
103         }
104     }
105 
106     @Test
107     public void testReplacePropertiesSyntaxError() throws Exception {
108         final Properties props = initProperties();
109         final Object internalLoader = getInternalLoaderInstance(new PropertiesExpander(props));
110 
111         try {
112             final String value = invokeReplacePropertiesMethod(internalLoader, "${a", null);
113             assertWithMessage("expected to fail, instead got: " + value).fail();
114         }
115         catch (ReflectiveOperationException exc) {
116             assertWithMessage("Invalid exception cause message")
117                 .that(exc.getCause())
118                 .isInstanceOf(CheckstyleException.class);
119             assertWithMessage("Invalid exception message")
120                 .that(exc.getCause().getMessage())
121                 .isEqualTo("Syntax error in property: ${a");
122         }
123     }
124 
125     @Test
126     public void testReplacePropertiesMissingProperty() throws Exception {
127         final Properties props = initProperties();
128         final Object internalLoader = getInternalLoaderInstance(new PropertiesExpander(props));
129 
130         try {
131             final String value = invokeReplacePropertiesMethod(internalLoader, "${c}", null);
132             assertWithMessage("expected to fail, instead got: " + value).fail();
133         }
134         catch (ReflectiveOperationException exc) {
135             assertWithMessage("Invalid exception cause message")
136                 .that(exc.getCause())
137                 .isInstanceOf(CheckstyleException.class);
138             assertWithMessage("Invalid exception message")
139                 .that(exc.getCause().getMessage())
140                 .isEqualTo("Property ${c} has not been set");
141         }
142     }
143 
144     @Test
145     public void testReplacePropertiesReplace() throws Exception {
146         final String[][] testValues = {
147             {"${a}", "A"},
148             {"x${a}", "xA"},
149             {"${a}x", "Ax"},
150             {"${a}${b}", "AB"},
151             {"x${a}${b}", "xAB"},
152             {"${a}x${b}", "AxB"},
153             {"${a}${b}x", "ABx"},
154             {"x${a}y${b}", "xAyB"},
155             {"${a}x${b}y", "AxBy"},
156             {"x${a}${b}y", "xABy"},
157             {"x${a}y${b}z", "xAyBz"},
158             {"$$", "$"},
159         };
160         final Properties props = initProperties();
161         final Object internalLoader = getInternalLoaderInstance(new PropertiesExpander(props));
162 
163         for (String[] testValue : testValues) {
164             final String value = invokeReplacePropertiesMethod(internalLoader, testValue[0], null);
165             assertWithMessage("\"" + testValue[0] + "\"")
166                 .that(value)
167                 .isEqualTo(testValue[1]);
168         }
169     }
170 
171     @Test
172     public void testReplacePropertiesDefault() throws Exception {
173         final Properties props = new Properties();
174         final String defaultValue = "defaultValue";
175         final Object internalLoader = getInternalLoaderInstance(new PropertiesExpander(props));
176 
177         final String value =
178                 invokeReplacePropertiesMethod(
179                         internalLoader, "${checkstyle.basedir}", defaultValue);
180 
181         assertWithMessage("Invalid property value")
182             .that(value)
183             .isEqualTo(defaultValue);
184     }
185 
186     @Test
187     public void testParsePropertyString() throws Exception {
188         final Properties props = initProperties();
189         final Object internalLoader = getInternalLoaderInstance(new PropertiesExpander(props));
190 
191         final List<String> propertyRefs = new ArrayList<>();
192         final List<String> fragments = new ArrayList<>();
193 
194         invokeParsePropertyStringMethod(internalLoader, "$", fragments, propertyRefs);
195         assertWithMessage("Fragments list has unexpected amount of items")
196             .that(fragments)
197             .hasSize(1);
198     }
199 
200     private static Properties initProperties() {
201         final Properties props = new Properties();
202         props.setProperty("a", "A");
203         props.setProperty("b", "B");
204         return props;
205     }
206 
207     @Test
208     public void testResourceLoadConfiguration() throws Exception {
209         final Properties props = new Properties();
210         props.setProperty("checkstyle.basedir", "basedir");
211 
212         // load config that's only found in the classpath
213         final DefaultConfiguration config =
214             (DefaultConfiguration) ConfigurationLoader.loadConfiguration(
215                 getPath("InputConfigurationLoaderChecks.xml"), new PropertiesExpander(props));
216 
217         // verify the root, and property substitution
218         final Properties attributes = new Properties();
219         attributes.setProperty("tabWidth", "4");
220         attributes.setProperty("basedir", "basedir");
221         verifyConfigNode(config, "Checker", 3, attributes);
222     }
223 
224     @Test
225     public void testResourceLoadConfigurationWithMultiThreadConfiguration() throws Exception {
226         final Properties props = new Properties();
227         props.setProperty("checkstyle.basedir", "basedir");
228 
229         final PropertiesExpander propertiesExpander = new PropertiesExpander(props);
230         final String configPath = getPath("InputConfigurationLoaderChecks.xml");
231         final ThreadModeSettings multiThreadModeSettings =
232             new ThreadModeSettings(4, 2);
233 
234         try {
235             ConfigurationLoader.loadConfiguration(
236                 configPath, propertiesExpander, multiThreadModeSettings);
237             assertWithMessage("An exception is expected").fail();
238         }
239         catch (IllegalArgumentException exc) {
240             assertWithMessage("Invalid exception message")
241                 .that(exc.getMessage())
242                 .isEqualTo("Multi thread mode for Checker module is not implemented");
243         }
244     }
245 
246     @Test
247     public void testResourceLoadConfigurationWithSingleThreadConfiguration() throws Exception {
248         final Properties props = new Properties();
249         props.setProperty("checkstyle.basedir", "basedir");
250 
251         final PropertiesExpander propertiesExpander = new PropertiesExpander(props);
252         final String configPath = getPath("InputConfigurationLoaderChecks.xml");
253         final ThreadModeSettings singleThreadModeSettings =
254             ThreadModeSettings.SINGLE_THREAD_MODE_INSTANCE;
255 
256         final DefaultConfiguration config =
257             (DefaultConfiguration) ConfigurationLoader.loadConfiguration(
258                 configPath, propertiesExpander, singleThreadModeSettings);
259 
260         final Properties attributes = new Properties();
261         attributes.setProperty("tabWidth", "4");
262         attributes.setProperty("basedir", "basedir");
263         verifyConfigNode(config, "Checker", 3, attributes);
264     }
265 
266     @Test
267     public void testEmptyConfiguration() throws Exception {
268         final DefaultConfiguration config =
269             (DefaultConfiguration) loadConfiguration("InputConfigurationLoaderEmpty.xml");
270         verifyConfigNode(config, "Checker", 0, new Properties());
271     }
272 
273     @Test
274     public void testEmptyModuleResolver() throws Exception {
275         final DefaultConfiguration config =
276             (DefaultConfiguration) loadConfiguration(
277                 "InputConfigurationLoaderEmpty.xml", new Properties());
278         verifyConfigNode(config, "Checker", 0, new Properties());
279     }
280 
281     @Test
282     public void testMissingPropertyName() throws Exception {
283         try {
284             loadConfiguration("InputConfigurationLoaderMissingPropertyName.xml");
285             assertWithMessage("missing property name").fail();
286         }
287         catch (CheckstyleException exc) {
288             assertWithMessage("Invalid exception message: " + exc.getMessage())
289                     .that(exc.getMessage())
290                     .contains("\"name\"");
291             assertWithMessage("Invalid exception message: " + exc.getMessage())
292                     .that(exc.getMessage())
293                     .contains("\"property\"");
294             assertWithMessage("Invalid exception message: " + exc.getMessage())
295                     .that(exc.getMessage())
296                     .endsWith(":8:41");
297         }
298     }
299 
300     @Test
301     public void testMissingPropertyNameInMethodWithBooleanParameter() throws Exception {
302         try {
303             final String fName = getPath("InputConfigurationLoaderMissingPropertyName.xml");
304             ConfigurationLoader.loadConfiguration(fName, new PropertiesExpander(new Properties()),
305                     IgnoredModulesOptions.EXECUTE);
306 
307             assertWithMessage("missing property name").fail();
308         }
309         catch (CheckstyleException exc) {
310             assertWithMessage("Invalid exception message: " + exc.getMessage())
311                     .that(exc.getMessage())
312                     .contains("\"name\"");
313             assertWithMessage("Invalid exception message: " + exc.getMessage())
314                     .that(exc.getMessage())
315                     .contains("\"property\"");
316             assertWithMessage("Invalid exception message: " + exc.getMessage())
317                     .that(exc.getMessage())
318                     .endsWith(":8:41");
319         }
320     }
321 
322     @Test
323     public void testMissingPropertyValue() throws Exception {
324         try {
325             loadConfiguration("InputConfigurationLoaderMissingPropertyValue.xml");
326             assertWithMessage("missing property value").fail();
327         }
328         catch (CheckstyleException exc) {
329             assertWithMessage("Invalid exception message: " + exc.getMessage())
330                     .that(exc.getMessage())
331                     .contains("\"value\"");
332             assertWithMessage("Invalid exception message: " + exc.getMessage())
333                     .that(exc.getMessage())
334                     .contains("\"property\"");
335             assertWithMessage("Invalid exception message: " + exc.getMessage())
336                     .that(exc.getMessage())
337                     .endsWith(":8:43");
338         }
339     }
340 
341     @Test
342     public void testMissingConfigName() throws Exception {
343         try {
344             loadConfiguration("InputConfigurationLoaderMissingConfigName.xml");
345             assertWithMessage("missing module name").fail();
346         }
347         catch (CheckstyleException exc) {
348             assertWithMessage("Invalid exception message: " + exc.getMessage())
349                     .that(exc.getMessage())
350                     .contains("\"name\"");
351             assertWithMessage("Invalid exception message: " + exc.getMessage())
352                     .that(exc.getMessage())
353                     .contains("\"module\"");
354             assertWithMessage("Invalid exception message: " + exc.getMessage())
355                     .that(exc.getMessage())
356                     .endsWith(":7:23");
357         }
358     }
359 
360     @Test
361     public void testMissingConfigParent() throws Exception {
362         try {
363             loadConfiguration("InputConfigurationLoaderMissingConfigParent.xml");
364             assertWithMessage("missing module parent").fail();
365         }
366         catch (CheckstyleException exc) {
367             assertWithMessage("Invalid exception message: " + exc.getMessage())
368                     .that(exc.getMessage())
369                     .contains("\"property\"");
370             assertWithMessage("Invalid exception message: " + exc.getMessage())
371                     .that(exc.getMessage())
372                     .contains("\"module\"");
373             assertWithMessage("Invalid exception message: " + exc.getMessage())
374                     .that(exc.getMessage())
375                     .endsWith(":8:38");
376         }
377     }
378 
379     @Test
380     public void testCheckstyleChecks() throws Exception {
381         final Properties props = new Properties();
382         props.setProperty("checkstyle.basedir", "basedir");
383 
384         final DefaultConfiguration config =
385             (DefaultConfiguration) loadConfiguration(
386                 "InputConfigurationLoaderChecks.xml", props);
387 
388         // verify the root, and property substitution
389         final Properties atts = new Properties();
390         atts.setProperty("tabWidth", "4");
391         atts.setProperty("basedir", "basedir");
392         verifyConfigNode(config, "Checker", 3, atts);
393 
394         // verify children
395         final Configuration[] children = config.getChildren();
396         atts.clear();
397         verifyConfigNode(
398             (DefaultConfiguration) children[1], "JavadocPackage", 0, atts);
399         verifyConfigNode(
400             (DefaultConfiguration) children[2], "Translation", 0, atts);
401         atts.setProperty("testName", "testValue");
402         verifyConfigNode(
403             (DefaultConfiguration) children[0],
404             "TreeWalker",
405             8,
406             atts);
407 
408         // verify TreeWalker's first, last, NoWhitespaceAfterCheck
409         final Configuration[] grandchildren = children[0].getChildren();
410         atts.clear();
411         verifyConfigNode(
412             (DefaultConfiguration) grandchildren[0],
413             "AvoidStarImport",
414             0,
415             atts);
416         atts.setProperty("format", "System.out.println");
417         verifyConfigNode(
418             (DefaultConfiguration) grandchildren[grandchildren.length - 1],
419             "GenericIllegalRegexp",
420             0,
421             atts);
422         atts.clear();
423         atts.setProperty("tokens", "DOT");
424         atts.setProperty("allowLineBreaks", "true");
425         verifyConfigNode(
426             (DefaultConfiguration) grandchildren[6],
427             "NoWhitespaceAfter",
428             0,
429             atts);
430     }
431 
432     @Test
433     public void testCustomMessages() throws Exception {
434         final Properties props = new Properties();
435         props.setProperty("checkstyle.basedir", "basedir");
436 
437         final DefaultConfiguration config =
438             (DefaultConfiguration) loadConfiguration(
439                 "InputConfigurationLoaderCustomMessages.xml", props);
440 
441         final Configuration[] children = config.getChildren();
442         final Configuration[] grandchildren = children[0].getChildren();
443         final List<String> messages = new ArrayList<>(grandchildren[0].getMessages().values());
444         final String expectedKey = "name.invalidPattern";
445         final List<String> expectedMessages = Collections
446                 .singletonList("Member ''{0}'' must start with ''m'' (checked pattern ''{1}'').");
447         assertWithMessage("Messages should contain key: " + expectedKey)
448                 .that(grandchildren[0].getMessages())
449                 .containsKey(expectedKey);
450         assertWithMessage("Message is not expected")
451                 .that(messages)
452                 .isEqualTo(expectedMessages);
453     }
454 
455     private static void verifyConfigNode(
456         DefaultConfiguration config, String name, int childrenLength,
457         Properties atts) throws Exception {
458         assertWithMessage("name.")
459             .that(config.getName())
460             .isEqualTo(name);
461         assertWithMessage("children.length.")
462             .that(config.getChildren().length)
463             .isEqualTo(childrenLength);
464 
465         final String[] attNames = config.getPropertyNames();
466         assertWithMessage("attributes.length")
467             .that(attNames.length)
468             .isEqualTo(atts.size());
469 
470         for (String attName : attNames) {
471             final String attribute = config.getProperty(attName);
472             assertWithMessage("attribute[" + attName + "]")
473                 .that(attribute)
474                 .isEqualTo(atts.getProperty(attName));
475         }
476     }
477 
478     @Test
479     public void testSystemEntity() throws Exception {
480         final Properties props = new Properties();
481         props.setProperty("checkstyle.basedir", "basedir");
482 
483         final DefaultConfiguration config =
484             (DefaultConfiguration) loadConfiguration(
485                 "InputConfigurationLoaderSystemDoctype.xml", props);
486 
487         final Properties atts = new Properties();
488         atts.setProperty("tabWidth", "4");
489 
490         verifyConfigNode(config, "Checker", 0, atts);
491     }
492 
493     @Test
494     public void testExternalEntity() throws Exception {
495         final Properties props = new Properties();
496         props.setProperty("checkstyle.basedir", "basedir");
497 
498         System.setProperty(
499                 XmlLoader.LoadExternalDtdFeatureProvider.ENABLE_EXTERNAL_DTD_LOAD, "true");
500 
501         final DefaultConfiguration config =
502             (DefaultConfiguration) loadConfiguration(
503                 "InputConfigurationLoaderExternalEntity.xml", props);
504 
505         final Properties atts = new Properties();
506         atts.setProperty("tabWidth", "4");
507         atts.setProperty("basedir", "basedir");
508         verifyConfigNode(config, "Checker", 2, atts);
509     }
510 
511     @Test
512     public void testExternalEntitySubdirectory() throws Exception {
513         final Properties props = new Properties();
514         props.setProperty("checkstyle.basedir", "basedir");
515 
516         System.setProperty(
517                 XmlLoader.LoadExternalDtdFeatureProvider.ENABLE_EXTERNAL_DTD_LOAD, "true");
518 
519         final DefaultConfiguration config =
520             (DefaultConfiguration) loadConfiguration(
521                 "subdir/InputConfigurationLoaderExternalEntitySubDir.xml", props);
522 
523         final Properties attributes = new Properties();
524         attributes.setProperty("tabWidth", "4");
525         attributes.setProperty("basedir", "basedir");
526         verifyConfigNode(config, "Checker", 2, attributes);
527     }
528 
529     @Test
530     public void testExternalEntityFromUri() throws Exception {
531         final Properties props = new Properties();
532         props.setProperty("checkstyle.basedir", "basedir");
533 
534         System.setProperty(
535                 XmlLoader.LoadExternalDtdFeatureProvider.ENABLE_EXTERNAL_DTD_LOAD, "true");
536 
537         final File file = new File(
538                 getPath("subdir/InputConfigurationLoaderExternalEntitySubDir.xml"));
539         final DefaultConfiguration config =
540             (DefaultConfiguration) ConfigurationLoader.loadConfiguration(
541                     file.toURI().toString(), new PropertiesExpander(props));
542 
543         final Properties atts = new Properties();
544         atts.setProperty("tabWidth", "4");
545         atts.setProperty("basedir", "basedir");
546         verifyConfigNode(config, "Checker", 2, atts);
547     }
548 
549     @Test
550     public void testIncorrectTag() throws Exception {
551         final Class<?> aClassParent = ConfigurationLoader.class;
552         final Object objParent = TestUtil.instantiate(aClassParent, null, true, null);
553 
554         final Class<?> aClass = Class.forName("com.puppycrawl.tools.checkstyle."
555                 + "ConfigurationLoader$InternalLoader");
556         final Object obj = TestUtil.instantiate(aClass, objParent);
557 
558         try {
559             TestUtil.invokeMethod(obj, "startElement", "", "", "hello", null);
560 
561             assertWithMessage("InvocationTargetException is expected").fail();
562         }
563         catch (ReflectiveOperationException exc) {
564             assertWithMessage("Invalid exception cause message")
565                 .that(exc)
566                     .hasCauseThat()
567                         .hasMessageThat()
568                         .isEqualTo("Unknown name:" + "hello" + ".");
569         }
570     }
571 
572     @Test
573     public void testNonExistentPropertyName() throws Exception {
574         try {
575             loadConfiguration("InputConfigurationLoaderNonexistentProperty.xml");
576             assertWithMessage("exception in expected").fail();
577         }
578         catch (CheckstyleException exc) {
579             assertWithMessage("Invalid exception message")
580                 .that(exc.getMessage())
581                 .isEqualTo("unable to parse configuration stream");
582             assertWithMessage("Expected cause of type SAXException")
583                 .that(exc.getCause())
584                 .isInstanceOf(SAXException.class);
585             assertWithMessage("Expected cause of type CheckstyleException")
586                 .that(exc.getCause().getCause())
587                 .isInstanceOf(CheckstyleException.class);
588             assertWithMessage("Invalid exception cause message")
589                 .that(exc)
590                 .hasCauseThat()
591                 .hasCauseThat()
592                 .hasMessageThat()
593                 .isEqualTo("Property ${nonexistent} has not been set");
594         }
595     }
596 
597     @Test
598     public void testConfigWithIgnore() throws Exception {
599         final DefaultConfiguration config =
600                 (DefaultConfiguration) ConfigurationLoader.loadConfiguration(
601                         getPath("InputConfigurationLoaderModuleIgnoreSeverity.xml"),
602                         new PropertiesExpander(new Properties()), IgnoredModulesOptions.OMIT);
603 
604         final Configuration[] children = config.getChildren();
605         final int length = children[0].getChildren().length;
606         assertWithMessage("Invalid children count")
607             .that(length)
608             .isEqualTo(0);
609     }
610 
611     @Test
612     public void testConfigWithIgnoreUsingInputSource() throws Exception {
613         final DefaultConfiguration config =
614                 (DefaultConfiguration) ConfigurationLoader.loadConfiguration(new InputSource(
615                         new File(getPath("InputConfigurationLoaderModuleIgnoreSeverity.xml"))
616                             .toURI().toString()),
617                         new PropertiesExpander(new Properties()), IgnoredModulesOptions.OMIT);
618 
619         final Configuration[] children = config.getChildren();
620         final int length = children[0].getChildren().length;
621         assertWithMessage("Invalid children count")
622             .that(length)
623             .isEqualTo(0);
624     }
625 
626     @Test
627     public void testConfigCheckerWithIgnore() throws Exception {
628         final DefaultConfiguration config =
629                 (DefaultConfiguration) ConfigurationLoader.loadConfiguration(
630                         getPath("InputConfigurationLoaderCheckerIgnoreSeverity.xml"),
631                         new PropertiesExpander(new Properties()), IgnoredModulesOptions.OMIT);
632 
633         final Configuration[] children = config.getChildren();
634         assertWithMessage("Invalid children count")
635             .that(children.length)
636             .isEqualTo(0);
637     }
638 
639     @Test
640     public void testLoadConfigurationWrongUrl() {
641         try {
642             ConfigurationLoader.loadConfiguration(
643                     ";InputConfigurationLoaderModuleIgnoreSeverity.xml",
644                     new PropertiesExpander(new Properties()), IgnoredModulesOptions.OMIT);
645 
646             assertWithMessage("Exception is expected").fail();
647         }
648         catch (CheckstyleException exc) {
649             assertWithMessage("Invalid exception message")
650                 .that(exc.getMessage())
651                 .isEqualTo("Unable to find: ;InputConfigurationLoaderModuleIgnoreSeverity.xml");
652         }
653     }
654 
655     @Test
656     public void testLoadConfigurationDeprecated() throws Exception {
657         final DefaultConfiguration config =
658                 (DefaultConfiguration) ConfigurationLoader.loadConfiguration(
659                         new InputSource(Files.newInputStream(Path.of(
660                             getPath("InputConfigurationLoaderModuleIgnoreSeverity.xml")))),
661                         new PropertiesExpander(new Properties()), IgnoredModulesOptions.OMIT);
662 
663         final Configuration[] children = config.getChildren();
664         final int length = children[0].getChildren().length;
665         assertWithMessage("Invalid children count")
666             .that(length)
667             .isEqualTo(0);
668     }
669 
670     @Test
671     public void testLoadConfigurationFromClassPath() throws Exception {
672         final DefaultConfiguration config =
673                 (DefaultConfiguration) ConfigurationLoader.loadConfiguration(
674                         getPath("InputConfigurationLoaderModuleIgnoreSeverity.xml"),
675                         new PropertiesExpander(new Properties()), IgnoredModulesOptions.OMIT);
676 
677         final Configuration[] children = config.getChildren();
678         final int length = children[0].getChildren().length;
679         assertWithMessage("Invalid children count")
680             .that(length)
681             .isEqualTo(0);
682     }
683 
684     @Test
685     public void testLoadConfigurationFromClassPathWithNonAsciiSymbolsInPath() throws Exception {
686         final DefaultConfiguration config =
687                 (DefaultConfiguration) ConfigurationLoader.loadConfiguration(
688                     getResourcePath("棵¥/InputConfigurationLoaderDefaultProperty.xml"),
689                         new PropertiesExpander(new Properties()));
690 
691         final Properties expectedPropertyValues = new Properties();
692         expectedPropertyValues.setProperty("tabWidth", "2");
693         expectedPropertyValues.setProperty("basedir", ".");
694         // charset property uses 2 variables, one is not defined, so default becomes a result value
695         expectedPropertyValues.setProperty("charset", "ASCII");
696         verifyConfigNode(config, "Checker", 0, expectedPropertyValues);
697     }
698 
699     @Test
700     public void testConstructors() throws Exception {
701         final Properties props = new Properties();
702         props.setProperty("checkstyle.basedir", "basedir");
703         final String fName = getPath("InputConfigurationLoaderChecks.xml");
704 
705         final Configuration configuration = ConfigurationLoader.loadConfiguration(fName,
706                 new PropertiesExpander(props), ConfigurationLoader.IgnoredModulesOptions.OMIT);
707         assertWithMessage("Name is not expected")
708             .that(configuration.getName())
709             .isEqualTo("Checker");
710 
711         final DefaultConfiguration configuration1 =
712                 (DefaultConfiguration) ConfigurationLoader.loadConfiguration(
713                         new InputSource(Files.newInputStream(Path.of(
714                             getPath("InputConfigurationLoaderModuleIgnoreSeverity.xml")))),
715                         new PropertiesExpander(new Properties()),
716                         ConfigurationLoader.IgnoredModulesOptions.EXECUTE);
717 
718         final Configuration[] children = configuration1.getChildren();
719         final int length = children[0].getChildren().length;
720         assertWithMessage("Unexpected children size")
721             .that(length)
722             .isEqualTo(1);
723     }
724 
725     @Test
726     public void testConfigWithIgnoreExceptionalAttributes() {
727         try (MockedConstruction<DefaultConfiguration> mocked = mockConstruction(
728                 DefaultConfiguration.class, (mock, context) -> {
729                     when(mock.getPropertyNames()).thenReturn(new String[] {"severity"});
730                     when(mock.getName()).thenReturn("MemberName");
731                     when(mock.getProperty("severity")).thenThrow(CheckstyleException.class);
732                 })) {
733             final CheckstyleException ex =
734                     TestUtil.getExpectedThrowable(CheckstyleException.class, () -> {
735                         ConfigurationLoader.loadConfiguration(
736                                 getPath("InputConfigurationLoaderModuleIgnoreSeverity.xml"),
737                                 new PropertiesExpander(
738                                         new Properties()), IgnoredModulesOptions.OMIT);
739                     });
740             final String expectedMessage =
741                 "Problem during accessing 'severity' attribute for MemberName";
742             assertWithMessage("Invalid exception cause message")
743                 .that(ex)
744                 .hasCauseThat()
745                     .hasMessageThat()
746                     .isEqualTo(expectedMessage);
747         }
748     }
749 
750     @Test
751     public void testLoadConfiguration3() throws Exception {
752         final String[] configFiles = {
753             "InputConfigurationLoaderOldConfig0.xml",
754             "InputConfigurationLoaderOldConfig1.xml",
755             "InputConfigurationLoaderOldConfig2.xml",
756             "InputConfigurationLoaderOldConfig3.xml",
757             "InputConfigurationLoaderOldConfig4.xml",
758             "InputConfigurationLoaderOldConfig5.xml",
759             "InputConfigurationLoaderOldConfig6.xml",
760             "InputConfigurationLoaderOldConfig7.xml",
761         };
762 
763         for (String configFile : configFiles) {
764             final DefaultConfiguration config =
765                     (DefaultConfiguration) ConfigurationLoader.loadConfiguration(
766                             new InputSource(Files.newInputStream(Path.of(
767                                     getPath(configFile)))),
768                             new PropertiesExpander(new Properties()),
769                             IgnoredModulesOptions.OMIT);
770 
771             assertWithMessage("should have properties")
772                     .that(config.getPropertyNames()).asList()
773                     .contains("severity");
774 
775             assertWithMessage("should have properties")
776                     .that(config.getPropertyNames()).asList()
777                     .contains("fileExtensions");
778 
779             assertWithMessage("")
780                     .that(config.getAttribute("severity"))
781                     .isEqualTo("error");
782 
783             assertWithMessage("")
784                     .that(config.getAttribute("fileExtensions"))
785                     .isEqualTo("java, properties, xml");
786 
787             assertWithMessage("")
788                     .that(config.getChildren().length)
789                     .isEqualTo(1);
790 
791             final Configuration[] children = config.getChildren();
792             final Configuration[] grandchildren = children[0].getChildren();
793 
794             assertWithMessage("")
795                     .that(children[0].getPropertyNames()).asList()
796                     .contains("severity");
797 
798             assertWithMessage("")
799                     .that(grandchildren[0].getPropertyNames()).asList()
800                     .contains("query");
801         }
802     }
803 
804     @Test
805     public void testDefaultValuesForNonDefinedProperties() throws Exception {
806         final Properties props = new Properties();
807         props.setProperty("checkstyle.charset.base", "UTF");
808 
809         final File file = new File(
810                 getPath("InputConfigurationLoaderDefaultProperty.xml"));
811         final DefaultConfiguration config =
812             (DefaultConfiguration) ConfigurationLoader.loadConfiguration(
813                     file.toURI().toString(), new PropertiesExpander(props));
814 
815         final Properties expectedPropertyValues = new Properties();
816         expectedPropertyValues.setProperty("tabWidth", "2");
817         expectedPropertyValues.setProperty("basedir", ".");
818         // charset property uses 2 variables, one is not defined, so default becomes a result value
819         expectedPropertyValues.setProperty("charset", "ASCII");
820         verifyConfigNode(config, "Checker", 0, expectedPropertyValues);
821     }
822 
823 }