280 lines
		
	
	
		
			8.7 KiB
		
	
	
	
		
			Python
		
	
	
			
		
		
	
	
			280 lines
		
	
	
		
			8.7 KiB
		
	
	
	
		
			Python
		
	
	
| """
 | |
| Unit tests for Matlab wrap program
 | |
| Author: Matthew Sklar, Varun Agrawal
 | |
| Date: March 2019
 | |
| """
 | |
| # pylint: disable=import-error, wrong-import-position
 | |
| 
 | |
| import filecmp
 | |
| import os
 | |
| import os.path as osp
 | |
| import sys
 | |
| import unittest
 | |
| 
 | |
| from loguru import logger
 | |
| 
 | |
| sys.path.append(osp.dirname(osp.dirname(osp.abspath(__file__))))
 | |
| 
 | |
| from gtwrap.matlab_wrapper import MatlabWrapper
 | |
| 
 | |
| 
 | |
| class TestWrap(unittest.TestCase):
 | |
|     """
 | |
|     Test the Matlab wrapper
 | |
|     """
 | |
|     TEST_DIR = osp.dirname(osp.realpath(__file__))
 | |
|     INTERFACE_DIR = osp.join(TEST_DIR, "fixtures")
 | |
|     MATLAB_TEST_DIR = osp.join(TEST_DIR, "expected", "matlab")
 | |
|     MATLAB_ACTUAL_DIR = osp.join(TEST_DIR, "actual", "matlab")
 | |
| 
 | |
|     # Create the `actual/matlab` directory
 | |
|     os.makedirs(MATLAB_ACTUAL_DIR, exist_ok=True)
 | |
| 
 | |
|     # set the log level to INFO by default
 | |
|     logger.remove()  # remove the default sink
 | |
|     logger.add(sys.stderr, format="{time} {level} {message}", level="INFO")
 | |
| 
 | |
|     def generate_content(self, cc_content, path=MATLAB_ACTUAL_DIR):
 | |
|         """Generate files and folders from matlab wrapper content.
 | |
| 
 | |
|         Keyword arguments:
 | |
|         cc_content -- the content to generate formatted as
 | |
|             (file_name, file_content) or
 | |
|             (folder_name, [(file_name, file_content)])
 | |
|         path -- the path to the files parent folder within the main folder
 | |
|         """
 | |
|         for c in cc_content:
 | |
|             if isinstance(c, list):
 | |
|                 if len(c) == 0:
 | |
|                     continue
 | |
|                 logger.debug("c object: {}".format(c[0][0]))
 | |
|                 path_to_folder = osp.join(path, c[0][0])
 | |
| 
 | |
|                 if not osp.isdir(path_to_folder):
 | |
|                     try:
 | |
|                         os.makedirs(path_to_folder, exist_ok=True)
 | |
|                     except OSError:
 | |
|                         pass
 | |
| 
 | |
|                 for sub_content in c:
 | |
|                     logger.debug("sub object: {}".format(sub_content[1][0][0]))
 | |
|                     self.generate_content(sub_content[1], path_to_folder)
 | |
| 
 | |
|             elif isinstance(c[1], list):
 | |
|                 path_to_folder = osp.join(path, c[0])
 | |
| 
 | |
|                 logger.debug(
 | |
|                     "[generate_content_global]: {}".format(path_to_folder))
 | |
|                 if not osp.isdir(path_to_folder):
 | |
|                     try:
 | |
|                         os.makedirs(path_to_folder, exist_ok=True)
 | |
|                     except OSError:
 | |
|                         pass
 | |
|                 for sub_content in c[1]:
 | |
|                     path_to_file = osp.join(path_to_folder, sub_content[0])
 | |
|                     logger.debug(
 | |
|                         "[generate_global_method]: {}".format(path_to_file))
 | |
|                     with open(path_to_file, 'w') as f:
 | |
|                         f.write(sub_content[1])
 | |
| 
 | |
|             else:
 | |
|                 path_to_file = osp.join(path, c[0])
 | |
| 
 | |
|                 logger.debug("[generate_content]: {}".format(path_to_file))
 | |
|                 if not osp.isdir(path_to_file):
 | |
|                     try:
 | |
|                         os.mkdir(path)
 | |
|                     except OSError:
 | |
|                         pass
 | |
| 
 | |
|                 with open(path_to_file, 'w') as f:
 | |
|                     f.write(c[1])
 | |
| 
 | |
|     def compare_and_diff(self, file):
 | |
|         """
 | |
|         Compute the comparison between the expected and actual file,
 | |
|         and assert if diff is zero.
 | |
|         """
 | |
|         output = osp.join(self.MATLAB_ACTUAL_DIR, file)
 | |
|         expected = osp.join(self.MATLAB_TEST_DIR, file)
 | |
|         success = filecmp.cmp(output, expected)
 | |
|         if not success:
 | |
|             print("Differ in file: {}".format(file))
 | |
|             os.system("diff {} {}".format(output, expected))
 | |
|         self.assertTrue(success, "Mismatch for file {0}".format(file))
 | |
| 
 | |
|     def test_geometry(self):
 | |
|         """
 | |
|         Check generation of matlab geometry wrapper.
 | |
|         python3 wrap/matlab_wrapper.py --src wrap/tests/geometry.h
 | |
|             --module_name geometry --out wrap/tests/actual-matlab
 | |
|         """
 | |
|         with open(osp.join(self.INTERFACE_DIR, 'geometry.i'), 'r') as f:
 | |
|             content = f.read()
 | |
| 
 | |
|         if not osp.exists(self.MATLAB_ACTUAL_DIR):
 | |
|             os.mkdir(self.MATLAB_ACTUAL_DIR)
 | |
| 
 | |
|         # Create MATLAB wrapper instance
 | |
|         wrapper = MatlabWrapper(
 | |
|             module_name='geometry',
 | |
|             top_module_namespace=['gtsam'],
 | |
|             ignore_classes=[''],
 | |
|         )
 | |
| 
 | |
|         cc_content = wrapper.wrap(content)
 | |
| 
 | |
|         self.generate_content(cc_content)
 | |
| 
 | |
|         self.assertTrue(osp.isdir(osp.join(self.MATLAB_ACTUAL_DIR, '+gtsam')))
 | |
| 
 | |
|         files = ['+gtsam/Point2.m', '+gtsam/Point3.m', 'geometry_wrapper.cpp']
 | |
| 
 | |
|         for file in files:
 | |
|             self.compare_and_diff(file)
 | |
| 
 | |
|     def test_functions(self):
 | |
|         """Test interface file with function info."""
 | |
|         with open(osp.join(self.INTERFACE_DIR, 'functions.i'), 'r') as f:
 | |
|             content = f.read()
 | |
| 
 | |
|         if not osp.exists(self.MATLAB_ACTUAL_DIR):
 | |
|             os.mkdir(self.MATLAB_ACTUAL_DIR)
 | |
| 
 | |
|         wrapper = MatlabWrapper(
 | |
|             module_name='functions',
 | |
|             top_module_namespace=['gtsam'],
 | |
|             ignore_classes=[''],
 | |
|         )
 | |
| 
 | |
|         cc_content = wrapper.wrap(content)
 | |
| 
 | |
|         self.generate_content(cc_content)
 | |
| 
 | |
|         files = [
 | |
|             'functions_wrapper.cpp', 'aGlobalFunction.m', 'load2D.m',
 | |
|             'MultiTemplatedFunctionDoubleSize_tDouble.m',
 | |
|             'MultiTemplatedFunctionStringSize_tDouble.m',
 | |
|             'overloadedGlobalFunction.m', 'TemplatedFunctionRot3.m'
 | |
|         ]
 | |
| 
 | |
|         for file in files:
 | |
|             self.compare_and_diff(file)
 | |
| 
 | |
|     def test_class(self):
 | |
|         """Test interface file with only class info."""
 | |
|         with open(osp.join(self.INTERFACE_DIR, 'class.i'), 'r') as f:
 | |
|             content = f.read()
 | |
| 
 | |
|         if not osp.exists(self.MATLAB_ACTUAL_DIR):
 | |
|             os.mkdir(self.MATLAB_ACTUAL_DIR)
 | |
| 
 | |
|         wrapper = MatlabWrapper(
 | |
|             module_name='class',
 | |
|             top_module_namespace=['gtsam'],
 | |
|             ignore_classes=[''],
 | |
|         )
 | |
| 
 | |
|         cc_content = wrapper.wrap(content)
 | |
| 
 | |
|         self.generate_content(cc_content)
 | |
| 
 | |
|         files = [
 | |
|             'class_wrapper.cpp', 'FunDouble.m', 'FunRange.m',
 | |
|             'MultipleTemplatesIntDouble.m', 'MultipleTemplatesIntFloat.m',
 | |
|             'MyFactorPosePoint2.m', 'MyVector3.m', 'MyVector12.m',
 | |
|             'PrimitiveRefDouble.m', 'Test.m'
 | |
|         ]
 | |
| 
 | |
|         for file in files:
 | |
|             self.compare_and_diff(file)
 | |
| 
 | |
|     def test_inheritance(self):
 | |
|         """Test interface file with class inheritance definitions."""
 | |
|         with open(osp.join(self.INTERFACE_DIR, 'inheritance.i'), 'r') as f:
 | |
|             content = f.read()
 | |
| 
 | |
|         if not osp.exists(self.MATLAB_ACTUAL_DIR):
 | |
|             os.mkdir(self.MATLAB_ACTUAL_DIR)
 | |
| 
 | |
|         wrapper = MatlabWrapper(
 | |
|             module_name='inheritance',
 | |
|             top_module_namespace=['gtsam'],
 | |
|             ignore_classes=[''],
 | |
|         )
 | |
| 
 | |
|         cc_content = wrapper.wrap(content)
 | |
| 
 | |
|         self.generate_content(cc_content)
 | |
| 
 | |
|         files = [
 | |
|             'inheritance_wrapper.cpp', 'MyBase.m', 'MyTemplateMatrix.m',
 | |
|             'MyTemplatePoint2.m'
 | |
|         ]
 | |
| 
 | |
|         for file in files:
 | |
|             self.compare_and_diff(file)
 | |
| 
 | |
|     def test_namespaces(self):
 | |
|         """
 | |
|         Test interface file with full namespace definition.
 | |
|         """
 | |
|         with open(osp.join(self.INTERFACE_DIR, 'namespaces.i'), 'r') as f:
 | |
|             content = f.read()
 | |
| 
 | |
|         if not osp.exists(self.MATLAB_ACTUAL_DIR):
 | |
|             os.mkdir(self.MATLAB_ACTUAL_DIR)
 | |
| 
 | |
|         wrapper = MatlabWrapper(
 | |
|             module_name='namespaces',
 | |
|             top_module_namespace=['gtsam'],
 | |
|             ignore_classes=[''],
 | |
|         )
 | |
| 
 | |
|         cc_content = wrapper.wrap(content)
 | |
| 
 | |
|         self.generate_content(cc_content)
 | |
| 
 | |
|         files = [
 | |
|             'namespaces_wrapper.cpp', '+ns1/aGlobalFunction.m',
 | |
|             '+ns1/ClassA.m', '+ns1/ClassB.m', '+ns2/+ns3/ClassB.m',
 | |
|             '+ns2/aGlobalFunction.m', '+ns2/ClassA.m', '+ns2/ClassC.m',
 | |
|             '+ns2/overloadedGlobalFunction.m', 'ClassD.m'
 | |
|         ]
 | |
| 
 | |
|         for file in files:
 | |
|             self.compare_and_diff(file)
 | |
| 
 | |
|     def test_special_cases(self):
 | |
|         """
 | |
|         Tests for some unique, non-trivial features.
 | |
|         """
 | |
|         with open(osp.join(self.INTERFACE_DIR, 'special_cases.i'), 'r') as f:
 | |
|             content = f.read()
 | |
| 
 | |
|         if not osp.exists(self.MATLAB_ACTUAL_DIR):
 | |
|             os.mkdir(self.MATLAB_ACTUAL_DIR)
 | |
| 
 | |
|         wrapper = MatlabWrapper(
 | |
|             module_name='special_cases',
 | |
|             top_module_namespace=['gtsam'],
 | |
|             ignore_classes=[''],
 | |
|         )
 | |
| 
 | |
|         cc_content = wrapper.wrap(content)
 | |
| 
 | |
|         self.generate_content(cc_content)
 | |
| 
 | |
|         files = [
 | |
|             'special_cases_wrapper.cpp',
 | |
|             '+gtsam/PinholeCameraCal3Bundler.m',
 | |
|             '+gtsam/NonlinearFactorGraph.m',
 | |
|         ]
 | |
| 
 | |
|         for file in files:
 | |
|             self.compare_and_diff(file)
 | |
| 
 | |
| 
 | |
| if __name__ == '__main__':
 | |
|     unittest.main()
 |