GT-3035 - Restore Integration Tests - restored missing test files; fast

tests
This commit is contained in:
dragonmacher 2019-08-14 15:08:37 -04:00
parent 822e5a0610
commit 4dc8e77172
45 changed files with 6609 additions and 0 deletions

View file

@ -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);
}
}

View file

@ -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);
}
}

View file

@ -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();
}
}
}

View file

@ -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());
}
}
}

View file

@ -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());
}
}

View file

@ -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 = "<?xml version='1.0' encoding='ISO-8859-1' ?>\n" +
"<!-- Auto-generated on Fri Apr 03 09:37:08 EDT 2015 -->\n\n" +
"<tocroot>\n" +
"</tocroot>\n";
//@formatter:on
Files.write(file, TOCXML.getBytes(), StandardOpenOption.CREATE);
return file;
}
protected Path createHelpContent(Path topic, String anchor) throws IOException {
Path htmlPath = topic.resolve(HELP_FILENAME);
Path file = Files.createFile(htmlPath);
if (anchor == null) {
anchor = "Default_Anchor";
}
//@formatter:off
String HTML =
"<HTML>\n" +
"<HEAD>\n" +
"<TITLE>Configure Tool</TITLE>\n" +
"<LINK rel=\"stylesheet\" type=\"text/css\" href=\"../../shared/Frontpage.css\">\n" +
"</HEAD>\n" +
"<BODY>\n" +
" <H1><A name=\""+anchor+"\"></A>Configure Tool</H1>\n" +
" Some text with reference to shared image <IMG src=\"../../shared/test.png\">\n" +
" \n" +
"</BODY>\n" +
"</HTML>\n";
//@formatter:on
Files.write(file, HTML.getBytes(), StandardOpenOption.CREATE);
return file;
}
protected Path createHelpContent_WithReferenceHREF(Path topic, String HREF) throws IOException {
Path htmlPath = topic.resolve(HELP_FILENAME);
Path file = Files.createFile(htmlPath);
assertNotNull("Must specify the A tag HREF attribute", HREF);
//@formatter:off
String HTML =
"<HTML>\n" +
"<HEAD>\n" +
"<TITLE>Configure Tool</TITLE>\n" +
"<LINK rel=\"stylesheet\" type=\"text/css\" href=\"../../shared/Frontpage.css\">\n" +
"</HEAD>\n" +
"<BODY>\n" +
" <H1><A name=\"Fake_Anchor\"></A>Configure Tool</H1>\n" +
" And this is a link <A HREF=\""+HREF+"\">Click Me</A>" +
" \n" +
"</BODY>\n" +
"</HTML>\n";
//@formatter:on
Files.write(file, HTML.getBytes(), StandardOpenOption.CREATE);
return file;
}
protected Path createHelpContent_WithReferenceIMG_SRC(Path topic, String SRC)
throws IOException {
Path htmlPath = topic.resolve(HELP_FILENAME);
Path file = Files.createFile(htmlPath);
assertNotNull("Must specify the A tag SRC attribute", SRC);
//@formatter:off
String HTML =
"<HTML>\n" +
"<HEAD>\n" +
"<TITLE>Configure Tool</TITLE>\n" +
"<LINK rel=\"stylesheet\" type=\"text/css\" href=\"../../shared/Frontpage.css\">\n" +
"</HEAD>\n" +
"<BODY>\n" +
" <H1><A name=\"Fake_Anchor\"></A>Configure Tool</H1>\n" +
" Some text with reference to shared image <IMG src=\""+SRC+"\">\n" +
" \n" +
"</BODY>\n" +
"</HTML>\n";
//@formatter:on
Files.write(file, HTML.getBytes(), StandardOpenOption.CREATE);
return file;
}
protected void copy(Path from, Path to) throws Exception {
FileUtilities.copyDir(from.toFile(), to.toFile(), null);
}
}

View file

@ -0,0 +1,99 @@
/* ###
* 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.*;
import java.net.URISyntaxException;
import java.nio.file.Path;
import java.nio.file.Paths;
import org.junit.Test;
public class HelpBuildUtilsTest extends AbstractHelpTest {
private static final String HELP_TOPIC_PATH = "/some/fake/path/to/help/topics";
private static final String TOPIC_AND_FILENAME = "FooTopic/FooFile.html";
private static final String HTML_FILE_PATH = HELP_TOPIC_PATH + '/' + TOPIC_AND_FILENAME;
public HelpBuildUtilsTest() {
super();
}
@Test
public void testGetRelativeHelpPath() {
String relativeString = "help/topics/FooTopic/FooFile.html";
Path path = Paths.get("/some/fake/path/to/" + relativeString);
Path relative = HelpBuildUtils.relativizeWithHelpTopics(path);
assertEquals(relativeString, relative.toString());
}
@Test
public void testGetRelativeHelpPath_NoHelpTopicInPath() {
String invalidRelativeString = "help/topicz/" + TOPIC_AND_FILENAME;
Path path = Paths.get("/some/fake/path/to/" + invalidRelativeString);
Path relative = HelpBuildUtils.relativizeWithHelpTopics(path);
assertNull(relative);
}
@Test
public void testLocateReference_Local_HelpSystemSyntax() throws URISyntaxException {
Path sourceFile = Paths.get(HTML_FILE_PATH);
String reference = "help/topics/shared/foo.png";
Path resolved = HelpBuildUtils.locateReference(sourceFile, reference);
assertEquals("Help System syntax was not preserved", Paths.get(reference), resolved);
}
@Test
public void testLocateReference_Local_RelativeSyntax() throws URISyntaxException {
Path sourceFile = Paths.get(HTML_FILE_PATH);
String reference = "../shared/foo.png";// go up one to the help dir
Path resolved = HelpBuildUtils.locateReference(sourceFile, reference);
assertEquals("Relative syntax did not locate file",
Paths.get(HELP_TOPIC_PATH + "/shared/foo.png"), resolved);
}
@Test
public void testLocateReference_Remote() throws URISyntaxException {
Path sourceFile = Paths.get(HTML_FILE_PATH);
String reference = "http://some.fake.server/foo.png";
Path resolved = HelpBuildUtils.locateReference(sourceFile, reference);
assertNull(resolved);
boolean isRemote = HelpBuildUtils.isRemote(reference);
assertTrue(isRemote);
}
@Test
public void testLocateReferences_Icons() throws URISyntaxException {
Path sourceFile = Paths.get(HTML_FILE_PATH);
String reference = "Icons.REFRESH_ICON"; // see Icons class
ImageLocation location = HelpBuildUtils.locateImageReference(sourceFile, reference);
Path resolved = location.getResolvedPath();
String name = resolved.getFileName().toString();
assertEquals("Help System syntax was not preserved", "reload3.png", name);
assertTrue(location.isRuntime());
assertFalse(location.isRemote());
}
@Test
public void testLocateReferences_Icons_BadName() throws URISyntaxException {
Path sourceFile = Paths.get(HTML_FILE_PATH);
String reference = "Icons.REFRESH_ICON_BAD"; // non-existent
ImageLocation location = HelpBuildUtils.locateImageReference(sourceFile, reference);
Path resolved = location.getResolvedPath();
assertNull(resolved);
}
}

View file

@ -0,0 +1,418 @@
/* ###
* 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.assertEquals;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.help.HelpSet;
import org.junit.Test;
import help.validator.LinkDatabase;
import help.validator.location.*;
import help.validator.model.*;
public class OverlayHelpTreeTest {
@Test
public void testSourceTOCFileThatDependsUponPreBuiltHelp() {
//
// We want to make sure the overlay tree will properly resolve help TOC items being
// built from TOC_Source.xml files when that file uses <TOCREF> items that are defined
// in a help <TOCITEM> that lives inside of a pre-built jar file.
//
/*
Example makeup we will create:
PreBuild_TOC.xml
<tocitem id="root" target="fake">
<tocitem id="child_1" target="fake" />
</tocitem>
TOC_Source.xml
<tocref id="root">
<tocref="child_1">
<tocdef id="child_2" target="fake" />
</tocref>
</tocref>
*/
TOCItemExternal root = externalItem("root");
TOCItemExternal child_1 = externalItem(root, "child_1");
Path tocSourceFile = Paths.get("/fake/path_2/TOC_Source.xml");
String root_ID = root.getIDAttribute();
TOCItemReference root_ref = referenceItem(root_ID, tocSourceFile);
String child_1_ID = child_1.getIDAttribute();
TOCItemReference child_1_ref = referenceItem(root_ref, child_1_ID, tocSourceFile);
TOCItemDefinition child_2 = definitionItem(child_1_ref, "child_2", tocSourceFile);
TOCItemProviderTestStub tocProvider = new TOCItemProviderTestStub();
tocProvider.addExternal(root);
tocProvider.addExternal(child_1);
tocProvider.addDefinition(child_2);
TOCSpyWriter spy = printOverlayTree(tocProvider, tocSourceFile);
assertNodeCount(spy, 3);
assertOrder(spy, 1, root);
assertOrder(spy, 2, child_1);
assertOrder(spy, 3, child_2);
}
@Test
public void testSourceTOCFileThatDependsUponPreBuiltHelp_MultiplePreBuiltInputs() {
//
// We want to make sure the overlay tree will properly resolve help TOC items being
// built from TOC_Source.xml files when that file uses <TOCREF> items that are defined
// in a help <TOCITEM> that lives inside of multiple pre-built jar files.
//
/*
Example makeup we will create:
PreBuild_TOC.xml
<tocitem id="root" target="fake">
<tocitem id="child_1" target="fake">
<tocitem="prebuilt_a_child" target="fake" />
</tocitem>
</tocitem>
Another PreBuild_TOC.xml
<tocitem id="root" target="fake">
<tocitem id="child_1" target="fake">
<tocitem="prebuilt_b_child" target="fake" />
</tocitem>
</tocitem>
TOC_Source.xml
<tocref id="root">
<tocref="child_1">
<tocdef id="child_2" target="fake" />
</tocref>
</tocref>
*/
TOCItemExternal root_a = externalItem("root");
TOCItemExternal child_1_a = externalItem(root_a, "child_1");
TOCItemExternal prebuilt_a_child = externalItem(child_1_a, "prebuilt_a_child");
// note: same ID values, since they represent the same nodes, but from different TOC files
TOCItemExternal root_b = externalItemAlt(null, "root");
TOCItemExternal child_1_b = externalItemAlt(root_b, "child_1");
TOCItemExternal prebuilt_b_child = externalItemAlt(child_1_b, "prebuilt_b_child");
Path tocSourceFile = Paths.get("/fake/path_2/TOC_Source.xml");
String root_ID = root_a.getIDAttribute();
TOCItemReference root_ref = referenceItem(root_ID, tocSourceFile);
String child_1_ID = child_1_a.getIDAttribute();
TOCItemReference child_1_ref = referenceItem(root_ref, child_1_ID, tocSourceFile);
TOCItemDefinition child_2 = definitionItem(child_1_ref, "child_2", tocSourceFile);
TOCItemProviderTestStub tocProvider = new TOCItemProviderTestStub();
tocProvider.addExternal(root_a);
tocProvider.addExternal(root_b);
tocProvider.addExternal(child_1_a);
tocProvider.addExternal(child_1_b);
tocProvider.addExternal(prebuilt_a_child);
tocProvider.addExternal(prebuilt_b_child);
tocProvider.addDefinition(child_2);
TOCSpyWriter spy = printOverlayTree(tocProvider, tocSourceFile);
assertNodeCount(spy, 3);
assertOrder(spy, 1, root_a);// could also be root_b, same ID
assertOrder(spy, 2, child_1_a);// could also be child_1_b, same ID
assertOrder(spy, 3, child_2);
// note: prebuilt_a_child and prebuilt_b_child don't get output, since they do not have
// the same TOC file ID as the help file being processed (in other words, they don't
// live in the TOC_Source.xml being processes, so they are not part of the output).
}
@Test
public void testSourceTOCFileThatDependsAnotherTOCSourceFile() {
/*
The first source file defines attributes that the second file references.
Example makeup we will create:
TOC_Source.xml
<tocdef id="root" target="fake">
<tocdef id="child_1" target="fake" />
</tocdef>
Another TOC_Source.xml
<tocref id="root">
<tocref="child_1">
<tocdef id="child_2" target="fake" />
</tocref>
</tocref>
*/
Path toc_1 = Paths.get("/fake/path_1/TOC_Source.xml");
TOCItemDefinition root = definitionItem("root", toc_1);
TOCItemDefinition child_1 = definitionItem(root, "child_1", toc_1);
Path toc_2 = Paths.get("/fake/path_2/TOC_Source.xml");
String root_ID = root.getIDAttribute();
String child_1_ID = child_1.getIDAttribute();
TOCItemReference root_ref = referenceItem(root_ID, toc_2);
TOCItemReference child_1_ref = referenceItem(root_ref, child_1_ID, toc_2);
TOCItemDefinition child_2 = definitionItem(child_1_ref, "child_2", toc_2);
TOCItemProviderTestStub tocProvider = new TOCItemProviderTestStub();
tocProvider.addDefinition(root);
tocProvider.addDefinition(child_1);
tocProvider.addDefinition(child_2);// in the second TOC file
TOCSpyWriter spy = printOverlayTree(tocProvider, toc_2);
assertNodeCount(spy, 3);
assertOrder(spy, 1, root);
assertOrder(spy, 2, child_1);
assertOrder(spy, 3, child_2);
}
//==================================================================================================
// Inner Classes
//==================================================================================================
private TOCSpyWriter printOverlayTree(TOCItemProviderTestStub tocItemProvider, Path tocFile) {
//
// Create a test version of the LinkDatabase for the overlay tree, with test versions of
// it's required TOC input file and HelpModuleLocation
//
GhidraTOCFileDummy toc = new GhidraTOCFileDummy(tocFile);
OverlayHelpModuleLocationTestStub location = new OverlayHelpModuleLocationTestStub(toc);
LinkDatabaseTestStub db = new LinkDatabaseTestStub(location);
// This is the class we are testing!!
OverlayHelpTree overlayHelpTree = new OverlayHelpTree(tocItemProvider, db);
TOCSpyWriter spy = new TOCSpyWriter();
String TOCID = tocFile.toUri().toString();
overlayHelpTree.printTreeForID(spy, TOCID);
System.out.println(spy.toString());
return spy;
}
private TOCItemDefinition definitionItem(String ID, Path tocSourceFile) {
return definitionItem(null, ID, tocSourceFile);
}
private TOCItemDefinition definitionItem(TOCItem parent, String ID, Path tocSourceFile) {
String target = "fake";
String sort = "";
int line = 1;
return new TOCItemDefinition(parent, tocSourceFile, ID, ID, target, sort, line);
}
private TOCItemReference referenceItem(String referenceID, Path tocSourceFile) {
return referenceItem(null, referenceID, tocSourceFile);
}
private TOCItemReference referenceItem(TOCItem parent, String referenceID, Path tocSourceFile) {
return new TOCItemReference(parent, tocSourceFile, referenceID, 1);
}
private TOCItemExternal externalItem(String ID) {
return externalItem(null, ID);
}
private TOCItemExternal externalItem(TOCItem parent, String ID) {
Path tocFile = Paths.get("/fake/path_1/PreBuild_TOC.xml");
String target = "fake";
String sort = "";
int line = 1;
return new TOCItemExternal(parent, tocFile, ID, ID, target, sort, line);
}
private TOCItemExternal externalItemAlt(TOCItem parent, String ID) {
Path tocFile = Paths.get("/fake/path_1/PreBuild_TOC.xml");
String target = "fake";
String sort = "";
int line = 1;
return new TOCItemExternal(parent, tocFile, ID, ID, target, sort, line);
}
private void assertOrder(TOCSpyWriter spy, int ordinal, TOCItem item) {
String ID = spy.getItem(ordinal - 1 /* make an index */);
assertEquals("Did not find TOC item at expected index: " + ordinal, item.getIDAttribute(),
ID);
}
private void assertNodeCount(TOCSpyWriter spy, int count) {
assertEquals("Did not get exactly one node per TOC item input", count, spy.getItemCount());
}
private class TOCSpyWriter extends PrintWriter {
private StringWriter stringWriter;
private List<String> tocItems = new ArrayList<>();
public TOCSpyWriter() {
super(new StringWriter(), true);
stringWriter = ((StringWriter) out);
}
String getItem(int position) {
return tocItems.get(position);
}
int getItemCount() {
return tocItems.size();
}
@Override
public void println(String s) {
super.println(s);
s = s.trim();
if (!s.startsWith("<tocitem")) {
return;
}
storeDisplayAttribute(s);
}
private void storeDisplayAttribute(String s) {
// create a pattern to pull out the display string
Pattern p = Pattern.compile(".*display=\"(.*)\" toc_id.*");
Matcher matcher = p.matcher(s.trim());
if (!matcher.matches()) {
return;// not a TOC item
}
String value = matcher.group(1);
tocItems.add(value);
}
@Override
public String toString() {
return stringWriter.getBuffer().toString();
}
}
private class TOCItemProviderTestStub implements TOCItemProvider {
Map<String, TOCItemExternal> externals = new HashMap<>();
Map<String, TOCItemDefinition> definitions = new HashMap<>();
void addExternal(TOCItemExternal item) {
String displayText = item.getIDAttribute();
externals.put(displayText, item);
}
void addDefinition(TOCItemDefinition item) {
String ID = item.getIDAttribute();
definitions.put(ID, item);
}
@Override
public Map<String, TOCItemExternal> getTOCItemExternalsByDisplayMapping() {
return externals;
}
@Override
public Map<String, TOCItemDefinition> getTOCItemDefinitionsByIDMapping() {
return definitions;
}
}
private class LinkDatabaseTestStub extends LinkDatabase {
public LinkDatabaseTestStub(HelpModuleLocation loc) {
super(HelpModuleCollection.fromHelpLocations(Collections.singleton(loc)));
}
@Override
public String getIDForLink(String target) {
return "test_ID_" + target;
}
}
private class OverlayHelpModuleLocationTestStub extends HelpModuleLocationTestDouble {
OverlayHelpModuleLocationTestStub(GhidraTOCFileDummy toc) {
super(Paths.get("/fake/help"));
this.sourceTOCFile = toc;
}
@Override
protected void loadHelpTopics() {
// no! ...don't really go to the filesystem
}
@Override
public GhidraTOCFile loadSourceTOCFile() {
return null;// we set this in the constructor
}
@Override
public HelpSet loadHelpSet() {
return null;
}
@Override
public boolean isHelpInputSource() {
return true;
}
}
private class GhidraTOCFileDummy extends GhidraTOCFileTestDouble {
public GhidraTOCFileDummy(Path path) {
super(path);
}
}
}

View file

@ -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 help.validator.location;
import java.nio.file.Path;
import help.validator.location.HelpModuleLocation;
public abstract class HelpModuleLocationTestDouble extends HelpModuleLocation {
// this class exists to open up the package-level constructor
public HelpModuleLocationTestDouble(Path source) {
super(source);
}
}

View file

@ -0,0 +1,70 @@
/* ###
* 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.validator.model;
import static org.junit.Assert.assertEquals;
import java.nio.file.Path;
import java.nio.file.Paths;
import org.junit.Assert;
import org.junit.Test;
import generic.test.AbstractGenericTest;
import ghidra.util.exception.AssertException;
public class AnchorDefinitionTest extends AbstractGenericTest {
public AnchorDefinitionTest() {
super();
}
@Test
public void testFileWithoutAnchor() {
// this should generate and ID that is the filename only
Path fullPath = Paths.get("/fake/full/path/help/topics/TopicName/HelpFilename.html"); // dir case
AnchorDefinition def = new AnchorDefinition(fullPath, null, 1);
assertEquals("TopicName_HelpFilename", def.getId());
}
@Test
public void testFileInHelpTopicDir() {
Path fullPath = Paths.get("/fake/full/path/help/topics/TopicName/HelpFilename.html"); // dir case
AnchorDefinition def = new AnchorDefinition(fullPath, "anchor_1", 1);
assertEquals("TopicName_anchor_1", def.getId());
}
@Test
public void testFileInHelpTopicJar() {
Path fullPath = Paths.get("/help/topics/TopicName/HelpFilename.html"); // jar case
AnchorDefinition def = new AnchorDefinition(fullPath, "anchor_1", 1);
assertEquals("TopicName_anchor_1", def.getId());
}
@Test
public void testFileInHelpDir_NotUnderHelpTopic() {
Path fullPath = Paths.get("/fake/full/path/help/HelpFilename.html"); // dir case
try {
new AnchorDefinition(fullPath, "anchor_1", 1);
Assert.fail("Did not fail with file not living under a help topic directory");
}
catch (AssertException e) {
// good
}
}
}

View file

@ -0,0 +1,28 @@
/* ###
* IP: GHIDRA
* REVIEWED: YES
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* 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.validator.model;
import java.nio.file.Path;
public class GhidraTOCFileTestDouble extends GhidraTOCFile {
// this class exists to open up constructor access
public GhidraTOCFileTestDouble(Path sourceFile) {
super(sourceFile);
}
}

View file

@ -0,0 +1,307 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package help.validator.model;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import java.io.IOException;
import java.nio.file.*;
import java.util.Collection;
import org.junit.Test;
import help.AbstractHelpTest;
import help.validator.*;
import help.validator.location.DirectoryHelpModuleLocation;
public class HelpFileTest extends AbstractHelpTest {
@Test
public void testGoodHTML() throws IOException {
Path helpDir = createTempHelpDir();
addRequiredHelpDirStructure(helpDir);
Path topic = createFakeHelpTopic(helpDir);
DirectoryHelpModuleLocation helpLocation =
new DirectoryHelpModuleLocation(helpDir.toFile());
Path html = createGoodHTMLFile(topic);
new HelpFile(helpLocation, html);
// if we get here, then no exceptions happened
}
@Test
public void testBadHTML_InvalidStyleSheet() throws Exception {
Path helpDir = createTempHelpDir();
addRequiredHelpDirStructure(helpDir);
Path topic = createFakeHelpTopic(helpDir);
DirectoryHelpModuleLocation helpLocation =
new DirectoryHelpModuleLocation(helpDir.toFile());
Path html = createBadHTMLFile_InvalidStyleSheet(topic);
try {
new HelpFile(helpLocation, html);
fail("Parsing did not fail for invalid stylesheet");
}
catch (Exception e) {
// good
}
}
@Test
public void testBadHTML_InvalidAnchorRef_BadURI() throws Exception {
Path helpDir = createTempHelpDir();
addRequiredHelpDirStructure(helpDir);
Path topic = createFakeHelpTopic(helpDir);
DirectoryHelpModuleLocation helpLocation =
new DirectoryHelpModuleLocation(helpDir.toFile());
Path html = createBadHTMLFile_InvalidAnchor_BadURI(topic);
try {
new HelpFile(helpLocation, html);
fail("Parsing did not fail for invalid stylesheet");
}
catch (Exception e) {
// good
}
}
@Test
public void testBadHTML_InvalidAnchorRef_WrongAttribtues() throws Exception {
// no 'name' or 'href' attribute
Path helpDir = createTempHelpDir();
addRequiredHelpDirStructure(helpDir);
Path topic = createFakeHelpTopic(helpDir);
DirectoryHelpModuleLocation helpLocation =
new DirectoryHelpModuleLocation(helpDir.toFile());
Path html = createBadHTMLFile_InvalidAnchor_WrongAttributes(topic);
try {
new HelpFile(helpLocation, html);
fail("Parsing did not fail for invalid stylesheet");
}
catch (Exception e) {
// good
}
}
@Test
public void testBadHTML_InvalidIMG_WrongAttribtues() throws Exception {
// no 'src'
Path helpDir = createTempHelpDir();
addRequiredHelpDirStructure(helpDir);
Path topic = createFakeHelpTopic(helpDir);
DirectoryHelpModuleLocation helpLocation =
new DirectoryHelpModuleLocation(helpDir.toFile());
Path html = createBadHTMLFile_InvalidIMG_WrongAttributes(topic);
try {
new HelpFile(helpLocation, html);
fail("Parsing did not fail for invalid stylesheet");
}
catch (Exception e) {
// good
}
}
@Test
public void testCommentGetsIgnored() throws Exception {
Path helpDir = createTempHelpDir();
addRequiredHelpDirStructure(helpDir);
Path topic = createFakeHelpTopic(helpDir);
DirectoryHelpModuleLocation helpLocation =
new DirectoryHelpModuleLocation(helpDir.toFile());
Path html = createGoodHTMLFile_InvalidAnchor_CommentedOut_MultiLineComment(topic);
HelpFile helpFile = new HelpFile(helpLocation, html);
Collection<HREF> hrefs = helpFile.getAllHREFs();
assertTrue(hrefs.isEmpty());
}
// @Test
// for debugging a real help file
public void test() throws Exception {
Path path = Paths.get("<home dir>/<git>/ghidra/Ghidra/Features/" +
"Base/src/main/help/help/topics/Annotations/Annotations.html");
Path helpDir = createTempHelpDir();
addRequiredHelpDirStructure(helpDir);
DirectoryHelpModuleLocation helpLocation =
new DirectoryHelpModuleLocation(helpDir.toFile());
AnchorManager anchorManager = new AnchorManager();
ReferenceTagProcessor tagProcessor = new ReferenceTagProcessor(helpLocation, anchorManager);
HTMLFileParser.scanHtmlFile(path, tagProcessor);
}
//==================================================================================================
// Private Methods
//==================================================================================================
/** Has valid links */
private Path createGoodHTMLFile(Path topic) throws IOException {
String anchor = "ManagePluginsDialog";
return createHelpContent(topic, anchor);
}
private Path createBadHTMLFile_InvalidAnchor_WrongAttributes(Path topic) throws IOException {
Path htmlPath = topic.resolve("FakeHTML_WrongAttributes.html");
Path file = Files.createFile(htmlPath);
String badAttr = "bob=1";
//@formatter:off
String HTML =
"<HTML>\n" +
"<HEAD>\n" +
"<TITLE>Configure Tool</TITLE>\n" +
"<LINK rel=\"stylesheet\" type=\"text/css\" href=\"../../shared/Frontpage.css\">\n" +
"</HEAD>\n" +
"<BODY>\n" +
"<H1><A name=\"ManagePluginsDialog\"></A>Configure Tool</H1>\n" +
"Some text with reference to shared image <a "+badAttr+">Click me</a>\n" +
"\n" +
"</BODY>\n" +
"</HTML>\n";
//@formatter:on
Files.write(file, HTML.getBytes(), StandardOpenOption.CREATE);
return file;
}
private Path createBadHTMLFile_InvalidIMG_WrongAttributes(Path topic) throws IOException {
Path htmlPath = topic.resolve("FakeHTML_WrongAttributes.html");
Path file = Files.createFile(htmlPath);
String badAttr = "bob=1";
//@formatter:off
String HTML =
"<HTML>\n" +
"<HEAD>\n" +
"<TITLE>Configure Tool</TITLE>\n" +
"<LINK rel=\"stylesheet\" type=\"text/css\" href=\"../../shared/Frontpage.css\">\n" +
"</HEAD>\n" +
"<BODY>\n" +
"<H1><A name=\"ManagePluginsDialog\"></A>Configure Tool</H1>\n" +
"Some text with reference to shared image <IMG "+badAttr+"s>\n" +
"\n" +
"</BODY>\n" +
"</HTML>\n";
//@formatter:on
Files.write(file, HTML.getBytes(), StandardOpenOption.CREATE);
return file;
}
private Path createBadHTMLFile_InvalidAnchor_BadURI(Path topic) throws IOException {
Path htmlPath = topic.resolve("FakeHTML_BadURI.html");
Path file = Files.createFile(htmlPath);
String badURI = ":baduri"; // no scheme name on this URI
//@formatter:off
String HTML =
"<HTML>\n" +
"<HEAD>\n" +
"<TITLE>Configure Tool</TITLE>\n" +
"<LINK rel=\"stylesheet\" type=\"text/css\" href=\"../../shared/Frontpage.css\">\n" +
"</HEAD>\n" +
"<BODY>\n" +
"<H1><A name=\"ManagePluginsDialog\"></A>Configure Tool</H1>\n" +
"Some text with reference to shared image <a href=\""+badURI+"\">Click me</a>\n" +
"\n" +
"</BODY>\n" +
"</HTML>\n";
//@formatter:on
Files.write(file, HTML.getBytes(), StandardOpenOption.CREATE);
return file;
}
private Path createBadHTMLFile_InvalidStyleSheet(Path topic) throws IOException {
Path htmlPath = topic.resolve("FakeHTML_InvalidStyleSheet.html");
Path file = Files.createFile(htmlPath);
String badName = "bad_name";
//@formatter:off
String HTML =
"<HTML>\n" +
"<HEAD>\n" +
"<TITLE>Configure Tool</TITLE>\n" +
"<LINK rel=\"stylesheet\" type=\"text/css\" href=\"../../shared/"+badName+".css\">\n" +
"</HEAD>\n" +
"<BODY>\n" +
"<H1><A name=\"ManagePluginsDialog\"></A>Configure Tool</H1>\n" +
"Some text with reference to shared image <IMG src=\"../../shared/test.png\">\n" +
"\n" +
"</BODY>\n" +
"</HTML>\n";
//@formatter:on
Files.write(file, HTML.getBytes(), StandardOpenOption.CREATE);
return file;
}
private Path createGoodHTMLFile_InvalidAnchor_CommentedOut_MultiLineComment(Path topic)
throws IOException {
Path htmlPath = topic.resolve("HTMLWithComment.html");
Path file = Files.createFile(htmlPath);
String badURI = ":baduri"; // no scheme name on this URI
//@formatter:off
String HTML =
"<HTML>\n" +
"<HEAD>\n" +
"<TITLE>Configure Tool</TITLE>\n" +
"<LINK rel=\"stylesheet\" type=\"text/css\" href=\"../../shared/Frontpage.css\">\n" +
"</HEAD>\n" +
"<BODY>\n" +
"<H1><A name=\"ManagePluginsDialog\"></A>Configure Tool</H1>\n" +
" <!--" +
" Some text with reference to shared image <a href=\""+badURI+"\">Click me</a>\n" +
" -->" +
"\n" +
"</BODY>\n" +
"</HTML>\n";
//@formatter:on
Files.write(file, HTML.getBytes(), StandardOpenOption.CREATE);
return file;
}
}

View file

@ -0,0 +1,94 @@
/* ###
* IP: GHIDRA
* REVIEWED: YES
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* 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.headless;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.util.Locale;
import sun.java2d.HeadlessGraphicsEnvironment;
public class MyHeadlessGraphicsEnvironment extends GraphicsEnvironment {
static volatile boolean swingErrorRegistered = false;
private static String preferredGraphicsEnv;
private GraphicsEnvironment localEnv;
static void setup() {
//System.setProperty("java.awt.headless", "true");
preferredGraphicsEnv = System.getProperty("java.awt.graphicsenv");
System.setProperty("java.awt.graphicsenv", MyHeadlessGraphicsEnvironment.class.getName());
}
public MyHeadlessGraphicsEnvironment() {
swingErrorRegistered = true;
try {
throw new Exception("Swing invocation detected for Headless Mode");
}
catch (Exception e) {
e.printStackTrace();
}
getRealGraphicsEnvironemnt();
}
@Override
public Graphics2D createGraphics(BufferedImage img) {
return null;
}
@Override
public Font[] getAllFonts() {
return localEnv.getAllFonts();
}
@Override
public String[] getAvailableFontFamilyNames() {
return localEnv.getAvailableFontFamilyNames();
}
@Override
public String[] getAvailableFontFamilyNames(Locale l) {
return localEnv.getAvailableFontFamilyNames(l);
}
@Override
public GraphicsDevice getDefaultScreenDevice() throws HeadlessException {
return localEnv.getDefaultScreenDevice();
}
@Override
public GraphicsDevice[] getScreenDevices() throws HeadlessException {
return localEnv.getScreenDevices();
}
private void getRealGraphicsEnvironemnt() {
try {
localEnv = (GraphicsEnvironment) Class.forName(preferredGraphicsEnv).newInstance();
if (isHeadless()) {
localEnv = new HeadlessGraphicsEnvironment(localEnv);
}
} catch (ClassNotFoundException e) {
throw new Error("Could not find class: " + preferredGraphicsEnv);
} catch (InstantiationException e) {
throw new Error("Could not instantiate Graphics Environment: " + preferredGraphicsEnv);
} catch (IllegalAccessException e) {
throw new Error("Could not access Graphics Environment: " + preferredGraphicsEnv);
}
}
}

View file

@ -0,0 +1,195 @@
/* ###
* 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.headless;
import java.awt.*;
import java.awt.Dialog.ModalExclusionType;
import java.awt.Dialog.ModalityType;
import java.awt.datatransfer.Clipboard;
import java.awt.font.TextAttribute;
import java.awt.im.InputMethodHighlight;
import java.awt.image.*;
import java.net.URL;
import java.util.Map;
import java.util.Properties;
import sun.awt.HeadlessToolkit;
public class MyHeadlessToolkit extends Toolkit {
static volatile boolean swingErrorRegistered = false;
private static String preferredToolkit;
private Toolkit localToolKit;
static void setup() {
//System.setProperty("java.awt.headless", "true");
preferredToolkit = System.getProperty("awt.toolkit", "sun.awt.X11.XToolkit");
System.setProperty("awt.toolkit", MyHeadlessToolkit.class.getName());
}
public MyHeadlessToolkit() {
swingErrorRegistered = true;
try {
throw new Exception("Swing invocation detected for Headless Mode");
}
catch (Exception e) {
e.printStackTrace();
}
getRealToolkit();
}
@Override
public void beep() {
localToolKit.beep();
}
@Override
public int checkImage(Image image, int width, int height,
ImageObserver observer) {
return localToolKit.checkImage(image, width, height, observer);
}
@Override
public Image createImage(String filename) {
return localToolKit.createImage(filename);
}
@Override
public Image createImage(URL url) {
return localToolKit.createImage(url);
}
@Override
public Image createImage(ImageProducer producer) {
return localToolKit.createImage(producer);
}
@Override
public Image createImage(byte[] imagedata, int imageoffset, int imagelength) {
return localToolKit.createImage(imagedata, imageoffset, imagelength);
}
@Override
public ColorModel getColorModel() throws HeadlessException {
return localToolKit.getColorModel();
}
@Override
public String[] getFontList() {
return localToolKit.getFontList();
}
@Override
public FontMetrics getFontMetrics(Font font) {
return localToolKit.getFontMetrics(font);
}
@Override
public Image getImage(String filename) {
return localToolKit.getImage(filename);
}
@Override
public Image getImage(URL url) {
return localToolKit.getImage(url);
}
@Override
public PrintJob getPrintJob(Frame frame, String jobtitle, Properties props) {
return localToolKit.getPrintJob(frame, jobtitle, props);
}
@Override
public int getScreenResolution() throws HeadlessException {
return localToolKit.getScreenResolution();
}
@Override
public Dimension getScreenSize() throws HeadlessException {
return localToolKit.getScreenSize();
}
@Override
public Clipboard getSystemClipboard() throws HeadlessException {
return localToolKit.getSystemClipboard();
}
@Override
protected EventQueue getSystemEventQueueImpl() {
return localToolKit.getSystemEventQueue();
}
@Override
public boolean isModalExclusionTypeSupported(
ModalExclusionType modalExclusionType) {
return localToolKit.isModalExclusionTypeSupported(modalExclusionType);
}
@Override
public boolean isModalityTypeSupported(ModalityType modalityType) {
return localToolKit.isModalityTypeSupported(modalityType);
}
@Override
public Map<TextAttribute, ?> mapInputMethodHighlight(
InputMethodHighlight highlight) throws HeadlessException {
return localToolKit.mapInputMethodHighlight(highlight);
}
@Override
public boolean prepareImage(Image image, int width, int height,
ImageObserver observer) {
return localToolKit.prepareImage(image, width, height, observer);
}
@Override
public void sync() {
localToolKit.sync();
}
private void getRealToolkit() {
try {
// We disable the JIT during toolkit initialization. This
// tends to touch lots of classes that aren't needed again
// later and therefore JITing is counter-productiive.
java.lang.Compiler.disable();
Class<?> cls = null;
try {
try {
cls = Class.forName(preferredToolkit);
} catch (ClassNotFoundException ee) {
throw new AWTError("Toolkit not found: " + preferredToolkit);
}
if (cls != null) {
localToolKit = (Toolkit)cls.newInstance();
if (GraphicsEnvironment.isHeadless()) {
localToolKit = new HeadlessToolkit(localToolKit);
}
}
} catch (InstantiationException e) {
throw new AWTError("Could not instantiate Toolkit: " + preferredToolkit);
} catch (IllegalAccessException e) {
throw new AWTError("Could not access Toolkit: " + preferredToolkit);
}
} finally {
// Make sure to always re-enable the JIT.
java.lang.Compiler.enable();
}
}
}

View file

@ -0,0 +1,313 @@
/* ###
* 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;
import static org.junit.Assert.*;
import java.util.*;
import java.util.stream.Collectors;
import org.junit.*;
import ghidra.framework.plugintool.testplugins.*;
import ghidra.framework.plugintool.util.PluginException;
import ghidra.framework.plugintool.util.PluginUtils;
import ghidra.test.AbstractGhidraHeadedIntegrationTest;
import ghidra.test.TestEnv;
import ghidra.util.classfinder.ClassSearcher;
import ghidra.util.exception.AssertException;
public class PluginManagerTest extends AbstractGhidraHeadedIntegrationTest {
private TestEnv env;
private PluginTool tool;
@Before
public void setUp() throws Exception {
env = new TestEnv();
tool = env.getTool();
runSwing(() -> tool.setConfigChanged(false));
}
@After
public void tearDown() throws Exception {
env.dispose();
}
@Test
public void testConflictPluginNames() {
// Test loading a plugin that has a name conflict with another plugin
try {
tool.addPlugin(NameConflictingPlugin.class.getName());
fail("Should have gotten a plugin exception because of the conflicting plugin names");
}
catch (PluginException e) {
// ensure that the exception message mentions both of the conflicting plugin class names.
String msg = e.getMessage();
assertTrue(msg.contains(NameConflictingPlugin.class.getName()));
assertTrue(msg.contains(
ghidra.framework.plugintool.testplugins.secondconflict.NameConflictingPlugin.class.getName()));
}
assertNotPlugin(NameConflictingPlugin.class);
assertNotPlugin(
ghidra.framework.plugintool.testplugins.secondconflict.NameConflictingPlugin.class);
}
@Test
public void testDiamond() throws PluginException {
// Test loading a plugin (A) that has dependencies in a diamond shape.
// A
// / \
// B C
// \ /
// D
tool.addPlugin(DiamondPluginA.class.getName());
assertPlugin(DiamondPluginA.class);
assertPlugin(DiamondPluginB.class);
assertPlugin(DiamondPluginC.class);
assertPlugin(DiamondPluginD.class);
assertTrue(tool.hasConfigChanged());
}
@Test
public void testCircularDependency() throws PluginException {
// Test loading plugins that have circular dependencies.
// Currently this is allowed but a warning is logged to the message console.
// +---------+
// | |
// v |
// A ------> B
tool.addPlugin(CircularPluginA.class.getName());
assertPlugin(CircularPluginA.class);
assertPlugin(CircularPluginB.class);
assertTrue(tool.hasConfigChanged());
removePlugin(getPlugin(CircularPluginB.class), false);
assertNotPlugin(CircularPluginA.class);
assertNotPlugin(CircularPluginB.class);
}
@Test
public void testLoadSameMultipleTimes() throws PluginException {
// Loading the same plugin multiple times should not cause a problem and the second
// attempt should just be ignored.
tool.addPlugin(DiamondPluginD.class.getName());
assertPlugin(DiamondPluginD.class);
assertTrue(tool.hasConfigChanged());
tool.addPlugin(DiamondPluginD.class.getName());
// as long as we didn't get an exception everything is good
}
@Test
public void testMissingDependency() throws PluginException {
// Test loading a plugin that has an dependency without a default provider.
int pluginCount = tool.getManagedPlugins().size();
try {
tool.addPlugin(MissingDepPluginA.class.getName());
fail("PluginA should have failed to load");
}
catch (PluginException e) {
String msg = e.getMessage();
assertTrue(msg.contains("Unresolved dependency") &&
msg.contains(MissingDepServiceB.class.getName()));
}
assertEquals(pluginCount, tool.getManagedPlugins().size());
assertTrue(tool.hasConfigChanged());
// If we manually add the missing dependency, it should now work
tool.addPlugin(MissingDepPluginB.class.getName());
tool.addPlugin(MissingDepPluginA.class.getName());
assertPlugin(MissingDepPluginB.class);
assertPlugin(MissingDepPluginA.class);
assertTrue(tool.hasConfigChanged());
}
@Test
public void testLoadingDepSimultaneously() throws PluginException {
// Load a plugin and a second plugin that provides a dependency at the same time.
// Loading PluginA by itself would fail.
tool.addPlugins(
new String[] { MissingDepPluginA.class.getName(), MissingDepPluginB.class.getName() });
assertPlugin(MissingDepPluginA.class);
assertPlugin(MissingDepPluginB.class);
assertTrue(tool.hasConfigChanged());
}
@Test
public void testInitFail() {
// Test that a plugin that throws an error during init() is removed and cleaned up.
int pluginCount = tool.getManagedPlugins().size();
int disposeCountB = InitFailPluginB.disposeCount;
setErrorsExpected(true);
try {
tool.addPlugin(InitFailPluginB.class.getName());
fail(
"PluginB should have failed to load because PluginB throws exception during init()");
}
catch (PluginException pe) {
// good
assertTrue(pe.getMessage().contains(InitFailPluginB.ERROR_MSG));
}
setErrorsExpected(false);
assertEquals(disposeCountB + 1, InitFailPluginB.disposeCount);
assertEquals(pluginCount, tool.getManagedPlugins().size());
assertTrue(tool.hasConfigChanged());
}
@Test
public void testInitFailInDependency() {
// Test that a plugin that has a dependency that throws an error during init()
// is removed and cleaned up.
int pluginCount = tool.getManagedPlugins().size();
int disposeCountA = InitFailPluginA.disposeCount;
int disposeCountB = InitFailPluginB.disposeCount;
setErrorsExpected(true);
try {
tool.addPlugin(InitFailPluginA.class.getName());
fail(
"PluginA should have failed to load because PluginB throws exception during init()");
}
catch (PluginException pe) {
// good
assertTrue(pe.getMessage().contains(InitFailPluginB.ERROR_MSG));
}
setErrorsExpected(false);
assertNotPlugin(InitFailPluginA.class);
assertEquals(pluginCount, tool.getManagedPlugins().size());
assertEquals(disposeCountB + 1, InitFailPluginB.disposeCount);
assertEquals(disposeCountA + 1, InitFailPluginA.disposeCount);
}
@Test
public void testDisposeFail() throws PluginException {
// Test when a plugin throws an exception during its dispose()
// Exceptions are logged to the console because the dispose was executed
// on the swing thread.
tool.addPlugin(DisposeFailPluginA.class.getName());
assertTrue(tool.hasConfigChanged());
Plugin pluginA = getPlugin(DisposeFailPluginA.class);
runSwing(() -> tool.setConfigChanged(false));
removePlugin(pluginA, true);
assertNotPlugin(DisposeFailPluginA.class);
assertTrue(tool.hasConfigChanged());
}
@Test
public void testLoadFailure_Isolated() {
// test loading multiple plugins, good should load successfully, bad ones
// shouldn't cause entire failure.
setErrorsExpected(true);
try {
tool.addPlugins(new String[] { IsolatedFailPluginA.class.getName(),
IsolatedFailPluginB.class.getName() });
fail("Should have gotten an exception because PluginB was bad");
}
catch (PluginException pe) {
// currently expected behavior, partial errors cause exception
}
setErrorsExpected(false);
assertTrue(tool.hasConfigChanged());
assertPlugin(IsolatedFailPluginA.class);
assertNotPlugin(IsolatedFailPluginB.class);
}
@Test
public void testUniquePluginNames() {
// Ensure all current plugins have a unique name.
// Build a string with a list of the bad plugins and report it at the end.
Map<String, Class<? extends Plugin>> simpleNameToClassMap = new HashMap<>();
Map<String, Set<Class<? extends Plugin>>> badPlugins = new HashMap<>();
for (Class<? extends Plugin> pluginClass : ClassSearcher.getClasses(Plugin.class)) {
if (TestingPlugin.class.isAssignableFrom(pluginClass)) {
// ignore plugins marked with the TestingPlugin interface because
// they are supposed to have name conflicts and other problems.
continue;
}
String pluginName = PluginUtils.getPluginNameFromClass(pluginClass);
Class<? extends Plugin> previousPluginClass =
simpleNameToClassMap.putIfAbsent(pluginName, pluginClass);
if (previousPluginClass != null) {
Set<Class<? extends Plugin>> set =
badPlugins.computeIfAbsent(pluginName, x -> new HashSet<>());
set.add(pluginClass);
set.add(previousPluginClass);
}
}
// simplename: pluginclassname1,pluginclassname2*\n[repeat].
String badPluginsStr = badPlugins.entrySet().stream().map( //
entry -> entry.getKey() + ": " +
entry.getValue().stream().map(pc -> pc.getName()).collect(Collectors.joining(",")) //
).collect(Collectors.joining("\n"));
assertTrue("Plugins with name collisions: " + badPluginsStr, badPluginsStr.isEmpty());
}
//==================================================================================================
// Private Methods
//==================================================================================================
private void removePlugin(Plugin p, boolean exceptional) {
runSwing(() -> {
try {
tool.removePlugins(new Plugin[] { p });
}
catch (Exception e) {
if (!exceptional) {
throw new AssertException(e);
}
}
});
}
private void assertPlugin(Class<? extends Plugin> pluginClass) {
assertTrue("Plugin " + pluginClass.getName() + " not present",
tool.getManagedPlugins().stream().anyMatch(p -> p.getClass() == pluginClass));
}
private void assertNotPlugin(Class<? extends Plugin> pluginClass) {
List<Plugin> plugins = tool.getManagedPlugins();
for (Plugin p : plugins) {
assertNotSame("Plugin " + pluginClass.getName() + " loaded but shouldn't be",
p.getClass(), pluginClass);
}
}
private Plugin getPlugin(Class<? extends Plugin> pluginClass) {
return tool.getManagedPlugins().stream().filter(
p -> p.getClass() == pluginClass).findFirst().get();
}
}

View file

@ -0,0 +1,23 @@
/* ###
* 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;
/**
* Marker interface to signal that the implementing class is a test plugin and should
* not be considered as 'real'.
*/
public interface TestingPlugin {
}

