/* ### * 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.diff; import static org.junit.Assert.*; import java.awt.Color; import java.awt.Window; import java.math.BigInteger; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; import javax.swing.*; import javax.swing.tree.TreePath; import org.junit.Test; import docking.ActionContext; import docking.DialogComponentProvider; import docking.action.DockingActionIf; import docking.widgets.fieldpanel.FieldPanel; import docking.widgets.fieldpanel.support.FieldLocation; import ghidra.app.cmd.data.CreateDataCmd; import ghidra.app.events.ProgramLocationPluginEvent; import ghidra.app.events.ProgramSelectionPluginEvent; import ghidra.app.plugin.core.progmgr.MultiTabPanel; import ghidra.app.plugin.core.progmgr.MultiTabPlugin; import ghidra.app.util.viewer.field.OpenCloseField; import ghidra.app.util.viewer.listingpanel.ListingModel; import ghidra.framework.plugintool.Plugin; import ghidra.program.database.ProgramBuilder; import ghidra.program.database.ProgramDB; import ghidra.program.model.address.AddressSet; import ghidra.program.model.data.ArrayDataType; import ghidra.program.model.data.WordDataType; import ghidra.program.model.listing.*; import ghidra.program.util.ProgramLocation; import ghidra.program.util.ProgramSelection; public class DiffTest extends DiffTestAdapter { @Test public void testViewDiffsEnablement() throws Exception { getDiffActions(); assertNotNull(openClosePgm2); assertTrue(!openClosePgm2.isEnabled()); loadProgram(diffTestP1); assertTrue(openClosePgm2.isEnabled()); closeProgram(); assertTrue(!openClosePgm2.isEnabled()); } @Test public void testOpenDiffProgram() { programBuilderDiffTest1.createMemory("d4", "0x400", 0x100); programBuilderDiffTest2.createMemory("d2", "0x200", 0x100); openDiff(diffTestP1, diffTestP2); assertNotNull(fp2.getTopLevelAncestor()); ProgramSelection expectedSelection = new ProgramSelection(getSetupAllDiffsSet()); checkIfSameSelection(expectedSelection, diffPlugin.getDiffHighlightSelection()); // Check action enablement. assertTrue(viewDiffs.isEnabled()); assertTrue(!applyDiffs.isEnabled()); assertTrue(!applyDiffsNext.isEnabled()); assertTrue(!ignoreDiffs.isEnabled()); assertTrue(nextDiff.isEnabled()); assertTrue(!prevDiff.isEnabled()); assertTrue(diffDetails.isEnabled()); assertTrue(diffApplySettings.isEnabled()); assertTrue(getDiffs.isEnabled()); assertTrue(selectAllDiffs.isEnabled()); assertTrue(!setPgm2Selection.isEnabled()); // Check background color where there is and isn't a difference. setLocation("1009942"); FieldLocation cursorPosition = fp2.getCursorLocation(); BigInteger index = cursorPosition.getIndex(); Color bg = getBgColor(fp1, index); Color bg2 = getBgColor(fp2, index); assertEquals(bg, bg2); setLocation("100a002"); cursorPosition = fp2.getCursorLocation(); index = cursorPosition.getIndex(); bg = getBgColor(fp1, index); bg2 = getBgColor(fp2, index); assertEquals(bg, bg2); } @Test public void testCloseDiffProgram() throws Exception { programBuilderDiffTest1.createMemory("d4", "0x400", 0x100); programBuilderDiffTest2.createMemory("d2", "0x200", 0x100); openDiff(diffTestP1, diffTestP2); assertNotNull(fp2.getTopLevelAncestor()); closeDiff(); assertNull(diffListingPanel.getProgram()); } @Test public void testCancelDiff() throws Exception { // this latch lets us keep the diff from progressing until we are ready CountDownLatch latch = installDiffBlockingLatch(); programBuilderDiffTest1.createMemory("d4", "0x400", 0x100); programBuilderDiffTest2.createMemory("d2", "0x200", 0x100); loadProgram(diffTestP1); pickSecondProgram(diffTestP2); waitForTasks(); Window win = waitForWindow("Determine Program Differences"); pressButton(win, "OK"); win = waitForWindow("Checking Program Differences"); pressButton(win, "Cancel"); win = waitForWindow("Cancel?"); pressButton(win, "Yes"); // now that we have pressed cancel, it is safe to let the diff continue latch.countDown(); waitForCondition(() -> getWindow("Checking Program Differences") == null); } @Test public void testViewDiffsAction() throws Exception { programBuilderDiffTest1.createMemory("d4", "0x400", 0x100); programBuilderDiffTest2.createMemory("d2", "0x200", 0x100); loadProgram(diffTestP1); pickSecondProgram(diffTestP2); waitForTasks(); Window win = waitForWindow("Determine Program Differences"); pressButton(win, "Cancel"); getDiffActions(); invokeLater(viewDiffs); Window window = waitForWindow("Diff Already In Progress"); assertNotNull(window); pressButtonByText(window, "OK"); invokeLater(getDiffs); win = waitForWindow("Determine Program Differences"); pressButton(win, "OK"); waitForSwing(); waitForCondition(() -> getWindow("Checking Program Differences") == null); waitForTasks(); // this waits for the task and swing thread to finish posting results ProgramSelection expectedSelection = new ProgramSelection(getSetupAllDiffsSet()); checkIfSameSelection(expectedSelection, diffPlugin.getDiffHighlightSelection()); } @Test public void testNextDiffAction() { programBuilderDiffTest1.createMemory("d4", "0x400", 0x100); programBuilderDiffTest2.createMemory("d2", "0x200", 0x100); openDiff(diffTestP1, diffTestP2); assertNotNull(nextDiff); assertTrue(nextDiff.isEnabled()); assertEquals(addr("100"), getDiffAddress()); assertEquals(cb.getCurrentSelection(), new ProgramSelection()); invokeLater(nextDiff); assertEquals(addr("1001034"), getDiffAddress()); assertEquals(cb.getCurrentSelection(), new ProgramSelection(addr("1001034"), addr("1001034"))); } @Test public void testNextDiffAction2() { programBuilderDiffTest1.createMemory("d4", "0x400", 0x100); programBuilderDiffTest2.createMemory("d2", "0x200", 0x100); openDiff(diffTestP1, diffTestP2); assertNotNull(nextDiff); assertTrue(nextDiff.isEnabled()); tool.firePluginEvent(new ProgramLocationPluginEvent("test", new ProgramLocation(program, addr("1004c61")), program)); assertEquals(addr("1004c61"), getDiffAddress()); assertEquals(cb.getCurrentSelection(), new ProgramSelection()); invokeLater(nextDiff); assertEquals(addr("1005e4f"), getDiffAddress()); assertEquals(cb.getCurrentSelection(), new ProgramSelection(addr("1005e4f"), addr("1005e53"))); } @Test public void testPreviousDiffAction() { programBuilderDiffTest1.createMemory("d4", "0x400", 0x100); programBuilderDiffTest2.createMemory("d2", "0x200", 0x100); openDiff(diffTestP1, diffTestP2); assertNotNull(nextDiff); assertTrue(nextDiff.isEnabled()); tool.firePluginEvent(new ProgramLocationPluginEvent("test", new ProgramLocation(program, addr("100f3ff")), program)); assertEquals(addr("100f3ff"), getDiffAddress()); assertEquals(cb.getCurrentSelection(), new ProgramSelection()); invokeLater(prevDiff); assertEquals(addr("1005e4f"), getDiffAddress()); assertEquals(cb.getCurrentSelection(), new ProgramSelection(addr("1005e4f"), addr("1005e53"))); } @Test public void testPreviousDiffAction2() { programBuilderDiffTest1.createMemory("d4", "0x400", 0x100); programBuilderDiffTest2.createMemory("d2", "0x200", 0x100); openDiff(diffTestP1, diffTestP2); assertNotNull(nextDiff); assertTrue(nextDiff.isEnabled()); tool.firePluginEvent(new ProgramLocationPluginEvent("test", new ProgramLocation(program, addr("1004c61")), program)); assertEquals(addr("1004c61"), getDiffAddress()); assertEquals(cb.getCurrentSelection(), new ProgramSelection()); invokeLater(prevDiff); assertEquals(addr("100415a"), getDiffAddress()); assertEquals(cb.getCurrentSelection(), new ProgramSelection(addr("100415a"), addr("100415a"))); tool.firePluginEvent(new ProgramLocationPluginEvent("test", new ProgramLocation(program, addr("1002055")), program)); assertEquals(addr("1002055"), getDiffAddress()); invokeLater(prevDiff); assertEquals(addr("100204c"), getDiffAddress()); assertEquals(cb.getCurrentSelection(), new ProgramSelection(addr("100204c"), addr("100204c"))); } @Test public void testShowHideDiffDetails() { programBuilderDiffTest1.createMemory("d4", "0x400", 0x100); programBuilderDiffTest2.createMemory("d2", "0x200", 0x100); openDiff(diffTestP1, diffTestP2); assertNotNull(diffDetails); assertTrue(diffDetails.isEnabled()); tool.firePluginEvent(new ProgramLocationPluginEvent("test", new ProgramLocation(program, addr("1004c61")), program)); assertEquals(addr("1004c61"), getDiffAddress()); assertEquals(cb.getCurrentSelection(), new ProgramSelection()); assertEquals(false, isDiffDetailsDisplayed()); invokeLater(diffDetails); // show waitForSwing(); assertEquals(true, isDiffDetailsDisplayed()); runSwing(() -> { DiffDetailsProvider detailsProvider = diffPlugin.getDiffDetailsProvider(); detailsProvider.closeComponent(); // hide }, false); waitForSwing(); assertEquals(false, isDiffDetailsDisplayed()); } boolean isDiffDetailsDisplayed() { boolean shown = isProviderShown(tool.getToolFrame(), "Diff Details"); if (!shown) { return false; } JPanel detailsPanel = (JPanel) findComponentByName(tool.getToolFrame(), DiffDetailsProvider.DIFF_DETAILS_PANEL); return detailsPanel != null; } void checkDetails() { JPanel detailsPanel = (JPanel) findComponentByName(tool.getToolFrame(), "Diff Details Panel"); assertNotNull(detailsPanel); JTextArea textArea = (JTextArea) findComponentByName(detailsPanel, DiffDetailsProvider.DIFF_DETAILS_TEXT_AREA); assertNotNull(textArea); JCheckBox autoUpdateCB = (JCheckBox) findComponentByName(detailsPanel, DiffDetailsProvider.AUTO_UPDATE_CHECK_BOX); assertNotNull(autoUpdateCB); } @Test public void testDiffDetailsAction() { programBuilderDiffTest1.createMemory("d4", "0x400", 0x100); programBuilderDiffTest2.createMemory("d2", "0x200", 0x100); openDiff(diffTestP1, diffTestP2); assertNotNull(diffDetails); assertTrue(diffDetails.isEnabled()); tool.firePluginEvent(new ProgramLocationPluginEvent("test", new ProgramLocation(program, addr("100")), program)); assertEquals(addr("100"), getDiffAddress()); invokeLater(diffDetails); // Check where there are differences assertEquals(true, isDiffDetailsDisplayed()); JPanel detailsPanel = (JPanel) findComponentByName(tool.getToolFrame(), DiffDetailsProvider.DIFF_DETAILS_PANEL); assertNotNull(detailsPanel); JEditorPane textArea = (JEditorPane) findComponentByName(detailsPanel, DiffDetailsProvider.DIFF_DETAILS_TEXT_AREA); assertNotNull(textArea); String info = textArea.getText(); assertTrue(info.indexOf("Byte Diffs") != -1); assertTrue(info.indexOf("Bookmark Diffs") == -1); assertEquals(addr("100"), getDiffAddress()); tool.firePluginEvent(new ProgramLocationPluginEvent("test", new ProgramLocation(program, addr("1001014")), program)); assertEquals(addr("1001014"), getDiffAddress()); invokeLater(diffDetails); waitForSwing(); assertEquals(true, isDiffDetailsDisplayed()); // Check where there are no differences info = textArea.getText(); assertTrue(info.indexOf("No differences") != -1); assertEquals(addr("1001014"), getDiffAddress()); } @Test public void testSelectAllDiffsAction() { programBuilderDiffTest1.createMemory("d4", "0x400", 0x100); programBuilderDiffTest2.createMemory("d2", "0x200", 0x100); openDiff(diffTestP1, diffTestP2); assertNotNull(diffDetails); assertTrue(diffDetails.isEnabled()); invokeLater(selectAllDiffs); ProgramSelection expectedSelection = new ProgramSelection(getSetupAllDiffsSet()); checkIfSameSelection(expectedSelection, cb.getCurrentSelection()); } @Test public void testSetPgm2SelectionAction() { programBuilderDiffTest1.createMemory("d4", "0x400", 0x100); programBuilderDiffTest2.createMemory("d2", "0x200", 0x100); openDiff(diffTestP1, diffTestP2); assertNotNull(setPgm2Selection); assertTrue(!setPgm2Selection.isEnabled()); AddressSet as = new AddressSet(); as.addRange(addr("1001008"), addr("100103f")); as.addRange(addr("1001965"), addr("1001968")); as.addRange(addr("1002053"), addr("1002054")); as.addRange(addr("10022e9"), addr("1002309")); as.addRange(addr("100a000"), addr("100a006")); AddressSet diffAs = new AddressSet(); diffAs.addRange(addr("1001034"), addr("1001034")); diffAs.addRange(addr("10022ee"), addr("10022fc")); diffAs.addRange(addr("1002304"), addr("1002304")); diffAs.addRange(addr("1002306"), addr("1002306")); tool.firePluginEvent( new ProgramSelectionPluginEvent("test", new ProgramSelection(as), program)); tool.firePluginEvent(new ProgramLocationPluginEvent("test", new ProgramLocation(program, addr("1001000")), program)); assertTrue(setPgm2Selection.isEnabled()); invokeLater(setPgm2Selection); assertEquals(new ProgramSelection(diffAs), cb.getCurrentSelection()); } @Test public void testChangeToEntireViewWithDiff() throws Exception { programBuilderDiffTest1.createMemory("d4", "0x400", 0x100); programBuilderDiffTest2.createMemory("d2", "0x200", 0x100); openDiff(diffTestP1, diffTestP2); JTree tree = getProgramTree(); // Replace view with .data selectTreeNodeByText(tree, ".data"); invokeAndWait(replaceView); topOfFile(fp1); assertEquals(addr("1008000"), cb.getCurrentAddress()); bottomOfFile(fp1); assertEquals(addr("10085ff"), cb.getCurrentAddress()); // Replace with program view selectTreeNodeByText(tree, "DiffTestPgm1"); invokeAndWait(replaceView); topOfFile(fp1); assertEquals(addr("100"), cb.getCurrentAddress()); bottomOfFile(fp1); assertEquals(addr("100f3ff"), cb.getCurrentAddress()); assertEquals(new ProgramSelection(getSetupAllDiffsSet()), diffPlugin.getDiffHighlightSelection()); } @Test public void testDisplaySingleFragmentWithDiff() throws Exception { programBuilderDiffTest1.createMemory("d4", "0x400", 0x100); programBuilderDiffTest2.createMemory("d2", "0x200", 0x100); openDiff(diffTestP1, diffTestP2); JTree tree = getProgramTree(); selectTreeNodeByText(tree, ".data"); runSwing(() -> replaceView.actionPerformed(new ActionContext())); topOfFile(fp1); assertEquals(addr("1008000"), cb.getCurrentAddress()); bottomOfFile(fp1); assertEquals(addr("10085ff"), cb.getCurrentAddress()); assertEquals(new ProgramSelection(getSetupAllDiffsSet()), diffPlugin.getDiffHighlightSelection()); } @Test public void testDisplayMultipleFragmentsWithDiff() throws Exception { programBuilderDiffTest1.createMemory("d4", "0x400", 0x100); programBuilderDiffTest2.createMemory("d2", "0x200", 0x100); programBuilderDiffTest2.createComment("0x01008000", "My comment", CodeUnit.EOL_COMMENT); programBuilderDiffTest2.createComment("0x01008607", "My comment", CodeUnit.EOL_COMMENT); programBuilderDiffTest2.createComment("0x01008a99", "My comment", CodeUnit.EOL_COMMENT); programBuilderDiffTest2.createComment("0x0100a001", "My comment", CodeUnit.EOL_COMMENT); openDiff(diffTestP1, diffTestP2); JTree tree = getProgramTree(); selectTreeNodeByText(tree, ".data"); runSwing(() -> replaceView.actionPerformed(new ActionContext())); selectTreeNodeByText(tree, ".rsrc"); runSwing(() -> goToView.actionPerformed(new ActionContext())); topOfFile(fp1); assertEquals(addr("1008000"), cb.getCurrentAddress()); bottomOfFile(fp1); assertEquals(addr("100f3ff"), cb.getCurrentAddress()); AddressSet diffSet = new AddressSet(getSetupAllDiffsSet()); diffSet.add(addr("0x01008000")); diffSet.add(addr("0x01008607")); diffSet.add(addr("0x01008a99")); diffSet.add(addr("0x0100a001")); assertEquals(new ProgramSelection(diffSet), diffPlugin.getDiffHighlightSelection()); AddressSet viewSet = new AddressSet(); viewSet.addRange(addr("1008000"), addr("10085ff")); // .data viewSet.addRange(addr("100a000"), addr("100f3ff")); // .rsrc assertEquals(viewSet, cb.getView()); // top of View .rsrc cb.goTo(new ProgramLocation(program, addr("100a000"))); assertEquals(addr("100a000"), cb.getCurrentAddress()); assertEquals(addr("100a000"), getDiffAddress()); // Previous Diff should add .datau to the view invokeLater(prevDiff); waitForSwing(); viewSet.addRange(addr("1008600"), addr("1009943")); // .datau assertEquals(addr("1008a99"), cb.getCurrentAddress()); assertEquals(addr("1008a99"), getDiffAddress()); assertEquals(cb.getCurrentSelection(), new ProgramSelection(addr("1008a99"), addr("1008a99"))); assertEquals(viewSet, cb.getView()); // top of View .data topOfFile(fp1); assertEquals(addr("1008000"), cb.getCurrentAddress()); assertEquals(addr("1008000"), getDiffAddress()); // Previous Diff should add .text to the view invokeLater(prevDiff); viewSet.addRange(addr("1001000"), addr("10075ff")); assertEquals(addr("1005e4f"), cb.getCurrentAddress()); assertEquals(addr("1005e4f"), getDiffAddress()); assertEquals(cb.getCurrentSelection(), new ProgramSelection(addr("1005e4f"), addr("1005e53"))); assertEquals(viewSet, cb.getView()); } @Test public void testEmptyViewDiff() throws Exception { programBuilderDiffTest1.createMemory("d4", "0x400", 0x100); programBuilderDiffTest2.createMemory("d2", "0x200", 0x100); programBuilderDiffTest2.createComment("0x01008000", "My comment", CodeUnit.EOL_COMMENT); programBuilderDiffTest2.createComment("0x01008607", "My comment", CodeUnit.EOL_COMMENT); programBuilderDiffTest2.createComment("0x01009943", "My comment", CodeUnit.EOL_COMMENT); programBuilderDiffTest2.createComment("0x0100a001", "My comment", CodeUnit.EOL_COMMENT); openDiff(diffTestP1, diffTestP2); JTree tree = getProgramTree(); selectTreeNodeByText(tree, "DiffTestPgm1"); performAction(removeView, true); AddressSet viewSet = new AddressSet(); assertEquals(viewSet, cb.getView()); topOfFile(fp1); assertNull(cb.getCurrentAddress()); bottomOfFile(fp1); assertNull(cb.getCurrentAddress()); fp1.getHeight(); assertEquals(0, fp1.getLayoutModel().getNumIndexes().intValue()); assertEquals(0, fp2.getLayoutModel().getNumIndexes().intValue()); AddressSet diffSet = new AddressSet(getSetupAllDiffsSet()); diffSet.add(addr("0x01008000")); diffSet.add(addr("0x01008607")); diffSet.add(addr("0x01009943")); diffSet.add(addr("0x0100a001")); assertEquals(new ProgramSelection(diffSet), diffPlugin.getDiffHighlightSelection()); assertEquals(addr("100"), diffPlugin.getCurrentAddress()); assertEquals(addr("100"), getDiffAddress()); // Next Diff should add .text to the view invokeLater(nextDiff); viewSet.addRange(addr("1001000"), addr("10075ff")); assertEquals(addr("1001034"), cb.getCurrentAddress()); assertEquals(addr("1001034"), getDiffAddress()); assertEquals(cb.getCurrentSelection(), new ProgramSelection(addr("1001034"), addr("1001034"))); assertEquals(viewSet, cb.getView()); // bottom of View .text bottomOfFile(fp1); assertEquals(addr("10075ff"), cb.getCurrentAddress()); assertEquals(addr("10075ff"), getDiffAddress()); // Next Diff should add .data to the view invokeLater(nextDiff); waitForSwing(); viewSet.addRange(addr("1008000"), addr("10085ff")); assertEquals(addr("1008000"), cb.getCurrentAddress()); assertEquals(addr("1008000"), getDiffAddress()); assertEquals(cb.getCurrentSelection(), new ProgramSelection(addr("1008000"), addr("1008000"))); assertEquals(viewSet, cb.getView()); // bottom of View .data bottomOfFile(fp1); assertEquals(addr("10085ff"), cb.getCurrentAddress()); assertEquals(addr("10085ff"), getDiffAddress()); // Next Diff should add .datau to the view invokeLater(nextDiff); viewSet.addRange(addr("1008600"), addr("1009943")); assertEquals(addr("1008607"), cb.getCurrentAddress()); assertEquals(addr("1008607"), getDiffAddress()); assertEquals(cb.getCurrentSelection(), new ProgramSelection(addr("1008607"), addr("1008607"))); assertEquals(viewSet, cb.getView()); // bottom of View .datau bottomOfFile(fp1); assertEquals(addr("1009943"), cb.getCurrentAddress()); assertEquals(addr("1009943"), getDiffAddress()); // Next Diff should add .rsrc to the view invokeLater(nextDiff); viewSet.addRange(addr("100a000"), addr("100f3ff")); assertEquals(addr("100a001"), cb.getCurrentAddress()); assertEquals(addr("100a001"), getDiffAddress()); assertEquals(cb.getCurrentSelection(), new ProgramSelection(addr("100a001"), addr("100a001"))); assertEquals(viewSet, cb.getView()); } @Test public void testDiffWithChangeTabs() throws Exception { programBuilderDiffTest1.createMemory("d4", "0x400", 0x100); programBuilderDiffTest2.createMemory("d2", "0x200", 0x100); ProgramBuilder builder3 = new ProgramBuilder("Program3", ProgramBuilder._X86); builder3.createMemory(".text", "0x1001000", 0x6600); builder3.createMemory(".data", "0x1008000", 0x600); ProgramDB program3 = builder3.getProgram(); ProgramBuilder builder4 = new ProgramBuilder("Program4", ProgramBuilder._X86); builder4.createMemory(".text", "0x1001000", 0x6600); builder4.createMemory(".data", "0x1008000", 0x600); ProgramDB program4 = builder4.getProgram(); tool.removePlugins(new Plugin[] { pt }); tool.addPlugin(MultiTabPlugin.class.getName()); openProgram(program3); openProgram(program4); openProgram(diffTestP1); openDiff(diffTestP2); assertNotNull(fp2.getTopLevelAncestor()); ProgramSelection expectedSelection = new ProgramSelection(getSetupAllDiffsSet()); checkIfSameSelection(expectedSelection, diffPlugin.getDiffHighlightSelection()); MultiTabPanel panel = findComponent(tool.getToolFrame(), MultiTabPanel.class); assertEquals(true, isDiffing()); assertEquals(true, isShowingDiff()); // Check action enablement. checkDiffAction("View Program Differences", true, true); checkDiffAction("Open/Close Program View", true, true); checkDiffAction("Apply Differences", true, false); checkDiffAction("Apply Differences and Goto Next Difference", true, false); checkDiffAction("Ignore Selection and Goto Next Difference", true, false); checkDiffAction("Next Difference", true, true); checkDiffAction("Previous Difference", true, false); checkDiffAction("Show Diff Location Details", true, true); checkDiffAction("Show Diff Apply Settings", true, true); checkDiffAction("Get Differences", true, true); checkDiffAction("Select All Differences", true, true); checkDiffAction("Set Program1 Selection On Program2", true, false); // Check background color where there is and isn't a difference. setLocation("1002995"); assertEquals(addr("1002995"), diffPlugin.getCurrentAddress()); BigInteger index = fp2.getCursorLocation().getIndex(); Color bg = getBgColor(fp1, index); Color bg2 = getBgColor(fp2, index); assertEquals(bg, bg2); checkDiffAction("Next Difference", true, true); checkDiffAction("Previous Difference", true, true); setLocation("100299e"); index = fp2.getCursorLocation().getIndex(); assertEquals(addr("100299e"), diffPlugin.getCurrentAddress()); bg = getBgColor(fp1, index); bg2 = getBgColor(fp2, index); assertEquals(bg, bg2); checkDiffAction("Next Difference", true, true); checkDiffAction("Previous Difference", true, true); selectTab(panel, program3); assertEquals(true, isDiffing()); assertEquals(false, isShowingDiff()); // Check action enablement. checkDiffAction("View Program Differences", true, true); checkDiffAction("Apply Differences", false, false); checkDiffAction("Apply Differences and Goto Next Difference", false, false); checkDiffAction("Ignore Selection and Goto Next Difference", false, false); checkDiffAction("Next Difference", false, false); checkDiffAction("Previous Difference", false, false); checkDiffAction("Show Diff Location Details", false, false); checkDiffAction("Show Diff Apply Settings", false, false); checkDiffAction("Get Differences", false, false); checkDiffAction("Select All Differences", false, false); checkDiffAction("Set Program1 Selection On Program2", false, false); selectTab(panel, program4); assertEquals(true, isDiffing()); assertEquals(false, isShowingDiff()); // Check action enablement. checkDiffAction("View Program Differences", true, true); checkDiffAction("Apply Differences", false, false); checkDiffAction("Apply Differences and Goto Next Difference", false, false); checkDiffAction("Ignore Selection and Goto Next Difference", false, false); checkDiffAction("Next Difference", false, false); checkDiffAction("Previous Difference", false, false); checkDiffAction("Show Diff Location Details", false, false); checkDiffAction("Show Diff Apply Settings", false, false); checkDiffAction("Get Differences", false, false); checkDiffAction("Select All Differences", false, false); checkDiffAction("Set Program1 Selection On Program2", false, false); selectTab(panel, diffTestP1); assertEquals(true, isDiffing()); assertEquals(true, isShowingDiff()); assertEquals(addr("100299e"), diffPlugin.getCurrentAddress()); // Check action enablement. checkDiffAction("View Program Differences", true, true); checkDiffAction("Apply Differences", true, false); checkDiffAction("Apply Differences and Goto Next Difference", true, false); checkDiffAction("Ignore Selection and Goto Next Difference", true, false); checkDiffAction("Next Difference", true, true); checkDiffAction("Previous Difference", true, true); checkDiffAction("Show Diff Location Details", true, true); checkDiffAction("Show Diff Apply Settings", true, true); checkDiffAction("Get Differences", true, true); checkDiffAction("Select All Differences", true, true); checkDiffAction("Set Program1 Selection On Program2", true, false); // Now close the Diff. closeDiff(); assertNull(diffListingPanel.getProgram()); assertEquals(false, isDiffing()); assertEquals(false, isShowingDiff()); } @Test public void testOpenCloseProgramAction() throws Exception { programBuilderDiffTest1.createMemory("d4", "0x400", 0x100); programBuilderDiffTest2.createMemory("d2", "0x200", 0x100); ProgramBuilder builder3 = new ProgramBuilder("Program3", ProgramBuilder._X86); builder3.createMemory(".text", "0x1001000", 0x6600); builder3.createMemory(".data", "0x1008000", 0x600); ProgramDB program3 = builder3.getProgram(); ProgramBuilder builder4 = new ProgramBuilder("Program4", ProgramBuilder._X86); builder4.createMemory(".text", "0x1001000", 0x6600); builder4.createMemory(".data", "0x1008000", 0x600); ProgramDB program4 = builder4.getProgram(); tool.removePlugins(new Plugin[] { pt }); tool.addPlugin(MultiTabPlugin.class.getName()); openProgram(program3); openProgram(program4); openProgram(diffTestP1); openDiff(diffTestP2); assertNotNull(fp2.getTopLevelAncestor()); ProgramSelection expectedSelection = new ProgramSelection(getSetupAllDiffsSet()); checkIfSameSelection(expectedSelection, diffPlugin.getDiffHighlightSelection()); MultiTabPanel panel = findComponent(tool.getToolFrame(), MultiTabPanel.class); assertEquals(true, isDiffing()); assertEquals(true, isShowingDiff()); checkDiffAction("Open/Close Program View", true, true); // // Different tab--still enabled // selectTab(panel, program3); checkDiffAction("Open/Close Program View", true, true); clickDiffButton(); assertTrue("Not diffing after clicking the diff button when on a non-diff tab", isDiffing()); assertTrue("Diff not showing after clicking the diff button when on a non-diff tab", isShowingDiff()); // // Diff tab--still enabled // checkDiffAction("Open/Close Program View", true, true); clickDiffButton(); DialogComponentProvider dialogProvider = waitForDialogComponent("Close Diff Session"); assertNotNull("Did not get confirmation dialog", dialogProvider); pressButtonByText(dialogProvider.getComponent(), "Yes", true); waitForSwing(); assertFalse("Still diffing after clicking the diff button when on the diff tab", isDiffing()); assertFalse("Still showing diff after clicking the diff button when on the diff tab", isShowingDiff()); } @Test public void testOpenCloseArrayWithDiffShowing() throws Exception { programBuilderDiffTest1.createMemory("d4", "0x400", 0x100); programBuilderDiffTest2.createMemory("d2", "0x200", 0x100); openDiff(diffTestP1, diffTestP2); waitForSwing(); ArrayDataType array = new ArrayDataType(new WordDataType(), 12, 2); CreateDataCmd cmd = new CreateDataCmd(addr("0x00000106"), array); tool.execute(cmd, diffTestP1); Data data = diffTestP1.getListing().getDataAt(addr("0x00000106")); ListingModel listingModel = cb.getListingModel(); cb.goToField(addr("0x00000106"), "+", 0, 0); assertTrue(cb.getCurrentField() instanceof OpenCloseField); assertFalse("Array is not closed as expected.", listingModel.isOpen(data)); cb.goToField(addr("0x00000120"), "Address", 0, 0); assertEquals("00000120", cb.getCurrentFieldText()); cb.goToField(addr("0x00000106"), "Address", 0, 0); assertEquals("00000106", cb.getCurrentFieldText()); cb.goToField(addr("0x00000106"), "+", 0, 0); click(cb, 1); waitForSwing(); assertTrue("Array failed to open.", listingModel.isOpen(data)); cb.goToField(addr("0x00000106"), "+", 0, 0); click(cb, 1); waitForSwing(); cb.goToField(addr("0x00000120"), "Address", 0, 0); cb.goToField(addr("0x00000106"), "Address", 0, 0); assertEquals("00000106", cb.getCurrentFieldText()); assertFalse("Array failed to close.", listingModel.isOpen(data)); } //================================================================================================== // Private Methods //================================================================================================== private Color getBgColor(FieldPanel fp, BigInteger index) { return runSwing(() -> fp.getBackgroundColor(index)); } private CountDownLatch installDiffBlockingLatch() { final CountDownLatch continueLatch = new CountDownLatch(1); diffPlugin.setDiffTaskListener(inProgress -> { try { continueLatch.await(5, TimeUnit.SECONDS); } catch (InterruptedException e) { // shouldn't happen throw new RuntimeException("Unexpectedly interrupted while blocking the diff task!", e); } }); return continueLatch; } private void clickDiffButton() { runSwing(() -> { openClosePgm2.setSelected(!openClosePgm2.isSelected()); openClosePgm2.actionPerformed(new ActionContext()); }, false); waitForSwing(); } /** * Checks that the specified Diff action is in the indicated state and * causes a JUnit assert if not. * * @param actionName the name of the DIff action. * @param inTool the action is currently added to the tool. * @param enabled the action is enabled. */ private void checkDiffAction(String actionName, boolean inTool, boolean enabled) { DockingActionIf tmpAction = getAction(diffPlugin, actionName); if (inTool) { if (tmpAction == null) { assertNotNull("Diff action, " + actionName + ", was not in the tool as expected.", tmpAction); } } else { if (tmpAction != null) { assertNull("Diff action, " + actionName + ", was unexpectedly found in the tool.", tmpAction); } } if (tmpAction == null) { return; } assertEquals("Diff action, " + actionName + ", was unexpectedly " + (enabled ? "disabled" : "enabled") + ".", enabled, tmpAction.isEnabled()); } private boolean isDiffing() { if (diffPlugin == null) { return false; } if (diffPlugin.getFirstProgram() == null || diffPlugin.getDiffController() == null) { return false; } return true; } private boolean isShowingDiff() { if (diffPlugin == null) { return false; } Program currentProgram = diffPlugin.getCurrentProgram(); Program firstProgram = diffPlugin.getFirstProgram(); if (currentProgram == null || currentProgram != firstProgram) { return false; } return true; } private void selectTab(final MultiTabPanel panel, final Program pgm) { runSwing(() -> invokeInstanceMethod("setSelectedProgram", panel, new Class[] { Program.class }, new Object[] { pgm }), true); waitForSwing(); } private void selectTreeNodeByText(final JTree tree, final String text) throws Exception { runSwing(() -> { TreePath path = findTreePathToText(tree, text); if (path == null) { throw new RuntimeException("tree path is null."); } tree.expandPath(path); }); waitForSwing(); runSwing(() -> { TreePath path = findTreePathToText(tree, text); if (path == null) { throw new RuntimeException("tree path is null."); } tree.getSelectionModel().setSelectionPath(path); }); } }