165 lines
		
	
	
		
			5.6 KiB
		
	
	
	
		
			Python
		
	
	
		
		
			
		
	
	
			165 lines
		
	
	
		
			5.6 KiB
		
	
	
	
		
			Python
		
	
	
|  | """
 | ||
|  | Unit test for Pybind wrap program | ||
|  | Author: Matthew Sklar, Varun Agrawal | ||
|  | Date: February 2019 | ||
|  | """
 | ||
|  | 
 | ||
|  | # pylint: disable=import-error, wrong-import-position, too-many-branches | ||
|  | 
 | ||
|  | import filecmp | ||
|  | import os | ||
|  | import os.path as osp | ||
|  | import sys | ||
|  | import unittest | ||
|  | 
 | ||
|  | sys.path.append(osp.dirname(osp.dirname(osp.abspath(__file__)))) | ||
|  | sys.path.append( | ||
|  |     osp.normpath(osp.abspath(osp.join(__file__, '../../../build/wrap')))) | ||
|  | 
 | ||
|  | from gtwrap.pybind_wrapper import PybindWrapper | ||
|  | 
 | ||
|  | sys.path.append(osp.dirname(osp.dirname(osp.abspath(__file__)))) | ||
|  | 
 | ||
|  | 
 | ||
|  | class TestWrap(unittest.TestCase): | ||
|  |     """Tests for Python wrapper based on Pybind11.""" | ||
|  |     TEST_DIR = osp.dirname(osp.realpath(__file__)) | ||
|  |     INTERFACE_DIR = osp.join(TEST_DIR, 'fixtures') | ||
|  |     PYTHON_TEST_DIR = osp.join(TEST_DIR, 'expected', 'python') | ||
|  |     PYTHON_ACTUAL_DIR = osp.join(TEST_DIR, "actual", "python") | ||
|  | 
 | ||
|  |     # Create the `actual/python` directory | ||
|  |     os.makedirs(PYTHON_ACTUAL_DIR, exist_ok=True) | ||
|  | 
 | ||
|  |     def wrap_content(self, | ||
|  |                      sources, | ||
|  |                      module_name, | ||
|  |                      output_dir, | ||
|  |                      use_boost_serialization=False): | ||
|  |         """
 | ||
|  |         Common function to wrap content in `sources`. | ||
|  |         """
 | ||
|  |         with open(osp.join(self.TEST_DIR, "pybind_wrapper.tpl"), | ||
|  |                   encoding="UTF-8") as template_file: | ||
|  |             module_template = template_file.read() | ||
|  | 
 | ||
|  |         # Create Pybind wrapper instance | ||
|  |         wrapper = PybindWrapper( | ||
|  |             module_name=module_name, | ||
|  |             top_module_namespaces=[''], | ||
|  |             ignore_classes=[''], | ||
|  |             module_template=module_template, | ||
|  |             use_boost_serialization=use_boost_serialization) | ||
|  | 
 | ||
|  |         output = osp.join(self.TEST_DIR, output_dir, module_name + ".cpp") | ||
|  | 
 | ||
|  |         if not osp.exists(osp.join(self.TEST_DIR, output_dir)): | ||
|  |             os.mkdir(osp.join(self.TEST_DIR, output_dir)) | ||
|  | 
 | ||
|  |         wrapper.wrap(sources, output) | ||
|  | 
 | ||
|  |         return output | ||
|  | 
 | ||
|  |     def compare_and_diff(self, file, actual): | ||
|  |         """
 | ||
|  |         Compute the comparison between the expected and actual file, | ||
|  |         and assert if diff is zero. | ||
|  |         """
 | ||
|  |         expected = osp.join(self.PYTHON_TEST_DIR, file) | ||
|  |         success = filecmp.cmp(actual, expected) | ||
|  | 
 | ||
|  |         if not success: | ||
|  |             os.system(f"diff {actual} {expected}") | ||
|  |         self.assertTrue(success, f"Mismatch for file {file}") | ||
|  | 
 | ||
|  |     def test_geometry(self): | ||
|  |         """
 | ||
|  |         Check generation of python geometry wrapper. | ||
|  |         python3 ../pybind_wrapper.py --src geometry.h --module_name | ||
|  |             geometry_py --out output/geometry_py.cc | ||
|  |         """
 | ||
|  |         source = osp.join(self.INTERFACE_DIR, 'geometry.i') | ||
|  |         output = self.wrap_content([source], | ||
|  |                                    'geometry_py', | ||
|  |                                    self.PYTHON_ACTUAL_DIR, | ||
|  |                                    use_boost_serialization=True) | ||
|  | 
 | ||
|  |         self.compare_and_diff('geometry_pybind.cpp', output) | ||
|  | 
 | ||
|  |     def test_functions(self): | ||
|  |         """Test interface file with function info.""" | ||
|  |         source = osp.join(self.INTERFACE_DIR, 'functions.i') | ||
|  |         output = self.wrap_content([source], 'functions_py', | ||
|  |                                    self.PYTHON_ACTUAL_DIR) | ||
|  | 
 | ||
|  |         self.compare_and_diff('functions_pybind.cpp', output) | ||
|  | 
 | ||
|  |     def test_class(self): | ||
|  |         """Test interface file with only class info.""" | ||
|  |         source = osp.join(self.INTERFACE_DIR, 'class.i') | ||
|  |         output = self.wrap_content([source], 'class_py', | ||
|  |                                    self.PYTHON_ACTUAL_DIR) | ||
|  | 
 | ||
|  |         self.compare_and_diff('class_pybind.cpp', output) | ||
|  | 
 | ||
|  |     def test_templates(self): | ||
|  |         """Test interface file with templated class.""" | ||
|  |         source = osp.join(self.INTERFACE_DIR, 'templates.i') | ||
|  |         output = self.wrap_content([source], 'templates_py', | ||
|  |                                    self.PYTHON_ACTUAL_DIR) | ||
|  | 
 | ||
|  |         self.compare_and_diff('templates_pybind.cpp', output) | ||
|  | 
 | ||
|  |     def test_inheritance(self): | ||
|  |         """Test interface file with class inheritance definitions.""" | ||
|  |         source = osp.join(self.INTERFACE_DIR, 'inheritance.i') | ||
|  |         output = self.wrap_content([source], 'inheritance_py', | ||
|  |                                    self.PYTHON_ACTUAL_DIR) | ||
|  | 
 | ||
|  |         self.compare_and_diff('inheritance_pybind.cpp', output) | ||
|  | 
 | ||
|  |     def test_namespaces(self): | ||
|  |         """
 | ||
|  |         Check generation of python wrapper for full namespace definition. | ||
|  |         python3 ../pybind_wrapper.py --src namespaces.i --module_name | ||
|  |             namespaces_py --out output/namespaces_py.cpp | ||
|  |         """
 | ||
|  |         source = osp.join(self.INTERFACE_DIR, 'namespaces.i') | ||
|  |         output = self.wrap_content([source], 'namespaces_py', | ||
|  |                                    self.PYTHON_ACTUAL_DIR) | ||
|  | 
 | ||
|  |         self.compare_and_diff('namespaces_pybind.cpp', output) | ||
|  | 
 | ||
|  |     def test_operator_overload(self): | ||
|  |         """
 | ||
|  |         Tests for operator overloading. | ||
|  |         """
 | ||
|  |         source = osp.join(self.INTERFACE_DIR, 'operator.i') | ||
|  |         output = self.wrap_content([source], 'operator_py', | ||
|  |                                    self.PYTHON_ACTUAL_DIR) | ||
|  | 
 | ||
|  |         self.compare_and_diff('operator_pybind.cpp', output) | ||
|  | 
 | ||
|  |     def test_special_cases(self): | ||
|  |         """
 | ||
|  |         Tests for some unique, non-trivial features. | ||
|  |         """
 | ||
|  |         source = osp.join(self.INTERFACE_DIR, 'special_cases.i') | ||
|  |         output = self.wrap_content([source], 'special_cases_py', | ||
|  |                                    self.PYTHON_ACTUAL_DIR) | ||
|  | 
 | ||
|  |         self.compare_and_diff('special_cases_pybind.cpp', output) | ||
|  | 
 | ||
|  |     def test_enum(self): | ||
|  |         """
 | ||
|  |         Test if enum generation is correct. | ||
|  |         """
 | ||
|  |         source = osp.join(self.INTERFACE_DIR, 'enum.i') | ||
|  |         output = self.wrap_content([source], 'enum_py', self.PYTHON_ACTUAL_DIR) | ||
|  | 
 | ||
|  |         self.compare_and_diff('enum_pybind.cpp', output) | ||
|  | 
 | ||
|  | 
 | ||
|  | if __name__ == '__main__': | ||
|  |     unittest.main() |