|Build Status| |PyPI|
A pytest module for The Interactive Disassembler and IDAPython, by executing an internal pytest runner inside IDA or mocking IDAPython functionality outside of IDA.
As the avarage IDAPython plugin size increases, the need of proper unitests becomes more evident. The purpose of this pytest plugin is to ease unittesting IDAPython plugins and scripts and mitigate the gap between Continuous Integration services and the IDA executable (which we are unable to execute in a CI).
The pytest-idapro plugin adds new command line flags to the pytest executable.
All pytest-idapro flags start with :code:--ida
and exist under the
"interactive disassembler testing facilities" category.
The most basic pytest-idapro usage will be using :code:--ida
to execute a
pyteset session within IDA, and the optional :code:--ida-file
flag:
.. code-block:: console
$ pytest --ida
Running the above command will run all tests detected by pytest in the current directory inside an IDA instance with a given IDA supported file (IDB, EXE, SO, etc).
Since version 0.3.5, pytest-idapro has shifted from a mock-up focus to
record-and-replay focus by providing two new command line flags;
:code:--ida-record
will record all IDAPython API calls and IDA's behavior
while running tests into specified json file. Using :code:--ida-replay
and a
json recording file, pytest-idapro is then able to replay the IDA environment
and IDAPython API behavior without an IDA executable or the :code:--ida
flag.
Pytest Fixtures <https://docs.pytest.org/en/latest/fixture.html>
_ are
exteremly powerful when writing tests, and pytest-idapro currently comes with
two helpful fixtures:
idapro_plugin_entry
- pytest-idapro will automatically identify all
ida plugin entry points (functions named :code:PLUGIN_ENTRY
) across your
code base and let you easily writing tests for all plugin objects defined.idapro_action_entry
- pytest-idapro will automatically identify all
ida actions (objects inheriting the :code:action_handler_t
class)
throughout your code and again, let you easily write tests for all of your
actions.By providing the :code:--ida
flag ipytest-idapro will run a worker pytest
instance inside IDA which will execute all tests, collect results and
communicate with the main pytest process (this behavior is somewhat similar to
the pytest-xdist plugin). By defualt IDA will open a temporary empty database
file unless the :code:--ida-file
flag is used to specify IDB or binary file
for IDA to analyze before running any tests.
In order to record API calls, IDA python objects and their interaction, a series of proxy/wrapper objects are created for all IDA implemented python objects (modules, functions, clases, objects, etc). Those proxy objects will behave identically but will register all interaction between executed code and the IDAPython interface, which will eventually be dumped to a JSON file.
For the recording to take place as soon as possible, pytest-idapro will modify IDA's python initialization script (python/init.py). The change is performed just before starting an IDA instance and revereted as soon as possible.
When an IDA API function is called during replaying, the appropriate return value must be returned. This is easy when every function is called once, but is increasingly difficult when the same function is called more then once, and even more so when it's called more than once with the same arguments. To correctly return the right value for every call, all calls are recorded with metadata describing call environment such as the call stack and arguments. Those are then used to match the correct instance of a call or a class instantiation while replaying.
<IDA DIR>/python/init.py
... |Build Status| image:: https://travis-ci.org/nirizr/pytest-idapro.svg?branch=master :alt: Build Status :target: https://travis-ci.org/nirizr/pytest-idapro .. |PyPI| image:: https://img.shields.io/pypi/v/pytest-idapro.svg :alt: PyPI :target: https://pypi.python.org/pypi/pytest-idapro