# binja-test-mocks
[](https://github.com/mblsha/binja-test-mocks/actions/workflows/tests.yml)
[](https://badge.fury.io/py/binja-test-mocks)
[](https://pypi.org/project/binja-test-mocks/)
Mock Binary Ninja API for testing Binary Ninja plugins without requiring a Binary Ninja license.
## Overview
`binja-test-mocks` provides a comprehensive set of mock objects and utilities that allow you to:
- Unit test Binary Ninja plugins without a Binary Ninja installation
- Run type checking with mypy/pyright using accurate type stubs
- Develop and test plugins in CI/CD environments
## Installation
```bash
pip install binja-test-mocks
```
For development:
```bash
pip install -e /path/to/binja-test-mocks
```
## Quick Start
### Basic Usage
```python
# In your test files, set the environment variable before imports
import os
os.environ["FORCE_BINJA_MOCK"] = "1"
# Import the mock API before importing your plugin
from binja_test_mocks import binja_api # noqa: F401
# Now you can import your plugin modules that use Binary Ninja
from your_plugin import YourArchitecture
```
### Example Test
```python
import os
os.environ["FORCE_BINJA_MOCK"] = "1"
from binja_test_mocks import binja_api # noqa: F401
from binja_test_mocks.mock_llil import MockLowLevelILFunction
from your_plugin.arch import MyArchitecture
def test_instruction_lifting():
# Create mock LLIL function
il = MockLowLevelILFunction()
# Test your architecture's IL generation
arch = MyArchitecture()
arch.get_instruction_low_level_il(b"\x90", 0x1000, il)
# Verify the generated IL
assert len(il.operations) == 1
assert il.operations[0].op == "NOP"
```
## Components
### Mock Modules
- **binja_api.py**: Core mock loader that intercepts Binary Ninja imports
- **mock_llil.py**: Mock Low Level IL classes and operations
- **mock_binaryview.py**: Mock BinaryView for testing file format plugins
- **mock_analysis.py**: Mock analysis information (branches, calls, etc.)
- **tokens.py**: Token generation utilities for disassembly
- **coding.py**: Binary encoding/decoding helpers
- **eval_llil.py**: LLIL expression evaluator for testing
### Type Stubs
Complete type stubs for Binary Ninja API in `stubs/binaryninja/`:
- architecture.pyi
- binaryview.pyi
- lowlevelil.pyi
- enums.pyi
- types.pyi
- function.pyi
- log.pyi
- interaction.pyi
## Integration Examples
### Plugin Structure
```python
# your_plugin/__init__.py
import sys
from pathlib import Path
# Add plugin directory to path
plugin_dir = str(Path(__file__).resolve().parent)
if plugin_dir not in sys.path:
sys.path.insert(0, plugin_dir)
# For testing, load mock API
import os
if os.environ.get("FORCE_BINJA_MOCK") == "1":
from binja_test_mocks import binja_api # noqa: F401
# Your normal plugin code
from binaryninja import Architecture
from .arch import MyArchitecture
MyArchitecture.register()
```
### Type Checking Configuration
#### mypy.ini
```ini
[mypy]
mypy_path = /path/to/binja-test-mocks/src/binja_test_mocks/stubs
plugins = mypy_binja_plugin
[mypy-binaryninja.*]
ignore_missing_imports = False
```
#### pyrightconfig.json
```json
{
"extraPaths": [
"/path/to/binja-test-mocks/src/binja_test_mocks/stubs"
],
"typeCheckingMode": "strict"
}
```
### Running Tests
```bash
# Set environment variable and run pytest
FORCE_BINJA_MOCK=1 pytest
# Or use a test runner script
python -m binja_test_mocks.scripts.run_tests
```
## Advanced Usage
### Custom Mock Behavior
```python
from binja_test_mocks.mock_llil import MockLowLevelILFunction
class CustomMockIL(MockLowLevelILFunction):
def __init__(self):
super().__init__()
self.custom_data = []
def append(self, expr):
self.custom_data.append(expr)
return super().append(expr)
```
### Testing Binary Views
```python
from binja_test_mocks.mock_binaryview import MockBinaryView
def test_binary_view_parsing():
data = b"\x4d\x5a\x90\x00" # PE header
bv = MockBinaryView(data)
# Your binary view implementation
my_view = MyBinaryView(bv)
assert my_view.init()
```
## Migration from binja_helpers
If you're migrating from the old `binja_helpers`:
1. Update imports:
```python
# Old
from binja_helpers import binja_api
# New
from binja_test_mocks import binja_api
```
2. Update path additions if needed:
```python
# Old
sys.path.insert(0, str(plugin_dir / "binja_helpers_tmp"))
# New - not needed if installed via pip
```
## Contributing
Contributions are welcome! Please ensure:
- All tests pass with `pytest`
- Type checking passes with `mypy` and `pyright`
- Code is formatted with `ruff`
## License
MIT License - see LICENSE file for details.
Raw data
{
"_id": null,
"home_page": null,
"name": "binja-test-mocks",
"maintainer": null,
"docs_url": null,
"requires_python": ">=3.10",
"maintainer_email": null,
"keywords": "binary ninja, testing, mocks, reverse engineering",
"author": "mblsha",
"author_email": null,
"download_url": "https://files.pythonhosted.org/packages/1e/21/ab1aa17da4e38e32eb16ad3ae0bfd54fca534e0c0cb4699806dd600c9036/binja_test_mocks-0.1.0.tar.gz",
"platform": null,
"description": "# binja-test-mocks\n\n[](https://github.com/mblsha/binja-test-mocks/actions/workflows/tests.yml)\n[](https://badge.fury.io/py/binja-test-mocks)\n[](https://pypi.org/project/binja-test-mocks/)\n\nMock Binary Ninja API for testing Binary Ninja plugins without requiring a Binary Ninja license.\n\n## Overview\n\n`binja-test-mocks` provides a comprehensive set of mock objects and utilities that allow you to:\n- Unit test Binary Ninja plugins without a Binary Ninja installation\n- Run type checking with mypy/pyright using accurate type stubs\n- Develop and test plugins in CI/CD environments\n\n## Installation\n\n```bash\npip install binja-test-mocks\n```\n\nFor development:\n```bash\npip install -e /path/to/binja-test-mocks\n```\n\n## Quick Start\n\n### Basic Usage\n\n```python\n# In your test files, set the environment variable before imports\nimport os\nos.environ[\"FORCE_BINJA_MOCK\"] = \"1\"\n\n# Import the mock API before importing your plugin\nfrom binja_test_mocks import binja_api # noqa: F401\n\n# Now you can import your plugin modules that use Binary Ninja\nfrom your_plugin import YourArchitecture\n```\n\n### Example Test\n\n```python\nimport os\nos.environ[\"FORCE_BINJA_MOCK\"] = \"1\"\n\nfrom binja_test_mocks import binja_api # noqa: F401\nfrom binja_test_mocks.mock_llil import MockLowLevelILFunction\nfrom your_plugin.arch import MyArchitecture\n\ndef test_instruction_lifting():\n # Create mock LLIL function\n il = MockLowLevelILFunction()\n \n # Test your architecture's IL generation\n arch = MyArchitecture()\n arch.get_instruction_low_level_il(b\"\\x90\", 0x1000, il)\n \n # Verify the generated IL\n assert len(il.operations) == 1\n assert il.operations[0].op == \"NOP\"\n```\n\n## Components\n\n### Mock Modules\n\n- **binja_api.py**: Core mock loader that intercepts Binary Ninja imports\n- **mock_llil.py**: Mock Low Level IL classes and operations\n- **mock_binaryview.py**: Mock BinaryView for testing file format plugins\n- **mock_analysis.py**: Mock analysis information (branches, calls, etc.)\n- **tokens.py**: Token generation utilities for disassembly\n- **coding.py**: Binary encoding/decoding helpers\n- **eval_llil.py**: LLIL expression evaluator for testing\n\n### Type Stubs\n\nComplete type stubs for Binary Ninja API in `stubs/binaryninja/`:\n- architecture.pyi\n- binaryview.pyi\n- lowlevelil.pyi\n- enums.pyi\n- types.pyi\n- function.pyi\n- log.pyi\n- interaction.pyi\n\n## Integration Examples\n\n### Plugin Structure\n\n```python\n# your_plugin/__init__.py\nimport sys\nfrom pathlib import Path\n\n# Add plugin directory to path\nplugin_dir = str(Path(__file__).resolve().parent)\nif plugin_dir not in sys.path:\n sys.path.insert(0, plugin_dir)\n\n# For testing, load mock API\nimport os\nif os.environ.get(\"FORCE_BINJA_MOCK\") == \"1\":\n from binja_test_mocks import binja_api # noqa: F401\n\n# Your normal plugin code\nfrom binaryninja import Architecture\nfrom .arch import MyArchitecture\n\nMyArchitecture.register()\n```\n\n### Type Checking Configuration\n\n#### mypy.ini\n```ini\n[mypy]\nmypy_path = /path/to/binja-test-mocks/src/binja_test_mocks/stubs\nplugins = mypy_binja_plugin\n\n[mypy-binaryninja.*]\nignore_missing_imports = False\n```\n\n#### pyrightconfig.json\n```json\n{\n \"extraPaths\": [\n \"/path/to/binja-test-mocks/src/binja_test_mocks/stubs\"\n ],\n \"typeCheckingMode\": \"strict\"\n}\n```\n\n### Running Tests\n\n```bash\n# Set environment variable and run pytest\nFORCE_BINJA_MOCK=1 pytest\n\n# Or use a test runner script\npython -m binja_test_mocks.scripts.run_tests\n```\n\n## Advanced Usage\n\n### Custom Mock Behavior\n\n```python\nfrom binja_test_mocks.mock_llil import MockLowLevelILFunction\n\nclass CustomMockIL(MockLowLevelILFunction):\n def __init__(self):\n super().__init__()\n self.custom_data = []\n \n def append(self, expr):\n self.custom_data.append(expr)\n return super().append(expr)\n```\n\n### Testing Binary Views\n\n```python\nfrom binja_test_mocks.mock_binaryview import MockBinaryView\n\ndef test_binary_view_parsing():\n data = b\"\\x4d\\x5a\\x90\\x00\" # PE header\n bv = MockBinaryView(data)\n \n # Your binary view implementation\n my_view = MyBinaryView(bv)\n assert my_view.init()\n```\n\n## Migration from binja_helpers\n\nIf you're migrating from the old `binja_helpers`:\n\n1. Update imports:\n ```python\n # Old\n from binja_helpers import binja_api\n \n # New\n from binja_test_mocks import binja_api\n ```\n\n2. Update path additions if needed:\n ```python\n # Old\n sys.path.insert(0, str(plugin_dir / \"binja_helpers_tmp\"))\n \n # New - not needed if installed via pip\n ```\n\n## Contributing\n\nContributions are welcome! Please ensure:\n- All tests pass with `pytest`\n- Type checking passes with `mypy` and `pyright`\n- Code is formatted with `ruff`\n\n## License\n\nMIT License - see LICENSE file for details.\n",
"bugtrack_url": null,
"license": "MIT",
"summary": "Mock Binary Ninja API for testing Binary Ninja plugins without requiring a license",
"version": "0.1.0",
"project_urls": {
"Homepage": "https://github.com/mblsha/binja-test-mocks",
"Issues": "https://github.com/mblsha/binja-test-mocks/issues",
"Repository": "https://github.com/mblsha/binja-test-mocks"
},
"split_keywords": [
"binary ninja",
" testing",
" mocks",
" reverse engineering"
],
"urls": [
{
"comment_text": null,
"digests": {
"blake2b_256": "8d6c9d4d082970219ad5ea97fade58abd4a6247647ddf51f1600828492527b6b",
"md5": "7f642ad39425442549027b12cb6fc897",
"sha256": "621f5504b6bfd43ca31adb33e0ca1959b06860176eb256e4cf2be7692533fbb6"
},
"downloads": -1,
"filename": "binja_test_mocks-0.1.0-py3-none-any.whl",
"has_sig": false,
"md5_digest": "7f642ad39425442549027b12cb6fc897",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": ">=3.10",
"size": 25127,
"upload_time": "2025-07-19T10:36:10",
"upload_time_iso_8601": "2025-07-19T10:36:10.829287Z",
"url": "https://files.pythonhosted.org/packages/8d/6c/9d4d082970219ad5ea97fade58abd4a6247647ddf51f1600828492527b6b/binja_test_mocks-0.1.0-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": null,
"digests": {
"blake2b_256": "1e21ab1aa17da4e38e32eb16ad3ae0bfd54fca534e0c0cb4699806dd600c9036",
"md5": "9b49156cc89fe5b6f17b018b773f8106",
"sha256": "4924cbdd6827f627d393ecfda5a0cb4661e63cf8db2071d14831c42aace5ec07"
},
"downloads": -1,
"filename": "binja_test_mocks-0.1.0.tar.gz",
"has_sig": false,
"md5_digest": "9b49156cc89fe5b6f17b018b773f8106",
"packagetype": "sdist",
"python_version": "source",
"requires_python": ">=3.10",
"size": 22223,
"upload_time": "2025-07-19T10:36:12",
"upload_time_iso_8601": "2025-07-19T10:36:12.380711Z",
"url": "https://files.pythonhosted.org/packages/1e/21/ab1aa17da4e38e32eb16ad3ae0bfd54fca534e0c0cb4699806dd600c9036/binja_test_mocks-0.1.0.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2025-07-19 10:36:12",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "mblsha",
"github_project": "binja-test-mocks",
"travis_ci": false,
"coveralls": false,
"github_actions": true,
"lcname": "binja-test-mocks"
}