blob: 4369193bf075013986b35cb03f2f42196981a812 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2006, 2015 IBM Corporation and others.
* 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:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.compare.tests;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.Map;
import junit.framework.TestCase;
import org.eclipse.compare.CompareConfiguration;
import org.eclipse.compare.ICompareFilter;
import org.eclipse.compare.IEditableContent;
import org.eclipse.compare.IStreamContentAccessor;
import org.eclipse.compare.ITypedElement;
import org.eclipse.compare.contentmergeviewer.TextMergeViewer;
import org.eclipse.compare.internal.ChangeCompareFilterPropertyAction;
import org.eclipse.compare.internal.IMergeViewerTestAdapter;
import org.eclipse.compare.internal.MergeViewerContentProvider;
import org.eclipse.compare.internal.Utilities;
import org.eclipse.compare.structuremergeviewer.DiffNode;
import org.eclipse.compare.structuremergeviewer.Differencer;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.jface.dialogs.Dialog;
import org.eclipse.jface.text.Document;
import org.eclipse.jface.text.DocumentEvent;
import org.eclipse.jface.text.IDocument;
import org.eclipse.jface.text.IDocumentPartitioner;
import org.eclipse.jface.text.IRegion;
import org.eclipse.jface.text.ITypedRegion;
import org.eclipse.jface.text.Region;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.ui.PlatformUI;
public class TextMergeViewerTest extends TestCase {
/**
* Returns a boolean value indicating whether or not the contents
* of the given streams are considered to be equal. Closes both input streams.
* @param a stream a
* @param b stream b
* @return whether the two streams contain the same contents
*/
public static boolean compareContent(InputStream a, InputStream b) {
int c, d;
if (a == null && b == null)
return true;
try {
if (a == null || b == null)
return false;
while ((c = a.read()) == (d = b.read()) && (c != -1 && d != -1)) {
//body not needed
}
return (c == -1 && d == -1);
} catch (IOException e) {
return false;
} finally {
try {
if (a != null)
a.close();
} catch (IOException e) {
// ignore
}
try {
if (b != null)
b.close();
} catch (IOException e) {
// ignore
}
}
}
public static class TestElement implements ITypedElement {
public Image getImage() {
return null;
}
public String getName() {
return "test";
}
public String getType() {
return UNKNOWN_TYPE;
}
}
/**
* A parent test element is an {@link IEditableContent} but is not directly editable.
* The purpose of the parent is to be able to copy a child into the destination element.
*/
public static class ParentTestElement extends TestElement implements IEditableContent {
public boolean isEditable() {
return false;
}
public ITypedElement replace(ITypedElement child, ITypedElement other) {
if (child == null) { // add child
// clone the other and return it as the new child
if (other instanceof EditableTestElement) {
EditableTestElement ete = (EditableTestElement) other;
return (ITypedElement)ete.clone();
}
}
if (other == null) { // delete child
// Return null as the new child
return null;
}
if (other instanceof IStreamContentAccessor && child instanceof IEditableContent) {
IEditableContent dst= (IEditableContent) child;
try {
InputStream is= ((IStreamContentAccessor)other).getContents();
byte[] bytes= Utilities.readBytes(is);
if (bytes != null)
dst.setContent(bytes);
} catch (CoreException ex) {
throw new WrappedException(ex);
}
}
return child;
}
public void setContent(byte[] newContent) {
// Node is not directly editable
}
}
public static class EditableTestElement extends TestElement implements IStreamContentAccessor, IEditableContent {
byte[] contents = new byte[0];
public EditableTestElement(byte[] contents) {
this.contents = contents;
}
public String getType() {
return TEXT_TYPE;
}
public InputStream getContents() {
return new ByteArrayInputStream(contents);
}
protected Object clone() {
return new EditableTestElement(contents);
}
public boolean isEditable() {
return true;
}
public ITypedElement replace(ITypedElement dest, ITypedElement src) {
// Nothing to do since this node has no children
return null;
}
public void setContent(byte[] newContent) {
contents = newContent;
}
public boolean equals(Object obj) {
if (obj instanceof EditableTestElement) {
EditableTestElement other = (EditableTestElement) obj;
return TextMergeViewerTest.compareContent(other.getContents(), getContents());
}
return false;
}
public Object getContentsAsString() {
return new String(contents);
}
}
public static class TestMergeViewer extends TextMergeViewer {
public TestMergeViewer(Composite parent) {
super(parent, new CompareConfiguration());
}
public TestMergeViewer(Composite parent, CompareConfiguration cc) {
super(parent, cc);
}
public void copy(boolean leftToRight) {
super.copy(leftToRight);
}
}
public static class WrappedException extends RuntimeException {
private static final long serialVersionUID = 1L;
Exception exception;
public WrappedException(Exception exception) {
super();
this.exception = exception;
}
public void throwException() throws Exception {
throw exception;
}
}
TestMergeViewer viewer;
public TextMergeViewerTest() {
super();
}
public TextMergeViewerTest(String name) {
super(name);
}
private void runInDialog(Object input, Runnable runnable) throws Exception {
runInDialog(input, runnable, new CompareConfiguration());
}
private void runInDialog(Object input, Runnable runnable,
final CompareConfiguration cc) throws Exception {
Shell shell = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell();
Dialog dialog = new Dialog(shell) {
protected Control createDialogArea(Composite parent) {
Composite composite = (Composite) super.createDialogArea(parent);
viewer = new TestMergeViewer(composite, cc);
return composite;
}
};
dialog.setBlockOnOpen(false);
dialog.open();
viewer.setInput(input);
try {
runnable.run();
} catch (WrappedException e) {
e.throwException();
}
dialog.close();
viewer = null;
}
protected void saveViewerContents() {
try {
viewer.save(new NullProgressMonitor());
} catch (CoreException e) {
throw new WrappedException(e);
}
}
protected IDocument getDocument(boolean left) {
char leg = left ? MergeViewerContentProvider.LEFT_CONTRIBUTOR : MergeViewerContentProvider.RIGHT_CONTRIBUTOR;
IDocument document = Utilities.getDocument(leg, viewer.getInput(), true, true);
if (document == null) {
return viewer.getAdapter(IMergeViewerTestAdapter.class).getDocument(leg);
}
return document;
}
public void testCopyRightToLeft() throws Exception {
DiffNode parentNode = new DiffNode(new ParentTestElement(), new ParentTestElement());
String copiedText = "hi there";
DiffNode testNode = new DiffNode(parentNode, Differencer.CHANGE, null, new EditableTestElement("some text".getBytes()), new EditableTestElement(copiedText.getBytes()));
runInDialog(testNode, new Runnable() {
public void run() {
viewer.copy(false /* rightToLeft */);
saveViewerContents();
}
});
assertEquals(copiedText, ((EditableTestElement)testNode.getLeft()).getContentsAsString());
}
public void testCopyLeftToRight() throws Exception {
DiffNode parentNode = new DiffNode(new ParentTestElement(), new ParentTestElement());
String copiedText = "hi there";
DiffNode testNode = new DiffNode(parentNode, Differencer.CHANGE, null, new EditableTestElement(copiedText.getBytes()), new EditableTestElement("some text".getBytes()));
runInDialog(testNode, new Runnable() {
public void run() {
viewer.copy(true /* leftToRight */);
saveViewerContents();
}
});
assertEquals(copiedText, ((EditableTestElement)testNode.getRight()).getContentsAsString());
}
public void testCopyRightToEmptyLeft() throws Exception {
DiffNode parentNode = new DiffNode(new ParentTestElement(), new ParentTestElement());
DiffNode testNode = new DiffNode(parentNode, Differencer.ADDITION, null, null, new EditableTestElement("hi there".getBytes()));
runInDialog(testNode, new Runnable() {
public void run() {
viewer.copy(false /* rightToLeft */);
saveViewerContents();
}
});
assertEquals(testNode.getRight(), testNode.getLeft());
}
public void testCopyLeftToEmptyRight() throws Exception {
DiffNode parentNode = new DiffNode(new ParentTestElement(), new ParentTestElement());
DiffNode testNode = new DiffNode(parentNode, Differencer.DELETION, null, new EditableTestElement("hi there".getBytes()), null);
runInDialog(testNode, new Runnable() {
public void run() {
viewer.copy(true /* leftToRight */);
saveViewerContents();
}
});
assertEquals(testNode.getRight(), testNode.getLeft());
}
public void testCopyEmptyLeftToRight() throws Exception {
DiffNode parentNode = new DiffNode(new ParentTestElement(), new ParentTestElement());
DiffNode testNode = new DiffNode(parentNode, Differencer.ADDITION, null, null, new EditableTestElement("hi there".getBytes()));
runInDialog(testNode, new Runnable() {
public void run() {
viewer.copy(true /* leftToRight */);
saveViewerContents();
}
});
assertNull(testNode.getLeft());
assertNull(testNode.getRight());
}
public void testCopyEmptyRightToLeft() throws Exception {
DiffNode parentNode = new DiffNode(new ParentTestElement(), new ParentTestElement());
DiffNode testNode = new DiffNode(parentNode, Differencer.DELETION, null, new EditableTestElement("hi there".getBytes()), null);
runInDialog(testNode, new Runnable() {
public void run() {
viewer.copy(false /* rightToLeft */);
saveViewerContents();
}
});
assertNull(testNode.getLeft());
assertNull(testNode.getRight());
}
public void testModifyLeft() throws Exception {
DiffNode testNode = new DiffNode(new EditableTestElement("hi there".getBytes()), null);
final String newText = "New text";
runInDialog(testNode, new Runnable() {
public void run() {
IDocument doc = getDocument(true /* left */);
doc.set(newText);
saveViewerContents();
}
});
assertEquals(newText, ((EditableTestElement)testNode.getLeft()).getContentsAsString());
}
public void testModifyRight() throws Exception {
DiffNode testNode = new DiffNode(null, new EditableTestElement("hi there".getBytes()));
final String newText = "New text";
runInDialog(testNode, new Runnable() {
public void run() {
IDocument doc = getDocument(false /* right */);
doc.set(newText);
saveViewerContents();
}
});
assertEquals(newText, ((EditableTestElement)testNode.getRight()).getContentsAsString());
}
public void testCopyEmptyRightToLeftAndModify() throws Exception {
DiffNode parentNode = new DiffNode(new ParentTestElement(), new ParentTestElement());
DiffNode testNode = new DiffNode(parentNode, Differencer.ADDITION, null, null, new EditableTestElement("hi there".getBytes()));
final String newText = "New text";
runInDialog(testNode, new Runnable() {
public void run() {
viewer.copy(false /* rightToLeft */);
IDocument doc = getDocument(true /* left */);
doc.set(newText);
saveViewerContents();
}
});
assertEquals(newText, ((EditableTestElement)testNode.getLeft()).getContentsAsString());
}
public void testCopyEmptyLeftToRightAndModify() throws Exception {
DiffNode parentNode = new DiffNode(new ParentTestElement(), new ParentTestElement());
DiffNode testNode = new DiffNode(parentNode, Differencer.DELETION, null, new EditableTestElement("hi there".getBytes()), null);
final String newText = "New text";
runInDialog(testNode, new Runnable() {
public void run() {
viewer.copy(true /* leftToRight */);
IDocument doc = getDocument(false /* right */);
doc.set(newText);
saveViewerContents();
}
});
assertEquals(newText, ((EditableTestElement)testNode.getRight()).getContentsAsString());
}
public void testCompareFilter() throws Exception {
DiffNode parentNode = new DiffNode(new ParentTestElement(),
new ParentTestElement());
final String leftString = "HI there";
final String rightString = "hi there";
final EditableTestElement leftElement = new EditableTestElement(
leftString.getBytes());
final EditableTestElement rightElement = new EditableTestElement(
rightString.getBytes());
DiffNode testNode = new DiffNode(parentNode, Differencer.CHANGE, null,
leftElement, rightElement);
final CompareConfiguration cc = new CompareConfiguration();
runInDialog(testNode, new Runnable() {
public void run() {
Object adapter = viewer
.getAdapter(IMergeViewerTestAdapter.class);
if (adapter instanceof IMergeViewerTestAdapter) {
IMergeViewerTestAdapter ta = (IMergeViewerTestAdapter) adapter;
assertEquals(ta.getChangesCount(), 1);
Map filters = new HashMap();
filters.put("filter.id", new ICompareFilter() {
public void setInput(Object input, Object ancestor,
Object left, Object right) {
assertTrue(leftElement == left);
assertTrue(rightElement == right);
}
public IRegion[] getFilteredRegions(
HashMap lineComparison) {
Object thisLine = lineComparison.get(THIS_LINE);
Object thisContributor = lineComparison
.get(THIS_CONTRIBUTOR);
Object otherLine = lineComparison.get(OTHER_LINE);
Object otherContributor = lineComparison
.get(OTHER_CONTRIBUTOR);
if (thisContributor.equals(new Character('L'))) {
assertEquals(thisLine, leftString);
assertEquals(otherContributor, new Character(
'R'));
assertEquals(otherLine, rightString);
} else {
assertEquals(thisContributor,
new Character('R'));
assertEquals(thisLine, rightString);
assertEquals(otherContributor, new Character(
'L'));
assertEquals(otherLine, leftString);
}
if (thisContributor.equals(new Character('L')))
return new IRegion[] { new Region(0, 1),
new Region(1, 1) };
return new IRegion[] { new Region(0, 2) };
}
public boolean isEnabledInitially() {
return false;
}
public boolean canCacheFilteredRegions() {
return true;
}
});
cc.setProperty(
ChangeCompareFilterPropertyAction.COMPARE_FILTERS,
filters);
assertEquals(ta.getChangesCount(), 0);
cc.setProperty(
ChangeCompareFilterPropertyAction.COMPARE_FILTERS,
null);
assertEquals(ta.getChangesCount(), 1);
}
}
}, cc);
}
public void testDocumentAsTypedElement() throws Exception {
class DocumentAsTypedElement extends Document implements ITypedElement {
public String getName() {
return "file";
}
public Image getImage() {
return null;
}
public String getType() {
return ITypedElement.UNKNOWN_TYPE;
}
}
DiffNode parentNode = new DiffNode(new ParentTestElement(), new ParentTestElement());
DocumentAsTypedElement leftDoc = new DocumentAsTypedElement();
DocumentAsTypedElement rightDoc = new DocumentAsTypedElement();
DiffNode testNode = new DiffNode(parentNode, Differencer.DELETION, null, leftDoc, rightDoc);
runInDialogWithPartioner(testNode, new Runnable() {
public void run() {
//Not needed
}
}, new CompareConfiguration());
assertNotNull(leftDoc.getDocumentPartitioner());
assertNotNull(rightDoc.getDocumentPartitioner());
}
private void runInDialogWithPartioner(Object input, Runnable runnable, final CompareConfiguration cc) throws Exception {
Shell shell = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell();
Dialog dialog = new Dialog(shell) {
protected Control createDialogArea(Composite parent) {
Composite composite = (Composite) super.createDialogArea(parent);
viewer = new TestMergeViewerWithPartitioner(composite, cc);
return composite;
}
};
dialog.setBlockOnOpen(false);
dialog.open();
viewer.setInput(input);
try {
runnable.run();
} catch (WrappedException e) {
e.throwException();
}
dialog.close();
viewer = null;
}
//This viewer is used to provide a dummy partitioner
public static class TestMergeViewerWithPartitioner extends TestMergeViewer {
public class DummyPartitioner implements IDocumentPartitioner {
public void connect(IDocument document) {
//Nothing to do
}
public void disconnect() {
//Nothing to do
}
public void documentAboutToBeChanged(DocumentEvent event) {
//Nothing to do
}
public boolean documentChanged(DocumentEvent event) {
return false;
}
public String[] getLegalContentTypes() {
return null;
}
public String getContentType(int offset) {
return null;
}
public ITypedRegion[] computePartitioning(int offset, int length) {
return null;
}
public ITypedRegion getPartition(int offset) {
return null;
}
}
public TestMergeViewerWithPartitioner(Composite parent) {
super(parent, new CompareConfiguration());
}
public TestMergeViewerWithPartitioner(Composite parent, CompareConfiguration cc) {
super(parent, cc);
}
public void copy(boolean leftToRight) {
super.copy(leftToRight);
}
protected IDocumentPartitioner getDocumentPartitioner() {
return new DummyPartitioner();
}
}
}