View Javadoc
1   ////////////////////////////////////////////////////////////////////////////////
2   // checkstyle: Checks Java source code for adherence to a set of rules.
3   // Copyright (C) 2001-2017 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.doclets;
21  
22  import static com.puppycrawl.tools.checkstyle.internal.utils.TestUtil.isUtilsClassHasPrivateConstructor;
23  import static org.junit.Assert.assertEquals;
24  import static org.junit.Assert.assertFalse;
25  import static org.junit.Assert.assertNotNull;
26  import static org.junit.Assert.assertTrue;
27  import static org.junit.Assert.fail;
28  
29  import java.io.File;
30  import java.lang.reflect.Method;
31  import java.nio.charset.StandardCharsets;
32  import java.util.ArrayList;
33  import java.util.List;
34  
35  import javax.tools.JavaFileObject;
36  
37  import org.apache.commons.io.FileUtils;
38  import org.junit.Assert;
39  import org.junit.Test;
40  
41  import com.puppycrawl.tools.checkstyle.AbstractPathTestSupport;
42  import com.sun.javadoc.RootDoc;
43  import com.sun.tools.javac.util.Context;
44  import com.sun.tools.javac.util.ListBuffer;
45  import com.sun.tools.javadoc.JavadocTool;
46  import com.sun.tools.javadoc.Messager;
47  import com.sun.tools.javadoc.ModifierFilter;
48  
49  public class TokenTypesDocletTest extends AbstractPathTestSupport {
50      @Override
51      protected String getPackageLocation() {
52          return "com/puppycrawl/tools/checkstyle/doclets/tokentypesdoclet";
53      }
54  
55      @Test
56      public void testIsProperUtilsClass() throws ReflectiveOperationException {
57          assertTrue("Constructor is not private",
58                  isUtilsClassHasPrivateConstructor(TokenTypesDoclet.class, true));
59      }
60  
61      @Test
62      public void testOptionLength() {
63          // optionLength returns 2 for option "-destfile"
64          assertEquals("Invalid option length", 2, TokenTypesDoclet.optionLength("-destfile"));
65  
66          // optionLength returns 0 for options different from "-destfile"
67          assertEquals("Invalid option length", 0, TokenTypesDoclet.optionLength("-anyOtherOption"));
68      }
69  
70      @Test
71      public void testCheckOptions() {
72          final Context context = new Context();
73          final TestMessager testMessager = new TestMessager(context);
74  
75          final String[][] options = new String[3][1];
76          assertFalse("Should return false when options are empty",
77                  TokenTypesDoclet.checkOptions(options, testMessager));
78  
79          options[0][0] = "-destfile";
80          assertTrue("Should return true when options are valid",
81                  TokenTypesDoclet.checkOptions(options, testMessager));
82  
83          //pass invalid options - array with more than one "-destfile" option
84          options[1][0] = "-destfile";
85          assertFalse("Should return false when more then one '-destfile' option passed",
86                  TokenTypesDoclet.checkOptions(options, testMessager));
87  
88          final String[] expected = {
89              "Usage: javadoc -destfile file -doclet TokenTypesDoclet ...",
90              "Only one -destfile option allowed.",
91          };
92  
93          Assert.assertArrayEquals("Invalid message", expected, testMessager.messages.toArray());
94      }
95  
96      @Test
97      public void testNotConstants() throws Exception {
98          // Token types must be public int constants, which means that they must have
99          // modifiers public, static, final and type int, because they are referenced statically in
100         // a lot of different places, must not be changed and an int value is used to encrypt
101         // a token type.
102         final ListBuffer<String[]> options = new ListBuffer<>();
103         options.add(new String[] {"-doclet", "TokenTypesDoclet"});
104         options.add(new String[] {"-destfile", "target/tokentypes.properties"});
105 
106         final ListBuffer<String> names = new ListBuffer<>();
107         names.add(getPath("InputTokenTypesDocletNotConstants.java"));
108 
109         final Context context = new Context();
110         final TestMessager test = new TestMessager(context);
111         assertNotNull("should be able to create TestMessager without issue", test);
112         final JavadocTool javadocTool = JavadocTool.make0(context);
113         final RootDoc rootDoc = getRootDoc(javadocTool, options, names);
114 
115         assertTrue("Should process valid root doc", TokenTypesDoclet.start(rootDoc));
116     }
117 
118     @Test
119     public void testEmptyJavadoc() throws Exception {
120         final ListBuffer<String[]> options = new ListBuffer<>();
121         options.add(new String[] {"-destfile", "target/tokentypes.properties"});
122 
123         final ListBuffer<String> names = new ListBuffer<>();
124         names.add(getPath("InputTokenTypesDocletEmptyJavadoc.java"));
125 
126         final Context context = new Context();
127         final TestMessager test = new TestMessager(context);
128         assertNotNull("should be able to create TestMessager without issue", test);
129         final JavadocTool javadocTool = JavadocTool.make0(context);
130         final RootDoc rootDoc = getRootDoc(javadocTool, options, names);
131 
132         try {
133             TokenTypesDoclet.start(rootDoc);
134             fail("IllegalArgumentException is expected");
135         }
136         catch (IllegalArgumentException expected) {
137             // Token types must have first sentence of Javadoc summary
138             // so that a brief description could be provided. Otherwise,
139             // an IllegalArgumentException is thrown.
140         }
141     }
142 
143     @Test
144     public void testCorrect() throws Exception {
145         final ListBuffer<String[]> options = new ListBuffer<>();
146         options.add(new String[] {"-destfile", "target/tokentypes.properties"});
147 
148         final ListBuffer<String> names = new ListBuffer<>();
149         names.add(getPath("InputTokenTypesDocletCorrect.java"));
150 
151         final Context context = new Context();
152         final TestMessager test = new TestMessager(context);
153         assertNotNull("should be able to create TestMessager without issue", test);
154         final JavadocTool javadocTool = JavadocTool.make0(context);
155         final RootDoc rootDoc = getRootDoc(javadocTool, options, names);
156 
157         assertTrue("Should process valid root doc", TokenTypesDoclet.start(rootDoc));
158         final String fileContent =
159                 FileUtils.readFileToString(new File("target/tokentypes.properties"),
160                         StandardCharsets.UTF_8);
161         assertTrue("File content is not expected",
162                 fileContent.startsWith("EOF=The end of file token."));
163 
164     }
165 
166     @Test
167     public void testJavadocTagPassValidation() throws Exception {
168         final ListBuffer<String[]> options = new ListBuffer<>();
169         options.add(new String[] {"-destfile", "target/tokentypes.properties"});
170 
171         final ListBuffer<String> names = new ListBuffer<>();
172         names.add(getPath("InputTokenTypesDocletJavadocParseError.java"));
173 
174         final Context context = new Context();
175         final TestMessager test = new TestMessager(context);
176         assertNotNull("should be able to create TestMessager without issue", test);
177         final JavadocTool javadocTool = JavadocTool.make0(context);
178         final RootDoc rootDoc = getRootDoc(javadocTool, options, names);
179 
180         assertTrue("Should process valid root doc", TokenTypesDoclet.start(rootDoc));
181     }
182 
183     private static RootDoc getRootDoc(JavadocTool javadocTool, ListBuffer<String[]> options,
184             ListBuffer<String> names) throws Exception {
185         final Method getRootDocImpl = getMethodGetRootDocImplByReflection();
186         final RootDoc rootDoc;
187         if (System.getProperty("java.version").startsWith("1.7.")) {
188             rootDoc = (RootDoc) getRootDocImpl.invoke(javadocTool, "",
189                     StandardCharsets.UTF_8.name(),
190                     new ModifierFilter(ModifierFilter.ALL_ACCESS),
191                     names.toList(),
192                     options.toList(),
193                     false,
194                     new ListBuffer<String>().toList(),
195                     new ListBuffer<String>().toList(),
196                     false, false, false);
197         }
198         else {
199             rootDoc = (RootDoc) getRootDocImpl.invoke(javadocTool, "",
200                     StandardCharsets.UTF_8.name(),
201                     new ModifierFilter(ModifierFilter.ALL_ACCESS),
202                     names.toList(),
203                     options.toList(),
204                     new ListBuffer<JavaFileObject>().toList(),
205                     false,
206                     new ListBuffer<String>().toList(),
207                     new ListBuffer<String>().toList(),
208                     false, false, false);
209         }
210         return rootDoc;
211     }
212 
213     private static Method getMethodGetRootDocImplByReflection() throws ClassNotFoundException {
214         Method result = null;
215         final Class<?> javadocToolClass = Class.forName("com.sun.tools.javadoc.JavadocTool");
216         final Method[] methods = javadocToolClass.getMethods();
217         for (Method method: methods) {
218             if ("getRootDocImpl".equals(method.getName())) {
219                 result = method;
220             }
221         }
222         return result;
223     }
224 
225     private static class TestMessager extends Messager {
226 
227         private final List<String> messages = new ArrayList<>();
228 
229         TestMessager(Context context) {
230             super(context, "");
231         }
232 
233         @Override
234         public void printError(String message) {
235             messages.add(message);
236         }
237     }
238 }