View Javadoc

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                     //if the fromExpression body isn't defined, skip expression test
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         					//remove the extra whitespace from both so as to have an accurrate comarison
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         //find all library translation files and find the
270         //the directory they exist in (since translation tests will
271         //be in the same directory structure)
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         //Now take all the testResourceLocationNames and get the actual locations
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 }