1. Project Clover database Tue Dec 20 2016 21:24:09 CET
  2. Package org.xwiki.rendering.test.cts

File CompatibilityTestSuite.java

 

Coverage histogram

../../../../../img/srcFileCovDistChart9.png
38% of files have more coverage

Code metrics

14
36
7
1
248
93
16
0.44
5.14
7
2.29

Classes

Class Line # Actions
CompatibilityTestSuite 89 36 0% 16 7
0.87719387.7%
 

Contributing tests

No tests hitting this source file were found.

Source view

1    /*
2    * See the NOTICE file distributed with this work for additional
3    * information regarding copyright ownership.
4    *
5    * This is free software; you can redistribute it and/or modify it
6    * under the terms of the GNU Lesser General Public License as
7    * published by the Free Software Foundation; either version 2.1 of
8    * the License, or (at your option) any later version.
9    *
10    * This software 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 software; if not, write to the Free
17    * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
18    * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
19    */
20    package org.xwiki.rendering.test.cts;
21   
22    import java.util.ArrayList;
23    import java.util.Collections;
24    import java.util.List;
25   
26    import org.apache.commons.lang3.StringUtils;
27    import org.junit.runner.Description;
28    import org.junit.runner.Runner;
29    import org.junit.runners.Suite;
30    import org.xwiki.component.manager.ComponentManager;
31    import org.xwiki.rendering.parser.Parser;
32    import org.xwiki.rendering.renderer.BlockRenderer;
33    import org.xwiki.test.jmock.XWikiComponentInitializer;
34   
35    /**
36    * Run all tests found in resources files located in the classpath, for a given Syntax.
37    *
38    * The algorithm is the following:
39    * <ul>
40    * <li>Look for {@code cts/[scope]} resources in the classpath where {@code [scope]} represents the value of the
41    * {@code &#064;Scope} annotation prefixed by {@code cts\\.}. By default if no Scope annotation is defined,
42    * {@code .*\\.xml} is used, leading to a total regex of {@code cts\\..*\\.xml}. This is the regex that's used
43    * to look for resources in the classpath. For example the following test file would match:
44    * {@code cts/simple/bold/bold1.inout.xml}. We call these {@code CTS} resources.</li>
45    * <li>For each {@code CTS} resource found look for equivalent test input and output files for the tested Syntax.
46    * For example if we have {@code cts/simple/bold/bold1.inout.xml} then if the Syntax is {@code xwiki/2.0} look
47    * for {@code xwiki20/simple/bold/bold1.[in|out|inout].txt} test files. We call them {@code SYN} resources.
48    * </li>
49    * <li>For each {@code SYN IN} resource, parse it with the corresponding Syntax parser and render the generated XDOM
50    * with the CTS Renderer, and compare the results with the {@code CTS OUT} resource. Note that if no
51    * {@code SYN IN} resource is found generate a warning in the test logs.</li>
52    * <li>For each {@code SYN OUT} resource, parse the {@code CTS IN} resource with the CTS Syntax parser and render the
53    * generated XDOM with the Syntax Renderer, and compare the results with the {@code SYN OUT} resource.
54    * Note that if no {@code SYN OUT} resource is found generate a warning in the test logs.</li>
55    * </ul>
56    *
57    * <p>
58    * Usage Example
59    * </p>
60    * <pre><code>
61    * &#064;RunWith(CompatibilityTestSuite.class)
62    * &#064;Syntax("xwiki/2.0")
63    * &#064;Scope("simple")
64    * public class IntegrationTests
65    * {
66    * }
67    * </code></pre>
68    * <p>
69    * It's also possible to get access to the underlying Component Manager used, for example in order to register
70    * Mock implementations of components. For example:
71    * </p>
72    * <pre><code>
73    * &#064;RunWith(CompatibilityTestSuite.class)
74    * &#064;Syntax("xwiki/2.0")
75    * &#064;Scope("simple")
76    * public class IntegrationTests
77    * {
78    * &#064;Initialized
79    * public void initialize(ComponentManager componentManager)
80    * {
81    * // Init mocks here for example
82    * }
83    * }
84    * </code></pre>
85    *
86    * @version $Id: c521120a3eadec5ee8e55f02ff137e7841cf8df9 $
87    * @since 4.1M1
88    */
 