View file

@ -0,0 +1,40 @@
/* ###
* 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;
/**
* Plugin for circular dependency testing {@link PluginManagerTest#testCircularDependency()}
*/
//@formatter:off
@PluginInfo(status = PluginStatus.HIDDEN,
packageName = DeveloperPluginPackage.NAME,
category = PluginCategoryNames.UNMANAGED,
shortDescription = "Test plugin",
description = "Test plugin",
servicesProvided = { CircularServiceA.class },
servicesRequired = { CircularServiceB.class } )
//@formatter:on
public class CircularPluginA extends Plugin implements CircularServiceA, TestingPlugin {
public CircularPluginA(PluginTool tool) {
super(tool);
}
}

View file

@ -0,0 +1,40 @@
/* ###
* 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;
/**
* Plugin for circular dependency testing {@link PluginManagerTest#testCircularDependency()}
*/
//@formatter:off
@PluginInfo(status = PluginStatus.HIDDEN,
packageName = DeveloperPluginPackage.NAME,
category = PluginCategoryNames.UNMANAGED,
shortDescription = "Test plugin",
description = "Test plugin",
servicesProvided = CircularServiceB.class,
servicesRequired = CircularServiceA.class)
//@formatter:on
public class CircularPluginB extends Plugin implements CircularServiceB, TestingPlugin {
public CircularPluginB(PluginTool tool) {
super(tool);
}
}

