1 package org.ocltf.test;
2
3 import java.io.File;
4 import java.io.FilenameFilter;
5 import java.io.IOException;
6 import java.net.URL;
7 import java.util.ArrayList;
8 import java.util.Collection;
9 import java.util.HashMap;
10 import java.util.Iterator;
11 import java.util.Map;
12
13 import junit.framework.TestCase;
14 import junit.framework.TestSuite;
15
16 import org.apache.commons.lang.StringUtils;
17 import org.apache.commons.logging.Log;
18 import org.apache.commons.logging.LogFactory;
19 import org.ocltf.ExpressionTranslator;
20 import org.ocltf.common.ComponentContainer;
21 import org.ocltf.common.ResourceFinder;
22 import org.ocltf.common.XmlObjectFactory;
23 import org.ocltf.model.ElementFacade;
24 import org.ocltf.model.ModelFacade;
25 import org.ocltf.translation.Expression;
26 import org.ocltf.translation.TraceTranslator;
27 import org.ocltf.translation.TranslationUtils;
28 import org.ocltf.translation.library.Library;
29 import org.ocltf.translation.library.LibraryTranslation;
30
31 /***
32 * This object is used to test Translations during
33 * development.
34 */
35 public class TranslationTestProcessor extends TestCase {
36
37 private static Log logger = LogFactory.getLog(TranslationTestProcessor.class);
38
39 private static Map testConfigs = new HashMap();
40
41 private static final String TEST_FILE_PREFIX = "TranslationTest-";
42
43 /***
44 * If this is specified as a system property, then
45 * the TraceTranslator will run instead of the specified translator.
46 * This is helpful, in allowing us to see which expressions are being
47 * parsed in what order, etc.
48 */
49 private boolean useTraceTranslator =
50 StringUtils.isNotEmpty(System.getProperty("trace.expression"));
51
52 /***
53 * If this is specified as a system property, then
54 * the only this translation will be tested (If .more than one
55 * TestTranslation-* file is found)
56 */
57 private String translationName =
58 StringUtils.trimToEmpty(System.getProperty("translation.name"));
59
60 private ModelFacade model = null;
61
62 /***
63 * The translation that is currently being tested.
64 */
65 private String testTranslation = null;
66
67 /***
68 * Basic constructor - called by the test runners.
69 */
70 private TranslationTestProcessor(String testName) {
71 super(testName);
72 }
73
74 /***
75 * Assembles test suite if all known tests
76 * @return non-null test suite
77 */
78 public static TestSuite suite() throws Exception {
79 ExpressionTranslator.instance().initialize();
80 TranslationTestProcessor.loadTests();
81 TestSuite suite = new TestSuite();
82 Iterator configIt = TranslationTestProcessor.testConfigs.keySet().iterator();
83 while (configIt.hasNext()) {
84 TranslationTestProcessor test = new TranslationTestProcessor("testTranslation");
85 test.setTestTranslation((String)configIt.next());
86 suite.addTest(test);
87 }
88 return suite;
89 }
90
91 /***
92 * Sets the value for the test translation which is the translation
93 * that will be tested.
94 * @param testTranslation
95 */
96 private void setTestTranslation(String testTranslation) {
97 this.testTranslation = testTranslation;
98 }
99
100 /***
101 * Finds the classifier having the.ocltf.llyQualifiedName in the model.
102 * @param fullyqQualifiedName
103 * @return ElementFacade the facade wrapped classifier.
104 */
105 protected ElementFacade findClassifier(String fullyQualifiedName) {
106 String methodName = "findClassifier";
107 ElementFacade element = null;
108 if(StringUtils.isNotEmpty(fullyQualifiedName)) {
109 model = ModelLoader.instance().getModel();
110 if(model == null) {
111 throw new RuntimeException(methodName
112 + " - model can not be null");
113 }
114 element = model.findClassifier(fullyQualifiedName);
115 if(element == null) {
116 String errMsg =
117 "No element found in model with name --> '"
118 + fullyQualifiedName
119 + "', please check your model or your TranslationTest file";
120 logger.error("ERROR! " + errMsg);
121 TestCase.fail(errMsg);
122 }
123 }
124 return element;
125 }
126
127 /***
128 * Tests the current translation set in the currentTestTranslation
129 * property.
130 */
131 public void testTranslation() {
132
133 String translation = this.testTranslation;
134
135 if(this.shouldTest(translation)) {
136
137 if(logger.isInfoEnabled()) {
138 logger.info("testing translation --> '" + translation + "'");
139 }
140
141 TranslationTest config = (TranslationTest)testConfigs.get(translation);
142
143 Map expressions = config.getExpressionConfigs();
144
145 if(expressions != null) {
146 Iterator expressionIt = expressions.keySet().iterator();
147 while (expressionIt.hasNext()) {
148
149 String fromExpression = (String)expressionIt.next();
150
151
152 if(StringUtils.isEmpty(fromExpression)) {
153 if(logger.isInfoEnabled()) {
154 logger.info("No body for the 'from' element was defined "
155 + "within translation test --> '"
156 + config.getUri()
157 + "', please define the body of this element with "
158 + "the expression you want to translate from");
159 }
160 continue;
161 }
162
163 Expression translated;
164 if(useTraceTranslator) {
165 translated = TraceTranslator.getInstance().translate(translation, null, fromExpression);
166 } else {
167
168 ExpressionTest expressionConfig =
169 (ExpressionTest)expressions.get(fromExpression);
170 String toExpression = expressionConfig.getTo();
171
172 translated = ExpressionTranslator.instance().translate(
173 translation,
174 this.findClassifier(
175 expressionConfig.getContextType()),
176 fromExpression);
177
178 if(translated != null) {
179
180 toExpression = TranslationUtils.removeExtraWhitespace(toExpression);
181 if(logger.isInfoEnabled()) {
182 logger.info("translated: --> '" + translated.getTranslatedExpression() + "'");
183 logger.info("expected: --> '" + toExpression + "'");
184 }
185 TestCase.assertEquals(toExpression, translated.getTranslatedExpression());
186 }
187 }
188 }
189 }
190 } else {
191 if(logger.isInfoEnabled()) {
192 logger.info("skipping translation --> '" + translation + "'");
193 }
194 }
195 }
196
197 /***
198 * This method returns true if we should allow the translation
199 * to be tested. This is so we can specify on the command line,
200 * the translation to be tested, if we don't want all to be tested.
201 * @param translation
202 * @return boolean
203 */
204 private boolean shouldTest(String translation) {
205 translation = StringUtils.trimToEmpty(translation);
206 return StringUtils.isEmpty(this.translationName) ||
207 (StringUtils.isNotEmpty(this.translationName) &&
208 this.translationName.equals(translation));
209 }
210
211 /***
212 * Finds and loads all test configuration files found.
213 */
214 private static void loadTests() throws IOException {
215
216 Collection testResourceLocations = findTestResourceLocations();
217
218 Iterator testResourceLocationIt = testResourceLocations.iterator();
219 for (int ctr = 0; testResourceLocationIt.hasNext(); ctr++) {
220
221 File packageFile = (File)testResourceLocationIt.next();
222
223 class XmlTestFileFilter implements FilenameFilter {
224 public boolean accept(File directory, String name) {
225 return StringUtils.trimToEmpty(name).startsWith(TEST_FILE_PREFIX);
226 }
227 }
228
229 File[] testFiles = packageFile.listFiles(new XmlTestFileFilter());
230
231 if(testFiles != null && testFiles.length > 0) {
232 for (int ctr2 = 0; ctr2 < testFiles.length; ctr2++) {
233 URL testUrl = testFiles[ctr2].toURL();
234 if(logger.isInfoEnabled()) {
235 logger.info("loading Translator test --> '" + testUrl + "'");
236 }
237 TranslationTest testConfig =
238 (TranslationTest)XmlObjectFactory.getInstance(TranslationTest.class, testUrl);
239 testConfig.setUri(testUrl);
240 testConfigs.put(testConfig.getTranslation(), testConfig);
241 }
242 } else {
243 if(logger.isDebugEnabled()) {
244 logger.debug("No Translator test files with prefix '"
245 + TEST_FILE_PREFIX
246 + "*'found in resource --> '"
247 + packageFile + "'");
248 }
249 }
250 }
251 if(testConfigs.isEmpty()) {
252 if(logger.isWarnEnabled()) {
253 logger.warn("WARNING!! No test resources found for any translation");
254 }
255 }
256 }
257
258 /***
259 * Finds all the directories which TranslationTest should be found in.
260 *
261 * @return Collection
262 */
263 private static Collection findTestResourceLocations() {
264 Collection libraries =
265 ComponentContainer.instance().findComponentsOfType(Library.class);
266
267 Collection testResourceLocationNames = new ArrayList();
268
269
270
271
272 Iterator libraryIt = libraries.iterator();
273 for (int ctr = 0; libraryIt.hasNext(); ctr++) {
274 Library library = (Library)libraryIt.next();
275 Map libraryTranslations = library.getLibraryTranslations();
276 if (libraryTranslations != null) {
277 Iterator libraryTranslationIt = libraryTranslations.keySet().iterator();
278 while (libraryTranslationIt.hasNext()) {
279 String libraryTranslationName = (String)libraryTranslationIt.next();
280 LibraryTranslation translation =
281 (LibraryTranslation)libraryTranslations.get(libraryTranslationName);
282 testResourceLocationNames.add(new File(translation.getFile()).getParent());
283 }
284 }
285 }
286
287 Collection testResourceLocations = new ArrayList();
288
289 Iterator testResourceLocationNameIt = testResourceLocationNames.iterator();
290
291
292 while (testResourceLocationNameIt.hasNext()) {
293 String name = (String)testResourceLocationNameIt.next();
294 URL[] resources = ResourceFinder.findResources(name);
295 if(resources != null && resources.length > 0) {
296 for (int ctr = 0; ctr < resources.length; ctr++) {
297 testResourceLocations.add(new File(resources[ctr].getFile()));
298 }
299 }
300 }
301
302 return testResourceLocations;
303 }
304
305 /***
306 * Runs the test suite
307 */
308 public static void main(String[] args) {
309 try {
310 junit.textui.TestRunner.run(suite());
311 } catch (Exception ex) {
312 ex.printStackTrace();
313 logger.error(ex);
314 }
315 }
316 }