1. Project Clover database Sat Feb 2 2019 06:45:20 CET
  2. Package org.xwiki.rendering.test.cts

File TestDataParser.java

 

Coverage histogram

../../../../../img/srcFileCovDistChart10.png
0% of files have more coverage

Code metrics

16
94
9
1
334
178
17
0.18
10.44
9
1.89

Classes

Class Line # Actions
TestDataParser 52 94 0% 17 1
0.9915966499.2%
 

Contributing tests

This file is covered by 2 tests. .

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.io.IOException;
23    import java.net.URL;
24    import java.util.ArrayList;
25    import java.util.Collections;
26    import java.util.List;
27    import java.util.Properties;
28    import java.util.Set;
29    import java.util.TreeSet;
30    import java.util.regex.Pattern;
31   
32    import org.apache.commons.configuration2.CompositeConfiguration;
33    import org.apache.commons.configuration2.builder.fluent.Configurations;
34    import org.apache.commons.io.IOUtils;
35    import org.apache.commons.lang3.StringUtils;
36    import org.apache.commons.lang3.tuple.ImmutablePair;
37    import org.apache.commons.lang3.tuple.Pair;
38    import org.reflections.Reflections;
39    import org.reflections.scanners.ResourcesScanner;
40    import org.reflections.util.ClasspathHelper;
41    import org.reflections.util.ConfigurationBuilder;
42    import org.reflections.util.FilterBuilder;
43   
44    /**
45    * Finds all test files in the current classloader, read them and return test data to represent them. See
46    * {@link CompatibilityTestSuite} for a description of the algorithm.
47    *
48    * @version $Id: f0f680f904245bca59f41b976974e7b085e25a58 $
49    * @since 4.1M1
50    * @see CompatibilityTestSuite
51    */
 
