|
14 | 14 | # See the License for the specific language governing permissions and |
15 | 15 | # limitations under the License. |
16 | 16 |
|
17 | | -"""Test that all the required Matlab functions are defined.""" |
| 17 | +"""Test that all the required MATLAB functions are defined.""" |
18 | 18 | import unittest |
| 19 | +import glob |
19 | 20 | import os |
| 21 | +import re |
| 22 | +import subprocess |
20 | 23 | import sys |
| 24 | + |
21 | 25 | WEBOTS_HOME = os.path.normpath(os.environ['WEBOTS_HOME']) |
22 | 26 | sys.path.append(os.path.join(WEBOTS_HOME, 'src', 'controller', 'matlab')) |
23 | 27 | import mgenerate # noqa: E402 |
24 | 28 |
|
25 | 29 |
|
26 | 30 | class TestMatlabFunctions(unittest.TestCase): |
27 | | - """Unit test for checking that all the required Matlab functions are defined.""" |
| 31 | + """Unit test for checking that all the required MATLAB functions are defined.""" |
28 | 32 |
|
29 | 33 | def setUp(self): |
30 | 34 | if sys.version_info[0] >= 3: |
31 | 35 | mgenerate.UPDATE = False |
32 | 36 | mgenerate.main() |
33 | | - """Get all the required function.""" |
| 37 | + """Get all the required functions.""" |
34 | 38 | skippedLines = [ |
35 | | - 'wbr', |
36 | | - 'microphone', |
37 | | - 'remote_control', |
38 | | - 'robot', |
39 | | - 'wb_device_get_type', |
40 | | - 'wb_node_get_name', |
41 | | - 'wbu_string', |
42 | | - 'lookup_table_size', |
43 | | - 'EXPORTS' |
| 39 | + # Patterns |
| 40 | + '.*_H', # Header Guards |
| 41 | + '.*_', # Some comments use the ..._* pattern to refer to a group of functions ; |
| 42 | + # grep will filter the *, but no function should end with _ |
| 43 | + 'wb_camera_image_get_.*', # The MATLAB API exposes the image data as a multidimensional array, |
| 44 | + # so these functions are not needed |
| 45 | + 'wb_(microphone|radio)_.*', # Experimental Node Types |
| 46 | + 'wb_remote_control_.*', 'wbr_.*', # Remote Control Plugin |
| 47 | + 'wb_robot_.*', # Many robot functions are used internally by the C API (e.x. wb_robot_mutex_*) |
| 48 | + '.*_lookup_table_size', # MATLAB lets you get the size of an array, so these functions are not needed |
| 49 | + 'wbu_string_.*', # String manipulation functions are not needed |
| 50 | + |
| 51 | + # Specific Functions |
| 52 | + |
| 53 | + # Non-Function Macros |
| 54 | + 'WB_ALLOW_MIXING_C_AND_CPP_API', |
| 55 | + 'WB_DEPRECATED', |
| 56 | + 'WB_MATLAB_LOADLIBRARY', |
| 57 | + 'WB_USING_C(PP)?_API', |
| 58 | + |
| 59 | + # These functions are used internally by the MATLAB API |
| 60 | + 'wb_camera_recognition_get_object', |
| 61 | + 'wb_lidar_get_point', |
| 62 | + 'wb_mouse_get_state_pointer', |
| 63 | + 'wb_radar_get_target', |
| 64 | + |
| 65 | + 'wb_device_get_type', # Deprecated since 8.0.0 |
| 66 | + 'wb_node_get_name', # C API Only |
| 67 | + |
| 68 | + # Not Yet Implemented |
| 69 | + 'wbu_system_tmpdir', |
| 70 | + 'wbu_system_webots_instance_path', |
44 | 71 | ] |
45 | 72 | self.functions = [] |
46 | | - filename = os.path.join(WEBOTS_HOME, 'src', 'controller', 'c', 'Controller.def') |
47 | | - self.assertTrue( |
48 | | - os.path.isfile(filename), |
49 | | - msg='Missing "%s" file.' % filename |
50 | | - ) |
51 | | - with open(filename) as file: |
52 | | - for line in file: |
53 | | - if not any(skippedLine in line for skippedLine in skippedLines) and not line[3:].isupper(): |
54 | | - self.functions.append(line.replace('\n', '')) |
| 73 | + |
| 74 | + symbolSearch = subprocess.run([ |
| 75 | + # Search for webots definitions |
| 76 | + 'grep', '-Ehio', r'\bwb_\w+\b', |
| 77 | + # In the controller headers |
| 78 | + *glob.glob(os.path.join(WEBOTS_HOME, 'include', 'controller', 'c', 'webots', '*.h')), |
| 79 | + *glob.glob(os.path.join(WEBOTS_HOME, 'include', 'controller', 'c', 'webots', 'utils', '*.h')) |
| 80 | + ], capture_output=True, text=True) |
| 81 | + if symbolSearch.returncode != 0: |
| 82 | + self.fail(f'Failed to generate function list:\n{symbolSearch.stdout}\n{symbolSearch.stderr}') |
| 83 | + |
| 84 | + for line in symbolSearch.stdout.splitlines(): |
| 85 | + if not any(re.match(f'^{skippedLine}$', line) for skippedLine in skippedLines) and line not in self.functions: |
| 86 | + self.functions.append(line) |
55 | 87 |
|
56 | 88 | @unittest.skipIf(sys.version_info[0] < 3, "not supported by Python 2.7") |
57 | 89 | def test_matlab_function_exists(self): |
58 | 90 | """Test that the function file exists.""" |
59 | | - for function in self.functions: |
60 | | - filename = os.path.join(WEBOTS_HOME, 'lib', 'controller', 'matlab', function + '.m') |
61 | | - self.assertTrue( |
62 | | - os.path.isfile(filename), |
63 | | - msg='Missing "%s" file.' % filename |
64 | | - ) |
| 91 | + expectedFiles = (os.path.join(WEBOTS_HOME, 'lib', 'controller', 'matlab', function + '.m') |
| 92 | + for function in self.functions) |
| 93 | + missingFiles = [file for file in expectedFiles if not os.path.isfile(file)] |
| 94 | + |
| 95 | + self.assertTrue( |
| 96 | + not missingFiles, |
| 97 | + msg='Missing files: %s' % ', '.join(missingFiles) |
| 98 | + ) |
65 | 99 |
|
66 | 100 |
|
67 | 101 | if __name__ == '__main__': |
|
0 commit comments