/******************************************************************************* * Copyright (c) 2006-2009 * Software Technology Group, Dresden University of Technology * * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Software Technology Group - TU Dresden, Germany * - initial API and implementation ******************************************************************************/ package org.reuseware.coconut.roundtrip.test; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.util.Collection; import java.util.LinkedHashSet; import org.eclipse.emf.common.util.EList; import org.eclipse.emf.common.util.TreeIterator; import org.eclipse.emf.common.util.URI; import org.eclipse.emf.ecore.EObject; import org.eclipse.emf.ecore.util.EcoreUtil; import org.eclipse.emf.ecore.util.EcoreUtil.Copier; import org.emftext.language.java.classifiers.ClassifiersPackage; import org.emftext.language.java.members.ClassMethod; import org.emftext.language.java.members.MembersFactory; import org.emftext.language.java.members.Method; import org.emftext.language.java.statements.LocalVariableStatement; import org.emftext.language.java.statements.StatementsPackage; import org.emftext.language.java.statements.impl.LocalVariableStatementImpl; import org.emftext.language.java.types.TypesFactory; import org.emftext.language.java.variables.LocalVariable; import org.emftext.language.java.variables.VariablesPackage; import org.junit.After; import org.junit.Before; import org.junit.Test; import org.reuseware.coconut.compositionprogram.CompositionProgram; import org.reuseware.coconut.compositionsystem.resource.csys.util.CsysEObjectUtil; import org.reuseware.coconut.compositionsystem.resource.csys.util.CsysStreamUtil; import org.reuseware.coconut.fragment.ComposedFragment; import org.reuseware.coconut.fragment.Fragment; import org.reuseware.coconut.fragment.util.IModificationHandler; import org.reuseware.coconut.resource.update.CyclicDependencyException; import org.reuseware.coconut.roundtrip.RoundtripModificationHandlerFactory; import org.reuseware.coconut.roundtrip.test.util.FileHelper; public class RoundtripTest extends AbstractRoundtripTest { private LocalVariableStatementImpl copiedVariable; private ComponentsCreator creator = new ComponentsCreator(); private TestModificationHandler testHandler; private TestConflictResolver testResolver; private IModificationHandler roundtripHandler; @Before public void setUp() { try { setDoOutput(false); super.setUp(); } catch (Exception e) { fail(e.getMessage()); } try { FileHelper helper = new FileHelper(); helper.clear(new File(ComponentsCreator.PATH_TO_WORKING_DIR)); helper.clear(new File(ComponentsCreator.PATH_TO_OUTPUT_DIR)); helper.copyDir( new File(ComponentsCreator.PATH_TO_INPUT_DIR), new File(ComponentsCreator.PATH_TO_WORKING_DIR) ); } catch (IOException e) { fail(e.getMessage()); } registerFragments(); createCompositionProgram1(); createCompositionProgram2(); testHandler = new TestModificationHandler(); testResolver = new TestConflictResolver(); roundtripHandler = RoundtripModificationHandlerFactory.INSTANCE.createRoundtripModificationHandler(testResolver); } @After public void tearDown() { assertUnregisterEverything(); } @Test public void testNonConflictingChanges() { ComposedFragment composedFragment = getComposedFragment(ComponentsCreator.UFI_COMPOSED_1, testHandler, roundtripHandler); changeAttribute(composedFragment); assertNumberOfChanges(1); assertIsChangedOne(); changeAttributeBack(composedFragment); assertIsChangedTwo(); changeAttribute(composedFragment); assertIsChangedOne(); changeAttributeBack(composedFragment); assertIsChangedTwo(); deleteVariable(composedFragment, "newvalue"); assertIsRemoved(); testResolver.setDoCopyFragment(false); assertTrue("Adding the variable should be successful.", addVariable(composedFragment)); assertIsAdded(); deleteVariable(composedFragment, "newvalue"); assertIsRemoved(); testResolver.setDoCopyFragment(false); addVariable(composedFragment); assertIsAdded(); } @Test public void testConflictingChange_AddMethod1() { ComposedFragment composedFragment = getComposedFragment(ComponentsCreator.UFI_COMPOSED_2); testResolver.setSelectedFragmentUFI(URI.createURI(ComponentsCreator.REUSEWARE_UFI_SOURCE_2)); // propagate to targets of all composition programs testResolver.setDoCopyFragment(false); addMethod(composedFragment); assertMethodIsAdded1(); } @Test public void testConflictingChange_AddMethod2() { ComposedFragment composedFragment = getComposedFragment(ComponentsCreator.UFI_COMPOSED_2); testResolver.setSelectedFragmentUFI(URI.createURI(ComponentsCreator.REUSEWARE_UFI_SOURCE_2)); // propagate to targets of all composition programs testResolver.setDoCopyFragment(true); testResolver.setNewNameForCopiedFragment(URI.createURI("./work/repository/Source4.java")); addMethod(composedFragment); assertMethodIsAdded2(); } private void createCompositionProgram1() { CompositionProgram compositionProgram = creator.createCompositionProgram1(); String path = ComponentsCreator.PATH_TO_WORKING_REPOSITORY_DIR + "composition_program1.fc"; saveAndRegisterCompositionProgram(compositionProgram, path); } private void createCompositionProgram2() { CompositionProgram compositionProgram = creator.createCompositionProgram2(); String path = ComponentsCreator.PATH_TO_WORKING_REPOSITORY_DIR + "composition_program2.fc"; saveAndRegisterCompositionProgram(compositionProgram, path); } private void saveAndRegisterCompositionProgram(CompositionProgram compositionProgram, String path) { creator.saveCompositionProgram(compositionProgram, path); File file = new File(path); try { assertRegisterCompositionProgram(file, URI.createFileURI(new File(TEMP_STORE_URI).getCanonicalPath() + "/")); } catch (IOException e) { fail(e.getMessage()); } try { getChangeSet().propagate(); } catch (CyclicDependencyException e) { fail(e.getMessage()); } } private void registerFragments() { setUpJava(); try { assertRegisterFragmentStore( CompositionTestPlugin.PLUGIN_ID, ComponentsCreator.PATH_TO_WORKING_DIR, new String[] {"java"}); } catch (Exception e) { e.printStackTrace(); fail(e.getMessage()); } } private void assertNumberOfChanges(int i) { assertEquals(i + " changes expected.", i, testHandler.getEvents().size()); } private void assertIsChangedOne() { assertFilesAreSame( "Source2_changed1.java", ComponentsCreator.JAVA_SOURCE_2, "Source2.java should be changed correctly." ); } private void assertIsChangedTwo() { assertFilesAreSame( "Source2_changed2.java", ComponentsCreator.JAVA_SOURCE_2, "Source2.java should be changed correctly." ); } private void assertIsRemoved() { assertFilesAreSame( "Source2_removed.java", ComponentsCreator.JAVA_SOURCE_2, "Attribute should be deleted" ); } private void assertIsAdded() { assertFilesAreSame( "Source2_added.java", ComponentsCreator.JAVA_SOURCE_2, "Attribute should be added" ); } private void assertMethodIsAdded1() { assertFilesAreSame( "Source2_method_added.java", ComponentsCreator.JAVA_SOURCE_2, "Method should be added" ); } private void assertMethodIsAdded2() { assertFilesAreSame( "Source4.java", ComponentsCreator.JAVA_SOURCE_4, "Method should be added" ); } private void assertFilesAreSame(String expectedFile, String actualFile, String message) { boolean result = compare( ComponentsCreator.PATH_TO_COMPARE_DIR + "/" + expectedFile, ComponentsCreator.PATH_TO_WORKING_REPOSITORY_DIR + "/" + actualFile ); assertTrue(message, result); } private void changeAttribute(Fragment fragment) { assertTrue("The attribute should be changed.", changeAttribute("myVariable", "testVariable", fragment)); } private void changeAttributeBack(Fragment fragment) { assertTrue("The attribute change should be reverted.", changeAttribute("testVariable", "myVariable", fragment)); } private boolean changeAttribute(String from, String to, Fragment fragment) { EList<EObject> compositionContent = fragment.getContents(); for (EObject contentObject : compositionContent) { TreeIterator<EObject> allContents = contentObject.eAllContents(); Collection<LocalVariable> variables = CsysEObjectUtil.getObjectsByType(allContents, VariablesPackage.eINSTANCE.getLocalVariable()); for (LocalVariable localVariable : variables) { if (localVariable.getName().equals(from)) { localVariable.setName(to); return true; } } } return false; } private void deleteVariable(Fragment fragment, String variableName) { EList<EObject> compositionContent = fragment.getContents(); for (EObject contentObject : compositionContent) { TreeIterator<EObject> allContents = contentObject.eAllContents(); Collection<LocalVariableStatement> statements = CsysEObjectUtil.getObjectsByType(allContents, StatementsPackage.eINSTANCE.getLocalVariableStatement()); for (LocalVariableStatement statement : statements) { if (statement.getVariable().getName().equals(variableName)) { Copier copier = new Copier(); copiedVariable = (LocalVariableStatementImpl) copier.copy(statement); copiedVariable.eAdapters().clear(); EcoreUtil.remove(statement); } } } } private boolean addVariable(Fragment fragment) { EList<EObject> compositionContent = fragment.getContents(); for (EObject contentObject : compositionContent) { TreeIterator<EObject> allContents = contentObject.eAllContents(); Collection<LocalVariableStatement> statements = CsysEObjectUtil.getObjectsByType(allContents, StatementsPackage.eINSTANCE.getLocalVariableStatement()); for (LocalVariableStatement statement : statements) { ClassMethod method = (ClassMethod) statement.eContainer(); if (method.getName().equals("Prototype_Fragment2")) { method.getStatements().add(copiedVariable); //System.out.println("copy: " + copiedVariable); return true; } } } return false; } private void addMethod(Fragment fragment) { Method newMethod = MembersFactory.eINSTANCE.createClassMethod(); newMethod.setName("testAddMethod"); newMethod.setTypeReference(TypesFactory.eINSTANCE.createVoid()); EList<EObject> contents = fragment.getContents(); Collection<org.emftext.language.java.classifiers.Class> clazzes = new LinkedHashSet<org.emftext.language.java.classifiers.Class>(); for (EObject content : contents) { Collection<org.emftext.language.java.classifiers.Class> foundClasses = CsysEObjectUtil.getObjectsByType(content.eAllContents(), ClassifiersPackage.eINSTANCE.getClass_()); clazzes.addAll(foundClasses); } for (org.emftext.language.java.classifiers.Class clazz : clazzes) { clazz.getMembers().add(newMethod); break; } } private boolean compare(String pathToExpectedModel, String pathToActualModel) { assertEquals("a\nb", removeWhitespacesAndEmptyLines("a\n\nb")); assertEquals("a\nb", removeWhitespacesAndEmptyLines("a\n\n\nb")); String expected; String actual; try { expected = getContent(pathToExpectedModel); actual = getContent(pathToActualModel); } catch (IOException e) { fail(e.getMessage()); return false; } expected = removeWhitespacesAndEmptyLines(expected); actual = removeWhitespacesAndEmptyLines(actual); expected = trimLines(expected); actual = trimLines(actual); boolean equal = expected.equals(actual); if (!equal) { System.out.println("EXPECTED: [" + expected + "]"); System.out.println("ACTUAL: [" + actual + "]"); } assertEquals(expected, actual); return equal; } private String getContent(String pathToModel) throws FileNotFoundException, IOException { FileInputStream inputStream = new FileInputStream(pathToModel); String content = CsysStreamUtil.getContent(inputStream); inputStream.close(); return content; } private String trimLines(String expected) { String result = trimLines(expected, "\n"); result = trimLines(result, "\r"); result = trimLines(result, "\n\r"); result = trimLines(result, "\r\n"); return result; } private String trimLines(String expected, String lineDelimiter) { String[] lines = expected.split(lineDelimiter); StringBuffer result = new StringBuffer(); for (String line : lines) { result.append(line.trim() + lineDelimiter); } return result.toString(); } private String removeWhitespacesAndEmptyLines(String text) { String result = text; int lengthBefore = result.length(); while (true) { result = result.replace("\t", ""); result = result.replace("\r\n\r\n", "\r\n"); result = result.replace("\n\r\n\r", "\n\r"); result = result.replace("\r\r", "\r"); result = result.replace("\n\n", "\n"); result = result.replaceAll("\\A\n", ""); result = result.replaceAll("\\A\r", ""); result = result.replaceAll(" $", ""); int lengthAfter = result.length(); if (lengthAfter == lengthBefore) { break; } lengthBefore = lengthAfter; } return result; } }