/******************************************************************************* * Copyright (c) 2000, 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.jdt.core.tests.model; import java.util.ArrayList; import org.eclipse.core.resources.IFile; import org.eclipse.core.resources.IProject; import org.eclipse.core.resources.IResource; import org.eclipse.core.runtime.CoreException; import org.eclipse.jdt.core.*; import junit.framework.Test; @SuppressWarnings({"rawtypes", "unchecked"}) public class BufferTests extends ModifyingResourceTests implements IBufferChangedListener { protected ArrayList events = null; public BufferTests(String name) { super(name); } /** * Cache the event */ public void bufferChanged(BufferChangedEvent bufferChangedEvent) { this.events.add(bufferChangedEvent); } protected IBuffer createBuffer(String path, String content) throws CoreException { waitUntilIndexesReady(); // ensure that the indexer is not reading the file this.createFile(path, content); ICompilationUnit cu = this.getCompilationUnit(path); IBuffer buffer = cu.getBuffer(); buffer.addBufferChangedListener(this); this.events = new ArrayList(); return buffer; } protected void deleteBuffer(IBuffer buffer) throws CoreException { buffer.removeBufferChangedListener(this); IResource resource = buffer.getUnderlyingResource(); if (resource != null) { deleteResource(resource); } } /** * @see AbstractJavaModelTests#setUpSuite() */ public void setUpSuite() throws Exception { super.setUpSuite(); try { this.createJavaProject("P", new String[] {""}, ""); this.createFolder("P/x/y"); } catch (CoreException e) { e.printStackTrace(); } } /** * @see AbstractJavaModelTests#tearDownSuite() */ public void tearDownSuite() throws Exception { super.tearDownSuite(); this.deleteProject("P"); } public static Test suite() { return buildModelTestSuite(BufferTests.class); } /** * Tests appending to a buffer. */ public void testAppend() throws CoreException { IBuffer buffer = createBuffer( "P/x/y/A.java", "package x.y;\n" + "public class A {\n" + "}" ); try { int oldLength= buffer.getLength(); buffer.append("\nclass B {}"); assertBufferEvent(oldLength, 0, "\nclass B {}"); assertSourceEquals( "unexpected buffer contents", "package x.y;\n" + "public class A {\n" + "}\n" + "class B {}", buffer.getContents() ); assertTrue("should have unsaved changes", buffer.hasUnsavedChanges()); } finally { deleteBuffer(buffer); } } /** * Tests appending to a read-only buffer. */ public void testAppendReadOnly() throws CoreException { IBuffer buffer = null; try { createJavaProject("P1", new String[] {}, new String[] {"JCL_LIB,JCL_SRC,JCL_SRCROOT"}, ""); IClassFile classFile = getClassFile("P1", getExternalJCLPathString(), "java.lang", "String.class"); buffer = classFile.getBuffer(); buffer.addBufferChangedListener(this); this.events = new ArrayList(); buffer.append("\nclass B {}"); assertTrue("unexpected event", this.events.isEmpty()); assertSourceEquals( "unexpected buffer contents", "package java.lang;\n" + "\n" + "public class String {\n" + "}\n", buffer.getContents() ); assertTrue("should not have unsaved changes", !buffer.hasUnsavedChanges()); } finally { if (buffer != null) { buffer.removeBufferChangedListener(this); } deleteProject("P1"); } } public void testClose() throws CoreException { IBuffer buffer = createBuffer( "P/x/y/A.java", "package x.y;\n" + "public class A {\n" + "}" ); try { buffer.close(); assertBufferEvent(0, 0, null); } finally { deleteBuffer(buffer); } } /** * Tests getting the underlying resource of a buffer. */ public void testGetUnderlyingResource() throws CoreException { IBuffer buffer = createBuffer( "P/x/y/A.java", "package x.y;\n" + "public class A {\n" + "}" ); ICompilationUnit copy = null; try { IFile file = getFile("P/x/y/A.java"); assertEquals("Unexpected underlying resource", file, buffer.getUnderlyingResource()); copy = this.getCompilationUnit("P/x/y/A.java").getWorkingCopy(null); assertEquals("Unexpected underlying resource 2", file, copy.getBuffer().getUnderlyingResource()); } finally { deleteBuffer(buffer); if (copy != null) { copy.discardWorkingCopy(); } } } /** * Tests deleting text at the beginning of a buffer. */ public void testDeleteBeginning() throws CoreException { IBuffer buffer = createBuffer( "P/x/y/A.java", "package x.y;\n" + "public class A {\n" + "}" ); try { buffer.replace(0, 13, ""); assertBufferEvent(0, 13, null); assertSourceEquals( "unexpected buffer contents", "public class A {\n" + "}", buffer.getContents() ); assertTrue("should have unsaved changes", buffer.hasUnsavedChanges()); } finally { deleteBuffer(buffer); } } /** * Tests deleting text in the middle of a buffer. */ public void testDeleteMiddle() throws CoreException { IBuffer buffer = createBuffer( "P/x/y/A.java", "package x.y;\n" + "public class A {\n" + "}" ); try { // delete "public " buffer.replace(13, 7, ""); assertBufferEvent(13, 7, null); assertSourceEquals( "unexpected buffer contents", "package x.y;\n" + "class A {\n" + "}", buffer.getContents() ); assertTrue("should have unsaved changes", buffer.hasUnsavedChanges()); } finally { deleteBuffer(buffer); } } /** * Tests deleting text at the end of a buffer. */ public void testDeleteEnd() throws CoreException { IBuffer buffer = createBuffer( "P/x/y/A.java", "package x.y;\n" + "public class A {\n" + "}" ); try { // delete "public class A {\n}" buffer.replace(13, 18, ""); assertBufferEvent(13, 18, null); assertSourceEquals( "unexpected buffer contents", "package x.y;\n", buffer.getContents() ); assertTrue("should have unsaved changes", buffer.hasUnsavedChanges()); } finally { deleteBuffer(buffer); } } /** * Tests the buffer char retrieval via source position */ public void testGetChar() throws CoreException { IBuffer buffer = createBuffer( "P/x/y/A.java", "package x.y;\n" + "public class A {\n" + "}" ); try { assertEquals("Unexpected char at position 17", 'i', buffer.getChar(17)); } finally { deleteBuffer(buffer); } } /** * Tests the buffer char retrieval via source position doesn't throw an exception if the buffer is closed. * (regression test for bug 46040 NPE in Eclipse console) */ public void testGetChar2() throws CoreException { IBuffer buffer = createBuffer( "P/x/y/A.java", "package x.y;\n" + "public class A {\n" + "}" ); buffer.close(); try { assertEquals("Unexpected char at position 17", Character.MIN_VALUE, buffer.getChar(17)); } finally { deleteBuffer(buffer); } } /** * Tests the buffer getLength() */ public void testGetLength() throws CoreException { IBuffer buffer = createBuffer( "P/x/y/A.java", "package x.y;\n" + "public class A {\n" + "}" ); try { assertEquals("Unexpected length", 31, buffer.getLength()); } finally { deleteBuffer(buffer); } } /** * Tests the buffer text retrieval via source position */ public void testGetText() throws CoreException { IBuffer buffer = createBuffer( "P/x/y/A.java", "package x.y;\n" + "public class A {\n" + "}" ); try { assertSourceEquals("Unexpected text (1)", "p", buffer.getText(0, 1)); assertSourceEquals("Unexpected text (2)", "public", buffer.getText(13, 6)); assertSourceEquals("Unexpected text (3)", "", buffer.getText(10, 0)); } finally { deleteBuffer(buffer); } } /** * Tests inserting text at the beginning of a buffer. */ public void testInsertBeginning() throws CoreException { IBuffer buffer = createBuffer( "P/x/y/A.java", "package x.y;\n" + "public class A {\n" + "}" ); try { buffer.replace(0, 0, "/* copyright mycompany */\n"); assertBufferEvent(0, 0, "/* copyright mycompany */\n"); assertSourceEquals( "unexpected buffer contents", "/* copyright mycompany */\n" + "package x.y;\n" + "public class A {\n" + "}", buffer.getContents() ); assertTrue("should have unsaved changes", buffer.hasUnsavedChanges()); } finally { deleteBuffer(buffer); } } /** * Tests replacing text at the beginning of a buffer. */ public void testReplaceBeginning() throws CoreException { IBuffer buffer = createBuffer( "P/x/y/A.java", "package x.y;\n" + "public class A {\n" + "}" ); try { buffer.replace(0, 13, "package other;\n"); assertBufferEvent(0, 13, "package other;\n"); assertSourceEquals( "unexpected buffer contents", "package other;\n" + "public class A {\n" + "}", buffer.getContents() ); assertTrue("should have unsaved changes", buffer.hasUnsavedChanges()); } finally { deleteBuffer(buffer); } } /** * Tests replacing text in the middle of a buffer. */ public void testReplaceMiddle() throws CoreException { IBuffer buffer = createBuffer( "P/x/y/A.java", "package x.y;\n" + "public class A {\n" + "}" ); try { // replace "public class A" after the \n of package statement buffer.replace(13, 14, "public class B"); assertBufferEvent(13, 14, "public class B"); assertSourceEquals( "unexpected buffer contents", "package x.y;\n" + "public class B {\n" + "}", buffer.getContents() ); assertTrue("should have unsaved changes", buffer.hasUnsavedChanges()); } finally { deleteBuffer(buffer); } } /** * Tests replacing text at the end of a buffer. */ public void testReplaceEnd() throws CoreException { IBuffer buffer = createBuffer( "P/x/y/A.java", "package x.y;\n" + "public class A {\n" + "}" ); try { // replace "}" at the end of cu with "}\n" int end = buffer.getLength(); buffer.replace(end-1, 1, "}\n"); assertBufferEvent(end-1, 1, "}\n"); assertSourceEquals( "unexpected buffer contents", "package x.y;\n" + "public class A {\n" + "}\n", buffer.getContents() ); assertTrue("should have unsaved changes", buffer.hasUnsavedChanges()); } finally { deleteBuffer(buffer); } } /* * Ensure that saving a buffer on a non-yet existing resource and using the UTF-8 encoding doesn't throw an exception * (regression test for https://bugs.eclipse.org/bugs/show_bug.cgi?id=234307 ) */ public void testSaveNonExistingUTF8() throws Exception { IBuffer buffer = (new WorkingCopyOwner() {}).createBuffer(getCompilationUnit("/P/X234307.java")); buffer.setContents( "public class X234307 {\n" + "}" ); IProject project = getProject("P"); String defaultCharset = project.getDefaultCharset(); try { project.setDefaultCharset("UTF-8", null); String newContents = "public interface X234307 {\n" + "}"; buffer.setContents(newContents); buffer.save(null, false/*don't force*/); char[] contents = org.eclipse.jdt.internal.compiler.util.Util.getFileCharContent(getFile("/P/X234307.java").getLocation().toFile(), null); assertSourceEquals("Unexpected source", newContents, new String(contents)); } finally { deleteBuffer(buffer); // this deletes the file as well project.setDefaultCharset(defaultCharset, null); } } /** * Tests inserting text in the middle of a buffer. */ public void testInsertMiddle() throws CoreException { IBuffer buffer = createBuffer( "P/x/y/A.java", "package x.y;\n" + "public class A {\n" + "}" ); try { // insert after the \n of package statement buffer.replace(13, 0, "/* class comment */\n"); assertBufferEvent(13, 0, "/* class comment */\n"); assertSourceEquals( "unexpected buffer contents", "package x.y;\n" + "/* class comment */\n" + "public class A {\n" + "}", buffer.getContents() ); assertTrue("should have unsaved changes", buffer.hasUnsavedChanges()); } finally { deleteBuffer(buffer); } } /** * Tests inserting text at the end of a buffer. */ public void testInsertEnd() throws CoreException { IBuffer buffer = createBuffer( "P/x/y/A.java", "package x.y;\n" + "public class A {\n" + "}" ); try { // insert after the \n of package statement int end = buffer.getLength(); buffer.replace(end, 0, "\nclass B {}"); assertBufferEvent(end, 0, "\nclass B {}"); assertSourceEquals( "unexpected buffer contents", "package x.y;\n" + "public class A {\n" + "}\n" + "class B {}", buffer.getContents() ); assertTrue("should have unsaved changes", buffer.hasUnsavedChanges()); } finally { deleteBuffer(buffer); } } /** * Tests replacing text within a buffer using a create import * (regression test for PR #1G7A0WI). */ public void testCreateImport() throws CoreException { IFile file = this.createFile( "P/x/y/A.java", "package x.y;\n" + "public class A {\n" + "}" ); ICompilationUnit copy = null; IBuffer buffer = null; try { copy = this.getCompilationUnit("P/x/y/A.java").getWorkingCopy(null); buffer = copy.getBuffer(); buffer.addBufferChangedListener(this); this.events = new ArrayList(); copy.createImport("java.io.IOException", null, null); assertBufferEvents( "(12, 0) import java.io.IOException;\n" + "(12, 0) \n" + "\n" ); // A.java has a \n line delimiter } finally { if (buffer != null) { buffer.removeBufferChangedListener(this); } if (copy != null) { copy.discardWorkingCopy(); } deleteResource(file); } } /** * Verify the buffer changed event. * The given text must contain '\n' line separators. */ protected void assertBufferEvent(int offset, int length, String text) { assertTrue("events should not be null", this.events != null); assertTrue("events should not be empty", !this.events.isEmpty()); BufferChangedEvent event = (BufferChangedEvent) this.events.get(0); assertEquals("unexpected offset", offset, event.getOffset()); assertEquals("unexpected length", length, event.getLength()); if (text == null) { assertTrue("text should be null", event.getText() == null); } else { assertSourceEquals("unexpected text", text, event.getText()); } } protected void assertBufferEvents(String expected) { StringBuffer buffer = new StringBuffer(); if (this.events == null) buffer.append("<null>"); else { for (int i = 0, length = this.events.size(); i < length; i++) { BufferChangedEvent event = (BufferChangedEvent) this.events.get(i); buffer.append('('); buffer.append(event.getOffset()); buffer.append(", "); buffer.append(event.getLength()); buffer.append(") "); buffer.append(event.getText()); if (i < length-1) buffer.append("\n"); } } assertSourceEquals("Unexpected buffer events", expected, buffer.toString()); } }