GT-3035 - Restore Integration Tests - more missing test files; updated

test environment to install a default tool
This commit is contained in:
dragonmacher 2019-08-15 14:49:07 -04:00
parent 4dc8e77172
commit 554bce2407
26 changed files with 4989 additions and 40 deletions

View File

@ -23,6 +23,7 @@ import javax.swing.*;
import docking.ActionContext;
import docking.WindowPosition;
import docking.options.editor.ButtonPanelFactory;
import docking.util.image.ToolIconURL;
import docking.widgets.OptionDialog;
import docking.widgets.label.*;
import ghidra.app.context.ListingActionContext;
@ -32,7 +33,6 @@ import ghidra.app.util.HelpTopics;
import ghidra.app.util.viewer.format.FieldHeaderComp;
import ghidra.app.util.viewer.format.FieldHeaderLocation;
import ghidra.framework.plugintool.ComponentProviderAdapter;
import ghidra.framework.project.tool.ToolIconURL;
import ghidra.program.util.ProgramLocation;
import ghidra.util.HelpLocation;
import ghidra.util.layout.VerticalLayout;

View File

@ -22,8 +22,6 @@ import java.util.*;
import java.util.concurrent.atomic.AtomicReference;
import java.util.stream.Collectors;
import javax.swing.JFrame;
import org.jdom.Element;
import docking.ComponentProvider;
@ -332,6 +330,7 @@ public class TestEnv {
* <P>This method is considered sub-standard and users should prefer instead
* {@link #launchDefaultTool()} or {@link #launchDefaultTool(Program)}.
*
* @param p the program
* @return the newly shown tool
*/
public PluginTool showTool(Program p) {
@ -357,7 +356,7 @@ public class TestEnv {
/**
* Waits for the first window of the given class. This method is the same as
* {@link #waitForDialogComponent(Window, Class, int)} with the exception that the parent
* {@link #waitForDialogComponent(Class, int)} with the exception that the parent
* window is assumed to be this instance's tool frame.
*
* @param ghidraClass The class of the dialog the user desires
@ -369,8 +368,7 @@ public class TestEnv {
@Deprecated
public <T extends DialogComponentProvider> T waitForDialogComponent(Class<T> ghidraClass,
int maxTimeMS) {
JFrame frame = lazyTool().getToolFrame();
return AbstractDockingTest.waitForDialogComponent(frame, ghidraClass, maxTimeMS);
return AbstractDockingTest.waitForDialogComponent(ghidraClass);
}
private static GhidraProject createGhidraTestProject(String projectName) throws IOException {
@ -381,7 +379,20 @@ public class TestEnv {
deleteSavedFrontEndTool();
String projectDirectoryName = AbstractGTest.getTestDirectoryPath();
return GhidraProject.createProject(projectDirectoryName, projectName, true);
GhidraProject gp = GhidraProject.createProject(projectDirectoryName, projectName, true);
//
// Unusual Code Alert: The default tool is not always found in the testing environment,
// depending upon where the test lives. This code maps the test tool to that tool name
// so that tests will have the default tool as needed.
//
Project project = gp.getProject();
ToolChest toolChest = project.getLocalToolChest();
ToolTemplate template = getToolTemplate(AbstractGenericTest.DEFAULT_TEST_TOOL_NAME);
template.setName(AbstractGenericTest.DEFAULT_TOOL_NAME);
AbstractGenericTest.runSwing(() -> toolChest.replaceToolTemplate(template));
return gp;
}
private static void deleteOldTestTools() {
@ -466,6 +477,7 @@ public class TestEnv {
/**
* This method differs from {@link #launchDefaultTool()} in that this method does not set the
* <tt>tool</tt> variable in of this <tt>TestEnv</tt> instance.
* @return the tool
*/
public PluginTool createDefaultTool() {
PluginTool newTool = launchDefaultToolByName(AbstractGenericTest.DEFAULT_TEST_TOOL_NAME);
@ -497,15 +509,14 @@ public class TestEnv {
return tool;
}
protected PluginTool launchDefaultToolByName(final String toolName) {
AtomicReference<PluginTool> ref = new AtomicReference<>();
AbstractGenericTest.runSwing(() -> {
protected PluginTool launchDefaultToolByName(String toolName) {
ToolTemplate toolTemplate =
ToolUtils.readToolTemplate("defaultTools/" + toolName + ".tool");
return AbstractGenericTest.runSwing(() -> {
ToolTemplate toolTemplate = getToolTemplate(toolName);
if (toolTemplate == null) {
Msg.debug(this, "Unable to find tool: " + toolName);
return;
return null;
}
boolean wasErrorGUIEnabled = AbstractDockingTest.isUseErrorGUI();
@ -515,11 +526,23 @@ public class TestEnv {
Project project = frontEndToolInstance.getProject();
ToolManager toolManager = project.getToolManager();
Workspace workspace = toolManager.getActiveWorkspace();
ref.set((PluginTool) workspace.runTool(toolTemplate));
AbstractDockingTest.setErrorGUIEnabled(wasErrorGUIEnabled);
return (PluginTool) workspace.runTool(toolTemplate);
});
}
private static ToolTemplate getToolTemplate(String toolName) {
return AbstractGenericTest.runSwing(() -> {
ToolTemplate toolTemplate =
ToolUtils.readToolTemplate("defaultTools/" + toolName + ".tool");
if (toolTemplate == null) {
Msg.debug(TestEnv.class, "Unable to find tool: " + toolName);
return null;
}
return toolTemplate;
});
return ref.get();
}
public ScriptTaskListener runScript(File script) throws PluginException {
@ -550,6 +573,7 @@ public class TestEnv {
/**
* Returns GhidraProject associated with this environment
* @return the project
*/
public GhidraProject getGhidraProject() {
return gp;
@ -559,6 +583,7 @@ public class TestEnv {
* A convenience method to close and then reopen the default project created by this TestEnv
* instance. This will not delete the project between opening and closing and will restore
* the project to its previous state.
* @throws IOException if any exception occurs while saving and reopening
*/
public void closeAndReopenProject() throws IOException {
gp.setDeleteOnClose(false);
@ -579,9 +604,6 @@ public class TestEnv {
return gp.getProjectManager();
}
/**
* Returns Project associated with this environment
*/
public Project getProject() {
return gp.getProject();
}
@ -646,6 +668,8 @@ public class TestEnv {
* the only reason to use this method vice openProgram().
*
* @param programName the name of the program zip file without the ".gzf" extension.
* @return the restored domain file
* @throws FileNotFoundException if the program file cannot be found
*/
public DomainFile restoreProgram(String programName) throws FileNotFoundException {
DomainFile df = programManager.addProgramToProject(getProject(), programName);
@ -674,12 +698,12 @@ public class TestEnv {
* @param relativePathName This should be a pathname relative to the "test_resources/testdata"
* director or relative to the "typeinfo" directory. The name should
* include the ".gdt" suffix.
* @param domainFolder the folder in the test project where the archive should be created.
* @param monitor monitor for canceling this restore.
* @param domainFolder the folder in the test project where the archive should be created
* @return the domain file that was created in the project
* @throws Exception if an exception occurs
*/
public DomainFile restoreDataTypeArchive(String relativePathName, DomainFolder domainFolder)
throws InvalidNameException, IOException, VersionException {
throws Exception {
File gdtFile;
try {
@ -738,10 +762,10 @@ public class TestEnv {
* @param program program object
* @param replace if true any existing cached database with the same name will be replaced
* @param monitor task monitor
* @throws DuplicateNameException if already cached
* @throws Exception if already cached
*/
public void saveToCache(String progName, ProgramDB program, boolean replace,
TaskMonitor monitor) throws IOException, DuplicateNameException, CancelledException {
TaskMonitor monitor) throws Exception {
programManager.saveToCache(progName, program, replace, monitor);
}
@ -826,7 +850,8 @@ public class TestEnv {
* Launches a tool of the given name using the given domain file.
* <p>
* Note: the tool returned will have auto save disabled by default.
*
*
* @param toolName the tool's name
* @return the tool that is launched
*/
public PluginTool launchTool(String toolName) {

View File

@ -0,0 +1,604 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package docking.widgets.tree;
import static org.junit.Assert.assertEquals;
import java.util.ArrayList;
import java.util.List;
import javax.swing.Icon;
import javax.swing.JComponent;
import org.junit.*;
import docking.*;
import docking.test.AbstractDockingTest;
import docking.widgets.filter.*;
import ghidra.test.DummyTool;
import ghidra.util.StringUtilities;
public class GTreeFilterTest extends AbstractDockingTest {
private GTree gTree;
private FilterTextField filterField;
private GTreeRootNode root;
private DockingWindowManager winMgr;
@Before
public void setUp() throws Exception {
root = new TestRootNode();
gTree = new GTree(root);
filterField = (FilterTextField) gTree.getFilterField();
winMgr = new DockingWindowManager(new DummyTool(), null);
winMgr.addComponent(new TestTreeComponentProvider());
winMgr.setVisible(true);
waitForTree();
}
@After
public void tearDown() throws Exception {
winMgr.dispose();
}
@Test
public void testContains() {
setFilterOptions(TextFilterStrategy.CONTAINS, false);
// no filter text - make sure all 5 nodes are there
assertEquals(5, root.getChildCount());
setFilterText("ABC");
assertEquals("Expected 4 of nodes to be in filtered tree!", 4, root.getChildCount());
checkContainsNode("ABC");
checkContainsNode("XABC");
checkContainsNode("ABCX");
checkContainsNode("XABCX");
setFilterText("MMM");
assertEquals("Expected 4 of nodes to be in filtered tree!", 0, root.getChildCount());
setFilterText("");
assertEquals("Expected all 5 nodes to be back", 5, root.getChildCount());
}
@Test
public void testMultiWordContains() {
setFilterOptions(TextFilterStrategy.CONTAINS, false);
// no filter text - make sure all 5 nodes are there
assertEquals(5, root.getChildCount());
setFilterOptions(TextFilterStrategy.CONTAINS, false, true, ' ',
MultitermEvaluationMode.AND);
setFilterText("CX AB");
assertEquals(2, root.getChildCount());
setFilterOptions(TextFilterStrategy.CONTAINS, false, true, ' ', MultitermEvaluationMode.OR);
setFilterText("CX AB");
assertEquals(4, root.getChildCount());
checkContainsNode("ABCX");
checkContainsNode("XABCX");
setFilterText("");
assertEquals("Expected all 5 nodes to be back", 5, root.getChildCount());
}
@Test
public void testMultiWordContainsDelimiters() {
setFilterOptions(TextFilterStrategy.CONTAINS, false);
// no filter text - make sure all 5 nodes are there
assertEquals(5, root.getChildCount());
for (char delim : FilterOptions.VALID_MULTITERM_DELIMITERS.toCharArray()) {
setFilterOptions(TextFilterStrategy.CONTAINS, false, true, delim,
MultitermEvaluationMode.AND);
setFilterText("CX" + delim + "AB");
assertEquals(2, root.getChildCount());
setFilterOptions(TextFilterStrategy.CONTAINS, false, true, delim,
MultitermEvaluationMode.OR);
setFilterText("CX" + delim + "AB");
assertEquals(4, root.getChildCount());
checkContainsNode("ABCX");
checkContainsNode("XABCX");
setFilterText("");
assertEquals("Expected all 5 nodes to be back", 5, root.getChildCount());
}
}
@Test
public void testMultiWordContainsDelimitersWithLeadingSpaces() {
setFilterOptions(TextFilterStrategy.CONTAINS, false);
// no filter text - make sure all 5 nodes are there
assertEquals(5, root.getChildCount());
String delimPad = StringUtilities.pad("", ' ', 1);
for (char delim : FilterOptions.VALID_MULTITERM_DELIMITERS.toCharArray()) {
setFilterOptions(TextFilterStrategy.CONTAINS, false, true, delim,
MultitermEvaluationMode.AND);
String delimStr = delimPad + delim;
setFilterText("CX" + delimStr + "AB");
assertEquals(2, root.getChildCount());
setFilterOptions(TextFilterStrategy.CONTAINS, false, true, delim,
MultitermEvaluationMode.OR);
setFilterText("CX" + delimStr + "AB");
assertEquals(4, root.getChildCount());
checkContainsNode("ABCX");
checkContainsNode("XABCX");
setFilterText("");
assertEquals("Expected all 5 nodes to be back", 5, root.getChildCount());
}
}
@Test
public void testMultiWordContainsDelimitersWithTrailingSpaces() {
setFilterOptions(TextFilterStrategy.CONTAINS, false);
// no filter text - make sure all 5 nodes are there
assertEquals(5, root.getChildCount());
String delimPad = StringUtilities.pad("", ' ', 1);
for (char delim : FilterOptions.VALID_MULTITERM_DELIMITERS.toCharArray()) {
setFilterOptions(TextFilterStrategy.CONTAINS, false, true, delim,
MultitermEvaluationMode.AND);
String delimStr = delim + delimPad;
setFilterText("CX" + delimStr + "AB");
assertEquals(2, root.getChildCount());
setFilterOptions(TextFilterStrategy.CONTAINS, false, true, delim,
MultitermEvaluationMode.OR);
setFilterText("CX" + delimStr + "AB");
assertEquals(4, root.getChildCount());
checkContainsNode("ABCX");
checkContainsNode("XABCX");
setFilterText("");
assertEquals("Expected all 5 nodes to be back", 5, root.getChildCount());
}
}
@Test
public void testMultiWordContainsDelimitersWithBoundingSpaces() {
setFilterOptions(TextFilterStrategy.CONTAINS, false);
// no filter text - make sure all 5 nodes are there
assertEquals(5, root.getChildCount());
String delimPad = StringUtilities.pad("", ' ', 1);
for (char delim : FilterOptions.VALID_MULTITERM_DELIMITERS.toCharArray()) {
setFilterOptions(TextFilterStrategy.CONTAINS, false, true, delim,
MultitermEvaluationMode.AND);
String delimStr = delimPad + delim + delimPad;
setFilterText("CX" + delimStr + "AB");
assertEquals(2, root.getChildCount());
setFilterOptions(TextFilterStrategy.CONTAINS, false, true, delim,
MultitermEvaluationMode.OR);
setFilterText("CX" + delimStr + "AB");
assertEquals(4, root.getChildCount());
checkContainsNode("ABCX");
checkContainsNode("XABCX");
setFilterText("");
assertEquals("Expected all 5 nodes to be back", 5, root.getChildCount());
}
}
@Test
public void testInvertedContains() {
setFilterOptions(TextFilterStrategy.CONTAINS, true);
assertEquals(5, root.getChildCount());
setFilterText("ABC");
assertEquals(1, root.getChildCount());
checkDoesNotContainsNode("ABC");
checkDoesNotContainsNode("XABC");
checkDoesNotContainsNode("ABCX");
checkDoesNotContainsNode("XABCX");
setFilterText("MMM");
assertEquals(5, root.getChildCount());
setFilterText("");
assertEquals("Expected all 5 nodes to be back", 5, root.getChildCount());
}
@Test
public void testInvertedMultiWordContains() {
setFilterOptions(TextFilterStrategy.CONTAINS, true, true, ' ', MultitermEvaluationMode.AND);
// no filter text - make sure all 5 nodes are there
assertEquals(5, root.getChildCount());
setFilterText("CX AB");
checkDoesNotContainsNode("ABCX");
checkDoesNotContainsNode("XABCX");
assertEquals(3, root.getChildCount());
setFilterOptions(TextFilterStrategy.CONTAINS, true, true, ' ', MultitermEvaluationMode.OR);
setFilterText("");
// no filter text - make sure all 5 nodes are there
assertEquals(5, root.getChildCount());
setFilterText("CX AB");
checkDoesNotContainsNode("ABCX");
checkDoesNotContainsNode("XABCX");
assertEquals(1, root.getChildCount());
setFilterText("");
assertEquals("Expected all 5 nodes to be back", 5, root.getChildCount());
}
@Test
public void testStartsWith() {
setFilterOptions(TextFilterStrategy.STARTS_WITH, false);
// no filter text - make sure all 5 nodes are there
assertEquals(5, root.getChildCount());
setFilterText("ABC");
checkContainsNode("ABC");
checkContainsNode("ABCX");
assertEquals(2, root.getChildCount());
setFilterText("MMM");
assertEquals(0, root.getChildCount());
setFilterText("");
assertEquals("Expected all 5 nodes to be back", 5, root.getChildCount());
}
@Test
public void testInvertedStartsWith() {
setFilterOptions(TextFilterStrategy.STARTS_WITH, true);
// no filter text - make sure all 5 nodes are there
assertEquals(5, root.getChildCount());
setFilterText("ABC");
checkDoesNotContainsNode("ABC");
checkDoesNotContainsNode("ABCX");
assertEquals(3, root.getChildCount());
setFilterText("MMM");
assertEquals(5, root.getChildCount());
setFilterText("");
assertEquals("Expected all 5 nodes to be back", 5, root.getChildCount());
}
@Test
public void testExactMatch() {
setFilterOptions(TextFilterStrategy.MATCHES_EXACTLY, false);
// no filter text - make sure all 5 nodes are there
assertEquals(5, root.getChildCount());
setFilterText("ABC");
checkContainsNode("ABC");
assertEquals(1, root.getChildCount());
setFilterText("MMM");
assertEquals(0, root.getChildCount());
setFilterText("");
assertEquals("Expected all 5 nodes to be back", 5, root.getChildCount());
}
@Test
public void testInvertedExactMatch() {
setFilterOptions(TextFilterStrategy.MATCHES_EXACTLY, true);
// no filter text - make sure all 5 nodes are there
assertEquals(5, root.getChildCount());
setFilterText("ABC");
checkDoesNotContainsNode("ABC");
assertEquals(4, root.getChildCount());
setFilterText("MMM");
assertEquals(5, root.getChildCount());
setFilterText("");
assertEquals("Expected all 5 nodes to be back", 5, root.getChildCount());
}
@Test
public void testRegExMatch() {
setFilterOptions(TextFilterStrategy.REGULAR_EXPRESSION, false);
// no filter text - make sure all 5 nodes are there
assertEquals(5, root.getChildCount());
setFilterText("^ABC$");
checkContainsNode("ABC");
assertEquals("Expected 1 node match exacly match ABC!", 1, root.getChildCount());
setFilterText("ABC");
checkContainsNode("ABC");
checkContainsNode("XABC");
checkContainsNode("ABCX");
checkContainsNode("XABCX");
assertEquals("Expected 4 of nodes that contain the text ABC!", 4, root.getChildCount());
setFilterText("XA.{0,2}X");
checkContainsNode("XABCX");
assertEquals(1, root.getChildCount());
setFilterText("X{0,1}A.{0,2}X");
checkContainsNode("XABCX");
checkContainsNode("ABCX");
assertEquals(2, root.getChildCount());
setFilterText("");
assertEquals("Expected all 5 nodes to be back", 5, root.getChildCount());
}
@Test
public void testInvertedRegExMatch() {
setFilterOptions(TextFilterStrategy.REGULAR_EXPRESSION, true);
// no filter text - make sure all 5 nodes are there
assertEquals(5, root.getChildCount());
setFilterText("^ABC$");
checkDoesNotContainsNode("ABC");
assertEquals(4, root.getChildCount());
setFilterText("ABC");
checkDoesNotContainsNode("ABC");
checkDoesNotContainsNode("XABC");
checkDoesNotContainsNode("ABCX");
checkDoesNotContainsNode("XABCX");
assertEquals(1, root.getChildCount());
setFilterText("XA.{0,2}X");
checkDoesNotContainsNode("XABCX");
assertEquals(4, root.getChildCount());
setFilterText("X{0,1}A.{0,2}X");
checkDoesNotContainsNode("XABCX");
checkDoesNotContainsNode("ABCX");
assertEquals(3, root.getChildCount());
setFilterText("");
assertEquals("Expected all 5 nodes to be back", 5, root.getChildCount());
}
@Test
public void testSwitchFilterTypes() {
setFilterOptions(TextFilterStrategy.STARTS_WITH, false);
setFilterText("ABC");
checkContainsNode("ABC");
checkContainsNode("ABCX");
assertEquals(2, root.getChildCount());
setFilterOptions(TextFilterStrategy.MATCHES_EXACTLY, false);
checkContainsNode("ABC");
assertEquals(1, root.getChildCount());
setFilterOptions(TextFilterStrategy.CONTAINS, false);
assertEquals("Expected 4 of nodes to be in filtered tree!", 4, root.getChildCount());
checkContainsNode("ABC");
checkContainsNode("XABC");
checkContainsNode("ABCX");
checkContainsNode("XABCX");
}
@Test
public void testSavingSelectedFilterType() {
setFilterOptions(TextFilterStrategy.MATCHES_EXACTLY, false);
setFilterText("ABC");
checkContainsNode("ABC");
assertEquals(1, root.getChildCount());
Object originalValue = getInstanceField("uniquePreferenceKey", gTree);
setInstanceField("preferenceKey", gTree.getFilterProvider(), "XYZ");
setFilterOptions(TextFilterStrategy.STARTS_WITH, false);
checkContainsNode("ABC");
checkContainsNode("ABCX");
assertEquals(2, root.getChildCount());
setInstanceField("preferenceKey", gTree.getFilterProvider(), originalValue);
setInstanceField("optionsSet", gTree.getFilterProvider(), false);
restorePreferences();
checkContainsNode("ABC");
assertEquals(1, root.getChildCount());
}
private void restorePreferences() {
runSwing(() -> {
GTreeFilterProvider filterProvider = gTree.getFilterProvider();
String key = (String) getInstanceField("uniquePreferenceKey", gTree);
Class<?>[] classes = new Class[] { DockingWindowManager.class, String.class };
Object[] objs = new Object[] { winMgr, key };
invokeInstanceMethod("loadFilterPreference", filterProvider, classes, objs);
});
waitForTree();
}
private void checkContainsNode(String string) {
List<GTreeNode> children = root.getChildren();
for (GTreeNode gTreeNode : children) {
if (gTreeNode.getName().equals(string)) {
return;
}
}
Assert.fail("Expected node " + string + " to be included in filter, but was not found!");
}
private void checkDoesNotContainsNode(String string) {
List<GTreeNode> children = root.getChildren();
for (GTreeNode gTreeNode : children) {
if (gTreeNode.getName().equals(string)) {
Assert.fail("Expected node " + string +
" to be NOT be included in filter, but was not found!");
}
}
}
private void setFilterText(final String text) {
runSwing(() -> {
filterField.setText(text);
});
waitForTree();
}
private void setFilterOptions(final TextFilterStrategy filterStrategy, final boolean inverted) {
runSwing(() -> {
FilterOptions filterOptions = new FilterOptions(filterStrategy, false, false, inverted);
((DefaultGTreeFilterProvider) gTree.getFilterProvider()).setFilterOptions(
filterOptions);
});
waitForTree();
}
private void setFilterOptions(TextFilterStrategy filterStrategy, boolean inverted,
boolean multiTerm, char splitCharacter, MultitermEvaluationMode evalMode) {
runSwing(() -> {
FilterOptions filterOptions = new FilterOptions(filterStrategy, false, false, inverted,
multiTerm, splitCharacter, evalMode);
((DefaultGTreeFilterProvider) gTree.getFilterProvider()).setFilterOptions(
filterOptions);
});
waitForTree();
}
private void waitForTree() {
waitForTree(gTree);
}
private class TestRootNode extends AbstractGTreeRootNode {
TestRootNode() {
List<GTreeNode> children = new ArrayList<>();
children.add(new LeafNode("XYZ"));
children.add(new LeafNode("ABC"));
children.add(new LeafNode("ABCX"));
children.add(new LeafNode("XABC"));
children.add(new LeafNode("XABCX"));
setChildren(children);
}
@Override
public Icon getIcon(boolean expanded) {
return null;
}
@Override
public String getName() {
return "Root";
}
@Override
public String getToolTip() {
return null;
}
@Override
public boolean isLeaf() {
return false;
}
}
/**
* A basic leaf node
*/
private class LeafNode extends AbstractGTreeNode {
private final String name;
LeafNode(String name) {
this.name = name;
}
@Override
public Icon getIcon(boolean expanded) {
return null;
}
@Override
public String getName() {
return name;
}
@Override
public String getToolTip() {
return null;
}
@Override
public boolean isLeaf() {
return true;
}
}
class TestTreeComponentProvider extends ComponentProvider {
public TestTreeComponentProvider() {
super(null, "Test", "Test");
setDefaultWindowPosition(WindowPosition.STACK);
setTabText("Test");
}
@Override
public JComponent getComponent() {
return gTree;
}
@Override
public String getTitle() {
return "Test Tree";
}
}
}

View File

@ -28,6 +28,7 @@ import org.junit.*;
import docking.action.DockingActionIf;
import docking.tool.ToolConstants;
import docking.util.image.ToolIconURL;
import docking.widgets.OptionDialog;
import docking.widgets.filechooser.GhidraFileChooser;
import generic.test.AbstractGTest;
@ -46,7 +47,6 @@ import ghidra.framework.model.ToolTemplate;
import ghidra.framework.plugintool.PluginTool;
import ghidra.framework.plugintool.util.PluginException;
import ghidra.framework.preferences.Preferences;
import ghidra.framework.project.tool.ToolIconURL;
import ghidra.test.AbstractGhidraHeadedIntegrationTest;
import ghidra.test.TestEnv;
import ghidra.util.exception.AssertException;

View File

@ -23,12 +23,12 @@ import org.junit.*;
import docking.action.DockingActionIf;
import docking.action.ToggleDockingAction;
import docking.util.image.ToolIconURL;
import ghidra.app.plugin.core.codebrowser.CodeBrowserPlugin;
import ghidra.app.plugin.core.progmgr.ProgramManagerPlugin;
import ghidra.framework.main.FrontEndPlugin;
import ghidra.framework.plugintool.PluginTool;
import ghidra.framework.project.tool.GhidraTool;
import ghidra.framework.project.tool.ToolIconURL;
import ghidra.program.database.ProgramDB;
import ghidra.test.ClassicSampleX86ProgramBuilder;
import ghidra.test.TestEnv;

View File

@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ghidra.framework.project.tool;
package docking.util.image;
import generic.Images;

View File

@ -0,0 +1,309 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package docking.widgets.tree;
import static org.junit.Assert.*;
import java.util.ArrayList;
import java.util.List;
import javax.swing.*;
import org.junit.*;
import docking.test.AbstractDockingTest;
import docking.widgets.OptionDialog;
import ghidra.util.exception.CancelledException;
import ghidra.util.task.TaskMonitor;
public class GTreeSlowLoadingNode1Test extends AbstractDockingTest {
private static final int MAX_DEPTH = 4;
private static final int MIN_CHILD_COUNT = 3;
private static final int MAX_CHILD_COUNT = 40;
private volatile boolean pauseChildLoading = false;
private JFrame frame;
private GTree gTree;
@Before
public void setUp() throws Exception {
gTree = new GTree(new EmptyRootNode());
frame = new JFrame("GTree Test");
frame.getContentPane().add(gTree);
frame.setSize(400, 400);
frame.setVisible(true);
waitForTree();
}
@After
public void tearDown() throws Exception {
gTree.dispose();
frame.dispose();
}
@Test
public void testBasicLoading() {
gTree.setRootNode(new TestRootNode(100));
waitForTree();
// make sure we have some children
GTreeRootNode rootNode = gTree.getRootNode();
GTreeNode nonLeaf1 = rootNode.getChild(0);
assertNotNull(nonLeaf1);
GTreeNode leaf1 = rootNode.getChild(1);
assertNotNull(leaf1);
GTreeNode nonLeaf2 = rootNode.getChild(2);
assertNotNull(nonLeaf2);
int childCount = nonLeaf1.getChildCount();
assertTrue("Did not find children for: " + nonLeaf1, childCount > 1);
assertEquals("An expected leaf node has some children", 0, leaf1.getChildCount());
childCount = nonLeaf2.getChildCount();
assertTrue("Did not find children for: " + nonLeaf2, childCount > 1);
}
@Test
public void testSlowNodeShowsProgressBar() {
gTree.setRootNode(new TestRootNode(5000));
waitForTree();
GTreeRootNode rootNode = gTree.getRootNode();
GTreeNode nonLeaf1 = rootNode.getChild(0);
assertNotNull(nonLeaf1);
gTree.expandPath(nonLeaf1);
assertProgressPanel(true);
assertTrue(nonLeaf1.isInProgress());
// Press the cancel button on the progress monitor
pressProgressPanelCancelButton();
waitForTree();
// Verify no progress component
assertProgressPanel(false);
}
//==================================================================================================
// Private Methods
//==================================================================================================
private void waitForTree() {
waitForTree(gTree);
}
private void assertProgressPanel(boolean isShowing) {
JComponent panel = (JComponent) getInstanceField("progressPanel", gTree);
if (!isShowing) {
assertNull("Panel is showing when it should not be", panel);
return;
}
if (panel == null || !panel.isShowing()) {
int maxWaits = 50;// wait a couple seconds, as the progress bar may be delayed
int tryCount = 0;
while (tryCount < maxWaits) {
panel = (JComponent) getInstanceField("progressPanel", gTree);
if (panel != null && panel.isShowing()) {
return;// finally showing!
}
tryCount++;
try {
Thread.sleep(50);
}
catch (Exception e) {
// who cares?
}
}
}
Assert.fail("Progress panel is not showing as expected");
}
private void pressProgressPanelCancelButton() {
Object taskMonitorComponent = getInstanceField("monitor", gTree);
final JButton cancelButton =
(JButton) getInstanceField("cancelButton", taskMonitorComponent);
runSwing(() -> cancelButton.doClick(), false);
OptionDialog confirDialog = waitForDialogComponent(frame, OptionDialog.class, 2000);
final JButton confirmCancelButton = findButtonByText(confirDialog, "Yes");
runSwing(() -> confirmCancelButton.doClick());
}
//==================================================================================================
// Inner Classes
//==================================================================================================
private class EmptyRootNode extends AbstractGTreeRootNode {
EmptyRootNode() {
setChildren(new ArrayList<GTreeNode>());
}
@Override
public Icon getIcon(boolean expanded) {
return null;
}
@Override
public String getName() {
return "Empty Test GTree Root Node";
}
@Override
public String getToolTip() {
return null;
}
@Override
public boolean isLeaf() {
return true;
}
}
private class TestRootNode extends AbstractGTreeRootNode {
TestRootNode(int loadDelayMillis) {
List<GTreeNode> children = new ArrayList<>();
children.add(new TestSlowLoadingNode(loadDelayMillis, 1));
children.add(new TestLeafNode());
children.add(new TestSlowLoadingNode(loadDelayMillis, 1));
setChildren(children);
}
@Override
public Icon getIcon(boolean expanded) {
return null;
}
@Override
public String getName() {
return "Test GTree Root Node";
}
@Override
public String getToolTip() {
return null;
}
@Override
public boolean isLeaf() {
return false;
}
}
private class TestSlowLoadingNode extends GTreeSlowLoadingNode {
private final long loadDelayMillis;
private final int depth;
TestSlowLoadingNode(long loadDelayMillis, int depth) {
this.loadDelayMillis = loadDelayMillis;
this.depth = depth;
}
@Override
public List<GTreeNode> generateChildren(TaskMonitor monitor) throws CancelledException {
if (depth > MAX_DEPTH) {
return new ArrayList<>();
}
if (monitor.isCancelled()) {
return new ArrayList<>();
}
sleep(loadDelayMillis);
while (pauseChildLoading) {
sleep(100);
}
int childCount = getRandomInt(MIN_CHILD_COUNT, MAX_CHILD_COUNT);
List<GTreeNode> children = new ArrayList<>();
for (int i = 0; i < childCount; i++) {
if (monitor.isCancelled()) {
return new ArrayList<>();
}
int value = getRandomInt(0, 1);
if (value == 0) {
children.add(new TestSlowLoadingNode(loadDelayMillis, depth + 1));
}
else {
children.add(new TestLeafNode());
}
}
return children;
}
@Override
public Icon getIcon(boolean expanded) {
return null;
}
@Override
public String getName() {
return getClass().getSimpleName();
}
@Override
public String getToolTip() {
return null;
}
@Override
public boolean isLeaf() {
return false;
}
}
private class TestLeafNode extends AbstractGTreeNode {
private String name = getClass().getSimpleName() + getRandomString();
@Override
public Icon getIcon(boolean expanded) {
return null;
}
@Override
public String getName() {
return name;
}
@Override
public String getToolTip() {
return null;
}
@Override
public boolean isLeaf() {
return true;
}
}
}

View File

@ -0,0 +1,255 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package docking.widgets.tree;
import static org.junit.Assert.assertEquals;
import java.util.ArrayList;
import java.util.List;
import javax.swing.*;
import org.junit.*;
import docking.test.AbstractDockingTest;
import docking.widgets.filter.FilterTextField;
import ghidra.util.exception.CancelledException;
import ghidra.util.task.TaskMonitor;
public class GTreeSlowLoadingNode2Test extends AbstractDockingTest {
private static final int MAX_DEPTH = 4;
private static final int MIN_CHILD_COUNT = 3;
private static final int MAX_CHILD_COUNT = 3;
private volatile boolean pauseChildLoading = false;
private JFrame frame;
private GTree gTree;
private FilterTextField filterField;
@Before
public void setUp() throws Exception {
gTree = new GTree(new EmptyRootNode());
filterField = (FilterTextField) gTree.getFilterField();
frame = new JFrame("GTree Test");
frame.getContentPane().add(gTree);
frame.setSize(400, 400);
frame.setVisible(true);
waitForTree();
}
@After
public void tearDown() throws Exception {
gTree.dispose();
frame.dispose();
}
@Test
public void testBasicLoading() {
gTree.setRootNode(new TestRootNode(0));
waitForTree();
// make sure we have some children
GTreeRootNode rootNode = gTree.getRootNode();
List<GTreeNode> allChildren = rootNode.getAllChildren();
typeFilterText("Many B1");
clearFilterText();
List<GTreeNode> allChildren2 = rootNode.getAllChildren();
assertEquals("Children were reloaded instead of being reused", allChildren, allChildren2);
}
//==================================================================================================
// Private Methods
//==================================================================================================
private void typeFilterText(String text) {
JTextField textField = (JTextField) getInstanceField("textField", filterField);
triggerText(textField, text);
waitForTree();
}
private void setFilterText(final String text) {
runSwing(() -> filterField.setText(text));
waitForTree();
}
private void clearFilterText() {
setFilterText("");
}
private void waitForTree() {
waitForTree(gTree);
}
//==================================================================================================
// Inner Classes
//==================================================================================================
private class EmptyRootNode extends AbstractGTreeRootNode {
EmptyRootNode() {
setChildren(new ArrayList<GTreeNode>());
}
@Override
public Icon getIcon(boolean expanded) {
return null;
}
@Override
public String getName() {
return "Empty Test GTree Root Node";
}
@Override
public String getToolTip() {
return null;
}
@Override
public boolean isLeaf() {
return true;
}
}
private class TestRootNode extends TestSlowLoadingNode implements GTreeRootNode {
private GTree tree;
TestRootNode(int loadDelayMillis) {
super(loadDelayMillis, 3);
}
@Override
public void setGTree(GTree tree) {
this.tree = tree;
}
@Override
public GTree getGTree() {
return tree;
}
@Override
public Icon getIcon(boolean expanded) {
return null;
}
@Override
public String getName() {
return "Test GTree Root Node";
}
@Override
public String getToolTip() {
return null;
}
@Override
public boolean isLeaf() {
return false;
}
}
private class TestSlowLoadingNode extends GTreeSlowLoadingNode {
private final long loadDelayMillis;
private final int depth;
TestSlowLoadingNode(long loadDelayMillis, int depth) {
this.loadDelayMillis = loadDelayMillis;
this.depth = depth;
}
@Override
public List<GTreeNode> generateChildren(TaskMonitor monitor) throws CancelledException {
if (depth > MAX_DEPTH) {
return new ArrayList<>();
}
if (monitor.isCancelled()) {
return new ArrayList<>();
}
sleep(loadDelayMillis);
while (pauseChildLoading) {
sleep(100);
}
int childCount = getRandomInt(MIN_CHILD_COUNT, MAX_CHILD_COUNT);
List<GTreeNode> children = new ArrayList<>();
for (int i = 0; i < childCount; i++) {
if (monitor.isCancelled()) {
return new ArrayList<>();
}
children.add(new TestSlowLoadingNode(0, depth + 1));
}
return children;
}
@Override
public Icon getIcon(boolean expanded) {
return null;
}
@Override
public String getName() {
return getClass().getSimpleName();
}
@Override
public String getToolTip() {
return null;
}
@Override
public boolean isLeaf() {
return false;
}
}
private class TestLeafNode extends AbstractGTreeNode {
private String name = getClass().getSimpleName() + getRandomString();
@Override
public Icon getIcon(boolean expanded) {
return null;
}
@Override
public String getName() {
return name;
}
@Override
public String getToolTip() {
return null;
}
@Override
public boolean isLeaf() {
return true;
}
}
}

View File

@ -0,0 +1,309 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package docking.widgets.tree;
import static org.junit.Assert.*;
import java.util.ArrayList;
import java.util.List;
import javax.swing.*;
import org.junit.*;
import docking.test.AbstractDockingTest;
import docking.widgets.OptionDialog;
import ghidra.util.exception.CancelledException;
import ghidra.util.task.TaskMonitor;
public class GTreeSlowLoadingNodeTest extends AbstractDockingTest {
private static final int MAX_DEPTH = 4;
private static final int MIN_CHILD_COUNT = 3;
private static final int MAX_CHILD_COUNT = 40;
private volatile boolean pauseChildLoading = false;
private JFrame frame;
private GTree gTree;
@Before
public void setUp() throws Exception {
gTree = new GTree(new EmptyRootNode());
frame = new JFrame("GTree Test");
frame.getContentPane().add(gTree);
frame.setSize(400, 400);
frame.setVisible(true);
waitForTree();
}
@After
public void tearDown() throws Exception {
gTree.dispose();
frame.dispose();
}
@Test
public void testBasicLoading() {
gTree.setRootNode(new TestRootNode(100));
waitForTree();
// make sure we have some children
GTreeRootNode rootNode = gTree.getRootNode();
GTreeNode nonLeaf1 = rootNode.getChild(0);
assertNotNull(nonLeaf1);
GTreeNode leaf1 = rootNode.getChild(1);
assertNotNull(leaf1);
GTreeNode nonLeaf2 = rootNode.getChild(2);
assertNotNull(nonLeaf2);
int childCount = nonLeaf1.getChildCount();
assertTrue("Did not find children for: " + nonLeaf1, childCount > 1);
assertEquals("An expected leaf node has some children", 0, leaf1.getChildCount());
childCount = nonLeaf2.getChildCount();
assertTrue("Did not find children for: " + nonLeaf2, childCount > 1);
}
@Test
public void testSlowNodeShowsProgressBar() {
gTree.setRootNode(new TestRootNode(5000));
waitForTree();
GTreeRootNode rootNode = gTree.getRootNode();
GTreeNode nonLeaf1 = rootNode.getChild(0);
assertNotNull(nonLeaf1);
gTree.expandPath(nonLeaf1);
assertProgressPanel(true);
assertTrue(nonLeaf1.isInProgress());
// Press the cancel button on the progress monitor
pressProgressPanelCancelButton();
waitForTree();
// Verify no progress component
assertProgressPanel(false);
}
//==================================================================================================
// Private Methods
//==================================================================================================
private void waitForTree() {
waitForTree(gTree);
}
private void assertProgressPanel(boolean isShowing) {
JComponent panel = (JComponent) getInstanceField("progressPanel", gTree);
if (!isShowing) {
assertNull("Panel is showing when it should not be", panel);
return;
}
if (panel == null || !panel.isShowing()) {
int maxWaits = 50;// wait a couple seconds, as the progress bar may be delayed
int tryCount = 0;
while (tryCount < maxWaits) {
panel = (JComponent) getInstanceField("progressPanel", gTree);
if (panel != null && panel.isShowing()) {
return;// finally showing!
}
tryCount++;
try {
Thread.sleep(50);
}
catch (Exception e) {
// who cares?
}
}
}
Assert.fail("Progress panel is not showing as expected");
}
private void pressProgressPanelCancelButton() {
Object taskMonitorComponent = getInstanceField("monitor", gTree);
final JButton cancelButton =
(JButton) getInstanceField("cancelButton", taskMonitorComponent);
runSwing(() -> cancelButton.doClick(), false);
OptionDialog confirDialog = waitForDialogComponent(OptionDialog.class);
final JButton confirmCancelButton = findButtonByText(confirDialog, "Yes");
runSwing(() -> confirmCancelButton.doClick());
}
//==================================================================================================
// Inner Classes
//==================================================================================================
private class EmptyRootNode extends AbstractGTreeRootNode {
EmptyRootNode() {
setChildren(new ArrayList<GTreeNode>());
}
@Override
public Icon getIcon(boolean expanded) {
return null;
}
@Override
public String getName() {
return "Empty Test GTree Root Node";
}
@Override
public String getToolTip() {
return null;
}
@Override
public boolean isLeaf() {
return true;
}
}
private class TestRootNode extends AbstractGTreeRootNode {
TestRootNode(int loadDelayMillis) {
List<GTreeNode> children = new ArrayList<>();
children.add(new TestSlowLoadingNode(loadDelayMillis, 1));
children.add(new TestLeafNode());
children.add(new TestSlowLoadingNode(loadDelayMillis, 1));
setChildren(children);
}
@Override
public Icon getIcon(boolean expanded) {
return null;
}
@Override
public String getName() {
return "Test GTree Root Node";
}
@Override
public String getToolTip() {
return null;
}
@Override
public boolean isLeaf() {
return false;
}
}
private class TestSlowLoadingNode extends GTreeSlowLoadingNode {
private final long loadDelayMillis;
private final int depth;
TestSlowLoadingNode(long loadDelayMillis, int depth) {
this.loadDelayMillis = loadDelayMillis;
this.depth = depth;
}
@Override
public List<GTreeNode> generateChildren(TaskMonitor monitor) throws CancelledException {
if (depth > MAX_DEPTH) {
return new ArrayList<>();
}
if (monitor.isCancelled()) {
return new ArrayList<>();
}
sleep(loadDelayMillis);
while (pauseChildLoading) {
sleep(100);
}
int childCount = getRandomInt(MIN_CHILD_COUNT, MAX_CHILD_COUNT);
List<GTreeNode> children = new ArrayList<>();
for (int i = 0; i < childCount; i++) {
if (monitor.isCancelled()) {
return new ArrayList<>();
}
int value = getRandomInt(0, 1);
if (value == 0) {
children.add(new TestSlowLoadingNode(loadDelayMillis, depth + 1));
}
else {
children.add(new TestLeafNode());
}
}
return children;
}
@Override
public Icon getIcon(boolean expanded) {
return null;
}
@Override
public String getName() {
return getClass().getSimpleName();
}
@Override
public String getToolTip() {
return null;
}
@Override
public boolean isLeaf() {
return false;
}
}
private class TestLeafNode extends AbstractGTreeNode {
private String name = getClass().getSimpleName() + getRandomString();
@Override
public Icon getIcon(boolean expanded) {
return null;
}
@Override
public String getName() {
return name;
}
@Override
public String getToolTip() {
return null;
}
@Override
public boolean isLeaf() {
return true;
}
}
}

File diff suppressed because it is too large Load Diff

View File

@ -62,6 +62,7 @@ public abstract class AbstractGenericTest extends AbstractGTest {
private static File debugDirectory;
public static final String TESTDATA_DIRECTORY_NAME = "testdata";
public static final String DEFAULT_TOOL_NAME = "CodeBrowser";
public static final String DEFAULT_TEST_TOOL_NAME = "TestCodeBrowser";
private static boolean initialized = false;

View File

@ -40,6 +40,7 @@ import docking.help.Help;
import docking.help.HelpService;
import docking.tool.ToolConstants;
import docking.util.AnimationUtils;
import docking.util.image.ToolIconURL;
import docking.widgets.OptionDialog;
import generic.jar.ResourceFile;
import generic.util.WindowUtilities;

View File

@ -32,11 +32,11 @@ import docking.dnd.*;
import docking.help.Help;
import docking.help.HelpService;
import docking.tool.ToolConstants;
import docking.util.image.ToolIconURL;
import docking.widgets.EmptyBorderButton;
import ghidra.framework.main.datatree.*;
import ghidra.framework.model.*;
import ghidra.framework.plugintool.PluginTool;
import ghidra.framework.project.tool.ToolIconURL;
import ghidra.util.*;
import ghidra.util.bean.GGlassPane;
import ghidra.util.exception.AssertException;

View File

@ -21,8 +21,8 @@ import java.beans.PropertyVetoException;
import org.jdom.Element;
import docking.DockingTool;
import docking.util.image.ToolIconURL;
import ghidra.framework.plugintool.PluginEvent;
import ghidra.framework.project.tool.ToolIconURL;
/**
*

View File

@ -19,7 +19,7 @@ import javax.swing.ImageIcon;
import org.jdom.Element;
import ghidra.framework.project.tool.ToolIconURL;
import docking.util.image.ToolIconURL;
/**
* Configuration of a tool that knows how to create tools.

View File

@ -42,6 +42,7 @@ import docking.help.Help;
import docking.help.HelpService;
import docking.tool.ToolConstants;
import docking.tool.util.DockingToolConstants;
import docking.util.image.ToolIconURL;
import docking.widgets.OptionDialog;
import ghidra.framework.OperatingSystem;
import ghidra.framework.Platform;
@ -56,7 +57,6 @@ import ghidra.framework.plugintool.dialog.ManagePluginsDialog;
import ghidra.framework.plugintool.mgr.*;
import ghidra.framework.plugintool.util.*;
import ghidra.framework.project.ProjectDataService;
import ghidra.framework.project.tool.ToolIconURL;
import ghidra.util.*;
import ghidra.util.task.Task;
import ghidra.util.task.TaskLauncher;

View File

@ -1,6 +1,5 @@
/* ###
* IP: GHIDRA
* REVIEWED: YES
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -16,10 +15,9 @@
*/
package ghidra.framework.plugintool.dialog;
import ghidra.framework.project.tool.ToolIconURL;
import java.util.*;
import docking.util.image.ToolIconURL;
import resources.ResourceManager;
/**

View File

@ -27,6 +27,7 @@ import javax.swing.event.*;
import docking.DialogComponentProvider;
import docking.options.editor.ButtonPanelFactory;
import docking.util.image.ToolIconURL;
import docking.widgets.OptionDialog;
import docking.widgets.filechooser.GhidraFileChooser;
import docking.widgets.label.GLabel;
@ -34,7 +35,6 @@ import ghidra.framework.model.*;
import ghidra.framework.plugintool.PluginTool;
import ghidra.framework.preferences.Preferences;
import ghidra.framework.project.tool.GhidraToolTemplate;
import ghidra.framework.project.tool.ToolIconURL;
import ghidra.util.HelpLocation;
import ghidra.util.NamingUtilities;
import ghidra.util.filechooser.ExtensionFileFilter;

View File

@ -22,8 +22,8 @@ import javax.swing.BorderFactory;
import javax.swing.JList;
import javax.swing.border.Border;
import docking.util.image.ToolIconURL;
import docking.widgets.list.GListCellRenderer;
import ghidra.framework.project.tool.ToolIconURL;
class ToolIconUrlRenderer extends GListCellRenderer<ToolIconURL> {
private Border emptyBorder = BorderFactory.createEmptyBorder(5, 5, 5, 5);

View File

@ -21,6 +21,7 @@ import javax.swing.ImageIcon;
import org.jdom.Element;
import docking.util.image.ToolIconURL;
import ghidra.framework.model.*;
import ghidra.util.Msg;
import ghidra.util.NumericUtilities;

View File

@ -30,10 +30,10 @@ import docking.*;
import docking.action.DockingActionIf;
import docking.actions.DockingToolActions;
import docking.actions.PopupActionProvider;
import docking.util.image.ToolIconURL;
import ghidra.framework.model.*;
import ghidra.framework.options.ToolOptions;
import ghidra.framework.plugintool.PluginEvent;
import ghidra.framework.project.tool.ToolIconURL;
import ghidra.program.model.listing.Program;
public class DummyTool implements Tool {
@ -361,8 +361,7 @@ public class DummyTool implements Tool {
@Override
public void setMenuGroup(String[] menuPath, String group, String menuSubGroup) {
// TODO Auto-generated method stub
//do nothing
}
@Override

View File

@ -19,8 +19,8 @@ import javax.swing.ImageIcon;
import org.jdom.Element;
import docking.util.image.ToolIconURL;
import ghidra.framework.model.*;
import ghidra.framework.project.tool.ToolIconURL;
import ghidra.program.model.listing.Program;
public class DummyToolTemplate implements ToolTemplate {

View File

@ -0,0 +1,131 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ghidra.app.cmd.function;
import static org.junit.Assert.*;
import org.junit.*;
import ghidra.app.plugin.core.analysis.AnalysisBackgroundCommand;
import ghidra.app.plugin.core.analysis.AutoAnalysisManager;
import ghidra.framework.cmd.Command;
import ghidra.framework.options.Options;
import ghidra.framework.plugintool.PluginTool;
import ghidra.program.database.ProgramBuilder;
import ghidra.program.model.data.DataType;
import ghidra.program.model.listing.Function;
import ghidra.program.model.listing.Program;
import ghidra.test.AbstractGhidraHeadedIntegrationTest;
import ghidra.test.TestEnv;
public class CreateFunctionThunkTest extends AbstractGhidraHeadedIntegrationTest {
private TestEnv env;
private PluginTool tool;
private Program program;
private ProgramBuilder builder;
@Before
public void setUp() throws Exception {
env = new TestEnv();
tool = env.getTool();
}
@After
public void tearDown() {
if (program != null) {
env.release(program);
}
program = null;
env.dispose();
}
private void analyze() {
// turn off some analyzers
setAnalysisOptions("Stack");
setAnalysisOptions("Embedded Media");
setAnalysisOptions("DWARF");
setAnalysisOptions("Create Address Tables");
setAnalysisOptions("MIPS Constant Reference Analyzer");
AutoAnalysisManager analysisMgr = AutoAnalysisManager.getAnalysisManager(program);
analysisMgr.reAnalyzeAll(null);
Command cmd = new AnalysisBackgroundCommand(analysisMgr, false);
tool.execute(cmd, program);
waitForBusyTool(tool);
}
protected void setAnalysisOptions(String optionName) {
int txId = program.startTransaction("Analyze");
Options analysisOptions = program.getOptions(Program.ANALYSIS_PROPERTIES);
analysisOptions.setBoolean(optionName, false);
program.endTransaction(txId, true);
}
@Test
public void testDelaySlotThunk() throws Exception {
builder = new ProgramBuilder("thunk", ProgramBuilder._MIPS);
builder.setBytes("0x1000", "08 22 96 44 24 04 00 02 08 11 96 44 00 00 00 00");
builder.disassemble("0x1000", 27, false);
builder.disassemble("0x1008", 27, false);
builder.createFunction("0x1000");
builder.createFunction("0x1008");
builder.analyze();
program = builder.getProgram();
Function noThunk = program.getFunctionManager().getFunctionAt(builder.addr(0x1000));
assertEquals(false, noThunk.isThunk());
Function isThunk = program.getFunctionManager().getFunctionAt(builder.addr(0x1008));
assertEquals(true, isThunk.isThunk());
}
/**
* This tests the forcing of a function to be a thunk with CreateThunkFunctionCmd
* Tests that the Function start analyzer will create a thunk given the thunk tag on a matching function
* That the MIPS BE language has a thunking pattern.
* That the MIPS 64/32 hybrid with sign extension of registers still gets found as a thunk.
* That the thunking function can be found with out the constant reference analyzer
*
*/
@Test
public void testDelayMips6432SlotThunk() throws Exception {
builder = new ProgramBuilder("thunk", ProgramBuilder._MIPS_6432);
builder.setBytes("0x466050", "3c 0f 00 47 8d f9 72 24 03 20 00 08 25 f8 72 24");
builder.setBytes("0x477224", "00 47 99 c0");
builder.createEmptyFunction("chdir", "0x4799c0", 1, DataType.VOID);
builder.disassemble("0x466050", 27, true);
builder.createFunction("0x466050");
program = builder.getProgram();
analyze();
Function isThunk = program.getFunctionManager().getFunctionAt(builder.addr(0x466050));
assertEquals(true, isThunk.isThunk());
assertEquals("chdir", isThunk.getName());
}
}

View File

@ -0,0 +1,307 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ghidra.app.plugin.core.processors;
import static org.junit.Assert.*;
import java.math.BigInteger;
import org.junit.*;
import docking.ActionContext;
import docking.action.DockingActionIf;
import docking.widgets.MultiLineLabel;
import docking.widgets.OptionDialog;
import docking.widgets.tree.GTree;
import docking.widgets.tree.GTreeNode;
import ghidra.framework.main.FrontEndTool;
import ghidra.framework.main.datatree.DomainFileNode;
import ghidra.framework.model.DomainFile;
import ghidra.framework.model.DomainFolder;
import ghidra.plugin.importer.NewLanguagePanel;
import ghidra.program.database.ProgramBuilder;
import ghidra.program.model.address.*;
import ghidra.program.model.lang.*;
import ghidra.program.model.listing.*;
import ghidra.program.model.symbol.RefType;
import ghidra.program.model.symbol.SourceType;
import ghidra.test.AbstractGhidraHeadedIntegrationTest;
import ghidra.test.TestEnv;
import ghidra.util.task.TaskMonitor;
public class SetLanguageTest extends AbstractGhidraHeadedIntegrationTest {
private TestEnv env;
private FrontEndTool frontEndTool;
private DockingActionIf setLanguageAction;
private GTreeNode notepadNode;
private DomainFile notepadFile;
private GTreeNode xyzFolderNode;
private AddressFactory addrFactory;
@Before
public void setUp() throws Exception {
env = new TestEnv();
setErrorGUIEnabled(true);
frontEndTool = env.getFrontEndTool();
env.showFrontEndTool();
setLanguageAction = getAction(frontEndTool, "LanguageProviderPlugin", "Set Language");
// NOTE: Only test translation from a supported language to another supported language
// TODO: Change test data to a supported case (e.g., MIPS-32 to MIPS-64)
DomainFolder rootFolder = env.getProject().getProjectData().getRootFolder();
ProgramBuilder builder = new ProgramBuilder("notepad", "x86:LE:32:default");
Program p = builder.getProgram();
assertEquals(new LanguageID("x86:LE:32:default"), p.getLanguageID());
rootFolder.createFile("notepad", p, TaskMonitor.DUMMY);
env.release(p);
builder.dispose();
rootFolder.createFolder("XYZ");
GTree tree = findComponent(frontEndTool.getToolFrame(), GTree.class);
waitForTree(tree);
GTreeNode rootNode = tree.getRootNode();
xyzFolderNode = rootNode.getChild(0);
notepadNode = rootNode.getChild(1);
notepadFile = ((DomainFileNode) notepadNode).getDomainFile();
waitForSwing();
}
@After
public void tearDown() throws Exception {
env.dispose();
}
@Test
public void testActionEnablement() throws Exception {
assertTrue(setLanguageAction.isEnabled());
assertTrue(!setLanguageAction.isEnabledForContext(createContext(xyzFolderNode)));
assertTrue(setLanguageAction.isEnabledForContext(createContext(notepadNode)));
}
private Address addr(String address) {
return addrFactory.getAddress(address);
}
private void startSetLanguage(final LanguageID languageID, final CompilerSpecID compilerSpecID,
boolean isFailureCase) throws Exception {
if (languageID == null) {
throw new RuntimeException("languageID == null not allowed");
}
if (compilerSpecID == null) {
throw new RuntimeException("compilerSpecID == null not allowed");
}
// this triggers a modal dialog
runSwing(() -> {
ActionContext context = createContext(notepadNode);
assertTrue(setLanguageAction.isEnabledForContext(context));
setLanguageAction.actionPerformed(context);
}, false);
OptionDialog confirmDlg = waitForDialogComponent(OptionDialog.class);
assertNotNull(confirmDlg);
MultiLineLabel msgLabel = findComponent(confirmDlg, MultiLineLabel.class);
assertNotNull(msgLabel);
assertTrue(msgLabel.getLabel().indexOf("Setting the language can not be undone") >= 0);
assertTrue(msgLabel.getLabel().indexOf("make a copy") > 0);
pressButtonByText(confirmDlg, "Ok");
final SetLanguageDialog dlg = waitForDialogComponent(SetLanguageDialog.class);
assertNotNull(dlg);
final NewLanguagePanel languagePanel =
(NewLanguagePanel) getInstanceField("selectLangPanel", dlg);
assertNotNull(languagePanel);
waitForSwing();
runSwing(() -> {
NewLanguagePanel selectLangPanel =
(NewLanguagePanel) getInstanceField("selectLangPanel", dlg);
selectLangPanel.setSelectedLcsPair(
new LanguageCompilerSpecPair(languageID, compilerSpecID));
}, true);
waitForSwing();
pressButtonByText(dlg, "OK");
if (!isFailureCase) {
confirmDlg = waitForDialogComponent(OptionDialog.class);
assertNotNull(confirmDlg);
msgLabel = findComponent(confirmDlg, MultiLineLabel.class);
assertNotNull(msgLabel);
assertTrue(msgLabel.getLabel().indexOf("Would you like to Save") >= 0);
pressButtonByText(confirmDlg, "Save");
}
}
@Test
public void testReplaceLanguage() throws Exception {
startSetLanguage(new LanguageID("x86:LE:32:System Management Mode"),
new CompilerSpecID("default"), false);
waitForTasks();
Program p = (Program) notepadFile.getDomainObject(this, false, false, TaskMonitor.DUMMY);
assertNotNull(p);
try {
assertEquals(new LanguageID("x86:LE:32:System Management Mode"),
p.getLanguage().getLanguageID());
// TODO: Other checks needed ??
}
finally {
p.release(this);
}
}
@Test
public void testReplaceLanguageFailure() throws Exception {
startSetLanguage(new LanguageID("8051:BE:16:default"), new CompilerSpecID("default"), true);
final OptionDialog errDlg = waitForDialogComponent(OptionDialog.class);
assertNotNull(errDlg);
MultiLineLabel msgLabel = findComponent(errDlg, MultiLineLabel.class);
assertNotNull(msgLabel);
assertTrue(msgLabel.getLabel().indexOf("Language translation not supported") >= 0);
pressButtonByText(errDlg, "OK");
closeAllWindows();
}
@Test
public void testReplaceLanguage2() throws Exception {
Program p = (Program) notepadFile.getDomainObject(this, false, false, TaskMonitor.DUMMY);
try {
int txId = p.startTransaction("set Language");
addrFactory = p.getAddressFactory();
ProgramContext pc = p.getProgramContext();
Register ax = pc.getRegister("ax");
Register ebp = pc.getRegister("ebp");
Register ebx = pc.getRegister("ebx");
pc.setValue(ax, addr("0x1001000"), addr("0x1001000"), BigInteger.valueOf(0x1234));
pc.setValue(ebp, addr("0x1001000"), addr("0x1001000"), BigInteger.valueOf(0x12345678));
pc.setValue(ebx, addr("0x1001000"), addr("0x1001000"), BigInteger.valueOf(0x12345678));
assertEquals(0x1234, pc.getValue(ax, addr("0x1001000"), false).longValue());
assertEquals(0x12345678, pc.getValue(ebp, addr("0x1001000"), false).longValue());
assertEquals(0x12345678, pc.getValue(ebx, addr("0x1001000"), false).longValue());
p.endTransaction(txId, true);
p.save(null, TaskMonitor.DUMMY);
}
finally {
p.release(this);
}
startSetLanguage(new LanguageID("x86:LE:32:default"), new CompilerSpecID("gcc"), false);
waitForTasks();
p = (Program) notepadFile.getDomainObject(this, true, false, TaskMonitor.DUMMY);
try {
addrFactory = p.getAddressFactory();
ProgramContext pc = p.getProgramContext();
Register ax = pc.getRegister("ax");
Register ebp = pc.getRegister("ebp");
Register ebx = pc.getRegister("ebx");
assertEquals(0x1234, pc.getValue(ax, addr("0x1001000"), false).longValue());
assertEquals(0x12345678, pc.getValue(ebp, addr("0x1001000"), false).longValue());
assertEquals(0x12345678, pc.getValue(ebx, addr("0x1001000"), false).longValue());
}
finally {
p.release(this);
}
}
@Test
public void testReplaceLanguage3() throws Exception {
Program p = (Program) notepadFile.getDomainObject(this, false, false, TaskMonitor.DUMMY);
addrFactory = p.getAddressFactory();
ProgramContext pc = p.getProgramContext();
Register eax = pc.getRegister("eax");
Register esi = pc.getRegister("esi");
Register edi = pc.getRegister("edi");
try {
int txId = p.startTransaction("set Language");
Function f = p.getListing().createFunction("BOB", addr("0x10041a8"),
new AddressSet(addr("0x10041a8"), addr("0x10041c0")), SourceType.USER_DEFINED);
f.setCustomVariableStorage(true);
ParameterImpl param = new ParameterImpl("PARAM_ONE", null, eax, p);
f.addParameter(param, SourceType.USER_DEFINED);
LocalVariableImpl local1 = new LocalVariableImpl("LOCAL_ONE", 0, null, esi, p);
LocalVariableImpl local2 = new LocalVariableImpl("LOCAL_TWO", 0, null, edi, p);
f.addLocalVariable(local1, SourceType.USER_DEFINED);
f.addLocalVariable(local2, SourceType.USER_DEFINED);
p.getReferenceManager().addRegisterReference(addr("0x10041b2"), 0, esi, RefType.DATA,
SourceType.USER_DEFINED);
p.getReferenceManager().addRegisterReference(addr("0x10041b3"), 0, edi, RefType.DATA,
SourceType.USER_DEFINED);
p.endTransaction(txId, true);
p.save(null, TaskMonitor.DUMMY);
}
finally {
p.release(this);
}
startSetLanguage(new LanguageID("x86:LE:32:default"), new CompilerSpecID("gcc"), false);
waitForTasks();
p = (Program) notepadFile.getDomainObject(this, true, false, TaskMonitor.DUMMY);
try {
addrFactory = p.getAddressFactory();
Function fun = p.getListing().getFunctionAt(addr("0x10041a8"));
Parameter[] params = fun.getParameters();
assertEquals(1, params.length);
assertEquals("PARAM_ONE", params[0].getName());
assertTrue(params[0].isRegisterVariable());
assertEquals(eax, params[0].getRegister());
Variable[] locals = fun.getLocalVariables();
assertEquals(2, locals.length);
assertEquals("LOCAL_ONE", locals[0].getName());
assertEquals("LOCAL_TWO", locals[1].getName());
assertTrue(params[0].isRegisterVariable());
assertEquals(esi, locals[0].getRegister());
assertEquals(edi, locals[1].getRegister());
}
finally {
p.release(this);
}
}
}