From 4dc8e77172f9462f977d95ca5eebe1f9068fac75 Mon Sep 17 00:00:00 2001
From: dragonmacher <48328597+dragonmacher@users.noreply.github.com>
Date: Wed, 14 Aug 2019 15:08:37 -0400
Subject: [PATCH] GT-3035 - Restore Integration Tests - restored missing test
files; fast tests
---
.../app/util/PseudoDisassemblerTest.java | 74 +
.../widgets/imagepanel/ImagePanelTest.java | 122 ++
.../textfield/HexOrDecimalInputTest.java | 519 ++++++
.../textfield/IntegerTextFieldTest.java | 290 ++++
.../util/task/TaskMonitorSplitterTest.java | 67 +
.../src/test/java/help/AbstractHelpTest.java | 196 +++
.../test/java/help/HelpBuildUtilsTest.java | 99 ++
.../test/java/help/OverlayHelpTreeTest.java | 418 +++++
.../HelpModuleLocationTestDouble.java | 28 +
.../validator/model/AnchorDefinitionTest.java | 70 +
.../model/GhidraTOCFileTestDouble.java | 28 +
.../help/validator/model/HelpFileTest.java | 307 ++++
.../MyHeadlessGraphicsEnvironment.java | 94 +
.../app/util/headless/MyHeadlessToolkit.java | 195 +++
.../plugintool/PluginManagerTest.java | 313 ++++
.../framework/plugintool/TestingPlugin.java | 23 +
.../testplugins/CircularPluginA.java | 40 +
.../testplugins/CircularPluginB.java | 40 +
.../testplugins/CircularServiceA.java | 27 +
.../testplugins/CircularServiceB.java | 27 +
.../testplugins/DiamondPluginA.java | 47 +
.../testplugins/DiamondPluginB.java | 48 +
.../testplugins/DiamondPluginC.java | 48 +
.../testplugins/DiamondPluginD.java | 46 +
.../testplugins/DiamondServiceB.java | 34 +
.../testplugins/DiamondServiceC.java | 34 +
.../testplugins/DiamondServiceD.java | 34 +
.../testplugins/DisposeFailPluginA.java | 46 +
.../testplugins/InitFailPluginA.java | 46 +
.../testplugins/InitFailPluginB.java | 52 +
.../testplugins/InitFailServiceB.java | 27 +
.../testplugins/IsolatedFailPluginA.java | 39 +
.../testplugins/IsolatedFailPluginB.java | 45 +
.../testplugins/MissingDepPluginA.java | 41 +
.../testplugins/MissingDepPluginB.java | 41 +
.../testplugins/MissingDepServiceB.java | 28 +
.../testplugins/NameConflictingPlugin.java | 41 +
.../secondconflict/NameConflictingPlugin.java | 41 +
.../program/disassemble/DisassemblerTest.java | 1534 +++++++++++++++++
.../model/lang/RegisterValueContextTest.java | 121 ++
.../program/model/lang/RegisterValueTest.java | 162 ++
.../server/RepositoryFileSystemTest.java | 428 +++++
.../ghidra/server/RepositoryManagerTest.java | 213 +++
.../java/ghidra/server/RepositoryTest.java | 144 ++
.../util/task/CachingSwingWorkerTest.java | 292 ++++
45 files changed, 6609 insertions(+)
create mode 100644 Ghidra/Features/Base/src/test.slow/java/ghidra/app/util/PseudoDisassemblerTest.java
create mode 100644 Ghidra/Framework/Docking/src/test.slow/java/docking/widgets/imagepanel/ImagePanelTest.java
create mode 100644 Ghidra/Framework/Docking/src/test.slow/java/docking/widgets/textfield/HexOrDecimalInputTest.java
create mode 100644 Ghidra/Framework/Docking/src/test.slow/java/docking/widgets/textfield/IntegerTextFieldTest.java
create mode 100644 Ghidra/Framework/Docking/src/test/java/ghidra/util/task/TaskMonitorSplitterTest.java
create mode 100644 Ghidra/Framework/Help/src/test/java/help/AbstractHelpTest.java
create mode 100644 Ghidra/Framework/Help/src/test/java/help/HelpBuildUtilsTest.java
create mode 100644 Ghidra/Framework/Help/src/test/java/help/OverlayHelpTreeTest.java
create mode 100644 Ghidra/Framework/Help/src/test/java/help/validator/location/HelpModuleLocationTestDouble.java
create mode 100644 Ghidra/Framework/Help/src/test/java/help/validator/model/AnchorDefinitionTest.java
create mode 100644 Ghidra/Framework/Help/src/test/java/help/validator/model/GhidraTOCFileTestDouble.java
create mode 100644 Ghidra/Framework/Help/src/test/java/help/validator/model/HelpFileTest.java
create mode 100644 Ghidra/Test/IntegrationTest/src/test.slow/java/ghidra/app/util/headless/MyHeadlessGraphicsEnvironment.java
create mode 100644 Ghidra/Test/IntegrationTest/src/test.slow/java/ghidra/app/util/headless/MyHeadlessToolkit.java
create mode 100644 Ghidra/Test/IntegrationTest/src/test.slow/java/ghidra/framework/plugintool/PluginManagerTest.java
create mode 100644 Ghidra/Test/IntegrationTest/src/test.slow/java/ghidra/framework/plugintool/TestingPlugin.java
create mode 100644 Ghidra/Test/IntegrationTest/src/test.slow/java/ghidra/framework/plugintool/testplugins/CircularPluginA.java
create mode 100644 Ghidra/Test/IntegrationTest/src/test.slow/java/ghidra/framework/plugintool/testplugins/CircularPluginB.java
create mode 100644 Ghidra/Test/IntegrationTest/src/test.slow/java/ghidra/framework/plugintool/testplugins/CircularServiceA.java
create mode 100644 Ghidra/Test/IntegrationTest/src/test.slow/java/ghidra/framework/plugintool/testplugins/CircularServiceB.java
create mode 100644 Ghidra/Test/IntegrationTest/src/test.slow/java/ghidra/framework/plugintool/testplugins/DiamondPluginA.java
create mode 100644 Ghidra/Test/IntegrationTest/src/test.slow/java/ghidra/framework/plugintool/testplugins/DiamondPluginB.java
create mode 100644 Ghidra/Test/IntegrationTest/src/test.slow/java/ghidra/framework/plugintool/testplugins/DiamondPluginC.java
create mode 100644 Ghidra/Test/IntegrationTest/src/test.slow/java/ghidra/framework/plugintool/testplugins/DiamondPluginD.java
create mode 100644 Ghidra/Test/IntegrationTest/src/test.slow/java/ghidra/framework/plugintool/testplugins/DiamondServiceB.java
create mode 100644 Ghidra/Test/IntegrationTest/src/test.slow/java/ghidra/framework/plugintool/testplugins/DiamondServiceC.java
create mode 100644 Ghidra/Test/IntegrationTest/src/test.slow/java/ghidra/framework/plugintool/testplugins/DiamondServiceD.java
create mode 100644 Ghidra/Test/IntegrationTest/src/test.slow/java/ghidra/framework/plugintool/testplugins/DisposeFailPluginA.java
create mode 100644 Ghidra/Test/IntegrationTest/src/test.slow/java/ghidra/framework/plugintool/testplugins/InitFailPluginA.java
create mode 100644 Ghidra/Test/IntegrationTest/src/test.slow/java/ghidra/framework/plugintool/testplugins/InitFailPluginB.java
create mode 100644 Ghidra/Test/IntegrationTest/src/test.slow/java/ghidra/framework/plugintool/testplugins/InitFailServiceB.java
create mode 100644 Ghidra/Test/IntegrationTest/src/test.slow/java/ghidra/framework/plugintool/testplugins/IsolatedFailPluginA.java
create mode 100644 Ghidra/Test/IntegrationTest/src/test.slow/java/ghidra/framework/plugintool/testplugins/IsolatedFailPluginB.java
create mode 100644 Ghidra/Test/IntegrationTest/src/test.slow/java/ghidra/framework/plugintool/testplugins/MissingDepPluginA.java
create mode 100644 Ghidra/Test/IntegrationTest/src/test.slow/java/ghidra/framework/plugintool/testplugins/MissingDepPluginB.java
create mode 100644 Ghidra/Test/IntegrationTest/src/test.slow/java/ghidra/framework/plugintool/testplugins/MissingDepServiceB.java
create mode 100644 Ghidra/Test/IntegrationTest/src/test.slow/java/ghidra/framework/plugintool/testplugins/NameConflictingPlugin.java
create mode 100644 Ghidra/Test/IntegrationTest/src/test.slow/java/ghidra/framework/plugintool/testplugins/secondconflict/NameConflictingPlugin.java
create mode 100644 Ghidra/Test/IntegrationTest/src/test.slow/java/ghidra/program/disassemble/DisassemblerTest.java
create mode 100644 Ghidra/Test/IntegrationTest/src/test/java/ghidra/program/model/lang/RegisterValueContextTest.java
create mode 100644 Ghidra/Test/IntegrationTest/src/test/java/ghidra/program/model/lang/RegisterValueTest.java
create mode 100644 Ghidra/Test/IntegrationTest/src/test/java/ghidra/server/RepositoryFileSystemTest.java
create mode 100644 Ghidra/Test/IntegrationTest/src/test/java/ghidra/server/RepositoryManagerTest.java
create mode 100644 Ghidra/Test/IntegrationTest/src/test/java/ghidra/server/RepositoryTest.java
create mode 100644 Ghidra/Test/IntegrationTest/src/test/java/ghidra/util/task/CachingSwingWorkerTest.java
diff --git a/Ghidra/Features/Base/src/test.slow/java/ghidra/app/util/PseudoDisassemblerTest.java b/Ghidra/Features/Base/src/test.slow/java/ghidra/app/util/PseudoDisassemblerTest.java
new file mode 100644
index 0000000000..5425838862
--- /dev/null
+++ b/Ghidra/Features/Base/src/test.slow/java/ghidra/app/util/PseudoDisassemblerTest.java
@@ -0,0 +1,74 @@
+/* ###
+ * 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.util;
+
+import static org.junit.Assert.assertEquals;
+
+import org.junit.*;
+
+import ghidra.program.database.ProgramBuilder;
+import ghidra.program.model.listing.Program;
+import ghidra.test.AbstractGhidraHeadlessIntegrationTest;
+
+public class PseudoDisassemblerTest extends AbstractGhidraHeadlessIntegrationTest {
+
+ private ProgramBuilder programBuilder;// Instructions are 2-byte aligned
+ private Program program;
+ private PseudoDisassembler disassembler;
+
+ private int txId;
+
+ @Before
+ public void setUp() throws Exception {
+ programBuilder = new ProgramBuilder("Test", ProgramBuilder._ARM);
+ program = programBuilder.getProgram();
+ txId = program.startTransaction("Add Memory");// leave open until tearDown
+ programBuilder.createMemory(".text", "0", 64).setExecute(true);// initialized
+ programBuilder.createUninitializedMemory(".unint", "0x40", 64).setExecute(true);// uninitialized
+ programBuilder.createUninitializedMemory(".dat", "0x80", 64);// no-execute
+ programBuilder.createMemory(".text2", "0x3e0", 0x800).setExecute(true);// initialized
+
+ disassembler = new PseudoDisassembler(program);
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ if (program != null) {
+ program.endTransaction(txId, true);
+ }
+ if (programBuilder != null) {
+ programBuilder.dispose();
+ }
+ }
+
+ @Test
+ public void testToStringArmSeparator() throws Exception {
+ programBuilder.setBytes("0", "08 f8 00 00 40 00");// strb.w r0,[r8,r0,0x0]
+ programBuilder.setRegisterValue("TMode", "0", "1", 1);
+ PseudoInstruction instr =
+ disassembler.disassemble(program.getAddressFactory().getAddress("0"));
+
+ String str = instr.toString();
+ assertEquals("strb.w r0,[r8,r0,lsl #0x0]", str);// wan't to make sure all markup is printed
+
+ programBuilder.setBytes("0", "00 f0 20 03");// nopeq
+ programBuilder.setRegisterValue("TMode", "0", "1", 0);
+ instr = disassembler.disassemble(program.getAddressFactory().getAddress("0"));
+
+ str = instr.toString();
+ assertEquals("nopeq", str);
+ }
+}
diff --git a/Ghidra/Framework/Docking/src/test.slow/java/docking/widgets/imagepanel/ImagePanelTest.java b/Ghidra/Framework/Docking/src/test.slow/java/docking/widgets/imagepanel/ImagePanelTest.java
new file mode 100644
index 0000000000..3ad663baa5
--- /dev/null
+++ b/Ghidra/Framework/Docking/src/test.slow/java/docking/widgets/imagepanel/ImagePanelTest.java
@@ -0,0 +1,122 @@
+/* ###
+ * 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.imagepanel;
+
+import static org.junit.Assert.assertTrue;
+
+import java.awt.Image;
+
+import javax.swing.Icon;
+import javax.swing.JFrame;
+
+import org.junit.*;
+
+import docking.test.AbstractDockingTest;
+import resources.ResourceManager;
+import resources.icons.EmptyIcon;
+
+public class ImagePanelTest extends AbstractDockingTest {
+
+ private JFrame frame;
+ private ImagePanel imagePanel;
+
+ @Before
+ public void setUp() throws Exception {
+ Icon emptyIcon = new EmptyIcon(32, 32);
+ Image emptyImage = ResourceManager.getImageIcon(emptyIcon).getImage();
+ imagePanel = new ImagePanel(emptyImage);
+
+ frame = new JFrame("ImagePanel Test");
+ frame.getContentPane().add(imagePanel);
+ frame.setSize(400, 400);
+
+ frame.setVisible(true);
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ frame.dispose();
+ }
+
+ private void reset() {
+ imagePanel.setZoomFactor(1.0f);
+
+ assertTrue("Unable to reset zoom factor",
+ Float.compare(imagePanel.getZoomFactor(), 1.0f) == 0);
+
+ }
+
+ @Test
+ public void testZoom_Neutral() {
+ reset();
+
+ imagePanel.setZoomFactor(1.0f);
+
+ assertTrue("Zoom factor not set to 1.0x",
+ Float.compare(imagePanel.getZoomFactor(), 1.0f) == 0);
+ }
+
+ @Test
+ public void testZoom_10Point0f() {
+ reset();
+
+ imagePanel.setZoomFactor(10.0f);
+
+ assertTrue("Zoom factor not set to 10.0x",
+ Float.compare(imagePanel.getZoomFactor(), 10.0f) == 0);
+ }
+
+ @Test
+ public void testZoom_0Point05() {
+ reset();
+
+ imagePanel.setZoomFactor(0.05f);
+
+ assertTrue("Zoom factor not set to 0.05x",
+ Float.compare(imagePanel.getZoomFactor(), 0.05f) == 0);
+ }
+
+ @Test
+ public void testZoom_20Point0() {
+ reset();
+
+ imagePanel.setZoomFactor(20.0f);
+
+ assertTrue("Zoom factor not set to 20.0x; should be 10.0x",
+ Float.compare(imagePanel.getZoomFactor(), 10.0f) == 0);
+ }
+
+ @Test
+ public void testZoom_0Point001() {
+ reset();
+
+ imagePanel.setZoomFactor(0.001f);
+
+ assertTrue("Zoom factor not set to 0.001x; should be 0.05x",
+ Float.compare(imagePanel.getZoomFactor(), 0.05f) == 0);
+ }
+
+ @Test
+ public void testZoom_3Point75() {
+ reset();
+
+ imagePanel.setZoomFactor(3.75f);
+
+ assertTrue("Zoom factor not set to 3.75x; should be 4.0x",
+ Float.compare(imagePanel.getZoomFactor(), 4.0f) == 0);
+ }
+
+}
diff --git a/Ghidra/Framework/Docking/src/test.slow/java/docking/widgets/textfield/HexOrDecimalInputTest.java b/Ghidra/Framework/Docking/src/test.slow/java/docking/widgets/textfield/HexOrDecimalInputTest.java
new file mode 100644
index 0000000000..b3a8f904c9
--- /dev/null
+++ b/Ghidra/Framework/Docking/src/test.slow/java/docking/widgets/textfield/HexOrDecimalInputTest.java
@@ -0,0 +1,519 @@
+/* ###
+ * 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.textfield;
+
+import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.CoreMatchers.nullValue;
+import static org.junit.Assert.assertThat;
+
+import java.awt.*;
+import java.awt.RenderingHints.Key;
+import java.awt.event.KeyEvent;
+import java.awt.event.KeyListener;
+import java.awt.font.FontRenderContext;
+import java.awt.font.GlyphVector;
+import java.awt.geom.AffineTransform;
+import java.awt.image.*;
+import java.awt.image.renderable.RenderableImage;
+import java.io.ByteArrayOutputStream;
+import java.io.PrintStream;
+import java.text.AttributedCharacterIterator;
+import java.util.Map;
+
+import javax.swing.DebugGraphics;
+import javax.swing.RepaintManager;
+
+import org.hamcrest.CoreMatchers;
+import org.junit.Test;
+
+public class HexOrDecimalInputTest {
+
+ @Test
+ public void testSetAllowNegative() {
+ HexOrDecimalInput input = new HexOrDecimalInput();
+
+ Long newValue = -1L;
+ input.setValue(newValue);
+
+ assertThat(input.getValue(), is(newValue));
+
+ input.setAllowNegative(false);
+ assertThat(input.getValue(), nullValue());
+
+ newValue = 20L;
+ input.setValue(newValue);
+ assertThat(input.getValue(), is(newValue));
+
+ newValue = -100L;
+ input.setValue(newValue);
+ assertThat(input.getValue(), nullValue());
+
+ input.setAllowNegative(true);
+ newValue = -100L;
+ input.setValue(newValue);
+ assertThat(input.getValue(), is(newValue));
+ }
+
+ @Test
+ public void testCustomPaint() {
+
+ HexOrDecimalInput input = new HexOrDecimalInput();
+ RepaintManager repaintManager = RepaintManager.currentManager(input);
+ repaintManager.setDoubleBufferingEnabled(false);
+
+ SpyPrintStream spy = new SpyPrintStream();
+ DebugGraphics.setLogStream(spy);
+
+ DebugGraphics debugGraphics = new DebugGraphics(scratchGraphics());
+ debugGraphics.setDebugOptions(DebugGraphics.LOG_OPTION);
+
+ Graphics2D g2d = new Graphics2DAdapter(debugGraphics);
+ input.paintComponent(g2d);
+ assertThat(spy.toString(), CoreMatchers.containsString("Dec"));
+
+ spy.reset();
+ input.setHexMode();
+ input.paintComponent(g2d);
+ assertThat(spy.toString(), CoreMatchers.containsString("Hex"));
+
+ spy.reset();
+ input.setDecimalMode();
+ input.paintComponent(g2d);
+ assertThat(spy.toString(), CoreMatchers.containsString("Dec"));
+ }
+
+ @Test
+ public void testToggleHexModeFromKeybinding() {
+ HexOrDecimalInput input = new HexOrDecimalInput();
+ Long value = 10L;
+ input.setValue(value);
+
+ assertThat(input.getValue(), is(value));
+
+ toggleMode(input);
+
+ assertThat(input.getValue(), is(0xAL));
+
+ toggleMode(input);
+
+ assertThat(input.getValue(), is(value));
+ }
+
+//==================================================================================================
+// Inner Classes
+//==================================================================================================
+
+ private void toggleMode(final HexOrDecimalInput input) {
+ KeyEvent event = new KeyEvent(input, 0, System.currentTimeMillis(), 0, KeyEvent.VK_M, 'm');
+ KeyListener[] keyListeners = input.getKeyListeners();
+ for (KeyListener listener : keyListeners) {
+ listener.keyPressed(event);
+ }
+ }
+
+ private Graphics scratchGraphics() {
+ BufferedImage image = new BufferedImage(100, 20, BufferedImage.TYPE_INT_BGR);
+ return image.getGraphics();
+ }
+
+ private static class SpyPrintStream extends PrintStream {
+ private static ByteArrayOutputStream baos = new ByteArrayOutputStream();
+
+ SpyPrintStream() {
+ super(baos);
+ }
+
+ void reset() {
+ baos.reset();
+ }
+
+ @Override
+ public String toString() {
+ return baos.toString();
+ }
+ }
+
+ /**
+ * An adapter to turn a Graphics into a Graphics2D. This implementation satisfies the base
+ * methods needed for the test. So, many operations are stubbed or are exceptional.
+ */
+ private static class Graphics2DAdapter extends Graphics2D {
+
+ private Graphics delegate;
+
+ Graphics2DAdapter(Graphics g) {
+ this.delegate = g;
+ }
+
+ @Override
+ public void draw(Shape s) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public boolean drawImage(Image img, AffineTransform xform, ImageObserver obs) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void drawImage(BufferedImage img, BufferedImageOp op, int x, int y) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void drawRenderedImage(RenderedImage img, AffineTransform xform) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void drawRenderableImage(RenderableImage img, AffineTransform xform) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void drawString(String str, int x, int y) {
+ delegate.drawString(str, x, y);
+ }
+
+ @Override
+ public void drawString(String str, float x, float y) {
+ delegate.drawString(str, (int) x, (int) y);
+ }
+
+ @Override
+ public void drawString(AttributedCharacterIterator iterator, int x, int y) {
+ delegate.drawString(iterator, x, y);
+ }
+
+ @Override
+ public void drawString(AttributedCharacterIterator iterator, float x, float y) {
+ delegate.drawString(iterator, (int) x, (int) y);
+ }
+
+ @Override
+ public void drawGlyphVector(GlyphVector g, float x, float y) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void fill(Shape s) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public boolean hit(Rectangle rect, Shape s, boolean onStroke) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public GraphicsConfiguration getDeviceConfiguration() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void setComposite(Composite comp) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void setPaint(Paint paint) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void setStroke(Stroke s) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void setRenderingHint(Key hintKey, Object hintValue) {
+ // no-op
+ }
+
+ @Override
+ public Object getRenderingHint(Key hintKey) {
+ return null;
+ }
+
+ @Override
+ public void setRenderingHints(Map, ?> hints) {
+ // no-op
+ }
+
+ @Override
+ public void addRenderingHints(Map, ?> hints) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public RenderingHints getRenderingHints() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void translate(int x, int y) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void translate(double tx, double ty) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void rotate(double theta) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void rotate(double theta, double x, double y) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void scale(double sx, double sy) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void shear(double shx, double shy) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void transform(AffineTransform Tx) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void setTransform(AffineTransform Tx) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public AffineTransform getTransform() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Paint getPaint() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Composite getComposite() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void setBackground(Color color) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Color getBackground() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Stroke getStroke() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void clip(Shape s) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public FontRenderContext getFontRenderContext() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Graphics create() {
+ return delegate.create();
+ }
+
+ @Override
+ public Color getColor() {
+ return delegate.getColor();
+ }
+
+ @Override
+ public void setColor(Color c) {
+ delegate.setColor(c);
+ }
+
+ @Override
+ public void setPaintMode() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void setXORMode(Color c1) {
+ delegate.setXORMode(c1);
+ }
+
+ @Override
+ public Font getFont() {
+ return delegate.getFont();
+ }
+
+ @Override
+ public void setFont(Font font) {
+ delegate.setFont(font);
+ }
+
+ @Override
+ public FontMetrics getFontMetrics(Font f) {
+ return delegate.getFontMetrics();
+ }
+
+ @Override
+ public Rectangle getClipBounds() {
+ return delegate.getClipBounds();
+ }
+
+ @Override
+ public void clipRect(int x, int y, int width, int height) {
+ delegate.clipRect(x, y, width, height);
+ }
+
+ @Override
+ public void setClip(int x, int y, int width, int height) {
+ delegate.setClip(x, y, width, height);
+ }
+
+ @Override
+ public Shape getClip() {
+ return delegate.getClip();
+ }
+
+ @Override
+ public void setClip(Shape clip) {
+ delegate.setClip(clip);
+ }
+
+ @Override
+ public void copyArea(int x, int y, int width, int height, int dx, int dy) {
+ delegate.copyArea(x, y, width, height, dx, dy);
+ }
+
+ @Override
+ public void drawLine(int x1, int y1, int x2, int y2) {
+ delegate.drawLine(x1, y1, x2, y2);
+ }
+
+ @Override
+ public void fillRect(int x, int y, int width, int height) {
+ delegate.fillRect(x, y, width, height);
+ }
+
+ @Override
+ public void clearRect(int x, int y, int width, int height) {
+ delegate.clearRect(x, y, width, height);
+ }
+
+ @Override
+ public void drawRoundRect(int x, int y, int width, int height, int arcWidth,
+ int arcHeight) {
+ delegate.drawRoundRect(x, y, width, height, arcWidth, arcHeight);
+ }
+
+ @Override
+ public void fillRoundRect(int x, int y, int width, int height, int arcWidth,
+ int arcHeight) {
+ delegate.fillRoundRect(x, y, width, height, arcWidth, arcHeight);
+ }
+
+ @Override
+ public void drawOval(int x, int y, int width, int height) {
+ delegate.drawOval(x, y, width, height);
+ }
+
+ @Override
+ public void fillOval(int x, int y, int width, int height) {
+ delegate.fillOval(x, y, width, height);
+ }
+
+ @Override
+ public void drawArc(int x, int y, int width, int height, int startAngle, int arcAngle) {
+ delegate.drawArc(x, y, width, height, startAngle, arcAngle);
+ }
+
+ @Override
+ public void fillArc(int x, int y, int width, int height, int startAngle, int arcAngle) {
+ delegate.fillArc(x, y, width, height, startAngle, arcAngle);
+ }
+
+ @Override
+ public void drawPolyline(int[] xPoints, int[] yPoints, int nPoints) {
+ delegate.drawPolyline(xPoints, yPoints, nPoints);
+ }
+
+ @Override
+ public void drawPolygon(int[] xPoints, int[] yPoints, int nPoints) {
+ delegate.drawPolygon(xPoints, yPoints, nPoints);
+ }
+
+ @Override
+ public void fillPolygon(int[] xPoints, int[] yPoints, int nPoints) {
+ delegate.fillPolygon(null);
+ }
+
+ @Override
+ public boolean drawImage(Image img, int x, int y, ImageObserver observer) {
+ return delegate.drawImage(img, x, y, observer);
+ }
+
+ @Override
+ public boolean drawImage(Image img, int x, int y, int width, int height,
+ ImageObserver observer) {
+ return delegate.drawImage(img, x, y, width, height, observer);
+ }
+
+ @Override
+ public boolean drawImage(Image img, int x, int y, Color bgcolor, ImageObserver observer) {
+ return delegate.drawImage(img, x, y, bgcolor, observer);
+ }
+
+ @Override
+ public boolean drawImage(Image img, int x, int y, int width, int height, Color bgcolor,
+ ImageObserver observer) {
+ return delegate.drawImage(img, x, y, width, height, bgcolor, observer);
+ }
+
+ @Override
+ public boolean drawImage(Image img, int dx1, int dy1, int dx2, int dy2, int sx1, int sy1,
+ int sx2, int sy2, ImageObserver observer) {
+ return delegate.drawImage(img, dx1, dy1, dx2, dy2, sx1, sy1, sx2, sy2, observer);
+ }
+
+ @Override
+ public boolean drawImage(Image img, int dx1, int dy1, int dx2, int dy2, int sx1, int sy1,
+ int sx2, int sy2, Color bgcolor, ImageObserver observer) {
+ return delegate.drawImage(img, dx1, dy1, dx2, dy2, sx1, sy1, sx2, sy2, bgcolor,
+ observer);
+ }
+
+ @Override
+ public void dispose() {
+ delegate.dispose();
+ }
+
+ }
+}
diff --git a/Ghidra/Framework/Docking/src/test.slow/java/docking/widgets/textfield/IntegerTextFieldTest.java b/Ghidra/Framework/Docking/src/test.slow/java/docking/widgets/textfield/IntegerTextFieldTest.java
new file mode 100644
index 0000000000..d708536be5
--- /dev/null
+++ b/Ghidra/Framework/Docking/src/test.slow/java/docking/widgets/textfield/IntegerTextFieldTest.java
@@ -0,0 +1,290 @@
+/* ###
+ * 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.textfield;
+
+import static org.junit.Assert.*;
+
+import java.math.BigInteger;
+import java.util.concurrent.atomic.AtomicIntegerArray;
+
+import javax.swing.*;
+import javax.swing.event.ChangeEvent;
+import javax.swing.event.ChangeListener;
+
+import org.junit.*;
+
+import docking.test.AbstractDockingTest;
+
+public class IntegerTextFieldTest extends AbstractDockingTest {
+
+ private JFrame frame;
+ private IntegerTextField field;
+ private JTextField textField;
+
+ @Before
+ public void setUp() throws Exception {
+ UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
+ field = new IntegerTextField(10);
+ field.setShowNumberMode(true);
+ textField = (JTextField) field.getComponent();
+ frame = new JFrame("Test");
+ frame.getContentPane().add(field.getComponent());
+ frame.pack();
+ frame.setVisible(true);
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ frame.setVisible(false);
+ }
+
+ @Test
+ public void testDefaultState() {
+ assertNull(field.getValue());// no value
+ assertEquals(0, field.getIntValue());// the "int value" return for null is 0
+ assertEquals(0, field.getLongValue());
+ assertTrue(!field.isHexMode());
+ assertNull(field.getMaxValue());
+ }
+
+ @Test
+ public void testTypeValidDecimalNumber() {
+ triggerText(textField, "123");
+ assertEquals(123, field.getIntValue());
+ }
+
+ @Test
+ public void testTypeValidHexNumber() {
+ triggerText(textField, "0x2abcdef");
+ assertEquals(0x2abcdef, field.getIntValue());
+ }
+
+ @Test
+ public void testInvalidCharsIgnored() {
+ triggerText(textField, "123ghijklmnopqrstuvwxyz4");
+ assertEquals(1234, field.getIntValue());
+ }
+
+ @Test
+ public void testHexCharsIgnoredInDecimalMode() {
+ assertTrue(!field.isHexMode());
+ triggerText(textField, "123ghijklmnopqrstuvwxyz4");
+ assertEquals(1234, field.getIntValue());
+ }
+
+ @Test
+ public void testXchangesHexMode() {
+ assertTrue(!field.isHexMode());
+ triggerText(textField, "0");
+ assertTrue(!field.isHexMode());
+ triggerText(textField, "x");
+ assertTrue(field.isHexMode());
+ triggerBackspaceKey(textField);
+ assertTrue(!field.isHexMode());
+ }
+
+ @Test
+ public void testHexModeWithoutPrefix() {
+ triggerText(textField, "abc");// not allowed when using hex prefix, so expect empty
+ assertEquals(null, field.getValue());
+
+ field.setAllowsHexPrefix(false);
+ field.setHexMode();
+ triggerText(textField, "abc");
+ assertEquals(0xabc, field.getIntValue());
+ }
+
+ @Test
+ public void testNegative() {
+ triggerText(textField, "-123");
+ assertEquals(-123, field.getIntValue());
+ }
+
+ @Test
+ public void testNegativeHex() {
+ triggerText(textField, "-0xa");
+ assertEquals(-10, field.getIntValue());
+ }
+
+ @Test
+ public void testNegativeNotAllowed() {
+ field.setAllowNegativeValues(false);
+ triggerText(textField, "-123");
+ assertEquals(123, field.getIntValue());
+ }
+
+ @Test
+ public void testSetNegativeWithCurrentNegativeValue() {
+ field.setValue(-123);
+ field.setAllowNegativeValues(false);
+ assertEquals(null, field.getValue());
+ }
+
+ @Test
+ public void testMax() {
+ field.setMaxValue(BigInteger.valueOf(13l));
+ triggerText(textField, "12");
+ assertEquals(12, field.getIntValue());
+
+ field.setValue(null);
+ triggerText(textField, "13");
+ assertEquals(13, field.getIntValue());
+
+ field.setValue(null);
+ triggerText(textField, "14");// four should be ignored
+ assertEquals(1, field.getIntValue());
+
+ }
+
+ @Test
+ public void testSetMaxToValueSmallerThanCurrent() {
+ field.setValue(500);
+ field.setMaxValue(BigInteger.valueOf(400));
+ assertEquals(400, field.getIntValue());
+ }
+
+ @Test
+ public void testMaxInHex() {
+ field.setMaxValue(BigInteger.valueOf(0xd));
+ triggerText(textField, "0xc");
+ assertEquals(12, field.getIntValue());
+
+ field.setValue(null);
+ triggerText(textField, "0xd");
+ assertEquals(13, field.getIntValue());
+
+ field.setValue(null);
+ triggerText(textField, "0xe");// e should be ignored
+ assertEquals(0, field.getIntValue());
+
+ }
+
+ @Test
+ public void testSwitchingHexMode() {
+ field.setValue(255);
+ assertEquals("255", field.getText());
+ field.setHexMode();
+ assertEquals("0xff", field.getText());
+ field.setDecimalMode();
+ assertEquals("255", field.getText());
+ }
+
+ @Test
+ public void testChangeListenerAfterValidInput() {
+ TestChangeListener listener = new TestChangeListener();
+ field.addChangeListener(listener);
+
+ triggerText(textField, "123");
+ assertEquals(3, listener.count);
+ assertEquals(1, listener.values.get(0));
+ assertEquals(12, listener.values.get(1));
+ assertEquals(123, listener.values.get(2));
+
+ triggerBackspaceKey(textField);
+ assertEquals(12, listener.values.get(3));
+
+ }
+
+ @Test
+ public void testChangeListenerAfterSwitchingModes() {
+ triggerText(textField, "123");
+
+ TestChangeListener listener = new TestChangeListener();
+ field.addChangeListener(listener);
+
+ setHexMode();
+
+ assertEquals(2, listener.count);
+ assertEquals(123, listener.values.get(1));
+
+ }
+
+ @Test
+ public void testNegativeHexFromValue() {
+ field.setValue(-255);
+ setHexMode();
+ assertEquals("-0xff", field.getText());
+ }
+
+ @Test
+ public void testNullValue() {
+ field.setValue(12);
+ assertEquals("12", field.getText());
+ field.setValue(null);
+ assertEquals("", field.getText());
+ assertEquals(0, field.getIntValue());
+ assertEquals(0l, field.getLongValue());
+ assertEquals(null, field.getValue());
+ }
+
+ @Test
+ public void testHexValueInDontRequireHexPrefixMode() {
+ field.setAllowsHexPrefix(false);
+ field.setHexMode();
+ field.setValue(255);
+ assertEquals("ff", field.getText());
+ }
+
+ @Test
+ public void testSetNotAllowNegativeModeWhileCurrentValueIsNegative() {
+ field.setValue(-10);
+ field.setAllowNegativeValues(false);
+ assertEquals("", field.getText());
+ assertEquals(0, field.getIntValue());
+ }
+
+ @Test
+ public void testSetLongValue() {
+ field.setValue(100L);
+ assertEquals(100L, field.getLongValue());
+ assertEquals(100, field.getIntValue());
+ }
+
+ @Test
+ public void testSettingNegativeNumberWhenNegativesArentAllowed() {
+ field.setValue(10);
+ field.setAllowNegativeValues(false);
+ field.setValue(-10);
+ assertEquals("", field.getText());
+ }
+
+ @Test
+ public void testUseHexPrefixUpdatesTextField() {
+ field.setAllowsHexPrefix(false);
+ field.setHexMode();
+ field.setValue(255);
+ assertEquals("ff", field.getText());
+ field.setAllowsHexPrefix(true);
+ assertEquals("0xff", field.getText());
+ }
+
+ private void setHexMode() {
+ runSwing(() -> field.setHexMode());
+ waitForSwing();
+ }
+
+ class TestChangeListener implements ChangeListener {
+ volatile int count;
+ private AtomicIntegerArray values = new AtomicIntegerArray(10);
+
+ @Override
+ public void stateChanged(ChangeEvent e) {
+ values.set(count++, field.getIntValue());
+ }
+
+ }
+
+}
diff --git a/Ghidra/Framework/Docking/src/test/java/ghidra/util/task/TaskMonitorSplitterTest.java b/Ghidra/Framework/Docking/src/test/java/ghidra/util/task/TaskMonitorSplitterTest.java
new file mode 100644
index 0000000000..58f266bbf4
--- /dev/null
+++ b/Ghidra/Framework/Docking/src/test/java/ghidra/util/task/TaskMonitorSplitterTest.java
@@ -0,0 +1,67 @@
+/* ###
+ * 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.util.task;
+
+import static org.junit.Assert.assertEquals;
+
+import org.junit.Test;
+
+import docking.test.AbstractDockingTest;
+import generic.test.AbstractGenericTest;
+
+public class TaskMonitorSplitterTest extends AbstractDockingTest {
+ TaskMonitor baseMonitor;
+
+ public TaskMonitorSplitterTest() {
+ super();
+ baseMonitor = new TaskMonitorComponent();
+ }
+
+ @Test
+ public void testBasicUse() {
+ TaskMonitor[] monitors = TaskMonitorSplitter.splitTaskMonitor(baseMonitor, 4);
+
+ monitors[0].initialize(100);
+ monitors[0].setProgress(1);
+ assertEquals(1, monitors[0].getProgress());
+ assertEquals(TaskMonitorSplitter.MONITOR_SIZE / 400, baseMonitor.getProgress());
+
+ monitors[0].incrementProgress(1);
+ assertEquals(2 * TaskMonitorSplitter.MONITOR_SIZE / 400, baseMonitor.getProgress());
+
+ monitors[0].setProgress(10);
+ assertEquals(10 * TaskMonitorSplitter.MONITOR_SIZE / 400, baseMonitor.getProgress());
+
+ }
+
+ @Test
+ public void testMaxSettings() {
+ TaskMonitor[] monitors = TaskMonitorSplitter.splitTaskMonitor(baseMonitor, 4);
+
+ monitors[0].initialize(100);
+ monitors[0].setProgress(50);
+ assertEquals(50 * TaskMonitorSplitter.MONITOR_SIZE / 400, baseMonitor.getProgress());
+
+ monitors[0].setMaximum(25);
+ assertEquals(25, monitors[0].getMaximum());
+ assertEquals(TaskMonitorSplitter.MONITOR_SIZE / 4, baseMonitor.getProgress());
+
+ monitors[0].setMaximum(100);
+ assertEquals(25 * TaskMonitorSplitter.MONITOR_SIZE / 400, baseMonitor.getProgress());
+
+ }
+
+}
diff --git a/Ghidra/Framework/Help/src/test/java/help/AbstractHelpTest.java b/Ghidra/Framework/Help/src/test/java/help/AbstractHelpTest.java
new file mode 100644
index 0000000000..8d8a3cdd73
--- /dev/null
+++ b/Ghidra/Framework/Help/src/test/java/help/AbstractHelpTest.java
@@ -0,0 +1,196 @@
+/* ###
+ * 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 help;
+
+import static org.junit.Assert.assertNotNull;
+
+import java.io.IOException;
+import java.nio.file.*;
+
+import org.junit.After;
+import org.junit.Before;
+
+import generic.test.AbstractGenericTest;
+import utilities.util.FileUtilities;
+
+public abstract class AbstractHelpTest extends AbstractGenericTest {
+
+ protected static final String HELP_FILENAME_PREFIX = "Fake";
+ protected static final String HELP_FILENAME = HELP_FILENAME_PREFIX + ".html";
+
+ private Path testTempDir;
+
+ public AbstractHelpTest() {
+ super();
+ }
+
+ @Before
+ public void setUp() throws Exception {
+
+ testTempDir = Files.createTempDirectory(testName.getMethodName());
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ FileUtilities.deleteDir(testTempDir.toFile());
+ }
+
+ protected Path createHelpBuildOutputDir() throws IOException {
+ Path out = testTempDir.resolve("build/help/main/help");
+ Files.createDirectories(out);
+ return out;
+ }
+
+ protected Path createFakeHelpTopic(Path helpDir) throws IOException {
+ return createFakeHelpTopic("FakeTopic", helpDir);
+ }
+
+ protected Path createFakeHelpTopic(String topicName, Path helpDir) throws IOException {
+ Path topicsDir = helpDir.resolve("topics");
+ Path fakeTopicDir = topicsDir.resolve(topicName);
+ Files.createDirectories(fakeTopicDir);
+ return fakeTopicDir;
+ }
+
+ protected Path createTempHelpDir() throws IOException {
+ Path helpDir = testTempDir.resolve("help");
+ Files.createDirectory(helpDir);
+ return helpDir;
+ }
+
+ protected void addRequiredHelpDirStructure(Path helpDir) throws IOException {
+
+ // HelpFile wants to read one of these, so put one there
+ createEmpty_TOC_Source_File(helpDir);
+ createSharedDir(helpDir);
+ }
+
+ protected Path createSharedDir(Path helpDir) throws IOException {
+ Path sharedDir = helpDir.resolve("shared");
+ Files.createDirectory(sharedDir);
+
+ Path css = sharedDir.resolve("Frontpage.css");
+ Files.createFile(css);
+
+ Path png = sharedDir.resolve("test.png");
+ Files.createFile(png);
+
+ return sharedDir;
+ }
+
+ protected Path createEmpty_TOC_Source_File(Path dir) throws IOException {
+
+ Path fullTOCPath = dir.resolve("TOC_Source.xml");
+ Path file = Files.createFile(fullTOCPath);
+
+ //@formatter:off
+ String TOCXML = "\n" +
+ "\n\n" +
+
+ "
+ * A <------- you are here + * / \ + * B C + * \ / + * D + *+ */ +//@formatter:off +@PluginInfo(status = PluginStatus.HIDDEN, + packageName = DeveloperPluginPackage.NAME, + category = PluginCategoryNames.UNMANAGED, + shortDescription = "Test plugin", + description = "Test plugin", + servicesRequired = { DiamondServiceB.class, DiamondServiceC.class} ) +//@formatter:on +public class DiamondPluginA extends Plugin implements TestingPlugin { + + public DiamondPluginA(PluginTool tool) { + super(tool); + } + +} diff --git a/Ghidra/Test/IntegrationTest/src/test.slow/java/ghidra/framework/plugintool/testplugins/DiamondPluginB.java b/Ghidra/Test/IntegrationTest/src/test.slow/java/ghidra/framework/plugintool/testplugins/DiamondPluginB.java new file mode 100644 index 0000000000..14424c1031 --- /dev/null +++ b/Ghidra/Test/IntegrationTest/src/test.slow/java/ghidra/framework/plugintool/testplugins/DiamondPluginB.java @@ -0,0 +1,48 @@ +/* ### + * 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.framework.plugintool.testplugins; + +import ghidra.app.DeveloperPluginPackage; +import ghidra.app.plugin.PluginCategoryNames; +import ghidra.framework.plugintool.*; +import ghidra.framework.plugintool.util.PluginStatus; + +/** + * Test plugin for {@link PluginManagerTest#testDiamond()} + *
+ * A + * / \ + * B <---C--------------- you are here + * \ / + * D + *+ */ +//@formatter:off +@PluginInfo(status = PluginStatus.HIDDEN, + packageName = DeveloperPluginPackage.NAME, + category = PluginCategoryNames.UNMANAGED, + shortDescription = "Test plugin", + description = "Test plugin", + servicesProvided = DiamondServiceB.class, + servicesRequired = DiamondServiceD.class) +//@formatter:on +public class DiamondPluginB extends Plugin implements DiamondServiceB, TestingPlugin { + + public DiamondPluginB(PluginTool tool) { + super(tool); + } + +} diff --git a/Ghidra/Test/IntegrationTest/src/test.slow/java/ghidra/framework/plugintool/testplugins/DiamondPluginC.java b/Ghidra/Test/IntegrationTest/src/test.slow/java/ghidra/framework/plugintool/testplugins/DiamondPluginC.java new file mode 100644 index 0000000000..f8a86abbfa --- /dev/null +++ b/Ghidra/Test/IntegrationTest/src/test.slow/java/ghidra/framework/plugintool/testplugins/DiamondPluginC.java @@ -0,0 +1,48 @@ +/* ### + * 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.framework.plugintool.testplugins; + +import ghidra.app.DeveloperPluginPackage; +import ghidra.app.plugin.PluginCategoryNames; +import ghidra.framework.plugintool.*; +import ghidra.framework.plugintool.util.PluginStatus; + +/** + * Test plugin for {@link PluginManagerTest#testDiamond()} + *
+ * A + * / \ + * B C <------ you are here + * \ / + * D + *+ */ +//@formatter:off +@PluginInfo(status = PluginStatus.HIDDEN, + packageName = DeveloperPluginPackage.NAME, + category = PluginCategoryNames.UNMANAGED, + shortDescription = "Test plugin", + description = "Test plugin", + servicesProvided = DiamondServiceC.class, + servicesRequired = DiamondServiceD.class) +//@formatter:on +public class DiamondPluginC extends Plugin implements DiamondServiceC, TestingPlugin { + + public DiamondPluginC(PluginTool tool) { + super(tool); + } + +} diff --git a/Ghidra/Test/IntegrationTest/src/test.slow/java/ghidra/framework/plugintool/testplugins/DiamondPluginD.java b/Ghidra/Test/IntegrationTest/src/test.slow/java/ghidra/framework/plugintool/testplugins/DiamondPluginD.java new file mode 100644 index 0000000000..c121c9cb48 --- /dev/null +++ b/Ghidra/Test/IntegrationTest/src/test.slow/java/ghidra/framework/plugintool/testplugins/DiamondPluginD.java @@ -0,0 +1,46 @@ +/* ### + * 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.framework.plugintool.testplugins; + +import ghidra.app.DeveloperPluginPackage; +import ghidra.app.plugin.PluginCategoryNames; +import ghidra.framework.plugintool.*; +import ghidra.framework.plugintool.util.PluginStatus; + +/** + * Test plugin for {@link PluginManagerTest#testDiamond()} + *
+ * A + * / \ + * B C + * \ / + * D <--------- you are here + *+ */ +//@formatter:off +@PluginInfo(status = PluginStatus.HIDDEN, + packageName = DeveloperPluginPackage.NAME, + category = PluginCategoryNames.UNMANAGED, + shortDescription = "Test plugin", + description = "Test plugin", + servicesProvided = DiamondServiceD.class) +//@formatter:on +public class DiamondPluginD extends Plugin implements DiamondServiceD, TestingPlugin { + + public DiamondPluginD(PluginTool tool) { + super(tool); + } +} diff --git a/Ghidra/Test/IntegrationTest/src/test.slow/java/ghidra/framework/plugintool/testplugins/DiamondServiceB.java b/Ghidra/Test/IntegrationTest/src/test.slow/java/ghidra/framework/plugintool/testplugins/DiamondServiceB.java new file mode 100644 index 0000000000..77647df019 --- /dev/null +++ b/Ghidra/Test/IntegrationTest/src/test.slow/java/ghidra/framework/plugintool/testplugins/DiamondServiceB.java @@ -0,0 +1,34 @@ +/* ### + * 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.framework.plugintool.testplugins; + +import ghidra.framework.plugintool.PluginManagerTest; +import ghidra.framework.plugintool.ServiceInfo; + +/** + * Test plugin service for {@link PluginManagerTest#testDiamond()} + *
+ * A + * / \ + * B<----C------------ you are here + * \ / + * D + *+ */ +@ServiceInfo(defaultProvider = DiamondPluginB.class, description = "Test service") +public interface DiamondServiceB { + +} diff --git a/Ghidra/Test/IntegrationTest/src/test.slow/java/ghidra/framework/plugintool/testplugins/DiamondServiceC.java b/Ghidra/Test/IntegrationTest/src/test.slow/java/ghidra/framework/plugintool/testplugins/DiamondServiceC.java new file mode 100644 index 0000000000..489ff78409 --- /dev/null +++ b/Ghidra/Test/IntegrationTest/src/test.slow/java/ghidra/framework/plugintool/testplugins/DiamondServiceC.java @@ -0,0 +1,34 @@ +/* ### + * 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.framework.plugintool.testplugins; + +import ghidra.framework.plugintool.PluginManagerTest; +import ghidra.framework.plugintool.ServiceInfo; + +/** + * Test plugin service for {@link PluginManagerTest#testDiamond()} + *
+ * A + * / \ + * B C <---------- you are here + * \ / + * D + *+ */ +@ServiceInfo(defaultProvider = DiamondPluginC.class, description = "Test service") +public interface DiamondServiceC { + +} diff --git a/Ghidra/Test/IntegrationTest/src/test.slow/java/ghidra/framework/plugintool/testplugins/DiamondServiceD.java b/Ghidra/Test/IntegrationTest/src/test.slow/java/ghidra/framework/plugintool/testplugins/DiamondServiceD.java new file mode 100644 index 0000000000..0f6427ec97 --- /dev/null +++ b/Ghidra/Test/IntegrationTest/src/test.slow/java/ghidra/framework/plugintool/testplugins/DiamondServiceD.java @@ -0,0 +1,34 @@ +/* ### + * 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.framework.plugintool.testplugins; + +import ghidra.framework.plugintool.PluginManagerTest; +import ghidra.framework.plugintool.ServiceInfo; + +/** + * Test plugin service for {@link PluginManagerTest#testDiamond()} + *
+ * A + * / \ + * B C + * \ / + * D <---------- you are here + *+ */ +@ServiceInfo(defaultProvider = DiamondPluginD.class, description = "Test service") +public interface DiamondServiceD { + +} diff --git a/Ghidra/Test/IntegrationTest/src/test.slow/java/ghidra/framework/plugintool/testplugins/DisposeFailPluginA.java b/Ghidra/Test/IntegrationTest/src/test.slow/java/ghidra/framework/plugintool/testplugins/DisposeFailPluginA.java new file mode 100644 index 0000000000..cab4780550 --- /dev/null +++ b/Ghidra/Test/IntegrationTest/src/test.slow/java/ghidra/framework/plugintool/testplugins/DisposeFailPluginA.java @@ -0,0 +1,46 @@ +/* ### + * 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.framework.plugintool.testplugins; + +import ghidra.app.DeveloperPluginPackage; +import ghidra.app.plugin.PluginCategoryNames; +import ghidra.framework.plugintool.*; +import ghidra.framework.plugintool.util.PluginStatus; + +/** + * Test plugin for {@link PluginManagerTest#testDisposeFail()} and friends. + */ +//@formatter:off +@PluginInfo(status = PluginStatus.HIDDEN, + packageName = DeveloperPluginPackage.NAME, + category = PluginCategoryNames.UNMANAGED, + shortDescription = "Test plugin", + description = "Test plugin" ) +//@formatter:on +public class DisposeFailPluginA extends Plugin implements TestingPlugin { + public static final String ERROR_MSG = "PluginA dispose exception message"; + public static int disposeCount = 0; + + public DisposeFailPluginA(PluginTool tool) { + super(tool); + } + + @Override + protected void dispose() { + throw new RuntimeException(ERROR_MSG); + } + +} diff --git a/Ghidra/Test/IntegrationTest/src/test.slow/java/ghidra/framework/plugintool/testplugins/InitFailPluginA.java b/Ghidra/Test/IntegrationTest/src/test.slow/java/ghidra/framework/plugintool/testplugins/InitFailPluginA.java new file mode 100644 index 0000000000..a238505872 --- /dev/null +++ b/Ghidra/Test/IntegrationTest/src/test.slow/java/ghidra/framework/plugintool/testplugins/InitFailPluginA.java @@ -0,0 +1,46 @@ +/* ### + * 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.framework.plugintool.testplugins; + +import ghidra.app.DeveloperPluginPackage; +import ghidra.app.plugin.PluginCategoryNames; +import ghidra.framework.plugintool.*; +import ghidra.framework.plugintool.util.PluginStatus; + +/** + * Test plugin for {@link PluginManagerTest#testInitFail()} and friends. + */ +//@formatter:off +@PluginInfo(status = PluginStatus.HIDDEN, + packageName = DeveloperPluginPackage.NAME, + category = PluginCategoryNames.UNMANAGED, + shortDescription = "Test plugin", + description = "Test plugin", + servicesRequired = { InitFailServiceB.class } ) +//@formatter:on +public class InitFailPluginA extends Plugin implements TestingPlugin { + public static int disposeCount = 0; + + public InitFailPluginA(PluginTool tool) { + super(tool); + } + + @Override + protected void dispose() { + disposeCount++; + } + +} diff --git a/Ghidra/Test/IntegrationTest/src/test.slow/java/ghidra/framework/plugintool/testplugins/InitFailPluginB.java b/Ghidra/Test/IntegrationTest/src/test.slow/java/ghidra/framework/plugintool/testplugins/InitFailPluginB.java new file mode 100644 index 0000000000..44d5c4e081 --- /dev/null +++ b/Ghidra/Test/IntegrationTest/src/test.slow/java/ghidra/framework/plugintool/testplugins/InitFailPluginB.java @@ -0,0 +1,52 @@ +/* ### + * 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.framework.plugintool.testplugins; + +import ghidra.app.DeveloperPluginPackage; +import ghidra.app.plugin.PluginCategoryNames; +import ghidra.framework.plugintool.*; +import ghidra.framework.plugintool.util.PluginStatus; + +/** + * Test plugin for {@link PluginManagerTest#testInitFail()} and friends. + */ +//@formatter:off +@PluginInfo(status = PluginStatus.HIDDEN, + packageName = DeveloperPluginPackage.NAME, + category = PluginCategoryNames.UNMANAGED, + shortDescription = "Test plugin", + description = "Test plugin", + servicesProvided = { InitFailServiceB.class } ) +//@formatter:on +public class InitFailPluginB extends Plugin implements InitFailServiceB, TestingPlugin { + public static final String ERROR_MSG = "PluginB fails during Plugin.init()"; + public static int disposeCount = 0; + + public InitFailPluginB(PluginTool tool) { + super(tool); + } + + @Override + protected void init() { + throw new RuntimeException(ERROR_MSG); + } + + @Override + protected void dispose() { + disposeCount++; + } + +} diff --git a/Ghidra/Test/IntegrationTest/src/test.slow/java/ghidra/framework/plugintool/testplugins/InitFailServiceB.java b/Ghidra/Test/IntegrationTest/src/test.slow/java/ghidra/framework/plugintool/testplugins/InitFailServiceB.java new file mode 100644 index 0000000000..84323d0314 --- /dev/null +++ b/Ghidra/Test/IntegrationTest/src/test.slow/java/ghidra/framework/plugintool/testplugins/InitFailServiceB.java @@ -0,0 +1,27 @@ +/* ### + * 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.framework.plugintool.testplugins; + +import ghidra.framework.plugintool.PluginManagerTest; +import ghidra.framework.plugintool.ServiceInfo; + +/** + * Test plugin service for {@link PluginManagerTest#testInitFail()} and friends. + */ +@ServiceInfo(defaultProvider = InitFailPluginB.class, description = "Test service") +public interface InitFailServiceB { + +} diff --git a/Ghidra/Test/IntegrationTest/src/test.slow/java/ghidra/framework/plugintool/testplugins/IsolatedFailPluginA.java b/Ghidra/Test/IntegrationTest/src/test.slow/java/ghidra/framework/plugintool/testplugins/IsolatedFailPluginA.java new file mode 100644 index 0000000000..b701c7e984 --- /dev/null +++ b/Ghidra/Test/IntegrationTest/src/test.slow/java/ghidra/framework/plugintool/testplugins/IsolatedFailPluginA.java @@ -0,0 +1,39 @@ +/* ### + * 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.framework.plugintool.testplugins; + +import ghidra.app.DeveloperPluginPackage; +import ghidra.app.plugin.PluginCategoryNames; +import ghidra.framework.plugintool.*; +import ghidra.framework.plugintool.util.PluginStatus; + +/** + * Test plugin for {@link PluginManagerTest#testLoadFailure_Isolated} + */ +//@formatter:off +@PluginInfo(status = PluginStatus.HIDDEN, + packageName = DeveloperPluginPackage.NAME, + category = PluginCategoryNames.UNMANAGED, + shortDescription = "Test plugin", + description = "Test plugin") +//@formatter:on +public class IsolatedFailPluginA extends Plugin implements TestingPlugin { + + public IsolatedFailPluginA(PluginTool tool) { + super(tool); + } + +} diff --git a/Ghidra/Test/IntegrationTest/src/test.slow/java/ghidra/framework/plugintool/testplugins/IsolatedFailPluginB.java b/Ghidra/Test/IntegrationTest/src/test.slow/java/ghidra/framework/plugintool/testplugins/IsolatedFailPluginB.java new file mode 100644 index 0000000000..459bf4c102 --- /dev/null +++ b/Ghidra/Test/IntegrationTest/src/test.slow/java/ghidra/framework/plugintool/testplugins/IsolatedFailPluginB.java @@ -0,0 +1,45 @@ +/* ### + * 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.framework.plugintool.testplugins; + +import ghidra.app.DeveloperPluginPackage; +import ghidra.app.plugin.PluginCategoryNames; +import ghidra.framework.plugintool.*; +import ghidra.framework.plugintool.util.PluginStatus; + +/** + * Test plugin for {@link PluginManagerTest#testLoadFailure_Isolated} + */ +//@formatter:off +@PluginInfo(status = PluginStatus.HIDDEN, + packageName = DeveloperPluginPackage.NAME, + category = PluginCategoryNames.UNMANAGED, + shortDescription = "Test plugin", + description = "Test plugin") +//@formatter:on +public class IsolatedFailPluginB extends Plugin implements TestingPlugin { + + public static final String ERROR_MSG = "IsolatedFailPluginB error message"; + + public IsolatedFailPluginB(PluginTool tool) { + super(tool); + } + + @Override + protected void init() { + throw new RuntimeException(ERROR_MSG); + } +} diff --git a/Ghidra/Test/IntegrationTest/src/test.slow/java/ghidra/framework/plugintool/testplugins/MissingDepPluginA.java b/Ghidra/Test/IntegrationTest/src/test.slow/java/ghidra/framework/plugintool/testplugins/MissingDepPluginA.java new file mode 100644 index 0000000000..0965283993 --- /dev/null +++ b/Ghidra/Test/IntegrationTest/src/test.slow/java/ghidra/framework/plugintool/testplugins/MissingDepPluginA.java @@ -0,0 +1,41 @@ +/* ### + * 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.framework.plugintool.testplugins; + +import ghidra.app.DeveloperPluginPackage; +import ghidra.app.plugin.PluginCategoryNames; +import ghidra.framework.plugintool.*; +import ghidra.framework.plugintool.util.PluginStatus; + +/** + * Test plugin for {@link PluginManagerTest#testMissingDependency()} and + * {@link PluginManagerTest#testLoadingDepSimultaneously()} + */ +//@formatter:off +@PluginInfo(status = PluginStatus.HIDDEN, + packageName = DeveloperPluginPackage.NAME, + category = PluginCategoryNames.UNMANAGED, + shortDescription = "Test plugin", + description = "Test plugin", + servicesRequired = { MissingDepServiceB.class } ) +//@formatter:on +public class MissingDepPluginA extends Plugin implements TestingPlugin { + + public MissingDepPluginA(PluginTool tool) { + super(tool); + } + +} diff --git a/Ghidra/Test/IntegrationTest/src/test.slow/java/ghidra/framework/plugintool/testplugins/MissingDepPluginB.java b/Ghidra/Test/IntegrationTest/src/test.slow/java/ghidra/framework/plugintool/testplugins/MissingDepPluginB.java new file mode 100644 index 0000000000..bd94be8b07 --- /dev/null +++ b/Ghidra/Test/IntegrationTest/src/test.slow/java/ghidra/framework/plugintool/testplugins/MissingDepPluginB.java @@ -0,0 +1,41 @@ +/* ### + * 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.framework.plugintool.testplugins; + +import ghidra.app.DeveloperPluginPackage; +import ghidra.app.plugin.PluginCategoryNames; +import ghidra.framework.plugintool.*; +import ghidra.framework.plugintool.util.PluginStatus; + +/** + * Test plugin for {@link PluginManagerTest#testMissingDependency()} and + * {@link PluginManagerTest#testLoadingDepSimultaneously()} + */ +//@formatter:off +@PluginInfo(status = PluginStatus.HIDDEN, + packageName = DeveloperPluginPackage.NAME, + category = PluginCategoryNames.UNMANAGED, + shortDescription = "Test plugin", + description = "Test plugin", + servicesProvided = MissingDepServiceB.class) +//@formatter:on +public class MissingDepPluginB extends Plugin implements MissingDepServiceB, TestingPlugin { + + public MissingDepPluginB(PluginTool tool) { + super(tool); + } + +} diff --git a/Ghidra/Test/IntegrationTest/src/test.slow/java/ghidra/framework/plugintool/testplugins/MissingDepServiceB.java b/Ghidra/Test/IntegrationTest/src/test.slow/java/ghidra/framework/plugintool/testplugins/MissingDepServiceB.java new file mode 100644 index 0000000000..14723e09f7 --- /dev/null +++ b/Ghidra/Test/IntegrationTest/src/test.slow/java/ghidra/framework/plugintool/testplugins/MissingDepServiceB.java @@ -0,0 +1,28 @@ +/* ### + * 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.framework.plugintool.testplugins; + +import ghidra.framework.plugintool.PluginManagerTest; +import ghidra.framework.plugintool.ServiceInfo; + +/** + * Test plugin service for {@link PluginManagerTest#testMissingDependency()} and + * {@link PluginManagerTest#testLoadingDepSimultaneously()} + */ +@ServiceInfo(description = "Test service" /*, defaultProvider=not_specified*/ ) +public interface MissingDepServiceB { + +} diff --git a/Ghidra/Test/IntegrationTest/src/test.slow/java/ghidra/framework/plugintool/testplugins/NameConflictingPlugin.java b/Ghidra/Test/IntegrationTest/src/test.slow/java/ghidra/framework/plugintool/testplugins/NameConflictingPlugin.java new file mode 100644 index 0000000000..ff97a0ff06 --- /dev/null +++ b/Ghidra/Test/IntegrationTest/src/test.slow/java/ghidra/framework/plugintool/testplugins/NameConflictingPlugin.java @@ -0,0 +1,41 @@ +/* ### + * 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.framework.plugintool.testplugins; + +import ghidra.app.DeveloperPluginPackage; +import ghidra.app.plugin.PluginCategoryNames; +import ghidra.framework.plugintool.*; +import ghidra.framework.plugintool.util.PluginStatus; + +//@formatter:off +/** + * Test plugin for {@link PluginManagerTest#testConflictPluginNames()}. + * + * Class name needs to match *Plugin so the class searcher finds it. + */ +@PluginInfo(status = PluginStatus.HIDDEN, + packageName = DeveloperPluginPackage.NAME, + category = PluginCategoryNames.UNMANAGED, + shortDescription = "Test plugin name collision", + description = "Test plugin name collision.") +//@formatter:on +public class NameConflictingPlugin extends Plugin implements TestingPlugin { + + public NameConflictingPlugin(PluginTool tool) { + super(tool); + } + +} diff --git a/Ghidra/Test/IntegrationTest/src/test.slow/java/ghidra/framework/plugintool/testplugins/secondconflict/NameConflictingPlugin.java b/Ghidra/Test/IntegrationTest/src/test.slow/java/ghidra/framework/plugintool/testplugins/secondconflict/NameConflictingPlugin.java new file mode 100644 index 0000000000..f30df9b5d3 --- /dev/null +++ b/Ghidra/Test/IntegrationTest/src/test.slow/java/ghidra/framework/plugintool/testplugins/secondconflict/NameConflictingPlugin.java @@ -0,0 +1,41 @@ +/* ### + * 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.framework.plugintool.testplugins.secondconflict; + +import ghidra.app.DeveloperPluginPackage; +import ghidra.app.plugin.PluginCategoryNames; +import ghidra.framework.plugintool.*; +import ghidra.framework.plugintool.util.PluginStatus; + +/** + * Test plugin for {@link PluginManagerTest#testConflictPluginNames()} + * + * Class name needs to match *Plugin so the class searcher finds it. + */ +//@formatter:off +@PluginInfo(status = PluginStatus.HIDDEN, + packageName = DeveloperPluginPackage.NAME, + category = PluginCategoryNames.UNMANAGED, + shortDescription = "Test plugin name collision", + description = "Test plugin name collision.") +//@formatter:on +public class NameConflictingPlugin extends Plugin implements TestingPlugin { + + public NameConflictingPlugin(PluginTool tool) { + super(tool); + } + +} diff --git a/Ghidra/Test/IntegrationTest/src/test.slow/java/ghidra/program/disassemble/DisassemblerTest.java b/Ghidra/Test/IntegrationTest/src/test.slow/java/ghidra/program/disassemble/DisassemblerTest.java new file mode 100644 index 0000000000..3428ddd822 --- /dev/null +++ b/Ghidra/Test/IntegrationTest/src/test.slow/java/ghidra/program/disassemble/DisassemblerTest.java @@ -0,0 +1,1534 @@ +/* ### + * 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.program.disassemble; + +import static org.junit.Assert.*; + +import java.math.BigInteger; +import java.util.List; +import java.util.Set; + +import org.junit.*; + +import ghidra.program.model.address.*; +import ghidra.program.model.data.ByteDataType; +import ghidra.program.model.lang.Register; +import ghidra.program.model.listing.*; +import ghidra.program.model.symbol.SourceType; +import ghidra.test.AbstractGhidraHeadlessIntegrationTest; +import ghidra.test.ToyProgramBuilder; +import ghidra.util.task.TaskMonitorAdapter; +import util.CollectionUtils; + +public class DisassemblerTest extends AbstractGhidraHeadlessIntegrationTest { + + // TODO: Disassembler Concerns + // - Unsure we can detect context inconsistencies where context produces constant and + // does not influence parse decision (i.e., prototypes are equal) + // - Once CodeManager detects block overlap it stops processing instructions within the + // block at the point of duplication causing inconsistent prototypes not to be detected + // in some cases (see testDisassemblerMidBlockOverlapWithProgramAndConflictDetection) + // - InstructionBlock holds only one conflict - this may cause + // some conflicts to get lost - CodeManager also sets conflicts which + // can wipe a previous conflict + // - Conflicting context setting (via globalset) are not detected - last one wins + // - We are inconsistent in our treatment of uninitialized memory and undefined memory + // in terms of conflict/error bookmarks + + // TODO: Change error handling of unintialized memory and EXTERNAL block + + // TODO: Add test where internal conflict occurs on top of different program + // code units - CODE_UNIT conflict handling assumes real code unit exists at conflictAddress + + private ToyProgramBuilder programBuilder;// Instructions are 2-byte aligned + private Program program; + private Listing listing; + private Disassembler disassembler; + + private int txId; + + @Before + public void setUp() throws Exception { + programBuilder = new ToyProgramBuilder("Test", true, true, null); + program = programBuilder.getProgram(); + txId = program.startTransaction("Add Memory");// leave open until tearDown + programBuilder.createMemory(".text", "0", 64).setExecute(true);// initialized + programBuilder.createUninitializedMemory(".unint", "0x40", 64).setExecute(true);// uninitialized + programBuilder.createUninitializedMemory(".dat", "0x80", 64);// no-execute + programBuilder.createMemory(".text2", "0x3e0", 0x800).setExecute(true);// initialized + + listing = program.getListing(); + disassembler = new Disassembler(program, TaskMonitorAdapter.DUMMY_MONITOR, null); + } + + @After + public void tearDown() throws Exception { + if (program != null) { + program.endTransaction(txId, true); + } + if (programBuilder != null) { + programBuilder.dispose(); + } + } + + /** + * ** Diagnostic Aid ** Dump context register values + */ +// private void dumpContextRanges(long min, long max, String regName) { +// Msg.info(this, "Context ranges: " + regName); +// Register fctxReg = program.getRegister(regName); +// ProgramContext programContext = program.getProgramContext(); +// AddressRangeIterator ranges = +// programContext.getRegisterValueAddressRanges(fctxReg, addr(min), addr(max)); +// for (AddressRange range : ranges) { +// Msg.info(this, +// range + ": " + programContext.getValue(fctxReg, range.getMinAddress(), false)); +// } +// assertFalse(ranges.hasNext()); +// } + + private Address addr(long offset) { + return programBuilder.getAddress(offset); + } + + private AddressRange range(long start, long end) { + return new AddressRangeImpl(addr(start), addr(end)); + } + + private AddressSet addrset(AddressRange... ranges) { + AddressSet addrset = new AddressSet(); + for (AddressRange range : ranges) { + addrset.add(range); + } + return addrset; + } + + private void verifyInstructionPresence() { + verifyInstructionPresence(null); + } + + private void verifyInstructionPresence(Set exclusions) { +// InstructionIterator instructions = listing.getInstructions(true); +// while (instructions.hasNext()) { +// Instruction instr = instructions.next(); +// System.out.println("Instruction at " + instr.getAddress()); +// } + List instrAddrs = programBuilder.getDefinedInstructionAddress(); + int expectedCnt = instrAddrs.size(); + if (exclusions != null) { + expectedCnt -= exclusions.size(); + } + assertEquals(expectedCnt, listing.getNumInstructions()); + for (Address addr : instrAddrs) { + if (exclusions != null && exclusions.contains(addr)) { + continue; + } + assertNotNull("Expected instruction at " + addr, listing.getInstructionAt(addr)); + } + } + + private void verifyNoBookmarks() { + assertEquals("unexpected bookmarks exist", 0, + program.getBookmarkManager().getBookmarkCount()); + } + + private void verifyErrorBookmark(Address addr, String text) { + assertEquals("Expected error bookmark at " + addr, 1, + program.getBookmarkManager().getBookmarkCount()); + + Bookmark errMark = program.getBookmarkManager().getBookmark(addr, BookmarkType.ERROR, + Disassembler.ERROR_BOOKMARK_CATEGORY); + assertNotNull("Expected error bookmark at " + addr, errMark); + + if (text != null) { + assertTrue("Expected error bookmark at " + addr + " to contain text: " + text, + errMark.getComment().indexOf(text) >= 0); + } + + } + + private static class ContextRangeValue { + long startOffset; + long endOffset; + int value; + + ContextRangeValue(long start, long end, int value) { + startOffset = start; + endOffset = end; + this.value = value; + } + } + + private void verifyContextRanges(long min, long max, String regName, + ContextRangeValue... valueRanges) { + Register fctxReg = program.getRegister(regName); + ProgramContext programContext = program.getProgramContext(); + AddressRangeIterator ranges = + programContext.getRegisterValueAddressRanges(fctxReg, addr(min), addr(max)); + for (ContextRangeValue valueRange : valueRanges) { + assertTrue(ranges.hasNext()); + AddressRange range = ranges.next(); + assertEquals(valueRange.startOffset, range.getMinAddress().getOffset()); + assertEquals(valueRange.endOffset, range.getMaxAddress().getOffset()); + BigInteger val = programContext.getValue(fctxReg, range.getMinAddress(), false); + assertNotNull("Expected flow context at " + range.getMinAddress()); + assertEquals(valueRange.value, val.longValue()); + } + assertFalse(ranges.hasNext()); + } + + /** + * + * +-> 10: breq 20 --+ (start) + * | 12: ret | + * | | + * +-- 20: breq 10 <-+ + * 22: ret + * + * Test circular flow + * + */ + @Test + public void testDisassemblerCircularFlow() throws Exception { + + programBuilder.addBytesBranchConditional(10, 20); + programBuilder.addBytesReturn(12); + + programBuilder.addBytesBranchConditional(20, 10); + programBuilder.addBytesReturn(22); + + AddressSetView disAddrs = disassembler.disassemble(addr(10), null); + assertEquals(addrset(range(10, 13), range(20, 23)), disAddrs); + + verifyInstructionPresence(); + + verifyNoBookmarks(); + + } + + /** + * + * 10: call 20 --+ (start) + * 12: ret | + * | + * 20: or <----+ + * 22: ret + * + * Test call + * + */ + @Test + public void testDisassemblerCallFlow() throws Exception { + + programBuilder.addBytesCall(10, 20); + programBuilder.addBytesReturn(12); + + programBuilder.addBytesFallthrough(20); + programBuilder.addBytesReturn(22); + + AddressSetView disAddrs = disassembler.disassemble(addr(10), null); + assertEquals(addrset(range(10, 13), range(20, 23)), disAddrs); + + verifyInstructionPresence(); + + verifyNoBookmarks(); + + } + + /** + * + * 10: call 20 --+ (start) + * 12: ret | (should not disassemble) + * | + * 20: or <----+ (no-return) + * 22: ret + * + * Test call + * + */ + @Test + public void testDisassemblerCallFlowNoReturn() throws Exception { + + programBuilder.addBytesFallthrough(20); + programBuilder.addBytesReturn(22); + + AddressSetView disAddrs = disassembler.disassemble(addr(20), null); + AddressSet funcBody = addrset(range(20, 23)); + assertEquals(funcBody, disAddrs); + + verifyInstructionPresence(); + + Function func = listing.createFunction("Foo", addr(20), funcBody, SourceType.USER_DEFINED); + func.setNoReturn(true); + + programBuilder.addBytesCall(10, 20); + programBuilder.addBytesReturn(12);// should not disassemble + + disAddrs = disassembler.disassemble(addr(10), null); + assertEquals(addrset(range(10, 11)), disAddrs); + + verifyInstructionPresence(CollectionUtils.asSet(addr(12))); + + verifyNoBookmarks(); + + } + + /** + * +--10: breq 20 (start) + * | 12: call 30 --+ + * | 14: ret | + * | | + * +-> 20: or | + * +-- 22: bral 40 | + * | | + * | 30: or <----+ + * | 32: bral 40 -+ + * | | + * +->40: ret <---+ + * + */ + @Test + public void testDisassemblerMultipath() throws Exception { + + programBuilder.addBytesBranchConditional(10, 20); + programBuilder.addBytesCall(12, 30); + programBuilder.addBytesReturn(14); + + programBuilder.addBytesFallthrough(20); + programBuilder.addBytesBranch(22, 40); + + programBuilder.addBytesFallthrough(30); + programBuilder.addBytesBranch(32, 40); + + programBuilder.addBytesReturn(40); + + AddressSetView disAddrs = disassembler.disassemble(addr(10), null); + assertEquals(addrset(range(10, 15), range(20, 23), range(30, 33), range(40, 41)), disAddrs); + + verifyInstructionPresence(); + + verifyNoBookmarks(); + + } + + /** + * + * 10: callds 20 --+ (start) + * 12: _or | + * 14: ret | + * | + * 20: or <------+ + * 22: ret + * + * Test simple delay slot flow + * + */ + @Test + public void testDisassemblerDelaySlot() throws Exception { + + programBuilder.addBytesCallWithDelaySlot(10, 20); + programBuilder.addBytesReturn(14); + + programBuilder.addBytesFallthrough(20); + programBuilder.addBytesReturn(22); + + AddressSetView disAddrs = disassembler.disassemble(addr(10), null); + assertEquals(addrset(range(10, 15), range(20, 23)), disAddrs); + + verifyInstructionPresence(); + + verifyNoBookmarks(); + + } + + /** + * 10: or (start) + * +- 12: brds 20 + * | 14: _or <-----+ + * | 16: ret | + * | | + * +->20: or | + * 22: breq 14 ----+ + * 24: ret + * + * Test branch into delay slot already in InstructionSet + * + */ + @Test + public void testDisassemblerBranchIntoDelaySlot() throws Exception { + + programBuilder.addBytesFallthrough(10); + programBuilder.addBytesBranchWithDelaySlot(12, 20); + programBuilder.addBytesReturn(16); + + programBuilder.addBytesFallthrough(20); + programBuilder.addBytesBranchConditional(22, 14); + programBuilder.addBytesReturn(24); + + AddressSetView disAddrs = disassembler.disassemble(addr(10), null); + assertEquals(addrset(range(10, 17), range(20, 25)), disAddrs); + + verifyInstructionPresence(); + + verifyNoBookmarks(); + + Instruction instr = listing.getInstructionAt(addr(12)); + assertEquals(1, instr.getDelaySlotDepth()); + instr = listing.getInstructionAt(addr(14)); + assertTrue(instr.isInDelaySlot()); + + } + + /** + * 4: bral 14 ----+ (start2) + * | + * 10: or | (start1) + * +- 12: brds 20 | + * | 14: _or <-----+ + * | 16: ret (part of second run) + * | + * +->20: ret + * + * Test branch into delay slot already in Program + * + */ + @Test + public void testDisassemblerBranchIntoDelaySlotInProgram() throws Exception { + + programBuilder.addBytesBranch(4, 14); + + programBuilder.addBytesFallthrough(10); + programBuilder.addBytesBranchWithDelaySlot(12, 20); + programBuilder.addBytesReturn(16); + + programBuilder.addBytesReturn(20); + + AddressSetView disAddrs = disassembler.disassemble(addr(10), null); + assertEquals(addrset(range(10, 15), range(20, 21)), disAddrs); + + disAddrs = disassembler.disassemble(addr(4), null); + assertEquals(addrset(range(4, 5), range(16, 17)), disAddrs); + + verifyInstructionPresence(); + + verifyNoBookmarks(); + + Instruction instr = listing.getInstructionAt(addr(12)); + assertEquals(1, instr.getDelaySlotDepth()); + instr = listing.getInstructionAt(addr(14)); + assertTrue(instr.isInDelaySlot()); + + } + + /** + * +-- 6: bral 12 (start) + * | + * | 10: callds 30 <-+ -+ + * +-> 12: _or | | + * 14: breq 20 --+ | | + * 16: ret | | | + * | | | + * 20: or <----+ | | + * 22: bral 10 ----+ | + * | + * 30: ret <---------+ + * + * Test delay slot disassembled first + * + */ + @Test + public void testDisassemblerDelaySlotFirst() throws Exception { + + programBuilder.addBytesBranch(6, 12); + + programBuilder.addBytesCallWithDelaySlot(10, 30); + programBuilder.addBytesBranchConditional(14, 20); + programBuilder.addBytesReturn(16); + + programBuilder.addBytesFallthrough(20); + programBuilder.addBytesBranch(22, 10); + + programBuilder.addBytesReturn(30); + + AddressSetView disAddrs = disassembler.disassemble(addr(6), null); + assertEquals(addrset(range(6, 7), range(10, 17), range(20, 23), range(30, 31)), disAddrs); + + verifyInstructionPresence(); + + verifyNoBookmarks(); + + Instruction instr = listing.getInstructionAt(addr(10)); + assertEquals(1, instr.getDelaySlotDepth()); + instr = listing.getInstructionAt(addr(12)); + assertTrue(instr.isInDelaySlot()); + + } + + /** + * +-- 6: bral 12 (start1) + * | + * | 10: callds 20 <-+ (start2) + * +-> 12: or 12: _or | + * 14: ret | + * | + * 20: ret <------+ + * + * Test delay slot disassembled first in program + * + */ + @Test + public void testDisassemblerDelaySlotFirstInProgram() throws Exception { + + programBuilder.addBytesBranch(6, 12); + + programBuilder.addBytesCallWithDelaySlot(10, 20); + programBuilder.addBytesReturn(14); + + programBuilder.addBytesReturn(20); + + AddressSetView disAddrs = disassembler.disassemble(addr(6), null); + assertEquals(addrset(range(6, 7), range(12, 15)), disAddrs); + + disAddrs = disassembler.disassemble(addr(10), null); + assertEquals(addrset(range(10, 13), range(20, 21)), disAddrs); + + verifyInstructionPresence(); + + verifyNoBookmarks(); + + Instruction instr = listing.getInstructionAt(addr(10)); + assertEquals(1, instr.getDelaySlotDepth()); + instr = listing.getInstructionAt(addr(12)); + assertTrue(instr.isInDelaySlot()); + + } + + /** + * 4: fctx #2 (start) + * +-- 6: bral 14 + * | + * | 10: nfctx #3 <-+ + * | 12: callds 30 | --+ + * +-> 14: _or | | + * 16: breq 10 ----+ | + * 18: ret | + * | + * 30: ret <-----------+ + * + * Test delay slot disassembled first w/ context + * + */ + @Test + public void testDisassemblerDelaySlotFirstWithContext() throws Exception { + + programBuilder.addBytesFallthroughSetFlowContext(4, 2); + programBuilder.addBytesBranch(6, 14); + + programBuilder.addBytesFallthroughSetNoFlowContext(10, 3); + programBuilder.addBytesCallWithDelaySlot(12, 30); + programBuilder.addBytesBranchConditional(16, 10); + programBuilder.addBytesReturn(18); + + programBuilder.addBytesReturn(30); + + AddressSetView disAddrs = disassembler.disassemble(addr(4), null); + assertEquals(addrset(range(4, 7), range(10, 19), range(30, 31)), disAddrs); + + verifyInstructionPresence(); + + verifyNoBookmarks(); + + Instruction instr = listing.getInstructionAt(addr(12)); + assertEquals(1, instr.getDelaySlotDepth()); + instr = listing.getInstructionAt(addr(14)); + assertTrue(instr.isInDelaySlot()); + + //dumpContextRanges(0, 40, "fctx"); + //dumpContextRanges(0, 40, "nfctx"); + + //openProgramInTool(); + + //@formatter:off + verifyContextRanges(0, 40, "fctx", + new ContextRangeValue(6, 7, 2), + new ContextRangeValue(10, 11, 2), + new ContextRangeValue(12, 12, 2), // range split due to nfctx set @ 12 + new ContextRangeValue(13, 19, 2), + new ContextRangeValue(30, 31, 2)); + verifyContextRanges(0, 40, "nfctx", + new ContextRangeValue(12, 12, 3)); + //@formatter:on + + } + + /** + * 4: fctx #2 (start) + * +-- 6: bral 14 + * | + * | 10: nfctx #3 <-+ + * | 12: call 30 | --+ + * +-> 14: breq 10 ----+ | + * 16: ret | + * | + * 30: ret <-----------+ + * + * Test disassembly w/ context (without delay slot) + * + */ + @Test + public void testDisassemblerWithContext() throws Exception { + + programBuilder.addBytesFallthroughSetFlowContext(4, 2); + programBuilder.addBytesBranch(6, 14); + + programBuilder.addBytesFallthroughSetNoFlowContext(10, 3); + programBuilder.addBytesCall(12, 30); + programBuilder.addBytesBranchConditional(14, 10); + programBuilder.addBytesReturn(16); + + programBuilder.addBytesReturn(30); + + AddressSetView disAddrs = disassembler.disassemble(addr(4), null); + assertEquals(addrset(range(4, 7), range(10, 17), range(30, 31)), disAddrs); + + verifyInstructionPresence(); + + verifyNoBookmarks(); + + //@formatter:off + verifyContextRanges(0, 40, "fctx", + new ContextRangeValue(6, 7, 2), + new ContextRangeValue(10, 11, 2), + new ContextRangeValue(12, 12, 2), // range split due to nfctx set @ 12 + new ContextRangeValue(13, 17, 2), + new ContextRangeValue(30, 31, 2)); + verifyContextRanges(0, 40, "nfctx", + new ContextRangeValue(12, 12, 3)); + //@formatter:on + + } + + /** + * 10: nfctx #3 + * 12: cop3 + * 14: ret + * + * Test use of non-flow context in disassembly + * + */ + @Test + public void testDisassemblerNonFlowContextParse() throws Exception { + + programBuilder.addBytesFallthroughSetNoFlowContext(10, 3); + programBuilder.addBytesCopInstruction(12); + programBuilder.addBytesReturn(14); + + AddressSetView disAddrs = disassembler.disassemble(addr(10), null); + assertEquals(addrset(range(10, 15)), disAddrs); + + verifyInstructionPresence(); + + verifyNoBookmarks(); + + //@formatter:off + verifyContextRanges(0, 40, "nfctx", + new ContextRangeValue(12, 12, 3)); + //@formatter:on + + Instruction instr = listing.getInstructionAt(addr(12)); + assertEquals("cop3", instr.getMnemonicString()); + } + + /** + * 10: or + * 12: cop3 + * 14: ret + * + * Test use of non-flow context in disassembly (previously set) + * + */ + @Test + public void testDisassemblerNonFlowContextParsePreset() throws Exception { + + program.getProgramContext().setValue(program.getRegister("nfctx"), addr(12), addr(12), + BigInteger.valueOf(3)); + + programBuilder.addBytesFallthrough(10); + programBuilder.addBytesCopInstruction(12); + programBuilder.addBytesReturn(14); + + AddressSetView disAddrs = disassembler.disassemble(addr(10), null); + assertEquals(addrset(range(10, 15)), disAddrs); + + verifyInstructionPresence(); + + verifyNoBookmarks(); + + Instruction instr = listing.getInstructionAt(addr(12)); + assertEquals("cop3", instr.getMnemonicString()); + } + + /** + * 10: or + * 12: cop3 + * 14: ret + * + * Test use of non-flow context in disassembly (previously set - mid-range) + * + */ + @Test + public void testDisassemblerNonFlowContextParsePresetRange() throws Exception { + + program.getProgramContext().setValue(program.getRegister("nfctx"), addr(10), addr(12), + BigInteger.valueOf(3)); + + programBuilder.addBytesFallthrough(10); + programBuilder.addBytesCopInstruction(12); + programBuilder.addBytesReturn(14); + + AddressSetView disAddrs = disassembler.disassemble(addr(10), null); + assertEquals(addrset(range(10, 15)), disAddrs); + + verifyInstructionPresence(); + + verifyNoBookmarks(); + + Instruction instr = listing.getInstructionAt(addr(12)); + assertEquals("cop3", instr.getMnemonicString()); + } + + // + // TEST RESTRICTED DISASSEMBLY + // + + /** + * + * 10: call 30 ----+ (start) + * 12: breq 20 --+ | + * 14: ret | | + * +-> 16: ret | | (should not disassemble) + * | ^^ restrict ^^ | | + * | | | + * +-- 20: breq 16 <-+ | (should not disassemble) + * 22: ret | (should not disassemble) + * | + * 30: ret <---+ (should not disassemble) + * + * Test restricted disassembly + * + */ + @Test + public void testDisassemblerRestricted() throws Exception { + + programBuilder.addBytesCall(10, 30); + programBuilder.addBytesBranchConditional(12, 20); + programBuilder.addBytesReturn(14); + programBuilder.addBytesReturn(16); + + programBuilder.addBytesBranchConditional(20, 16); + programBuilder.addBytesReturn(22); + + programBuilder.addBytesReturn(30); + + AddressSet restrictSet = addrset(range(0, 19)); + + AddressSetView disAddrs = disassembler.disassemble(addr(10), restrictSet); + assertEquals(addrset(range(10, 15)), disAddrs); + + verifyInstructionPresence(CollectionUtils.asSet(addr(16), addr(20), addr(22), addr(30))); + + verifyNoBookmarks(); + + } + + /** + * + * 10: or + * 12: breq 14 --+ + * 14: or <----+ + * 16: or + * 18: ret (should not disassemble) + * + * Test restricted disassembly + * + */ + @Test + public void testDisassemblerRestricted2() throws Exception { + + programBuilder.addBytesFallthrough(10); + programBuilder.addBytesBranchConditional(12, 14); + programBuilder.addBytesFallthrough(14); + programBuilder.addBytesFallthrough(16); + programBuilder.addBytesReturn(18); + + AddressSet restrictSet = addrset(range(0, 17)); + + AddressSetView disAddrs = disassembler.disassemble(addr(10), restrictSet); + assertEquals(addrset(range(10, 17)), disAddrs); + + verifyInstructionPresence(CollectionUtils.asSet(addr(18))); + + verifyNoBookmarks(); + + } + + // + // TEST INSTRUCTION-SET LIMIT - FRAGMENTED DISASSEMBLY + // + + /** + * +-- 6: bral 12 (start) + * | + * | 10: callds 20 <-+ --+ + * +-> 12: _or | | + * 14: breq 10 ----+ | + * 16: ret | + * | + * 20: ret <-----------+ + * + * Test fragmented disassembly with InstructionSet size limit of 1 + * + */ + @Test + public void testDisassemblerLimit1() throws Exception { + + // Override instruction set limit + disassembler.setInstructionSetSizeLimit(1); + + programBuilder.addBytesBranch(6, 12); + + programBuilder.addBytesCallWithDelaySlot(10, 20); + programBuilder.addBytesBranchConditional(14, 10); + programBuilder.addBytesReturn(16); + + programBuilder.addBytesReturn(20); + + AddressSetView disAddrs = disassembler.disassemble(addr(6), null); + assertEquals(addrset(range(6, 7), range(10, 17), range(20, 21)), disAddrs); + + verifyInstructionPresence(); + + verifyNoBookmarks(); + + Instruction instr = listing.getInstructionAt(addr(10)); + assertEquals(1, instr.getDelaySlotDepth()); + instr = listing.getInstructionAt(addr(12)); + assertTrue(instr.isInDelaySlot()); + + } + + /** + * +-- 6: bral 12 (start) + * | + * | 10: callds 20 <-+ --+ + * +-> 12: _or | | + * 14: breq 10 ----+ | + * 16: ret | + * | + * 20: ret <-----------+ + * + * Test fragmented disassembly with InstructionSet size limit of 2 + * + */ + @Test + public void testDisassemblerLimit2() throws Exception { + + // Override instruction set limit + disassembler.setInstructionSetSizeLimit(2); + + programBuilder.addBytesBranch(6, 12); + + programBuilder.addBytesCallWithDelaySlot(10, 20); + programBuilder.addBytesBranchConditional(14, 10); + programBuilder.addBytesReturn(16); + + programBuilder.addBytesReturn(20); + + AddressSetView disAddrs = disassembler.disassemble(addr(6), null); + assertEquals(addrset(range(6, 7), range(10, 17), range(20, 21)), disAddrs); + + verifyInstructionPresence(); + + verifyNoBookmarks(); + + Instruction instr = listing.getInstructionAt(addr(10)); + assertEquals(1, instr.getDelaySlotDepth()); + instr = listing.getInstructionAt(addr(12)); + assertTrue(instr.isInDelaySlot()); + + } + + /** + * +--10: breq 20 (start) + * | 12: call 30 --+ + * | 14: ret | + * | | + * +-> 20: or | + * +-- 22: bral 40 | + * | | + * | 30: or <----+ + * | 32: bral 40 -+ + * | | + * +->40: ret <---+ + * + * Test fragmented disassembly with InstructionSet size limit of 2 + * + */ + @Test + public void testDisassemblerLimit3() throws Exception { + + // Override instruction set limit + disassembler.setInstructionSetSizeLimit(2); + + programBuilder.addBytesBranchConditional(10, 20); + programBuilder.addBytesCall(12, 30); + programBuilder.addBytesReturn(14); + + programBuilder.addBytesFallthrough(20); + programBuilder.addBytesBranch(22, 40); + + programBuilder.addBytesFallthrough(30); + programBuilder.addBytesBranch(32, 40); + + programBuilder.addBytesReturn(40); + + AddressSetView disAddrs = disassembler.disassemble(addr(10), null); + assertEquals(addrset(range(10, 15), range(20, 23), range(30, 33), range(40, 41)), disAddrs); + + verifyInstructionPresence(); + + verifyNoBookmarks(); + + } + + /** + * 1000: or + * 1002: or + * ... + * 2000: or + * 2002: ret + * + * Test fragmented disassembly with InstructionSet size limit of 2 + * + */ + @Test + public void testDisassemblerLimit4() throws Exception { + + // Override instruction set limit + disassembler.setInstructionSetSizeLimit(2); + + for (long offset = 1000; offset <= 2000; offset += 2) { + programBuilder.addBytesFallthrough(offset); + } + programBuilder.addBytesReturn(2002); + + AddressSetView disAddrs = disassembler.disassemble(addr(1000), null); + assertEquals(addrset(range(1000, 2003)), disAddrs); + + verifyInstructionPresence(); + + verifyNoBookmarks(); + + } + + /** + * 10: nfctx #3 (start) -- writes no-flow context =3 @ 30 + * +-- 14: br 22 + * | + * | 20: nop <-+ + * +-> 22: breq 30 - | -+ + * 24: br 20 --+ | + * | + * 30: cop3 <-------+ + * 32: ret + * + * Limit Size: 4 + * InstructionSet Order: 10,14,22,24/20,(22),(24),(30)/30,32 + * () - indicates instructions blocked by those already added to program + * + * Test fragmented disassembly with InstructionSet size limit of 4 + * and flow priority given to code blocks already added to program. + * Flow priority is needed to ensure that block which consumes context + * is assured of being added. + * + */ + @Test + public void testDisassemblerFlowPriority() throws Exception { + + // Override instruction set limit + disassembler.setInstructionSetSizeLimit(4); + + programBuilder.addBytesFallthroughSetNoFlowContext(10, 3, 30); + programBuilder.addBytesBranch(14, 22); + + programBuilder.addBytesFallthrough(20); + programBuilder.addBytesBranchConditional(22, 30); + programBuilder.addBytesBranch(24, 20); + + programBuilder.addBytesCopInstruction(30); + programBuilder.addBytesReturn(32); + + AddressSetView disAddrs = disassembler.disassemble(addr(10), null); + +// openProgramInTool(); + + assertEquals(addrset(range(10, 15), range(20, 25), range(30, 33)), disAddrs); + + verifyContextRanges(30, 30, "nfctx", new ContextRangeValue(30, 30, 3)); + + verifyInstructionPresence(); + + verifyNoBookmarks(); + + } + + // + // TEST DUPLICATION WITH INSTRUCTIONS IN PROGRAM + // + + /** + * + * +-> 10: breq 20 --+ (start1) + * | 12: ret | + * | | 18: breq 30 -+ (start2) + * +-- 20: breq 10 <-+ ... | + * 22: ret | + * | + * 30: ret <---+ + * + * Test bumping into existing instructions in Program mid-block + * + */ + @Test + public void testDisassemblerMidBlockOverlapWithProgram() throws Exception { + + programBuilder.addBytesBranchConditional(10, 20); + programBuilder.addBytesReturn(12); + + programBuilder.addBytesBranchConditional(20, 10); + programBuilder.addBytesReturn(22); + + AddressSetView disAddrs = disassembler.disassemble(addr(10), null); + assertEquals(addrset(range(10, 13), range(20, 23)), disAddrs); + + programBuilder.addBytesBranchConditional(18, 30); + + programBuilder.addBytesReturn(30); + + disAddrs = disassembler.disassemble(addr(18), null); + assertEquals(addrset(range(18, 19), range(30, 31)), disAddrs); + + verifyInstructionPresence(); + + verifyNoBookmarks(); + + } + +// public void testDisassemblerMidBlockOverlapWithProgramAndConflictPreservation() +// throws Exception { +// // TODO: having difficult time coming up with valid test case +// } + +// public void testDisassemblerMidBlockOverlapWithProgramAndConflictDetection() throws Exception { +// // TODO: having difficult time coming up with valid test case +// } + + // + // TEST BAD PARSE CASES + // + + /** + * 10: or + * 12: BAD (Unable to resolve constructor) + * 14: ret (Not parsed due to parse error @ 12) + * + * Test parse error + * + */ + @Test + public void testDisassemblerBadParse1() throws Exception { + + programBuilder.addBytesFallthrough(10); + programBuilder.addBytesBadInstruction(12); + programBuilder.addBytesReturn(14); + + AddressSetView disAddrs = disassembler.disassemble(addr(10), null); + assertEquals(addrset(range(10, 11)), disAddrs); + + verifyInstructionPresence(CollectionUtils.asSet(addr(14))); + + verifyErrorBookmark(addr(12), "Unable to resolve constructor"); + + } + + /** + * 10: or + * 12: cop# (Unable to resolve constructor without context) + * 14: ret (Not parsed due to parse error @ 12) + * + * Test use of non-flow context in disassembly with expected parse error (not set) + * + */ + @Test + public void testDisassemblerBadParse2() throws Exception { + + programBuilder.addBytesFallthrough(10); + programBuilder.addBytesCopInstruction(12); + programBuilder.addBytesReturn(14); + + AddressSetView disAddrs = disassembler.disassemble(addr(10), null); + assertEquals(addrset(range(10, 11)), disAddrs); + + verifyInstructionPresence(CollectionUtils.asSet(addr(12), addr(14))); + + verifyErrorBookmark(addr(12), "Unable to resolve constructor"); + + } + + // + // TEST CONFLICT CASES + // + + /** + * 10: or + * 12: ret (Not parsed due to data conflict @ 13) + * + * Test data conflict error + * + */ + @Test + public void testDisassemblerDataConflict() throws Exception { + + programBuilder.addBytesFallthrough(10); + programBuilder.addBytesReturn(12); + + listing.createData(addr(13), ByteDataType.dataType); + + AddressSetView disAddrs = disassembler.disassemble(addr(10), null); + + assertEquals(addrset(range(10, 11)), disAddrs); + + verifyInstructionPresence(CollectionUtils.asSet(addr(12))); + + verifyErrorBookmark(addr(12), "conflicting data"); + + } + + /** + * 10: or (start2) + * 12: nfctx 20,2 (4-byte instr not parsed due to instruction conflict @ 14) + * +->16: ret + * | + * | 14: imm (start1) (parsed tail of 4-byte nfctx instr) + * +--+ + * + * Test instruction conflict error + * + */ + @Test + public void testDisassemblerInstructionConflict() throws Exception { + + // instr at 14 is tail of nfctx but we need to add to program builder to register + // instruction location for verification purpose only + programBuilder.addBytesFallthrough(14); + + programBuilder.addBytesFallthrough(10); + programBuilder.addBytesFallthroughSetNoFlowContext(12, 2, 30);// overwrites instr bytes at 14 + programBuilder.addBytesReturn(16); + + AddressSetView disAddrs = disassembler.disassemble(addr(14), null); + assertEquals(addrset(range(14, 17)), disAddrs); + + disAddrs = disassembler.disassemble(addr(10), null); + assertEquals(addrset(range(10, 11)), disAddrs); + + verifyInstructionPresence(CollectionUtils.asSet(addr(12))); + + verifyErrorBookmark(addr(12), "conflicting instruction"); + + } + + /** + * +--10: breq 20 + * | 12: breq 30 ---+ + * | 14: ret | + * | | + * +-> 20: or | + * 22: nfctx 18,2 | 24: imm (forced conflict) + * +-- 26: bral 40 | + * | | + * | 30: or <-----+ + * | 32: nfctx 28,2 + * | 36: bral 40 ---+ + * | | + * +->40: ret <-----+ (clear after first dis to allow flow from 36) + * + */ + @Test + public void testDisassemblerMultipathInstructionConflict1() throws Exception { + + // instr at 24 is tail of nfctx but we need to add to program builder to register + // instruction location for verification purpose only + programBuilder.addBytesFallthrough(24); + + programBuilder.addBytesBranchConditional(10, 20); + programBuilder.addBytesBranchConditional(12, 30); + programBuilder.addBytesReturn(14); + + programBuilder.addBytesFallthrough(20); + programBuilder.addBytesFallthroughSetNoFlowContext(22, 2, 18);// overwrites instr bytes at 24 + programBuilder.addBytesBranch(26, 40); + + programBuilder.addBytesFallthrough(30); + programBuilder.addBytesFallthroughSetNoFlowContext(32, 2, 18); + programBuilder.addBytesBranch(36, 40); + + programBuilder.addBytesReturn(40); + + AddressSetView disAddrs = disassembler.disassemble(addr(24), null); + assertEquals(addrset(range(24, 27), range(40, 41)), disAddrs); + + // clear instruction at 40 to allow flow from 36 + program.getListing().clearCodeUnits(addr(40), addr(40), true); + + disAddrs = disassembler.disassemble(addr(10), null); + assertEquals(addrset(range(10, 15), range(20, 21), range(30, 37), range(40, 41)), disAddrs); + + verifyInstructionPresence(CollectionUtils.asSet(addr(22))); + + verifyErrorBookmark(addr(22), "conflicting instruction"); + + } + + /** + * +--10: breq 20 + * | 12: breq 30 ---+ + * | 14: ret | + * | | + * +-> 20: or | + * 22: nfctx 18,2 | + * +-- 26: bral 40 | + * | | + * | 30: or <-----+ + * | 32: nfctx 28,2 34: imm (forced conflict) + * | 36: bral 40 ---+ + * | | + * +->40: ret <-----+ (clear after first dis to allow flow from 26) + * + */ + @Test + public void testDisassemblerMultipathInstructionConflict2() throws Exception { + + // instr at 24 is tail of nfctx but we need to add to program builder to register + // instruction location for verification purpose only + programBuilder.addBytesFallthrough(34); + + programBuilder.addBytesBranchConditional(10, 20); + programBuilder.addBytesBranchConditional(12, 30); + programBuilder.addBytesReturn(14); + + programBuilder.addBytesFallthrough(20); + programBuilder.addBytesFallthroughSetNoFlowContext(22, 2, 18); + programBuilder.addBytesBranch(26, 40); + + programBuilder.addBytesFallthrough(30); + programBuilder.addBytesFallthroughSetNoFlowContext(32, 2, 18);// overwrites instr bytes at 34 + programBuilder.addBytesBranch(36, 40); + + programBuilder.addBytesReturn(40); + + AddressSetView disAddrs = disassembler.disassemble(addr(34), null); + assertEquals(addrset(range(34, 37), range(40, 41)), disAddrs); + + // clear instruction at 40 to allow flow from 26 + program.getListing().clearCodeUnits(addr(40), addr(40), true); + + disAddrs = disassembler.disassemble(addr(10), null); + assertEquals(addrset(range(10, 15), range(20, 27), range(30, 31), range(40, 41)), disAddrs); + + verifyInstructionPresence(CollectionUtils.asSet(addr(32))); + + verifyErrorBookmark(addr(32), "conflicting instruction"); + + } + + /** + * 10: nfctx #3 (start) + * 12: cop # <-----+ (conflict due to varying context) + * 14: bral 20 -----+ | + * | | + * 20: nfctx 12,2 <-+ | (4-byte instr) + * 24: breq 12 ------+ + * 26: ret + * + * Test use of non-flow context in disassembly with expected parse error + * + */ + @Test + public void testDisassemblerInconsistentStartBlock() throws Exception { + + programBuilder.addBytesFallthroughSetNoFlowContext(10, 3); + programBuilder.addBytesCopInstruction(12); + programBuilder.addBytesBranch(14, 20); + + programBuilder.addBytesFallthroughSetNoFlowContext(20, 2, 12); + programBuilder.addBytesBranchConditional(24, 12); + programBuilder.addBytesReturn(26); + + AddressSetView disAddrs = disassembler.disassemble(addr(10), null); + assertEquals(addrset(range(10, 15), range(20, 27)), disAddrs); + + verifyInstructionPresence(); + + verifyErrorBookmark(addr(12), "inconsistent instruction prototype"); + + } + + /** + * 6: bral 12 --+ (start w/ nfctx=2 @ 12) + * | + * +-> 10: nfctx #3 | + * | 12: cop3 <--+ (conflict due to varying context) + * +-- 14: bral 10 + * + * Test use of non-flow context in disassembly with expected parse error + * + */ + @Test + public void testDisassemblerInconsistentMidBlock() throws Exception { + + program.getProgramContext().setValue(program.getRegister("nfctx"), addr(12), addr(12), + BigInteger.valueOf(2)); + + programBuilder.addBytesBranch(6, 12); + + programBuilder.addBytesFallthroughSetNoFlowContext(10, 3); + programBuilder.addBytesCopInstruction(12); + programBuilder.addBytesBranch(14, 10); + + AddressSetView disAddrs = disassembler.disassemble(addr(6), null); + assertEquals(addrset(range(6, 7), range(10, 15)), disAddrs); + + verifyInstructionPresence(); + + verifyErrorBookmark(addr(12), "inconsistent instruction prototype"); + + } + + /** + * 10: nfctx #3 (start1) + * 12: cop # <-----+ (conflict due to varying context) + * 14: ret | + * | + * 20: nfctx 12,2 | (start2) (4-byte instr) + * 24: breq 12 ------+ + * 26: ret + * + * Test use of non-flow context in disassembly with expected parse error + * + */ + @Test + public void testDisassemblerInconsistentStartBlockInProgram() throws Exception { + + programBuilder.addBytesFallthroughSetNoFlowContext(10, 3); + programBuilder.addBytesCopInstruction(12); + programBuilder.addBytesReturn(14); + + programBuilder.addBytesFallthroughSetNoFlowContext(20, 2, 12); + programBuilder.addBytesBranchConditional(24, 12); + programBuilder.addBytesReturn(26); + + AddressSetView disAddrs = disassembler.disassemble(addr(10), null); + assertEquals(addrset(range(10, 15)), disAddrs); + + disAddrs = disassembler.disassemble(addr(20), null); + assertEquals(addrset(range(20, 27)), disAddrs); + + verifyInstructionPresence(); + + verifyErrorBookmark(addr(12), "inconsistent instruction prototype"); + + } + + /** + * 6: bral 12 --+ (start1 w/ nfctx=2 @ 12) + * | + * 10: nfctx #3 | (start2) + * 12: cop3 <--+ (conflict due to varying context) + * 14: ret + * + * Test use of non-flow context in disassembly with expected parse error + * + */ + @Test + public void testDisassemblerInconsistentMidBlockInProgram() throws Exception { + + program.getProgramContext().setValue(program.getRegister("nfctx"), addr(12), addr(12), + BigInteger.valueOf(2)); + + programBuilder.addBytesBranch(6, 12); + + programBuilder.addBytesFallthroughSetNoFlowContext(10, 3); + programBuilder.addBytesCopInstruction(12); + programBuilder.addBytesReturn(14); + + AddressSetView disAddrs = disassembler.disassemble(addr(6), null); + assertEquals(addrset(range(6, 7), range(12, 15)), disAddrs); + + disAddrs = disassembler.disassemble(addr(10), null); + assertEquals(addrset(range(10, 11)), disAddrs); + + verifyInstructionPresence(); + + verifyErrorBookmark(addr(12), "inconsistent instruction prototype"); + + } + +// public void testDisassemblerMultipleConflictsWithinBlock() throws Exception { +// // TODO: having difficult time coming up with valid test case +// } + + // + // TEST MEMORY RESTRICTIONS + // + + /** + * +-- 4: breq 11 (error bookmark on unaligned flow) + * | 6: ret (not disassembled - due to halted flow) + * | + * +-> 11: ret (not allowed - unaligned) + * + * Test unaligned disassembly + * + */ + @Test + public void testDisassemblerUnaligned() throws Exception { + + programBuilder.addBytesBranchConditional(4, 11); + programBuilder.addBytesReturn(6); + + programBuilder.addBytesReturn(11); + + AddressSetView disAddrs = disassembler.disassemble(addr(4), null); + assertEquals(addrset(range(4, 5)), disAddrs); + + verifyInstructionPresence(CollectionUtils.asSet(addr(6), addr(11))); + + verifyErrorBookmark(addr(4), "violates 2-byte instruction alignment"); + + } + + /** + * +-- 4: bral 10 + * | + * +-> 10: nfctx 20,2 (4-byte instr) + * 14: bral 20 --+ | (offcut conflict error @ 12) + * | | + * 20: cop #2 <-+ | + * 22: bral 12 ----+ (offcut conflict error) + * + * Test offcut-conflict disassembly + * + */ + @Test + public void testDisassemblerOffcutConflict() throws Exception { + + programBuilder.addBytesBranch(4, 10); + + programBuilder.addBytesFallthroughSetNoFlowContext(10, 2, 20); + programBuilder.addBytesBranch(14, 20); + + programBuilder.addBytesCopInstruction(20); + programBuilder.addBytesBranch(22, 12); + + AddressSetView disAddrs = disassembler.disassemble(addr(4), null); + assertEquals(addrset(range(4, 5), range(10, 15), range(20, 23)), disAddrs); + + verifyInstructionPresence(); + + verifyErrorBookmark(addr(12), "conflicting instruction"); + + } + + /** + * +-- 4: bral 10 + * | + * +-> 10: nfctx 20,2 (4-byte instr) + * 14: bral 20 --+ | (offcut conflict error @ 12) + * | | + * 20: cop #2 <-+ | + * 22: ret | + * | + * 30: bral 12 ----+ + * + * Test offcut-conflict disassembly + * + */ + @Test + public void testDisassemblerOffcutConflictInProgram() throws Exception { + + programBuilder.addBytesBranch(4, 10); + + programBuilder.addBytesFallthroughSetNoFlowContext(10, 2, 20); + programBuilder.addBytesBranch(14, 20); + + programBuilder.addBytesCopInstruction(20); + programBuilder.addBytesReturn(22); + + programBuilder.addBytesBranch(30, 12); + + AddressSetView disAddrs = disassembler.disassemble(addr(4), null); + assertEquals(addrset(range(4, 5), range(10, 15), range(20, 23)), disAddrs); + + disAddrs = disassembler.disassemble(addr(30), null); + assertEquals(addrset(range(30, 31)), disAddrs); + + verifyInstructionPresence(); + + verifyErrorBookmark(addr(12), "conflicting instruction"); + + } + + /** + * 10: bral 200 (error on flow to non-existing memory) + * + * Test flow into non-existing memory + * + */ + @Test + public void testDisassemblerNoMemory() throws Exception { + + programBuilder.addBytesBranch(10, 0xffffffe0L); + + AddressSetView disAddrs = disassembler.disassemble(addr(10), null); + assertEquals(addrset(range(10, 11)), disAddrs); + + verifyInstructionPresence(); + + verifyErrorBookmark(addr(10), "non-existing memory"); + + } + +// public void testDisassemblerNonInitializedMemory() throws Exception { +// // TODO: currently we ignore attempts to disassemble into Non-Intialized Memory +// } + + @Test + public void testDisassemblerNoExecuteMemory() throws Exception { + // TODO: need to do this in master branch + } + +} diff --git a/Ghidra/Test/IntegrationTest/src/test/java/ghidra/program/model/lang/RegisterValueContextTest.java b/Ghidra/Test/IntegrationTest/src/test/java/ghidra/program/model/lang/RegisterValueContextTest.java new file mode 100644 index 0000000000..21fa0b663e --- /dev/null +++ b/Ghidra/Test/IntegrationTest/src/test/java/ghidra/program/model/lang/RegisterValueContextTest.java @@ -0,0 +1,121 @@ +/* ### + * 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.program.model.lang; + +import static org.junit.Assert.assertEquals; + +import java.math.BigInteger; + +import org.junit.Before; +import org.junit.Test; + +import ghidra.test.AbstractGhidraHeadlessIntegrationTest; + +public class RegisterValueContextTest extends AbstractGhidraHeadlessIntegrationTest { + + private Language language; + + private Register regContext; + + @Before + public void setUp() throws Exception { + LanguageService languageService = getLanguageService(); + language = languageService.getLanguage(new LanguageID("x86:LE:32:default")); + + regContext = language.getContextBaseRegister();// 4-byte context reg + } + + @Test + public void testRegisterValueMask() { + + RegisterValue val = new RegisterValue(regContext, BigInteger.valueOf(0x12345678)); + BigInteger value = val.getUnsignedValue(); + assertEquals(0x12345678, value.longValue()); + BigInteger valueMask = val.getValueMask(); + assertEquals(0xffffffffL, valueMask.longValue()); + + RegisterValue newValue = new RegisterValue(regContext, value, valueMask); + assertEquals(0x12345678, newValue.getUnsignedValue().longValue()); + assertEquals(0xffffffffL, newValue.getValueMask().longValue()); + + } + + @Test + public void testBytes() { + + RegisterValue val = new RegisterValue(regContext, + new byte[] { (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, 1, 2, 3, 4 }); + + assertEquals(0x01020304, val.getUnsignedValueIgnoreMask().longValue()); + assertEquals(0x01020304, val.getSignedValueIgnoreMask().longValue()); + assertEquals(0x01020304, val.getUnsignedValue().longValue()); + assertEquals(0x01020304, val.getSignedValue().longValue()); + assertEquals(0x0ffffffffL, val.getValueMask().longValue()); + + val = new RegisterValue(regContext, + new byte[] { (byte) 0xff, (byte) 0xff, (byte) 0xf0, (byte) 0xff, 1, 2, 3, 4 }); + + assertEquals(0x01020304, val.getUnsignedValueIgnoreMask().longValue()); + assertEquals(0x01020304, val.getSignedValueIgnoreMask().longValue()); + assertEquals(null, val.getUnsignedValue()); + assertEquals(null, val.getSignedValue()); + assertEquals(0x0fffff0ffL, val.getValueMask().longValue()); + } + + @Test + public void testBytesGrow() { + + RegisterValue val = + new RegisterValue(regContext, new byte[] { (byte) 0xff, (byte) 0xff, 0x12, 0x34 }); + + assertEquals(0x12340000, val.getUnsignedValueIgnoreMask().longValue()); + assertEquals(0x12340000, val.getSignedValueIgnoreMask().longValue()); + assertEquals(null, val.getUnsignedValue()); + assertEquals(null, val.getSignedValue()); + assertEquals(0x0ffff0000L, val.getValueMask().longValue()); + + val = new RegisterValue(regContext, new byte[] { (byte) 0x10, (byte) 0xff, 0x12, 0x34 }); + + assertEquals(0x10340000, val.getUnsignedValueIgnoreMask().longValue()); + assertEquals(0x10340000, val.getSignedValueIgnoreMask().longValue()); + assertEquals(null, val.getUnsignedValue()); + assertEquals(null, val.getSignedValue()); + assertEquals(0x10ff0000, val.getValueMask().longValue()); + } + + @Test + public void testBytesShrink() { + + RegisterValue val = new RegisterValue(regContext, new byte[] { (byte) 0xff, (byte) 0xff, + (byte) 0xff, (byte) 0xff, 0, 0, 0, 0, 0x12, 0x34, 0x56, 0x78, 0, 0, 0, 0 }); + + assertEquals(0x12345678, val.getUnsignedValueIgnoreMask().longValue()); + assertEquals(0x12345678, val.getSignedValueIgnoreMask().longValue()); + assertEquals(0x12345678, val.getUnsignedValue().longValue()); + assertEquals(0x12345678, val.getSignedValue().longValue()); + assertEquals(0x0ffffffffL, val.getValueMask().longValue()); + + val = new RegisterValue(regContext, new byte[] { (byte) 0xff, (byte) 0xff, (byte) 0xf0, + (byte) 0xff, 0, 0, 0, 0, 0x12, 0x34, 0x56, 0x78, 0, 0, 0, 0 }); + + assertEquals(0x12345078, val.getUnsignedValueIgnoreMask().longValue()); + assertEquals(0x12345078, val.getSignedValueIgnoreMask().longValue()); + assertEquals(null, val.getUnsignedValue()); + assertEquals(null, val.getSignedValue()); + assertEquals(0x0fffff0ffL, val.getValueMask().longValue()); + } + +} diff --git a/Ghidra/Test/IntegrationTest/src/test/java/ghidra/program/model/lang/RegisterValueTest.java b/Ghidra/Test/IntegrationTest/src/test/java/ghidra/program/model/lang/RegisterValueTest.java new file mode 100644 index 0000000000..67443c1e1b --- /dev/null +++ b/Ghidra/Test/IntegrationTest/src/test/java/ghidra/program/model/lang/RegisterValueTest.java @@ -0,0 +1,162 @@ +/* ### + * 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.program.model.lang; + +import static org.junit.Assert.assertEquals; + +import java.math.BigInteger; + +import org.junit.Before; +import org.junit.Test; + +import ghidra.test.AbstractGhidraHeadlessIntegrationTest; + +public class RegisterValueTest extends AbstractGhidraHeadlessIntegrationTest { + + private Language language; + + private Register regEAX; + private Register regAX; + private Register regAH; + private Register regAL; + + private Register regEBX; + private Register regBX; + private Register regBH; + private Register regBL; + + private Register regCF; + + @Before + public void setUp() throws Exception { + LanguageService languageService = getLanguageService(); + language = languageService.getLanguage(new LanguageID("x86:LE:32:default")); + + regEAX = language.getRegister("EAX");// 4-byte reg within 8-byte parent + regAX = language.getRegister("AX"); + regAH = language.getRegister("AH"); + regAL = language.getRegister("AL"); + + regEBX = language.getRegister("EBX");// 4-byte reg within 8-byte parent + regBX = language.getRegister("BX"); + regBH = language.getRegister("BH"); + regBL = language.getRegister("BL"); + + regCF = language.getRegister("CF");// 1-byte reg (basereg) + } + + @Test + public void testRegisterValueMask() { + + RegisterValue valAH = new RegisterValue(regAH, BigInteger.valueOf(0x55)); + BigInteger value = valAH.getUnsignedValue(); + assertEquals(0x55, value.longValue()); + BigInteger valueMask = valAH.getValueMask(); + assertEquals(0xff, valueMask.longValue()); + + RegisterValue newValue = new RegisterValue(regBH, value, valueMask); + assertEquals(0x55, newValue.getUnsignedValue().longValue()); + assertEquals(0xff, newValue.getValueMask().longValue()); + + newValue = newValue.getRegisterValue(regEBX); + assertEquals(0x5500, newValue.getUnsignedValueIgnoreMask().longValue()); + assertEquals(0xff00, newValue.getValueMask().longValue()); + + newValue = new RegisterValue(regBL, value, valueMask); + assertEquals(0x55, newValue.getUnsignedValue().longValue()); + assertEquals(0xff, newValue.getValueMask().longValue()); + + RegisterValue valEAX = valAH.getRegisterValue(regEAX).assign(regAL, newValue); + assertEquals(0x5555, valEAX.getUnsignedValueIgnoreMask().longValue()); + assertEquals(0xffff, valEAX.getValueMask().longValue()); + + } + + @Test + public void testBytes() { + + RegisterValue val = new RegisterValue(regEBX, + new byte[] { (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, + (byte) 0xff, (byte) 0xff, (byte) 0xff, 0, 0, 0, 0, 0, 0, 0x12, 0x34 }); + + assertEquals(0x1234, val.getUnsignedValueIgnoreMask().longValue()); + assertEquals(0x1234, val.getSignedValueIgnoreMask().longValue()); + assertEquals(0x1234, val.getUnsignedValue().longValue()); + assertEquals(0x1234, val.getSignedValue().longValue()); + assertEquals(0x0ffffffffL, val.getValueMask().longValue()); + + val = new RegisterValue(regEBX, + new byte[] { (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, + (byte) 0xff, (byte) 0xf0, (byte) 0xff, 0, 0, 0, 0, 0, 0, 0x12, 0x34 }); + + assertEquals(0x1034, val.getUnsignedValueIgnoreMask().longValue()); + assertEquals(0x1034, val.getSignedValueIgnoreMask().longValue()); + assertEquals(null, val.getUnsignedValue()); + assertEquals(null, val.getSignedValue()); + assertEquals(0x0fffff0ffL, val.getValueMask().longValue()); + } + + @Test + public void testBytesGrow() { + + RegisterValue val = + new RegisterValue(regEBX, new byte[] { (byte) 0xff, (byte) 0xff, 0x12, 0x34 }); + + assertEquals(0x1234, val.getUnsignedValueIgnoreMask().longValue()); + assertEquals(0x1234, val.getSignedValueIgnoreMask().longValue()); + assertEquals(0x1234, val.getUnsignedValue().longValue()); + assertEquals(0x1234, val.getSignedValue().longValue()); + assertEquals(0x0ffffffffL, val.getValueMask().longValue()); + + val = new RegisterValue(regEBX, new byte[] { (byte) 0x10, (byte) 0xff, 0x12, 0x34 }); + + assertEquals(0x1034, val.getUnsignedValueIgnoreMask().longValue()); + assertEquals(0x1034, val.getSignedValueIgnoreMask().longValue()); + assertEquals(null, val.getUnsignedValue()); + assertEquals(null, val.getSignedValue()); + assertEquals(0x10ff, val.getValueMask().longValue()); + } + + @Test + public void testBytesShrink() { + + RegisterValue val = + new RegisterValue(regCF, new byte[] { (byte) 0xff, (byte) 0xff, 0x12, 0x34 }); + + assertEquals(0x34, val.getUnsignedValueIgnoreMask().longValue()); + assertEquals(0x34, val.getSignedValueIgnoreMask().longValue()); + assertEquals(0x34, val.getUnsignedValue().longValue()); + assertEquals(0x34, val.getSignedValue().longValue()); + assertEquals(0x0ffL, val.getValueMask().longValue()); + + val = new RegisterValue(regCF, new byte[] { (byte) 0xf0, (byte) 0xff, 0x12, 0x34 }); + + assertEquals(0x34, val.getUnsignedValueIgnoreMask().longValue()); + assertEquals(0x34, val.getSignedValueIgnoreMask().longValue()); + assertEquals(0x34, val.getUnsignedValue().longValue()); + assertEquals(0x34, val.getSignedValue().longValue()); + assertEquals(0x0ffL, val.getValueMask().longValue()); + + val = new RegisterValue(regCF, new byte[] { (byte) 0xff, (byte) 0xf0, 0x12, 0x34 }); + + assertEquals(0x30, val.getUnsignedValueIgnoreMask().longValue()); + assertEquals(0x30, val.getSignedValueIgnoreMask().longValue()); + assertEquals(null, val.getUnsignedValue()); + assertEquals(null, val.getSignedValue()); + assertEquals(0x0f0, val.getValueMask().longValue()); + } + +} diff --git a/Ghidra/Test/IntegrationTest/src/test/java/ghidra/server/RepositoryFileSystemTest.java b/Ghidra/Test/IntegrationTest/src/test/java/ghidra/server/RepositoryFileSystemTest.java new file mode 100644 index 0000000000..c4a938236f --- /dev/null +++ b/Ghidra/Test/IntegrationTest/src/test/java/ghidra/server/RepositoryFileSystemTest.java @@ -0,0 +1,428 @@ +/* ### + * 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.server; + +import static org.junit.Assert.*; + +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +import org.junit.*; + +import db.*; +import db.buffers.BufferFile; +import db.buffers.ManagedBufferFile; +import ghidra.framework.client.ClientUtil; +import ghidra.framework.store.*; +import ghidra.framework.store.local.LocalFileSystem; +import ghidra.server.store.RepositoryFile; +import ghidra.server.store.RepositoryFolder; +import ghidra.test.AbstractGhidraHeadedIntegrationTest; +import ghidra.util.Msg; +import ghidra.util.exception.FileInUseException; +import utilities.util.FileUtilities; + +public class RepositoryFileSystemTest extends AbstractGhidraHeadedIntegrationTest { + + private static final String USER = ClientUtil.getUserName(); + + private File serverRoot; + + private RepositoryManager mgr; + private Repository repository; + + private List