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