mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-03 17:59:46 +02:00
GT-3035 - Restore Integration Tests - restored missing test files; fast
tests
This commit is contained in:
parent
822e5a0610
commit
4dc8e77172
45 changed files with 6609 additions and 0 deletions
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -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();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
|
@ -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());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -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());
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
196
Ghidra/Framework/Help/src/test/java/help/AbstractHelpTest.java
Normal file
196
Ghidra/Framework/Help/src/test/java/help/AbstractHelpTest.java
Normal 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);
|
||||||
|
}
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
|
@ -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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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();
|
||||||
|
}
|
||||||
|
}
|
|
@ -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 {
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
|
@ -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 {
|
||||||
|
|
||||||
|
}
|
|
@ -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 {
|
||||||
|
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
|
@ -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 {
|
||||||
|
|
||||||
|
}
|
|
@ -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 {
|
||||||
|
|
||||||
|
}
|
|
@ -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 {
|
||||||
|
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -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++;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -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++;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -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 {
|
||||||
|
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -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 {
|
||||||
|
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
File diff suppressed because it is too large
Load diff
|
@ -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());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -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());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -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());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue