mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-06 03:50:02 +02:00
GP-4643: Add a JIT-accelerated p-code emulator (API/scripting only)
This commit is contained in:
parent
20285e267d
commit
a8fae1fe5b
320 changed files with 32638 additions and 630 deletions
|
@ -4,9 +4,9 @@
|
|||
* 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.
|
||||
|
@ -29,7 +29,9 @@ import java.util.function.Supplier;
|
|||
import org.junit.Assert;
|
||||
import org.junit.Rule;
|
||||
import org.junit.rules.TestName;
|
||||
import org.junit.rules.TestRule;
|
||||
|
||||
import generic.test.rule.*;
|
||||
import ghidra.framework.Application;
|
||||
import ghidra.framework.TestApplicationUtils;
|
||||
import ghidra.util.SystemUtilities;
|
||||
|
@ -41,11 +43,12 @@ import utility.application.ApplicationUtilities;
|
|||
/**
|
||||
* A root for system tests that provides known system information.
|
||||
*
|
||||
* <P>This class exists so that fast unit tests have a place to share data without having the
|
||||
* slowness of more heavy weight concepts like {@link Application}, logging, etc.
|
||||
* <P>
|
||||
* This class exists so that fast unit tests have a place to share data without having the slowness
|
||||
* of more heavy weight concepts like {@link Application}, logging, etc.
|
||||
*
|
||||
* <P> !! WARNING !!
|
||||
* This test is meant to initialize quickly. All file I/O should be avoided.
|
||||
* <P>
|
||||
* !! WARNING !! This test is meant to initialize quickly. All file I/O should be avoided.
|
||||
*/
|
||||
public abstract class AbstractGTest {
|
||||
|
||||
|
@ -75,8 +78,25 @@ public abstract class AbstractGTest {
|
|||
public TestName testName = new TestName();
|
||||
|
||||
/**
|
||||
* Get the directory path within which all temporary test
|
||||
* data files should be created.
|
||||
* This rule handles the {@link Repeated} annotation
|
||||
*
|
||||
* <p>
|
||||
* During batch mode, this rule should never be needed. This rule is included here as a
|
||||
* convenience, in case a developer wants to use the {@link Repeated} annotation to diagnose a
|
||||
* non-deterministic test failure. Without this rule, the annotation would be silently ignored.
|
||||
*/
|
||||
@Rule
|
||||
public TestRule repeatedRule = new RepeatedTestRule();
|
||||
|
||||
/**
|
||||
* This rule handles the {@link IgnoreUnfinished} annotation
|
||||
*/
|
||||
@Rule
|
||||
public TestRule ignoreUnfinishedRule = new IgnoreUnfinishedRule();
|
||||
|
||||
/**
|
||||
* Get the directory path within which all temporary test data files should be created.
|
||||
*
|
||||
* @return test directory path ending with a File.separator character
|
||||
*/
|
||||
private static String createTestDirectoryPath() {
|
||||
|
@ -161,9 +181,9 @@ public abstract class AbstractGTest {
|
|||
}
|
||||
|
||||
/**
|
||||
* Compares the contents of two arrays to determine if they are equal. The contents must
|
||||
* match in the same order. If <code>message</code>
|
||||
* is <code>null</code>, then a generic error message will be printed.
|
||||
* Compares the contents of two arrays to determine if they are equal. The contents must match
|
||||
* in the same order. If <code>message</code> is <code>null</code>, then a generic error message
|
||||
* will be printed.
|
||||
*
|
||||
* @param message The message to print upon failure; can be null
|
||||
* @param expected The expected array.
|
||||
|
@ -180,9 +200,9 @@ public abstract class AbstractGTest {
|
|||
}
|
||||
|
||||
/**
|
||||
* Compares the contents of two arrays to determine if they are equal. The contents do not have
|
||||
* to be in the same order. If <code>message</code>
|
||||
* is <code>null</code>, then a generic error message will be printed.
|
||||
* Compares the contents of two arrays to determine if they are equal. The contents do not have
|
||||
* to be in the same order. If <code>message</code> is <code>null</code>, then a generic error
|
||||
* message will be printed.
|
||||
*
|
||||
* @param message The message to print upon failure; can be null
|
||||
* @param expected The expected array.
|
||||
|
@ -394,7 +414,7 @@ public abstract class AbstractGTest {
|
|||
}
|
||||
|
||||
/**
|
||||
* Waits for the given AtomicBoolean to return true. This is a convenience method for
|
||||
* Waits for the given AtomicBoolean to return true. This is a convenience method for
|
||||
* {@link #waitFor(BooleanSupplier)}.
|
||||
*
|
||||
* @param ab the atomic boolean
|
||||
|
@ -441,8 +461,8 @@ public abstract class AbstractGTest {
|
|||
* Waits for the given condition to return true
|
||||
*
|
||||
* @param condition the condition that returns true when satisfied
|
||||
* @param failureMessageSupplier the function that will supply the failure message in the
|
||||
* event of a timeout.
|
||||
* @param failureMessageSupplier the function that will supply the failure message in the event
|
||||
* of a timeout.
|
||||
* @throws AssertionFailedError if the condition is not met within the timeout period
|
||||
*/
|
||||
public static void waitForCondition(BooleanSupplier condition,
|
||||
|
@ -452,11 +472,12 @@ public abstract class AbstractGTest {
|
|||
}
|
||||
|
||||
/**
|
||||
* Waits for the given condition to return true. Most of the <code>waitForCondition()</code>
|
||||
* methods throw an {@link AssertionFailedError} if the timeout period expires.
|
||||
* This method allows you to setup a longer wait period by repeatedly calling this method.
|
||||
* Waits for the given condition to return true. Most of the <code>waitForCondition()</code>
|
||||
* methods throw an {@link AssertionFailedError} if the timeout period expires. This method
|
||||
* allows you to setup a longer wait period by repeatedly calling this method.
|
||||
*
|
||||
* <P>Most clients should use {@link #waitForCondition(BooleanSupplier)}.
|
||||
* <P>
|
||||
* Most clients should use {@link #waitForCondition(BooleanSupplier)}.
|
||||
*
|
||||
* @param supplier the supplier that returns true when satisfied
|
||||
*/
|
||||
|
@ -496,8 +517,8 @@ public abstract class AbstractGTest {
|
|||
}
|
||||
|
||||
/**
|
||||
* Waits for the value returned by the supplier to be non-null, throwing an exception if
|
||||
* that does not happen by the default timeout.
|
||||
* Waits for the value returned by the supplier to be non-null, throwing an exception if that
|
||||
* does not happen by the default timeout.
|
||||
*
|
||||
* @param supplier the supplier of the value
|
||||
* @param failureMessage the message to print upon the timeout being reached
|
||||
|
@ -509,8 +530,8 @@ public abstract class AbstractGTest {
|
|||
}
|
||||
|
||||
/**
|
||||
* Waits for the value returned by the supplier to be non-null, throwing an exception if
|
||||
* that does not happen by the default timeout.
|
||||
* Waits for the value returned by the supplier to be non-null, throwing an exception if that
|
||||
* does not happen by the default timeout.
|
||||
*
|
||||
* @param supplier the supplier of the value
|
||||
* @return the non-null value
|
||||
|
@ -521,8 +542,8 @@ public abstract class AbstractGTest {
|
|||
}
|
||||
|
||||
/**
|
||||
* Waits for the value returned by the supplier to be non-null, throwing an exception if
|
||||
* that does not happen by the default timeout.
|
||||
* Waits for the value returned by the supplier to be non-null, throwing an exception if that
|
||||
* does not happen by the default timeout.
|
||||
*
|
||||
* @param supplier the supplier of the value
|
||||
* @return the non-null value
|
||||
|
@ -533,12 +554,13 @@ public abstract class AbstractGTest {
|
|||
}
|
||||
|
||||
/**
|
||||
* Waits for the value returned by the supplier to be non-null. If the timeout period
|
||||
* expires, then null will be returned. Most of the <code>waitXyz()</code> methods
|
||||
* throw an {@link AssertionFailedError} if the timeout period expires. This method allows
|
||||
* you to setup a longer wait period by repeatedly calling this method.
|
||||
* Waits for the value returned by the supplier to be non-null. If the timeout period expires,
|
||||
* then null will be returned. Most of the <code>waitXyz()</code> methods throw an
|
||||
* {@link AssertionFailedError} if the timeout period expires. This method allows you to setup a
|
||||
* longer wait period by repeatedly calling this method.
|
||||
*
|
||||
* <P>Most clients should use {@link #waitForValue(Supplier)}.
|
||||
* <P>
|
||||
* Most clients should use {@link #waitForValue(Supplier)}.
|
||||
*
|
||||
* @param supplier the supplier of the value
|
||||
* @return the value; may be null
|
||||
|
@ -549,8 +571,8 @@ public abstract class AbstractGTest {
|
|||
}
|
||||
|
||||
/**
|
||||
* Waits for the value returned by the supplier to be non-null, optionally
|
||||
* throwing an exception if that does not happen by the given timeout.
|
||||
* Waits for the value returned by the supplier to be non-null, optionally throwing an exception
|
||||
* if that does not happen by the given timeout.
|
||||
*
|
||||
* @param supplier the supplier of the value
|
||||
* @param failureMessage the message to print upon the timeout being reached
|
||||
|
|
|
@ -4,9 +4,9 @@
|
|||
* 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.
|
||||
|
@ -15,7 +15,7 @@
|
|||
*/
|
||||
package generic.test;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
import java.awt.*;
|
||||
import java.awt.image.BufferedImage;
|
||||
|
@ -39,8 +39,6 @@ import org.junit.rules.*;
|
|||
import org.junit.runner.Description;
|
||||
|
||||
import generic.jar.ResourceFile;
|
||||
import generic.test.rule.Repeated;
|
||||
import generic.test.rule.RepeatedTestRule;
|
||||
import generic.util.WindowUtilities;
|
||||
import ghidra.GhidraTestApplicationLayout;
|
||||
import ghidra.framework.*;
|
||||
|
@ -111,17 +109,6 @@ public abstract class AbstractGenericTest extends AbstractGTest {
|
|||
@Rule
|
||||
public RuleChain ruleChain = RuleChain.outerRule(testName).around(watchman);// control rule ordering
|
||||
|
||||
/**
|
||||
* This rule handles the {@link Repeated} annotation
|
||||
*
|
||||
* <p>
|
||||
* During batch mode, this rule should never be needed. This rule is included here as a
|
||||
* convenience, in case a developer wants to use the {@link Repeated} annotation to diagnose a
|
||||
* non-deterministic test failure. Without this rule, the annotation would be silently ignored.
|
||||
*/
|
||||
@Rule
|
||||
public TestRule repeatedRule = new RepeatedTestRule();
|
||||
|
||||
@After
|
||||
public void resetLogging() {
|
||||
if (logSettingsChanged) {
|
||||
|
@ -237,9 +224,9 @@ public abstract class AbstractGenericTest extends AbstractGTest {
|
|||
}
|
||||
|
||||
/**
|
||||
* A callback for subclasses when a test has failed. This will be called
|
||||
* <b>after</b> <code>tearDown()</code>. This means that any diagnostics will have to
|
||||
* take into account items that have already been disposed.
|
||||
* A callback for subclasses when a test has failed. This will be called <b>after</b>
|
||||
* <code>tearDown()</code>. This means that any diagnostics will have to take into account items
|
||||
* that have already been disposed.
|
||||
*
|
||||
* @param e the exception that happened when the test failed
|
||||
*/
|
||||
|
@ -258,10 +245,10 @@ public abstract class AbstractGenericTest extends AbstractGTest {
|
|||
}
|
||||
|
||||
/**
|
||||
* A convenience method to change the log level of the given logger name. The logger name is
|
||||
* typically the class name that contains specialized logging. You may also pass a package
|
||||
* name to get logging for all classes in that package.
|
||||
* See {@link Configurator#setLevel(String, Level)}
|
||||
* A convenience method to change the log level of the given logger name. The logger name is
|
||||
* typically the class name that contains specialized logging. You may also pass a package name
|
||||
* to get logging for all classes in that package. See
|
||||
* {@link Configurator#setLevel(String, Level)}
|
||||
* <P>
|
||||
* The console appender's log level will be changed if needed to ensure that messages for the
|
||||
* given log level are displayed.
|
||||
|
@ -316,9 +303,8 @@ public abstract class AbstractGenericTest extends AbstractGTest {
|
|||
* Returns the window parent of c. If c is a window, then c is returned.
|
||||
*
|
||||
* <P>
|
||||
* Warning: this differs from
|
||||
* {@link SwingUtilities#windowForComponent(Component)} in that the latter
|
||||
* method will not return the given component if it is a window.
|
||||
* Warning: this differs from {@link SwingUtilities#windowForComponent(Component)} in that the
|
||||
* latter method will not return the given component if it is a window.
|
||||
*
|
||||
* @param c the component
|
||||
* @return the window
|
||||
|
@ -328,8 +314,8 @@ public abstract class AbstractGenericTest extends AbstractGTest {
|
|||
}
|
||||
|
||||
/**
|
||||
* Load a text resource file into an ArrayList. Each line of the file is
|
||||
* stored as an item in the list.
|
||||
* Load a text resource file into an ArrayList. Each line of the file is stored as an item in
|
||||
* the list.
|
||||
*
|
||||
* @param cls class where resource exists
|
||||
* @param name resource filename
|
||||
|
@ -372,15 +358,14 @@ public abstract class AbstractGenericTest extends AbstractGTest {
|
|||
}
|
||||
|
||||
/**
|
||||
* Returns the file within the data directory of the TestResources module
|
||||
* that matches the given relative path
|
||||
* Returns the file within the data directory of the TestResources module that matches the given
|
||||
* relative path
|
||||
* <p>
|
||||
* A {@link FileNotFoundException} is throw if the file does not exist.
|
||||
*
|
||||
* @param path path relative to the data directory of the TestResources
|
||||
* module.
|
||||
* @return the file within the data directory of the TestResources module
|
||||
* that matches the given relative path
|
||||
* @param path path relative to the data directory of the TestResources module.
|
||||
* @return the file within the data directory of the TestResources module that matches the given
|
||||
* relative path
|
||||
* @throws FileNotFoundException if the given file does not exist
|
||||
*/
|
||||
public static File getTestDataFile(String path) throws FileNotFoundException {
|
||||
|
@ -390,8 +375,8 @@ public abstract class AbstractGenericTest extends AbstractGTest {
|
|||
}
|
||||
|
||||
/**
|
||||
* Returns a file that points to the location on disk of the given relative
|
||||
* path name. The path is relative to the test resources directory.
|
||||
* Returns a file that points to the location on disk of the given relative path name. The path
|
||||
* is relative to the test resources directory.
|
||||
*
|
||||
* @param relativePath the path of the file
|
||||
* @return a file that points to the location on disk of the relative path.
|
||||
|
@ -406,15 +391,14 @@ public abstract class AbstractGenericTest extends AbstractGTest {
|
|||
}
|
||||
|
||||
/**
|
||||
* Returns the file within the data directory of the TestResources module
|
||||
* that matches the given relative path.
|
||||
* Returns the file within the data directory of the TestResources module that matches the given
|
||||
* relative path.
|
||||
* <p>
|
||||
* Null is returned if the file could not be found.
|
||||
*
|
||||
* @param path path relative to the data directory of the TestResources
|
||||
* module.
|
||||
* @return the file within the data directory of the TestResources module
|
||||
* that matches the given relative path
|
||||
* @param path path relative to the data directory of the TestResources module.
|
||||
* @return the file within the data directory of the TestResources module that matches the given
|
||||
* relative path
|
||||
*/
|
||||
public static File findTestDataFile(String path) {
|
||||
try {
|
||||
|
@ -445,9 +429,9 @@ public abstract class AbstractGenericTest extends AbstractGTest {
|
|||
}
|
||||
|
||||
/**
|
||||
* Get the first field object contained within object ownerInstance which
|
||||
* has the type classType. This method is only really useful if it is known
|
||||
* that only a single field of classType exists within the ownerInstance.
|
||||
* Get the first field object contained within object ownerInstance which has the type
|
||||
* classType. This method is only really useful if it is known that only a single field of
|
||||
* classType exists within the ownerInstance.
|
||||
*
|
||||
* @param <T> the type
|
||||
* @param classType the class type of the desired field
|
||||
|
@ -461,17 +445,15 @@ public abstract class AbstractGenericTest extends AbstractGTest {
|
|||
/**
|
||||
* Sets the instance field by the given name on the given object instance.
|
||||
* <p>
|
||||
* Note: if the field is static, then the <code>ownerInstance</code> field can
|
||||
* be the class of the object that contains the variable.
|
||||
* Note: if the field is static, then the <code>ownerInstance</code> field can be the class of
|
||||
* the object that contains the variable.
|
||||
*
|
||||
* @param fieldName The name of the field to retrieve.
|
||||
* @param ownerInstance The object instance from which to get the variable
|
||||
* instance.
|
||||
* @param ownerInstance The object instance from which to get the variable instance.
|
||||
* @param value The value to use when setting the given field
|
||||
* @throws RuntimeException if there is a problem accessing the field using
|
||||
* reflection. A RuntimeException is used so that calling tests
|
||||
* can avoid using a try/catch block, but will still fail when
|
||||
* an error is encountered.
|
||||
* @throws RuntimeException if there is a problem accessing the field using reflection. A
|
||||
* RuntimeException is used so that calling tests can avoid using a try/catch block,
|
||||
* but will still fail when an error is encountered.
|
||||
* @see Field#set(Object, Object)
|
||||
*/
|
||||
public static void setInstanceField(String fieldName, Object ownerInstance, Object value)
|
||||
|
@ -480,20 +462,18 @@ public abstract class AbstractGenericTest extends AbstractGTest {
|
|||
}
|
||||
|
||||
/**
|
||||
* Gets the instance field by the given name on the given object instance.
|
||||
* The value is a primitive wrapper if it is a primitive type.
|
||||
* Gets the instance field by the given name on the given object instance. The value is a
|
||||
* primitive wrapper if it is a primitive type.
|
||||
* <p>
|
||||
* Note: if the field is static, then the <code>ownerInstance</code> field can
|
||||
* be the class of the object that contains the variable.
|
||||
* Note: if the field is static, then the <code>ownerInstance</code> field can be the class of
|
||||
* the object that contains the variable.
|
||||
*
|
||||
* @param fieldName The name of the field to retrieve.
|
||||
* @param ownerInstance The object instance from which to get the variable
|
||||
* instance.
|
||||
* @param ownerInstance The object instance from which to get the variable instance.
|
||||
* @return The field instance.
|
||||
* @throws RuntimeException if there is a problem accessing the field using
|
||||
* reflection. A RuntimeException is used so that calling tests
|
||||
* can avoid using a try/catch block, but will still fail when
|
||||
* an error is encountered.
|
||||
* @throws RuntimeException if there is a problem accessing the field using reflection. A
|
||||
* RuntimeException is used so that calling tests can avoid using a try/catch block,
|
||||
* but will still fail when an error is encountered.
|
||||
* @see Field#get(java.lang.Object)
|
||||
* @since Tracker Id 267
|
||||
*/
|
||||
|
@ -503,22 +483,19 @@ public abstract class AbstractGenericTest extends AbstractGTest {
|
|||
}
|
||||
|
||||
/**
|
||||
* Uses reflection to execute the constructor for the given class with the
|
||||
* given parameters. The new instance of the given class will be returned.
|
||||
* Uses reflection to execute the constructor for the given class with the given parameters. The
|
||||
* new instance of the given class will be returned.
|
||||
* <p>
|
||||
*
|
||||
* @param containingClass The class that contains the desired constructor.
|
||||
* @param parameterTypes The parameter <b>types</b> that the constructor
|
||||
* takes. This value can be null or zero length if there are no
|
||||
* parameters to pass
|
||||
* @param args The parameter values that should be passed to the
|
||||
* constructor. This value can be null or zero length if there
|
||||
* are no parameters to pass
|
||||
* @param parameterTypes The parameter <b>types</b> that the constructor takes. This value can
|
||||
* be null or zero length if there are no parameters to pass
|
||||
* @param args The parameter values that should be passed to the constructor. This value can be
|
||||
* null or zero length if there are no parameters to pass
|
||||
* @return The new class instance
|
||||
* @throws RuntimeException if there is a problem accessing the constructor
|
||||
* using reflection. A RuntimeException is used so that calling
|
||||
* tests can avoid using a try/catch block, but will still fail
|
||||
* when an error is encountered.
|
||||
* @throws RuntimeException if there is a problem accessing the constructor using reflection. A
|
||||
* RuntimeException is used so that calling tests can avoid using a try/catch block,
|
||||
* but will still fail when an error is encountered.
|
||||
*/
|
||||
public static Object invokeConstructor(Class<?> containingClass, Class<?>[] parameterTypes,
|
||||
Object[] args) throws RuntimeException {
|
||||
|
@ -527,26 +504,23 @@ public abstract class AbstractGenericTest extends AbstractGTest {
|
|||
}
|
||||
|
||||
/**
|
||||
* Uses reflection to execute the method denoted by the given method name.
|
||||
* If any value is returned from the method execution, then it will be
|
||||
* returned from this method. Otherwise, <code>null</code> is returned.
|
||||
* Uses reflection to execute the method denoted by the given method name. If any value is
|
||||
* returned from the method execution, then it will be returned from this method. Otherwise,
|
||||
* <code>null</code> is returned.
|
||||
* <p>
|
||||
* Note: if the method is static, then the <code>ownerInstance</code> field can
|
||||
* be the class of the object that contains the method.
|
||||
* Note: if the method is static, then the <code>ownerInstance</code> field can be the class of
|
||||
* the object that contains the method.
|
||||
*
|
||||
* @param methodName The name of the method to execute.
|
||||
* @param ownerInstance The object instance of which the method will be
|
||||
* executed.
|
||||
* @param ownerInstance The object instance of which the method will be executed.
|
||||
* @param parameterTypes The parameter <b>types</b> that the method takes.
|
||||
* @param args The parameter values that should be passed to the method.
|
||||
* This value can be null or zero length if there are no
|
||||
* parameters to pass
|
||||
* @param args The parameter values that should be passed to the method. This value can be null
|
||||
* or zero length if there are no parameters to pass
|
||||
* @return The return value as returned from executing the method.
|
||||
* @see Method#invoke(java.lang.Object, java.lang.Object[])
|
||||
* @throws RuntimeException if there is a problem accessing the field using
|
||||
* reflection. A RuntimeException is used so that calling tests
|
||||
* can avoid using a try/catch block, but will still fail when
|
||||
* an error is encountered.
|
||||
* @throws RuntimeException if there is a problem accessing the field using reflection. A
|
||||
* RuntimeException is used so that calling tests can avoid using a try/catch block,
|
||||
* but will still fail when an error is encountered.
|
||||
* @since Tracker Id 267
|
||||
*/
|
||||
public static Object invokeInstanceMethod(String methodName, Object ownerInstance,
|
||||
|
@ -557,19 +531,16 @@ public abstract class AbstractGenericTest extends AbstractGTest {
|
|||
|
||||
/**
|
||||
* This method is just a "pass through" method for
|
||||
* {@link #invokeInstanceMethod(String, Object, Class[], Object[])} so that
|
||||
* callers do not need to pass null to that method when the underlying
|
||||
* instance method does not have any parameters.
|
||||
* {@link #invokeInstanceMethod(String, Object, Class[], Object[])} so that callers do not need
|
||||
* to pass null to that method when the underlying instance method does not have any parameters.
|
||||
*
|
||||
* @param methodName The name of the method to execute.
|
||||
* @param ownerInstance The object instance of which the method will be
|
||||
* executed.
|
||||
* @param ownerInstance The object instance of which the method will be executed.
|
||||
* @return The return value as returned from executing the method.
|
||||
* @see Method#invoke(java.lang.Object, java.lang.Object[])
|
||||
* @throws RuntimeException if there is a problem accessing the field using
|
||||
* reflection. A RuntimeException is used so that calling tests
|
||||
* can avoid using a try/catch block, but will still fail when
|
||||
* an error is encountered.
|
||||
* @throws RuntimeException if there is a problem accessing the field using reflection. A
|
||||
* RuntimeException is used so that calling tests can avoid using a try/catch block,
|
||||
* but will still fail when an error is encountered.
|
||||
* @see #invokeInstanceMethod(String, Object, Class[], Object[])
|
||||
*/
|
||||
public static Object invokeInstanceMethod(String methodName, Object ownerInstance)
|
||||
|
@ -578,8 +549,8 @@ public abstract class AbstractGenericTest extends AbstractGTest {
|
|||
}
|
||||
|
||||
/**
|
||||
* Returns a string which is a printout of a stack trace for each thread
|
||||
* running in the current JVM
|
||||
* Returns a string which is a printout of a stack trace for each thread running in the current
|
||||
* JVM
|
||||
*
|
||||
* @return the stack trace string
|
||||
*/
|
||||
|
@ -588,8 +559,7 @@ public abstract class AbstractGenericTest extends AbstractGTest {
|
|||
}
|
||||
|
||||
/**
|
||||
* Prints the contents of the given collection by way of the
|
||||
* {@link Object#toString()} method.
|
||||
* Prints the contents of the given collection by way of the {@link Object#toString()} method.
|
||||
*
|
||||
* @param collection The contents of which to print
|
||||
* @return A string representation of the given collection
|
||||
|
@ -616,6 +586,7 @@ public abstract class AbstractGenericTest extends AbstractGTest {
|
|||
|
||||
/**
|
||||
* Returns a font metrics for the given font using a generic buffered image graphics context.
|
||||
*
|
||||
* @param font the font
|
||||
* @return the font metrics
|
||||
*/
|
||||
|
@ -628,10 +599,10 @@ public abstract class AbstractGenericTest extends AbstractGTest {
|
|||
}
|
||||
|
||||
/**
|
||||
* Signals that the client expected the System Under Test (SUT) to report errors. Use this
|
||||
* when you wish to verify that errors are reported and you do not want those errors to
|
||||
* fail the test. The default value for this setting is false, which means that any
|
||||
* errors reported will fail the running test.
|
||||
* Signals that the client expected the System Under Test (SUT) to report errors. Use this when
|
||||
* you wish to verify that errors are reported and you do not want those errors to fail the
|
||||
* test. The default value for this setting is false, which means that any errors reported will
|
||||
* fail the running test.
|
||||
*
|
||||
* @param expected true if errors are expected.
|
||||
*/
|
||||
|
@ -651,12 +622,12 @@ public abstract class AbstractGenericTest extends AbstractGTest {
|
|||
//==================================================================================================
|
||||
|
||||
/**
|
||||
* Returns the directory into which tests can write debug files, such as
|
||||
* files containing print statements or image files.
|
||||
* Returns the directory into which tests can write debug files, such as files containing print
|
||||
* statements or image files.
|
||||
*
|
||||
* <P>
|
||||
* This is not a temporary directory that will be deleted between tests,
|
||||
* which is useful in that the debug files will persist after a test run.
|
||||
* This is not a temporary directory that will be deleted between tests, which is useful in that
|
||||
* the debug files will persist after a test run.
|
||||
*
|
||||
* <P>
|
||||
* Examples of this directory:
|
||||
|
@ -701,16 +672,14 @@ public abstract class AbstractGenericTest extends AbstractGTest {
|
|||
}
|
||||
|
||||
/**
|
||||
* Creates a <b>sub-directory</b> with the given name as a child of the Java
|
||||
* temp directory. The given name will be the prefix of the new directory
|
||||
* name, with any additional text as created by
|
||||
* {@link Files#createTempDirectory(Path, String, java.nio.file.attribute.FileAttribute...)}.
|
||||
* Any left-over test directories will be cleaned-up before creating the new
|
||||
* directory.
|
||||
* Creates a <b>sub-directory</b> with the given name as a child of the Java temp directory. The
|
||||
* given name will be the prefix of the new directory name, with any additional text as created
|
||||
* by {@link Files#createTempDirectory(Path, String, java.nio.file.attribute.FileAttribute...)}.
|
||||
* Any left-over test directories will be cleaned-up before creating the new directory.
|
||||
*
|
||||
* <p>
|
||||
* Note: you should not call this method multiple times, as each call will
|
||||
* cleanup the previously created directories.
|
||||
* Note: you should not call this method multiple times, as each call will cleanup the
|
||||
* previously created directories.
|
||||
*
|
||||
* @param name the name of the directory to create
|
||||
* @return the newly created directory
|
||||
|
@ -738,14 +707,13 @@ public abstract class AbstractGenericTest extends AbstractGTest {
|
|||
}
|
||||
|
||||
/**
|
||||
* Creates a file path with a filename that is under the system temp
|
||||
* directory. The path returned will not point to an existing file. The
|
||||
* suffix of the file will be <code>.tmp</code>.
|
||||
* Creates a file path with a filename that is under the system temp directory. The path
|
||||
* returned will not point to an existing file. The suffix of the file will be
|
||||
* <code>.tmp</code>.
|
||||
*
|
||||
* @param name the filename
|
||||
* @return a new file path
|
||||
* @throws IOException if there is any problem ensuring that the created
|
||||
* path is non-existent
|
||||
* @throws IOException if there is any problem ensuring that the created path is non-existent
|
||||
* @see #createTempFilePath(String, String)
|
||||
*/
|
||||
public String createTempFilePath(String name) throws IOException {
|
||||
|
@ -754,16 +722,14 @@ public abstract class AbstractGenericTest extends AbstractGTest {
|
|||
}
|
||||
|
||||
/**
|
||||
* Creates a file path with a filename that is under the system temp
|
||||
* directory. The path returned will not point to an existing file. This
|
||||
* method is the same as {@link #createTempFilePath(String)}, except that
|
||||
* you must provide the extension.
|
||||
* Creates a file path with a filename that is under the system temp directory. The path
|
||||
* returned will not point to an existing file. This method is the same as
|
||||
* {@link #createTempFilePath(String)}, except that you must provide the extension.
|
||||
*
|
||||
* @param name the filename
|
||||
* @param extension the file extension
|
||||
* @return a new file path
|
||||
* @throws IOException if there is any problem ensuring that the created
|
||||
* path is non-existent
|
||||
* @throws IOException if there is any problem ensuring that the created path is non-existent
|
||||
* @see #createTempFile(String, String)
|
||||
*/
|
||||
public String createTempFilePath(String name, String extension) throws IOException {
|
||||
|
@ -773,10 +739,10 @@ public abstract class AbstractGenericTest extends AbstractGTest {
|
|||
}
|
||||
|
||||
/**
|
||||
* Creates a temp file for the current test, using the test name as a prefix
|
||||
* for the filename. This method calls {@link #createTempFile(String)},
|
||||
* which will cleanup any pre-existing temp files whose name pattern matches
|
||||
* this test name. This helps to avoid old temp files from accumulating.
|
||||
* Creates a temp file for the current test, using the test name as a prefix for the filename.
|
||||
* This method calls {@link #createTempFile(String)}, which will cleanup any pre-existing temp
|
||||
* files whose name pattern matches this test name. This helps to avoid old temp files from
|
||||
* accumulating.
|
||||
*
|
||||
* @return the new temp file
|
||||
* @throws IOException if there is a problem creating the new file
|
||||
|
@ -786,10 +752,10 @@ public abstract class AbstractGenericTest extends AbstractGTest {
|
|||
}
|
||||
|
||||
/**
|
||||
* Creates a temp file for the current test, using the test name as a prefix
|
||||
* for the filename. This method calls {@link #createTempFile(String)},
|
||||
* which will cleanup any pre-existing temp files whose name pattern matches
|
||||
* this test name. This helps to avoid old temp files from accumulating.
|
||||
* Creates a temp file for the current test, using the test name as a prefix for the filename.
|
||||
* This method calls {@link #createTempFile(String)}, which will cleanup any pre-existing temp
|
||||
* files whose name pattern matches this test name. This helps to avoid old temp files from
|
||||
* accumulating.
|
||||
*
|
||||
* @param suffix the suffix to provide for the temp file
|
||||
* @return the new temp file
|
||||
|
@ -800,15 +766,13 @@ public abstract class AbstractGenericTest extends AbstractGTest {
|
|||
}
|
||||
|
||||
/**
|
||||
* Creates a file in the Application temp directory using the given name as a
|
||||
* prefix and the given suffix. The final filename will also include the
|
||||
* current test name, as well as any data added by
|
||||
* {@link File#createTempFile(String, String, File)}. The file suffix will be
|
||||
* Creates a file in the Application temp directory using the given name as a prefix and the
|
||||
* given suffix. The final filename will also include the current test name, as well as any data
|
||||
* added by {@link File#createTempFile(String, String, File)}. The file suffix will be
|
||||
* <code>.tmp</code>
|
||||
* <p>
|
||||
* The file will be marked to delete on JVM exit. This will not work if the
|
||||
* JVM is taken down the hard way, as when pressing the stop button in
|
||||
* Eclipse.
|
||||
* The file will be marked to delete on JVM exit. This will not work if the JVM is taken down
|
||||
* the hard way, as when pressing the stop button in Eclipse.
|
||||
*
|
||||
* @param name the prefix to put on the file, before the test name
|
||||
* @return the newly created file
|
||||
|
@ -821,25 +785,22 @@ public abstract class AbstractGenericTest extends AbstractGTest {
|
|||
}
|
||||
|
||||
/**
|
||||
* Creates a file in the Application temp directory using the given name as a
|
||||
* prefix and the given suffix. The final filename will also include the
|
||||
* current test name, as well as any data added by
|
||||
* {@link File#createTempFile(String, String, File)}.
|
||||
* Creates a file in the Application temp directory using the given name as a prefix and the
|
||||
* given suffix. The final filename will also include the current test name, as well as any data
|
||||
* added by {@link File#createTempFile(String, String, File)}.
|
||||
* <p>
|
||||
* The file will be marked to delete on JVM exit. This will not work if the
|
||||
* JVM is taken down the hard way, as when pressing the stop button in
|
||||
* Eclipse.
|
||||
* The file will be marked to delete on JVM exit. This will not work if the JVM is taken down
|
||||
* the hard way, as when pressing the stop button in Eclipse.
|
||||
* <p>
|
||||
* Note: This method <b>will</b> create the file on disk! If you need the
|
||||
* file to not exist, then you must delete the file yourself. Alternatively,
|
||||
* you could instead call {@link #createTempFilePath(String, String)}, which
|
||||
* will ensure that the created temp file is deleted.
|
||||
* Note: This method <b>will</b> create the file on disk! If you need the file to not exist,
|
||||
* then you must delete the file yourself. Alternatively, you could instead call
|
||||
* {@link #createTempFilePath(String, String)}, which will ensure that the created temp file is
|
||||
* deleted.
|
||||
*
|
||||
* <p>
|
||||
* Finally, this method will delete any files that match the given name and
|
||||
* suffix values before creating the given temp file. <b>This is important,
|
||||
* as it will delete any files already created by the test that match this
|
||||
* info.</b>
|
||||
* Finally, this method will delete any files that match the given name and suffix values before
|
||||
* creating the given temp file. <b>This is important, as it will delete any files already
|
||||
* created by the test that match this info.</b>
|
||||
*
|
||||
* @param name the prefix to put on the file, before the test name
|
||||
* @param suffix the file suffix
|
||||
|
@ -866,8 +827,7 @@ public abstract class AbstractGenericTest extends AbstractGTest {
|
|||
}
|
||||
|
||||
/**
|
||||
* Delete any files under the Java temp directory that have the given text
|
||||
* in their name.
|
||||
* Delete any files under the Java temp directory that have the given text in their name.
|
||||
*
|
||||
* @param nameText the partial name text to match against the files
|
||||
* @see #deleteMatchingTempFiles(String)
|
||||
|
@ -880,8 +840,8 @@ public abstract class AbstractGenericTest extends AbstractGTest {
|
|||
}
|
||||
|
||||
/**
|
||||
* Delete any files under the this test case's specific temp directory that
|
||||
* match the give regex {@link Pattern}
|
||||
* Delete any files under the this test case's specific temp directory that match the give regex
|
||||
* {@link Pattern}
|
||||
*
|
||||
* @param namePattern the pattern to match against the files
|
||||
* @see #deleteSimilarTempFiles(String)
|
||||
|
|
|
@ -0,0 +1,38 @@
|
|||
/* ###
|
||||
* 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.test.rule;
|
||||
|
||||
import java.lang.annotation.*;
|
||||
|
||||
import ghidra.lifecycle.Unfinished.TODOException;
|
||||
|
||||
/**
|
||||
* Ignore failures due to {@link TODOException}
|
||||
*
|
||||
* <p>
|
||||
* As a matter of practice, tests ought not to be committed into source control with this
|
||||
* annotation. Or, if they are, they should only have this for a short period. Production code ought
|
||||
* not to be throwing {@link TODOException}, anyway, but the reality is, sometimes things are
|
||||
* "production ready," despite having some unfinished components. This annotation allows tests that
|
||||
* identify those unfinished portions to remain active, but ignored. During development, the
|
||||
* developer may also apply this annotation to distinguish "real" failures from those already
|
||||
* identified as "unfinished." The annotation ought to be removed when it's time to finish those
|
||||
* components, so that failures due to unfinished code are quickly identified.
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target({ ElementType.METHOD, ElementType.TYPE })
|
||||
public @interface IgnoreUnfinished {
|
||||
}
|
|
@ -0,0 +1,47 @@
|
|||
/* ###
|
||||
* IP: GHIDRA
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package generic.test.rule;
|
||||
|
||||
import org.junit.Rule;
|
||||
import org.junit.rules.TestRule;
|
||||
import org.junit.runner.Description;
|
||||
import org.junit.runners.model.Statement;
|
||||
|
||||
import generic.test.AbstractGenericTest;
|
||||
|
||||
/**
|
||||
* A test rule which processes the {@link IgnoreUnfinished} annotation
|
||||
*
|
||||
* <p>
|
||||
* This must be included in your test case (or a superclass) as a field with the {@link Rule}
|
||||
* annotation. It's included in the {@link AbstractGenericTest}, so most Ghidra test classes already
|
||||
* have it.
|
||||
*/
|
||||
public class IgnoreUnfinishedRule implements TestRule {
|
||||
@Override
|
||||
public Statement apply(Statement base, Description description) {
|
||||
IgnoreUnfinished annot;
|
||||
annot = description.getAnnotation(IgnoreUnfinished.class);
|
||||
if (annot != null) {
|
||||
return new IgnoreUnfinishedStatement(base);
|
||||
}
|
||||
annot = description.getTestClass().getAnnotation(IgnoreUnfinished.class);
|
||||
if (annot != null) {
|
||||
return new IgnoreUnfinishedStatement(base);
|
||||
}
|
||||
return base;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,44 @@
|
|||
/* ###
|
||||
* 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.test.rule;
|
||||
|
||||
import org.junit.AssumptionViolatedException;
|
||||
import org.junit.runners.model.Statement;
|
||||
|
||||
import ghidra.lifecycle.Unfinished.TODOException;
|
||||
|
||||
/**
|
||||
* A JUnit test statement that ignores {@link TODOException}
|
||||
*
|
||||
* @see IgnoreUnfinished
|
||||
*/
|
||||
public class IgnoreUnfinishedStatement extends Statement {
|
||||
private final Statement base;
|
||||
|
||||
public IgnoreUnfinishedStatement(Statement base) {
|
||||
this.base = base;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void evaluate() throws Throwable {
|
||||
try {
|
||||
base.evaluate();
|
||||
}
|
||||
catch (TODOException e) {
|
||||
throw new AssumptionViolatedException("Unfinished", e);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
/* ###
|
||||
* IP: GHIDRA
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package ghidra.lifecycle;
|
||||
|
||||
import static java.lang.annotation.ElementType.*;
|
||||
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* An annotation for experimental things
|
||||
*
|
||||
* <p>
|
||||
* The items are intended to become part of the public API, but the interfaces are unstable, and
|
||||
* there's no guarantee they will ever become public.
|
||||
*/
|
||||
@Target({ TYPE, FIELD, METHOD, CONSTRUCTOR, ANNOTATION_TYPE, PACKAGE, PARAMETER })
|
||||
public @interface Experimental {
|
||||
}
|
|
@ -0,0 +1,37 @@
|
|||
/* ###
|
||||
* IP: GHIDRA
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package ghidra.lifecycle;
|
||||
|
||||
import static java.lang.annotation.ElementType.*;
|
||||
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* An annotation for things internal to an implementation
|
||||
*
|
||||
* For organization, some interfaces and classes exist in packages outside where they are used, and
|
||||
* method access is required. Java allows those methods to be accessed from any package. This
|
||||
* annotation is applied to public methods which should not be accessed outside the implementation.
|
||||
*
|
||||
* A decent way to manually verify this is to ensure that any method marked with this annotation is
|
||||
* not listed in the exported interface. Generally, this means no method should have both
|
||||
* {@link Override} and {@link Internal} applied.
|
||||
*/
|
||||
@Target({ TYPE, FIELD, METHOD, CONSTRUCTOR, ANNOTATION_TYPE, PACKAGE })
|
||||
public @interface Internal {
|
||||
// TODO: Is it possible to warn when used outside the jar?
|
||||
// TODO: Is it possible to warn when also overrides an interface method?
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
/* ###
|
||||
* IP: GHIDRA
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package ghidra.lifecycle;
|
||||
|
||||
/**
|
||||
* The item is present for transitional purposes only and will soon be removed
|
||||
*/
|
||||
public @interface Transitional {
|
||||
|
||||
}
|
|
@ -0,0 +1,56 @@
|
|||
/* ###
|
||||
* IP: GHIDRA
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package ghidra.lifecycle;
|
||||
|
||||
/**
|
||||
* This serves both as a marker interface for classes missing important methods and as container for
|
||||
* the {@link #TODO(String, Object...)} method.
|
||||
*
|
||||
* <p>
|
||||
* TODO: It'd be nice to optionally ignore TODO exceptions, but this seems to require a dependency
|
||||
* on JUnit, which is a no-no within {@code src/main}. Maybe there's a way via the abstract test
|
||||
* case, or an interface mixin....
|
||||
*/
|
||||
public interface Unfinished {
|
||||
public class TODOException extends UnsupportedOperationException {
|
||||
public TODOException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
public TODOException() {
|
||||
this("TODO");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Perhaps a little better than returning {@code null} or throwing
|
||||
* {@link UnsupportedOperationException} yourself, as references can be found in most IDEs.
|
||||
*
|
||||
* @param message A message describing the task that is yet to be done
|
||||
* @param ignore variables involved in the implementation so far
|
||||
*/
|
||||
static <T> T TODO(String message, Object... ignore) {
|
||||
throw new TODOException(message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Perhaps a little better than returning {@code null} or throwing
|
||||
* {@link UnsupportedOperationException} yourself, as references can be found in most IDEs.
|
||||
*/
|
||||
static <T> T TODO() {
|
||||
throw new TODOException();
|
||||
}
|
||||
}
|
|
@ -15,6 +15,8 @@
|
|||
*/
|
||||
package ghidra.util;
|
||||
|
||||
import java.util.Comparator;
|
||||
|
||||
public class MathUtilities {
|
||||
|
||||
private MathUtilities() {
|
||||
|
@ -204,4 +206,20 @@ public class MathUtilities {
|
|||
public static long unsignedMax(long a, int b) {
|
||||
return (Long.compareUnsigned(a, b & 0x0ffffffffL) > 0) ? a : b;
|
||||
}
|
||||
|
||||
public static <C> C cmin(C a, C b, Comparator<C> comp) {
|
||||
return comp.compare(a, b) <= 0 ? a : b;
|
||||
}
|
||||
|
||||
public static <C extends Comparable<C>> C cmin(C a, C b) {
|
||||
return cmin(a, b, Comparator.naturalOrder());
|
||||
}
|
||||
|
||||
public static <C> C cmax(C a, C b, Comparator<C> comp) {
|
||||
return comp.compare(a, b) >= 0 ? a : b;
|
||||
}
|
||||
|
||||
public static <C extends Comparable<C>> C cmax(C a, C b) {
|
||||
return cmax(a, b, Comparator.naturalOrder());
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue