test_pybind_wrapper.py 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157
  1. """
  2. Unit test for Pybind wrap program
  3. Author: Matthew Sklar, Varun Agrawal
  4. Date: February 2019
  5. """
  6. # pylint: disable=import-error, wrong-import-position, too-many-branches
  7. import filecmp
  8. import os
  9. import os.path as osp
  10. import sys
  11. import unittest
  12. sys.path.append(osp.dirname(osp.dirname(osp.abspath(__file__))))
  13. sys.path.append(
  14. osp.normpath(osp.abspath(osp.join(__file__, '../../../build/wrap'))))
  15. from gtwrap.pybind_wrapper import PybindWrapper
  16. sys.path.append(osp.dirname(osp.dirname(osp.abspath(__file__))))
  17. class TestWrap(unittest.TestCase):
  18. """Tests for Python wrapper based on Pybind11."""
  19. TEST_DIR = osp.dirname(osp.realpath(__file__))
  20. INTERFACE_DIR = osp.join(TEST_DIR, 'fixtures')
  21. PYTHON_TEST_DIR = osp.join(TEST_DIR, 'expected', 'python')
  22. PYTHON_ACTUAL_DIR = osp.join(TEST_DIR, "actual", "python")
  23. # Create the `actual/python` directory
  24. os.makedirs(PYTHON_ACTUAL_DIR, exist_ok=True)
  25. def wrap_content(self, sources, module_name, output_dir):
  26. """
  27. Common function to wrap content in `sources`.
  28. """
  29. with open(osp.join(self.TEST_DIR,
  30. "pybind_wrapper.tpl")) as template_file:
  31. module_template = template_file.read()
  32. # Create Pybind wrapper instance
  33. wrapper = PybindWrapper(module_name=module_name,
  34. use_boost=False,
  35. top_module_namespaces=[''],
  36. ignore_classes=[''],
  37. module_template=module_template)
  38. output = osp.join(self.TEST_DIR, output_dir, module_name + ".cpp")
  39. if not osp.exists(osp.join(self.TEST_DIR, output_dir)):
  40. os.mkdir(osp.join(self.TEST_DIR, output_dir))
  41. wrapper.wrap(sources, output)
  42. return output
  43. def compare_and_diff(self, file, actual):
  44. """
  45. Compute the comparison between the expected and actual file,
  46. and assert if diff is zero.
  47. """
  48. expected = osp.join(self.PYTHON_TEST_DIR, file)
  49. success = filecmp.cmp(actual, expected)
  50. if not success:
  51. os.system("diff {} {}".format(actual, expected))
  52. self.assertTrue(success, "Mismatch for file {0}".format(file))
  53. def test_geometry(self):
  54. """
  55. Check generation of python geometry wrapper.
  56. python3 ../pybind_wrapper.py --src geometry.h --module_name
  57. geometry_py --out output/geometry_py.cc
  58. """
  59. source = osp.join(self.INTERFACE_DIR, 'geometry.i')
  60. output = self.wrap_content([source], 'geometry_py',
  61. self.PYTHON_ACTUAL_DIR)
  62. self.compare_and_diff('geometry_pybind.cpp', output)
  63. def test_functions(self):
  64. """Test interface file with function info."""
  65. source = osp.join(self.INTERFACE_DIR, 'functions.i')
  66. output = self.wrap_content([source], 'functions_py',
  67. self.PYTHON_ACTUAL_DIR)
  68. self.compare_and_diff('functions_pybind.cpp', output)
  69. def test_class(self):
  70. """Test interface file with only class info."""
  71. source = osp.join(self.INTERFACE_DIR, 'class.i')
  72. output = self.wrap_content([source], 'class_py',
  73. self.PYTHON_ACTUAL_DIR)
  74. self.compare_and_diff('class_pybind.cpp', output)
  75. def test_templates(self):
  76. """Test interface file with templated class."""
  77. source = osp.join(self.INTERFACE_DIR, 'templates.i')
  78. output = self.wrap_content([source], 'templates_py',
  79. self.PYTHON_ACTUAL_DIR)
  80. self.compare_and_diff('templates_pybind.cpp', output)
  81. def test_inheritance(self):
  82. """Test interface file with class inheritance definitions."""
  83. source = osp.join(self.INTERFACE_DIR, 'inheritance.i')
  84. output = self.wrap_content([source], 'inheritance_py',
  85. self.PYTHON_ACTUAL_DIR)
  86. self.compare_and_diff('inheritance_pybind.cpp', output)
  87. def test_namespaces(self):
  88. """
  89. Check generation of python wrapper for full namespace definition.
  90. python3 ../pybind_wrapper.py --src namespaces.i --module_name
  91. namespaces_py --out output/namespaces_py.cpp
  92. """
  93. source = osp.join(self.INTERFACE_DIR, 'namespaces.i')
  94. output = self.wrap_content([source], 'namespaces_py',
  95. self.PYTHON_ACTUAL_DIR)
  96. self.compare_and_diff('namespaces_pybind.cpp', output)
  97. def test_operator_overload(self):
  98. """
  99. Tests for operator overloading.
  100. """
  101. source = osp.join(self.INTERFACE_DIR, 'operator.i')
  102. output = self.wrap_content([source], 'operator_py',
  103. self.PYTHON_ACTUAL_DIR)
  104. self.compare_and_diff('operator_pybind.cpp', output)
  105. def test_special_cases(self):
  106. """
  107. Tests for some unique, non-trivial features.
  108. """
  109. source = osp.join(self.INTERFACE_DIR, 'special_cases.i')
  110. output = self.wrap_content([source], 'special_cases_py',
  111. self.PYTHON_ACTUAL_DIR)
  112. self.compare_and_diff('special_cases_pybind.cpp', output)
  113. def test_enum(self):
  114. """
  115. Test if enum generation is correct.
  116. """
  117. source = osp.join(self.INTERFACE_DIR, 'enum.i')
  118. output = self.wrap_content([source], 'enum_py', self.PYTHON_ACTUAL_DIR)
  119. self.compare_and_diff('enum_pybind.cpp', output)
  120. if __name__ == '__main__':
  121. unittest.main()