PageRenderTime 24ms CodeModel.GetById 15ms RepoModel.GetById 0ms app.codeStats 1ms

/emf-2.8.0/org.eclipse.emf.test.tools/src/org/eclipse/emf/test/tools/merger/JMergerTest.java

#
Java | 459 lines | 255 code | 53 blank | 151 comment | 24 complexity | 54b672d6595c9bc96bf5c0fb419dcf24 MD5 | raw file
  1. /**
  2. * Copyright (c) 2004-2007 IBM Corporation and others.
  3. * All rights reserved. This program and the accompanying materials
  4. * are made available under the terms of the Eclipse Public License v1.0
  5. * which accompanies this distribution, and is available at
  6. * http://www.eclipse.org/legal/epl-v10.html
  7. *
  8. * Contributors:
  9. * IBM - Initial API and implementation
  10. */
  11. package org.eclipse.emf.test.tools.merger;
  12. import java.io.File;
  13. import java.io.FileInputStream;
  14. import java.util.Collections;
  15. import java.util.HashMap;
  16. import java.util.Hashtable;
  17. import java.util.Map;
  18. import junit.framework.ComparisonFailure;
  19. import junit.framework.TestCase;
  20. import junit.framework.TestSuite;
  21. import org.eclipse.jdt.core.JavaCore;
  22. import org.eclipse.jdt.core.formatter.DefaultCodeFormatterConstants;
  23. import org.eclipse.emf.codegen.ecore.generator.Generator;
  24. import org.eclipse.emf.codegen.ecore.generator.GeneratorAdapterFactory;
  25. import org.eclipse.emf.codegen.ecore.genmodel.GenModel;
  26. import org.eclipse.emf.codegen.ecore.genmodel.GenModelFactory;
  27. import org.eclipse.emf.codegen.ecore.genmodel.generator.GenModelGeneratorAdapterFactory;
  28. import org.eclipse.emf.codegen.merge.java.JControlModel;
  29. import org.eclipse.emf.codegen.merge.java.JMerger;
  30. import org.eclipse.emf.codegen.merge.java.facade.FacadeHelper;
  31. import org.eclipse.emf.common.EMFPlugin;
  32. import org.eclipse.emf.test.common.TestUtil;
  33. import org.eclipse.emf.test.tools.AllSuites;
  34. /**
  35. * Base class for all JMerger tests.
  36. * <p>
  37. * For special test cases, default data directory is determined by {@link #getDefaultDataDirectory()}.
  38. * For tests created by <code>JMergerTestSuite</code>, see {@link JMergerTestSuite}.
  39. * <p>
  40. * Merge source and target files are respectively <code>MergerSource.java</code> and <code>MergerTarget.java</code> in data directory.
  41. * <p>
  42. * Expected output file is either test specific output file (determined by {@link #getTestSpecificExpectedOutput()} or
  43. * <code>MergerExpected.java</code> in data directory.
  44. * <p>
  45. * Merge rules are used from <code>merge.xml</code> file in data directory if it exists, otherwise default EMF merge rules are used.
  46. */
  47. public abstract class JMergerTest extends TestCase
  48. {
  49. /**
  50. * @param name
  51. */
  52. public JMergerTest(String name)
  53. {
  54. super(name);
  55. }
  56. /**
  57. * Creates and adds the test to the given test suite if possible
  58. *
  59. * @param ts
  60. * @param dataDirectory
  61. * @see #addItself(TestSuite)
  62. */
  63. public JMergerTest(TestSuite ts, File dataDirectory)
  64. {
  65. setDataDirectory(dataDirectory);
  66. addItself(ts);
  67. }
  68. /**
  69. * Default name of the expected output file.
  70. */
  71. public static final String DEFAULT_EXPECTED_OUTPUT_FILENAME = "MergerExpected.java";
  72. /**
  73. * Map of directory names to versions of Java to be used to overwrite settings in JavaCore.
  74. */
  75. public static final Map<String, String> DIRECTORY_NAMES_TO_JAVA_VERSIONS;
  76. static
  77. {
  78. Map<String, String> directoryNamesMap = new HashMap<String, String>(4);
  79. directoryNamesMap.put("java1.4", JavaCore.VERSION_1_4);
  80. directoryNamesMap.put("java5", JavaCore.VERSION_1_5);
  81. DIRECTORY_NAMES_TO_JAVA_VERSIONS = Collections.unmodifiableMap(directoryNamesMap);
  82. }
  83. /**
  84. * Verifies that target contents matches the contents of expected output file.
  85. *
  86. * @param expectedOutput
  87. * @param targetContents
  88. */
  89. protected static void verifyMerge(File expectedOutput, String targetContents)
  90. {
  91. // extract merged contents
  92. StringBuilder mergeResult = new StringBuilder(targetContents);
  93. // The merge expected file was saved without any '\r' so
  94. // we need to remove it from the mergedResult
  95. for (int i = mergeResult.length() - 1; i >= 0; i--)
  96. {
  97. if ('\r' == mergeResult.charAt(i))
  98. {
  99. mergeResult.deleteCharAt(i);
  100. }
  101. }
  102. String expectedMerge = TestUtil.readFile(expectedOutput, false);
  103. String actualMerge = mergeResult.toString();
  104. try
  105. {
  106. assertEquals("Make sure the line breaks are OK. The expected merge should have no '\\r'", expectedMerge, actualMerge);
  107. }
  108. catch (ComparisonFailure exception)
  109. {
  110. File alternative = new File(expectedOutput.toString().replace(".java", "Alt.java"));
  111. if (alternative.exists())
  112. {
  113. expectedMerge = TestUtil.readFile(alternative, false);
  114. assertEquals("Make sure the line breaks are OK. The expected merge should have no '\\r'", expectedMerge, actualMerge);
  115. }
  116. else
  117. {
  118. throw exception;
  119. }
  120. }
  121. }
  122. /**
  123. * If <code>true</code>, editor options are set from default options in genmodel.
  124. */
  125. protected boolean applyGenModelEditorFormatting = false;
  126. protected File dataDirectory = null;
  127. protected File expectedOutput = null;
  128. /**
  129. * URI of merge rules file to be used by {@link JControlModel#initialize(FacadeHelper, String)}
  130. */
  131. protected String mergeRulesURI = null;
  132. protected File source = null;
  133. protected File target = null;
  134. /**
  135. * @param javaVersion (one of {@link JavaCore#VERSION_1_1} to {@link JavaCore#VERSION_1_6}
  136. */
  137. @SuppressWarnings({"unchecked", "rawtypes"})
  138. protected void adjustSourceCompatibility(String javaVersion)
  139. {
  140. Hashtable map = JavaCore.getOptions();
  141. map.put(JavaCore.COMPILER_SOURCE, javaVersion);
  142. JavaCore.setOptions(map);
  143. }
  144. /**
  145. * Adjusts JavaCore source compatibility options based on {@link #computeJavaVersion()}.
  146. *
  147. * @see #adjustSourceCompatibility(String)
  148. */
  149. protected void adjustSourceCompatibility()
  150. {
  151. String javaVersion = computeJavaVersion();
  152. assertNotNull("Unable to determine Java version from directory name. ", javaVersion);
  153. adjustSourceCompatibility(javaVersion);
  154. }
  155. /**
  156. * Determines java version based on the name of the parent of data directory.
  157. * <p>
  158. * Parent directory must match one of {@link #DIRECTORY_NAMES_TO_JAVA_VERSIONS}
  159. * @return java version or <code>null</code> if can not be determined
  160. */
  161. protected String computeJavaVersion()
  162. {
  163. File parentDirectory = dataDirectory.getParentFile();
  164. String javaVersion = null;
  165. do
  166. {
  167. javaVersion = DIRECTORY_NAMES_TO_JAVA_VERSIONS.get(parentDirectory.getName());
  168. parentDirectory = parentDirectory.getParentFile();
  169. }
  170. while (javaVersion == null && parentDirectory != null);
  171. return javaVersion;
  172. }
  173. /**
  174. * @return test specific expected output file or default expected output file, but never <code>null</code>.
  175. * @see #getTestSpecificExpectedOutput()
  176. */
  177. protected File computeExpectedOutputFile()
  178. {
  179. File expectedOutput = getTestSpecificExpectedOutput();
  180. if (expectedOutput != null && expectedOutput.exists())
  181. {
  182. return expectedOutput;
  183. }
  184. else
  185. {
  186. return new File(getDataDirectory(), DEFAULT_EXPECTED_OUTPUT_FILENAME).getAbsoluteFile();
  187. }
  188. }
  189. /**
  190. * Returns unique name for the expected output file.
  191. * <p>
  192. * Expected to be overwritten by subclasses.
  193. * <p>
  194. * This implementation returns <code>null</code>.
  195. * @return expected output file, or <code>null</code> if only default file should be used
  196. */
  197. protected File getTestSpecificExpectedOutput()
  198. {
  199. return null;
  200. }
  201. /**
  202. * @param jControlModel
  203. */
  204. @SuppressWarnings("rawtypes")
  205. protected void applyGenModelEditorFormattingSettings(org.eclipse.emf.codegen.merge.java.JControlModel jControlModel)
  206. {
  207. if (EMFPlugin.IS_ECLIPSE_RUNNING)
  208. {
  209. Map options = JavaCore.getOptions();
  210. String tabSize = (String)options.get(DefaultCodeFormatterConstants.FORMATTER_TAB_SIZE);
  211. String braceStyle = (String)options.get(DefaultCodeFormatterConstants.FORMATTER_BRACE_POSITION_FOR_TYPE_DECLARATION);
  212. String tabCharacter = (String)options.get(DefaultCodeFormatterConstants.FORMATTER_TAB_CHAR);
  213. if (JavaCore.TAB.equals(tabCharacter))
  214. {
  215. jControlModel.setLeadingTabReplacement("\t");
  216. }
  217. else
  218. {
  219. String spaces = "";
  220. for (int i = Integer.parseInt(tabSize); i > 0; --i)
  221. {
  222. spaces += " ";
  223. }
  224. jControlModel.setLeadingTabReplacement(spaces);
  225. }
  226. jControlModel.setConvertToStandardBraceStyle(DefaultCodeFormatterConstants.END_OF_LINE.equals(braceStyle));
  227. }
  228. }
  229. /**
  230. * Default directory is in the form <code>data/merge.input/special.&lt;testname&gt;</code>
  231. *
  232. * @return default data directory to use if data directory not set
  233. */
  234. protected File getDefaultDataDirectory()
  235. {
  236. StringBuilder sb = new StringBuilder(TestUtil.getPluginDirectory(AllSuites.PLUGIN_ID));
  237. sb.append(File.separator).append("data");
  238. sb.append(File.separator).append("merge.input");
  239. sb.append(File.separator).append("special.").append(getName());
  240. return new File(sb.toString());
  241. }
  242. /**
  243. * @return URI of EMF merge rules resource
  244. */
  245. protected String getEMFMergeRulesURI()
  246. {
  247. // create model
  248. GenModel genModel = GenModelFactory.eINSTANCE.createGenModel();
  249. // create adapter factory
  250. GeneratorAdapterFactory adapterFactory = GenModelGeneratorAdapterFactory.DESCRIPTOR.createAdapterFactory();
  251. adapterFactory.setGenerator(new Generator());
  252. adapterFactory.initialize(genModel);
  253. // get merge rules URI
  254. return adapterFactory.getGenerator().getOptions().mergeRulesURI;
  255. }
  256. /**
  257. * @return the dataDirectory
  258. */
  259. public File getDataDirectory()
  260. {
  261. if (dataDirectory == null)
  262. {
  263. dataDirectory = getDefaultDataDirectory();
  264. }
  265. return dataDirectory;
  266. }
  267. /**
  268. * @return the expectedOutput
  269. */
  270. public File getExpectedOutput()
  271. {
  272. return expectedOutput;
  273. }
  274. /**
  275. * @return the mergeRulesURI
  276. */
  277. public String getMergeRulesURI()
  278. {
  279. return mergeRulesURI;
  280. }
  281. /**
  282. * @param dataDirectory the dataDirectory to set
  283. */
  284. public void setDataDirectory(File dataDirectory)
  285. {
  286. this.dataDirectory = dataDirectory;
  287. }
  288. /**
  289. * @param expectedOutput the expectedOutput to set
  290. */
  291. public void setExpectedOutput(File expectedOutput)
  292. {
  293. this.expectedOutput = expectedOutput;
  294. }
  295. /**
  296. * @param mergeRulesURI the mergeRulesURI to set
  297. */
  298. public void setMergeRulesURI(String mergeRulesURI)
  299. {
  300. this.mergeRulesURI = mergeRulesURI;
  301. }
  302. /**
  303. * Tests whether the facade helper is of correct type
  304. * @param facadeHelper
  305. */
  306. protected abstract void instanceTest(FacadeHelper facadeHelper);
  307. /**
  308. * @return facade helper instance
  309. */
  310. protected abstract FacadeHelper instanciateFacadeHelper();
  311. /**
  312. * Adds itself to the test suite if expected output file returned by {@link #computeExpectedOutputFile()} exists.
  313. *
  314. * @param ts
  315. */
  316. public void addItself(TestSuite ts)
  317. {
  318. File expectedOutput = computeExpectedOutputFile();
  319. if (expectedOutput.exists())
  320. {
  321. setExpectedOutput(expectedOutput);
  322. ts.addTest(this);
  323. }
  324. }
  325. /**
  326. * Perform and verify merge. To be used in merge tests by subclasses.
  327. * <b>
  328. * Before performing merge, java compiler source version is set based on data directory.
  329. *
  330. * @throws Exception
  331. * @see #adjustSourceCompatibility()
  332. */
  333. protected void merge() throws Exception
  334. {
  335. adjustSourceCompatibility();
  336. verifyMerge(expectedOutput, mergeFiles());
  337. }
  338. /**
  339. * @return contents after merging contents of source and target files
  340. * @throws Exception
  341. */
  342. protected String mergeFiles() throws Exception
  343. {
  344. String sourceCompatibility = JavaCore.getOption(JavaCore.COMPILER_SOURCE);
  345. FacadeHelper facadeHelper = instanciateFacadeHelper();
  346. instanceTest(facadeHelper);
  347. JControlModel controlModel = new JControlModel();
  348. assertFalse(controlModel.canMerge());
  349. controlModel.initialize(facadeHelper, mergeRulesURI);
  350. if (applyGenModelEditorFormatting)
  351. {
  352. applyGenModelEditorFormattingSettings(controlModel);
  353. }
  354. assertTrue(controlModel.canMerge());
  355. JMerger jMerger = new JMerger(controlModel);
  356. // set source
  357. jMerger.setSourceCompilationUnit(jMerger.createCompilationUnitForContents(TestUtil.readFile(source, true)));
  358. // set target
  359. if (target.isFile())
  360. {
  361. jMerger.setTargetCompilationUnit(jMerger.createCompilationUnitForInputStream(new FileInputStream(target)));
  362. }
  363. // merge source and target
  364. jMerger.merge();
  365. // Ensure the facade is returning the COMPILER_SOURCE to the original value.
  366. assertEquals(sourceCompatibility, JavaCore.getOption(JavaCore.COMPILER_SOURCE));
  367. return jMerger.getTargetCompilationUnitContents();
  368. }
  369. /**
  370. * Sets up data directory, source, target, expected output, and merge rules attributes.
  371. * <p>
  372. * If <code>merge.xml</code> is not available in data directory, default EMF merge rules are used.
  373. *
  374. * @see #getDataDirectory()
  375. * @see #computeExpectedOutputFile()
  376. * @see #getEMFMergeRulesURI()
  377. *
  378. * @see junit.framework.TestCase#setUp()
  379. */
  380. @Override
  381. protected void setUp() throws Exception
  382. {
  383. File dataDirectory = getDataDirectory();
  384. assertTrue("Merge Data directory is not available - " + dataDirectory.getAbsolutePath(), dataDirectory.isDirectory());
  385. if (mergeRulesURI == null)
  386. {
  387. File mergeXML = new File(dataDirectory, "merge.xml").getAbsoluteFile();
  388. if (!mergeXML.exists())
  389. {
  390. mergeRulesURI = getEMFMergeRulesURI();
  391. }
  392. else
  393. {
  394. mergeRulesURI = mergeXML.getAbsolutePath();
  395. }
  396. }
  397. source = new File(dataDirectory, "MergerSource.java").getAbsoluteFile();
  398. assertTrue("Merge Source file is not available - " + source.getAbsolutePath(), source.isFile());
  399. target = new File(dataDirectory, "MergerTarget.java").getAbsoluteFile();
  400. if (expectedOutput == null)
  401. {
  402. expectedOutput = computeExpectedOutputFile();
  403. }
  404. assertTrue("Merge Result file is not available - " + expectedOutput.getAbsolutePath(), expectedOutput.isFile());
  405. }
  406. }