/* * Copyright (c) 2006, 2009 Borland Software Corporation * * 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: * Alexander Fedorov (Borland) - initial API and implementation * Artem Tikhomirov (Borland) - additional test cases */ package org.eclipse.gmf.tests.tr; import java.text.MessageFormat; import java.util.regex.Matcher; import java.util.regex.Pattern; import junit.framework.TestCase; import org.eclipse.gmf.internal.common.codegen.PluginXMLTextMerger; public class PluginXMLTextMergerTest extends TestCase { private final static String NL = System.getProperties().getProperty("line.separator"); //$NON-NLS-1$ private static final String PI_TARGET_GMFGEN = "gmfgen"; //$NON-NLS-1$ private static final String PI_DATA_GENERATED = "generated"; //$NON-NLS-1$ private static final String PI_GENERATED_VALUE = "true"; //$NON-NLS-1$ private static final String PI = MessageFormat.format(" <?{0} {1}=\"{2}\"?>", PI_TARGET_GMFGEN, PI_DATA_GENERATED, PI_GENERATED_VALUE); //$NON-NLS-1$ private final static String T_00 = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" + NL; //$NON-NLS-1$ private final static String T_01 = "<?eclipse version=\"3.0\"?>" + NL + NL; //$NON-NLS-1$ private final static String T_02 = "<plugin>" + NL + NL; //$NON-NLS-1$ private final static String T_10 = " <extension point=\"org.eclipse.core.runtime.preferences\">" + NL; //$NON-NLS-1$ private final static String T_11 = PI + NL; private final static String T_12 = " <initializer class=\"org.example.mindmap.diagram.part.MindmapDiagramPreferenceInitializer\"/>" + NL; //$NON-NLS-1$ private final static String T_13 = " </extension>" + NL + NL; //$NON-NLS-1$ private final static String T_20 = " <extension point=\"org.eclipse.core.runtime.preferences\">" + NL; //$NON-NLS-1$ private final static String T_21 = PI + NL; private final static String T_22 = " <initializer class=\"org.example.mindmap.diagram.part.MindmapDiagramPreferenceInitializer2\"/>" + NL; //$NON-NLS-1$ private final static String T_23 = " </extension>" + NL + NL; //$NON-NLS-1$ private final static String T_30 = " <extension point=\"org.eclipse.core.runtime.preferences\">" + NL; //$NON-NLS-1$ private final static String T_31 = " <initializer class=\"org.example.mindmap.diagram.part.MindmapDiagramPreferenceInitializer3\"/>" + NL; //$NON-NLS-1$ private final static String T_32 = " </extension>" + NL + NL; //$NON-NLS-1$ private final static String T_33 = " <extension point='org.eclipse.core.runtime.preferences'>" + NL; //$NON-NLS-1$ private final static String T_34 = " <initializer class=\"org.example.mindmap.diagram.part.MindmapDiagramPreferenceInitializer3\"/>" + NL; //$NON-NLS-1$ private final static String T_35 = " </extension>" + NL + NL; //$NON-NLS-1$ private final static String T_36 = " <extension point = \"org.eclipse.core.runtime.preferences\">" + NL; //$NON-NLS-1$ private final static String T_37 = " <initializer class=\"org.example.mindmap.diagram.part.MindmapDiagramPreferenceInitializer3\"/>" + NL; //$NON-NLS-1$ private final static String T_38 = " </extension>" + NL + NL; //$NON-NLS-1$ private final static String T_40 = " <extension" + NL; //$NON-NLS-1$ private final static String T_41 = " point=\"org.eclipse.ui.views\">" + NL; //$NON-NLS-1$ private final static String T_42 = " <category" + NL; //$NON-NLS-1$ private final static String T_43 = " id=\"org.eclipse.gmf.examples.mindmap.diagram.categoryMindmap\"" + NL; //$NON-NLS-1$ private final static String T_44 = " name=\"%diagram.category.mindmap\"/>" + NL; //$NON-NLS-1$ private final static String T_45 = " </extension>" + NL + NL; //$NON-NLS-1$ private final static String T_50 = " <extension point=\"org.eclipse.gmf.runtime.common.ui.services.properties.propertiesProviders\">" + NL; //$NON-NLS-1$ private final static String T_51 = PI + NL; private final static String T_52 = " <PropertiesProvider"+ NL; //$NON-NLS-1$ private final static String T_53 = " verifyPluginLoaded=\"false\""+ NL; //$NON-NLS-1$ private final static String T_54 = " class=\"org.example.mindmap.diagram.providers.MindmapPropertyProvider\">"+ NL; //$NON-NLS-1$ private final static String T_55 = " <Priority name=\"Lowest\"/>"+ NL; //$NON-NLS-1$ private final static String T_56 = " </PropertiesProvider>"+ NL; //$NON-NLS-1$ private final static String T_57 = " </extension>" + NL + NL; //$NON-NLS-1$ private final static String T_60 = " <extension point=\"org.eclipse.gmf.runtime.common.ui.services.parserProviders\">" + NL; //$NON-NLS-1$ private final static String T_61 = PI + NL; private final static String T_62 = " <ParserProvider class=\"org.example.mindmap.diagram.providers.MindmapParserProvider\">"+ NL; //$NON-NLS-1$ private final static String T_63 = " <Priority name=\"Lowest\"/>"+ NL; //$NON-NLS-1$ private final static String T_64 = " </ParserProvider>"+ NL; //$NON-NLS-1$ private final static String T_65 = " </extension>" + NL + NL; //$NON-NLS-1$ private final static String T_70 = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"; //$NON-NLS-1$ private final static String T_71 = "<?eclipse version=\"3.0\"?>"; //$NON-NLS-1$ private final static String T_72 = "<plugin>"; //$NON-NLS-1$ private final static String T_73 = " <extension point=\"org.eclipse.core.runtime.preferences\">"; //$NON-NLS-1$ private final static String T_74 = PI; private final static String T_75 = " <initializer class=\"org.example.mindmap.diagram.part.MindmapDiagramPreferenceInitializer\"/>"; //$NON-NLS-1$ private final static String T_76 = " </extension>"; //$NON-NLS-1$ private final static String T_77 = " <extension point=\"org.eclipse.core.runtime.preferences\">"; //$NON-NLS-1$ private final static String T_78 = " <initializer class=\"org.example.mindmap.diagram.part.MindmapDiagramPreferenceInitializer3\"/>"; //$NON-NLS-1$ private final static String T_79 = " </extension>"; //$NON-NLS-1$ private final static String T_80 = " <extension point=\"org.eclipse.gmf.runtime.common.ui.services.parserProviders\">" + NL; //$NON-NLS-1$ private final static String T_81 = " <!-- " + PI + " -->" + NL; //$NON-NLS-1$ private final static String T_82 = " <!--<extension point=\"org.eclipse.core.runtime.preferences\">" + NL; //$NON-NLS-1$ private final static String T_83 = " <initializer class=\"org.example.mindmap.diagram.part.MindmapDiagramPreferenceInitializer3\"/>" + NL; //$NON-NLS-1$ private final static String T_84 = " </extension>-->" + NL + NL; //$NON-NLS-1$ private final static String T_85 = " <ParserProvider class=\"org.example.mindmap.diagram.providers.MindmapParserProvider\">"+ NL; //$NON-NLS-1$ private final static String T_86 = " <Priority name=\"Lowest\"/>"+ NL; //$NON-NLS-1$ private final static String T_87 = " </ParserProvider>"+ NL; //$NON-NLS-1$ private final static String T_88 = " </extension>" + NL + NL; //$NON-NLS-1$ private final static String T_99 = "</plugin>"; //$NON-NLS-1$ private final static String T_0 = T_00 + T_01 + T_02; private final static String T_1 = T_10 + T_11 + T_12 + T_13; private final static String T_2 = T_20 + T_21 + T_22 + T_23; private final static String T_3 = T_30 + T_31 + T_32; private final static String T_3_A = T_33 + T_34 + T_35; private final static String T_3_S = T_36 + T_37 + T_38; private final static String T_4 = T_40 + T_41 + T_42 + T_43 + T_44 + T_45; private final static String T_5 = T_50 + T_51 + T_52 + T_53 + T_54 + T_55 + T_56 + T_57; private final static String T_6 = T_60 + T_61 + T_62 + T_63 + T_64 + T_65; private final static String T_7 = T_70 + T_71 + T_72 + T_73 + T_74 + T_75 + T_76 + T_77 + T_78 + T_79; private final static String T_8 = T_80 + T_81 + T_82 + T_83 + T_84 + T_85 + T_86 + T_87 + T_88; private PluginXMLTextMerger myMerger; private boolean shouldFailOnException = true; private Pattern myNewLinePattern = Pattern.compile("\r\n"); public PluginXMLTextMergerTest(String name) { super(name); } protected void setUp() throws Exception { super.setUp(); myMerger = new PluginXMLTextMerger(PI_TARGET_GMFGEN, PI_DATA_GENERATED, PI_GENERATED_VALUE) { @Override protected void logException(String message, Exception e) { if (shouldFailOnException) { fail(message); } } }; } public void testInvalidOld() { final String oldXML = NL; final String newXML = T_0 + T_2 + T_99; final String expectedResult = newXML; shouldFailOnException = false; internalTest(oldXML, newXML, expectedResult); } public void testInvalidNew() { final String oldXML = T_0 + T_1 + T_99; final String newXML = NL; final String expectedResult = oldXML; shouldFailOnException = false; internalTest(oldXML, newXML, expectedResult); } /** * this one may pass ok even if result is not merged ok, because default behaviour is to just return newXML. */ public void testAddEmptyOld() { final String oldXML = T_0 + T_99; final String newXML = T_0 + T_2 + T_99; final String expectedResult = T_0 + T_2.trim() + NL + NL + T_99; internalTestIgnoreNewlines(oldXML, newXML, expectedResult); } /** * This one helps to catch situation from {@link #testAddEmptyOld()}, when * default newXML is returned */ public void testAddNonEmptyOld() { final String oldContent = "<extension-point id='zzz'/>" + NL; //$NON-NLS-1$ final String oldXML = T_0 + oldContent + T_99; final String newXML = T_0 + T_2 + T_99; final String expectedResult = T_0 + oldContent + T_2.trim() + NL + NL + T_99; internalTest(oldXML, newXML, expectedResult); } // DOESNT work because nothing but extensions are copied from original xml // public void testAddToEmptyWithComment() { // final String oldXML = T_0 + T_99; // final String newXML = T_0 + "<!-- xxx -->" + NL + T_2 + T_99; // final String expectedResult = newXML; // internalTestIgnoreNewlines(oldXML, newXML, expectedResult); // } public void testWithEntities() { final String e1 = " "; final String e2 = "<>"; final String oldXML = T_0 + e1 + T_1 + e2 + T_99; final String newXML = T_0 + T_2 + T_99; final String expectedResult = T_0 + e1 + T_2 + e2 + T_99; internalTest(oldXML, newXML, expectedResult); } public void testDifferentNewLines() { final String oldXML = T_0 + T_1 + T_3 + T_4 + T_5 + T_99; final String newXML = T_0 + T_2 + T_6 + T_99; final String expectedResult = T_0 + T_2 + T_3 + T_4 + T_6 + NL + T_99; internalTestIgnoreNewlines(oldXML, switchNewlines(newXML), expectedResult); internalTestIgnoreNewlines(switchNewlines(oldXML), newXML, expectedResult); internalTestIgnoreNewlines(switchNewlines(oldXML), switchNewlines(newXML), expectedResult); internalTestIgnoreNewlines(oldXML, newXML, switchNewlines(expectedResult)); } private static String switchNewlines(String testString) { final String replacement = NL.length() == 2 ? "\n" : "\r\n"; final Matcher matcher = Pattern.compile(NL).matcher(testString); assertTrue(matcher.find()); return matcher.replaceAll(replacement); } public void testRemove() { final String oldXML = T_0 + T_1 + T_99; final String newXML = T_0 + T_99; //TODO: remove orphan whitespaces final String expectedResult = T_0 + " " + NL + T_99; //$NON-NLS-1$ internalTest(oldXML, newXML, expectedResult); } public void testKeep() { final String oldXML = T_0 + T_4 + T_99; final String newXML = T_0 + T_99; final String expectedResult = T_0 + T_4 + T_99; internalTest(oldXML, newXML, expectedResult); } public void testReplace() { final String oldXML = T_0 + T_1 + T_99; final String newXML = T_0 + T_2 + T_99; final String expectedResult = newXML; internalTest(oldXML, newXML, expectedResult); } // DOESNT work because nothing but extensions are copied from original xml // public void testReplace2() { // final String oldXML = T_0 + T_1 + T_99; // final String newXML = T_0 + "<!-- xxx -->" + NL + T_2 + T_99; // final String expectedResult = newXML; // internalTest(oldXML, newXML, expectedResult); // } public void testGeneratedNot() { final String oldXML = (T_0 + T_1 + T_99).replace("generated=\"true\"", "generated=\"false\""); final String newXML = T_0 + T_2 + T_99; final String expectedResult = oldXML; internalTest(oldXML, newXML, expectedResult); } public void testComplex() { final String oldXML = T_0 + T_1 + T_3 + T_4 + T_5 + T_99; final String newXML = T_0 + T_2 + T_6 + T_99; final String expectedResult = T_0 + T_2 + T_3 + T_4 + T_6 + NL + T_99; internalTest(oldXML, newXML, expectedResult); } public void testUnformatted() { final String oldXML = T_7 + T_99; final String newXML = T_0 + T_2 + T_99; final String expectedResult = T_70 + T_71 + T_72 + T_20 + T_21 + T_22 + T_79 + NL + T_77 + T_78 + T_79 + T_99; internalTest(oldXML, newXML, expectedResult); } public void testWithComments() { final String oldXML = T_0 + T_1 + T_8 + T_99; final String newXML = T_0 + T_2 + T_99; final String expectedResult = T_0 + T_2 + T_8 + T_99; internalTest(oldXML, newXML, expectedResult); } public void testApostrophe() { final String oldXML = T_0 + T_3_A + T_99; final String newXML = T_0 + T_2 + T_99; final String expectedResult = T_0 + T_3_A + T_99; internalTest(oldXML, newXML, expectedResult); } public void testSpace() { final String oldXML = T_0 + T_3_S + T_99; final String newXML = T_0 + T_2 + T_99; final String expectedResult = T_0 + T_3_S + T_99; internalTest(oldXML, newXML, expectedResult); } private static final String file = T_0 + NL + "%s" + NL + T_99; private static final String extensionNoId = "<extension point=\"oeg.extpoint\">%s</extension>" + NL; private static final String extensionWithId = "<extension point=\"oeg.extpoint\" id=\"%s\">%s</extension>" + NL; // Synopsis: GMF adds generation of a new extension, while users have had written // extensions to the same point already in their plugin.xml public void testSameExtensionPointConflictNoIdentities() { String oldXML = String.format(extensionNoId, "<user><manual/></user>"); String newXML = String.format(extensionNoId, PI + "<newbody/>"); // NOTE, this test might duplicate one of the above, just for sanity check internalTest_Bodies(oldXML, newXML, /* sic! old content persists */ oldXML); } public void testConflictWithManuallyAddedIdentifiedExtension() { String oldXML = String.format(extensionWithId, "identity", "<user><manual/></user>"); String newXML = String.format(extensionNoId, PI + "<newbody/>"); internalTest_Bodies(oldXML, newXML, oldXML + newXML + NL); // new line is subtle hack } public void testConflictWithManuallyAddedNoIdentityExtension() { String oldXML = String.format(extensionNoId, "<user><manual/></user>"); String newXML = String.format(extensionWithId, "generated-identity", PI + "<newbody/>"); internalTest_Bodies(oldXML, newXML, oldXML + newXML + NL); // new line is subtle hack } public void testConflictWithManuallyAddedDistinctIdentities() { String oldXML = String.format(extensionWithId, "manual-identity", "<user><manual/></user>"); String newXML = String.format(extensionWithId, "generated-identity", PI + "<newbody/>"); internalTest_Bodies(oldXML, newXML, oldXML + newXML + NL); // new line is subtle hack } public void testConflictBothGeneratedButDistinctIdentities() { String oldXML_withIdentity = String.format(extensionWithId, "generated-id1", PI + "<oldbody/>"); String newXML = String.format(extensionWithId, "also-generated-id2", PI + "<newbody/>"); internalTest_Bodies(oldXML_withIdentity, newXML, newXML); String oldXML_noIdentity = String.format(extensionNoId, PI + "<oldbody/>"); internalTest_Bodies(oldXML_noIdentity, newXML, newXML); } public void testConflicTwoGeneratedTwistIdentities() { String oldXML_1 = String.format(extensionWithId, "generated-id1", PI + "<oldbody1/>"); String oldXML_2 = String.format(extensionWithId, "generated-id2", PI + "<oldbody2/>"); String newXML_1 = String.format(extensionWithId, "generated-id2", PI + "<newbody2/>"); String newXML_2 = String.format(extensionWithId, "generated-id1", PI + "<newbody1/>"); internalTest_Bodies(oldXML_1 + oldXML_2, newXML_1 + newXML_2, newXML_2 + newXML_1); } // Synopsis: GMF generates an extension, user adds another one for the same point, // would like to have former regenerated, while latter kept intact public void testTwoExtensionsSamePointOneAddedManualWithID() { String oldXML_1 = String.format(extensionWithId, "manual", "<user><trash/></user>"); String oldXML_2 = String.format(extensionNoId, PI + "<oldbody/>"); String newXML = String.format(extensionNoId, PI + "<newbody/>"); internalTest_Bodies(oldXML_1 + oldXML_2, newXML, oldXML_1 + newXML); // try different order of extensions internalTest_Bodies(oldXML_2 + oldXML_1, newXML, newXML + oldXML_1); } public void testTwoExtensionsSamePointOneAddedManualNoID() { String oldXML_1 = String.format(extensionNoId, "<user><trash/></user>"); String oldXML_2 = String.format(extensionWithId, "generated-identity", PI + "<oldbody/>"); String newXML = String.format(extensionWithId, "generated-identity", PI + "<newbody/>"); internalTest_Bodies(oldXML_1 + oldXML_2, newXML, oldXML_1 + newXML); // try different order of extensions internalTest_Bodies(oldXML_2 + oldXML_1, newXML, newXML + oldXML_1); } // bug #269542: 3 extensions for the same extpoint, all with distinct ids. One (first! in the file) is manually modified and // marked generated=false. After regeneration, original content of that extension is appended in the end of plugin.xml // Seems quite similar to the previous test, {@link #testTwoExtensionsSamePointOneAddedManualNoID}, the difference is // in identity of the modified extension public void testTwoExtensionsSamePointOneModified() { String oldXML_1 = String.format(extensionWithId, "id1", "<body1/>"); String oldXML_2 = String.format(extensionWithId, "id2", PI + "<body2/>"); String newXML_1 = String.format(extensionWithId, "id1", PI + "<newbody/>"); String newXML_2 = String.format(extensionWithId, "id2", PI + "<newbody/>"); internalTest_Bodies(oldXML_1 + oldXML_2, newXML_1 + newXML_2, oldXML_1 + newXML_2); // other ordering internalTest_Bodies(oldXML_1 + oldXML_2, newXML_2 + newXML_1, oldXML_1 + newXML_2); internalTest_Bodies(oldXML_2 + oldXML_1, newXML_1 + newXML_2, newXML_2 + oldXML_1); internalTest_Bodies(oldXML_2 + oldXML_1, newXML_2 + newXML_1, newXML_2 + oldXML_1); } public void testTwoGeneratedExtensionsSamePointReplacedByOne() { String oldXML_1 = String.format(extensionWithId, "generated-id1", PI + "<oldbody1/>"); // fill in some space in between String oldXML_2 = "<extension point=\"different.point\"><bogus/></extension>\n"; String oldXML_3 = String.format(extensionWithId, "generated-id3", PI + "<oldbody3/>"); String newXML = String.format(extensionWithId, "generated-id3", PI + "<newbody3/>"); // despite the fact that we replace third extension, order is always newXML+<bogus> // because first extension gets replaced with the only available new extension, and only // then, when it gets to third extension, it wipes it away as no more matching extension coming. // Perhaps, makes sense to modify PluginXMLTextMerger so that it looks though old descriptors // for matching identity even when there's single replacement extension - and if there's matching // in the old file, replace it instead of the presently processed (the one in the currentPosition) internalTest_Bodies(oldXML_1 + oldXML_2 + oldXML_3, newXML, newXML + oldXML_2); // try different order of extensions internalTest_Bodies(oldXML_3 + oldXML_2 + oldXML_1, newXML, newXML + oldXML_2); } public void testTwoGeneratedExtensionsSamePointReplacedByTwoWithIDs() { String oldXML_1 = String.format(extensionNoId, PI + "<oldbody1/>"); String oldXML_2 = String.format(extensionNoId, PI + "<oldbody2/>"); String newXML_1 = String.format(extensionWithId, "generated-id1", PI + "<newbody1/>"); String newXML_2 = String.format(extensionWithId, "generated-id2", PI + "<newbody2/>"); internalTest_Bodies(oldXML_1 + oldXML_2, newXML_1 + newXML_2, newXML_1 + newXML_2); } // new extension was generated, make sure it gets injected into result public void testNewExtensionIsInjected() { String oldXML = "<extension point=\"oeg.extpoint.one\" id=\"one\"><oldbody/></extension>"; String newXML_1 = "<extension point=\"oeg.extpoint.two\" id=\"two\"><newbody/></extension>" + NL; internalTest_Bodies(oldXML, newXML_1 + NL + oldXML, oldXML + NL + newXML_1 /*XXX order is changed, not good but ok for now*/); } private void internalTest_Bodies(String oldFileBody, String newFileBody, String expectedFileBody) { String result = myMerger.process(String.format(file, oldFileBody), String.format(file, newFileBody)); assertNotNull(result); final String expectedResult = String.format(file, expectedFileBody); assertEquals(expectedResult, result); } private void internalTest(String oldXML, String newXML, String expectedResult) { String result = myMerger.process(oldXML, newXML); assertNotNull(result); assertEquals(expectedResult, result); } private void internalTestIgnoreNewlines(String oldXML, String newXML, String expectedResult) { String result = myMerger.process(oldXML, newXML); assertNotNull(result); String uniformResult = myNewLinePattern.matcher(result).replaceAll("\n"); String uniformExpected = myNewLinePattern.matcher(expectedResult).replaceAll("\n"); assertEquals(uniformExpected, uniformResult); } }