View Javadoc

1   /*
2    * Copyright 2010-2013 smartics, Kronseder & Reiner GmbH
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    *     http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  package de.smartics.testdoc.collect.extractor;
17  
18  import java.lang.annotation.Annotation;
19  import java.util.List;
20  
21  import javax.lang.model.element.Element;
22  import javax.lang.model.element.ElementKind;
23  import javax.lang.model.element.ExecutableElement;
24  import javax.lang.model.element.TypeElement;
25  import javax.lang.model.util.Elements;
26  
27  import org.junit.Test;
28  import org.junit.experimental.theories.Theory;
29  
30  import de.smartics.testdoc.annotations.Uut;
31  import de.smartics.testdoc.collect.extractor.TestDocHintsExtractor.Hints;
32  import de.smartics.testdoc.collect.extractor.TestDocAnnotationExtractor.UutInfo;
33  import de.smartics.testdoc.core.doc.ScenarioTestDoc;
34  import de.smartics.testdoc.core.doc.SortKey;
35  import de.smartics.testdoc.core.doc.TestMethodDoc;
36  import de.smartics.testdoc.core.doc.Type;
37  import de.smartics.testdoc.core.doc.UnitTestDoc;
38  import de.smartics.testdoc.core.doc.names.TestNameUtils;
39  import de.smartics.testdoc.core.source.SourceCodeHelper;
40  import de.smartics.util.source.SourceCodeLocation;
41  
42  /**
43   * Base implementation for Extracting unit test doc information.
44   *
45   * @author <a href="mailto:robert.reiner@smartics.de">Robert Reiner</a>
46   * @version $Revision:591 $
47   */
48  public abstract class AbstractExtractor
49  {
50    // ********************************* Fields *********************************
51  
52    // --- constants ------------------------------------------------------------
53  
54    // --- members --------------------------------------------------------------
55  
56    /**
57     * The utilities of the APT interface.
58     */
59    protected final Elements elementUtils;
60  
61    /**
62     * The helper to access source code information.
63     */
64    protected final SourceCodeHelper sourceCodeHelper;
65  
66    /**
67     * The utilities to create names to be displayed (as labels) for tests.
68     */
69    private final TestNameUtils testNameUtils;
70  
71    /**
72     * The test case that is analyzed.
73     */
74    protected final TypeElement testCaseType;
75  
76    /**
77     * Extracts category information.
78     */
79    protected final CategoryExtractor categoryExtractor;
80  
81    /**
82     * Extracts hint information.
83     */
84    protected final TestDocHintsExtractor hintExtractor =
85        new TestDocHintsExtractor();
86  
87    /**
88     * Extracts UUT information.
89     */
90    protected final TestDocAnnotationExtractor uutExtractor =
91        new TestDocAnnotationExtractor();
92  
93    // ****************************** Initializer *******************************
94  
95    // ****************************** Constructors ******************************
96  
97    /**
98     * Default constructor.
99     *
100    * @param config the configuration to access processing information.
101    * @param testCaseType the test case that has an annotation that potentially
102    *          specifies the unit under test.
103    * @throws IllegalArgumentException if the <code>declaredUutField</code> is
104    *           not a field declaration within a class or any of the arguments is
105    *           <code>null</code>.
106    */
107   protected AbstractExtractor(final ExtractorConfig config,
108       final TypeElement testCaseType) throws IllegalArgumentException
109   {
110     checkArguments(config);
111     this.elementUtils = config.getElementUtils();
112     this.sourceCodeHelper = config.getSourceCodeHelper();
113     this.testNameUtils = config.getTestNameUtils();
114     this.testCaseType = testCaseType;
115     this.categoryExtractor = new CategoryExtractor(testCaseType);
116   }
117 
118   // ****************************** Inner Classes *****************************
119 
120   // ********************************* Methods ********************************
121 
122   // --- init -----------------------------------------------------------------
123 
124   private void checkArguments(final ExtractorConfig config)
125   {
126     if (config == null)
127     {
128       throw new IllegalArgumentException("The extractor config is required.");
129     }
130   }
131 
132   // --- get&set --------------------------------------------------------------
133 
134   // --- business -------------------------------------------------------------
135 
136   /**
137    * Reads the test documentation from the element the extractor instance is
138    * associated with.
139    *
140    * @return the test documentation read.
141    */
142   public abstract UnitTestDoc readTestDoc();
143 
144   protected ScenarioTestDoc createScenarioIfElementIsTestMethod(
145       final UutInfo uutInfo, final String testCaseType,
146       final ExecutableElement testMethod)
147   {
148     final String uutMethod = uutInfo.getMethod();
149     final Hints methodHints = hintExtractor.readHints(testMethod);
150     final TestMethodDoc testMethodDoc =
151         createTestMethod(methodHints, testMethod);
152     final List<String> categories =
153         categoryExtractor.calcCategories(testMethod);
154 
155     final Hints typeHints =
156         hintExtractor.readHints(testMethod.getEnclosingElement());
157     final SortKey sortKey = methodHints.createSortKey(typeHints);
158     final ScenarioTestDoc scenario =
159         new ScenarioTestDoc(uutMethod, new Type(testCaseType), testMethodDoc,
160             categories, sortKey);
161     return scenario;
162   }
163 
164   private TestMethodDoc createTestMethod(final Hints methodHints,
165       final ExecutableElement testMethod)
166   {
167     final String testName = testMethod.getSimpleName().toString();
168     final String testSentence = calculateTestSentence(methodHints, testName);
169     final SourceCodeLocation location =
170         sourceCodeHelper.getSourceCodeLocation(testMethod);
171     final String comment = elementUtils.getDocComment(testMethod);
172     return new TestMethodDoc(testName, testSentence, location, comment);
173   }
174 
175   protected String calculateTestSentence(final Hints hints,
176       final String testName)
177   {
178     if (hints.hasSentence())
179     {
180       return hints.getSentence();
181     }
182     else
183     {
184       return testNameUtils.calculateTestNameSentence(testName);
185     }
186   }
187 
188   protected static boolean isTestMethodWithoutUutAnnotation(
189       final Element element)
190   {
191     final ElementKind kind = element.getKind();
192     if (ElementKind.METHOD.equals(kind))
193     {
194       final ExecutableElement method = (ExecutableElement) element;
195       return (hasNotAnnotation(method, Uut.class) && (hasAnnotation(method,
196           Test.class) || hasAnnotation(method, Theory.class)));
197     }
198     return false;
199   }
200 
201   protected static boolean hasAnnotation(final Element method,
202       final Class<? extends Annotation> annotation)
203   {
204     return null != method.getAnnotation(annotation);
205   }
206 
207   protected static boolean hasNotAnnotation(final Element method,
208       final Class<? extends Annotation> annotation)
209   {
210     return null == method.getAnnotation(annotation);
211   }
212 
213   // --- object basics --------------------------------------------------------
214 
215 }