about summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--README.md7
-rw-r--r--optional_requirements.txt1
-rwxr-xr-xtest/test_all.py67
3 files changed, 68 insertions, 7 deletions
diff --git a/README.md b/README.md
index 07e1d8e6..50b8de59 100644
--- a/README.md
+++ b/README.md
@@ -583,7 +583,14 @@ Miasm comes with a set of regression tests. To run all of them:
 
 ```pycon
 cd miasm_directory/test
+
+# Run tests using our own test runner
 python test_all.py
+
+# Run tests using standard frameworks (slower, require 'parameterized')
+python -m unittest test_all.py        # sequential, requires 'unittest'
+python -m pytest test_all.py          # sequential, requires 'pytest'
+python -m pytest -n auto test_all.py  # parallel, requires 'pytest' and 'pytest-xdist'
 ```
 
 Some options can be specified:
diff --git a/optional_requirements.txt b/optional_requirements.txt
index 39d92a93..e8e1782c 100644
--- a/optional_requirements.txt
+++ b/optional_requirements.txt
@@ -1,3 +1,4 @@
 pycparser
 z3-solver==4.8.7.0
 llvmlite==0.31.0
+parameterized~=0.8.1
diff --git a/test/test_all.py b/test/test_all.py
index 1ec49324..2d078bf1 100755
--- a/test/test_all.py
+++ b/test/test_all.py
@@ -1,20 +1,23 @@
 #! /usr/bin/env python2
 
 from __future__ import print_function
-from builtins import map
-from builtins import range
+
 import argparse
-from distutils.spawn import find_executable
 import os
 import platform
-import time
+import subprocess
+import sys
 import tempfile
-import platform
+import time
+import unittest
+from builtins import map
+from builtins import range
+
+from parameterized import parameterized
 
+from utils import cosmetics, multithread
 from utils.test import Test
 from utils.testset import TestSet
-from utils import cosmetics, multithread
-from multiprocessing import Queue
 
 is_win = platform.system() == "Windows"
 is_64bit = platform.architecture()[0] == "64bit"
@@ -847,6 +850,56 @@ testset += RegressionTest(["launch.py"], base_dir="arch/mep/asm")
 testset += RegressionTest(["launch.py"], base_dir="arch/mep/ir")
 testset += RegressionTest(["launch.py"], base_dir="arch/mep/jit")
 
+
+# region Unittest compatibility
+
+class TestSequence(unittest.TestCase):
+    # Compatibility layer for Python's unittest module
+    # Instead of calling the '__main__' defined below, we parameterize a single test with all the tests selected in
+    # testset, and run them as we would have.
+
+    tests = testset.tests
+    tests_without_shellcodes = (t for t in tests if "shellcode.py" not in t.command_line[0])
+
+    @staticmethod
+    def run_process(t):
+        """
+        @type t: Test
+        """
+        print("Base dir:", t.base_dir)
+        print("Command: ", t.command_line)
+        print("Depends: ", [t.command_line for t in t.depends])
+        print("Tags:    ", t.tags)
+        print("Products:", t.products)
+        executable = t.executable if t.executable else sys.executable
+        print("Exec:    ", executable, "(explicit)" if t.executable else "(default)")
+
+        for t in t.depends:
+            assert "shellcode.py" in t.command_line[0], "At the moment, only dependencies on 'shellcode.py' are handled"
+
+        subprocess.check_call(
+            [executable] + t.command_line,
+            cwd=testset.base_dir + t.base_dir,
+        )
+
+        print("Done")
+
+    @classmethod
+    def setUpClass(cls):
+        for t in testset.tests:
+            if "shellcode.py" in t.command_line[0]:
+                print("\n*** Shellcode generation ***")
+                cls.run_process(t)
+
+    @parameterized.expand(("_".join(test.command_line), test) for test in tests_without_shellcodes)
+    def test(self, name, t):
+        print("***", name, "***")
+        TestSequence.run_process(t)
+
+
+# endregion
+
+
 if __name__ == "__main__":
     # Argument parsing
     parser = argparse.ArgumentParser(description="Miasm2 testing tool")