View file

@ -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;
/**
* Plugin service for circular dependency testing {@link PluginManagerTest#testCircularDependency()}
*/
@ServiceInfo(defaultProvider = CircularPluginA.class, description = "Test service")
public interface CircularServiceA {
}

View file

@ -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;
/**
* Plugin service for circular dependency testing {@link PluginManagerTest#testCircularDependency()}
*/
@ServiceInfo(defaultProvider = CircularPluginB.class, description = "Test service")
public interface CircularServiceB {
}

View file

@ -0,0 +1,47 @@
/* ###
* 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()}
* <pre>
* A <------- you are here
* / \
* B C
* \ /
* D
* </pre>
*/
//@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);
}
}

View file

@ -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()}
* <pre>
* A
* / \
* B <---C--------------- you are here
* \ /
* D
* </pre>
*/
//@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);
}
}

View file

@ -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()}
* <pre>
* A
* / \
* B C <------ you are here
* \ /
* D
* </pre>
*/
//@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);
}
}

View file

@ -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()}
* <pre>
* A
* / \
* B C
* \ /
* D <--------- you are here
* </pre>
*/
//@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);
}
}

View file

@ -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()}
* <pre>
* A
* / \
* B<----C------------ you are here
* \ /
* D
* </pre>
*/
@ServiceInfo(defaultProvider = DiamondPluginB.class, description = "Test service")
public interface DiamondServiceB {
}

View file

@ -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()}
* <pre>
* A
* / \
* B C <---------- you are here
* \ /
* D
* </pre>
*/
@ServiceInfo(defaultProvider = DiamondPluginC.class, description = "Test service")
public interface DiamondServiceC {
}

View file

@ -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()}
* <pre>
* A
* / \
* B C
* \ /
* D <---------- you are here
* </pre>
*/
@ServiceInfo(defaultProvider = DiamondPluginD.class, description = "Test service")
public interface DiamondServiceD {
}

View file

@ -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);
}
}

View file

@ -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++;
}
}

View file

@ -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++;
}
}

View file

@ -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 {
}

View file

@ -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);
}
}

View file

@ -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);
}
}

View file

@ -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);
}
}

View file

@ -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);
}
}

View file

@ -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 {
}

View file

@ -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);
}
}

View file

@ -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);
}
}

View file

@ -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());
}
}

View file

@ -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());
}
}

View file

@ -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<MyEvent> events = new ArrayList<>();
@Before
public void setUp() throws Exception {
File parent = createTempDirectory(getClass().getSimpleName());
// Create server instance
serverRoot = new File(parent, "My_Server");
FileUtilities.deleteDir(serverRoot);
serverRoot.mkdir();
mgr = new RepositoryManager(serverRoot, false, false, 0, false);
mgr.getUserManager().addUser(USER);
repository = mgr.createRepository(USER, "My_Repository");
LocalFileSystem fs = (LocalFileSystem) getInstanceField("fileSystem", repository);
fs.addFileSystemListener(new MyFileSystemListener());
}
@After
public void tearDown() throws Exception {
if (mgr != null) {
mgr.dispose();
}
FileUtilities.deleteDir(serverRoot);
}
private RepositoryFile createDatabase(String parentPath, String itemName, int maxVersion)
throws Exception {
RepositoryFolder folder = repository.getFolder(USER, parentPath, true);
DBHandle dbh = new DBHandle();
long id = dbh.startTransaction();
Schema schema =
new Schema(0, "key", new Class[] { IntField.class }, new String[] { "dummy" });
dbh.createTable("test", schema);
dbh.endTransaction(id, true);
ManagedBufferFile bf = folder.createDatabase(itemName, FileIDFactory.createFileID(),
dbh.getBufferSize(), "Database", USER, null);
bf.setVersionComment("Version 1");
dbh.saveAs(bf, true, null);
long checkoutId = bf.getCheckinID();
assertNotNull(dbh.getTable("test"));
dbh.close();
RepositoryFile file = folder.getFile(itemName);
assertNotNull(file);
assertEquals(1, file.getItem().getVersion());
for (int i = 2; i <= maxVersion; i++) {
// Checkout and open for update
bf = file.openDatabase(checkoutId, USER);
dbh = new DBHandle(bf);
assertTrue(dbh.canUpdate());
Table testTable = dbh.getTable("test");
assertEquals(i - 2, testTable.getRecordCount());
// Verify that update is not permitted for second open
BufferFile bf2 = file.openDatabase(1, -1, USER);
DBHandle dbh2 = new DBHandle(bf2);
assertTrue(!dbh2.canUpdate());
assertNotNull(dbh2.getTable("test"));
dbh2.close();
// Add record
long txId = dbh.startTransaction();
Record rec = schema.createRecord(i);
rec.setIntValue(0, i);
testTable.putRecord(rec);
Msg.debug(this, "Added record to test table, key=" + i);
Msg.debug(this,
"Added record to Record count for test table: " + testTable.getRecordCount());
dbh.endTransaction(txId, true);
// Create new version
Msg.debug(this, "Saving database version " + i);
dbh.save("Version " + i, new MyChangeSet(), null);
dbh.close();
// Verify item current version
assertEquals(i, file.getItem().getVersion());
// Check version history
Version[] versions = file.getVersions(USER);
assertEquals(i, versions.length);
for (int n = 0; n < i; n++) {
assertEquals(n + 1, versions[n].getVersion());
assertEquals("Version " + (n + 1), versions[n].getComment());
assertEquals(USER, versions[n].getUser());
}
}
file.terminateCheckout(checkoutId, USER, false);
return file;
}
@Test
public void testDeleteDataBaseVersions() {
try {
RepositoryFolder rootFolder = repository.getFolder(USER, "/", true);
RepositoryFolder[] folders = rootFolder.getFolders();
assertNotNull(folders);
assertEquals(0, folders.length);
RepositoryFile file = createDatabase("/abc", "fred", 3);
RepositoryFolder folder = repository.getFolder(USER, "/abc", false);
assertNotNull(folder);
// Can't delete open version
// BufferFile bf = item.open((int)1);
// try {
// item.delete(1);
// fail();
// } catch (FileInUseException e) {
// // expected
// }
// finally {
// bf.close();
// }
// Can't delete checked-out version
ItemCheckoutStatus coStatus = file.checkout(CheckoutType.NORMAL, USER, null);
try {
file.delete(3, USER);
Assert.fail();
}
catch (FileInUseException e) {
// expected
}
file = folder.getFile("fred");
assertNotNull(file);
// delete oldest version
file.delete(1, USER);
Thread.sleep(50);
file = folder.getFile("fred");
assertNotNull(file);
// verify that version 2 and 3 are still available
assertEquals(3, file.getItem().getVersion());
Version[] versions = file.getVersions(USER);
assertEquals(2, versions.length);
assertEquals(2, versions[0].getVersion());
assertEquals(3, versions[1].getVersion());
file.terminateCheckout(coStatus.getCheckoutId(), USER, false);
Thread.sleep(50);
// delete current version
file.delete(3, USER);
Thread.sleep(50);
file = folder.getFile("fred");
assertNotNull(file);
// verify that version 2 is still available
assertEquals(2, file.getItem().getVersion());
versions = file.getVersions(USER);
assertEquals(1, versions.length);
assertEquals(2, versions[0].getVersion());
// Open version 2 for check
DBHandle dbh = new DBHandle(file.openDatabase(2, -1, USER));
try {
Table testTable = dbh.getTable("test");
assertEquals(1, testTable.getRecordCount());
Record rec = testTable.getRecord(2);
assertNotNull(rec);
assertEquals(2, rec.getIntValue(0));
}
finally {
dbh.close();
}
// delete last version
file.delete(2, USER);
Thread.sleep(50);
file = folder.getFile("fred");
assertNull(file);
folders = rootFolder.getFolders();
assertNotNull(folders);
assertEquals(0, folders.length);
Thread.sleep(500);// wait for events
assertEquals(8, events.size());
checkEvent("Folder Created", "/", "abc", null, null, events.get(0));
checkEvent("Item Created", "/abc", "fred", null, null, events.get(1));
checkEvent("Item Changed", "/abc", "fred", null, null, events.get(2));// version 2 created
checkEvent("Item Changed", "/abc", "fred", null, null, events.get(3));// version 3 created
checkEvent("Item Changed", "/abc", "fred", null, null, events.get(4));// version 1 deleted
checkEvent("Item Changed", "/abc", "fred", null, null, events.get(5));// version 3 deleted
checkEvent("Item Deleted", "/abc", "fred", null, null, events.get(6));// last version deleted
checkEvent("Folder Deleted", "/", "abc", null, null, events.get(7));
}
catch (Exception e) {
e.printStackTrace();
Assert.fail(e.toString());
}
}
private void checkEvent(String op, String path, String name, String newPath, String newName,
Object evObj) {
MyEvent event = (MyEvent) evObj;
MyEvent ev = new MyEvent(op, path, name, newPath, newName);
assertEquals(ev, event);
}
class MyChangeSet implements DBChangeSet {
/*
* @see ghidra.framework.model.ChangeSet#read(ghidra.framework.store.db.DBHandle)
*/
@Override
public void read(DBHandle dbh) throws IOException {
// TODO Auto-generated method stub
}
/*
* @see ghidra.framework.model.ChangeSet#write(ghidra.framework.store.db.DBHandle)
*/
@Override
public void write(DBHandle dbh, boolean isRecoverSave) throws IOException {
// TODO Auto-generated method stub
}
/*
* @see ghidra.framework.model.ChangeSet#clear()
*/
public void clear() {
// TODO Auto-generated method stub
}
/*
* @see ghidra.framework.model.ChangeSet#undo()
*/
public void undo() {
// TODO Auto-generated method stub
}
/*
* @see ghidra.framework.model.ChangeSet#redo()
*/
public void redo() {
// TODO Auto-generated method stub
}
/*
* @see ghidra.framework.model.ChangeSet#setMaxUndos(int)
*/
public void setMaxUndos(int maxUndos) {
// TODO Auto-generated method stub
}
/*
* @see ghidra.framework.model.ChangeSet#clearUndo()
*/
public void clearUndo() {
// TODO Auto-generated method stub
}
/*
* @see ghidra.framework.model.ChangeSet#startTransaction()
*/
public void startTransaction() {
// TODO Auto-generated method stub
}
/*
* @see ghidra.framework.model.ChangeSet#endTransaction(boolean)
*/
public void endTransaction(boolean commit) {
// TODO Auto-generated method stub
}
}
class MyFileSystemListener implements FileSystemListener {
@Override
public void folderCreated(String parentPath, String name) {
events.add(new MyEvent("Folder Created", parentPath, name, null, null));
}
@Override
public void itemCreated(String parentPath, String name) {
events.add(new MyEvent("Item Created", parentPath, name, null, null));
}
@Override
public void folderDeleted(String parentPath, String name) {
events.add(new MyEvent("Folder Deleted", parentPath, name, null, null));
}
@Override
public void folderMoved(String parentPath, String name, String newParentPath) {
events.add(new MyEvent("Folder Moved", parentPath, name, newParentPath, null));
}
@Override
public void folderRenamed(String parentPath, String oldFolderName, String newFolderName) {
events.add(
new MyEvent("Folder Renamed", parentPath, oldFolderName, null, newFolderName));
}
@Override
public void itemDeleted(String folderPath, String itemName) {
events.add(new MyEvent("Item Deleted", folderPath, itemName, null, null));
}
@Override
public void itemRenamed(String folderPath, String oldItemName, String newItemName) {
events.add(new MyEvent("Item Renamed", folderPath, oldItemName, null, newItemName));
}
@Override
public void itemMoved(String parentPath, String name, String newParentPath,
String newName) {
events.add(new MyEvent("Item Moved", parentPath, name, newParentPath, newName));
}
@Override
public void itemChanged(String parentPath, String itemName) {
events.add(new MyEvent("Item Changed", parentPath, itemName, null, null));
}
@Override
public void syncronize() {
// Nothing to do
}
}
}
class MyEvent {
String op;
String parentPath;
String name;
String newParentPath;
String newName;
MyEvent(String op, String parentPath, String name, String newParentPath, String newName) {
this.op = op;
this.parentPath = parentPath;
this.name = name;
this.newParentPath = newParentPath;
this.newName = newName;
}
@Override
public boolean equals(Object obj) {
MyEvent other = (MyEvent) obj;
return eq(op, other.op) && eq(parentPath, other.parentPath) && eq(name, other.name) &&
eq(newParentPath, other.newParentPath) && eq(newName, other.newName);
}
private boolean eq(String s1, String s2) {
if (s1 == null) {
return s2 == null;
}
return s1.equals(s2);
}
@Override
public String toString() {
return op + " " + parentPath + " " + name + " " + newParentPath + " " + newName;
}
}