52    public class TestDataParser
53    {
54    /**
55    * Represents the Java resource separator.
56    */
57    private static final String SLASH = "/";
58   
59    /**
60    * Represents the dot package separator.
61    */
62    private static final String DOT = ".";
63   
64    /**
65    * Read all test data. See {@link CompatibilityTestSuite} for a detailed explanation of the algorithm.
66    *
67    * @param syntaxId the id of the syntax for which to parse data for
68    * @param ctsRootPackageName the root of the CTS resources
69    * @param packageFilter the regex to filter packages
70    * @param pattern a regex to decide which {@code *.xml} resources should be found. The default should be to find
71    * them all
72    * @return the list of test data
73    * @throws Exception in case of error while reading test data
74    */
 
75  29 toggle public List<TestData> parseTestData(String syntaxId, String ctsRootPackageName, String packageFilter,
76    String pattern) throws Exception
77    {
78  29 ClassLoader classLoader = getClass().getClassLoader();
79   
80  29 List<TestData> data = new ArrayList<TestData>();
81  29 String syntaxDirectory = computeSyntaxDirectory(syntaxId);
82   
83    // Read the suite-level Configuration data.
84  29 TestDataConfiguration configuration = parseTestConfiguration(syntaxDirectory, ctsRootPackageName, classLoader);
85   
86  29 Set<String> relativeDirectoryNames = findRelativeTestDirectoryNames(ctsRootPackageName, packageFilter, pattern);
87  29 for (String relativeDirectoryName : relativeDirectoryNames) {
88  1037 List<TestData> testDatas = parseSingleTestData(syntaxDirectory, ctsRootPackageName, relativeDirectoryName,
89    configuration, classLoader);
90  1037 for (TestData testData : testDatas) {
91  2114 testData.syntaxId = syntaxId;
92  2114 testData.prefix = relativeDirectoryName;
93  2114 testData.configuration = configuration;
94  2114 data.add(testData);
95    }
96    }
97  29 return data;
98    }
99   
100    /**
101    * Parse data for single test.
102    *
103    * @param syntaxDirectory the syntax directory from where to read syntax test data (eg "xwiki20" for "xwiki/2.0"
104    * syntax)
105    * @param ctsRootPackageName the root of the CTS resources
106    * @param relativeDirectoryName the name of the relative directory for a CTS test (eg "/simple/bold/bold1")
107    * @param configuration the test configuration
108    * @param classLoader the class loader from which the test data is read from
109    * @return the TestData instances for both input and output tests, including possible input alias tests
110    * @throws IOException in case of error while reading test data
111    */
 
112  1037 toggle public List<TestData> parseSingleTestData(String syntaxDirectory, String ctsRootPackageName,
113    String relativeDirectoryName, TestDataConfiguration configuration, ClassLoader classLoader) throws IOException
114    {
115    // Look for syntax-specific input/output file and read their content
116  1037 TestData testDataIN = new TestData();
117  1037 testDataIN.isSyntaxInputTest = true;
118  1037 TestData testDataOUT = new TestData();
119   
120    // Look for CTS input/output file and read their contents
121  1037 Pair<Pair<String, String>, Pair<String, String>> ctsData =
122    readDataForPrefix(ctsRootPackageName + SLASH + relativeDirectoryName, "xml", classLoader);
123   
124  1037 Pair<Pair<String, String>, Pair<String, String>> syntaxData = readDataForPrefix(
125    syntaxDirectory + SLASH + relativeDirectoryName, configuration.fileExtension, classLoader);
126   
127  1037 testDataIN.syntaxData = syntaxData.getLeft().getLeft();
128  1037 testDataIN.syntaxExtension = syntaxData.getLeft().getRight();
129  1037 testDataIN.ctsData = ctsData.getRight().getLeft();
130  1037 testDataIN.ctsExtension = ctsData.getRight().getRight();
131  1037 testDataOUT.syntaxData = syntaxData.getRight().getLeft();
132  1037 testDataOUT.syntaxExtension = syntaxData.getRight().getRight();
133  1037 testDataOUT.ctsData = ctsData.getLeft().getLeft();
134  1037 testDataOUT.ctsExtension = ctsData.getLeft().getRight();
135   
136    // Read possible "in" aliases
137  1037 List<TestData> testDataINAliases =
138    parseAliasesTestData(syntaxDirectory, relativeDirectoryName, ctsData, configuration, classLoader);
139   
140    // If the inherit configuration property is set and if the returned syntax is empty load from the inherit
141    // syntax.
142  1037 if (configuration.inheritSyntax != null) {
143  370 Pair<Pair<String, String>, Pair<String, String>> inheritedSyntaxData =
144    readDataForPrefix(computeSyntaxDirectory(configuration.inheritSyntax) + SLASH + relativeDirectoryName,
145    configuration.fileExtension, classLoader);
146  370 if (testDataIN.syntaxData == null) {
147  370 testDataIN.syntaxData = inheritedSyntaxData.getLeft().getLeft();
148  370 testDataIN.syntaxExtension = inheritedSyntaxData.getLeft().getRight();
149    }
150  370 if (testDataOUT.syntaxData == null) {
151  316 testDataOUT.syntaxData = inheritedSyntaxData.getRight().getLeft();
152  316 testDataOUT.syntaxExtension = inheritedSyntaxData.getRight().getRight();
153    }
154    }
155   
156  1037 List<TestData> result = new ArrayList<TestData>();
157  1037 result.add(testDataIN);
158  1037 result.addAll(testDataINAliases);
159  1037 result.add(testDataOUT);
160  1037 return result;
161    }
162   
163    /**
164    * Parse Alias test data for inputs.
165    *
166    * @param syntaxDirectory the syntax directory from where to read syntax test data (eg "xwiki20" for "xwiki/2.0"
167    * syntax)
168    * @param relativeDirectoryName the name of the relative directory for a CTS test (eg "/simple/bold/bold1")
169    * @param ctsData the CTS data to use to construct the alias test data
170    * @param configuration the test configuration
171    * @param classLoader the class loader from which the test data is read from
172    * @return the TestData instances for both input and output tests, including possible input alias tests
173    * @throws IOException in case of error while reading test data
174    */
 
175  1037 toggle private List<TestData> parseAliasesTestData(String syntaxDirectory, String relativeDirectoryName,
176    Pair<Pair<String, String>, Pair<String, String>> ctsData, TestDataConfiguration configuration,
177    ClassLoader classLoader) throws IOException
178    {
179  1037 List<TestData> testDataINAliases = new ArrayList<TestData>();
180  1037 Pair<Pair<String, String>, Pair<String, String>> syntaxDataAlias;
181  1037 int i = 1;
182  1037 do {
183  1077 syntaxDataAlias = readDataForPrefix(syntaxDirectory + SLASH + relativeDirectoryName,
184    i + DOT + configuration.fileExtension, classLoader);
185  1077 if (syntaxDataAlias.getLeft().getLeft() != null) {
186  40 TestData testDataINAlias = new TestData();
187  40 testDataINAlias.isSyntaxInputTest = true;
188  40 testDataINAlias.syntaxData = syntaxDataAlias.getLeft().getLeft();
189  40 testDataINAlias.syntaxExtension = syntaxDataAlias.getLeft().getRight();
190  40 testDataINAlias.ctsData = ctsData.getRight().getLeft();
191  40 testDataINAlias.ctsExtension = ctsData.getRight().getRight();
192  40 testDataINAliases.add(testDataINAlias);
193    }
194  1077 i++;
195  1077 } while (syntaxDataAlias.getLeft().getLeft() != null);
196  1037 return testDataINAliases;
197    }
198   
199    /**
200    * Parse Test configuration by looking for a {@code config.properties} file in the Syntax directory.
201    *
202    * @param syntaxDirectory the syntax directory under which to look for the configuration file
203    * @param ctsRootPackageName the root of the CTS resources
204    * @param classLoader the class loader from which the test configuration is read from
205    * @return the configuration
206    * @throws Exception in case of error while reading test configuration
207    */
 
208  29 toggle public TestDataConfiguration parseTestConfiguration(String syntaxDirectory, String ctsRootPackageName,
209    ClassLoader classLoader) throws Exception
210    {
211  29 TestDataConfiguration configuration = new TestDataConfiguration();
212   
213  29 CompositeConfiguration compositeConfiguration = new CompositeConfiguration();
214  29 addConfigurationData(compositeConfiguration, ctsRootPackageName, classLoader);
215  29 addConfigurationData(compositeConfiguration, syntaxDirectory, classLoader);
216   
217    // TODO: Remove these unsafe casts, need to find out how to do that nicely...
218  29 configuration.notApplicableTests =
219    (List<String>) (List<?>) compositeConfiguration.getList("notApplicableTests", Collections.emptyList());
220  29 configuration.failingTests =
221    (List<String>) (List<?>) compositeConfiguration.getList("failingTests", Collections.emptyList());
222  29 configuration.testDescriptions = compositeConfiguration.getProperties("testDescriptions", new Properties());
223  29 configuration.inheritSyntax = compositeConfiguration.getString("inheritSyntax");
224  29 configuration.fileExtension = compositeConfiguration.getString("fileExtension", "txt");
225   
226  29 return configuration;
227    }
228   
229    /**
230    * Add Configuration Data loaded from "config.properties" resources.
231    *
232    * @param configuration the composite configuration to add to
233    * @param rootPackageName the package where the configuration properties file is located
234    * @param classLoader the class loader from which the configuration is read from
235    * @throws Exception in case of error while reading test configuration
236    */
 
237  58 toggle private void addConfigurationData(CompositeConfiguration configuration, String rootPackageName,
238    ClassLoader classLoader) throws Exception
239    {
240  58 URL configurationURL = classLoader.getResource(rootPackageName + "/config.properties");
241  58 if (configurationURL != null) {
242  54 configuration.addConfiguration(new Configurations().properties(configurationURL));
243    }
244    }
245   
246    /**
247    * Read both input and output test data.
248    *
249    * @param prefix the prefix where to look for to read the test data
250    * @param fileExtension the test data file extension to look for
251    * @param classLoader the class loader from which the test data is read from
252    * @return the input and output test content along with their extensions
253    * @throws IOException in case of error while reading test data
254    */
 
255  3521 toggle private Pair<Pair<String, String>, Pair<String, String>> readDataForPrefix(String prefix, String fileExtension,
256    ClassLoader classLoader) throws IOException
257    {
258  3521 String in;
259  3521 String out;
260  3521 String inExtension = ".inout." + fileExtension;
261  3521 String outExtension = inExtension;
262  3521 String inOut = readData(prefix + inExtension, classLoader);
263  3521 if (inOut == null) {
264  2186 inExtension = ".in." + fileExtension;
265  2186 outExtension = ".out." + fileExtension;
266  2186 in = readData(prefix + inExtension, classLoader);
267  2186 out = readData(prefix + outExtension, classLoader);
268    } else {
269  1335 in = inOut;
270  1335 out = inOut;
271    }
272   
273  3521 return new ImmutablePair<Pair<String, String>, Pair<String, String>>(
274    new ImmutablePair<String, String>(in, inExtension), new ImmutablePair<String, String>(out, outExtension));
275    }
276   
277    /**
278    * @param resourceName the resource to load
279    * @param classLoader the class loader from which the test data is read from
280    * @return the test content or null if not found
281    * @throws IOException in case of error while reading test data
282    */
 
283  7893 toggle private String readData(String resourceName, ClassLoader classLoader) throws IOException
284    {
285  7893 String input = null;
286   
287  7893 URL inputURL = classLoader.getResource(resourceName);
288  7893 if (inputURL != null) {
289  2145 input = IOUtils.toString(inputURL);
290    }
291  7893 return input;
292    }
293   
294    /**
295    * Find {@code *.xml} files in the classpath and return the list of all resources found, without their filename
296    * extensions. For example if <code>{ctsDirectoryName}/simple/bold/bold1.*.xml</code> is found, return
297    * {@code simple/bold/bold1}.
298    *
299    * @param ctsRootPackageName the root of the CTS resources
300    * @param packageFilter the regex to filter packages
301    * @param pattern a regex to decide which {@code *.xml} resources should be found. The default should be to find
302    * them all
303    * @return the list of relative test directories found
304    */
 
305  30 toggle public Set<String> findRelativeTestDirectoryNames(String ctsRootPackageName, String packageFilter, String pattern)
306    {
307  30 Reflections reflections = new Reflections(new ConfigurationBuilder().setScanners(new ResourcesScanner())
308    .setUrls(ClasspathHelper.forPackage(ctsRootPackageName))
309    .filterInputsBy(new FilterBuilder.Include(FilterBuilder.prefix(ctsRootPackageName + DOT + packageFilter))));
310   
311  30 Set<String> prefixes = new TreeSet<String>();
312  30 for (String fullTestDirectoryName : reflections.getResources(Pattern.compile(pattern))) {
313    // Remove the prefix and trailing extension
314  1038 String testDirectoryName = StringUtils.substringAfter(fullTestDirectoryName, ctsRootPackageName + SLASH);
315  1038 testDirectoryName = StringUtils.substringBeforeLast(testDirectoryName, ".inout.xml");
316  1038 prefixes.add(testDirectoryName);
317    }
318   
319  30 return prefixes;
320    }
321   
322    /**
323    * Normalize a syntax directory by replacing removing "/" and "." characters. For example "xwiki/2.0" becomes
324    * "xwiki20".
325    *
326    * @param syntaxId the syntax id from which to compute a syntax directory
327    * @return the computed syntax directory
328    */
 
329  399 toggle private String computeSyntaxDirectory(String syntaxId)
330    {
331    // Remove "/" and "."
332  399 return syntaxId.replace(SLASH, "").replace(DOT, "");
333    }
334    }