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.PackageObjectFactory.AMBIGUOUS_MODULE_NAME_EXCEPTION_MESSAGE;
24  import static com.puppycrawl.tools.checkstyle.PackageObjectFactory.BASE_PACKAGE;
25  import static com.puppycrawl.tools.checkstyle.PackageObjectFactory.CHECK_SUFFIX;
26  import static com.puppycrawl.tools.checkstyle.PackageObjectFactory.ModuleLoadOption.SEARCH_REGISTERED_PACKAGES;
27  import static com.puppycrawl.tools.checkstyle.PackageObjectFactory.ModuleLoadOption.TRY_IN_ALL_REGISTERED_PACKAGES;
28  import static com.puppycrawl.tools.checkstyle.PackageObjectFactory.NULL_LOADER_MESSAGE;
29  import static com.puppycrawl.tools.checkstyle.PackageObjectFactory.NULL_PACKAGE_MESSAGE;
30  import static com.puppycrawl.tools.checkstyle.PackageObjectFactory.PACKAGE_SEPARATOR;
31  import static com.puppycrawl.tools.checkstyle.PackageObjectFactory.STRING_SEPARATOR;
32  import static com.puppycrawl.tools.checkstyle.PackageObjectFactory.UNABLE_TO_INSTANTIATE_EXCEPTION_MESSAGE;
33  import static com.puppycrawl.tools.checkstyle.internal.utils.TestUtil.getExpectedThrowable;
34  import static org.mockito.Mockito.mockStatic;
35  
36  import java.io.File;
37  import java.io.IOException;
38  import java.util.Arrays;
39  import java.util.Collection;
40  import java.util.Collections;
41  import java.util.HashSet;
42  import java.util.LinkedHashSet;
43  import java.util.Locale;
44  import java.util.Map;
45  import java.util.Optional;
46  import java.util.Set;
47  
48  import org.junit.jupiter.api.AfterAll;
49  import org.junit.jupiter.api.BeforeAll;
50  import org.junit.jupiter.api.Test;
51  import org.mockito.MockedStatic;
52  import org.mockito.Mockito;
53  
54  import com.puppycrawl.tools.checkstyle.api.AbstractFileSetCheck;
55  import com.puppycrawl.tools.checkstyle.api.CheckstyleException;
56  import com.puppycrawl.tools.checkstyle.api.FileText;
57  import com.puppycrawl.tools.checkstyle.api.Violation;
58  import com.puppycrawl.tools.checkstyle.checks.annotation.AnnotationLocationCheck;
59  import com.puppycrawl.tools.checkstyle.internal.utils.CheckUtil;
60  import com.puppycrawl.tools.checkstyle.internal.utils.TestUtil;
61  import com.puppycrawl.tools.checkstyle.utils.ModuleReflectionUtil;
62  
63  /**
64   * Enter a description of class PackageObjectFactoryTest.java.
65   *
66   */
67  public class PackageObjectFactoryTest {
68  
69      private static Locale defaultLocale;
70      private final PackageObjectFactory factory = new PackageObjectFactory(
71              BASE_PACKAGE, Thread.currentThread().getContextClassLoader());
72  
73      @BeforeAll
74      public static void setupLocale() {
75          defaultLocale = Locale.getDefault();
76          Locale.setDefault(Locale.ENGLISH);
77      }
78  
79      @AfterAll
80      public static void restoreLocale() {
81          Locale.setDefault(defaultLocale);
82      }
83  
84      @Test
85      public void testCtorNullLoaderException1() {
86          final IllegalArgumentException exc =
87                  getExpectedThrowable(IllegalArgumentException.class, () -> {
88                      final Object test =
89                              new PackageObjectFactory(new HashSet<>(), null);
90                      assertWithMessage("Exception is expected but got %s", test).fail();
91                  });
92          assertWithMessage("Invalid exception message")
93              .that(exc.getMessage())
94              .isEqualTo(NULL_LOADER_MESSAGE);
95      }
96  
97      @Test
98      public void testCtorNullLoaderException2() {
99          final IllegalArgumentException exc =
100                 getExpectedThrowable(IllegalArgumentException.class, () -> {
101                     final Object test = new PackageObjectFactory("test", null);
102                     assertWithMessage("Exception is expected but got %s", test).fail();
103                 });
104         assertWithMessage("Invalid exception message")
105             .that(exc.getMessage())
106             .isEqualTo(NULL_LOADER_MESSAGE);
107     }
108 
109     @Test
110     public void testCtorNullPackageException1() {
111         final ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
112         final IllegalArgumentException exc =
113                 getExpectedThrowable(IllegalArgumentException.class, () -> {
114                     final Object test =
115                             new PackageObjectFactory(Collections.singleton(null), classLoader);
116                     assertWithMessage("Exception is expected but got %s", test).fail();
117                 });
118         assertWithMessage("Invalid exception message")
119             .that(exc.getMessage())
120             .isEqualTo(NULL_PACKAGE_MESSAGE);
121     }
122 
123     @Test
124     public void testCtorNullPackageException2() {
125         final ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
126         final IllegalArgumentException exc =
127                 getExpectedThrowable(IllegalArgumentException.class, () -> {
128                     final Object test =
129                             new PackageObjectFactory((String) null, classLoader);
130                     assertWithMessage("Exception is expected but got %s", test).fail();
131                 });
132         assertWithMessage("Invalid exception message")
133             .that(exc.getMessage())
134             .isEqualTo(NULL_PACKAGE_MESSAGE);
135     }
136 
137     @Test
138     public void testCtorNullPackageException3() {
139         final ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
140         final IllegalArgumentException exc =
141                 getExpectedThrowable(IllegalArgumentException.class, () -> {
142                     final Object test =
143                             new PackageObjectFactory(Collections.singleton(null), classLoader,
144                                     TRY_IN_ALL_REGISTERED_PACKAGES);
145                     assertWithMessage("Exception is expected but got %s", test).fail();
146                 });
147         assertWithMessage("Invalid exception message")
148             .that(exc.getMessage())
149             .isEqualTo(NULL_PACKAGE_MESSAGE);
150     }
151 
152     @Test
153     public void testMakeObjectFromName()
154             throws CheckstyleException {
155         final Checker checker =
156             (Checker) factory.createModule(
157                         "com.puppycrawl.tools.checkstyle.Checker");
158         assertWithMessage("Checker should not be null when creating module from name")
159             .that(checker)
160             .isNotNull();
161     }
162 
163     @Test
164     public void testMakeCheckFromName() {
165         final String name = "com.puppycrawl.tools.checkstyle.checks.naming.ConstantName";
166         final CheckstyleException exc =
167                 getExpectedThrowable(CheckstyleException.class, () -> {
168                     factory.createModule(name);
169                 }, "Exception is expected");
170         final LocalizedMessage exceptionMessage = new LocalizedMessage(
171                 Definitions.CHECKSTYLE_BUNDLE, factory.getClass(),
172                 UNABLE_TO_INSTANTIATE_EXCEPTION_MESSAGE, name, null);
173         assertWithMessage("Invalid exception message")
174             .that(exc.getMessage())
175             .isEqualTo(exceptionMessage.getMessage());
176     }
177 
178     @Test
179     public void testCreateModuleWithNonExistName() {
180         final String[] names = {"NonExistClassOne", "NonExistClassTwo", };
181         for (String name : names) {
182             final CheckstyleException exc =
183                     getExpectedThrowable(CheckstyleException.class, () -> {
184                         factory.createModule(name);
185                     }, "Exception is expected");
186             final String attemptedNames = BASE_PACKAGE + PACKAGE_SEPARATOR + name
187                 + STRING_SEPARATOR + name + CHECK_SUFFIX + STRING_SEPARATOR
188                 + BASE_PACKAGE + PACKAGE_SEPARATOR + name + CHECK_SUFFIX;
189             final LocalizedMessage exceptionMessage = new LocalizedMessage(
190                 Definitions.CHECKSTYLE_BUNDLE, factory.getClass(),
191                 UNABLE_TO_INSTANTIATE_EXCEPTION_MESSAGE, name, attemptedNames);
192             assertWithMessage("Invalid exception message")
193                 .that(exc.getMessage())
194                 .isEqualTo(exceptionMessage.getMessage());
195         }
196     }
197 
198     @Test
199     public void testCreateObjectFromMap() throws Exception {
200         final String moduleName = "Foo";
201         final String name = moduleName + CHECK_SUFFIX;
202         final String packageName = BASE_PACKAGE + ".internal.testmodules.packageobjectfactory.bar";
203         final String fullName = packageName + PACKAGE_SEPARATOR + name;
204         final ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
205         final PackageObjectFactory objectFactory =
206                 new PackageObjectFactory(packageName, classLoader);
207         final Object instance1 = objectFactory.createModule(name);
208         assertWithMessage("Invalid canonical name")
209             .that(instance1.getClass().getCanonicalName())
210             .isEqualTo(fullName);
211         final Object instance2 = objectFactory.createModule(moduleName);
212         assertWithMessage("Invalid canonical name")
213             .that(instance2.getClass().getCanonicalName())
214             .isEqualTo(fullName);
215     }
216 
217     @Test
218     public void testCreateStandardModuleObjectFromMap() throws Exception {
219         final String moduleName = "TreeWalker";
220         final String packageName = BASE_PACKAGE + ".internal.testmodules.packageobjectfactory.bar";
221         final String fullName = BASE_PACKAGE + PACKAGE_SEPARATOR + moduleName;
222         final ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
223         final PackageObjectFactory objectFactory =
224                 new PackageObjectFactory(packageName, classLoader);
225         final Object instance = objectFactory.createModule(moduleName);
226         assertWithMessage("Invalid canonical name")
227             .that(instance.getClass().getCanonicalName())
228             .isEqualTo(fullName);
229     }
230 
231     @Test
232     public void testCreateStandardCheckModuleObjectFromMap() throws Exception {
233         final String moduleName = "TypeName";
234         final String packageName = BASE_PACKAGE + ".internal.testmodules.packageobjectfactory.bar";
235         final String fullName = BASE_PACKAGE + PACKAGE_SEPARATOR + "checks" + PACKAGE_SEPARATOR
236             + "naming" + PACKAGE_SEPARATOR + moduleName + CHECK_SUFFIX;
237         final ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
238         final PackageObjectFactory objectFactory =
239                 new PackageObjectFactory(packageName, classLoader);
240         final Object instance = objectFactory.createModule(moduleName);
241         assertWithMessage("Invalid canonical name")
242             .that(instance.getClass().getCanonicalName())
243             .isEqualTo(fullName);
244     }
245 
246     @Test
247     public void testCreateObjectFromFullModuleNamesWithAmbiguousException() {
248         final String barPackage = BASE_PACKAGE + ".internal.testmodules.packageobjectfactory.bar";
249         final String fooPackage = BASE_PACKAGE + ".internal.testmodules.packageobjectfactory.foo";
250         final ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
251         final PackageObjectFactory objectFactory = new PackageObjectFactory(
252                 new LinkedHashSet<>(Arrays.asList(barPackage, fooPackage)), classLoader);
253         final String name = "FooCheck";
254         final CheckstyleException exc =
255                 getExpectedThrowable(CheckstyleException.class, () -> {
256                     objectFactory.createModule(name);
257                 }, "Exception is expected");
258         final String optionalNames = barPackage + PACKAGE_SEPARATOR + name
259                 + STRING_SEPARATOR + fooPackage + PACKAGE_SEPARATOR + name;
260         final LocalizedMessage exceptionMessage = new LocalizedMessage(
261                 Definitions.CHECKSTYLE_BUNDLE, getClass(),
262                 AMBIGUOUS_MODULE_NAME_EXCEPTION_MESSAGE, name, optionalNames);
263         assertWithMessage("Invalid exception message")
264             .that(exc.getMessage())
265             .isEqualTo(exceptionMessage.getMessage());
266     }
267 
268     @Test
269     public void testCreateObjectFromFullModuleNamesWithCantInstantiateException() {
270         final String package1 = BASE_PACKAGE + ".wrong1";
271         final String package2 = BASE_PACKAGE + ".wrong2";
272         final ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
273         final PackageObjectFactory objectFactory = new PackageObjectFactory(
274                 new LinkedHashSet<>(Arrays.asList(package1, package2)), classLoader);
275         final String name = "FooCheck";
276         final String checkName = name + CHECK_SUFFIX;
277         final CheckstyleException exc =
278                 getExpectedThrowable(CheckstyleException.class, () -> {
279                     objectFactory.createModule(name);
280                 }, "Exception is expected");
281         final String attemptedNames = package1 + PACKAGE_SEPARATOR + name + STRING_SEPARATOR
282                 + package2 + PACKAGE_SEPARATOR + name + STRING_SEPARATOR
283                 + checkName + STRING_SEPARATOR
284                 + package1 + PACKAGE_SEPARATOR + checkName + STRING_SEPARATOR
285                 + package2 + PACKAGE_SEPARATOR + checkName;
286         final LocalizedMessage exceptionMessage = new LocalizedMessage(
287                 Definitions.CHECKSTYLE_BUNDLE, getClass(),
288                 UNABLE_TO_INSTANTIATE_EXCEPTION_MESSAGE, name, attemptedNames);
289         assertWithMessage("Invalid exception message")
290             .that(exc.getMessage())
291             .isEqualTo(exceptionMessage.getMessage());
292     }
293 
294     @Test
295     public void testCreateObjectFromFullModuleNamesWithExceptionByBruteForce() {
296         final String package1 = BASE_PACKAGE + ".wrong1";
297         final String package2 = BASE_PACKAGE + ".wrong2";
298         final ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
299         final PackageObjectFactory objectFactory = new PackageObjectFactory(
300                 new LinkedHashSet<>(Arrays.asList(package1, package2)), classLoader,
301                 TRY_IN_ALL_REGISTERED_PACKAGES);
302         final String name = "FooCheck";
303         final String checkName = name + CHECK_SUFFIX;
304         final CheckstyleException exc =
305                 getExpectedThrowable(CheckstyleException.class, () -> {
306                     objectFactory.createModule(name);
307                 }, "Exception is expected");
308         final String attemptedNames = package1 + PACKAGE_SEPARATOR + name + STRING_SEPARATOR
309                 + package2 + PACKAGE_SEPARATOR + name + STRING_SEPARATOR
310                 + checkName + STRING_SEPARATOR
311                 + package1 + PACKAGE_SEPARATOR + checkName + STRING_SEPARATOR
312                 + package2 + PACKAGE_SEPARATOR + checkName;
313         final Violation exceptionMessage = new Violation(1,
314                 Definitions.CHECKSTYLE_BUNDLE, UNABLE_TO_INSTANTIATE_EXCEPTION_MESSAGE,
315                 new String[] {name, attemptedNames}, null, getClass(), null);
316         assertWithMessage("Invalid exception message")
317             .that(exc.getMessage())
318             .isEqualTo(exceptionMessage.getViolation());
319     }
320 
321     @Test
322     public void testCreateObjectByBruteForce() throws Exception {
323         final String className = "Checker";
324         final Checker checker =
325                 TestUtil.invokeMethod(factory, "createModuleByTryInEachPackage",
326                         Checker.class, className);
327         assertWithMessage("Checker should not be null when creating module from name")
328             .that(checker)
329             .isNotNull();
330     }
331 
332     @Test
333     public void testCreateCheckByBruteForce() throws Exception {
334         final String checkName = "AnnotationLocation";
335         final PackageObjectFactory packageObjectFactory = new PackageObjectFactory(
336             new HashSet<>(Arrays.asList(BASE_PACKAGE, BASE_PACKAGE + ".checks.annotation")),
337             Thread.currentThread().getContextClassLoader(), TRY_IN_ALL_REGISTERED_PACKAGES);
338         final AnnotationLocationCheck check = TestUtil.invokeMethod(
339                 packageObjectFactory, "createModuleByTryInEachPackage",
340                 AnnotationLocationCheck.class, checkName);
341         assertWithMessage("Check should not be null when creating module from name")
342             .that(check)
343             .isNotNull();
344     }
345 
346     @Test
347     public void testCreateCheckWithPartialPackageNameByBruteForce() throws Exception {
348         final String checkName = "checks.annotation.AnnotationLocation";
349         final PackageObjectFactory packageObjectFactory = new PackageObjectFactory(
350             new HashSet<>(Collections.singletonList(BASE_PACKAGE)),
351             Thread.currentThread().getContextClassLoader(), TRY_IN_ALL_REGISTERED_PACKAGES);
352         final AnnotationLocationCheck check = (AnnotationLocationCheck) packageObjectFactory
353                 .createModule(checkName);
354         assertWithMessage("Check should not be null when creating module from name")
355             .that(check)
356             .isNotNull();
357     }
358 
359     @Test
360     public void testJoinPackageNamesWithClassName() throws Exception {
361         final Set<String> packages = Collections.singleton("test");
362         final String className = "SomeClass";
363         final String actual = TestUtil.invokeStaticMethod(
364                 PackageObjectFactory.class, "joinPackageNamesWithClassName", String.class,
365                 className, packages);
366         assertWithMessage("Invalid class name")
367             .that(actual)
368             .isEqualTo("test." + className);
369     }
370 
371     @Test
372     public void testNameToFullModuleNameMap() throws Exception {
373         final Set<Class<?>> classes = CheckUtil.getCheckstyleModules();
374         final Class<PackageObjectFactory> packageObjectFactoryClass = PackageObjectFactory.class;
375         final Collection<String> canonicalNames =
376                 TestUtil.getInternalStaticStateMap(
377                         packageObjectFactoryClass, "NAME_TO_FULL_MODULE_NAME").values();
378 
379         final Optional<Class<?>> optional1 = classes.stream()
380                 .filter(clazz -> {
381                     return !canonicalNames.contains(clazz.getCanonicalName())
382                             && !Definitions.INTERNAL_MODULES.contains(clazz.getName());
383                 }).findFirst();
384         assertWithMessage("Invalid canonical name: %s", optional1)
385                 .that(optional1.isPresent())
386                 .isFalse();
387         final Optional<String> optional2 = canonicalNames.stream().filter(canonicalName -> {
388             return classes.stream().map(Class::getCanonicalName)
389                     .noneMatch(classCanonicalName -> classCanonicalName.equals(canonicalName));
390         }).findFirst();
391         assertWithMessage("Invalid class: %s", optional2)
392                 .that(optional2.isPresent())
393                 .isFalse();
394     }
395 
396     @Test
397     public void testConstructorFailure() {
398         final CheckstyleException exc =
399                 getExpectedThrowable(CheckstyleException.class, () -> {
400                     factory.createModule(FailConstructorFileSet.class.getName());
401                 }, "Exception is expected");
402         assertWithMessage("Invalid exception message")
403             .that(exc.getMessage())
404             .isEqualTo("Unable to instantiate com.puppycrawl.tools.checkstyle."
405                 + "PackageObjectFactoryTest$FailConstructorFileSet");
406         assertWithMessage("Invalid exception cause class")
407             .that(exc.getCause().getClass().getSimpleName())
408             .isEqualTo("IllegalAccessException");
409     }
410 
411     @Test
412     public void testGetShortFromFullModuleNames() {
413         final String fullName =
414                 "com.puppycrawl.tools.checkstyle.checks.coding.DefaultComesLastCheck";
415 
416         assertWithMessage("Invalid simple check name")
417             .that(PackageObjectFactory.getShortFromFullModuleNames(fullName))
418             .isEqualTo("DefaultComesLastCheck");
419     }
420 
421     @Test
422     public void testGetShortFromFullModuleNamesThirdParty() {
423         final String fullName =
424                 "java.util.stream.Collectors";
425 
426         assertWithMessage("Invalid simple check name")
427             .that(PackageObjectFactory.getShortFromFullModuleNames(fullName))
428             .isEqualTo(fullName);
429     }
430 
431     /**
432      * This method is for testing the case of an exception caught inside
433      * {@code PackageObjectFactory.generateThirdPartyNameToFullModuleName}, a private method used
434      * to initialize private field {@code PackageObjectFactory.thirdPartyNameToFullModuleNames}.
435      * Since the method and the field both are private, the {@link TestUtil} is required to ensure
436      * that the field is changed. Also, the expected exception should be thrown from the static
437      * method {@link ModuleReflectionUtil#isCheckstyleModule}, so {@link Mockito#mockStatic}
438      * is required to mock this exception.
439      *
440      * @throws Exception when the code tested throws an exception
441      */
442     @Test
443     public void testGenerateThirdPartyNameToFullModuleNameWithException() throws Exception {
444         final String name = "String";
445         final String packageName = "java.lang";
446         final ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
447         final Set<String> packages = Collections.singleton(packageName);
448         final PackageObjectFactory objectFactory = new PackageObjectFactory(packages, classLoader,
449                 TRY_IN_ALL_REGISTERED_PACKAGES);
450 
451         try (MockedStatic<ModuleReflectionUtil> utilities =
452                      mockStatic(ModuleReflectionUtil.class)) {
453             utilities.when(() -> ModuleReflectionUtil.getCheckstyleModules(packages, classLoader))
454                     .thenThrow(new IOException("mock exception"));
455 
456             final String internalFieldName = "thirdPartyNameToFullModuleNames";
457             final Map<String, String> nullMap =
458                     TestUtil.getInternalStateMap(objectFactory, internalFieldName);
459             assertWithMessage("Expected uninitialized field")
460                     .that(nullMap)
461                     .isNull();
462 
463             final Object instance = objectFactory.createModule(name);
464             assertWithMessage("Expected empty string")
465                     .that(instance)
466                     .isEqualTo("");
467 
468             final Map<String, String> emptyMap =
469                     TestUtil.getInternalStateMap(objectFactory, internalFieldName);
470             assertWithMessage("Expected empty map")
471                     .that(emptyMap)
472                     .isEmpty();
473         }
474     }
475 
476     @Test
477     public void testCreateObjectWithNameContainingPackageSeparator() throws Exception {
478         final ClassLoader classLoader = ClassLoader.getSystemClassLoader();
479         final Set<String> packages = Collections.singleton(BASE_PACKAGE);
480         final PackageObjectFactory objectFactory =
481             new PackageObjectFactory(packages, classLoader, TRY_IN_ALL_REGISTERED_PACKAGES);
482 
483         final Object object = objectFactory.createModule(MockClass.class.getName());
484         assertWithMessage("Object should be an instance of MockClass")
485             .that(object)
486             .isInstanceOf(MockClass.class);
487     }
488 
489     /**
490      * This test case is designed to verify the behavior of the PackageObjectFactory's
491      * createModule method when it is provided with a fully qualified class name
492      * (containing a package separator).
493      * It ensures that ModuleReflectionUtil.getCheckstyleModules is not executed in this case.
494      */
495     @Test
496     public void testCreateObjectWithNameContainingPackageSeparatorWithoutSearch() throws Exception {
497         final ClassLoader classLoader = ClassLoader.getSystemClassLoader();
498         final Set<String> packages = Collections.singleton(BASE_PACKAGE);
499         final PackageObjectFactory objectFactory =
500             new PackageObjectFactory(packages, classLoader, TRY_IN_ALL_REGISTERED_PACKAGES);
501 
502         try (MockedStatic<ModuleReflectionUtil> utilities =
503                      mockStatic(ModuleReflectionUtil.class)) {
504             utilities.when(() -> ModuleReflectionUtil.getCheckstyleModules(packages, classLoader))
505                     .thenThrow(new IllegalStateException("creation of objects by fully qualified"
506                             + " class names should not result in search of modules in classpath"));
507 
508             final String fullyQualifiedName = MockClass.class.getName();
509             assertWithMessage("class name is not in expected format")
510                     .that(fullyQualifiedName).contains(".");
511             final Object object = objectFactory.createModule(fullyQualifiedName);
512             assertWithMessage("Object should be an instance of MockClass")
513                     .that(object)
514                     .isInstanceOf(MockClass.class);
515         }
516     }
517 
518     @Test
519     public void testCreateModuleWithTryInAllRegisteredPackages() {
520         final ClassLoader classLoader = ClassLoader.getSystemClassLoader();
521         final Set<String> packages = Collections.singleton(BASE_PACKAGE);
522         final PackageObjectFactory objectFactory =
523             new PackageObjectFactory(packages, classLoader, SEARCH_REGISTERED_PACKAGES);
524         final CheckstyleException ex =
525                 getExpectedThrowable(CheckstyleException.class, () -> {
526                     objectFactory.createModule("PackageObjectFactoryTest$MockClass");
527                 });
528 
529         assertWithMessage("Invalid exception message")
530             .that(ex.getMessage())
531             .startsWith(
532                 "Unable to instantiate 'PackageObjectFactoryTest$MockClass' class, it is also "
533                     + "not possible to instantiate it as "
534                     + "com.puppycrawl.tools.checkstyle.PackageObjectFactoryTest$MockClass, "
535                     + "PackageObjectFactoryTest$MockClassCheck, "
536                     + "com.puppycrawl.tools.checkstyle.PackageObjectFactoryTest$MockClassCheck"
537             );
538 
539     }
540 
541     @Test
542     public void testExceptionMessage() {
543         final String barPackage = BASE_PACKAGE + ".internal.testmodules.packageobjectfactory.bar";
544         final String fooPackage = BASE_PACKAGE + ".internal.testmodules.packageobjectfactory.foo";
545         final String zooPackage = BASE_PACKAGE + ".internal.testmodules.packageobjectfactory.zoo";
546         final String abcPackage = BASE_PACKAGE + ".internal.testmodules.packageobjectfactory.abc";
547         final ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
548         final PackageObjectFactory objectFactory = new PackageObjectFactory(
549                 new HashSet<>(Arrays.asList(abcPackage, barPackage,
550                         fooPackage, zooPackage)), classLoader);
551         final String name = "FooCheck";
552         final CheckstyleException exc =
553                 getExpectedThrowable(CheckstyleException.class, () -> {
554                     objectFactory.createModule(name);
555                 }, "Exception is expected");
556         final String optionalNames = abcPackage + PACKAGE_SEPARATOR + name
557                 + STRING_SEPARATOR + barPackage + PACKAGE_SEPARATOR + name
558                 + STRING_SEPARATOR + fooPackage + PACKAGE_SEPARATOR + name
559                 + STRING_SEPARATOR + zooPackage + PACKAGE_SEPARATOR + name;
560         final LocalizedMessage exceptionMessage = new LocalizedMessage(
561                 Definitions.CHECKSTYLE_BUNDLE, getClass(),
562                 AMBIGUOUS_MODULE_NAME_EXCEPTION_MESSAGE, name, optionalNames);
563         assertWithMessage("Invalid exception message")
564             .that(exc.getMessage())
565             .isEqualTo(exceptionMessage.getMessage());
566     }
567 
568     private static final class FailConstructorFileSet extends AbstractFileSetCheck {
569 
570         private FailConstructorFileSet() {
571             throw new IllegalArgumentException("Test");
572         }
573 
574         @Override
575         protected void processFiltered(File file, FileText fileText) {
576             // not used
577         }
578 
579     }
580 
581     public static class MockClass {
582         // Mock class for testing purposes.
583     }
584 }