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.core.doc;
17  
18  import java.io.Serializable;
19  import java.util.ArrayList;
20  import java.util.Collections;
21  import java.util.LinkedHashMap;
22  import java.util.List;
23  import java.util.Map;
24  
25  import org.apache.commons.lang.NullArgumentException;
26  
27  import net.jcip.annotations.GuardedBy;
28  import net.jcip.annotations.ThreadSafe;
29  
30  /**
31   * The index of all collected unit test documentation instances.
32   *
33   * @author <a href="mailto:robert.reiner@smartics.de">Robert Reiner</a>
34   * @version $Revision:591 $
35   */
36  @ThreadSafe
37  public class UnitTestDocIndex implements Serializable
38  {
39    // ********************************* Fields *********************************
40  
41    // --- constants ------------------------------------------------------------
42  
43    /**
44     * The class version identifier.
45     */
46    private static final long serialVersionUID = 1L;
47  
48    /**
49     * The guard name for synchronization.
50     */
51    private static final String GUARD = "unitTestDocs";
52  
53    // --- members --------------------------------------------------------------
54  
55    /**
56     * The test documentation mapped by the UUT's type name. For each type there
57     * is only one instance of {@link UnitTestDoc} that contains all information
58     * for that UUT.
59     */
60    private final Map<Type, UnitTestDoc> unitTestDocs =
61        new LinkedHashMap<Type, UnitTestDoc>();
62  
63    /**
64     * References from the test case classes to the units they test. The elements
65     * in the list are required to be the identical instances found in
66     * {@link #unitTestDocs}. This is just an alternative view on the UUTs to that
67     * of {@link #unitTestDocs}.
68     */
69    private final Map<Type, List<UnitTestDoc>> testCases =
70        new LinkedHashMap<Type, List<UnitTestDoc>>();
71  
72    // ****************************** Initializer *******************************
73  
74    // ****************************** Constructors ******************************
75  
76    /**
77     * Default constructor.
78     */
79    public UnitTestDocIndex()
80    {
81    }
82  
83    // ****************************** Inner Classes *****************************
84  
85    // ********************************* Methods ********************************
86  
87    // --- init -----------------------------------------------------------------
88  
89    // --- get&set --------------------------------------------------------------
90  
91    /**
92     * Returns a copy of the internal map that contains the test documentation
93     * instances.
94     *
95     * @return the content of the index.
96     */
97    @GuardedBy(GUARD)
98    public List<UnitTestDoc> getUnitTestDocs()
99    {
100     synchronized (unitTestDocs)
101     {
102       return new ArrayList<UnitTestDoc>(unitTestDocs.values());
103     }
104   }
105 
106   /**
107    * Returns the number of registered unit test documentation.
108    *
109    * @return the number of registered unit test documentation.
110    */
111   @GuardedBy(GUARD)
112   public Integer getSize()
113   {
114     synchronized (unitTestDocs)
115     {
116       return unitTestDocs.size();
117     }
118   }
119 
120   /**
121    * Checks whether the index contains elements or not.
122    *
123    * @return <code>true</code> if there is at least on element in the index,
124    *         <code>false</code> otherwise.
125    */
126   @GuardedBy(GUARD)
127   public boolean isEmpty()
128   {
129     synchronized (unitTestDocs)
130     {
131       return unitTestDocs.isEmpty();
132     }
133   }
134 
135   // --- business -------------------------------------------------------------
136 
137   /**
138    * Registers the given test documentation to the index. If a documentation is
139    * already registered, all information from the given <code>testDoc</code> is
140    * added to the already registered instance.
141    *
142    * @param unitTestDoc the test documentation to add.
143    * @return a reference to the registered instance.
144    * @throws NullPointerException if <code>testDoc</code> is <code>null</code>.
145    */
146   @GuardedBy(GUARD)
147   public UnitTestDoc register(final UnitTestDoc unitTestDoc)
148     throws NullPointerException
149   {
150     final Type uutType = unitTestDoc.getUutType();
151     synchronized (unitTestDocs)
152     {
153       final UnitTestDoc representative;
154       if (unitTestDocs.containsKey(uutType))
155       {
156         representative = unitTestDocs.get(uutType);
157         representative.addScenarios(unitTestDoc);
158       }
159       else
160       {
161         representative = unitTestDoc;
162         unitTestDocs.put(uutType, representative);
163       }
164       registerByTestCase(representative);
165       return representative;
166     }
167   }
168 
169   /**
170    * Requires to be run synchronized with {@link #GUARD}. It also expects that
171    * the <code>testDoc</code> is the instance that is registered with
172    * {@link #unitTestDocs}.
173    */
174   private void registerByTestCase(final UnitTestDoc testDoc)
175   {
176     scenarios: for (final ScenarioTestDoc scenario : testDoc.getScenarios())
177     {
178       final Type testCaseType = scenario.getTestCaseType();
179       List<UnitTestDoc> unitTestDocs = this.testCases.get(testCaseType);
180       if (unitTestDocs == null)
181       {
182         unitTestDocs = new ArrayList<UnitTestDoc>();
183         testCases.put(testCaseType, unitTestDocs);
184       }
185       else
186       {
187         for (final UnitTestDoc currentTestDoc : unitTestDocs)
188         {
189           if (testDoc == currentTestDoc)
190           {
191             continue scenarios; // type already registered.
192           }
193         }
194       }
195       unitTestDocs.add(testDoc);
196     }
197   }
198 
199   /**
200    * Returns the unit test documentation for the given UUT type.
201    *
202    * @param uutType the type of the UUT whose test documentation is requested.
203    * @return the test documentation for the given UUT type or <code>null</code>
204    *         if nothing is registered for that type.
205    */
206   @GuardedBy(GUARD)
207   public UnitTestDoc get(final Type uutType)
208   {
209     synchronized (unitTestDocs)
210     {
211       return unitTestDocs.get(uutType);
212     }
213   }
214 
215   /**
216    * Returns the list of UUT documentation whose UUT is tested by the given test
217    * case.
218    *
219    * @param testCaseType the type of the test case whose UUT documentation is
220    *          requested.
221    * @return the UUT documentation of all UUTs tested by the given test case
222    *         type.
223    */
224   @GuardedBy(GUARD)
225   public List<UnitTestDoc> getByTestCase(final Type testCaseType)
226   {
227     synchronized (unitTestDocs)
228     {
229       final List<UnitTestDoc> registered = testCases.get(testCaseType);
230       if (registered != null)
231       {
232         final List<UnitTestDoc> unitTestsOfTestCase =
233             filterScenariosByTestCase(testCaseType, registered);
234 
235         return Collections.unmodifiableList(unitTestsOfTestCase);
236       }
237       else
238       {
239         return Collections.emptyList();
240       }
241     }
242   }
243 
244   private static List<UnitTestDoc> filterScenariosByTestCase(
245       final Type testCaseType, final List<UnitTestDoc> registered)
246   {
247     final List<UnitTestDoc> unitTestsOfTestCase =
248         new ArrayList<UnitTestDoc>(registered.size());
249     for (final UnitTestDoc unitTestDoc : registered)
250     {
251       final List<ScenarioTestDoc> scenariosOfTestCase =
252           filterScenarios(testCaseType, unitTestDoc);
253       final UnitTestDoc unitTestDocOfTestCase =
254           cloneWithNewScenarios(unitTestDoc, scenariosOfTestCase);
255       unitTestsOfTestCase.add(unitTestDocOfTestCase);
256     }
257     return unitTestsOfTestCase;
258   }
259 
260   private static List<ScenarioTestDoc> filterScenarios(final Type testCaseType,
261       final UnitTestDoc unitTestDoc)
262   {
263     final List<ScenarioTestDoc> scenariosOfTestCase =
264         new ArrayList<ScenarioTestDoc>();
265     for (final ScenarioTestDoc scenario : unitTestDoc.getScenarios())
266     {
267       if (testCaseType.equals(scenario.getTestCaseType()))
268       {
269         scenariosOfTestCase.add(scenario);
270       }
271     }
272     return scenariosOfTestCase;
273   }
274 
275   private static UnitTestDoc cloneWithNewScenarios(
276       final UnitTestDoc unitTestDoc,
277       final List<ScenarioTestDoc> scenariosOfTestCase)
278   {
279     final UnitTestDoc unitTestDocOfTestCase =
280         new UnitTestDoc(unitTestDoc.getUutType(), scenariosOfTestCase);
281     return unitTestDocOfTestCase;
282   }
283 
284   /**
285    * Removes all scenarios of the given test case type.
286    *
287    * @param testCaseType the type of the test case whose scenario are to be
288    *          removed.
289    * @throws NullArgumentException if <code>testCaseType</code> is
290    *           <code>null</code>.
291    */
292   @GuardedBy(GUARD)
293   public void deregisterTestCase(final Type testCaseType)
294     throws NullArgumentException
295   {
296     if (testCaseType == null)
297     {
298       throw new NullArgumentException("testCaseType");
299     }
300 
301     synchronized (unitTestDocs)
302     {
303       final List<UnitTestDoc> unitTestDocsOfTestCase =
304           testCases.get(testCaseType);
305       if (unitTestDocsOfTestCase != null)
306       {
307         for (final UnitTestDoc unitTestDoc : unitTestDocsOfTestCase)
308         {
309           unitTestDoc.removeScenarios(testCaseType);
310         }
311       }
312     }
313   }
314 
315   /**
316    * Clears the index.
317    */
318   @GuardedBy(GUARD)
319   public void clear()
320   {
321     synchronized (unitTestDocs)
322     {
323       unitTestDocs.clear();
324       testCases.clear();
325     }
326   }
327 
328   // --- object basics --------------------------------------------------------
329 
330 }