89    public class CompatibilityTestSuite extends Suite
90    {
91    /**
92    * Used to locate and parse Test Data.
93    */
94    private static final TestDataParser PARSER = new TestDataParser();
95   
96    /**
97    * The Test instance (The Test instance is the class on which this Compatibility Test Suite is used).
98    */
99    private final Object testInstance;
100   
101    /**
102    * Used to find if there are Parser or Renderers for a given Syntax.
103    */
104    private final ComponentManager componentManager;
105   
106    /**
107    * We have one Test Runner per Syntax Test to execute, so that each test is reported individually and also to
108    * provide test isolation.
109    */
110    private final List<Runner> runners = new ArrayList<Runner>();
111   
112    /**
113    * Only called reflectively. Do not use programmatically.
114    *
115    * @param klass the test instance class on which this Test Suite is applied
116    * @throws Exception if we fail to locate or load test data, if the {@link RenderingTest} isn't a valid JUnit Test
117    * class or if we cannot locate the Component Manager
118    */
 
119  17 toggle public CompatibilityTestSuite(Class<?> klass) throws Exception
120    {
121  17 super(RenderingTest.class, Collections.<Runner>emptyList());
122   
123  17 try {
124  17 this.testInstance = klass.newInstance();
125    } catch (Exception e) {
126  0 throw new RuntimeException(String.format("Failed to construct instance of [%s]", klass.getName()), e);
127    }
128   
129    // If a Scope Annotation is present then use it to define the scope
130  17 Scope scopeAnnotation = klass.getAnnotation(Scope.class);
131  17 String packageFilter = "";
132  17 String pattern = Scope.DEFAULT_PATTERN;
133  17 if (scopeAnnotation != null) {
134  0 packageFilter = scopeAnnotation.value();
135  0 pattern = scopeAnnotation.pattern();
136    }
137   
138    // Get the specified Syntax from the Syntax annotation
139  17 Syntax syntaxAnnotation = klass.getAnnotation(Syntax.class);
140  17 if (syntaxAnnotation == null) {
141  0 throw new RuntimeException("You must specify a Syntax using the @Syntax annotation");
142    }
143  17 String syntaxId = syntaxAnnotation.value();
144  17 String metadataSyntaxId = syntaxAnnotation.metadata();
145  17 if (StringUtils.isEmpty(metadataSyntaxId)) {
146  17 metadataSyntaxId = syntaxId;
147    }
148   
149    // Initialize the Component Manager
150  17 this.componentManager = new XWikiComponentInitializer().getComponentManager();
151   
152    // Note: We use the Reflections framework to find all ClassLoader URLs that contain the "cts" package.
153  17 List<TestData> testDatas = PARSER.parseTestData(syntaxId, "cts", packageFilter, pattern);
154   
155  17 for (TestData testData : testDatas) {
156    // The following cases can happen:
157    // - There's no syntax test for the CTS test and there's no Parser/Renderer for that syntax: we don't add
158    // the test at all
159    // - The test is configured to be not applicable: we don't add the test at all
160    // - The test is configured as not working: we ignore it in JUnit with a cause message in the test
161    // description
162    // - There's no syntax test for the CTS test but there's a Parser/Renderer for that syntax: we ignore it in
163    // JUnit with a cause message in the test description
164  1277 if (isApplicable(testData)) {
165  804 if (testData.syntaxData != null && !testData.isFailingTest()) {
166  537 this.runners.add(new RenderingTestClassRunner(
167    this.testInstance, getTestClass().getJavaClass(), testData, metadataSyntaxId));
168    } else {
169  267 this.runners.add(new IgnoredRenderingTestClassRunner(getTestClass().getJavaClass(), testData));
170    }
171    }
172    }
173    }
174   
 
175  17 toggle @Override
176    protected List<Runner> getChildren()
177    {
178  17 return this.runners;
179    }
180   
181    /**
182    * {@inheritDoc}
183    *
184    * <p>
185    * We override this method so that the JUnit results are not displayed in a test hierarchy with a single test
186    * result for each node (as it would be otherwise since RenderingTest has a single test method).
187    * </p>
188    */
 
189  34 toggle @Override
190    public Description getDescription()
191    {
192  34 return Description.createSuiteDescription(getTestClass().getJavaClass());
193    }
194   
195    /**
196    * Verify if a test is applicable (ie it should be executed, even as ignored). A test is applicable if:
197    * <ul>
198    * <li>it's not marked as not applicable</li>
199    * <li>it has a Syntax test</li>
200    * <li>it doesn't have a Syntax test but there's a Parser or Renderer for the Syntax</li>
201    * </ul>
202    *
203    * @param testData the test data used to decide if the test is applicable or not
204    * @return if the test should be executed or false otherwise
205    */
 
206  1277 toggle private boolean isApplicable(TestData testData)
207    {
208  1277 boolean isApplicable;
209  1277 if (testData.isNotApplicable()) {
210  83 isApplicable = false;
211    } else {
212  1194 if (hasParserOrRenderer(testData)) {
213  804 isApplicable = true;
214    } else {
215  390 isApplicable = false;
216    }
217    }
218  1277 return isApplicable;
219    }
220   
221    /**
222    * @param testData the test data used to decide if the test has a Parser or Renderer for it
223    * @return true if there's a Parser or Renderer for the passed test data, false otherwise
224    */
 
225  1194 toggle private boolean hasParserOrRenderer(TestData testData)
226    {
227  1194 return (testData.isSyntaxInputTest && hasParserForSyntax(testData.syntaxId))
228    || (!testData.isSyntaxInputTest && hasRendererForSyntax(testData.syntaxId));
229    }
230   
231    /**
232    * @param syntaxId the syntax for which to verify if there's a Parser
233    * @return true if a Parser exists for the passed syntax, false otherwise
234    */
 
235  588 toggle private boolean hasParserForSyntax(String syntaxId)
236    {
237  588 return this.componentManager.hasComponent(Parser.class, syntaxId);
238    }
239   
240    /**
241    * @param syntaxId the syntax for which to verify if there's a Renderer
242    * @return true if a Renderer exists for the passed syntax, false otherwise
243    */
 
244  606 toggle private boolean hasRendererForSyntax(String syntaxId)
245    {
246  606 return this.componentManager.hasComponent(BlockRenderer.class, syntaxId);
247    }
248    }