mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-02-07 19:20:14 +00:00
GP-2184 - removed JMockit usage from some tests (part 4)
This commit is contained in:
parent
0e3fe30c67
commit
3ac7ecdb13
@ -190,7 +190,7 @@ public class GoToHelper {
|
||||
* @return true if navigation was successful or a list of possible linkage locations
|
||||
* was displayed.
|
||||
*/
|
||||
private boolean goToExternalLinkage(Navigatable nav, ExternalLocation externalLoc,
|
||||
protected boolean goToExternalLinkage(Navigatable nav, ExternalLocation externalLoc,
|
||||
boolean popupAllowed) {
|
||||
if (externalLoc == null) {
|
||||
return false;
|
||||
@ -457,10 +457,6 @@ public class GoToHelper {
|
||||
private Program findGoToProgram(Program currentProgram, Address address) {
|
||||
// we need to try and find a suitable program
|
||||
Program goToProgram = findProgramContaining(currentProgram, address);
|
||||
if (goToProgram == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return goToProgram;
|
||||
}
|
||||
|
||||
|
@ -15,7 +15,7 @@
|
||||
*/
|
||||
package ghidra.test;
|
||||
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
@ -115,7 +115,7 @@ public abstract class AbstractGhidraHeadlessIntegrationTest extends AbstractDock
|
||||
* Get the language and compiler spec associated with an old language name string. If the
|
||||
* language no longer exists, and suitable replacement language will be returned if found. If no
|
||||
* language is found, an exception will be thrown.
|
||||
*
|
||||
*
|
||||
* @param oldLanguageName old language name string
|
||||
* @return the language compiler and spec
|
||||
* @throws LanguageNotFoundException if the language is not found
|
||||
@ -138,7 +138,7 @@ public abstract class AbstractGhidraHeadlessIntegrationTest extends AbstractDock
|
||||
|
||||
/**
|
||||
* Creates an in-memory program with the given language
|
||||
*
|
||||
*
|
||||
* @param name the program name
|
||||
* @param languageString a language string of the format <code>x86:LE:32:default</code>
|
||||
* @param consumer a consumer for the program
|
||||
@ -157,7 +157,7 @@ public abstract class AbstractGhidraHeadlessIntegrationTest extends AbstractDock
|
||||
|
||||
/**
|
||||
* Creates an in-memory program with the given language
|
||||
*
|
||||
*
|
||||
* @param name the program name
|
||||
* @param languageString a language string of the format <code>x86:LE:32:default</code>
|
||||
* @param compilerSpecID the ID
|
||||
@ -236,7 +236,7 @@ public abstract class AbstractGhidraHeadlessIntegrationTest extends AbstractDock
|
||||
/**
|
||||
* Provides a convenient method for modifying the current program, handling the transaction
|
||||
* logic and returning a result.
|
||||
*
|
||||
*
|
||||
* @param <T> the return type
|
||||
* @param <E> the exception type
|
||||
* @param p the program
|
||||
@ -308,7 +308,7 @@ public abstract class AbstractGhidraHeadlessIntegrationTest extends AbstractDock
|
||||
|
||||
/**
|
||||
* Undo the last transaction on the domain object and wait for all events to be flushed.
|
||||
*
|
||||
*
|
||||
* @param dobj The domain object upon which to perform the undo.
|
||||
* @param wait if true, wait for undo to fully complete in Swing thread. If a modal dialog may
|
||||
* result from this undo, wait should be set false.
|
||||
@ -332,7 +332,7 @@ public abstract class AbstractGhidraHeadlessIntegrationTest extends AbstractDock
|
||||
|
||||
/**
|
||||
* Redo the last undone transaction on the domain object and wait for all events to be flushed.
|
||||
*
|
||||
*
|
||||
* @param dobj The domain object upon which to perform the redo.
|
||||
* @param wait if true, wait for redo to fully complete in Swing thread. If a modal dialog may
|
||||
* result from this redo, wait should be set false.
|
||||
@ -356,7 +356,7 @@ public abstract class AbstractGhidraHeadlessIntegrationTest extends AbstractDock
|
||||
|
||||
/**
|
||||
* Undo the last transaction on the domain object and wait for all events to be flushed.
|
||||
*
|
||||
*
|
||||
* @param dobj The domain object upon which to perform the undo.
|
||||
*/
|
||||
public static void undo(final UndoableDomainObject dobj) {
|
||||
@ -365,7 +365,7 @@ public abstract class AbstractGhidraHeadlessIntegrationTest extends AbstractDock
|
||||
|
||||
/**
|
||||
* Redo the last undone transaction on domain object and wait for all events to be flushed.
|
||||
*
|
||||
*
|
||||
* @param dobj The domain object upon which to perform the redo.
|
||||
*/
|
||||
public static void redo(final UndoableDomainObject dobj) {
|
||||
@ -375,7 +375,7 @@ public abstract class AbstractGhidraHeadlessIntegrationTest extends AbstractDock
|
||||
/**
|
||||
* Undo the last 'count' transactions on the domain object and wait for all events to be
|
||||
* flushed.
|
||||
*
|
||||
*
|
||||
* @param dobj The domain object upon which to perform the undo.
|
||||
* @param count number of transactions to undo
|
||||
*/
|
||||
@ -388,7 +388,7 @@ public abstract class AbstractGhidraHeadlessIntegrationTest extends AbstractDock
|
||||
/**
|
||||
* Redo the last 'count' undone transactions on the domain object and wait for all events to be
|
||||
* flushed.
|
||||
*
|
||||
*
|
||||
* @param dobj The domain object upon which to perform the redo.
|
||||
* @param count number of transactions to redo
|
||||
*/
|
||||
@ -514,7 +514,7 @@ public abstract class AbstractGhidraHeadlessIntegrationTest extends AbstractDock
|
||||
*
|
||||
* <P>
|
||||
* <B>Do not leave this call in your test when committing changes.</B>
|
||||
*
|
||||
*
|
||||
* @param p the program
|
||||
* @param address the address
|
||||
*
|
||||
@ -601,6 +601,11 @@ public abstract class AbstractGhidraHeadlessIntegrationTest extends AbstractDock
|
||||
}
|
||||
}
|
||||
|
||||
T instance = tool.getService(service);
|
||||
if (instance != null) {
|
||||
serviceManager.removeService(service, instance);
|
||||
}
|
||||
|
||||
set.add(replacement.getClass());
|
||||
serviceManager.addService(service, replacement);
|
||||
|
||||
@ -614,7 +619,7 @@ public abstract class AbstractGhidraHeadlessIntegrationTest extends AbstractDock
|
||||
|
||||
/**
|
||||
* Get language service used for testing.
|
||||
*
|
||||
*
|
||||
* @return language service.
|
||||
*/
|
||||
public synchronized static LanguageService getLanguageService() {
|
||||
|
@ -17,6 +17,8 @@ package ghidra.app.plugin.core.decompile;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
@ -29,14 +31,16 @@ import ghidra.app.actions.AbstractFindReferencesDataTypeAction;
|
||||
import ghidra.app.actions.AbstractFindReferencesToAddressAction;
|
||||
import ghidra.app.nav.Navigatable;
|
||||
import ghidra.app.plugin.core.decompile.actions.FindReferencesToHighSymbolAction;
|
||||
import ghidra.app.plugin.core.navigation.FindAppliedDataTypesService;
|
||||
import ghidra.app.plugin.core.navigation.locationreferences.LocationReferencesProvider;
|
||||
import ghidra.app.plugin.core.navigation.locationreferences.LocationReferencesService;
|
||||
import ghidra.app.services.*;
|
||||
import ghidra.program.model.data.DataType;
|
||||
import ghidra.program.model.listing.Program;
|
||||
import ghidra.program.util.ProgramLocation;
|
||||
import ghidra.util.HelpLocation;
|
||||
import ghidra.util.task.TaskMonitor;
|
||||
import mockit.*;
|
||||
import mockit.Mock;
|
||||
|
||||
public abstract class AbstractDecompilerFindReferencesActionTest extends AbstractDecompilerTest {
|
||||
|
||||
@ -44,8 +48,7 @@ public abstract class AbstractDecompilerFindReferencesActionTest extends Abstrac
|
||||
protected DockingActionIf findReferencesToSymbolAction;
|
||||
protected DockingActionIf findReferencesToAddressAction;
|
||||
|
||||
protected SpyDataTypeReferenceFinder<DataTypeReferenceFinder> spyReferenceFinder;
|
||||
protected SpyLocationReferencesService<LocationReferencesService> spyLocationReferenceService;
|
||||
protected SpyLocationReferencesService spyLocationReferenceService;
|
||||
|
||||
@Override
|
||||
@Before
|
||||
@ -63,18 +66,37 @@ public abstract class AbstractDecompilerFindReferencesActionTest extends Abstrac
|
||||
|
||||
private void installSpyDataTypeReferenceFinder() {
|
||||
|
||||
spyReferenceFinder = new SpyDataTypeReferenceFinder<>();
|
||||
replaceService(tool, DataTypeReferenceFinder.class, new StubDataTypeReferenceFinder());
|
||||
//
|
||||
// We replace services in order for us to spy on system internals. This gets tricky
|
||||
// because the LocationReferencesPlugin installs 2 services. So, when we replace it, we
|
||||
// lose both of it services. We only want to replace one of the services, so we have to
|
||||
// re-install the plugin to be the service provider for the service we still need.
|
||||
//
|
||||
FindAppliedDataTypesService fadService = tool.getService(FindAppliedDataTypesService.class);
|
||||
replaceService(tool, DataTypeReferenceFinder.class, new SpyDataTypeReferenceFinder());
|
||||
|
||||
spyLocationReferenceService = new SpyLocationReferencesService<>();
|
||||
LocationReferencesService lrService = tool.getService(LocationReferencesService.class);
|
||||
spyLocationReferenceService = new SpyLocationReferencesService(lrService);
|
||||
replaceService(tool, LocationReferencesService.class, spyLocationReferenceService);
|
||||
|
||||
// as noted above, put back this service implementation
|
||||
replaceService(tool, FindAppliedDataTypesService.class, fadService);
|
||||
}
|
||||
|
||||
protected void assertFindAllReferencesToCompositeFieldWasCalled() {
|
||||
|
||||
int last = SpyDataTypeReferenceFinder.instances.size() - 1;
|
||||
SpyDataTypeReferenceFinder spyReferenceFinder =
|
||||
SpyDataTypeReferenceFinder.instances.get(last);
|
||||
assertEquals(1, spyReferenceFinder.getFindCompositeFieldReferencesCallCount());
|
||||
assertEquals(0, spyReferenceFinder.getFindDataTypeReferencesCallCount());
|
||||
}
|
||||
|
||||
protected void assertFindAllReferencesToDataTypeWasCalled() {
|
||||
|
||||
int last = SpyDataTypeReferenceFinder.instances.size() - 1;
|
||||
SpyDataTypeReferenceFinder spyReferenceFinder =
|
||||
SpyDataTypeReferenceFinder.instances.get(last);
|
||||
assertEquals(0, spyReferenceFinder.getFindCompositeFieldReferencesCallCount());
|
||||
assertEquals(1, spyReferenceFinder.getFindDataTypeReferencesCallCount());
|
||||
}
|
||||
@ -152,11 +174,21 @@ public abstract class AbstractDecompilerFindReferencesActionTest extends Abstrac
|
||||
findReferencesAction.isAddToPopup(context));
|
||||
}
|
||||
|
||||
public class SpyDataTypeReferenceFinder<T extends DataTypeReferenceFinder> extends MockUp<T> {
|
||||
public static class SpyDataTypeReferenceFinder implements DataTypeReferenceFinder {
|
||||
|
||||
private static List<SpyDataTypeReferenceFinder> instances = new ArrayList<>();
|
||||
|
||||
private AtomicInteger dataTypeReferencesCallCount = new AtomicInteger();
|
||||
private AtomicInteger compositeFieldReferencesCallCount = new AtomicInteger();
|
||||
|
||||
public SpyDataTypeReferenceFinder() {
|
||||
|
||||
// Instances of this class are created by ReferenceUtils via the ClassSearcher. Save
|
||||
// the instances so we can use the spy in the test
|
||||
instances.add(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Mock
|
||||
public void findReferences(Program p, DataType dataType,
|
||||
Consumer<DataTypeReference> callback, TaskMonitor monitor) {
|
||||
@ -164,6 +196,7 @@ public abstract class AbstractDecompilerFindReferencesActionTest extends Abstrac
|
||||
dataTypeReferencesCallCount.incrementAndGet();
|
||||
}
|
||||
|
||||
@Override
|
||||
@Mock
|
||||
public void findReferences(Program p, DataType dt, String fieldName,
|
||||
Consumer<DataTypeReference> callback, TaskMonitor monitor) {
|
||||
@ -171,6 +204,7 @@ public abstract class AbstractDecompilerFindReferencesActionTest extends Abstrac
|
||||
compositeFieldReferencesCallCount.incrementAndGet();
|
||||
}
|
||||
|
||||
@Override
|
||||
@Mock
|
||||
public void findReferences(Program p, FieldMatcher fieldMatcher,
|
||||
Consumer<DataTypeReference> callback, TaskMonitor monitor) {
|
||||
@ -193,20 +227,30 @@ public abstract class AbstractDecompilerFindReferencesActionTest extends Abstrac
|
||||
}
|
||||
}
|
||||
|
||||
public class SpyLocationReferencesService<T extends LocationReferencesService>
|
||||
extends MockUp<T> {
|
||||
public class SpyLocationReferencesService implements LocationReferencesService {
|
||||
|
||||
private AtomicInteger showReferencesCallCount = new AtomicInteger();
|
||||
private LocationReferencesService lrService;
|
||||
|
||||
@Mock
|
||||
public void showReferencesToLocation(Invocation invocation, ProgramLocation location,
|
||||
Navigatable navigatable) {
|
||||
public SpyLocationReferencesService(LocationReferencesService lrService) {
|
||||
this.lrService = lrService;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void showReferencesToLocation(ProgramLocation location, Navigatable navigatable) {
|
||||
showReferencesCallCount.incrementAndGet();
|
||||
invocation.proceed(location, navigatable);
|
||||
lrService.showReferencesToLocation(location, navigatable);
|
||||
}
|
||||
|
||||
public int getShowReferencesCallCount() {
|
||||
return showReferencesCallCount.get();
|
||||
}
|
||||
|
||||
@Override
|
||||
public HelpLocation getHelpLocation() {
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -28,13 +28,14 @@ import ghidra.app.plugin.core.codebrowser.CodeViewerProvider;
|
||||
import ghidra.app.plugin.core.gotoquery.GoToHelper;
|
||||
import ghidra.app.plugin.core.navigation.NavigationOptions;
|
||||
import ghidra.app.plugin.core.navigation.NextPrevAddressPlugin;
|
||||
import ghidra.app.services.GoToService;
|
||||
import ghidra.app.util.navigation.GoToServiceImpl;
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.listing.*;
|
||||
import ghidra.program.model.symbol.*;
|
||||
import ghidra.program.util.OperandFieldLocation;
|
||||
import ghidra.program.util.ProgramLocation;
|
||||
import ghidra.test.ClassicSampleX86ProgramBuilder;
|
||||
import mockit.*;
|
||||
|
||||
public class DecompilerNavigationTest extends AbstractDecompilerTest {
|
||||
|
||||
@ -49,6 +50,23 @@ public class DecompilerNavigationTest extends AbstractDecompilerTest {
|
||||
tool.showComponentProvider(cbProvider, true);
|
||||
}
|
||||
|
||||
private void installSpyGoToHelper() {
|
||||
GoToHelper spyGoToHelper = new GoToHelper(tool) {
|
||||
|
||||
@Override
|
||||
protected boolean goToExternalLinkage(Navigatable nav, ExternalLocation externalLoc,
|
||||
boolean popupAllowed) {
|
||||
|
||||
goToExternalLinkageCalled = true;
|
||||
return super.goToExternalLinkage(nav, externalLoc, popupAllowed);
|
||||
}
|
||||
};
|
||||
|
||||
GoToServiceImpl goToServiceImpl = (GoToServiceImpl) tool.getService(GoToService.class);
|
||||
setInstanceField("helper", goToServiceImpl, spyGoToHelper);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Program getProgram() throws Exception {
|
||||
return buildProgram();
|
||||
@ -69,10 +87,10 @@ public class DecompilerNavigationTest extends AbstractDecompilerTest {
|
||||
public void testNavigation_ExternalEventDoesNotTriggerNavigation() {
|
||||
|
||||
//
|
||||
// Test to make sure that external ProgramLocationEvent notifications to not trigger
|
||||
// the Decompiler to broadcast a new event. Setup a tool with the Listing and
|
||||
// Test to make sure that external ProgramLocationEvent notifications to not trigger
|
||||
// the Decompiler to broadcast a new event. Setup a tool with the Listing and
|
||||
// the Decompiler open. Then, navigate in the Listing and verify the address does not
|
||||
// move. (This is somewhat subject to the Code Unit at the address in how the
|
||||
// move. (This is somewhat subject to the Code Unit at the address in how the
|
||||
// Decompiler itself responds to the incoming event.)
|
||||
//
|
||||
|
||||
@ -94,8 +112,7 @@ public class DecompilerNavigationTest extends AbstractDecompilerTest {
|
||||
public void testFunctionNavigation_ExternalProgramFunction_OptionNavigateToExternal()
|
||||
throws Exception {
|
||||
|
||||
// this call triggers jMockit to load our spy
|
||||
new SpyGoToHelper();
|
||||
installSpyGoToHelper();
|
||||
|
||||
tool.getOptions("Navigation")
|
||||
.setEnum("External Navigation",
|
||||
@ -107,7 +124,7 @@ public class DecompilerNavigationTest extends AbstractDecompilerTest {
|
||||
//
|
||||
|
||||
/*
|
||||
01005a32 e8 be d2 CALL ghidra
|
||||
01005a32 e8 be d2 CALL ghidra
|
||||
ff ff
|
||||
*/
|
||||
|
||||
@ -130,8 +147,7 @@ public class DecompilerNavigationTest extends AbstractDecompilerTest {
|
||||
public void testFunctionNavigation_ExternalProgramFunction_OptionNavigateToLinkage()
|
||||
throws Exception {
|
||||
|
||||
// this call triggers jMockit to load our spy
|
||||
new SpyGoToHelper();
|
||||
installSpyGoToHelper();
|
||||
|
||||
tool.getOptions("Navigation")
|
||||
.setEnum("External Navigation",
|
||||
@ -143,7 +159,7 @@ public class DecompilerNavigationTest extends AbstractDecompilerTest {
|
||||
//
|
||||
|
||||
/*
|
||||
01005a32 e8 be d2 CALL ghidra
|
||||
01005a32 e8 be d2 CALL ghidra
|
||||
ff ff
|
||||
*/
|
||||
|
||||
@ -178,15 +194,14 @@ public class DecompilerNavigationTest extends AbstractDecompilerTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFunctionNavigation_WithAViewThatCachesTheLastValidFunction()
|
||||
throws Exception {
|
||||
public void testFunctionNavigation_WithAViewThatCachesTheLastValidFunction() throws Exception {
|
||||
|
||||
//
|
||||
// This is testing the case where the user starts on a function foo(). Ancillary windows
|
||||
// will display tool, such as a decompiled view. Now, if the user clicks to a
|
||||
// non-function location, such as data, the ancillary window may still show foo(), even
|
||||
// will display tool, such as a decompiled view. Now, if the user clicks to a
|
||||
// non-function location, such as data, the ancillary window may still show foo(), even
|
||||
// though the user is no longer in foo. At this point, if the user wishes to go to the
|
||||
// previous function, then from the ancillary window's perspective, it is the function
|
||||
// previous function, then from the ancillary window's perspective, it is the function
|
||||
// that came before foo().
|
||||
//
|
||||
|
||||
@ -204,7 +219,7 @@ public class DecompilerNavigationTest extends AbstractDecompilerTest {
|
||||
provider.requestFocus();
|
||||
waitForSwing();
|
||||
|
||||
//
|
||||
//
|
||||
// The Decompiler is focused, showing 'entry'. Going back while it is focused should go
|
||||
// to the function before 'entry', which is 'ghidra'.
|
||||
//
|
||||
@ -282,15 +297,4 @@ public class DecompilerNavigationTest extends AbstractDecompilerTest {
|
||||
program.flushEvents();
|
||||
waitForSwing();
|
||||
}
|
||||
|
||||
public class SpyGoToHelper extends MockUp<GoToHelper> {
|
||||
|
||||
@Mock
|
||||
private boolean goToExternalLinkage(Invocation invocation, Navigatable nav,
|
||||
ExternalLocation externalLoc, boolean popupAllowed) {
|
||||
|
||||
goToExternalLinkageCalled = true;
|
||||
return invocation.proceed(nav, externalLoc, popupAllowed);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user