| /******************************************************************************* |
| * Copyright (c) 2010, 2011 Obeo. |
| * 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: |
| * Obeo - initial API and implementation |
| *******************************************************************************/ |
| package org.eclipse.mylyn.docs.intent.client.ui.test.unit.compare; |
| |
| import com.google.common.collect.Sets; |
| |
| import java.util.Collection; |
| import java.util.List; |
| |
| import junit.framework.AssertionFailedError; |
| |
| import org.eclipse.emf.compare.Diff; |
| import org.eclipse.emf.compare.DifferenceKind; |
| import org.eclipse.emf.ecore.util.EcoreUtil; |
| import org.eclipse.mylyn.docs.intent.client.ui.test.util.AbstractIntentUITest; |
| import org.eclipse.mylyn.docs.intent.compare.utils.EMFCompareUtils; |
| import org.eclipse.mylyn.docs.intent.core.document.IntentDocument; |
| import org.eclipse.mylyn.docs.intent.core.document.IntentSection; |
| import org.eclipse.mylyn.docs.intent.core.document.IntentStructuredElement; |
| import org.eclipse.mylyn.docs.intent.parser.IntentParser; |
| import org.eclipse.mylyn.docs.intent.parser.modelingunit.ParseException; |
| |
| /** |
| * Test ensuring that the Intent match engine works as expected. |
| * |
| * @author <a href="mailto:alex.lagarde@obeo.fr">Alex Lagarde</a> |
| */ |
| public class IntentMatchEngineTests extends AbstractIntentUITest { |
| |
| /** |
| * Path of the test file. |
| */ |
| private static final String INTENT_DOCUMENT_FOLDER = "data/unit/documents/editorupdates/"; |
| |
| /** |
| * All assertion failed errors (are only raised in the end to have the number of failures and not stop at |
| * first one). |
| */ |
| private Collection<AssertionFailedError> errors = Sets.newLinkedHashSet(); |
| |
| /** |
| * Number of tested cases. |
| */ |
| private int compareCasesNumber; |
| |
| /** |
| * Ensures that the Intent match engine works as expected on the given test file. |
| */ |
| public void testCompareDocumentWithChapterTitles() { |
| doTestDiffEngine("compareTest-01.intent"); |
| } |
| |
| /** |
| * Ensures that the Intent match engine works as expected on the given test file. |
| */ |
| public void testCompareDocumentWithoutChapterTitles() { |
| doTestDiffEngine("compareTest-02.intent"); |
| } |
| |
| /** |
| * Ensures that all modifications that can be made on the IntentDocument located at the given model path |
| * are correctly detected. |
| * |
| * @param modelPath |
| * the path of the Intent document model (from |
| * org.eclipse.mylyn.docs.intent.client.ui.test/data/unit/models/documents/) |
| */ |
| protected void doTestDiffEngine(String modelPath) { |
| // Step 1: we load the intent document |
| parseIntentDocumentFromTests(INTENT_DOCUMENT_FOLDER + modelPath); |
| |
| // Step 2: compare with a copy of this element |
| doTestCopyIsEqualToOriginal(); |
| |
| // Step 3 : test that adding chapters works as expected |
| doTestAddingChapter(); |
| |
| // Step 4 : test that removing chapters works as expected |
| doTestRemovingChapter(); |
| |
| // Step 5 : test that adding sections works as expected |
| doTestAddingSections(); |
| |
| // Step 5 : test that removing sections works as expected |
| doTestRemovingSections(); |
| |
| // Step 6 : display assertion errors |
| if (!errors.isEmpty()) { |
| String message = errors.size() + " comparaison failures detected on " + compareCasesNumber |
| + " cases.\n First issue :" + errors.iterator().next().getMessage(); |
| AssertionFailedError error = new AssertionFailedError(message); |
| error.setStackTrace(errors.iterator().next().getStackTrace()); |
| throw error; |
| } |
| |
| } |
| |
| /** |
| * Ensures that no differences are detected when comparing a Document with a copy of itself. |
| */ |
| protected void doTestCopyIsEqualToOriginal() { |
| // Create a copy of the document |
| IntentStructuredElement copy = EcoreUtil.copy(getIntentDocument()); |
| |
| // Check that copy is equal to original |
| List<Diff> differences = EMFCompareUtils.compareDocuments(copy, getIntentDocument()).getDifferences(); |
| String message = "No difference should be detected between an Intent document and its copy"; |
| try { |
| assertDiffIsAsExpected(message, differences, 0); |
| } catch (AssertionFailedError e) { |
| errors.add(e); |
| } |
| } |
| |
| /** |
| * Ensures that the creation of any Chapter in the Intent document is correctly detected. |
| */ |
| protected void doTestAddingChapter() { |
| |
| // Create a copy with a new chapter |
| IntentDocument copy = EcoreUtil.copy(getIntentDocument()); |
| IntentSection newChapter; |
| try { |
| newChapter = (IntentSection)new IntentParser().parse("Chapter {\n\tChapter 1\n\tChaper1\n\t"); |
| |
| // according to where the chapter is added, we should have the following results : |
| for (int position = 0; position <= getIntentDocument().getIntentContent().size(); position++) { |
| copy.getSubSections().add(position, newChapter); |
| List<Diff> differences = EMFCompareUtils.compareDocuments(copy, getIntentDocument()) |
| .getDifferences(); |
| String message = "One new chapter should be detected at position " + position; |
| try { |
| Diff diff = assertDiffIsAsExpected(message, differences, 2); |
| assertEquals(message + '\n' + getDiffAsString(differences), DifferenceKind.ADD, |
| diff.getKind()); |
| // TODO migrate to emf compare2 |
| // assertEquals(message + getDiffAsString(differences), newChapter, |
| // ((ModelElementChangeLeftTarget)diff).getLeftElement()); |
| // assertEquals(message + getDiffAsString(differences), getIntentDocument(), |
| // ((ModelElementChangeLeftTarget)diff).getRightParent()); |
| } catch (AssertionFailedError e) { |
| errors.add(e); |
| } |
| copy.getSubSections().remove(newChapter); |
| |
| } |
| } catch (ParseException e) { |
| fail(e.getMessage()); |
| } |
| } |
| |
| /** |
| * Ensures that the deletion of any Chapter in the Intent document is correctly detected. |
| */ |
| protected void doTestRemovingChapter() { |
| // Create a copy in which a chapter is removed |
| IntentDocument copy = EcoreUtil.copy(getIntentDocument()); |
| // according to where the chapter is added, we should have the following results : |
| for (int position = 0; position < getIntentDocument().getSubSections().size(); position++) { |
| IntentSection chapterToRemoveinCopy = copy.getSubSections().get(position); |
| copy.getIntentContent().remove(chapterToRemoveinCopy); |
| String message = "A Chapter deletion should be detected at " + position; |
| try { |
| List<Diff> differences = EMFCompareUtils.compareDocuments(copy, getIntentDocument()) |
| .getDifferences(); |
| Diff diff = assertDiffIsAsExpected(message, differences, 2); |
| assertEquals(message + '\n' + getDiffAsString(differences), DifferenceKind.DELETE, |
| diff.getKind()); |
| // TODO migrate to emf compare2 |
| // assertEquals(message + '\n' + getDiffAsString(differences), chapterToRemoveInOriginal, |
| // ((ModelElementChangeRightTarget)diff).getRightElement()); |
| // assertEquals(message + '\n' + getDiffAsString(differences), copy, |
| // ((ModelElementChangeRightTarget)diff).getLeftParent()); |
| } catch (AssertionFailedError e) { |
| errors.add(e); |
| } |
| copy.getSubSections().add(position, chapterToRemoveinCopy); |
| |
| } |
| |
| } |
| |
| /** |
| * Ensures that the creation of any section/subsection in the Intent document is correctly detected. |
| */ |
| protected void doTestAddingSections() { |
| // Create a copy |
| IntentDocument copy = EcoreUtil.copy(getIntentDocument()); |
| |
| // For each chapter of the document |
| for (int chapterID = 0; chapterID < getIntentDocument().getSubSections().size(); chapterID++) { |
| doTestAddingSectionsRecursive(copy, getIntentDocument().getSubSections().get(chapterID), copy |
| .getSubSections().get(chapterID), 3); |
| } |
| } |
| |
| /** |
| * Ensures that the creation of any section/subsection in the Intent document is correctly detected. |
| * |
| * @param copy |
| * a copy of the intent document (in which the modification should be made) |
| * @param container |
| * the container in witch the new section should be added |
| * @param containerCopy |
| * the copy of the container in witch the new section should be added |
| * @param containerLevel |
| * the global containment level |
| */ |
| private void doTestAddingSectionsRecursive(IntentDocument copy, IntentSection container, |
| IntentSection containerCopy, int containerLevel) { |
| IntentSection newSection; |
| try { |
| newSection = (IntentSection)new IntentParser().parse("Section {\n\tSection 1\n\tSection1\n\t"); |
| |
| // according to where the section is added, we should have the following results : |
| for (int sectionID = 0; sectionID <= container.getSubSections().size(); sectionID++) { |
| containerCopy.getIntentContent().add(sectionID, newSection); |
| List<Diff> differences = EMFCompareUtils.compareDocuments(copy, getIntentDocument()) |
| .getDifferences(); |
| String message = "One new section should be detected at position " + containerLevel + "." |
| + sectionID; |
| try { |
| Diff diff = assertDiffIsAsExpected(message, differences, containerLevel); |
| assertEquals(message + '\n' + getDiffAsString(differences), DifferenceKind.ADD, |
| diff.getKind()); |
| // TODO migrate to emf compare2 |
| // assertEquals(message + '\n' + getDiffAsString(differences), newSection, |
| // ((ModelElementChangeLeftTarget)diff).getLeftElement()); |
| // assertEquals(message + '\n' + getDiffAsString(differences), container, |
| // ((ModelElementChangeLeftTarget)diff).getRightParent()); |
| } catch (AssertionFailedError e) { |
| errors.add(e); |
| } |
| containerCopy.getIntentContent().remove(sectionID); |
| |
| // considering subsections of the current container |
| for (int subSectionID = 0; subSectionID < container.getSubSections().size(); subSectionID++) { |
| doTestAddingSectionsRecursive(copy, container.getSubSections().get(subSectionID), |
| containerCopy.getSubSections().get(subSectionID), containerLevel + 1); |
| } |
| |
| } |
| } catch (ParseException e) { |
| fail(e.getMessage()); |
| } |
| |
| } |
| |
| /** |
| * Ensures that the deletion of any section/subsection in the Intent document is correctly detected. |
| */ |
| protected void doTestRemovingSections() { |
| // Create a copy |
| IntentDocument copy = EcoreUtil.copy(getIntentDocument()); |
| |
| // For each chapter of the document |
| for (int chapterID = 0; chapterID < getIntentDocument().getSubSections().size(); chapterID++) { |
| doTestRemovingSectionsRecursive(copy, getIntentDocument().getSubSections().get(chapterID), copy |
| .getSubSections().get(chapterID), 3); |
| } |
| |
| } |
| |
| /** |
| * Ensures that the deletion of any section/subsection in the Intent document is correctly detected. |
| * |
| * @param copy |
| * a copy of the intent document (in which the modification should be made) |
| * @param container |
| * the container in witch the new section should be added |
| * @param containerCopy |
| * the copy of the container in witch the new section should be added |
| * @param containerLevel |
| * the global containment level |
| */ |
| private void doTestRemovingSectionsRecursive(IntentDocument copy, IntentSection container, |
| IntentSection containerCopy, int containerLevel) { |
| |
| // Delete each subsection |
| for (int sectionID = 0; sectionID < container.getSubSections().size(); sectionID++) { |
| IntentSection removedSection = (IntentSection)containerCopy.getSubSections().get(sectionID); |
| int trueIndex = containerCopy.getIntentContent().indexOf(removedSection); |
| containerCopy.getIntentContent().remove(removedSection); |
| List<Diff> differences = EMFCompareUtils.compareDocuments(copy, getIntentDocument()) |
| .getDifferences(); |
| String message = "A Section deletion should be detected at position" + containerLevel + "." |
| + sectionID; |
| |
| try { |
| Diff diff = assertDiffIsAsExpected(message, differences, containerLevel); |
| assertEquals(message + '\n' + getDiffAsString(differences), DifferenceKind.DELETE, |
| diff.getKind()); |
| // TODO migrate to emf compare2 |
| // assertEquals(message + '\n' + getDiffAsString(differences), |
| // container.getIntentContent().get(trueIndex), |
| // ((ModelElementChangeRightTarget)diff).getRightElement()); |
| // assertEquals(message + '\n' + getDiffAsString(differences), containerCopy, |
| // ((ModelElementChangeRightTarget)diff).getLeftParent()); |
| } catch (AssertionFailedError e) { |
| errors.add(e); |
| } |
| containerCopy.getIntentContent().add(trueIndex, removedSection); |
| |
| // considering subsections of the current container |
| for (int subSectionID = 0; subSectionID < container.getSubSections().size(); subSectionID++) { |
| doTestRemovingSectionsRecursive(copy, container.getSubSections().get(subSectionID), |
| containerCopy.getSubSections().get(subSectionID), containerLevel + 1); |
| } |
| |
| } |
| } |
| |
| /** |
| * Ensures that the given differences describes exactly one difference at the expected level, with no |
| * sub-differences. |
| * |
| * @param message |
| * the failure message |
| * @param differences |
| * the differences to inspect |
| * @param expectedLevel |
| * the expected level for the diff (2 for chapter, 3 for root section, 4 for subsection...). |
| * @return the expected diff element if correct |
| */ |
| protected Diff assertDiffIsAsExpected(String message, Collection<Diff> differences, int expectedLevel) { |
| compareCasesNumber++; |
| assertEquals(message + '\n' + getDiffAsString(differences), 1, differences.size()); |
| |
| // We want to have exactly one difference at the expected level |
| Diff childDiff = differences.iterator().next(); |
| int currentLevel = 0; |
| while (childDiff != null && currentLevel < expectedLevel) { |
| // assertEquals(message + '\n' + getDiffAsString(differences), 1, childDiff.getSubDiffs().size()); |
| // TODO migrate to emf compare2 |
| currentLevel++; |
| // childDiff = childDiff.getSubDiffs().iterator().next(); |
| // TODO migrate to emf compare2 |
| } |
| |
| // This difference should not have any sub difference elements |
| // assertEquals(message + '\n' + getDiffAsString(differences), 0, childDiff.getSubDiffs().size()); // |
| // TODO migrate to emf compare2 |
| return childDiff; |
| } |
| |
| /** |
| * Returns the given differences as string (to show them in assertion message). |
| * |
| * @param differences |
| * the dirrences to get as string |
| * @return the given differences as string (to show them in assertion message) |
| */ |
| protected String getDiffAsString(Collection<Diff> differences) { |
| String diff = ""; |
| for (Diff element : differences) { |
| diff += element.toString() + '\n'; |
| // diff += getDiffAsString(element.getSubDiffs()); // TODO migrate to emf compare2 |
| } |
| return diff; |
| } |
| } |