View file

@ -0,0 +1,213 @@
/* ###
* 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.assertEquals;
import static org.junit.Assert.assertNotNull;
import java.io.File;
import org.junit.*;
import ghidra.framework.remote.User;
import ghidra.server.remote.ServerTestUtil;
import ghidra.test.AbstractGhidraHeadedIntegrationTest;
import ghidra.util.exception.DuplicateFileException;
import ghidra.util.exception.UserAccessException;
public class RepositoryManagerTest extends AbstractGhidraHeadedIntegrationTest {
private RepositoryManager mgr;
private File root;
public RepositoryManagerTest() {
super();
}
@Before
public void setUp() throws Exception {
File parent = createTempDirectory(getName());
root = new File(parent, "Repositories");
if (root.exists()) {
deleteFiles(root);
root.delete();
}
root.mkdir();
writeUserList(root);
}
@After
public void tearDown() throws Exception {
if (mgr != null) {
mgr.dispose();
}
deleteFiles(root);
root.delete();
}
@Test
public void testCreateRepositoryManager() throws Exception {
mgr = new RepositoryManager(root, false, false, 0, false);
assertNotNull(mgr);
String[] userNames = mgr.getAllUsers("User_0");
assertEquals(10, userNames.length);
}
@Test
public void testCreateRepositoryManagerWithAnonymous() throws Exception {
mgr = new RepositoryManager(root, false, false, 0, true);
assertNotNull(mgr);
String[] userNames = mgr.getAllUsers("User_0");
assertEquals(10, userNames.length);
userNames = mgr.getAllUsers(UserManager.ANONYMOUS_USERNAME);
assertEquals(0, userNames.length);
}
@Test
public void testCreateRepository() throws Exception {
mgr = new RepositoryManager(root, false, false, 0, false);
Repository rep = mgr.createRepository("User_0", "REPOSITORY_A");
assertNotNull(rep);
}
@Test
public void testCreateRepositoryAnonymous() throws Exception {
mgr = new RepositoryManager(root, false, false, 0, true);
Repository rep = mgr.createRepository("User_0", "REPOSITORY_A");
assertNotNull(rep);
try {
mgr.createRepository(UserManager.ANONYMOUS_USERNAME, "REPOSITORY_B");
Assert.fail("Expected UserAccessException");
}
catch (UserAccessException e) {
// expected
}
}
@Test
public void testCreateDuplicateRepository() throws Exception {
mgr = new RepositoryManager(root, false, false, 0, false);
mgr.createRepository("User_0", "REPOSITORY_A");
try {
mgr.createRepository("User_5", "REPOSITORY_A");
Assert.fail("Should have gotten DuplicateNameException!");
}
catch (DuplicateFileException e) {
}
}
@Test
public void testGetRepository() throws Exception {
mgr = new RepositoryManager(root, false, false, 0, true);
Repository rep1 = mgr.createRepository("User_0", "REPOSITORY_A");
addUsers("User_0", true, rep1);
Repository rep2 = mgr.createRepository("User_0", "REPOSITORY_B");
addUsers("User_0", false, rep2);
Repository rep3 = mgr.createRepository("User_9", "REPOSITORY_9A");
addUsers("User_9", false, rep3);
Repository rep4 = mgr.createRepository("User_9", "REPOSITORY_9B");
addUsers("User_9", false, rep4);
assertEquals(rep1, mgr.getRepository("User_1", "REPOSITORY_A"));
assertEquals(rep1, mgr.getRepository(UserManager.ANONYMOUS_USERNAME, "REPOSITORY_A"));
assertEquals(rep2, mgr.getRepository("User_2", "REPOSITORY_B"));
try {
mgr.getRepository(UserManager.ANONYMOUS_USERNAME, "REPOSITORY_B");
Assert.fail("Expected UserAccessException");
}
catch (UserAccessException e) {
// expected
}
assertEquals(rep3, mgr.getRepository("User_3", "REPOSITORY_9A"));
assertEquals(rep4, mgr.getRepository("User_4", "REPOSITORY_9B"));
}
@Test
public void testGetRepositoryBadUser() throws Exception {
mgr = new RepositoryManager(root, false, false, 0, false);
mgr.createRepository("User_0", "REPOSITORY_A");
try {
mgr.getRepository("unknownUser", "REPOSITORY_A");
Assert.fail("Should not have been able to get repository!");
}
catch (UserAccessException e) {
}
try {
mgr.getRepository(UserManager.ANONYMOUS_USERNAME, "REPOSITORY_A");
Assert.fail("Should not have been able to get repository!");
}
catch (UserAccessException e) {
}
}
private void addUsers(String currentUser, boolean allowAnonymousAccess, Repository rep)
throws Exception {
User[] users = new User[10];
for (int i = 0; i < 10; i++) {
String name = "User_" + i;
int type = User.READ_ONLY;
if (name.equals(currentUser)) {
type = User.ADMIN;
}
users[i] = new User("User_" + i, type);
}
rep.setUserList(currentUser, users, allowAnonymousAccess);
}
private void writeUserList(File repositoryRoot) throws Exception {
String[] userNames = new String[10];
for (int i = 0; i < userNames.length; i++) {
userNames[i] = "User_" + i;
}
ServerTestUtil.createUsers(repositoryRoot.getAbsolutePath(), userNames);
}
/**
* Recursive method to delete files in the given parent directory.
*/
private boolean deleteFiles(File parent) {
File[] f = parent.listFiles();
for (File element : f) {
if (element.isDirectory()) {
if (!deleteFiles(element)) {
return false;
}
element.delete();
}
else if (!element.delete()) {
return false;
}
}
return true;
}
}

View file

