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