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