/*******************************************************************************
* Copyright (c) 2010 Red Hat Inc. 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
*******************************************************************************/
package org.eclipse.linuxtools.changelog.parsers.tests;
import static org.eclipse.linuxtools.changelog.tests.helpers.EditorHelper.closeEditor;
import static org.eclipse.linuxtools.changelog.tests.helpers.EditorHelper.getContent;
import static org.eclipse.linuxtools.changelog.tests.helpers.EditorHelper.openEditor;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IStorage;
import org.eclipse.core.runtime.Path;
import org.eclipse.jface.text.IDocument;
import org.eclipse.jface.text.TextSelection;
import org.eclipse.linuxtools.changelog.core.IParserChangeLogContrib;
import org.eclipse.linuxtools.changelog.tests.fixtures.CStringStorage;
import org.eclipse.linuxtools.changelog.tests.fixtures.CStringStorageInput;
import org.eclipse.linuxtools.changelog.tests.fixtures.ChangeLogTestProject;
import org.eclipse.linuxtools.internal.changelog.core.ChangeLogExtensionManager;
import org.eclipse.ui.IEditorPart;
import org.eclipse.ui.IStorageEditorInput;
import org.eclipse.ui.texteditor.AbstractTextEditor;
import org.eclipse.ui.texteditor.IDocumentProvider;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
/**
* CParser test suite.
*
*/
public class CParserTest {
// A unique string to mark the place of current selection in source code
private static final String OFFSET_MARKER = "<# selection #>";
// The parser under test
private IParserChangeLogContrib cParser;
// A faked project
private ChangeLogTestProject project;
// The IEditorPart corresponding to the ChangeLog file
private IEditorPart cppSourceEditorPart = null;
@Before
public void setUp() throws Exception {
cParser = ChangeLogExtensionManager.getExtensionManager().getParserContributor("CEditor");
project = new ChangeLogTestProject("c-parser-test-project");
}
@After
public void tearDown() throws Exception {
// Tests in this class use javaSourceEditorPart. In order to avoid
// spill-over from previous runs, truncate content (i.e. manually set
// content to the empty string).
if (cppSourceEditorPart != null) {
AbstractTextEditor castEditor = (AbstractTextEditor) cppSourceEditorPart;
IDocumentProvider iDocProvider = castEditor.getDocumentProvider();
IDocument changelogContentDoc = iDocProvider.getDocument(castEditor.getEditorInput());
changelogContentDoc.set("");
cppSourceEditorPart.doSave(null);
// Also close open editor in order for default content to work.
// I.e. avoid spill over from previous test runs
closeEditor(cppSourceEditorPart);
}
project.getTestProject().delete(true, true, null); // dispose
}
/**
* Given an IEditorPart we should be able to retrieve the currently
* function active C function inside a C source file.
*
* @throws Exception
*/
@Test
public void canParseCurrentFunctionFromCFile() throws Exception {
// make testproject a C project
project.addCNature();
final String expectedFunctionName = "doSomething";
final String cSourceCode = "static int " + expectedFunctionName + "(char *test)\n"
+ "{\n"
+ "int index = 0;\n"
+ "// " + OFFSET_MARKER + "\n"
+ "return 0;\n"
+ "}\n";
assertNull(project.getTestProject().findMember( new Path(
"/src/some_c_file.c")));
// Add some_c_file.c to project
InputStream newFileInputStream = new ByteArrayInputStream(
cSourceCode.getBytes());
IFile cSourceFile = project.addFileToProject(
"/src",
"some_c_file.c", newFileInputStream);
assertNotNull(project.getTestProject().findMember( new Path(
"/src/some_c_file.c")));
// Open a source file and get the IEditorPart
cppSourceEditorPart = openEditor(cSourceFile);
assertEquals(cSourceCode, getContent(cppSourceEditorPart));
// make sure we have the proper editor type
assertTrue( cppSourceEditorPart instanceof AbstractTextEditor );
// Select the snippet we want
int selectionStart = cSourceCode.indexOf(OFFSET_MARKER);
assertTrue(selectionStart >= 0);
int selectionLength = OFFSET_MARKER.length();
AbstractTextEditor cEditor = (AbstractTextEditor) cppSourceEditorPart;
cEditor.getSelectionProvider().setSelection(
new TextSelection(selectionStart, selectionLength));
final String actualFunctionName = cParser.parseCurrentFunction(cppSourceEditorPart);
assertEquals(expectedFunctionName, actualFunctionName);
}
/**
* Given an IEditorPart and not being inside any function within a C
* source file, no function should be determined.
*
* @throws Exception
*/
@Test
public void canDetermineThatInNoFunctionInCFile() throws Exception {
// make test project a C project
project.addCNature();
final String cSourceCode = "// Prototype " + OFFSET_MARKER + "\n"
+ "static int doSomething(char *test);\n\n"
+ "static int doSomething(char *test)\n"
+ "{\n"
+ "int index = 0;\n"
+ "return 0;\n"
+ "}\n";
assertNull(project.getTestProject().findMember( new Path(
"/src/some_c_file.c")));
// Add some_c_file.c to project
InputStream newFileInputStream = new ByteArrayInputStream(
cSourceCode.getBytes());
IFile cSourceFile = project.addFileToProject(
"/src",
"some_c_file.c", newFileInputStream);
assertNotNull(project.getTestProject().findMember( new Path(
"/src/some_c_file.c")));
// Open a source file and get the IEditorPart
cppSourceEditorPart = openEditor(cSourceFile);
assertEquals(cSourceCode, getContent(cppSourceEditorPart));
// make sure we have the proper editor type
assertTrue( cppSourceEditorPart instanceof AbstractTextEditor );
// Select the snippet we want
int selectionStart = cSourceCode.indexOf(OFFSET_MARKER);
assertTrue(selectionStart >= 0);
int selectionLength = OFFSET_MARKER.length();
AbstractTextEditor cEditor = (AbstractTextEditor) cppSourceEditorPart;
cEditor.getSelectionProvider().setSelection(
new TextSelection(selectionStart, selectionLength));
final String actualFunctionName = cParser.parseCurrentFunction(cppSourceEditorPart);
assertEquals("" /* expect empty function name */, actualFunctionName);
}
/**
* Given an IEditorPart we should be able to retrieve the currently selected
* variable identifier inside a C++ file.
*
* @throws Exception
*/
@Test
public void canParseCurrentlySelectedVariableIdentifierInCppFile() throws Exception {
// make test project a C++ project
project.addCCNature();
final String expectedIdentifier = "myIdentifier";
final String className = "shape";
final String cppSourceCode = "class " + className + " {\n"
+ "int x;\n"
+ "int y;\n"
+ "private:\n"
+ "int color;\n"
+ "float " + expectedIdentifier + ";\n"
+ "void set_color(int color);\n"
+"}\n";
assertNull(project.getTestProject().findMember( new Path(
"/src/shape.h")));
// Add shape.h to project
InputStream newFileInputStream = new ByteArrayInputStream(
cppSourceCode.getBytes());
IFile cppSourceFile = project.addFileToProject(
"/src",
"shape.h", newFileInputStream);
assertNotNull(project.getTestProject().findMember( new Path(
"/src/shape.h")));
// Open a source file and get the IEditorPart
cppSourceEditorPart = openEditor(cppSourceFile);
// make sure editor content is correct
assertEquals(cppSourceCode, getContent(cppSourceEditorPart));
// make sure we have the proper editor type
assertTrue( cppSourceEditorPart instanceof AbstractTextEditor );
// Select the snippet we want
int selectionStart = cppSourceCode.indexOf(expectedIdentifier);
assertTrue(selectionStart >= 0);
// shouldn't need to mark whole length of identifier.
int selectionLength = expectedIdentifier.length() - 3;
AbstractTextEditor cppEditor = (AbstractTextEditor) cppSourceEditorPart;
cppEditor.getSelectionProvider().setSelection(
new TextSelection(selectionStart, selectionLength));
final String actualIdentifier = cParser.parseCurrentFunction(cppSourceEditorPart);
assertEquals(className + "." + expectedIdentifier, actualIdentifier);
}
/**
* Given an IEditorPart and not selected any variable identifier in a class, we should
* get the class name as selected function name only.
*
* @throws Exception
*/
@Test
public void canParseClassNameIfNoVariableIdentifierSelectedInCppFile() throws Exception {
// make test project a C++ project
project.addCCNature();
final String className = "shape";
final String cppSourceCode = "class " + className + " {\n"
+ "int x;\n"
+ "int y;\n"
+ "// " + OFFSET_MARKER + "\n"
+ "private:\n"
+ "int color;\n"
+ "void set_color(int color);\n"
+"}\n";
assertNull(project.getTestProject().findMember( new Path(
"/src/shape.h")));
// Add shape.h to project
InputStream newFileInputStream = new ByteArrayInputStream(
cppSourceCode.getBytes());
IFile cppSourceFile = project.addFileToProject(
"/src",
"shape.h", newFileInputStream);
assertNotNull(project.getTestProject().findMember( new Path(
"/src/shape.h")));
// Open a source file and get the IEditorPart
cppSourceEditorPart = openEditor(cppSourceFile);
// make sure editor content is correct
assertEquals(cppSourceCode, getContent(cppSourceEditorPart));
// make sure we have the proper editor type
assertTrue( cppSourceEditorPart instanceof AbstractTextEditor );
// Select the snippet we want
int selectionStart = cppSourceCode.indexOf(OFFSET_MARKER);
assertTrue(selectionStart >= 0);
int selectionLength = OFFSET_MARKER.length();
AbstractTextEditor cppEditor = (AbstractTextEditor) cppSourceEditorPart;
cppEditor.getSelectionProvider().setSelection(
new TextSelection(selectionStart, selectionLength));
final String actualFunction = cParser.parseCurrentFunction(cppSourceEditorPart);
assertEquals(className, actualFunction);
}
/**
* Given an IEditorPart and current selection is inside a method,
* CParser should be able to figure that out.
*
* @throws Exception
*/
@Test
public void canParseCurrentMethodNameInCppFile() throws Exception {
// make test project a C++ project
project.addCCNature();
final String expectedMethodName = "circle::area";
final String cppSourceCode = "#include \"circle.h\"\n"
+ "#include <math.h>\n"
+ "float " + expectedMethodName + "() {\n"
+ "// " + OFFSET_MARKER + "\n"
+ "return this->radius * this-> radius * M_PI\n"
+ "}\n";
assertNull(project.getTestProject().findMember( new Path(
"/src/circle.cpp")));
// Add shape.h to project
InputStream newFileInputStream = new ByteArrayInputStream(
cppSourceCode.getBytes());
IFile cppSourceFile = project.addFileToProject(
"/src",
"circle.cpp", newFileInputStream);
assertNotNull(project.getTestProject().findMember( new Path(
"/src/circle.cpp")));
// Open a source file and get the IEditorPart
cppSourceEditorPart = openEditor(cppSourceFile);
// make sure editor content is correct
assertEquals(cppSourceCode, getContent(cppSourceEditorPart));
// make sure we have the proper editor type
assertTrue( cppSourceEditorPart instanceof AbstractTextEditor );
// Select the snippet we want
int selectionStart = cppSourceCode.indexOf(OFFSET_MARKER);
assertTrue(selectionStart >= 0);
int selectionLength = OFFSET_MARKER.length();
AbstractTextEditor cppEditor = (AbstractTextEditor) cppSourceEditorPart;
cppEditor.getSelectionProvider().setSelection(
new TextSelection(selectionStart, selectionLength));
final String actualMethodName = cParser.parseCurrentFunction(cppSourceEditorPart);
assertEquals(expectedMethodName, actualMethodName);
}
/**
* Given an IEditorPart and current selection is inside a method,
* CParser should be able to figure that out.
*
* @throws Exception
*/
@Test
public void canParseCurrentFunctionInCppFile() throws Exception {
// make test project a C++ project
project.addCCNature();
final String expectedFunction = "main";
final String cppSourceCode = "#include \"circle.h\"\n"
+ "#include <math.h>\n"
+ "float circle::area() {\n"
+ "return this->radius * this-> radius * M_PI\n"
+ "}\n"
+ "int " + expectedFunction + "() {\n"
+ "int some_var = 0;\n"
+ "// " + OFFSET_MARKER + "\n"
+ "return 0;\n"
+ "}\n";
assertNull(project.getTestProject().findMember( new Path(
"/src/circle.cpp")));
// Add shape.h to project
InputStream newFileInputStream = new ByteArrayInputStream(
cppSourceCode.getBytes());
IFile cppSourceFile = project.addFileToProject(
"/src",
"circle.cpp", newFileInputStream);
assertNotNull(project.getTestProject().findMember( new Path(
"/src/circle.cpp")));
// Open a source file and get the IEditorPart
cppSourceEditorPart = openEditor(cppSourceFile);
// make sure editor content is correct
assertEquals(cppSourceCode, getContent(cppSourceEditorPart));
// make sure we have the proper editor type
assertTrue( cppSourceEditorPart instanceof AbstractTextEditor );
// Select the snippet we want
int selectionStart = cppSourceCode.indexOf(OFFSET_MARKER);
assertTrue(selectionStart >= 0);
int selectionLength = OFFSET_MARKER.length();
AbstractTextEditor cppEditor = (AbstractTextEditor) cppSourceEditorPart;
cppEditor.getSelectionProvider().setSelection(
new TextSelection(selectionStart, selectionLength));
final String actualFunction = cParser.parseCurrentFunction(cppSourceEditorPart);
assertEquals(expectedFunction, actualFunction);
}
/**
* Given an IStorageEditorInput we should be able to retrieve the currently
* active C function.
*
* @throws Exception
*/
@Test
public void canParseCurrentFunctionFromCStringInIStorageEditorInput() throws Exception {
final String expectedFunctionName = "doSomething";
final String cSourceCode = "static int " + expectedFunctionName + "(char *test)\n"
+ "{\n"
+ "int index = 0;\n"
+ "// " + OFFSET_MARKER + "\n"
+ "return 0;\n"
+ "}\n";
// prepare IStorageEditorInput
IStorage cStringStorage = new CStringStorage(cSourceCode);
IStorageEditorInput cStringStorageEditorInput = new CStringStorageInput(cStringStorage);
// Figure out the desired offset
int selectOffset = cSourceCode.indexOf(OFFSET_MARKER);
assertTrue(selectOffset >= 0);
final String actualFunctionName = cParser.parseCurrentFunction(cStringStorageEditorInput, selectOffset);
assertEquals(expectedFunctionName, actualFunctionName);
}
}