1   ////////////////////////////////////////////////////////////////////////////////
2   // checkstyle: Checks Java source code for adherence to a set of rules.
3   // Copyright (C) 2001-2019 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 org.junit.Assert.assertEquals;
23  import static org.junit.Assert.assertNotEquals;
24  import static org.junit.Assert.assertTrue;
25  import static org.junit.Assert.fail;
26  
27  import java.io.File;
28  import java.io.IOException;
29  import java.io.InputStream;
30  import java.net.URL;
31  import java.net.URLConnection;
32  import java.net.URLStreamHandler;
33  import java.util.Arrays;
34  import java.util.Collections;
35  import java.util.Enumeration;
36  import java.util.HashSet;
37  import java.util.Set;
38  
39  import org.junit.Test;
40  import org.xml.sax.SAXException;
41  
42  import com.puppycrawl.tools.checkstyle.api.CheckstyleException;
43  
44  /**
45   * Custom class loader is needed to pass URLs to pretend these are loaded from the classpath
46   * though we can't add/change the files for testing. The class loader is nested in this class,
47   * so the custom class loader we are using is safe.
48   * @noinspection ClassLoaderInstantiation
49   */
50  public class PackageNamesLoaderTest extends AbstractPathTestSupport {
51  
52      @Override
53      protected String getPackageLocation() {
54          return "com/puppycrawl/tools/checkstyle/packagenamesloader";
55      }
56  
57      @Test
58      public void testDefault()
59              throws CheckstyleException {
60          final Set<String> packageNames = PackageNamesLoader
61                  .getPackageNames(Thread.currentThread()
62                          .getContextClassLoader());
63          assertEquals("pkgNames.length.", 0,
64                  packageNames.size());
65      }
66  
67      @Test
68      public void testNoPackages() throws Exception {
69          final Set<String> actualPackageNames = PackageNamesLoader
70                  .getPackageNames(new TestUrlsClassLoader(Collections.emptyEnumeration()));
71  
72          assertEquals("Invalid package names length.", 0, actualPackageNames.size());
73      }
74  
75      @Test
76      public void testPackagesFile() throws Exception {
77          final Enumeration<URL> enumeration = Collections.enumeration(Collections.singleton(
78                  new File(getPath("InputPackageNamesLoaderFile.xml")).toURI().toURL()));
79  
80          final Set<String> actualPackageNames = PackageNamesLoader
81                  .getPackageNames(new TestUrlsClassLoader(enumeration));
82          final String[] expectedPackageNames = {
83              "com.puppycrawl.tools.checkstyle",
84              "com.puppycrawl.tools.checkstyle.checks",
85              "com.puppycrawl.tools.checkstyle.checks.annotation",
86              "com.puppycrawl.tools.checkstyle.checks.blocks",
87              "com.puppycrawl.tools.checkstyle.checks.coding",
88              "com.puppycrawl.tools.checkstyle.checks.design",
89              "com.puppycrawl.tools.checkstyle.checks.header",
90              "com.puppycrawl.tools.checkstyle.checks.imports",
91              "com.puppycrawl.tools.checkstyle.checks.indentation",
92              "com.puppycrawl.tools.checkstyle.checks.javadoc",
93              "com.puppycrawl.tools.checkstyle.checks.metrics",
94              "com.puppycrawl.tools.checkstyle.checks.modifier",
95              "com.puppycrawl.tools.checkstyle.checks.naming",
96              "com.puppycrawl.tools.checkstyle.checks.regexp",
97              "com.puppycrawl.tools.checkstyle.checks.sizes",
98              "com.puppycrawl.tools.checkstyle.checks.whitespace",
99              "com.puppycrawl.tools.checkstyle.filefilters",
100             "com.puppycrawl.tools.checkstyle.filters",
101         };
102 
103         assertEquals("Invalid package names length.", expectedPackageNames.length,
104             actualPackageNames.size());
105         final Set<String> checkstylePackagesSet =
106                 new HashSet<>(Arrays.asList(expectedPackageNames));
107         assertEquals("Invalid names set.", checkstylePackagesSet, actualPackageNames);
108     }
109 
110     @Test
111     public void testPackagesWithDots() throws Exception {
112         final Enumeration<URL> enumeration = Collections.enumeration(Collections.singleton(
113                 new File(getPath("InputPackageNamesLoaderWithDots.xml")).toURI().toURL()));
114 
115         final Set<String> actualPackageNames = PackageNamesLoader
116                 .getPackageNames(new TestUrlsClassLoader(enumeration));
117         final String[] expectedPackageNames = {
118             "coding.",
119         };
120 
121         assertEquals("Invalid package names length.", expectedPackageNames.length,
122             actualPackageNames.size());
123         final Set<String> checkstylePackagesSet =
124                 new HashSet<>(Arrays.asList(expectedPackageNames));
125         assertEquals("Invalid names set.", checkstylePackagesSet, actualPackageNames);
126     }
127 
128     @Test
129     public void testPackagesWithDotsEx() throws Exception {
130         final Enumeration<URL> enumeration = Collections.enumeration(Collections.singleton(
131                 new File(getPath("InputPackageNamesLoaderWithDotsEx.xml")).toURI().toURL()));
132 
133         final Set<String> actualPackageNames = PackageNamesLoader
134                 .getPackageNames(new TestUrlsClassLoader(enumeration));
135         final String[] expectedPackageNames = {
136             "coding.specific",
137             "coding.",
138         };
139 
140         assertEquals("Invalid package names length.", expectedPackageNames.length,
141             actualPackageNames.size());
142         final Set<String> checkstylePackagesSet =
143                 new HashSet<>(Arrays.asList(expectedPackageNames));
144         assertEquals("Invalid names set.", checkstylePackagesSet, actualPackageNames);
145     }
146 
147     @Test
148     public void testPackagesWithSaxException() throws Exception {
149         final Enumeration<URL> enumeration = Collections.enumeration(Collections.singleton(
150                 new File(getPath("InputPackageNamesLoaderNotXml.java")).toURI().toURL()));
151 
152         try {
153             PackageNamesLoader.getPackageNames(new TestUrlsClassLoader(enumeration));
154             fail("CheckstyleException is expected");
155         }
156         catch (CheckstyleException ex) {
157             assertTrue("Invalid exception cause class", ex.getCause() instanceof SAXException);
158         }
159     }
160 
161     @Test
162     public void testPackagesWithIoException() throws Exception {
163         final URLConnection urlConnection = new URLConnection(null) {
164             @Override
165             public void connect() {
166                 // no code
167             }
168 
169             @Override
170             public InputStream getInputStream() {
171                 return null;
172             }
173         };
174         final URL url = new URL("test", null, 0, "", new URLStreamHandler() {
175             @Override
176             protected URLConnection openConnection(URL u) {
177                 return urlConnection;
178             }
179         });
180 
181         final Enumeration<URL> enumeration = Collections.enumeration(Collections.singleton(url));
182 
183         try {
184             PackageNamesLoader.getPackageNames(new TestUrlsClassLoader(enumeration));
185             fail("CheckstyleException is expected");
186         }
187         catch (CheckstyleException ex) {
188             assertTrue("Invalid exception cause class", ex.getCause() instanceof IOException);
189             assertNotEquals("Invalid exception message",
190                     "unable to get package file resources", ex.getMessage());
191         }
192     }
193 
194     @Test
195     public void testPackagesWithIoExceptionGetResources() {
196         try {
197             PackageNamesLoader.getPackageNames(new TestIoExceptionClassLoader());
198             fail("CheckstyleException is expected");
199         }
200         catch (CheckstyleException ex) {
201             assertTrue("Invalid exception cause class", ex.getCause() instanceof IOException);
202             assertEquals("Invalid exception message",
203                     "unable to get package file resources", ex.getMessage());
204         }
205     }
206 
207     /**
208      * Custom class loader is needed to pass URLs to pretend these are loaded from the classpath
209      * though we can't add/change the files for testing.
210      * @noinspection CustomClassloader
211      */
212     private static class TestUrlsClassLoader extends ClassLoader {
213 
214         private final Enumeration<URL> urls;
215 
216         /* package */ TestUrlsClassLoader(Enumeration<URL> urls) {
217             this.urls = urls;
218         }
219 
220         @Override
221         public Enumeration<URL> getResources(String name) {
222             return urls;
223         }
224     }
225 
226     /**
227      * Custom class loader is needed to throw an exception to test a catch statement.
228      * @noinspection CustomClassloader
229      */
230     private static class TestIoExceptionClassLoader extends ClassLoader {
231         @Override
232         public Enumeration<URL> getResources(String name) throws IOException {
233             throw new IOException("test");
234         }
235     }
236 
237 }