From 240be214ff239622b104775241b3b5d06da7cc02 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexandre=20C=C3=B4t=C3=A9?= Date: Wed, 10 Apr 2024 12:05:00 -0400 Subject: [PATCH] Parse names without _u suffix and add tests. --- README.md | 5 +++++ nimfilt.py | 4 ++-- test/test_names.py | 51 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 58 insertions(+), 2 deletions(-) create mode 100644 test/test_names.py diff --git a/README.md b/README.md index 0dfe2d3..bf05d4c 100644 --- a/README.md +++ b/README.md @@ -38,6 +38,11 @@ Navigate to Edit -> Plugins -> Nimfilt and click on it. You can set Nimfilt to automatically execute when a loaded file is recognized as a Nim binary. To do so, set the `AUTO_RUN` global variable to `True` in `nimfilt_ida.py` +## Running tests + +Nimfilt uses the [unittest](https://docs.python.org/3/library/unittest.html) package from the Python standard library for unit testing. You can run the test suite using the following command: `python -m unittest test/*.py`. + + ## Features Current features include: diff --git a/nimfilt.py b/nimfilt.py index 070fde9..d0de3d0 100755 --- a/nimfilt.py +++ b/nimfilt.py @@ -161,12 +161,12 @@ def demangle_function(name: str) -> str: class NimName(): def __init__(self, namestr): # ___u_.@ - m = re.fullmatch(r'@?([a-zA-Z0-9_]+_?)__(.*)(_u[0-9]+)(_[0-9]+)?(\.[a-z]+\.[0-9]+)?(@[0-9]+)?', namestr) + m = re.fullmatch(r'@?([a-zA-Z0-9_]+_?)__([^@_]+)(_u[0-9]+)?(_[0-9]+)?(\.[a-z]+\.[0-9]+)?(@[0-9]+)?', namestr) if m is None or len(m.group(1)) <= 1: raise ValueError("Invalid Nim function name \"{}\"".format(namestr)) self.fnname = demangle_function(m.group(1)) self.pkgname = demangle_module(m.group(2)) - self.suffix = m.group(3)[1:] + self.suffix = None if m.group(3) is None else m.group(3)[1:] self.ida_suffix = m.group(4) self.num_args = m.group(6) diff --git a/test/test_names.py b/test/test_names.py new file mode 100644 index 0000000..b25d14d --- /dev/null +++ b/test/test_names.py @@ -0,0 +1,51 @@ +import unittest +import nimfilt + +class TestNameParsing(unittest.TestCase): + def test_simple_name(self): + n = nimfilt.NimName("@add__system_u2308@8") + self.assertTrue(n.is_std()) + self.assertEqual(n.fnname, "add") + self.assertEqual(n.pkgname, "system") + self.assertEqual(n.suffix, "u2308") + self.assertIsNone(n.ida_suffix) + self.assertEqual(n.num_args, "@8") + + def test_name_all_fields(self): + n = nimfilt.NimName("@add__system_u2308_1.link.88@16") + self.assertTrue(n.is_std()) + self.assertEqual(n.fnname, "add") + self.assertEqual(n.pkgname, "system") + self.assertEqual(n.suffix, "u2308") + self.assertEqual(n.ida_suffix, "_1") + self.assertEqual(n.num_args, "@16") + + def test_init_name(self): + n = nimfilt.NimInitName("@atmlibatssystemdotnim_Init000@0") + self.assertTrue(n.is_std) + self.assertEqual(n.fnname, "Init000") + self.assertEqual(n.pkgname, "lib/system") + self.assertIsNone(n.suffix) + self.assertIsNone(n.ida_suffix) + self.assertEqual(n.num_args, "@0") + + def test_wrong_name(self): + with self.assertRaises(ValueError): + nimfilt.NimName("____w64_mingwthr_remove_key_dtor") + with self.assertRaises(ValueError): + nimfilt.NimName("@atmlibatssystemdotnim_Init000@0") + + with self.assertRaises(ValueError): + nimfilt.NimInitName("____w64_mingwthr_remove_key_dtor") + with self.assertRaises(ValueError): + nimfilt.NimInitName("@add__system_u2308@8") + +class TestDemangling(unittest.TestCase): + def test_func_name(self): + n = nimfilt.NimName("@eqdestroy___stdZ80rivateZntpath_u119@4") + self.assertEqual(n.fnname, "=destroy") + self.assertEqual(n.pkgname, "std/Private/ntpath") + + +if __name__ == "__main__": + unittest.main()