Merge remote-tracking branch 'origin/GT-0-dragonmacher-test-fixes'

This commit is contained in:
ghidravore 2020-01-29 18:55:47 -05:00
commit ccd5030574
12 changed files with 196 additions and 156 deletions

View file

@ -114,19 +114,19 @@ public class FunctionComparison implements Comparable<FunctionComparison> {
String sourceName = getSource().getName();
String otherName = o.getSource().getName();
if (sourcePath.equals(otherPath)) {
if (sourceName.contentEquals(otherName)) {
return getSource().getBody()
.getMinAddress()
.compareTo(o.getSource().getBody().getMinAddress());
}
else {
return sourceName.compareTo(otherName);
}
int result = sourcePath.compareTo(otherPath);
if (result != 0) {
return result;
}
return sourcePath.compareTo(otherPath);
// equal paths
result = sourceName.compareTo(otherName);
if (result != 0) {
return result;
}
// equal names
return getSource().getEntryPoint().compareTo(o.getSource().getEntryPoint());
}
/**
@ -144,20 +144,21 @@ public class FunctionComparison implements Comparable<FunctionComparison> {
String o1Path = o1.getProgram().getDomainFile().getPathname();
String o2Path = o2.getProgram().getDomainFile().getPathname();
String o1Name = o1.getName();
String o2Name = o2.getName();
if (o1Path.equals(o2Path)) {
if (o1Name.equals(o2Name)) {
return o1.getBody().getMinAddress().compareTo(o2.getBody().getMinAddress());
}
else {
return o1Name.compareTo(o2Name);
}
int result = o1Path.compareTo(o2Path);
if (result != 0) {
return result;
}
return o1Path.compareTo(o2Path);
// equal paths
String o1Name = o1.getName();
String o2Name = o2.getName();
result = o1Name.compareTo(o2Name);
if (result != 0) {
return result;
}
// equal names
return o1.getEntryPoint().compareTo(o2.getEntryPoint());
}
}
}

View file

@ -89,19 +89,17 @@ public class MultiFunctionComparisonPanel extends FunctionComparisonPanel {
*/
@Override
public void reload() {
SwingUtilities.invokeLater(() -> {
reloadSourceList();
Function selectedSource = (Function) sourceFunctionsCBModel.getSelectedItem();
reloadTargetList(selectedSource);
loadFunctions(selectedSource, (Function) targetFunctionsCBModel.getSelectedItem());
reloadSourceList();
Function selectedSource = (Function) sourceFunctionsCBModel.getSelectedItem();
reloadTargetList(selectedSource);
loadFunctions(selectedSource, (Function) targetFunctionsCBModel.getSelectedItem());
updateTabText();
updateTabText();
// Fire a notification to update the UI state; without this the
// actions would not be properly enabled/disabled
tool.contextChanged(provider);
tool.setStatusInfo("function comparisons updated");
});
// Fire a notification to update the UI state; without this the
// actions would not be properly enabled/disabled
tool.contextChanged(provider);
tool.setStatusInfo("function comparisons updated");
}
/**

View file

@ -155,8 +155,7 @@ public class FunctionComparisonModel {
Iterator<FunctionComparison> iter = comparisons.iterator();
while (iter.hasNext()) {
// First remove any comparisons that have the function as its
// source
// First remove any comparisons that have the function as its source
FunctionComparison fc = iter.next();
if (fc.getSource().equals(function)) {
comparisonsToRemove.add(fc);

View file

@ -449,8 +449,8 @@ public class ComponentProviderActionsTest extends AbstractGhidraHeadedIntegratio
private void setOptionsKeyStroke(KeyStroke newKs) {
ToolOptions keyOptions = tool.getOptions(DockingToolConstants.KEY_BINDINGS);
// shared option name/format: "Provider Name (Tool)" - the shared action's owner is the Tool
runSwing(() -> keyOptions.setKeyStroke(provider.getName() + " (Tool)", newKs));
// shared option name/format: "Provider Name (Shared)" - the shared action's owner is the Tool
runSwing(() -> keyOptions.setKeyStroke(provider.getName() + " (Shared)", newKs));
waitForSwing();
}
@ -496,8 +496,8 @@ public class ComponentProviderActionsTest extends AbstractGhidraHeadedIntegratio
ToolOptions options = getKeyBindingOptions();
// Option name: the action name with the 'Tool' as the owner
String fullName = provider.getName() + " (Tool)";
// Option name: the action name with the 'Shared' owner
String fullName = provider.getName() + " (Shared)";
KeyStroke optionsKs = runSwing(() -> options.getKeyStroke(fullName, null));
assertEquals("Key stroke in options does not match expected key stroke", expectedKs,
optionsKs);

View file

@ -89,8 +89,10 @@ public class KeyBindingsTest extends AbstractGhidraHeadedIntegrationTest {
// look for the info panel
MultiLineLabel label = findComponent(panel, MultiLineLabel.class);
String str = "To add or change a key binding, select an action\n" +
" and type any key combination.\n" + "To remove a key binding, select an action and\n" +
"press <Enter> or <Backspace>.";
"and type any key combination\n" +
" \n" +
"To remove a key binding, select an action and\n" +
"press <Enter> or <Backspace>";
assertEquals(str, label.getLabel());

View file

@ -15,9 +15,7 @@
*/
package ghidra.app.plugin.core.functioncompare;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.*;
import java.awt.Window;
import java.util.Date;
@ -81,27 +79,26 @@ public class CompareFunctionsSlowTest extends AbstractGhidraHeadedIntegrationTes
@Test
public void testRemoveLastItem() throws Exception {
Set<Function> functions = CompareFunctionsTestUtility.getFunctionsAsSet(foo);
provider = plugin.compareFunctions(functions);
provider = waitForComponentProvider(FunctionComparisonProvider.class);
plugin.removeFunction(foo, provider);
provider = compareFunctions(functions);
runSwing(() -> plugin.removeFunction(foo, provider));
assertFalse(provider.isVisible());
}
@Test
public void testCloseProgram() throws Exception {
Set<Function> functions = CompareFunctionsTestUtility.getFunctionsAsSet(foo, bar);
provider = plugin.compareFunctions(functions);
provider = compareFunctions(functions);
CompareFunctionsTestUtility.checkSourceFunctions(provider, foo, bar);
CompareFunctionsTestUtility.checkTargetFunctions(provider, foo, foo, bar);
CompareFunctionsTestUtility.checkTargetFunctions(provider, bar, foo, bar);
plugin.programClosed(program1);
runSwing(() -> plugin.programClosed(program1));
CompareFunctionsTestUtility.checkSourceFunctions(provider, bar);
CompareFunctionsTestUtility.checkTargetFunctions(provider, bar, bar);
plugin.programClosed(program2);
runSwing(() -> plugin.programClosed(program2));
CompareFunctionsTestUtility.checkSourceFunctions(provider);
}
@ -109,9 +106,7 @@ public class CompareFunctionsSlowTest extends AbstractGhidraHeadedIntegrationTes
@Test
public void testNextPreviousAction() {
Set<Function> functions = CompareFunctionsTestUtility.getFunctionsAsSet(foo, bar);
provider = plugin.compareFunctions(functions);
provider.setVisible(true);
waitForSwing();
provider = compareFunctions(functions);
// Must do this or there will be no "active" provider in the actions
// initiated below
@ -134,9 +129,7 @@ public class CompareFunctionsSlowTest extends AbstractGhidraHeadedIntegrationTes
@Test
public void testNextPreviousActionSwitchPanelFocus() {
Set<Function> functions = CompareFunctionsTestUtility.getFunctionsAsSet(foo, bar);
provider = plugin.compareFunctions(functions);
provider.setVisible(true);
waitForSwing();
provider = compareFunctions(functions);
// Must do this or there will be no "active" provider in the actions
// initiated below
@ -169,50 +162,46 @@ public class CompareFunctionsSlowTest extends AbstractGhidraHeadedIntegrationTes
@Test
public void testOpenFunctionTableActionForAdd() {
Set<Function> functions = CompareFunctionsTestUtility.getFunctionsAsSet(foo, bar);
provider = plugin.compareFunctions(functions);
provider.setVisible(true);
provider = compareFunctions(functions);
// Must do this or the context for the action initiated below will be
// for the listing, not the comparison provider
clickComponentProvider(provider);
DockingActionIf openTableAction = getAction(plugin, "Add Functions To Comparison");
performAction(openTableAction);
performAction(openTableAction, false);
Window selectWindow = waitForWindowByTitleContaining("Select Functions");
assertNotNull(selectWindow);
selectWindow.setVisible(false);
}
@SuppressWarnings("unchecked")
@Test
public void testAddFunctionToExistingCompare() {
Set<Function> functions = CompareFunctionsTestUtility.getFunctionsAsSet(foo);
provider = plugin.compareFunctions(functions);
provider.setVisible(true);
waitForSwing();
provider = compareFunctions(functions);
// Must do this or there will be no "active" provider in the actions
// initiated below
clickComponentProvider(provider);
assertTrue(provider.getModel().getSourceFunctions().size() == 1);
assertEquals(provider.getModel().getSourceFunctions().size(), 1);
assertTrue(provider.getModel().getSourceFunctions().contains(foo));
DockingActionIf openTableAction = getAction(plugin, "Add Functions To Comparison");
performAction(openTableAction);
performAction(openTableAction, false);
TableChooserDialog<FunctionTableModel> chooser =
waitForDialogComponent(TableChooserDialog.class);
assertNotNull(chooser);
GFilterTable<FunctionRowObject> table =
(GFilterTable<FunctionRowObject>) getInstanceField("gFilterTable", chooser);
assertTrue(table.getModel().getRowCount() == 2);
assertEquals(table.getModel().getRowCount(), 2);
clickTableCell(table.getTable(), 1, 0, 1);
pressButtonByText(chooser, "OK");
waitForSwing();
assertTrue(provider.getModel().getSourceFunctions().size() == 2);
assertEquals(provider.getModel().getSourceFunctions().size(), 2);
assertTrue(provider.getModel().getSourceFunctions().contains(foo));
assertTrue(provider.getModel().getSourceFunctions().contains(bat));
}
@ -225,10 +214,9 @@ public class CompareFunctionsSlowTest extends AbstractGhidraHeadedIntegrationTes
@Test
public void testDeleteFunctionFromListing() {
Set<Function> functions = CompareFunctionsTestUtility.getFunctionsAsSet(foo, bar);
provider = plugin.compareFunctions(functions);
provider.setVisible(true);
provider = compareFunctions(functions);
assertTrue(provider.getModel().getSourceFunctions().size() == 2);
assertEquals(provider.getModel().getSourceFunctions().size(), 2);
assertTrue(provider.getModel().getSourceFunctions().contains(foo));
assertTrue(provider.getModel().getSourceFunctions().contains(bar));
@ -236,14 +224,20 @@ public class CompareFunctionsSlowTest extends AbstractGhidraHeadedIntegrationTes
ProgramLocation loc = new ProgramLocation(program1, addr);
cbPlugin.goTo(loc);
DockingActionIf deleteAction = getAction(functionPlugin, "Delete Function");
performAction(deleteAction);
performAction(deleteAction, cbPlugin.getProvider().getActionContext(null), true);
waitForSwing();
assertTrue(provider.getModel().getSourceFunctions().size() == 1);
assertEquals(provider.getModel().getSourceFunctions().size(), 1);
assertTrue(provider.getModel().getSourceFunctions().contains(bar));
}
private FunctionComparisonProvider compareFunctions(Set<Function> functions) {
provider = runSwing(() -> plugin.compareFunctions(functions));
provider.setVisible(true);
waitForSwing();
return provider;
}
/**
* Builds a program with 2 functions
*/

View file

@ -109,6 +109,14 @@ public abstract class AbstractDecompilerTest extends AbstractProgramBasedTest {
return (ClangTextField) line;
}
protected ClangTextField getFieldForLine(DecompilerProvider theProvider, int lineNumber) {
DecompilerPanel panel = theProvider.getDecompilerPanel();
List<Field> fields = panel.getFields();
Field line = fields.get(lineNumber - 1); // -1 for 1-based line number
return (ClangTextField) line;
}
// note: the index is 0-based; use getFieldForLine() when using 1-based line numbers
protected ClangTextField getFieldForIndex(int lineIndex) {
@ -119,15 +127,16 @@ public abstract class AbstractDecompilerTest extends AbstractProgramBasedTest {
}
protected ClangToken getToken(int line, int col) {
FieldLocation loc = loc(line, col);
ClangTextField field = getFieldForLine(line);
ClangToken token = field.getToken(loc);
return token;
return getToken(loc(line, col));
}
protected ClangToken getToken(FieldLocation loc) {
return getToken(provider, loc);
}
protected ClangToken getToken(DecompilerProvider theProvider, FieldLocation loc) {
int lineNumber = loc.getIndex().intValue() + 1; // 0-based
ClangTextField field = getFieldForLine(lineNumber);
ClangTextField field = getFieldForLine(theProvider, lineNumber);
ClangToken token = field.getToken(loc);
return token;
}
@ -141,9 +150,13 @@ public abstract class AbstractDecompilerTest extends AbstractProgramBasedTest {
* @return the token under the cursor
*/
protected ClangToken getToken() {
DecompilerPanel panel = getDecompilerPanel();
return getToken(provider);
}
protected ClangToken getToken(DecompilerProvider theProvider) {
DecompilerPanel panel = theProvider.getDecompilerPanel();
FieldLocation loc = panel.getCursorPosition();
return getToken(loc);
return getToken(theProvider, loc);
}
protected String getTokenText(FieldLocation loc) {

View file

@ -755,12 +755,13 @@ public class DecompilerClangTest extends AbstractDecompilerTest {
Color color = highlight();
DecompilerProvider clone = cloneDecompiler();
assertAllFieldsHighlighted(clone, secondaryHighlightText, color);
ClangToken cloneToken = getToken(clone);
assertAllFieldsSecondaryHighlighted(clone, cloneToken, color);
// ensure one field provider does not affect the other
removeSecondaryHighlight();
assertNoFieldsSecondaryHighlighted(secondaryHighlightText);
assertAllFieldsHighlighted(clone, secondaryHighlightText, color);
assertAllFieldsSecondaryHighlighted(clone, cloneToken, color);
}
@Test
@ -989,8 +990,11 @@ public class DecompilerClangTest extends AbstractDecompilerTest {
}
private Color getCombinedHighlightColor(ClangToken token) {
DecompilerController controller = provider.getController();
DecompilerPanel panel = controller.getDecompilerPanel();
return getCombinedHighlightColor(provider, token);
}
private Color getCombinedHighlightColor(DecompilerProvider theProvider, ClangToken token) {
DecompilerPanel panel = theProvider.getDecompilerPanel();
ClangHighlightController highlightController = panel.getHighlightController();
return highlightController.getCombinedColor(token);
}
@ -1168,12 +1172,19 @@ public class DecompilerClangTest extends AbstractDecompilerTest {
assertAllFieldsHighlighted(provider, name, colorMatcher, ignore);
}
private void assertAllFieldsHighlighted(DecompilerProvider theProvider, String name,
Color color) {
private void assertAllFieldsSecondaryHighlighted(DecompilerProvider theProvider,
ClangToken token, Color color) {
ColorMatcher cm = new ColorMatcher(color);
Predicate<ClangToken> noIgnores = t -> false;
assertAllFieldsHighlighted(theProvider, name, cm, noIgnores);
Predicate<ClangToken> ignores = t -> t == token;
String name = token.getText();
Color combinedColor = getCombinedHighlightColor(theProvider, token);
ColorMatcher cm = new ColorMatcher(color, combinedColor);
assertAllFieldsHighlighted(theProvider, name, cm, ignores);
// test the token under the cursor directly, as that may have a combined highlight applied
Color actual = token.getHighlight();
assertTrue("Token is not highlighted: '" + token + "'" + "\n\texpected: " + cm +
"; found: " + toString(actual), cm.matches(actual));
}
private void assertAllFieldsHighlighted(DecompilerProvider theProvider, String name,

View file

@ -22,6 +22,7 @@ import java.util.regex.Matcher;
import java.util.regex.Pattern;
import ghidra.app.util.NamespaceUtils;
import ghidra.app.util.SymbolPath;
import ghidra.app.util.demangler.*;
import ghidra.program.model.lang.CompilerSpec;
import ghidra.util.StringUtilities;
@ -373,9 +374,9 @@ public class GnuDemanglerParser implements DemanglerParser {
}
// this will yield:
// fullNamespace: NS1::Foo::operator
// fullName: NS1::Foo::operator
// fullReturnType: std::string
String fullNamespace = matcher.group(1);// group 0 is the entire match string
String fullName = matcher.group(1);// group 0 is the entire match string
String fullReturnType = matcher.group(2);
boolean isConst = false;
@ -393,14 +394,17 @@ public class GnuDemanglerParser implements DemanglerParser {
method.setReturnType(returnType);
// 'conversion operator' syntax is operator <name, which is the type>()
// assume fullName endsWith '::operator'
int operatorIndex = fullName.lastIndexOf("::operator");
String namespace = fullName.substring(0, operatorIndex);
String templatelessNamespace = stripOffTemplates(fullNamespace);
String templatelessNamespace = stripOffTemplates(namespace);
setNamespace(method, templatelessNamespace);
// shortReturnType: string
String templatelessReturnType = stripOffTemplates(fullReturnType);
List<String> names = NamespaceUtils.splitNamespacePath(templatelessReturnType);
String shortReturnTypeName = names.get(names.size() - 1);
SymbolPath path = new SymbolPath(templatelessReturnType);
String shortReturnTypeName = path.getName();
//
// The preferred name: 'operator basic_string()'
@ -410,7 +414,7 @@ public class GnuDemanglerParser implements DemanglerParser {
//
method.setName("operator.cast.to." + shortReturnTypeName);
method.setSignature(fullNamespace + " " + fullReturnType);
method.setSignature(fullName + " " + fullReturnType);
method.setOverloadedOperator(true);
return method;
@ -481,17 +485,24 @@ public class GnuDemanglerParser implements DemanglerParser {
}
private String stripOffTemplates(String string) {
int templateStart = string.indexOf("<");
if (templateStart == -1) {
return string;
}
StringBuilder buffy = new StringBuilder();
int templateCount = 0;
for (int i = 0; i < string.length(); i++) {
char c = string.charAt(i);
if (c == '<') {
templateCount++;
continue;
}
else if (c == '>') {
templateCount--;
continue;
}
int templateEnd = string.lastIndexOf(">");
if (templateEnd == -1) {
return string;// shouldn't happen
if (templateCount == 0) {
buffy.append(c);
}
}
return string.substring(0, templateStart);
return buffy.toString();
}
private DemangledObject parseGuardVariableOrReferenceTemporary(String demangled,

View file

@ -37,10 +37,6 @@ public class GnuDemanglerParserTest extends AbstractGenericTest {
parser = new GnuDemanglerParser(process);
}
/**
* This method just tries to demangled a bunch o'
* mangled names just checking for stack traces.
*/
@Test
public void test() throws Exception {
long start = System.currentTimeMillis();
@ -341,48 +337,6 @@ public class GnuDemanglerParserTest extends AbstractGenericTest {
assertEquals("float", parameters.get(0).toSignature());
}
@Test
public void testOperator() throws Exception {
String mangled = "_ZN6MagickltERKNS_10CoordinateES2_";
String demangled = process.demangle(mangled);
DemangledObject object = parser.parse(mangled, demangled);
assertTrue(object instanceof DemangledMethod);
assertName(object, "operator<", "Magick");
DemangledMethod method = (DemangledMethod) object;
assertEquals(
"undefined Magick::operator<(Magick::Coordinate const &,Magick::Coordinate const &)",
method.getSignature(false));
List<DemangledDataType> parameters = method.getParameters();
assertEquals(2, parameters.size());
assertEquals("Magick::Coordinate const &", parameters.get(0).toSignature());
assertEquals("Magick::Coordinate const &", parameters.get(1).toSignature());
}
@Test
public void testOperatorCastTo() throws Exception {
//
// Mangled: _ZNKSt17integral_constantIbLb0EEcvbEv
//
// Demangled: std::integral_constant<bool, false>::operator bool() const
String mangled = "_ZNKSt17integral_constantIbLb0EEcvbEv";
String demangled = process.demangle(mangled);
DemangledObject object = parser.parse(mangled, demangled);
assertNotNull(object);
assertTrue(object instanceof DemangledFunction);
String signature = object.getSignature(false);
assertEquals(
"bool std::integral_constant::operator.cast.to.bool(void)",
signature);
}
@Test
public void testFunctions() throws Exception {
String mangled = "_Z7toFloatidcls";
@ -713,6 +667,48 @@ public class GnuDemanglerParserTest extends AbstractGenericTest {
object.getSignature(false));
}
@Test
public void testOperator() throws Exception {
String mangled = "_ZN6MagickltERKNS_10CoordinateES2_";
String demangled = process.demangle(mangled);
DemangledObject object = parser.parse(mangled, demangled);
assertTrue(object instanceof DemangledMethod);
assertName(object, "operator<", "Magick");
DemangledMethod method = (DemangledMethod) object;
assertEquals(
"undefined Magick::operator<(Magick::Coordinate const &,Magick::Coordinate const &)",
method.getSignature(false));
List<DemangledDataType> parameters = method.getParameters();
assertEquals(2, parameters.size());
assertEquals("Magick::Coordinate const &", parameters.get(0).toSignature());
assertEquals("Magick::Coordinate const &", parameters.get(1).toSignature());
}
@Test
public void testOperatorCastTo() throws Exception {
//
// Mangled: _ZNKSt17integral_constantIbLb0EEcvbEv
//
// Demangled: std::integral_constant<bool, false>::operator bool() const
String mangled = "_ZNKSt17integral_constantIbLb0EEcvbEv";
String demangled = process.demangle(mangled);
DemangledObject object = parser.parse(mangled, demangled);
assertNotNull(object);
assertTrue(object instanceof DemangledFunction);
String signature = object.getSignature(false);
assertEquals(
"bool std::integral_constant::operator.cast.to.bool(void)",
signature);
}
@Test
public void testConversionOperator() throws Exception {
@ -738,6 +734,13 @@ public class GnuDemanglerParserTest extends AbstractGenericTest {
@Test
public void testConversionOperatorWithConst() throws Exception {
//
//
// Mangled: _ZN12_GLOBAL__N_120decode_charset_iconvEPKc
//
// Demangled: GCC_IndicationPDU::operator GCC_ApplicationInvokeIndication const&() const
//
//
// Converts the object upon which it is overridden to the given value.
//

View file

@ -488,6 +488,10 @@ public class ComponentPlaceholder {
/** Updates local actions for providers */
void contextChanged() {
if (componentProvider == null) {
return; // disposed
}
ActionContext actionContext = componentProvider.getActionContext(null);
if (actionContext == null) {
actionContext = new ActionContext(componentProvider, null);

View file

@ -60,17 +60,21 @@ public class ConcurrentTestExceptionStatement extends Statement {
}
private long getTestTimeout() {
String timeoutString =
System.getProperty(TEST_TIMEOUT_MILLIS_PROPERTY, Long.toString(TIMEOUT_MILLIS));
String timeoutOverrideString =
System.getProperty(TEST_TIMEOUT_MILLIS_PROPERTY, null);
if (timeoutOverrideString == null) {
return TIMEOUT_MILLIS;
}
try {
long timeout = Long.parseLong(timeoutString);
long timeout = Long.parseLong(timeoutOverrideString);
Msg.info(this, "Using test timeout override value " + timeout + "ms");
return timeout;
}
catch (NumberFormatException e) {
Msg.error(this,
"Unable to parse " + TEST_TIMEOUT_MILLIS_PROPERTY + " Long value '" +
timeoutString + "'");
timeoutOverrideString + "'");
}
return TIMEOUT_MILLIS;
}