@ -0,0 +1,144 @@
/* ###
* 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.assertEquals;
import static org.junit.Assert.assertNotNull;
import java.io.File;
import org.junit.*;
import ghidra.framework.remote.User;
import ghidra.test.AbstractGhidraHeadedIntegrationTest;
import ghidra.util.NamingUtilities;
import ghidra.util.SystemUtilities;
import ghidra.util.exception.UserAccessException;
import utilities.util.FileUtilities;
public class RepositoryTest extends AbstractGhidraHeadedIntegrationTest {
private static final String REPOSITORY_NAME = "My_Repository";
private File serverRoot;
private RepositoryManager mgr;
private Repository repository;
private String userName;
@Before
public void setUp() throws Exception {
userName = SystemUtilities.getUserName();
File parent = createTempDirectory(getClass().getSimpleName());
// Create repository manager with no users
serverRoot = new File(parent, "My_Server");
FileUtilities.deleteDir(serverRoot);
serverRoot.mkdir();
mgr = new RepositoryManager(serverRoot, false, false, 0, false);
mgr.getUserManager().addUser(userName);
repository = mgr.createRepository(userName, REPOSITORY_NAME);
}
@Test
public void testGetRepositoryName() throws Exception {
assertEquals(REPOSITORY_NAME, repository.getName());
}
@Test
public void testSetGetUserList() throws Exception {
User[] users = new User[5];
users[0] = new User("user-a", User.READ_ONLY);
users[1] = new User("user-b", User.WRITE);
users[2] = new User("user-c", User.ADMIN);
users[3] = new User("user-d", User.READ_ONLY);
users[4] = new User(userName, User.ADMIN);
repository.setUserList(userName, users, false);
User[] reportedUsers = repository.getUserList(userName);
assertEquals(users.length, reportedUsers.length);
for (int i = 0; i < users.length; i++) {
assertEquals(users[i].getName(), reportedUsers[i].getName());
assertEquals(users[i].getPermissionType(), reportedUsers[i].getPermissionType());
}
}
@Test
public void testSetListBadUser() throws Exception {
User[] users = new User[5];
users[0] = new User("user-a", User.READ_ONLY);
users[1] = new User("user-b", User.WRITE);
users[2] = new User("user-c", User.ADMIN);
users[3] = new User("user-d", User.READ_ONLY);
users[4] = new User(userName, User.WRITE);
try {
repository.setUserList(userName, users, false);
Assert.fail("Should not have been able to change current user's access!");
}
catch (UserAccessException e) {
}
users[3] = new User("user-x", User.ADMIN);
try {
repository.setUserList(userName, users, false);
Assert.fail("Should not have been able to set the user list!");
}
catch (UserAccessException e) {
}
users[4] = new User(userName, User.ADMIN);
repository.setUserList(userName, users, false);
User[] reportedUsers = repository.getUserList(userName);
assertEquals(users.length, reportedUsers.length);
for (int i = 0; i < users.length; i++) {
assertEquals(users[i].getName(), reportedUsers[i].getName());
assertEquals(users[i].getPermissionType(), reportedUsers[i].getPermissionType());
}
}
@Test
public void testExistingRepository() throws Exception {
User[] users = new User[5];
users[0] = new User("user-a", User.READ_ONLY);
users[1] = new User("user-b", User.WRITE);
users[2] = new User("user-c", User.ADMIN);
users[3] = new User("user-d", User.READ_ONLY);
users[4] = new User(userName, User.ADMIN);
repository.setUserList(userName, users, false);
File repRoot = new File(serverRoot, NamingUtilities.mangle(REPOSITORY_NAME));
Repository rep = new Repository(mgr, null, repRoot, REPOSITORY_NAME);
assertNotNull(rep);
User[] reportedUsers = rep.getUserList(userName);
assertEquals(users.length, reportedUsers.length);
for (int i = 0; i < users.length; i++) {
assertEquals(users[i].getName(), reportedUsers[i].getName());
assertEquals(users[i].getPermissionType(), reportedUsers[i].getPermissionType());
}
}
}

View file

@ -0,0 +1,292 @@
/* ###
* 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.*;
import java.util.ArrayList;
import java.util.List;
import javax.swing.SwingWorker;
import org.junit.Test;
import docking.test.AbstractDockingTest;
import sun.awt.AppContext;
import sun.swing.AccumulativeRunnable;
public class CachingSwingWorkerTest extends AbstractDockingTest {
private static final int ITEM_COUNT = 10;
@Test
public void testSimpleThreadCase() throws InterruptedException {
TestWorker worker = new TestWorker();
MyThread r1 = new MyThread(0, worker);
MyThread r2 = new MyThread(0, worker);
MyThread r3 = new MyThread(10, worker);
MyThread r4 = new MyThread(20, worker);
worker.setDone();
r1.join();
r2.join();
r3.join();
r4.join();
assertEquals("number of runs", 1, worker.getNumRuns());
assertEquals(ITEM_COUNT, r1.size());
assertEquals(ITEM_COUNT, r2.size());
assertEquals(ITEM_COUNT, r3.size());
assertEquals(ITEM_COUNT, r4.size());
}
@Test
public void testSimpleSwingThreadCase() {
disasbleTimerUsage();
TestWorker worker = new TestWorker();
worker.setTaskDialogDelay(0);
ClientRunnable runnable = new ClientRunnable(worker);
runSwing(runnable, false);
TaskDialog dialog = waitForDialogComponent(null, TaskDialog.class, 2000);
assertNotNull(dialog);
worker.setDone();
worker.get(TaskMonitorAdapter.DUMMY_MONITOR);
waitForPostedSwingRunnables();
assertTrue(!dialog.isVisible());
assertEquals("number of runs", 1, worker.getNumRuns());
assertEquals(ITEM_COUNT, runnable.size());
}
@Test
public void testSwingAndAnotherThreadCase() throws InterruptedException {
disasbleTimerUsage();
TestWorker worker = new TestWorker();
worker.setTaskDialogDelay(0);
ClientRunnable runnable = new ClientRunnable(worker);
runSwing(runnable, false);
MyThread r1 = new MyThread(100, worker);
TaskDialog dialog = waitForDialogComponent(null, TaskDialog.class, 2000);
assertNotNull(dialog);
worker.setDone();
worker.get(TaskMonitorAdapter.DUMMY_MONITOR);
r1.join();
assertEquals(ITEM_COUNT, r1.size());
waitForPostedSwingRunnables();
assertTrue(!dialog.isVisible());
assertEquals("number of runs", 1, worker.getNumRuns());
assertEquals(ITEM_COUNT, runnable.size());
}
@Test
public void testSwingAfterAnotherThreadCase() throws InterruptedException {
disasbleTimerUsage();
TestWorker worker = new TestWorker();
worker.setTaskDialogDelay(0);
MyThread r1 = new MyThread(0, worker);
Thread.sleep(50);
ClientRunnable runnable = new ClientRunnable(worker);
runSwing(runnable, false);
TaskDialog dialog = waitForDialogComponent(null, TaskDialog.class, 2000);
assertNotNull(dialog);
worker.setDone();
worker.get(TaskMonitorAdapter.DUMMY_MONITOR);
r1.join();
assertEquals(ITEM_COUNT, r1.size());
waitForPostedSwingRunnables();
assertTrue(!dialog.isVisible());
assertEquals("number of runs", 1, worker.getNumRuns());
assertEquals(ITEM_COUNT, runnable.size());
}
@Test
public void testCancelled() {
TestWorker worker = new TestWorker();
worker.setTaskDialogDelay(0);
ClientRunnable runnable = new ClientRunnable(worker);
runSwing(runnable, false);
runSwing(runnable, false);
TaskDialog dialog = waitForDialogComponent(null, TaskDialog.class, 2000);
assertTrue(dialog.getTitle().contains("Test Worker"));
assertNotNull(dialog);
dialog.cancel();
worker.get(TaskMonitorAdapter.DUMMY_MONITOR);
waitForPostedSwingRunnables();
assertTrue(!dialog.isVisible());
assertEquals("number of runs", 1, worker.getNumRuns());
assertTrue(worker.wasCancelled);
}
//==================================================================================================
// Private Methods
//==================================================================================================
private void disasbleTimerUsage() {
AccumulativeRunnable<Runnable> nonTimerAccumulativeRunnable =
new AccumulativeRunnable<Runnable>() {
@Override
protected void run(List<Runnable> args) {
for (Runnable runnable : args) {
runnable.run();
}
}
};
Object key = getInstanceField("DO_SUBMIT_KEY", SwingWorker.class);
AppContext appContext = AppContext.getAppContext();
appContext.put(key, nonTimerAccumulativeRunnable);
}
//==================================================================================================
// Inner Classes
//==================================================================================================
class MyThread extends Thread {
ClientRunnable runnable;
MyThread(int delay, TestWorker worker) {
runnable = new ClientRunnable(worker);
try {
Thread.sleep(delay);
}
catch (InterruptedException e) {
// whatever
}
start();
}
@Override
public void run() {
runnable.run();
}
int size() {
if (runnable == null) {
return 0;
}
return runnable.size();
}
}
class TestWorker extends CachingSwingWorker<List<String>> {
private volatile boolean done = false;
private int numRuns = 0;
private volatile boolean wasCancelled = false;
public TestWorker() {
super("Test Worker", true);
}
@Override
protected List<String> runInBackground(TaskMonitor monitor) {
monitor.initialize(ITEM_COUNT);
numRuns++;
List<String> list = new ArrayList<String>();
int count = 0;
while (!done || count < ITEM_COUNT) {
if (monitor.isCancelled()) {
wasCancelled = true;
break;
}
if (count < ITEM_COUNT) {
String message = "line " + count;
list.add(message);
monitor.setProgress(count);
monitor.setMessage(message);
}
count++;
try {
Thread.sleep(10);
}
catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
if (count > 600) {
list.add("timeout");
break;
}
}
return list;
}
void setDone() {
done = true;
}
boolean wasCancelled() {
return wasCancelled;
}
int getNumRuns() {
return numRuns;
}
}
class ClientRunnable implements Runnable {
List<String> result;
private TestWorker worker;
ClientRunnable(TestWorker worker) {
this.worker = worker;
}
public int size() {
return result == null ? 0 : result.size();
}
@Override
public void run() {
result = worker.get(TaskMonitorAdapter.DUMMY_MONITOR);
}
}
}