mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-05 02:39:44 +02:00
Tests - cleanup of stack traces in test log file
This commit is contained in:
parent
b7c8056c8a
commit
e5358323d8
24 changed files with 889 additions and 678 deletions
|
@ -713,6 +713,7 @@ public class GhidraSourceBundle extends GhidraBundle {
|
|||
}
|
||||
}
|
||||
catch (Throwable e) {
|
||||
Msg.error(this, "Exception searching ", e);
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
@ -1090,46 +1091,51 @@ public class GhidraSourceBundle extends GhidraBundle {
|
|||
* @throws IOException if there's a problem listing files
|
||||
*/
|
||||
ClassMapper(Path directory) throws IOException {
|
||||
if (Files.exists(directory)) {
|
||||
try (Stream<Path> pathStream = Files.list(directory)) {
|
||||
classToClassFilesMap = pathStream
|
||||
.filter(f -> Files.isRegularFile(f) &&
|
||||
f.getFileName().toString().endsWith(".class"))
|
||||
.collect(groupingBy(f -> {
|
||||
String fileName = f.getFileName().toString();
|
||||
// if f is the class file of an inner class, use the class name
|
||||
int money = fileName.indexOf('$');
|
||||
if (money >= 0) {
|
||||
return fileName.substring(0, money);
|
||||
}
|
||||
// drop ".class"
|
||||
return fileName.substring(0, fileName.length() - 6);
|
||||
}));
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (!Files.exists(directory)) {
|
||||
classToClassFilesMap = Collections.emptyMap();
|
||||
return;
|
||||
}
|
||||
|
||||
try (Stream<Path> paths = Files.list(directory)) {
|
||||
classToClassFilesMap = paths
|
||||
.filter(p -> Files.isRegularFile(p))
|
||||
.filter(p -> p.getFileName().toString().endsWith(".class"))
|
||||
.collect(groupingBy(this::getClassName));
|
||||
}
|
||||
}
|
||||
|
||||
private String getClassName(Path p) {
|
||||
String fileName = p.getFileName().toString();
|
||||
// if f is the class file of an inner class, use the class name
|
||||
int money = fileName.indexOf('$');
|
||||
if (money >= 0) {
|
||||
return fileName.substring(0, money);
|
||||
}
|
||||
// drop ".class"
|
||||
return fileName.substring(0, fileName.length() - 6);
|
||||
}
|
||||
|
||||
List<Path> findAndRemove(ResourceFile sourceFile) {
|
||||
String className = sourceFile.getName();
|
||||
if (className.endsWith(".java")) {
|
||||
className = className.substring(0, className.length() - 5);
|
||||
long lastModifiedSource = sourceFile.lastModified();
|
||||
List<Path> classFiles = classToClassFilesMap.remove(className);
|
||||
if (classFiles == null) {
|
||||
classFiles = Collections.emptyList();
|
||||
}
|
||||
long lastModifiedClassFile = classFiles.isEmpty() ? -1
|
||||
: classFiles.stream()
|
||||
.mapToLong(p -> p.toFile().lastModified())
|
||||
.min()
|
||||
.getAsLong();
|
||||
// if source is newer than the oldest binary, report
|
||||
if (lastModifiedSource > lastModifiedClassFile) {
|
||||
return classFiles;
|
||||
}
|
||||
if (!className.endsWith(".java")) {
|
||||
return null;
|
||||
}
|
||||
|
||||
className = className.substring(0, className.length() - 5);
|
||||
long lastModifiedSource = sourceFile.lastModified();
|
||||
List<Path> classFiles = classToClassFilesMap.remove(className);
|
||||
if (classFiles == null) {
|
||||
classFiles = Collections.emptyList();
|
||||
}
|
||||
|
||||
long lastModifiedClassFile = classFiles.isEmpty() ? -1
|
||||
: classFiles.stream()
|
||||
.mapToLong(p -> p.toFile().lastModified())
|
||||
.min()
|
||||
.getAsLong();
|
||||
// if source is newer than the oldest binary, report
|
||||
if (lastModifiedSource > lastModifiedClassFile) {
|
||||
return classFiles;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
|
|
@ -241,6 +241,7 @@ public class GhidraScriptUtil {
|
|||
*/
|
||||
@Deprecated
|
||||
public static List<ResourceFile> getExplodedCompiledSourceBundlePaths() {
|
||||
|
||||
try (Stream<Path> pathStream = Files.list(BundleHost.getOsgiDir())) {
|
||||
return pathStream.filter(Files::isDirectory)
|
||||
.map(x -> new ResourceFile(x.toFile()))
|
||||
|
|
|
@ -50,11 +50,9 @@ import ghidra.program.model.util.*;
|
|||
import ghidra.program.util.DefaultLanguageService;
|
||||
import ghidra.program.util.GhidraProgramUtilities;
|
||||
import ghidra.test.AbstractGhidraHeadedIntegrationTest;
|
||||
import ghidra.util.NumericUtilities;
|
||||
import ghidra.util.Saveable;
|
||||
import ghidra.util.*;
|
||||
import ghidra.util.exception.*;
|
||||
import ghidra.util.task.TaskMonitor;
|
||||
import ghidra.util.task.TaskMonitorAdapter;
|
||||
|
||||
// TODO: Move this class into a different package (i.e., ghidra.test.program)
|
||||
public class ProgramBuilder {
|
||||
|
@ -97,7 +95,7 @@ public class ProgramBuilder {
|
|||
* Construct program builder using the big-endian Toy language and default compiler spec.
|
||||
* This builder object will be the program consumer and must be disposed to properly
|
||||
* release the program.
|
||||
* @throws Exception
|
||||
* @throws Exception if there is an exception creating the program
|
||||
*/
|
||||
public ProgramBuilder() throws Exception {
|
||||
this("Test Program", _TOY);
|
||||
|
@ -109,7 +107,7 @@ public class ProgramBuilder {
|
|||
* release the program.
|
||||
* @param name program name
|
||||
* @param languageName supported language ID (includes all Toy language IDs)
|
||||
* @throws Exception
|
||||
* @throws Exception if there is an exception creating the program
|
||||
*/
|
||||
public ProgramBuilder(String name, String languageName) throws Exception {
|
||||
this(name, languageName, null, null);
|
||||
|
@ -120,7 +118,7 @@ public class ProgramBuilder {
|
|||
* @param name program name
|
||||
* @param languageName supported language ID (includes all Toy language IDs)
|
||||
* @param consumer program consumer (if null this builder will be used as consumer and must be disposed to release program)
|
||||
* @throws Exception
|
||||
* @throws Exception if there is an exception creating the program
|
||||
*/
|
||||
public ProgramBuilder(String name, String languageName, Object consumer) throws Exception {
|
||||
this(name, languageName, null, consumer);
|
||||
|
@ -132,7 +130,7 @@ public class ProgramBuilder {
|
|||
* @param languageName supported language ID (includes all Toy language IDs)
|
||||
* @param compilerSpecID compiler specification ID (if null default spec will be used)
|
||||
* @param consumer program consumer (if null this builder will be used as consumer and must be disposed to release program)
|
||||
* @throws Exception
|
||||
* @throws Exception if there is an exception creating the program
|
||||
*/
|
||||
public ProgramBuilder(String name, String languageName, String compilerSpecID, Object consumer)
|
||||
throws Exception {
|
||||
|
@ -205,10 +203,22 @@ public class ProgramBuilder {
|
|||
|
||||
public void dispose() {
|
||||
if (program.isUsedBy(this)) {
|
||||
|
||||
// Make sure any buffered events are processed before we release. This fixes a timing
|
||||
// issue that can happen when the test thread disposes the program while the Swing
|
||||
// thread is processing events.
|
||||
flushEvents();
|
||||
program.release(this);
|
||||
}
|
||||
}
|
||||
|
||||
private void flushEvents() {
|
||||
program.flushEvents();
|
||||
if (!SystemUtilities.isInHeadlessMode()) {
|
||||
AbstractGenericTest.waitForSwing();
|
||||
}
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
startTransaction();
|
||||
try {
|
||||
|
@ -286,7 +296,8 @@ public class ProgramBuilder {
|
|||
LanguageService languageService = DefaultLanguageService.getLanguageService(ldefFile);
|
||||
try {
|
||||
language = languageService.getLanguage(new LanguageID(languageName));
|
||||
} catch (LanguageNotFoundException e) {
|
||||
}
|
||||
catch (LanguageNotFoundException e) {
|
||||
throw new LanguageNotFoundException("Unsupported test language: " + languageName);
|
||||
}
|
||||
LANGUAGE_CACHE.put(languageName, language);
|
||||
|
@ -303,7 +314,10 @@ public class ProgramBuilder {
|
|||
AbstractGenericTest.setInstanceField("recordChanges", program, Boolean.valueOf(enabled));
|
||||
}
|
||||
|
||||
/** Don't show the 'ask to analyze' dialog by default */
|
||||
/**
|
||||
* This prevents the 'ask to analyze' dialog from showing when called with {@code true}
|
||||
* @param analyzed true to mark the program as analyzed
|
||||
*/
|
||||
public void setAnalyzed(boolean analyzed) {
|
||||
GhidraProgramUtilities.setAnalyzedFlag(program, analyzed);
|
||||
}
|
||||
|
@ -325,7 +339,7 @@ public class ProgramBuilder {
|
|||
MemoryBlock block = null;
|
||||
try {
|
||||
block = memory.createInitializedBlock(name, startAddress, size, initialValue,
|
||||
TaskMonitorAdapter.DUMMY_MONITOR, false);
|
||||
TaskMonitor.DUMMY, false);
|
||||
block.setComment(comment);
|
||||
}
|
||||
catch (CancelledException e) {
|
||||
|
@ -359,8 +373,9 @@ public class ProgramBuilder {
|
|||
|
||||
startTransaction();
|
||||
try {
|
||||
return program.getMemory().createInitializedBlock(name, addr(address), size, (byte) 0,
|
||||
TaskMonitor.DUMMY, true);
|
||||
return program.getMemory()
|
||||
.createInitializedBlock(name, addr(address), size, (byte) 0,
|
||||
TaskMonitor.DUMMY, true);
|
||||
}
|
||||
catch (Exception e) {
|
||||
throw new RuntimeException("Exception building memory", e);
|
||||
|
@ -378,7 +393,7 @@ public class ProgramBuilder {
|
|||
* @param address String containing numeric value, preferably hex encoded: "0x1004000"
|
||||
* @param byteString String containing 2 digit hex values, separated by ' ' space chars
|
||||
* or by comma ',' chars: "12 05 ff". See {@link NumericUtilities#parseHexLong(String)}.
|
||||
* @throws Exception
|
||||
* @throws Exception if there is an exception applying the bytes
|
||||
*/
|
||||
public void setBytes(String address, String byteString) throws Exception {
|
||||
byte[] bytes = NumericUtilities.convertStringToBytes(byteString);
|
||||
|
@ -395,7 +410,7 @@ public class ProgramBuilder {
|
|||
* @param byteString String containing 2 digit hex values, separated by ' ' space chars
|
||||
* or by comma ',' chars: "12 05 ff". See {@link NumericUtilities#parseHexLong(String)}.
|
||||
* @param disassemble boolean flag.
|
||||
* @throws Exception
|
||||
* @throws Exception if there is an exception applying the bytes
|
||||
*/
|
||||
public void setBytes(String address, String byteString, boolean disassemble) throws Exception {
|
||||
byte[] bytes = NumericUtilities.convertStringToBytes(byteString);
|
||||
|
@ -413,7 +428,7 @@ public class ProgramBuilder {
|
|||
* @param stringAddress String containing numeric value, preferably hex encoded: "0x1004000"
|
||||
* @param bytes array of bytes to copy into the memory buffer at the addresss.
|
||||
* @param disassemble boolean flag. See {@link #disassemble(String, int)}
|
||||
* @throws Exception
|
||||
* @throws Exception if there is an exception applying the bytes
|
||||
*/
|
||||
public void setBytes(String stringAddress, byte[] bytes, boolean disassemble) throws Exception {
|
||||
Address address = addr(stringAddress);
|
||||
|
@ -547,9 +562,6 @@ public class ProgramBuilder {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This creates a function as big as you say.
|
||||
*/
|
||||
public Function createEmptyFunction(String name, String address, int size, DataType returnType,
|
||||
Parameter... params) throws Exception, OverlappingFunctionException {
|
||||
|
||||
|
|
|
@ -674,7 +674,7 @@ public class RefMergerExtTest extends AbstractExternalMergerTest {
|
|||
assertEquals("Bar", ((ExternalReference) refs[0]).getExternalLocation().getLabel());
|
||||
assertTrue(refs[0].getSource() == SourceType.ANALYSIS);
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testExtRefChangeRefTypeConflictPickMy() throws Exception {
|
||||
|
||||
|
@ -688,19 +688,20 @@ public class RefMergerExtTest extends AbstractExternalMergerTest {
|
|||
int txId = program.startTransaction("Modify Original Program");
|
||||
boolean commit = false;
|
||||
try {
|
||||
ExternalLocation extLoc = createExternalLabel(program, new String[] { "Library", "Namespace", "Label1" },
|
||||
ExternalLocation extLoc = createExternalLabel(program,
|
||||
new String[] { "Library", "Namespace", "Label1" },
|
||||
addr(program, "77db1020"), SourceType.ANALYSIS);
|
||||
|
||||
|
||||
ReferenceManager refMgr = program.getReferenceManager();
|
||||
|
||||
|
||||
Reference[] refs = refMgr.getReferencesFrom(addr(program, "0x1001000"), 0);
|
||||
assertEquals(1, refs.length);
|
||||
Address fromAddress = refs[0].getFromAddress();
|
||||
int operandIndex = refs[0].getOperandIndex();
|
||||
refMgr.delete(refs[0]);
|
||||
|
||||
|
||||
refMgr.addExternalReference(fromAddress, operandIndex, extLoc,
|
||||
extLoc.getSource(), RefType.DATA);
|
||||
extLoc.getSource(), RefType.DATA);
|
||||
|
||||
commit = true;
|
||||
}
|
||||
|
@ -721,12 +722,12 @@ public class RefMergerExtTest extends AbstractExternalMergerTest {
|
|||
boolean commit = false;
|
||||
try {
|
||||
ReferenceManager refMgr = program.getReferenceManager();
|
||||
|
||||
|
||||
ExternalLocation extLoc = getExternalLocation(program,
|
||||
new String[] { "Library", "Namespace", "Label1" });
|
||||
|
||||
new String[] { "Library", "Namespace", "Label1" });
|
||||
|
||||
refMgr.addExternalReference(addr(program, "0x1001000"), 0, extLoc,
|
||||
extLoc.getSource(), RefType.COMPUTED_CALL);
|
||||
extLoc.getSource(), RefType.COMPUTED_CALL);
|
||||
|
||||
commit = true;
|
||||
}
|
||||
|
@ -747,12 +748,12 @@ public class RefMergerExtTest extends AbstractExternalMergerTest {
|
|||
boolean commit = false;
|
||||
try {
|
||||
ReferenceManager refMgr = program.getReferenceManager();
|
||||
|
||||
|
||||
ExternalLocation extLoc = getExternalLocation(program,
|
||||
new String[] { "Library", "Namespace", "Label1" });
|
||||
|
||||
new String[] { "Library", "Namespace", "Label1" });
|
||||
|
||||
refMgr.addExternalReference(addr(program, "0x1001000"), 0, extLoc,
|
||||
extLoc.getSource(), RefType.COMPUTED_CALL_TERMINATOR);
|
||||
extLoc.getSource(), RefType.COMPUTED_CALL_TERMINATOR);
|
||||
|
||||
commit = true;
|
||||
}
|
||||
|
@ -1328,13 +1329,7 @@ public class RefMergerExtTest extends AbstractExternalMergerTest {
|
|||
finally {
|
||||
program.endTransaction(txId, commit);
|
||||
}
|
||||
ExternalManager externalManager = program.getExternalManager();
|
||||
ExternalLocationIterator externalLocations =
|
||||
externalManager.getExternalLocations("ADVAPI32.DLL");
|
||||
while (externalLocations.hasNext()) {
|
||||
ExternalLocation next = externalLocations.next();
|
||||
System.out.println("Location=" + next.getSymbol().getName(true));
|
||||
}
|
||||
|
||||
ExternalLocation externalLocation1 =
|
||||
getExternalLocation(program, new String[] { "USER32.DLL", "printf" });
|
||||
assertNotNull(externalLocation1);
|
||||
|
@ -1452,13 +1447,7 @@ public class RefMergerExtTest extends AbstractExternalMergerTest {
|
|||
finally {
|
||||
program.endTransaction(txId, commit);
|
||||
}
|
||||
ExternalManager externalManager = program.getExternalManager();
|
||||
ExternalLocationIterator externalLocations =
|
||||
externalManager.getExternalLocations("ADVAPI32.DLL");
|
||||
while (externalLocations.hasNext()) {
|
||||
ExternalLocation next = externalLocations.next();
|
||||
System.out.println("Location=" + next.getSymbol().getName(true));
|
||||
}
|
||||
|
||||
ExternalLocation externalLocation1 =
|
||||
getExternalLocation(program, new String[] { "USER32.DLL", "printf" });
|
||||
assertNotNull(externalLocation1);
|
||||
|
|
|
@ -94,15 +94,7 @@ public class SymbolMergeManagerNamespace1Test extends AbstractListingMergeManage
|
|||
// 01005c6f FUN_01005c6f body:[1005c6f-1005fbd][1005ff5-10061e2]
|
||||
// 01006420 entry body:[1006420-1006581][10065a4-10065cd]
|
||||
|
||||
/**
|
||||
*
|
||||
* @param arg0
|
||||
*/
|
||||
public SymbolMergeManagerNamespace1Test() {
|
||||
super();
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* Test generic Namespace symbols being removed from either the LATEST or
|
||||
* CHECKED OUT program when it doesn't result in a conflict.
|
||||
* @throws Exception
|
||||
|
@ -169,7 +161,7 @@ public class SymbolMergeManagerNamespace1Test extends AbstractListingMergeManage
|
|||
assertNull(funcMgr.getFunctionAt(addr("0x01004bc0")));
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* Test Class symbols being removed from either the LATEST or
|
||||
* CHECKED OUT program when it doesn't result in a conflict.
|
||||
* @throws Exception
|
||||
|
@ -566,17 +558,21 @@ public class SymbolMergeManagerNamespace1Test extends AbstractListingMergeManage
|
|||
try {
|
||||
Namespace ns;
|
||||
GhidraClass gc;
|
||||
ns = program.getSymbolTable().createNameSpace(program.getGlobalNamespace(),
|
||||
"Blue", SourceType.USER_DEFINED);
|
||||
ns = program.getSymbolTable()
|
||||
.createNameSpace(program.getGlobalNamespace(),
|
||||
"Blue", SourceType.USER_DEFINED);
|
||||
assertNotNull(ns);
|
||||
ns = program.getSymbolTable().createNameSpace(program.getGlobalNamespace(),
|
||||
"Green", SourceType.USER_DEFINED);
|
||||
ns = program.getSymbolTable()
|
||||
.createNameSpace(program.getGlobalNamespace(),
|
||||
"Green", SourceType.USER_DEFINED);
|
||||
assertNotNull(ns);
|
||||
gc = program.getSymbolTable().createClass(program.getGlobalNamespace(), "Red",
|
||||
SourceType.USER_DEFINED);
|
||||
gc = program.getSymbolTable()
|
||||
.createClass(program.getGlobalNamespace(), "Red",
|
||||
SourceType.USER_DEFINED);
|
||||
assertNotNull(gc);
|
||||
gc = program.getSymbolTable().createClass(program.getGlobalNamespace(),
|
||||
"Yellow", SourceType.USER_DEFINED);
|
||||
gc = program.getSymbolTable()
|
||||
.createClass(program.getGlobalNamespace(),
|
||||
"Yellow", SourceType.USER_DEFINED);
|
||||
assertNotNull(gc);
|
||||
commit = true;
|
||||
}
|
||||
|
@ -598,17 +594,21 @@ public class SymbolMergeManagerNamespace1Test extends AbstractListingMergeManage
|
|||
try {
|
||||
Namespace ns;
|
||||
GhidraClass gc;
|
||||
gc = program.getSymbolTable().createClass(program.getGlobalNamespace(), "Blue",
|
||||
SourceType.USER_DEFINED);
|
||||
gc = program.getSymbolTable()
|
||||
.createClass(program.getGlobalNamespace(), "Blue",
|
||||
SourceType.USER_DEFINED);
|
||||
assertNotNull(gc);
|
||||
gc = program.getSymbolTable().createClass(program.getGlobalNamespace(), "Green",
|
||||
SourceType.USER_DEFINED);
|
||||
gc = program.getSymbolTable()
|
||||
.createClass(program.getGlobalNamespace(), "Green",
|
||||
SourceType.USER_DEFINED);
|
||||
assertNotNull(gc);
|
||||
ns = program.getSymbolTable().createNameSpace(program.getGlobalNamespace(),
|
||||
"Red", SourceType.USER_DEFINED);
|
||||
ns = program.getSymbolTable()
|
||||
.createNameSpace(program.getGlobalNamespace(),
|
||||
"Red", SourceType.USER_DEFINED);
|
||||
assertNotNull(ns);
|
||||
ns = program.getSymbolTable().createNameSpace(program.getGlobalNamespace(),
|
||||
"Yellow", SourceType.USER_DEFINED);
|
||||
ns = program.getSymbolTable()
|
||||
.createNameSpace(program.getGlobalNamespace(),
|
||||
"Yellow", SourceType.USER_DEFINED);
|
||||
assertNotNull(ns);
|
||||
commit = true;
|
||||
}
|
||||
|
@ -665,17 +665,21 @@ public class SymbolMergeManagerNamespace1Test extends AbstractListingMergeManage
|
|||
"EmptyNamespace", program.getGlobalNamespace()).getObject();
|
||||
Namespace ns;
|
||||
GhidraClass gc;
|
||||
ns = program.getSymbolTable().createNameSpace(emptyNamespace, "Blue",
|
||||
SourceType.USER_DEFINED);
|
||||
ns = program.getSymbolTable()
|
||||
.createNameSpace(emptyNamespace, "Blue",
|
||||
SourceType.USER_DEFINED);
|
||||
assertNotNull(ns);
|
||||
ns = program.getSymbolTable().createNameSpace(emptyNamespace, "Green",
|
||||
SourceType.USER_DEFINED);
|
||||
ns = program.getSymbolTable()
|
||||
.createNameSpace(emptyNamespace, "Green",
|
||||
SourceType.USER_DEFINED);
|
||||
assertNotNull(ns);
|
||||
gc = program.getSymbolTable().createClass(emptyNamespace, "Red",
|
||||
SourceType.USER_DEFINED);
|
||||
gc = program.getSymbolTable()
|
||||
.createClass(emptyNamespace, "Red",
|
||||
SourceType.USER_DEFINED);
|
||||
assertNotNull(gc);
|
||||
gc = program.getSymbolTable().createClass(emptyNamespace, "Yellow",
|
||||
SourceType.USER_DEFINED);
|
||||
gc = program.getSymbolTable()
|
||||
.createClass(emptyNamespace, "Yellow",
|
||||
SourceType.USER_DEFINED);
|
||||
assertNotNull(gc);
|
||||
commit = true;
|
||||
}
|
||||
|
@ -699,17 +703,21 @@ public class SymbolMergeManagerNamespace1Test extends AbstractListingMergeManage
|
|||
"EmptyNamespace", program.getGlobalNamespace()).getObject();
|
||||
Namespace ns;
|
||||
GhidraClass gc;
|
||||
gc = program.getSymbolTable().createClass(emptyNamespace, "Blue",
|
||||
SourceType.USER_DEFINED);
|
||||
gc = program.getSymbolTable()
|
||||
.createClass(emptyNamespace, "Blue",
|
||||
SourceType.USER_DEFINED);
|
||||
assertNotNull(gc);
|
||||
gc = program.getSymbolTable().createClass(emptyNamespace, "Green",
|
||||
SourceType.USER_DEFINED);
|
||||
gc = program.getSymbolTable()
|
||||
.createClass(emptyNamespace, "Green",
|
||||
SourceType.USER_DEFINED);
|
||||
assertNotNull(gc);
|
||||
ns = program.getSymbolTable().createNameSpace(emptyNamespace, "Red",
|
||||
SourceType.USER_DEFINED);
|
||||
ns = program.getSymbolTable()
|
||||
.createNameSpace(emptyNamespace, "Red",
|
||||
SourceType.USER_DEFINED);
|
||||
assertNotNull(ns);
|
||||
ns = program.getSymbolTable().createNameSpace(emptyNamespace, "Yellow",
|
||||
SourceType.USER_DEFINED);
|
||||
ns = program.getSymbolTable()
|
||||
.createNameSpace(emptyNamespace, "Yellow",
|
||||
SourceType.USER_DEFINED);
|
||||
assertNotNull(ns);
|
||||
commit = true;
|
||||
}
|
||||
|
@ -773,17 +781,21 @@ public class SymbolMergeManagerNamespace1Test extends AbstractListingMergeManage
|
|||
try {
|
||||
Namespace ns;
|
||||
GhidraClass gc;
|
||||
ns = program.getSymbolTable().createNameSpace(program.getGlobalNamespace(),
|
||||
"Blue", SourceType.USER_DEFINED);
|
||||
ns = program.getSymbolTable()
|
||||
.createNameSpace(program.getGlobalNamespace(),
|
||||
"Blue", SourceType.USER_DEFINED);
|
||||
assertNotNull(ns);
|
||||
ns = program.getSymbolTable().createNameSpace(program.getGlobalNamespace(),
|
||||
"Green", SourceType.USER_DEFINED);
|
||||
ns = program.getSymbolTable()
|
||||
.createNameSpace(program.getGlobalNamespace(),
|
||||
"Green", SourceType.USER_DEFINED);
|
||||
assertNotNull(ns);
|
||||
gc = program.getSymbolTable().createClass(program.getGlobalNamespace(), "Red",
|
||||
SourceType.USER_DEFINED);
|
||||
gc = program.getSymbolTable()
|
||||
.createClass(program.getGlobalNamespace(), "Red",
|
||||
SourceType.USER_DEFINED);
|
||||
assertNotNull(gc);
|
||||
gc = program.getSymbolTable().createClass(program.getGlobalNamespace(),
|
||||
"Yellow", SourceType.USER_DEFINED);
|
||||
gc = program.getSymbolTable()
|
||||
.createClass(program.getGlobalNamespace(),
|
||||
"Yellow", SourceType.USER_DEFINED);
|
||||
assertNotNull(gc);
|
||||
commit = true;
|
||||
}
|
||||
|
@ -805,23 +817,29 @@ public class SymbolMergeManagerNamespace1Test extends AbstractListingMergeManage
|
|||
try {
|
||||
Namespace ns;
|
||||
GhidraClass gc;
|
||||
gc = program.getSymbolTable().createClass(program.getGlobalNamespace(), "Blue",
|
||||
SourceType.USER_DEFINED);
|
||||
gc = program.getSymbolTable()
|
||||
.createClass(program.getGlobalNamespace(), "Blue",
|
||||
SourceType.USER_DEFINED);
|
||||
assertNotNull(gc);
|
||||
gc = program.getSymbolTable().createClass(program.getGlobalNamespace(), "Green",
|
||||
SourceType.USER_DEFINED);
|
||||
gc = program.getSymbolTable()
|
||||
.createClass(program.getGlobalNamespace(), "Green",
|
||||
SourceType.USER_DEFINED);
|
||||
assertNotNull(gc);
|
||||
ns = program.getSymbolTable().createNameSpace(program.getGlobalNamespace(),
|
||||
"Red", SourceType.USER_DEFINED);
|
||||
ns = program.getSymbolTable()
|
||||
.createNameSpace(program.getGlobalNamespace(),
|
||||
"Red", SourceType.USER_DEFINED);
|
||||
assertNotNull(ns);
|
||||
gc = program.getSymbolTable().createClass(ns, "SubRed",
|
||||
SourceType.USER_DEFINED);
|
||||
gc = program.getSymbolTable()
|
||||
.createClass(ns, "SubRed",
|
||||
SourceType.USER_DEFINED);
|
||||
assertNotNull(gc);
|
||||
ns = program.getSymbolTable().createNameSpace(program.getGlobalNamespace(),
|
||||
"Yellow", SourceType.USER_DEFINED);
|
||||
ns = program.getSymbolTable()
|
||||
.createNameSpace(program.getGlobalNamespace(),
|
||||
"Yellow", SourceType.USER_DEFINED);
|
||||
assertNotNull(ns);
|
||||
ns = program.getSymbolTable().createNameSpace(ns, "SubYellow",
|
||||
SourceType.USER_DEFINED);
|
||||
ns = program.getSymbolTable()
|
||||
.createNameSpace(ns, "SubYellow",
|
||||
SourceType.USER_DEFINED);
|
||||
assertNotNull(ns);
|
||||
commit = true;
|
||||
}
|
||||
|
@ -1271,15 +1289,6 @@ public class SymbolMergeManagerNamespace1Test extends AbstractListingMergeManage
|
|||
"The following namespaces were not removed", 4000);
|
||||
waitForMergeCompletion();
|
||||
|
||||
SymbolTable symtab = resultProgram.getSymbolTable();
|
||||
Namespace globalNS = resultProgram.getGlobalNamespace();
|
||||
SymbolIterator iter = symtab.getSymbols(globalNS);
|
||||
while (iter.hasNext()) {
|
||||
Symbol s = iter.next();
|
||||
if (s.getSymbolType().equals(SymbolType.NAMESPACE)) {
|
||||
System.out.println("Namespace = " + s.getName(true));
|
||||
}
|
||||
}
|
||||
Symbol firstNsSymbol =
|
||||
getUniqueSymbol(resultProgram, "FirstNamespace", resultProgram.getGlobalNamespace());
|
||||
assertNotNull(firstNsSymbol);
|
||||
|
|
|
@ -15,24 +15,14 @@
|
|||
*/
|
||||
package ghidra.app.plugin.core.analysis;
|
||||
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.*;
|
||||
|
||||
import javax.swing.JComponent;
|
||||
import javax.swing.table.TableModel;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.*;
|
||||
|
||||
import docking.widgets.OptionDialog;
|
||||
import ghidra.GhidraOptions;
|
||||
|
@ -71,6 +61,7 @@ public class AnalyzeAllOpenProgramsTaskTest extends AbstractGhidraHeadedIntegrat
|
|||
for (Program program : openPrograms) {
|
||||
env.release(program);
|
||||
}
|
||||
tool.close();
|
||||
env.dispose();
|
||||
}
|
||||
|
||||
|
@ -236,7 +227,7 @@ public class AnalyzeAllOpenProgramsTaskTest extends AbstractGhidraHeadedIntegrat
|
|||
openPrograms.toArray(new Program[openPrograms.size()]), spy);
|
||||
runTask(task);
|
||||
|
||||
OptionDialog warningDialog = waitForDialogComponent(null, OptionDialog.class, 2000);
|
||||
OptionDialog warningDialog = waitForDialogComponent(OptionDialog.class);
|
||||
pressButtonByText(warningDialog, "Cancel");
|
||||
|
||||
waitForTasks();
|
||||
|
@ -307,17 +298,19 @@ public class AnalyzeAllOpenProgramsTaskTest extends AbstractGhidraHeadedIntegrat
|
|||
findComponent(optionsDialog.getComponent(), AnalysisPanel.class, false);
|
||||
invokeInstanceMethod("deselectAll", panel);
|
||||
waitForSwing();
|
||||
|
||||
close(optionsDialog);
|
||||
}
|
||||
|
||||
private void enableOption(String optionName, boolean expectWarning) {
|
||||
|
||||
if (expectWarning) {
|
||||
OptionDialog warningDialog = waitForDialogComponent(null, OptionDialog.class, 2000);
|
||||
OptionDialog warningDialog = waitForDialogComponent(OptionDialog.class);
|
||||
pressButtonByText(warningDialog, "Continue");
|
||||
}
|
||||
|
||||
AnalysisOptionsDialog optionsDialog =
|
||||
waitForDialogComponent(null, AnalysisOptionsDialog.class, DEFAULT_WINDOW_TIMEOUT);
|
||||
waitForDialogComponent(AnalysisOptionsDialog.class);
|
||||
|
||||
// select some options
|
||||
JComponent root = optionsDialog.getComponent();
|
||||
|
@ -332,7 +325,7 @@ public class AnalyzeAllOpenProgramsTaskTest extends AbstractGhidraHeadedIntegrat
|
|||
|
||||
private void cancelAnalysisDialog() {
|
||||
AnalysisOptionsDialog optionsDialog =
|
||||
waitForDialogComponent(null, AnalysisOptionsDialog.class, DEFAULT_WINDOW_TIMEOUT);
|
||||
waitForDialogComponent(AnalysisOptionsDialog.class);
|
||||
|
||||
// press Apply
|
||||
pressButtonByText(optionsDialog, "Cancel");
|
||||
|
@ -437,6 +430,11 @@ public class AnalyzeAllOpenProgramsTaskTest extends AbstractGhidraHeadedIntegrat
|
|||
}
|
||||
return super.getOptions(categoryName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
runSwing(super::close);
|
||||
}
|
||||
}
|
||||
|
||||
private class AnalyzeProgramStrategySpy extends AnalyzeProgramStrategy {
|
||||
|
|
|
@ -24,6 +24,7 @@ import javax.swing.table.*;
|
|||
|
||||
import org.junit.*;
|
||||
|
||||
import docking.ActionContext;
|
||||
import docking.ComponentProvider;
|
||||
import docking.action.DockingActionIf;
|
||||
import docking.tool.ToolConstants;
|
||||
|
@ -45,6 +46,7 @@ public class FunctionWindowPluginTest extends AbstractGhidraHeadedIntegrationTes
|
|||
private Program program;
|
||||
private FunctionWindowPlugin plugin;
|
||||
private GTable functionTable;
|
||||
private ComponentProvider provider;
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
|
@ -56,7 +58,7 @@ public class FunctionWindowPluginTest extends AbstractGhidraHeadedIntegrationTes
|
|||
|
||||
plugin.showFunctions();
|
||||
waitForSwing();
|
||||
ComponentProvider provider = tool.getComponentProvider("Functions Window");
|
||||
provider = tool.getComponentProvider("Functions Window");
|
||||
functionTable = (GTable) findComponentByName(provider.getComponent(), "FunctionTable");
|
||||
}
|
||||
|
||||
|
@ -74,6 +76,8 @@ public class FunctionWindowPluginTest extends AbstractGhidraHeadedIntegrationTes
|
|||
private void closeProgram() {
|
||||
ProgramManager pm = tool.getService(ProgramManager.class);
|
||||
pm.closeProgram(program, true);
|
||||
waitForSwing();
|
||||
waitForNotBusy(functionTable);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -96,16 +100,13 @@ public class FunctionWindowPluginTest extends AbstractGhidraHeadedIntegrationTes
|
|||
waitForNotBusy(functionTable);
|
||||
|
||||
assertEquals(numData, functionTable.getRowCount());
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testProgramClose() throws Exception {
|
||||
closeProgram();
|
||||
waitForNotBusy(functionTable);
|
||||
|
||||
assertEquals(functionTable.getRowCount(), 0);
|
||||
loadProgram("notepad");
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -147,7 +148,8 @@ public class FunctionWindowPluginTest extends AbstractGhidraHeadedIntegrationTes
|
|||
String signatureText = getRenderedTableCellValue(functionTable, row, column);
|
||||
|
||||
DockingActionIf copyAction = getAction(tool, ToolConstants.SHARED_OWNER, "Table Data Copy");
|
||||
performAction(copyAction);
|
||||
ActionContext context = new ActionContext(provider, functionTable);
|
||||
performAction(copyAction, context, true);
|
||||
|
||||
//
|
||||
// Note: we cannot make this call:
|
||||
|
|
|
@ -15,8 +15,7 @@
|
|||
*/
|
||||
package ghidra.app.plugin.core.label;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import javax.swing.JComponent;
|
||||
import javax.swing.JTable;
|
||||
|
@ -44,7 +43,8 @@ import ghidra.program.model.symbol.*;
|
|||
import ghidra.program.util.*;
|
||||
import ghidra.test.*;
|
||||
|
||||
public class LabelActionTest extends AbstractGhidraHeadedIntegrationTest implements LocationCallback {
|
||||
public class LabelActionTest extends AbstractGhidraHeadedIntegrationTest
|
||||
implements LocationCallback {
|
||||
private static final String ADD_LABEL = "Add Label";
|
||||
private static final String EDIT_LABEL = "Edit Label";
|
||||
private static final String EDIT_EXTERNAL_LOC = "Edit External Location";
|
||||
|
@ -80,6 +80,8 @@ public class LabelActionTest extends AbstractGhidraHeadedIntegrationTest impleme
|
|||
editExternalLocation = getAction(labelMgrPlugin, EDIT_EXTERNAL_LOC);
|
||||
removeLabel = getAction(labelMgrPlugin, REMOVE_LABEL);
|
||||
setLabel = getAction(labelMgrPlugin, SET_LABEL);
|
||||
|
||||
env.showTool();
|
||||
}
|
||||
|
||||
@After
|
||||
|
@ -128,6 +130,7 @@ public class LabelActionTest extends AbstractGhidraHeadedIntegrationTest impleme
|
|||
|
||||
Object author = model.getValueAt(0, 2);
|
||||
assertTrue(author.toString().startsWith(System.getProperty("user.name")));
|
||||
close(provider);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
|
@ -27,7 +27,6 @@ import java.util.concurrent.TimeUnit;
|
|||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import javax.swing.*;
|
||||
import javax.swing.table.TableModel;
|
||||
|
@ -64,6 +63,7 @@ import ghidra.util.exception.CancelledException;
|
|||
import ghidra.util.table.GhidraTableFilterPanel;
|
||||
import ghidra.util.task.*;
|
||||
import util.CollectionUtils;
|
||||
import utilities.util.FileUtilities;
|
||||
|
||||
public abstract class AbstractGhidraScriptMgrPluginTest
|
||||
extends AbstractGhidraHeadedIntegrationTest {
|
||||
|
@ -170,32 +170,19 @@ public abstract class AbstractGhidraScriptMgrPluginTest
|
|||
deleteFile(testScriptFile);
|
||||
testScriptFile = null;
|
||||
}
|
||||
wipeUserScripts();
|
||||
deleteUserScripts();
|
||||
|
||||
env.dispose();
|
||||
}
|
||||
|
||||
protected static void wipe(ResourceFile path) throws IOException {
|
||||
wipe(Paths.get(path.getAbsolutePath()));
|
||||
protected static void delete(Path path) {
|
||||
FileUtilities.deleteDir(path);
|
||||
}
|
||||
|
||||
protected static void wipe(Path path) throws IOException {
|
||||
if (Files.exists(path)) {
|
||||
try (Stream<Path> walk = Files.walk(path)) {
|
||||
for (Path p : (Iterable<Path>) walk.sorted(Comparator.reverseOrder())::iterator) {
|
||||
Files.deleteIfExists(p);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
protected void deleteUserScripts() throws IOException {
|
||||
|
||||
protected void wipeUserScripts() throws IOException {
|
||||
Path userScriptDir = java.nio.file.Paths.get(GhidraScriptUtil.USER_SCRIPTS_DIR);
|
||||
try (Stream<Path> pathStream = Files.list(userScriptDir)) {
|
||||
for (Path p : (Iterable<Path>) pathStream::iterator) {
|
||||
wipe(p);
|
||||
}
|
||||
}
|
||||
Path userScriptDir = Paths.get(GhidraScriptUtil.USER_SCRIPTS_DIR);
|
||||
FileUtilities.forEachFile(userScriptDir, paths -> paths.forEach(p -> delete(p)));
|
||||
}
|
||||
|
||||
//==================================================================================================
|
||||
|
@ -983,9 +970,9 @@ public abstract class AbstractGhidraScriptMgrPluginTest
|
|||
|
||||
}
|
||||
|
||||
protected void cleanupOldTestFiles() throws IOException {
|
||||
protected void cleanupOldTestFiles() {
|
||||
// remove the compiled bundles directory so that any scripts we use will be recompiled
|
||||
wipe(GhidraSourceBundle.getCompiledBundlesDir());
|
||||
delete(GhidraSourceBundle.getCompiledBundlesDir());
|
||||
|
||||
String myTestName = super.testName.getMethodName();
|
||||
|
||||
|
@ -1559,12 +1546,12 @@ public abstract class AbstractGhidraScriptMgrPluginTest
|
|||
|
||||
@Override
|
||||
public void taskAdded(Task task) {
|
||||
Msg.debug(this, "taskAdded(): " + task.getTaskTitle());
|
||||
Msg.trace(this, "taskAdded(): " + task.getTaskTitle());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void taskRemoved(Task task) {
|
||||
Msg.debug(this, "taskRemoved(): " + task.getTaskTitle());
|
||||
Msg.trace(this, "taskRemoved(): " + task.getTaskTitle());
|
||||
if (taskName.equals(task.getTaskTitle())) {
|
||||
ended = true;
|
||||
}
|
||||
|
@ -1657,13 +1644,13 @@ public abstract class AbstractGhidraScriptMgrPluginTest
|
|||
@Override
|
||||
public void println(String msg) {
|
||||
apiBuffer.append(msg).append('\n');
|
||||
Msg.debug(this, "Spy Script Console - println(): " + msg);
|
||||
Msg.trace(this, "Spy Script Console - println(): " + msg);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addMessage(String originator, String msg) {
|
||||
apiBuffer.append(msg).append('\n');
|
||||
Msg.debug(this, "Spy Script Console - addMessage(): " + msg);
|
||||
Msg.trace(this, "Spy Script Console - addMessage(): " + msg);
|
||||
}
|
||||
|
||||
String getApiOutput() {
|
||||
|
|
|
@ -23,7 +23,6 @@ import java.nio.file.Path;
|
|||
import java.util.*;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import org.junit.*;
|
||||
import org.osgi.framework.Bundle;
|
||||
|
@ -31,27 +30,23 @@ import org.osgi.framework.Bundle;
|
|||
import generic.jar.ResourceFile;
|
||||
import ghidra.app.plugin.core.osgi.*;
|
||||
import ghidra.test.AbstractGhidraHeadlessIntegrationTest;
|
||||
import utilities.util.FileUtilities;
|
||||
|
||||
public class BundleHostTest extends AbstractGhidraHeadlessIntegrationTest {
|
||||
BundleHost bundleHost;
|
||||
CapturingBundleHostListener capturingBundleHostListener;
|
||||
private static final String TEMP_NAME_PREFIX = "sourcebundle";
|
||||
private BundleHost bundleHost;
|
||||
private CapturingBundleHostListener capturingBundleHostListener;
|
||||
|
||||
Set<Path> tempDirs = new HashSet<>();
|
||||
LinkedList<GhidraBundle> bundleStack = new LinkedList<>();
|
||||
GhidraBundle currentBundle;
|
||||
private Set<Path> tempDirs = new HashSet<>();
|
||||
private LinkedList<GhidraBundle> bundleStack = new LinkedList<>();
|
||||
private GhidraBundle currentBundle;
|
||||
|
||||
protected static void wipe(Path path) throws IOException {
|
||||
if (Files.exists(path)) {
|
||||
try (Stream<Path> walk = Files.walk(path)) {
|
||||
for (Path p : (Iterable<Path>) walk.sorted(Comparator.reverseOrder())::iterator) {
|
||||
Files.deleteIfExists(p);
|
||||
}
|
||||
}
|
||||
}
|
||||
private static void wipe(Path path) {
|
||||
FileUtilities.deleteDir(path);
|
||||
}
|
||||
|
||||
protected GhidraBundle pushNewBundle() throws IOException {
|
||||
String dir = String.format("sourcebundle%03d", tempDirs.size());
|
||||
private GhidraBundle pushNewBundle() throws IOException {
|
||||
String dir = String.format(TEMP_NAME_PREFIX + "%03d", tempDirs.size());
|
||||
Path tmpDir = new File(getTestDirectoryPath(), dir).toPath();
|
||||
Files.createDirectories(tmpDir);
|
||||
tempDirs.add(tmpDir);
|
||||
|
@ -62,7 +57,7 @@ public class BundleHostTest extends AbstractGhidraHeadlessIntegrationTest {
|
|||
return currentBundle;
|
||||
}
|
||||
|
||||
static class CapturingBundleHostListener implements BundleHostListener {
|
||||
private static class CapturingBundleHostListener implements BundleHostListener {
|
||||
String lastBuildSummary;
|
||||
|
||||
@Override
|
||||
|
@ -76,6 +71,7 @@ public class BundleHostTest extends AbstractGhidraHeadlessIntegrationTest {
|
|||
@Before
|
||||
public void setup() throws OSGiException, IOException {
|
||||
wipe(GhidraSourceBundle.getCompiledBundlesDir());
|
||||
deleteSimilarTempFiles(TEMP_NAME_PREFIX);
|
||||
|
||||
bundleHost = new BundleHost();
|
||||
bundleHost.startFramework();
|
||||
|
@ -86,7 +82,7 @@ public class BundleHostTest extends AbstractGhidraHeadlessIntegrationTest {
|
|||
}
|
||||
|
||||
@After
|
||||
public void tearDown() throws IOException {
|
||||
public void tearDown() {
|
||||
bundleHost.dispose();
|
||||
capturingBundleHostListener = null;
|
||||
bundleHost = null;
|
||||
|
@ -96,7 +92,7 @@ public class BundleHostTest extends AbstractGhidraHeadlessIntegrationTest {
|
|||
}
|
||||
}
|
||||
|
||||
protected void buildWithExpectations(String expectedCompilerOutput, String expectedSummary)
|
||||
private void buildWithExpectations(String expectedCompilerOutput, String expectedSummary)
|
||||
throws Exception {
|
||||
StringWriter stringWriter = new StringWriter();
|
||||
|
||||
|
@ -110,32 +106,32 @@ public class BundleHostTest extends AbstractGhidraHeadlessIntegrationTest {
|
|||
capturingBundleHostListener.lastBuildSummary);
|
||||
}
|
||||
|
||||
protected void activate() throws Exception {
|
||||
private void activate() throws Exception {
|
||||
Bundle bundle = bundleHost.install(currentBundle);
|
||||
assertNotNull("failed to install bundle", bundle);
|
||||
bundle.start();
|
||||
}
|
||||
|
||||
protected void buildAndActivate() throws Exception {
|
||||
private void buildAndActivate() throws Exception {
|
||||
buildWithExpectations("", "");
|
||||
activate();
|
||||
}
|
||||
|
||||
protected Class<?> loadClass(String classname) throws ClassNotFoundException {
|
||||
private Class<?> loadClass(String classname) throws ClassNotFoundException {
|
||||
Class<?> clazz = currentBundle.getOSGiBundle().loadClass(classname);
|
||||
assertNotNull("failed to load class", clazz);
|
||||
return clazz;
|
||||
}
|
||||
|
||||
protected void addClass(String fullclassname, String body) throws IOException {
|
||||
private void addClass(String fullclassname, String body) throws IOException {
|
||||
addClass("", fullclassname, body);
|
||||
}
|
||||
|
||||
protected void addClass(String imports, String fullclassname, String body) throws IOException {
|
||||
private void addClass(String imports, String fullclassname, String body) throws IOException {
|
||||
addClass("", imports, fullclassname, body);
|
||||
}
|
||||
|
||||
protected void addClass(String meta, String imports, String fullclassname, String body)
|
||||
private void addClass(String meta, String imports, String fullclassname, String body)
|
||||
throws IOException {
|
||||
String simplename;
|
||||
Path tmpsource = currentBundle.getFile().getFile(false).toPath();
|
||||
|
@ -172,7 +168,7 @@ public class BundleHostTest extends AbstractGhidraHeadlessIntegrationTest {
|
|||
|
||||
}
|
||||
|
||||
protected Object getInstance(String classname) throws Exception {
|
||||
private Object getInstance(String classname) throws Exception {
|
||||
Class<?> clazz = loadClass(classname);
|
||||
Object object = clazz.getDeclaredConstructor().newInstance();
|
||||
assertNotNull("failed to create instance", object);
|
||||
|
|
|
@ -65,155 +65,13 @@ public class BundleStatusManagerTest extends AbstractGhidraScriptMgrPluginTest {
|
|||
provider.getBundleHost().removeListener(testBundleHostListener);
|
||||
}
|
||||
|
||||
protected static String translateSeperators(String path) {
|
||||
if (!File.separator.equals("/")) {
|
||||
return path.replace("/", File.separator);
|
||||
}
|
||||
return path;
|
||||
}
|
||||
|
||||
void enableViaGUI(int viewRow) throws InterruptedException {
|
||||
testBundleHostListener.reset();
|
||||
runSwing(() -> {
|
||||
bundleStatusTable.setValueAt(true, viewRow, 0);
|
||||
});
|
||||
waitForSwing();
|
||||
// we wait for the last event, the activation of the bundle.
|
||||
testBundleHostListener.awaitActivation();
|
||||
}
|
||||
|
||||
void disableViaGUI(int viewRow) throws InterruptedException {
|
||||
testBundleHostListener.reset();
|
||||
runSwing(() -> {
|
||||
bundleStatusTable.setValueAt(false, viewRow, 0);
|
||||
});
|
||||
waitForSwing();
|
||||
testBundleHostListener.awaitDisablement();
|
||||
}
|
||||
|
||||
List<BundleStatus> selectRows(int... viewRows) {
|
||||
List<BundleStatus> statuses = Arrays.stream(viewRows)
|
||||
.mapToObj(bundleStatusTableModel::getRowObject)
|
||||
.collect(Collectors.toList());
|
||||
for (BundleStatus status : statuses) {
|
||||
assertNotNull(status);
|
||||
}
|
||||
|
||||
runSwing(() -> {
|
||||
bundleStatusTable.clearSelection();
|
||||
for (int viewRow : viewRows) {
|
||||
bundleStatusTable.addRowSelectionInterval(viewRow, viewRow);
|
||||
}
|
||||
});
|
||||
|
||||
return statuses;
|
||||
}
|
||||
|
||||
void removeViaGUI(int... viewRows) throws InterruptedException {
|
||||
assertTrue("removeViaGUI called with no arguments", viewRows.length > 0);
|
||||
selectRows(viewRows);
|
||||
|
||||
List<BundleStatus> statuses = bundleStatusTableModel.getModelData();
|
||||
int initialSize = statuses.size();
|
||||
|
||||
DockingActionIf removeBundlesAction =
|
||||
getActionByName(bundleStatusProvider, "RemoveBundles");
|
||||
performAction(removeBundlesAction);
|
||||
waitForSwing();
|
||||
|
||||
int count = 0;
|
||||
do {
|
||||
if (statuses.size() <= initialSize - viewRows.length) {
|
||||
break;
|
||||
}
|
||||
Thread.sleep(250);
|
||||
}
|
||||
while (++count < 8);
|
||||
assertTrue("Failure, clean took too long", count < 8);
|
||||
|
||||
}
|
||||
|
||||
void cleanViaGUI(int... viewRows) throws InterruptedException {
|
||||
assertTrue("cleanViaGUI called with no arguments", viewRows.length > 0);
|
||||
|
||||
List<BundleStatus> statuses = selectRows(viewRows);
|
||||
|
||||
List<File> binaryDirs = statuses.stream().map((status) -> {
|
||||
status.setSummary("no summary"); // we use the summary later to test that the bundle's been cleaned
|
||||
GhidraSourceBundle bundle = (GhidraSourceBundle) provider.getBundleHost()
|
||||
.getExistingGhidraBundle(status.getFile());
|
||||
assertNotNull(bundle);
|
||||
File binaryDir = ((Path) getInstanceField("binaryDir", bundle)).toFile();
|
||||
assertTrue("Clean of bundle that doesn't exist", binaryDir.exists());
|
||||
return binaryDir;
|
||||
}).collect(Collectors.toList());
|
||||
|
||||
DockingActionIf cleanBundlesAction = getActionByName(bundleStatusProvider, "CleanBundles");
|
||||
performAction(cleanBundlesAction);
|
||||
waitForSwing();
|
||||
|
||||
// after cleaning, status is cleared, test for a clear status to know we're done cleaning.
|
||||
int count = 0;
|
||||
do {
|
||||
if (statuses.stream().allMatch(status -> status.getSummary().isEmpty())) {
|
||||
break;
|
||||
}
|
||||
Thread.sleep(250);
|
||||
}
|
||||
while (++count < 8);
|
||||
assertTrue("Failure, clean took too long", count < 8);
|
||||
for (File binaryDir : binaryDirs) {
|
||||
assertFalse("Clean of bundle didn't remove directory", binaryDir.exists());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the view row index in the BundleStatusTableModel of the status with the given bundle path, or
|
||||
* -1 if it's not found.
|
||||
*
|
||||
* @param bundlePath bundle path to find
|
||||
* @return view row index or -1 if not found
|
||||
*/
|
||||
protected int getBundleRow(String bundlePath) {
|
||||
AtomicInteger rowref = new AtomicInteger(-1);
|
||||
runSwing(() -> {
|
||||
for (int i = 0; i < bundleStatusTableModel.getRowCount(); i++) {
|
||||
BundleStatus status = bundleStatusTableModel.getRowObject(i);
|
||||
if (bundlePath.equals(status.getPathAsString())) {
|
||||
rowref.set(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
return rowref.get();
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
DockingActionIf getActionByName(ComponentProvider componentProvider, String actionName) {
|
||||
Set<DockingActionIf> actionSet =
|
||||
(Set<DockingActionIf>) getInstanceField("actionSet", bundleStatusProvider);
|
||||
for (DockingActionIf action : actionSet) {
|
||||
if (action.getName().equals(actionName)) {
|
||||
return action;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDisableEnableScriptDirectory() throws Exception {
|
||||
//
|
||||
// Tests that the user can disable then enable a script directory
|
||||
//
|
||||
int viewRow = getBundleRow(BUNDLE_PATH);
|
||||
|
||||
assertTrue(viewRow != -1);
|
||||
|
||||
runSwing(() -> {
|
||||
bundleStatusTable.selectRow(viewRow);
|
||||
bundleStatusTable.scrollToSelectedRow();
|
||||
});
|
||||
waitForSwing();
|
||||
selectRow(viewRow);
|
||||
|
||||
BundleStatus status = bundleStatusTableModel.getRowObject(viewRow);
|
||||
|
||||
|
@ -222,78 +80,22 @@ public class BundleStatusManagerTest extends AbstractGhidraScriptMgrPluginTest {
|
|||
assertTrue(status.isEnabled());
|
||||
assertScriptInTable(scriptFile);
|
||||
|
||||
// disable it
|
||||
disableViaGUI(viewRow);
|
||||
assertTrue(!status.isEnabled());
|
||||
assertScriptNotInTable(scriptFile);
|
||||
|
||||
// re-enable it
|
||||
enableViaGUI(viewRow);
|
||||
assertTrue(status.isEnabled());
|
||||
assertScriptInTable(scriptFile);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a list of bundles with the addBundles dialogue.
|
||||
*
|
||||
* <p>All bundles should reside in a common directory.
|
||||
*
|
||||
* @param bundleFiles the bundle files
|
||||
* @throws Exception if waitForUpdateOnChooser fails
|
||||
*/
|
||||
void addBundlesViaGUI(File... bundleFiles) throws Exception {
|
||||
assertTrue("addBundlesViaGUI called with no arguments", bundleFiles.length > 0);
|
||||
|
||||
DockingActionIf addBundlesAction = getActionByName(bundleStatusProvider, "AddBundles");
|
||||
performAction(addBundlesAction, false);
|
||||
waitForSwing();
|
||||
|
||||
List<File> files = List.of(bundleFiles);
|
||||
|
||||
GhidraFileChooser chooser = waitForDialogComponent(GhidraFileChooser.class);
|
||||
assertNotNull(chooser);
|
||||
|
||||
runSwing(() -> {
|
||||
chooser.setCurrentDirectory(bundleFiles[0]);
|
||||
}, true);
|
||||
waitForUpdateOnChooser(chooser);
|
||||
|
||||
runSwing(() -> {
|
||||
// there is no setFiles method of GhidraFileChooser
|
||||
Object selectedFiles = getInstanceField("selectedFiles", chooser);
|
||||
invokeInstanceMethod("setFiles", selectedFiles, new Class[] { List.class },
|
||||
new Object[] { files });
|
||||
Object validatedFiles = getInstanceField("validatedFiles", chooser);
|
||||
invokeInstanceMethod("setFiles", validatedFiles, new Class[] { List.class },
|
||||
new Object[] { files });
|
||||
});
|
||||
waitForUpdateOnChooser(chooser);
|
||||
testBundleHostListener.reset(bundleFiles.length);
|
||||
pressButtonByText(chooser, "OK");
|
||||
waitForSwing();
|
||||
testBundleHostListener.awaitActivation();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String runScript(String scriptName) throws Exception {
|
||||
env.getTool().showComponentProvider(provider, true);
|
||||
selectScript(scriptName);
|
||||
String output = super.runScript(scriptName);
|
||||
env.getTool().showComponentProvider(bundleStatusProvider, true);
|
||||
return output;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRunCleanRun() throws Exception {
|
||||
|
||||
int viewRow = getBundleRow(BUNDLE_PATH);
|
||||
assertNotEquals(viewRow, -1);
|
||||
|
||||
assertTrue(viewRow != -1);
|
||||
|
||||
runSwing(() -> {
|
||||
bundleStatusTable.selectRow(viewRow);
|
||||
bundleStatusTable.scrollToSelectedRow();
|
||||
});
|
||||
waitForSwing();
|
||||
selectRows(viewRow);
|
||||
|
||||
BundleStatus status = bundleStatusTableModel.getRowObject(viewRow);
|
||||
|
||||
|
@ -302,18 +104,15 @@ public class BundleStatusManagerTest extends AbstractGhidraScriptMgrPluginTest {
|
|||
assertTrue(status.isEnabled());
|
||||
assertScriptInTable(scriptFile);
|
||||
|
||||
// run
|
||||
runScript(SCRIPT_NAME);
|
||||
|
||||
// clean
|
||||
cleanViaGUI(viewRow);
|
||||
|
||||
// run
|
||||
runScript(SCRIPT_NAME);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void addRunCleanRemoveTwoBundles() throws Exception {
|
||||
public void testAddRunCleanRemoveTwoBundles() throws Exception {
|
||||
final String TEST_SCRIPT_NAME = testName.getMethodName();
|
||||
|
||||
//@formatter:off
|
||||
|
@ -385,30 +184,227 @@ public class BundleStatusManagerTest extends AbstractGhidraScriptMgrPluginTest {
|
|||
String output = runScript(TEST_SCRIPT_NAME + ".java");
|
||||
assertEquals(EXPECTED_OUTPUT, output);
|
||||
|
||||
int row1 = getBundleRow(generic.util.Path.toPathString(new ResourceFile(dir1)));
|
||||
int row2 = getBundleRow(generic.util.Path.toPathString(new ResourceFile(dir2)));
|
||||
assertFalse(row1 == -1);
|
||||
assertFalse(row2 == -1);
|
||||
int row1 = getBundleRow(dir1);
|
||||
int row2 = getBundleRow(dir2);
|
||||
assertNotEquals(row1, -1);
|
||||
assertNotEquals(row2, -1);
|
||||
|
||||
cleanViaGUI(row1, row2);
|
||||
|
||||
|
||||
removeViaGUI(row1, row2);
|
||||
|
||||
row1 = getBundleRow(generic.util.Path.toPathString(new ResourceFile(dir1)));
|
||||
row2 = getBundleRow(generic.util.Path.toPathString(new ResourceFile(dir2)));
|
||||
assertTrue(row1 == -1);
|
||||
assertTrue(row2 == -1);
|
||||
row1 = getBundleRow(dir1);
|
||||
row2 = getBundleRow(dir2);
|
||||
assertEquals(row1, -1);
|
||||
assertEquals(row2, -1);
|
||||
}
|
||||
finally {
|
||||
wipe(dir1.toPath());
|
||||
wipe(dir2.toPath());
|
||||
delete(dir1.toPath());
|
||||
delete(dir2.toPath());
|
||||
}
|
||||
}
|
||||
|
||||
private static String translateSeperators(String path) {
|
||||
if (!File.separator.equals("/")) {
|
||||
return path.replace("/", File.separator);
|
||||
}
|
||||
return path;
|
||||
}
|
||||
|
||||
private void enableViaGUI(int viewRow) throws InterruptedException {
|
||||
testBundleHostListener.reset();
|
||||
runSwing(() -> {
|
||||
bundleStatusTable.setValueAt(true, viewRow, 0);
|
||||
});
|
||||
waitForSwing();
|
||||
// we wait for the last event, the activation of the bundle.
|
||||
testBundleHostListener.awaitActivation();
|
||||
}
|
||||
|
||||
private void disableViaGUI(int viewRow) throws InterruptedException {
|
||||
testBundleHostListener.reset();
|
||||
runSwing(() -> {
|
||||
bundleStatusTable.setValueAt(false, viewRow, 0);
|
||||
});
|
||||
waitForSwing();
|
||||
testBundleHostListener.awaitDisablement();
|
||||
}
|
||||
|
||||
private void selectRow(int viewRow) {
|
||||
assertNotEquals(viewRow, -1);
|
||||
runSwing(() -> {
|
||||
bundleStatusTable.selectRow(viewRow);
|
||||
bundleStatusTable.scrollToSelectedRow();
|
||||
});
|
||||
waitForSwing();
|
||||
}
|
||||
|
||||
private List<BundleStatus> selectRows(int... viewRows) {
|
||||
List<BundleStatus> statuses = Arrays.stream(viewRows)
|
||||
.mapToObj(bundleStatusTableModel::getRowObject)
|
||||
.collect(Collectors.toList());
|
||||
for (BundleStatus status : statuses) {
|
||||
assertNotNull(status);
|
||||
}
|
||||
|
||||
runSwing(() -> {
|
||||
bundleStatusTable.clearSelection();
|
||||
for (int viewRow : viewRows) {
|
||||
bundleStatusTable.addRowSelectionInterval(viewRow, viewRow);
|
||||
}
|
||||
});
|
||||
|
||||
return statuses;
|
||||
}
|
||||
|
||||
private void removeViaGUI(int... viewRows) throws InterruptedException {
|
||||
assertTrue("removeViaGUI called with no arguments", viewRows.length > 0);
|
||||
selectRows(viewRows);
|
||||
|
||||
List<BundleStatus> statuses = bundleStatusTableModel.getModelData();
|
||||
int initialSize = statuses.size();
|
||||
|
||||
DockingActionIf removeBundlesAction =
|
||||
getActionByName(bundleStatusProvider, "RemoveBundles");
|
||||
performAction(removeBundlesAction);
|
||||
waitForSwing();
|
||||
|
||||
int count = 0;
|
||||
do {
|
||||
if (statuses.size() <= initialSize - viewRows.length) {
|
||||
break;
|
||||
}
|
||||
Thread.sleep(250);
|
||||
}
|
||||
while (++count < 8);
|
||||
assertTrue("Failure, clean took too long", count < 8);
|
||||
|
||||
}
|
||||
|
||||
private void cleanViaGUI(int... viewRows) throws InterruptedException {
|
||||
assertTrue("cleanViaGUI called with no arguments", viewRows.length > 0);
|
||||
|
||||
List<BundleStatus> statuses = selectRows(viewRows);
|
||||
|
||||
List<File> binaryDirs = statuses.stream().map((status) -> {
|
||||
status.setSummary("no summary"); // we use the summary later to test that the bundle's been cleaned
|
||||
GhidraSourceBundle bundle = (GhidraSourceBundle) provider.getBundleHost()
|
||||
.getExistingGhidraBundle(status.getFile());
|
||||
assertNotNull(bundle);
|
||||
File binaryDir = ((Path) getInstanceField("binaryDir", bundle)).toFile();
|
||||
assertTrue("Clean of bundle that doesn't exist", binaryDir.exists());
|
||||
return binaryDir;
|
||||
}).collect(Collectors.toList());
|
||||
|
||||
DockingActionIf cleanBundlesAction = getActionByName(bundleStatusProvider, "CleanBundles");
|
||||
performAction(cleanBundlesAction);
|
||||
waitForSwing();
|
||||
|
||||
// after cleaning, status is cleared, test for a clear status to know we're done cleaning.
|
||||
int count = 0;
|
||||
do {
|
||||
if (statuses.stream().allMatch(status -> status.getSummary().isEmpty())) {
|
||||
break;
|
||||
}
|
||||
Thread.sleep(250);
|
||||
}
|
||||
while (++count < 8);
|
||||
assertTrue("Failure, clean took too long", count < 8);
|
||||
for (File binaryDir : binaryDirs) {
|
||||
assertFalse("Clean of bundle didn't remove directory", binaryDir.exists());
|
||||
}
|
||||
}
|
||||
|
||||
private int getBundleRow(File dir) {
|
||||
return getBundleRow(generic.util.Path.toPathString(new ResourceFile(dir)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the view row index in the BundleStatusTableModel of the status with the given bundle path, or
|
||||
* -1 if it's not found.
|
||||
*
|
||||
* @param bundlePath bundle path to find
|
||||
* @return view row index or -1 if not found
|
||||
*/
|
||||
private int getBundleRow(String bundlePath) {
|
||||
AtomicInteger rowref = new AtomicInteger(-1);
|
||||
runSwing(() -> {
|
||||
for (int i = 0; i < bundleStatusTableModel.getRowCount(); i++) {
|
||||
BundleStatus status = bundleStatusTableModel.getRowObject(i);
|
||||
if (bundlePath.equals(status.getPathAsString())) {
|
||||
rowref.set(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
return rowref.get();
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private DockingActionIf getActionByName(ComponentProvider componentProvider,
|
||||
String actionName) {
|
||||
Set<DockingActionIf> actionSet =
|
||||
(Set<DockingActionIf>) getInstanceField("actionSet", bundleStatusProvider);
|
||||
for (DockingActionIf action : actionSet) {
|
||||
if (action.getName().equals(actionName)) {
|
||||
return action;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a list of bundles with the addBundles dialogue.
|
||||
*
|
||||
* <p>All bundles should reside in a common directory.
|
||||
*
|
||||
* @param bundleFiles the bundle files
|
||||
* @throws Exception if waitForUpdateOnChooser fails
|
||||
*/
|
||||
private void addBundlesViaGUI(File... bundleFiles) throws Exception {
|
||||
assertTrue("addBundlesViaGUI called with no arguments", bundleFiles.length > 0);
|
||||
|
||||
DockingActionIf addBundlesAction = getActionByName(bundleStatusProvider, "AddBundles");
|
||||
performAction(addBundlesAction, false);
|
||||
waitForSwing();
|
||||
|
||||
List<File> files = List.of(bundleFiles);
|
||||
|
||||
GhidraFileChooser chooser = waitForDialogComponent(GhidraFileChooser.class);
|
||||
assertNotNull(chooser);
|
||||
|
||||
runSwing(() -> chooser.setCurrentDirectory(bundleFiles[0]));
|
||||
waitForUpdateOnChooser(chooser);
|
||||
|
||||
runSwing(() -> {
|
||||
// there is no setFiles method of GhidraFileChooser
|
||||
Object selectedFiles = getInstanceField("selectedFiles", chooser);
|
||||
invokeInstanceMethod("setFiles", selectedFiles, new Class[] { List.class },
|
||||
new Object[] { files });
|
||||
Object validatedFiles = getInstanceField("validatedFiles", chooser);
|
||||
invokeInstanceMethod("setFiles", validatedFiles, new Class[] { List.class },
|
||||
new Object[] { files });
|
||||
});
|
||||
waitForUpdateOnChooser(chooser);
|
||||
testBundleHostListener.reset(bundleFiles.length);
|
||||
pressButtonByText(chooser, "OK");
|
||||
waitForSwing();
|
||||
testBundleHostListener.awaitActivation();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String runScript(String scriptName) throws Exception {
|
||||
env.getTool().showComponentProvider(provider, true);
|
||||
selectScript(scriptName);
|
||||
String output = super.runScript(scriptName);
|
||||
env.getTool().showComponentProvider(bundleStatusProvider, true);
|
||||
return output;
|
||||
}
|
||||
|
||||
/**
|
||||
* A {@link BundleHostListener} to help serialize bundle operations.
|
||||
*/
|
||||
protected class TestBundleHostListener implements BundleHostListener {
|
||||
private class TestBundleHostListener implements BundleHostListener {
|
||||
CountDownLatch activationLatch;
|
||||
CountDownLatch disablementLatch;
|
||||
|
||||
|
|
|
@ -631,6 +631,7 @@ public class SearchTextPlugin2Test extends AbstractGhidraHeadedIntegrationTest {
|
|||
waitForSearchTasks(tempDialog);
|
||||
waitForSwing();
|
||||
assertFalse(tempDialog.isVisible());
|
||||
|
||||
assertFalse(isEnabled(searchAction));
|
||||
}
|
||||
|
||||
|
|
|
@ -112,6 +112,8 @@ public class KeyBindingUtilsTest extends AbstractGhidraHeadedIntegrationTest {
|
|||
tool.addPlugin(DataPlugin.class.getName());
|
||||
tool.addPlugin(FunctionPlugin.class.getName());
|
||||
|
||||
env.showTool();
|
||||
|
||||
debug("two");
|
||||
}
|
||||
|
||||
|
|
|
@ -15,8 +15,7 @@
|
|||
*/
|
||||
package ghidra.program.database.map;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import java.util.Iterator;
|
||||
|
||||
|
@ -67,7 +66,7 @@ public class NormalizedAddressSetTest extends AbstractGhidraHeadedIntegrationTes
|
|||
}
|
||||
|
||||
@Test
|
||||
public void testAdd() {
|
||||
public void testAdd() {
|
||||
set.addRange(addr(0), addr(10));
|
||||
AddressSet addrSet = set.intersect(new AddressSet(addr(5), addr(15)));
|
||||
assertEquals(6, addrSet.getNumAddresses());
|
||||
|
@ -76,14 +75,14 @@ public class NormalizedAddressSetTest extends AbstractGhidraHeadedIntegrationTes
|
|||
}
|
||||
|
||||
@Test
|
||||
public void testAddBig() {
|
||||
public void testAddBig() {
|
||||
set.addRange(addr(0xfffffff0l), addr(0xffffffffl));
|
||||
assertEquals(addr(0xfffffff0l), set.getMinAddress());
|
||||
assertEquals(addr(0xffffffffl), set.getMaxAddress());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUnionNonOverlap() {
|
||||
public void testUnionNonOverlap() {
|
||||
set.addRange(addr(0), addr(0));
|
||||
set.addRange(addr(5), addr(5));
|
||||
set.addRange(addr(0xffffffffL), addr(0xffffffffL));
|
||||
|
@ -106,7 +105,7 @@ public class NormalizedAddressSetTest extends AbstractGhidraHeadedIntegrationTes
|
|||
}
|
||||
|
||||
@Test
|
||||
public void testUnionWithOverlap() {
|
||||
public void testUnionWithOverlap() {
|
||||
set.addRange(addr(0), addr(22));
|
||||
set.addRange(addr(42), addr(75));
|
||||
set.addRange(addr(0xfffffe10L), addr(0xfffffe20L));
|
||||
|
@ -129,7 +128,7 @@ public class NormalizedAddressSetTest extends AbstractGhidraHeadedIntegrationTes
|
|||
}
|
||||
|
||||
@Test
|
||||
public void testUnionPosFirst() {
|
||||
public void testUnionPosFirst() {
|
||||
set.addRange(addr(0), addr(0));
|
||||
set.addRange(addr(5), addr(5));
|
||||
set.addRange(addr(40), addr(45));
|
||||
|
@ -152,7 +151,7 @@ public class NormalizedAddressSetTest extends AbstractGhidraHeadedIntegrationTes
|
|||
}
|
||||
|
||||
@Test
|
||||
public void testUnionNegFirst() {
|
||||
public void testUnionNegFirst() {
|
||||
set.addRange(addr(0xffffffffL), addr(0xffffffffL));
|
||||
set.addRange(addr(0xfffffe0cL), addr(0xfffffe70L));
|
||||
set.addRange(addr(0xffffffecL), addr(0xfffffffdL));
|
||||
|
@ -185,7 +184,7 @@ public class NormalizedAddressSetTest extends AbstractGhidraHeadedIntegrationTes
|
|||
}
|
||||
|
||||
@Test
|
||||
public void testIntersectNonOverlap() {
|
||||
public void testIntersectNonOverlap() {
|
||||
set.addRange(addr(0), addr(0));
|
||||
set.addRange(addr(5), addr(5));
|
||||
set.addRange(addr(0xffffffffL), addr(0xffffffffL));
|
||||
|
@ -204,7 +203,7 @@ public class NormalizedAddressSetTest extends AbstractGhidraHeadedIntegrationTes
|
|||
}
|
||||
|
||||
@Test
|
||||
public void testIntersectWithOverlap() {
|
||||
public void testIntersectWithOverlap() {
|
||||
set.addRange(addr(0), addr(22));
|
||||
set.addRange(addr(42), addr(75));
|
||||
set.addRange(addr(0xfffffe10L), addr(0xfffffe20L));
|
||||
|
@ -239,7 +238,7 @@ public class NormalizedAddressSetTest extends AbstractGhidraHeadedIntegrationTes
|
|||
}
|
||||
|
||||
@Test
|
||||
public void testDelete() {
|
||||
public void testDelete() {
|
||||
set.addRange(addr(0), addr(22));
|
||||
set.addRange(addr(42), addr(75));
|
||||
set.addRange(addr(0xfffffe10L), addr(0xfffffe20L));
|
||||
|
@ -261,7 +260,7 @@ public class NormalizedAddressSetTest extends AbstractGhidraHeadedIntegrationTes
|
|||
}
|
||||
|
||||
@Test
|
||||
public void testSubtract() {
|
||||
public void testSubtract() {
|
||||
set.addRange(addr(0), addr(22));
|
||||
set.addRange(addr(42), addr(75));
|
||||
set.addRange(addr(0xfffffe10L), addr(0xfffffe20L));
|
||||
|
@ -283,7 +282,7 @@ public class NormalizedAddressSetTest extends AbstractGhidraHeadedIntegrationTes
|
|||
}
|
||||
|
||||
@Test
|
||||
public void testXor() {
|
||||
public void testXor() {
|
||||
set.addRange(addr(0), addr(22));
|
||||
set.addRange(addr(42), addr(75));
|
||||
set.addRange(addr(0xfffffe10L), addr(0xfffffe20L));
|
||||
|
@ -308,7 +307,7 @@ public class NormalizedAddressSetTest extends AbstractGhidraHeadedIntegrationTes
|
|||
}
|
||||
|
||||
@Test
|
||||
public void testContains() {
|
||||
public void testContains() {
|
||||
set.addRange(addr(0), addr(22));
|
||||
set.addRange(addr(42), addr(75));
|
||||
set.addRange(addr(0xfffffe10L), addr(0xfffffe20L));
|
||||
|
@ -348,7 +347,7 @@ public class NormalizedAddressSetTest extends AbstractGhidraHeadedIntegrationTes
|
|||
}
|
||||
|
||||
@Test
|
||||
public void testContains2() {
|
||||
public void testContains2() {
|
||||
set.addRange(addr(0), addr(0xffffffffL));
|
||||
|
||||
assertEquals(true, set.contains(addr(0)));
|
||||
|
@ -384,7 +383,7 @@ public class NormalizedAddressSetTest extends AbstractGhidraHeadedIntegrationTes
|
|||
}
|
||||
|
||||
@Test
|
||||
public void testForwardIterator() {
|
||||
public void testForwardIterator() {
|
||||
set.addRange(addr(0), addr(22));
|
||||
set.addRange(addr(42), addr(75));
|
||||
set.addRange(addr(0xfffffe10L), addr(0xfffffe20L));
|
||||
|
@ -418,7 +417,7 @@ public class NormalizedAddressSetTest extends AbstractGhidraHeadedIntegrationTes
|
|||
}
|
||||
|
||||
@Test
|
||||
public void testBackwardIterator() {
|
||||
public void testBackwardIterator() {
|
||||
set.addRange(addr(0), addr(22));
|
||||
set.addRange(addr(42), addr(75));
|
||||
set.addRange(addr(0xfffffe10L), addr(0xfffffe20L));
|
||||
|
@ -429,7 +428,7 @@ public class NormalizedAddressSetTest extends AbstractGhidraHeadedIntegrationTes
|
|||
AddressIterator iter = set.getAddresses(false);
|
||||
while (iter.hasNext()) {
|
||||
Address addr = iter.next();
|
||||
System.out.println(addr.toString(true));
|
||||
|
||||
assertEquals(checkAddress, addr);
|
||||
if (checkAddress.equals(addr(0xffffffccL))) {
|
||||
checkAddress = addr(0xffffffbbL);
|
||||
|
|
|
@ -15,8 +15,7 @@
|
|||
*/
|
||||
package ghidra.program.database.util;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Iterator;
|
||||
|
@ -30,10 +29,12 @@ import ghidra.util.datastruct.IndexRange;
|
|||
import ghidra.util.datastruct.IndexRangeIterator;
|
||||
|
||||
@SuppressWarnings("deprecation") // the SharedRangeMapDB is deprecated, but we still need to test it
|
||||
public class SharedRangeMapDBTest extends AbstractGhidraHeadedIntegrationTest implements ErrorHandler {
|
||||
public class SharedRangeMapDBTest extends AbstractGhidraHeadedIntegrationTest
|
||||
implements ErrorHandler {
|
||||
|
||||
private DBHandle dbh;
|
||||
private long transactionID;
|
||||
|
||||
/**
|
||||
* Constructor for SharedRangeMapDBTest.
|
||||
* @param arg0
|
||||
|
@ -45,9 +46,9 @@ public class SharedRangeMapDBTest extends AbstractGhidraHeadedIntegrationTest im
|
|||
/*
|
||||
* @see TestCase#setUp()
|
||||
*/
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
|
||||
dbh = new DBHandle();
|
||||
transactionID = dbh.startTransaction();
|
||||
}
|
||||
|
@ -55,28 +56,30 @@ public class SharedRangeMapDBTest extends AbstractGhidraHeadedIntegrationTest im
|
|||
/*
|
||||
* @see TestCase#tearDown()
|
||||
*/
|
||||
@After
|
||||
public void tearDown() throws Exception {
|
||||
@After
|
||||
public void tearDown() throws Exception {
|
||||
dbh.endTransaction(transactionID, false);
|
||||
dbh.close();
|
||||
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @see db.util.ErrorHandler#dbError(java.io.IOException)
|
||||
*/
|
||||
@Override
|
||||
public void dbError(IOException e) {
|
||||
throw new RuntimeException(e.getMessage());
|
||||
}
|
||||
|
||||
|
||||
private int indexOf(Object[] list, Object item) {
|
||||
for (int i = 0; i < list.length; i++) {
|
||||
if (list[i].equals(item))
|
||||
if (list[i].equals(item)) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Crude inspection - assumes two records will not contain the same
|
||||
* content.
|
||||
|
@ -85,76 +88,79 @@ public class SharedRangeMapDBTest extends AbstractGhidraHeadedIntegrationTest im
|
|||
* @param mapRangeToValue (from is rangeKey, to is value)
|
||||
* @throws IOException
|
||||
*/
|
||||
private void inspectRecords(SharedRangeMapDB map, IndexRange[] ranges, IndexRange[] mapRangeToValue) throws IOException {
|
||||
System.out.println("Inspecting---");
|
||||
private void inspectRecords(SharedRangeMapDB map, IndexRange[] ranges,
|
||||
IndexRange[] mapRangeToValue) throws IOException {
|
||||
|
||||
RecordIterator iter = map.rangeTable.iterator();
|
||||
int cnt = 0;
|
||||
while (iter.hasNext()) {
|
||||
++cnt;
|
||||
Record rec = iter.next();
|
||||
IndexRange range = new IndexRange(rec.getKey(), rec.getLongValue(SharedRangeMapDB.RANGE_TO_COL));
|
||||
if (indexOf(ranges, range) < 0)
|
||||
IndexRange range =
|
||||
new IndexRange(rec.getKey(), rec.getLongValue(SharedRangeMapDB.RANGE_TO_COL));
|
||||
if (indexOf(ranges, range) < 0) {
|
||||
Assert.fail("Unexpected range: " + range.getStart() + " - " + range.getEnd());
|
||||
System.out.println(" Range: " + range.getStart() + " - " + range.getEnd());
|
||||
}
|
||||
}
|
||||
assertEquals(ranges.length, cnt);
|
||||
|
||||
|
||||
iter = map.mapTable.iterator();
|
||||
cnt = 0;
|
||||
while (iter.hasNext()) {
|
||||
++cnt;
|
||||
Record rec = iter.next();
|
||||
IndexRange entry = new IndexRange(rec.getLongValue(SharedRangeMapDB.MAP_RANGE_KEY_COL),
|
||||
rec.getLongValue(SharedRangeMapDB.MAP_VALUE_COL));
|
||||
if (indexOf(mapRangeToValue, entry) < 0)
|
||||
Assert.fail("Unexpected map entry: rangeKey=" + entry.getStart() + ", value=" + entry.getEnd());
|
||||
System.out.println(" Map entry: rangeKey=" + entry.getStart() + ", value=" + entry.getEnd());
|
||||
rec.getLongValue(SharedRangeMapDB.MAP_VALUE_COL));
|
||||
if (indexOf(mapRangeToValue, entry) < 0) {
|
||||
Assert.fail("Unexpected map entry: rangeKey=" + entry.getStart() + ", value=" +
|
||||
entry.getEnd());
|
||||
}
|
||||
}
|
||||
assertEquals(mapRangeToValue.length, cnt);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAdd() throws IOException {
|
||||
|
||||
@Test
|
||||
public void testAdd() throws IOException {
|
||||
SharedRangeMapDB map = new SharedRangeMapDB(dbh, "TEST", this, true);
|
||||
|
||||
|
||||
// Add initial set of ranges
|
||||
map.add(10, 20, 1);
|
||||
map.add(30, 40, 1);
|
||||
map.add(50, 60, 1);
|
||||
map.add(70, 80, 1);
|
||||
|
||||
|
||||
IndexRange[] ranges = new IndexRange[] {
|
||||
new IndexRange(10,20),
|
||||
new IndexRange(30,40),
|
||||
new IndexRange(50,60),
|
||||
new IndexRange(70,80)
|
||||
new IndexRange(10, 20),
|
||||
new IndexRange(30, 40),
|
||||
new IndexRange(50, 60),
|
||||
new IndexRange(70, 80)
|
||||
};
|
||||
|
||||
|
||||
IndexRange[] entries = new IndexRange[] {
|
||||
new IndexRange(10, 1),
|
||||
new IndexRange(30, 1),
|
||||
new IndexRange(50, 1),
|
||||
new IndexRange(70, 1)
|
||||
};
|
||||
|
||||
|
||||
inspectRecords(map, ranges, entries);
|
||||
|
||||
|
||||
// Range already included
|
||||
map.add(52, 58, 1);
|
||||
map.add(52, 60, 1);
|
||||
map.add(50, 60, 1);
|
||||
|
||||
|
||||
inspectRecords(map, ranges, entries);
|
||||
|
||||
// Add range
|
||||
map.add(21, 29, 1);
|
||||
|
||||
|
||||
ranges = new IndexRange[] {
|
||||
new IndexRange(10,40),
|
||||
new IndexRange(50,60),
|
||||
new IndexRange(70,80)
|
||||
new IndexRange(10, 40),
|
||||
new IndexRange(50, 60),
|
||||
new IndexRange(70, 80)
|
||||
};
|
||||
|
||||
|
||||
entries = new IndexRange[] {
|
||||
new IndexRange(10, 1),
|
||||
new IndexRange(50, 1),
|
||||
|
@ -162,44 +168,44 @@ System.out.println(" Map entry: rangeKey=" + entry.getStart() + ", value=" + en
|
|||
};
|
||||
|
||||
inspectRecords(map, ranges, entries);
|
||||
|
||||
|
||||
// Add range
|
||||
map.add(35, 55, 1);
|
||||
|
||||
|
||||
ranges = new IndexRange[] {
|
||||
new IndexRange(10,60),
|
||||
new IndexRange(70,80)
|
||||
new IndexRange(10, 60),
|
||||
new IndexRange(70, 80)
|
||||
};
|
||||
|
||||
|
||||
entries = new IndexRange[] {
|
||||
new IndexRange(10, 1),
|
||||
new IndexRange(70, 1)
|
||||
};
|
||||
|
||||
inspectRecords(map, ranges, entries);
|
||||
|
||||
|
||||
// Add range
|
||||
map.add(55, 90, 1);
|
||||
|
||||
|
||||
ranges = new IndexRange[] {
|
||||
new IndexRange(10,90)
|
||||
new IndexRange(10, 90)
|
||||
};
|
||||
|
||||
|
||||
entries = new IndexRange[] {
|
||||
new IndexRange(10, 1)
|
||||
};
|
||||
|
||||
inspectRecords(map, ranges, entries);
|
||||
|
||||
|
||||
// Add second overlapped value
|
||||
map.add(20, 30, 2);
|
||||
|
||||
|
||||
ranges = new IndexRange[] {
|
||||
new IndexRange(10, 19),
|
||||
new IndexRange(20, 30),
|
||||
new IndexRange(31, 90)
|
||||
};
|
||||
|
||||
|
||||
entries = new IndexRange[] {
|
||||
new IndexRange(10, 1),
|
||||
new IndexRange(20, 1),
|
||||
|
@ -211,7 +217,7 @@ System.out.println(" Map entry: rangeKey=" + entry.getStart() + ", value=" + en
|
|||
|
||||
// Add third overlapped value
|
||||
map.add(28, 35, 3);
|
||||
|
||||
|
||||
ranges = new IndexRange[] {
|
||||
new IndexRange(10, 19),
|
||||
new IndexRange(20, 27),
|
||||
|
@ -219,7 +225,7 @@ System.out.println(" Map entry: rangeKey=" + entry.getStart() + ", value=" + en
|
|||
new IndexRange(31, 35),
|
||||
new IndexRange(36, 90)
|
||||
};
|
||||
|
||||
|
||||
entries = new IndexRange[] {
|
||||
new IndexRange(10, 1),
|
||||
new IndexRange(20, 1),
|
||||
|
@ -233,10 +239,10 @@ System.out.println(" Map entry: rangeKey=" + entry.getStart() + ", value=" + en
|
|||
};
|
||||
|
||||
inspectRecords(map, ranges, entries);
|
||||
|
||||
|
||||
// Add fourth overlapped value
|
||||
map.add(28, 35, 4);
|
||||
|
||||
|
||||
ranges = new IndexRange[] {
|
||||
new IndexRange(10, 19),
|
||||
new IndexRange(20, 27),
|
||||
|
@ -244,7 +250,7 @@ System.out.println(" Map entry: rangeKey=" + entry.getStart() + ", value=" + en
|
|||
new IndexRange(31, 35),
|
||||
new IndexRange(36, 90)
|
||||
};
|
||||
|
||||
|
||||
entries = new IndexRange[] {
|
||||
new IndexRange(10, 1),
|
||||
new IndexRange(20, 1),
|
||||
|
@ -260,10 +266,10 @@ System.out.println(" Map entry: rangeKey=" + entry.getStart() + ", value=" + en
|
|||
};
|
||||
|
||||
inspectRecords(map, ranges, entries);
|
||||
|
||||
|
||||
// Expand fourth overlapped value range
|
||||
map.add(25, 39, 4);
|
||||
|
||||
|
||||
ranges = new IndexRange[] {
|
||||
new IndexRange(10, 19),
|
||||
new IndexRange(20, 24),
|
||||
|
@ -273,7 +279,7 @@ System.out.println(" Map entry: rangeKey=" + entry.getStart() + ", value=" + en
|
|||
new IndexRange(36, 39),
|
||||
new IndexRange(40, 90)
|
||||
};
|
||||
|
||||
|
||||
entries = new IndexRange[] {
|
||||
new IndexRange(10, 1),
|
||||
new IndexRange(20, 1),
|
||||
|
@ -296,10 +302,10 @@ System.out.println(" Map entry: rangeKey=" + entry.getStart() + ", value=" + en
|
|||
inspectRecords(map, ranges, entries);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRemove() throws IOException {
|
||||
@Test
|
||||
public void testRemove() throws IOException {
|
||||
SharedRangeMapDB map = new SharedRangeMapDB(dbh, "TEST", this, true);
|
||||
|
||||
|
||||
// Add same entries as the testAdd used
|
||||
map.add(10, 20, 1);
|
||||
map.add(30, 40, 1);
|
||||
|
@ -307,20 +313,20 @@ System.out.println(" Map entry: rangeKey=" + entry.getStart() + ", value=" + en
|
|||
map.add(70, 80, 1);
|
||||
|
||||
map.add(21, 29, 1);
|
||||
|
||||
|
||||
map.add(35, 55, 1);
|
||||
|
||||
|
||||
map.add(55, 90, 1);
|
||||
|
||||
|
||||
map.add(20, 30, 2);
|
||||
|
||||
|
||||
map.add(28, 35, 3);
|
||||
|
||||
|
||||
map.add(28, 35, 4);
|
||||
|
||||
|
||||
// Remove
|
||||
map.remove(4);
|
||||
|
||||
|
||||
IndexRange[] ranges = new IndexRange[] {
|
||||
new IndexRange(10, 19),
|
||||
new IndexRange(20, 27),
|
||||
|
@ -328,7 +334,7 @@ System.out.println(" Map entry: rangeKey=" + entry.getStart() + ", value=" + en
|
|||
new IndexRange(31, 35),
|
||||
new IndexRange(36, 90)
|
||||
};
|
||||
|
||||
|
||||
IndexRange[] entries = new IndexRange[] {
|
||||
new IndexRange(10, 1),
|
||||
new IndexRange(20, 1),
|
||||
|
@ -342,16 +348,16 @@ System.out.println(" Map entry: rangeKey=" + entry.getStart() + ", value=" + en
|
|||
};
|
||||
|
||||
inspectRecords(map, ranges, entries);
|
||||
|
||||
|
||||
// Remove
|
||||
map.remove(3);
|
||||
|
||||
|
||||
ranges = new IndexRange[] {
|
||||
new IndexRange(10, 19),
|
||||
new IndexRange(20, 30),
|
||||
new IndexRange(31, 90)
|
||||
};
|
||||
|
||||
|
||||
entries = new IndexRange[] {
|
||||
new IndexRange(10, 1),
|
||||
new IndexRange(20, 1),
|
||||
|
@ -360,31 +366,31 @@ System.out.println(" Map entry: rangeKey=" + entry.getStart() + ", value=" + en
|
|||
};
|
||||
|
||||
inspectRecords(map, ranges, entries);
|
||||
|
||||
|
||||
// Remove
|
||||
map.remove(2);
|
||||
|
||||
|
||||
ranges = new IndexRange[] {
|
||||
new IndexRange(10,90)
|
||||
new IndexRange(10, 90)
|
||||
};
|
||||
|
||||
|
||||
entries = new IndexRange[] {
|
||||
new IndexRange(10, 1)
|
||||
};
|
||||
|
||||
inspectRecords(map, ranges, entries);
|
||||
|
||||
|
||||
// Remove last one
|
||||
map.remove(1);
|
||||
assertEquals(0, map.rangeTable.getRecordCount());
|
||||
assertEquals(0, map.mapTable.getRecordCount());
|
||||
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetValueIterator() {
|
||||
@Test
|
||||
public void testGetValueIterator() {
|
||||
SharedRangeMapDB map = new SharedRangeMapDB(dbh, "TEST", this, true);
|
||||
|
||||
|
||||
// Add same entries as the testAdd used
|
||||
map.add(10, 20, 1);
|
||||
map.add(30, 40, 1);
|
||||
|
@ -392,17 +398,17 @@ System.out.println(" Map entry: rangeKey=" + entry.getStart() + ", value=" + en
|
|||
map.add(70, 80, 1);
|
||||
|
||||
map.add(21, 29, 1);
|
||||
|
||||
|
||||
map.add(35, 55, 1);
|
||||
|
||||
|
||||
map.add(55, 90, 1);
|
||||
|
||||
|
||||
map.add(20, 30, 2);
|
||||
|
||||
|
||||
map.add(28, 35, 3);
|
||||
|
||||
|
||||
map.add(28, 35, 4);
|
||||
|
||||
|
||||
// Test 1
|
||||
Iterator<Field> iter = map.getValueIterator(29, 34);
|
||||
LongField[] values = new LongField[] {
|
||||
|
@ -414,12 +420,13 @@ System.out.println(" Map entry: rangeKey=" + entry.getStart() + ", value=" + en
|
|||
int cnt = 0;
|
||||
while (iter.hasNext()) {
|
||||
++cnt;
|
||||
LongField v = (LongField)iter.next();
|
||||
if (indexOf(values, v) < 0)
|
||||
LongField v = (LongField) iter.next();
|
||||
if (indexOf(values, v) < 0) {
|
||||
Assert.fail("Unexpected value: " + v.getLongValue());
|
||||
}
|
||||
}
|
||||
assertEquals(values.length, cnt);
|
||||
|
||||
|
||||
// Test 2
|
||||
iter = map.getValueIterator(0, 20);
|
||||
values = new LongField[] {
|
||||
|
@ -429,12 +436,13 @@ System.out.println(" Map entry: rangeKey=" + entry.getStart() + ", value=" + en
|
|||
cnt = 0;
|
||||
while (iter.hasNext()) {
|
||||
++cnt;
|
||||
LongField v = (LongField)iter.next();
|
||||
if (indexOf(values, v) < 0)
|
||||
LongField v = (LongField) iter.next();
|
||||
if (indexOf(values, v) < 0) {
|
||||
Assert.fail("Unexpected value: " + v.getLongValue());
|
||||
}
|
||||
}
|
||||
assertEquals(values.length, cnt);
|
||||
|
||||
|
||||
// Test 3
|
||||
iter = map.getValueIterator(89, 100);
|
||||
values = new LongField[] {
|
||||
|
@ -443,23 +451,23 @@ System.out.println(" Map entry: rangeKey=" + entry.getStart() + ", value=" + en
|
|||
cnt = 0;
|
||||
while (iter.hasNext()) {
|
||||
++cnt;
|
||||
LongField v = (LongField)iter.next();
|
||||
if (indexOf(values, v) < 0)
|
||||
LongField v = (LongField) iter.next();
|
||||
if (indexOf(values, v) < 0) {
|
||||
Assert.fail("Unexpected value: " + v.getLongValue());
|
||||
}
|
||||
}
|
||||
assertEquals(values.length, cnt);
|
||||
|
||||
|
||||
|
||||
// Test 4
|
||||
iter = map.getValueIterator(0, 9);
|
||||
assertTrue(!iter.hasNext());
|
||||
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetValueRangeIterator() {
|
||||
@Test
|
||||
public void testGetValueRangeIterator() {
|
||||
SharedRangeMapDB map = new SharedRangeMapDB(dbh, "TEST", this, true);
|
||||
System.out.println("testGetValueRangeIterator ---");
|
||||
System.out.println("testGetValueRangeIterator ---");
|
||||
// Add same entries as the testAdd used
|
||||
map.add(10, 20, 1);
|
||||
map.add(30, 40, 1);
|
||||
|
@ -467,19 +475,19 @@ System.out.println("testGetValueRangeIterator ---");
|
|||
map.add(70, 80, 1);
|
||||
|
||||
map.add(21, 29, 1);
|
||||
|
||||
|
||||
map.add(35, 55, 1);
|
||||
|
||||
|
||||
map.add(55, 90, 1);
|
||||
|
||||
|
||||
map.add(20, 30, 2);
|
||||
|
||||
|
||||
map.add(28, 35, 3);
|
||||
|
||||
|
||||
map.add(28, 35, 4);
|
||||
|
||||
|
||||
map.add(25, 39, 4);
|
||||
|
||||
|
||||
IndexRangeIterator iter = map.getValueRangeIterator(2);
|
||||
IndexRange[] ranges = new IndexRange[] {
|
||||
new IndexRange(20, 24),
|
||||
|
@ -490,12 +498,13 @@ System.out.println("testGetValueRangeIterator ---");
|
|||
while (iter.hasNext()) {
|
||||
++cnt;
|
||||
IndexRange range = iter.next();
|
||||
if (indexOf(ranges, range) < 0)
|
||||
if (indexOf(ranges, range) < 0) {
|
||||
Assert.fail("Unexpected range: " + range.getStart() + " - " + range.getEnd());
|
||||
System.out.println(" Range: " + range.getStart() + " - " + range.getEnd());
|
||||
}
|
||||
System.out.println(" Range: " + range.getStart() + " - " + range.getEnd());
|
||||
}
|
||||
assertEquals(ranges.length, cnt);
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -60,6 +60,7 @@ import ghidra.test.TestEnv;
|
|||
*/
|
||||
public class OptionsDialogTest extends AbstractGhidraHeadedIntegrationTest {
|
||||
|
||||
private static final String MY_PATH_NAME_OPTION_NAME = "My PathName";
|
||||
private static final String TOOL_NODE_NAME = "Tool";
|
||||
private PluginTool tool;
|
||||
private TestEnv env;
|
||||
|
@ -281,7 +282,7 @@ public class OptionsDialogTest extends AbstractGhidraHeadedIntegrationTest {
|
|||
|
||||
ScrollableOptionsEditor editor = showOptions(ToolConstants.TOOL_OPTIONS);
|
||||
|
||||
pressBrowseButton(editor, "My PathName");
|
||||
pressBrowseButton(editor, MY_PATH_NAME_OPTION_NAME);
|
||||
|
||||
GhidraFileChooser chooser = waitForDialogComponent(GhidraFileChooser.class);
|
||||
assertNotNull(chooser);
|
||||
|
@ -297,7 +298,7 @@ public class OptionsDialogTest extends AbstractGhidraHeadedIntegrationTest {
|
|||
pressButton(openButton);
|
||||
waitForSwing();
|
||||
|
||||
JTextField pathField = getEditorTextField(editor, "My PathName");
|
||||
JTextField pathField = getEditorTextField(editor, MY_PATH_NAME_OPTION_NAME);
|
||||
assertEquals(file.getAbsolutePath(), pathField.getText());
|
||||
}
|
||||
|
||||
|
@ -305,7 +306,7 @@ public class OptionsDialogTest extends AbstractGhidraHeadedIntegrationTest {
|
|||
public void testFileChooserEditor_ClearValue() throws Exception {
|
||||
|
||||
ScrollableOptionsEditor editor = showOptions(ToolConstants.TOOL_OPTIONS);
|
||||
JTextField pathField = getEditorTextField(editor, "My PathName");
|
||||
JTextField pathField = getEditorTextField(editor, MY_PATH_NAME_OPTION_NAME);
|
||||
|
||||
setText(pathField, "");
|
||||
|
||||
|
@ -313,7 +314,7 @@ public class OptionsDialogTest extends AbstractGhidraHeadedIntegrationTest {
|
|||
|
||||
showOptionsDialog(tool);
|
||||
editor = showOptions(ToolConstants.TOOL_OPTIONS);
|
||||
pathField = getEditorTextField(editor, "My PathName");
|
||||
pathField = getEditorTextField(editor, MY_PATH_NAME_OPTION_NAME);
|
||||
assertEquals("", pathField.getText());
|
||||
}
|
||||
|
||||
|
@ -1059,10 +1060,13 @@ public class OptionsDialogTest extends AbstractGhidraHeadedIntegrationTest {
|
|||
// register this options because it is used in a test that saves and restores and
|
||||
// only registered options are saved.
|
||||
String myOptionsName = "My Options" + Options.DELIMITER;
|
||||
options.registerOption(myOptionsName + "my sub group Boolean Value", true, null, null);
|
||||
options.registerOption(myOptionsName + "my sub group Boolean Value", true, null,
|
||||
"description");
|
||||
|
||||
options.registerOption("My PathName", OptionType.FILE_TYPE, null, null, "");
|
||||
options.setFile("My PathName", new File(System.getProperty("user.dir")));
|
||||
File file = new File(System.getProperty("user.dir"));
|
||||
options.registerOption(MY_PATH_NAME_OPTION_NAME, OptionType.FILE_TYPE, file, null,
|
||||
"description");
|
||||
options.setFile(MY_PATH_NAME_OPTION_NAME, file);
|
||||
|
||||
// the following "get" methods set a value
|
||||
options.getInt(myOptionsName + "my sub group" + Options.DELIMITER + "My Test Value", 10);
|
||||
|
@ -1071,19 +1075,29 @@ public class OptionsDialogTest extends AbstractGhidraHeadedIntegrationTest {
|
|||
|
||||
String intOptionName = myOptionsName + "my sub group" + Options.DELIMITER + "Group A" +
|
||||
Options.DELIMITER + "Second Int Value";
|
||||
options.registerOption(intOptionName, 50, null, "description");
|
||||
options.setInt(intOptionName, 50);
|
||||
options.setBoolean(myOptionsName + "my sub group" + Options.DELIMITER + "Group A" +
|
||||
Options.DELIMITER + "First boolean value", true);
|
||||
|
||||
options.setInt(
|
||||
String name = myOptionsName + "my sub group" + Options.DELIMITER + "Group A" +
|
||||
Options.DELIMITER + "First boolean value";
|
||||
options.registerOption(name, true, null, "description");
|
||||
options.setBoolean(name, true);
|
||||
|
||||
name =
|
||||
"New Options" + Options.DELIMITER + " subgroup A" + Options.DELIMITER + " subgroup B" +
|
||||
Options.DELIMITER + " subgroup C" + Options.DELIMITER + "Another int value",
|
||||
300);
|
||||
Options.DELIMITER + " subgroup C" + Options.DELIMITER + "Another int value";
|
||||
options.registerOption(name, 300, null, "description");
|
||||
options.setInt(name, 300);
|
||||
|
||||
options.setColor("Favorite Color", Color.RED);
|
||||
name = "Favorite Color";
|
||||
options.registerOption(name, Color.RED, null, "description");
|
||||
options.setColor(name, Color.RED);
|
||||
|
||||
// select the middle button
|
||||
options.setEnum("Mouse Buttons" + Options.DELIMITER + "Mouse Button To Activate",
|
||||
name = "Mouse Buttons" + Options.DELIMITER + "Mouse Button To Activate";
|
||||
options.registerOption(name, GhidraOptions.CURSOR_MOUSE_BUTTON_NAMES.MIDDLE, null,
|
||||
"description");
|
||||
options.setEnum(name,
|
||||
GhidraOptions.CURSOR_MOUSE_BUTTON_NAMES.MIDDLE);
|
||||
|
||||
}
|
||||
|
|
|
@ -28,7 +28,7 @@ import ghidra.program.model.listing.ProgramChangeSet;
|
|||
import ghidra.test.TestEnv;
|
||||
import ghidra.util.InvalidNameException;
|
||||
import ghidra.util.exception.CancelledException;
|
||||
import ghidra.util.task.TaskMonitorAdapter;
|
||||
import ghidra.util.task.TaskMonitor;
|
||||
|
||||
/**
|
||||
* This model is used by the {@link MergeTestFacilitator} to configure programs needed
|
||||
|
@ -62,8 +62,8 @@ public abstract class AbstractMTFModel {
|
|||
* This represents the original checked-out version.
|
||||
* Program returned will be released by the MergeTestFacilitator
|
||||
* when disposed or re-initialized.
|
||||
* @return the program
|
||||
*/
|
||||
|
||||
public ProgramDB getOriginalProgram() {
|
||||
return originalProgram;
|
||||
}
|
||||
|
@ -73,8 +73,8 @@ public abstract class AbstractMTFModel {
|
|||
* This represents the current version.
|
||||
* Program returned will be released by the MergeTestFacilitator
|
||||
* when disposed or re-initialized.
|
||||
* @return the program
|
||||
*/
|
||||
|
||||
public ProgramDB getLatestProgram() {
|
||||
return latestProgram;
|
||||
}
|
||||
|
@ -84,8 +84,8 @@ public abstract class AbstractMTFModel {
|
|||
* This represents the local program to be checked-in.
|
||||
* Program returned will be released by the MergeTestFacilitator
|
||||
* when disposed or re-initialized.
|
||||
* @return the program
|
||||
*/
|
||||
|
||||
public ProgramDB getPrivateProgram() {
|
||||
return privateProgram;
|
||||
}
|
||||
|
@ -95,8 +95,8 @@ public abstract class AbstractMTFModel {
|
|||
* This represents the checkin program containing the merged data.
|
||||
* Program returned will be released by the MergeTestFacilitator
|
||||
* when disposed or re-initialized.
|
||||
* @return the program
|
||||
*/
|
||||
|
||||
public ProgramDB getResultProgram() {
|
||||
return resultProgram;
|
||||
}
|
||||
|
@ -129,7 +129,7 @@ public abstract class AbstractMTFModel {
|
|||
BufferFile bufferFile = item.open();
|
||||
try {
|
||||
fileSystem.createDatabase(parent.getPathname(), newName, FileIDFactory.createFileID(),
|
||||
bufferFile, null, item.getContentType(), false, TaskMonitorAdapter.DUMMY_MONITOR,
|
||||
bufferFile, null, item.getContentType(), false, TaskMonitor.DUMMY,
|
||||
null);
|
||||
}
|
||||
finally {
|
||||
|
@ -141,6 +141,7 @@ public abstract class AbstractMTFModel {
|
|||
}
|
||||
|
||||
protected void cleanup() {
|
||||
|
||||
if (originalProgram != null) {
|
||||
originalProgram.release(this);
|
||||
originalProgram = null;
|
||||
|
@ -154,6 +155,8 @@ public abstract class AbstractMTFModel {
|
|||
privateProgram = null;
|
||||
}
|
||||
if (resultProgram != null) {
|
||||
resultProgram.flushEvents();
|
||||
AbstractGenericTest.waitForSwing();
|
||||
resultProgram.release(this);
|
||||
resultProgram = null;
|
||||
}
|
||||
|
|
|
@ -734,6 +734,8 @@ public class FunctionGraphPlugin1Test extends AbstractFunctionGraphTest {
|
|||
|
||||
setNavigationHistoryOption(NavigationHistoryChoices.NAVIGATION_EVENTS);
|
||||
|
||||
clearHistory();
|
||||
|
||||
FGVertex v1 = vertex("01004178");
|
||||
pickVertex(v1);
|
||||
|
||||
|
@ -743,17 +745,18 @@ public class FunctionGraphPlugin1Test extends AbstractFunctionGraphTest {
|
|||
FGVertex v3 = vertex("010041a4");
|
||||
pickVertex(v3);
|
||||
|
||||
// in this navigation mode, merely selecting nodes does *not* put previous nodes in history
|
||||
assertNotInHistory(v1, v2);
|
||||
|
||||
//
|
||||
// Now leave the function and verify the old function is in the history
|
||||
// Perform a navigation action (e.g., goTo()) and verify the old function is in the history
|
||||
//
|
||||
Address ghidra = getAddress("0x01002cf5");
|
||||
goTo(ghidra);
|
||||
assertInHistory(v3.getVertexAddress());
|
||||
|
||||
Address foo = getAddress("0x01002339");
|
||||
goTo(foo);
|
||||
|
||||
assertInHistory(v3.getVertexAddress(), ghidra);
|
||||
}
|
||||
|
||||
|
@ -785,6 +788,14 @@ public class FunctionGraphPlugin1Test extends AbstractFunctionGraphTest {
|
|||
}
|
||||
}
|
||||
|
||||
private void clearHistory() {
|
||||
GoToService goTo = tool.getService(GoToService.class);
|
||||
Navigatable navigatable = goTo.getDefaultNavigatable();
|
||||
|
||||
NavigationHistoryService service = tool.getService(NavigationHistoryService.class);
|
||||
service.clear(navigatable);
|
||||
}
|
||||
|
||||
private List<LocationMemento> getNavigationHistory() {
|
||||
|
||||
GoToService goTo = tool.getService(GoToService.class);
|
||||
|
@ -823,8 +834,8 @@ public class FunctionGraphPlugin1Test extends AbstractFunctionGraphTest {
|
|||
|
||||
for (Address a : expectedAddresses) {
|
||||
|
||||
assertTrue("Vertex address should be in the history list: " + a + ".\nHistory: " +
|
||||
actualAddresses + "\nNavigated vertices: " + expectedAddresses,
|
||||
assertTrue("Vertex address should be in the history list: " + a + ".\nActual: " +
|
||||
actualAddresses + "\nExpected: " + expectedAddresses,
|
||||
actualAddresses.contains(a));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -29,10 +29,10 @@ import javax.security.auth.spi.LoginModule;
|
|||
|
||||
import com.sun.security.auth.UserPrincipal;
|
||||
|
||||
import generic.concurrent.io.ProcessConsumer;
|
||||
import ghidra.server.RepositoryManager;
|
||||
import ghidra.util.DateUtils;
|
||||
import ghidra.util.timer.Watchdog;
|
||||
import utilities.util.FileUtilities;
|
||||
|
||||
/**
|
||||
* A JAAS {@link LoginModule} that executes an external program that decides if the username
|
||||
|
@ -208,10 +208,11 @@ public class ExternalProgramLoginModule implements LoginModule {
|
|||
Process p = Runtime.getRuntime().exec(cmdArray);
|
||||
process.set(p);
|
||||
|
||||
FileUtilities.asyncForEachLine(p.getInputStream(), (stdOutStr) -> {
|
||||
ProcessConsumer.consume(p.getInputStream(), stdOutStr -> {
|
||||
RepositoryManager.log(null, null, extProgramName + " STDOUT: " + stdOutStr, null);
|
||||
});
|
||||
FileUtilities.asyncForEachLine(p.getErrorStream(), (errStr) -> {
|
||||
|
||||
ProcessConsumer.consume(p.getErrorStream(), errStr -> {
|
||||
RepositoryManager.log(null, null, extProgramName + " STDERR: " + errStr, null);
|
||||
});
|
||||
|
||||
|
@ -266,8 +267,12 @@ public class ExternalProgramLoginModule implements LoginModule {
|
|||
}
|
||||
extProgramName = extProFile.getName();
|
||||
|
||||
List<String> argKeys = options.keySet().stream().filter(
|
||||
key -> key.startsWith(ARG_OPTION_NAME)).sorted().collect(Collectors.toList());
|
||||
List<String> argKeys = options.keySet()
|
||||
.stream()
|
||||
.filter(
|
||||
key -> key.startsWith(ARG_OPTION_NAME))
|
||||
.sorted()
|
||||
.collect(Collectors.toList());
|
||||
List<String> cmdArrayValues = new ArrayList<>();
|
||||
cmdArrayValues.add(externalProgram.toString());
|
||||
for (String argKey : argKeys) {
|
||||
|
|
|
@ -2245,12 +2245,25 @@ public class DockingWindowManager implements PropertyChangeListener, Placeholder
|
|||
|
||||
// Unable to find the manager. This can happen during testing; only report if
|
||||
// it is unexpected
|
||||
if (!instances.isEmpty()) {
|
||||
Msg.debug(DockingWindowManager.class,
|
||||
"Unable to find Docking Window Manager for " +
|
||||
component.getClass().getSimpleName(),
|
||||
ReflectionUtilities.createJavaFilteredThrowable());
|
||||
maybeReportMissingManager();
|
||||
}
|
||||
|
||||
private void maybeReportMissingManager() {
|
||||
if (instances.isEmpty()) {
|
||||
return; // not manager means no tool; assume testing
|
||||
}
|
||||
|
||||
if (instances.size() == 1) {
|
||||
DockingWindowManager dwm = instances.get(0);
|
||||
if (!dwm.isVisible()) {
|
||||
return; // not showing; assume testing with tool not shown
|
||||
}
|
||||
}
|
||||
|
||||
Msg.debug(DockingWindowManager.class,
|
||||
"Unable to find Docking Window Manager for " +
|
||||
component.getClass().getSimpleName(),
|
||||
ReflectionUtilities.createJavaFilteredThrowable());
|
||||
}
|
||||
});
|
||||
|
||||
|
|
|
@ -2102,40 +2102,34 @@ public abstract class AbstractDockingTest extends AbstractGenericTest {
|
|||
}
|
||||
|
||||
public static boolean isEnabled(DockingActionIf action) {
|
||||
AtomicBoolean ref = new AtomicBoolean();
|
||||
runSwing(() -> ref.set(action.isEnabledForContext(new ActionContext())));
|
||||
return ref.get();
|
||||
return runSwing(() -> action.isEnabledForContext(new ActionContext()));
|
||||
}
|
||||
|
||||
public static boolean isEnabled(AbstractButton button) {
|
||||
AtomicBoolean ref = new AtomicBoolean();
|
||||
runSwing(() -> ref.set(button.isEnabled()));
|
||||
return ref.get();
|
||||
return runSwing(() -> button.isEnabled());
|
||||
}
|
||||
|
||||
public static boolean isSelected(AbstractButton button) {
|
||||
AtomicBoolean ref = new AtomicBoolean();
|
||||
runSwing(() -> ref.set(button.isSelected()));
|
||||
return ref.get();
|
||||
return runSwing(() -> button.isSelected());
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a generic action context with no provider, with the given payload
|
||||
* @param payload the generic object to put in the context
|
||||
* Creates a generic action context with no provider, with the given context object
|
||||
* @param contextObject the generic object to put in the context
|
||||
* @return the new context
|
||||
*/
|
||||
public ActionContext createContext(Object payload) {
|
||||
return new ActionContext().setContextObject(payload);
|
||||
public ActionContext createContext(Object contextObject) {
|
||||
return new ActionContext().setContextObject(contextObject);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a generic action context with the given provider, with the given payload
|
||||
* Creates a generic action context with the given provider, with the given context object
|
||||
* @param provider the provider
|
||||
* @param payload the generic object to put in the context
|
||||
* @param contextObject the generic object to put in the context
|
||||
* @return the new context
|
||||
*/
|
||||
public ActionContext createContext(ComponentProvider provider, Object payload) {
|
||||
return new ActionContext(provider).setContextObject(payload);
|
||||
public ActionContext createContext(ComponentProvider provider, Object contextObject) {
|
||||
return new ActionContext(provider).setContextObject(contextObject);
|
||||
}
|
||||
|
||||
//==================================================================================================
|
||||
|
|
|
@ -0,0 +1,81 @@
|
|||
/* ###
|
||||
* 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 generic.concurrent.io;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import ghidra.util.Msg;
|
||||
import utilities.util.reflection.ReflectionUtilities;
|
||||
import utility.function.Dummy;
|
||||
|
||||
/**
|
||||
* Class to pass to a thread pool that will consume all output from an external process. This is
|
||||
* a {@link Runnable} that get submitted to a thread pool. This class records the data it reads
|
||||
*/
|
||||
public class IOResult implements Runnable {
|
||||
|
||||
public static final String THREAD_POOL_NAME = "I/O Thread Pool";
|
||||
|
||||
private List<String> outputLines = new ArrayList<String>();
|
||||
private BufferedReader commandOutput;
|
||||
private final Throwable inception;
|
||||
private Consumer<String> consumer = Dummy.consumer();
|
||||
|
||||
public IOResult(InputStream input) {
|
||||
this(ReflectionUtilities.createThrowableWithStackOlderThan(IOResult.class), input);
|
||||
}
|
||||
|
||||
public IOResult(Throwable inception, InputStream input) {
|
||||
this.inception = inception;
|
||||
commandOutput = new BufferedReader(new InputStreamReader(input));
|
||||
}
|
||||
|
||||
public void setConsumer(Consumer<String> consumer) {
|
||||
this.consumer = consumer;
|
||||
}
|
||||
|
||||
public String getOutputAsString() {
|
||||
StringBuilder buffy = new StringBuilder();
|
||||
for (String line : outputLines) {
|
||||
buffy.append(line);
|
||||
}
|
||||
return buffy.toString();
|
||||
}
|
||||
|
||||
public List<String> getOutput() {
|
||||
return outputLines;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
String line = null;
|
||||
|
||||
try {
|
||||
while ((line = commandOutput.readLine()) != null) {
|
||||
consumer.accept(line);
|
||||
outputLines.add(line);
|
||||
}
|
||||
}
|
||||
catch (Exception e) {
|
||||
String inceptionString = ReflectionUtilities.stackTraceToString(inception);
|
||||
Msg.debug(IOResult.class,
|
||||
"Exception reading output from process. Created from:\n" + inceptionString, e);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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 generic.concurrent.io;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import generic.concurrent.GThreadPool;
|
||||
import utilities.util.reflection.ReflectionUtilities;
|
||||
import utility.function.Dummy;
|
||||
|
||||
/**
|
||||
* A class that allows clients to <b>asynchronously</b> consume the output of a {@link Process}s
|
||||
* input and error streams. The task is asynchronous to avoid deadlocks when both streams need
|
||||
* to be read in order for the process to proceed.
|
||||
*/
|
||||
public class ProcessConsumer {
|
||||
|
||||
/**
|
||||
* Read the given input stream line-by-line.
|
||||
*
|
||||
* <p>To get all output after all reading is done you can call the blocking operation
|
||||
* {@link Future#get()}.
|
||||
*
|
||||
* @param is the input stream
|
||||
* @return the future that will be complete when all lines are read
|
||||
*/
|
||||
public static Future<IOResult> consume(InputStream is) {
|
||||
return consume(is, Dummy.consumer());
|
||||
}
|
||||
|
||||
/**
|
||||
* Read the given input stream line-by-line.
|
||||
*
|
||||
* <p>If you wish to get all output after all reading is done you can call the blocking
|
||||
* operation {@link Future#get()}.
|
||||
*
|
||||
* @param is the input stream
|
||||
* @param lineConsumer the line consumer; may be null
|
||||
* @return the future that will be complete when all lines are read
|
||||
*/
|
||||
public static Future<IOResult> consume(InputStream is,
|
||||
Consumer<String> lineConsumer) {
|
||||
|
||||
lineConsumer = Dummy.ifNull(lineConsumer);
|
||||
|
||||
Throwable inception = ReflectionUtilities.filterJavaThrowable(
|
||||
ReflectionUtilities.createThrowableWithStackOlderThan(ProcessConsumer.class));
|
||||
|
||||
GThreadPool pool = GThreadPool.getSharedThreadPool(IOResult.THREAD_POOL_NAME);
|
||||
IOResult runnable = new IOResult(inception, is);
|
||||
runnable.setConsumer(lineConsumer);
|
||||
Future<IOResult> future = pool.submit(runnable, runnable);
|
||||
return future;
|
||||
}
|
||||
}
|
|
@ -26,6 +26,7 @@ import java.text.DecimalFormat;
|
|||
import java.text.NumberFormat;
|
||||
import java.util.*;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import generic.jar.ResourceFile;
|
||||
import ghidra.util.*;
|
||||
|
@ -95,6 +96,8 @@ public final class FileUtilities {
|
|||
|
||||
/**
|
||||
* Return an array of bytes read from the given file.
|
||||
* @param sourceFile the source file
|
||||
* @return the bytes
|
||||
* @throws IOException if the file could not be accessed
|
||||
*/
|
||||
public final static byte[] getBytesFromFile(File sourceFile) throws IOException {
|
||||
|
@ -118,6 +121,8 @@ public final class FileUtilities {
|
|||
|
||||
/**
|
||||
* Return an array of bytes read from the given file.
|
||||
* @param sourceFile the source file
|
||||
* @return the bytes
|
||||
* @throws IOException if the file could not be accessed
|
||||
*/
|
||||
public final static byte[] getBytesFromFile(ResourceFile sourceFile) throws IOException {
|
||||
|
@ -161,7 +166,6 @@ public final class FileUtilities {
|
|||
}
|
||||
byte[] data = new byte[(int) length];
|
||||
|
||||
|
||||
try (InputStream fis = sourceFile.getInputStream()) {
|
||||
if (fis.skip(offset) != offset) {
|
||||
throw new IOException("Did not skip to the specified offset!");
|
||||
|
@ -383,9 +387,20 @@ public final class FileUtilities {
|
|||
}
|
||||
|
||||
/**
|
||||
* Delete a directory and all of its contents.
|
||||
* Delete a file or directory and all of its contents
|
||||
*
|
||||
* @param dir the directory to delete
|
||||
* @return true if delete was successful. If false is returned, a partial
|
||||
* delete may have occurred.
|
||||
*/
|
||||
public static boolean deleteDir(Path dir) {
|
||||
return deleteDir(dir.toFile());
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete a file or directory and all of its contents
|
||||
*
|
||||
* @param dir
|
||||
* @param dir the dir to delete
|
||||
* @return true if delete was successful. If false is returned, a partial
|
||||
* delete may have occurred.
|
||||
*/
|
||||
|
@ -400,11 +415,13 @@ public final class FileUtilities {
|
|||
}
|
||||
|
||||
/**
|
||||
* Delete a directory and all of its contents.
|
||||
* Delete a directory and all of its contents
|
||||
*
|
||||
* @param dir
|
||||
* @param dir the dir to delete
|
||||
* @param monitor the task monitor
|
||||
* @return true if delete was successful. If false is returned, a partial
|
||||
* delete may have occurred.
|
||||
* @throws CancelledException if the operation is cancelled
|
||||
*/
|
||||
public final static boolean deleteDir(File dir, TaskMonitor monitor) throws CancelledException {
|
||||
File[] files = dir.listFiles();
|
||||
|
@ -472,6 +489,12 @@ public final class FileUtilities {
|
|||
/**
|
||||
* This is the same as calling {@link #copyDir(File, File, FileFilter, TaskMonitor)} with
|
||||
* a {@link FileFilter} that accepts all files.
|
||||
* @param originalDir the source dir
|
||||
* @param copyDir the destination dir
|
||||
* @param monitor the task monitor
|
||||
* @return the number of filed copied
|
||||
* @throws IOException if there is an issue copying the files
|
||||
* @throws CancelledException if the operation is cancelled
|
||||
*/
|
||||
public final static int copyDir(File originalDir, File copyDir, TaskMonitor monitor)
|
||||
throws IOException, CancelledException {
|
||||
|
@ -487,6 +510,7 @@ public final class FileUtilities {
|
|||
* @param copyDir The directory in which the extracted contents will be placed
|
||||
* @param filter a filter to apply against the directory's contents
|
||||
* @param monitor the task monitor
|
||||
* @return the number of filed copied
|
||||
* @throws IOException if there was a problem accessing the files
|
||||
* @throws CancelledException if the copy is cancelled
|
||||
*/
|
||||
|
@ -572,7 +596,7 @@ public final class FileUtilities {
|
|||
return;// squash during production mode
|
||||
}
|
||||
|
||||
Msg.debug(SystemUtilities.class, text);
|
||||
Msg.debug(FileUtilities.class, text);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -644,10 +668,10 @@ public final class FileUtilities {
|
|||
}
|
||||
|
||||
/**
|
||||
* Returns all of the lines in the file without any newline characters.
|
||||
* Returns all of the lines in the file without any newline characters
|
||||
* @param file The file to read in
|
||||
* @return a list of file lines
|
||||
* @throws IOException
|
||||
* @throws IOException if an error occurs reading the file
|
||||
*/
|
||||
public static List<String> getLines(File file) throws IOException {
|
||||
return getLines(new ResourceFile(file));
|
||||
|
@ -660,7 +684,7 @@ public final class FileUtilities {
|
|||
* <p>
|
||||
* @param file The text file to read in
|
||||
* @return a list of file lines
|
||||
* @throws IOException if an error occurs trying to read the file.
|
||||
* @throws IOException if an error occurs reading the file
|
||||
*/
|
||||
public static List<String> getLines(ResourceFile file) throws IOException {
|
||||
try (InputStream is = file.getInputStream()) {
|
||||
|
@ -857,7 +881,7 @@ public final class FileUtilities {
|
|||
* @param f1 the parent file
|
||||
* @param f2 the child file
|
||||
* @return the portion of the second file that trails the full path of the first file.
|
||||
* @throws IOException
|
||||
* @throws IOException if there is an error canonicalizing the path
|
||||
*/
|
||||
public static String relativizePath(File f1, File f2) throws IOException {
|
||||
String parentPath = f1.getCanonicalPath().replace('\\', '/');
|
||||
|
@ -1108,7 +1132,7 @@ public final class FileUtilities {
|
|||
* <p>
|
||||
* TODO: why is the method using 1000 vs. 1024 for K?
|
||||
*
|
||||
* @param length
|
||||
* @param length the length to format
|
||||
* @return pretty string - "1.1KB", "5.0MB"
|
||||
*/
|
||||
public static String formatLength(long length) {
|
||||
|
@ -1123,6 +1147,11 @@ public final class FileUtilities {
|
|||
return formatter.format((length / 1000000f)) + "MB";
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a temporary directory using the given prefix
|
||||
* @param prefix the prefix
|
||||
* @return the temp file
|
||||
*/
|
||||
public static File createTempDirectory(String prefix) {
|
||||
try {
|
||||
File temp = File.createTempFile(prefix, Long.toString(System.currentTimeMillis()));
|
||||
|
@ -1175,51 +1204,32 @@ public final class FileUtilities {
|
|||
public static void openNative(File file) throws IOException {
|
||||
if (!Desktop.isDesktopSupported()) {
|
||||
Msg.showError(FileUtilities.class, null, "Native Desktop Unsupported",
|
||||
"Access to the user's native desktop is not supported in the current environment.");
|
||||
"Access to the user's native desktop is not supported in the current environment." +
|
||||
"\nUnable to open file: " + file);
|
||||
return;
|
||||
}
|
||||
Desktop.getDesktop().open(file);
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes each text line in a text file, in a separate thread.
|
||||
* <p>
|
||||
* Thread exits when EOF is reached.
|
||||
*
|
||||
* @param is {@link InputStream} to read
|
||||
* @param consumer code that will process each text of the text file.
|
||||
* A convenience method to list the contents of the given directory path and pass each to the
|
||||
* given consumer. If the given path does not represent a directory, nothing will happen.
|
||||
*
|
||||
* <p>This method handles closing resources by using the try-with-resources construct on
|
||||
* {@link Files#list(Path)}
|
||||
*
|
||||
* @param path the directory
|
||||
* @param consumer the consumer of each child in the given directory
|
||||
* @throws IOException if there is any problem reading the directory contents
|
||||
*/
|
||||
public static void asyncForEachLine(InputStream is, Consumer<String> consumer) {
|
||||
asyncForEachLine(new BufferedReader(new InputStreamReader(is)), consumer);
|
||||
public static void forEachFile(Path path, Consumer<Stream<Path>> consumer) throws IOException {
|
||||
|
||||
if (!Files.isDirectory(path)) {
|
||||
return;
|
||||
}
|
||||
|
||||
try (Stream<Path> pathStream = Files.list(path)) {
|
||||
consumer.accept(pathStream);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes each text line in a text file, in a separate thread.
|
||||
* <p>
|
||||
* Thread exits when EOF is reached.
|
||||
*
|
||||
* @param reader {@link BufferedReader} to read
|
||||
* @param consumer code that will process each text of the text file.
|
||||
*/
|
||||
public static void asyncForEachLine(BufferedReader reader, Consumer<String> consumer) {
|
||||
new Thread(() -> {
|
||||
try {
|
||||
while (true) {
|
||||
String line = reader.readLine();
|
||||
if (line == null) {
|
||||
break;
|
||||
}
|
||||
consumer.accept(line);
|
||||
}
|
||||
}
|
||||
catch (IOException ioe) {
|
||||
// ignore io errors while reading because thats normal when hitting EOF
|
||||
}
|
||||
catch (Exception e) {
|
||||
Msg.error(FileUtilities.class, "Exception while reading", e);
|
||||
}
|
||||
|
||||
}, "Threaded Stream Reader Thread").start();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue