blob: b344f8ce76cc0b3c8cb5bafa762474d52d6c25a0 [file] [log] [blame]
Mohammad Azim Khanfff49042017-03-28 01:48:31 +01001"""
Azim Khan4b543232017-06-30 09:35:21 +01002mbed TLS
3Copyright (c) 2017 ARM Limited
Mohammad Azim Khanfff49042017-03-28 01:48:31 +01004
5Licensed under the Apache License, Version 2.0 (the "License");
6you may not use this file except in compliance with the License.
7You may obtain a copy of the License at
8
9 http://www.apache.org/licenses/LICENSE-2.0
10
11Unless required by applicable law or agreed to in writing, software
12distributed under the License is distributed on an "AS IS" BASIS,
13WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14See the License for the specific language governing permissions and
15limitations under the License.
16"""
17
18import os
19import re
20import argparse
21import shutil
22
23
24"""
25Generates code in following structure.
26
27<output dir>/
Azim Khan4b543232017-06-30 09:35:21 +010028 |-- mbedtls/
29 | |-- <test suite #1>/
30 | | |-- main.c
31 | | |-- *.data files
32 | ...
33 | |-- <test suite #n>/
34 | | |-- main.c
35 | | |-- *.data files
36 | |
Mohammad Azim Khanfff49042017-03-28 01:48:31 +010037"""
38
39
40BEGIN_HEADER_REGEX = '/\*\s*BEGIN_HEADER\s*\*/'
41END_HEADER_REGEX = '/\*\s*END_HEADER\s*\*/'
42
43BEGIN_DEP_REGEX = 'BEGIN_DEPENDENCIES'
44END_DEP_REGEX = 'END_DEPENDENCIES'
45
46BEGIN_CASE_REGEX = '/\*\s*BEGIN_CASE\s*(.*?)\s*\*/'
47END_CASE_REGEX = '/\*\s*END_CASE\s*\*/'
48
49
50class InvalidFileFormat(Exception):
51 """
52 Exception to indicate invalid file format.
53 """
54 pass
55
56
Azim Khan4b543232017-06-30 09:35:21 +010057class FileWrapper(file):
58 """
59 File wrapper class. Provides reading with line no. tracking.
60 """
61
62 def __init__(self, file_name):
63 """
64 Init file handle.
65
66 :param file_name:
67 """
68 super(FileWrapper, self).__init__(file_name, 'r')
69 self.line_no = 0
70
71 def next(self):
72 """
73 Iterator return impl.
74 :return:
75 """
76 line = super(FileWrapper, self).next()
77 if line:
78 self.line_no += 1
79 return line
80
81 def readline(self, limit=0):
82 """
83 Wrap the base class readline.
84
85 :param limit:
86 :return:
87 """
88 return self.next()
89
90
91def split_dep(dep):
92 return ('!', dep[1:]) if dep[0] == '!' else ('', dep)
93
94
Mohammad Azim Khanfff49042017-03-28 01:48:31 +010095def gen_deps(deps):
96 """
97 Generates dependency i.e. if def and endif code
98
99 :param deps:
100 :return:
101 """
Azim Khan4b543232017-06-30 09:35:21 +0100102 dep_start = ''.join(['#if %sdefined(%s)\n' % split_dep(x) for x in deps])
103 dep_end = ''.join(['#endif /* %s */\n' % x for x in reversed(deps)])
104
Mohammad Azim Khanfff49042017-03-28 01:48:31 +0100105 return dep_start, dep_end
106
107
108def gen_deps_one_line(deps):
109 """
110 Generates dependency checks in one line. Useful for writing code in #else case.
111
112 :param deps:
113 :return:
114 """
Azim Khan4b543232017-06-30 09:35:21 +0100115 defines = ('#if ' if len(deps) else '') + ' && '.join(['%sdefined(%s)' % split_dep(x) for x in deps])
116 return defines
Mohammad Azim Khanfff49042017-03-28 01:48:31 +0100117
118
Azim Khan4b543232017-06-30 09:35:21 +0100119def gen_function_wrapper(name, locals, args_dispatch):
Mohammad Azim Khanfff49042017-03-28 01:48:31 +0100120 """
121 Creates test function code
122
123 :param name:
Azim Khan4b543232017-06-30 09:35:21 +0100124 :param locals:
Mohammad Azim Khanfff49042017-03-28 01:48:31 +0100125 :param args_dispatch:
126 :return:
127 """
128 # Then create the wrapper
129 wrapper = '''
130void {name}_wrapper( void ** params )
131{{
132 {unused_params}
Azim Khan2397bba2017-06-09 04:35:03 +0100133{locals}
Mohammad Azim Khanfff49042017-03-28 01:48:31 +0100134 {name}( {args} );
135}}
Azim Khan4b543232017-06-30 09:35:21 +0100136'''.format(name=name, unused_params='(void)params;' if len(args_dispatch) == 0 else '',
137 args=', '.join(args_dispatch),
138 locals=locals)
Mohammad Azim Khanfff49042017-03-28 01:48:31 +0100139 return wrapper
140
141
142def gen_dispatch(name, deps):
143 """
144 Generates dispatch condition for the functions.
145
146 :param name:
147 :param deps:
148 :return:
149 """
150 if len(deps):
151 ifdef = gen_deps_one_line(deps)
152 dispatch_code = '''
153{ifdef}
154 {name}_wrapper,
155#else
156 NULL,
157#endif
158'''.format(ifdef=ifdef, name=name)
159 else:
160 dispatch_code = '''
161 {name}_wrapper,
162'''.format(name=name)
163
164 return dispatch_code
165
166
Azim Khan4b543232017-06-30 09:35:21 +0100167def parse_suite_headers(funcs_f):
Mohammad Azim Khanfff49042017-03-28 01:48:31 +0100168 """
169 Parses function headers.
170
Mohammad Azim Khanfff49042017-03-28 01:48:31 +0100171 :param funcs_f:
172 :return:
173 """
Azim Khan4b543232017-06-30 09:35:21 +0100174 headers = '#line %d "%s"\n' % (funcs_f.line_no + 1, funcs_f.name)
Mohammad Azim Khanfff49042017-03-28 01:48:31 +0100175 for line in funcs_f:
Mohammad Azim Khanfff49042017-03-28 01:48:31 +0100176 if re.search(END_HEADER_REGEX, line):
177 break
178 headers += line
179 else:
180 raise InvalidFileFormat("file: %s - end header pattern [%s] not found!" % (funcs_f.name, END_HEADER_REGEX))
181
Azim Khan4b543232017-06-30 09:35:21 +0100182 return headers
Mohammad Azim Khanfff49042017-03-28 01:48:31 +0100183
184
Azim Khan4b543232017-06-30 09:35:21 +0100185def parse_suite_deps(funcs_f):
Mohammad Azim Khanfff49042017-03-28 01:48:31 +0100186 """
187 Parses function dependencies.
188
Mohammad Azim Khanfff49042017-03-28 01:48:31 +0100189 :param funcs_f:
190 :return:
191 """
192 deps = []
193 for line in funcs_f:
Mohammad Azim Khanfff49042017-03-28 01:48:31 +0100194 m = re.search('depends_on\:(.*)', line.strip())
195 if m:
196 deps += [x.strip() for x in m.group(1).split(':')]
197 if re.search(END_DEP_REGEX, line):
198 break
199 else:
200 raise InvalidFileFormat("file: %s - end dependency pattern [%s] not found!" % (funcs_f.name, END_DEP_REGEX))
201
Azim Khan4b543232017-06-30 09:35:21 +0100202 return deps
Mohammad Azim Khanfff49042017-03-28 01:48:31 +0100203
204
205def parse_function_deps(line):
206 """
207
208 :param line:
209 :return:
210 """
211 deps = []
212 m = re.search(BEGIN_CASE_REGEX, line)
213 dep_str = m.group(1)
214 if len(dep_str):
215 m = re.search('depends_on:(.*)', dep_str)
216 if m:
Azim Khan4b543232017-06-30 09:35:21 +0100217 deps = [x.strip() for x in m.group(1).strip().split(':')]
Mohammad Azim Khanfff49042017-03-28 01:48:31 +0100218 return deps
219
220
221def parse_function_signature(line):
222 """
223 Parsing function signature
224
225 :param line:
226 :return:
227 """
228 args = []
Azim Khan2397bba2017-06-09 04:35:03 +0100229 locals = ''
Mohammad Azim Khanfff49042017-03-28 01:48:31 +0100230 args_dispatch = []
231 m = re.search('\s*void\s+(\w+)\s*\(', line, re.I)
232 if not m:
233 raise ValueError("Test function should return 'void'\n%s" % line)
234 name = m.group(1)
235 line = line[len(m.group(0)):]
236 arg_idx = 0
237 for arg in line[:line.find(')')].split(','):
238 arg = arg.strip()
239 if arg == '':
240 continue
241 if re.search('int\s+.*', arg.strip()):
242 args.append('int')
243 args_dispatch.append('*( (int *) params[%d] )' % arg_idx)
244 elif re.search('char\s*\*\s*.*', arg.strip()):
245 args.append('char*')
246 args_dispatch.append('(char *) params[%d]' % arg_idx)
Azim Khan2397bba2017-06-09 04:35:03 +0100247 elif re.search('HexParam_t\s*\*\s*.*', arg.strip()):
Azim Khana57a4202017-05-31 20:32:32 +0100248 args.append('hex')
Azim Khan2397bba2017-06-09 04:35:03 +0100249 # create a structure
250 locals += """ HexParam_t hex%d = {%s, %s};
251""" % (arg_idx, '(uint8_t *) params[%d]' % arg_idx, '*( (uint32_t *) params[%d] )' % (arg_idx + 1))
252
253 args_dispatch.append('&hex%d' % arg_idx)
254 arg_idx += 1
Mohammad Azim Khanfff49042017-03-28 01:48:31 +0100255 else:
Azim Khan4b543232017-06-30 09:35:21 +0100256 raise ValueError("Test function arguments can only be 'int', 'char *' or 'HexParam_t'\n%s" % line)
Mohammad Azim Khanfff49042017-03-28 01:48:31 +0100257 arg_idx += 1
258
Azim Khan4b543232017-06-30 09:35:21 +0100259 return name, args, locals, args_dispatch
Mohammad Azim Khanfff49042017-03-28 01:48:31 +0100260
261
Azim Khan4b543232017-06-30 09:35:21 +0100262def parse_function_code(funcs_f, deps, suite_deps):
Mohammad Azim Khanfff49042017-03-28 01:48:31 +0100263 """
264
265 :param line_no:
266 :param funcs_f:
267 :param deps:
268 :param suite_deps:
269 :return:
270 """
Azim Khan4b543232017-06-30 09:35:21 +0100271 code = '#line %d "%s"\n' % (funcs_f.line_no + 1, funcs_f.name)
Mohammad Azim Khanfff49042017-03-28 01:48:31 +0100272 for line in funcs_f:
Mohammad Azim Khanfff49042017-03-28 01:48:31 +0100273 # Check function signature
274 m = re.match('.*?\s+(\w+)\s*\(', line, re.I)
275 if m:
276 # check if we have full signature i.e. split in more lines
277 if not re.match('.*\)', line):
278 for lin in funcs_f:
279 line += lin
Mohammad Azim Khanfff49042017-03-28 01:48:31 +0100280 if re.search('.*?\)', line):
281 break
Azim Khan4b543232017-06-30 09:35:21 +0100282 name, args, locals, args_dispatch = parse_function_signature(line)
Mohammad Azim Khanfff49042017-03-28 01:48:31 +0100283 code += line.replace(name, 'test_' + name)
284 name = 'test_' + name
285 break
286 else:
287 raise InvalidFileFormat("file: %s - Test functions not found!" % funcs_f.name)
288
289 for line in funcs_f:
Mohammad Azim Khanfff49042017-03-28 01:48:31 +0100290 if re.search(END_CASE_REGEX, line):
291 break
292 code += line
293 else:
294 raise InvalidFileFormat("file: %s - end case pattern [%s] not found!" % (funcs_f.name, END_CASE_REGEX))
295
296 # Add exit label if not present
297 if code.find('exit:') == -1:
298 s = code.rsplit('}', 1)
299 if len(s) == 2:
Azim Khan4b543232017-06-30 09:35:21 +0100300 code = """exit:
Mohammad Azim Khanfff49042017-03-28 01:48:31 +0100301 ;;
Azim Khan4b543232017-06-30 09:35:21 +0100302}""".join(s)
Mohammad Azim Khanfff49042017-03-28 01:48:31 +0100303
Azim Khan4b543232017-06-30 09:35:21 +0100304 code += gen_function_wrapper(name, locals, args_dispatch)
Mohammad Azim Khanfff49042017-03-28 01:48:31 +0100305 ifdef, endif = gen_deps(deps)
306 dispatch_code = gen_dispatch(name, suite_deps + deps)
Azim Khan4b543232017-06-30 09:35:21 +0100307 return name, args, ifdef + code + endif, dispatch_code
Mohammad Azim Khanfff49042017-03-28 01:48:31 +0100308
309
310def parse_functions(funcs_f):
311 """
312 Returns functions code pieces
313
314 :param funcs_f:
315 :return:
316 """
Mohammad Azim Khanfff49042017-03-28 01:48:31 +0100317 suite_headers = ''
318 suite_deps = []
319 suite_functions = ''
320 func_info = {}
321 function_idx = 0
322 dispatch_code = ''
323 for line in funcs_f:
Mohammad Azim Khanfff49042017-03-28 01:48:31 +0100324 if re.search(BEGIN_HEADER_REGEX, line):
Azim Khan4b543232017-06-30 09:35:21 +0100325 headers = parse_suite_headers(funcs_f)
Mohammad Azim Khanfff49042017-03-28 01:48:31 +0100326 suite_headers += headers
327 elif re.search(BEGIN_DEP_REGEX, line):
Azim Khan4b543232017-06-30 09:35:21 +0100328 deps = parse_suite_deps(funcs_f)
Mohammad Azim Khanfff49042017-03-28 01:48:31 +0100329 suite_deps += deps
330 elif re.search(BEGIN_CASE_REGEX, line):
331 deps = parse_function_deps(line)
Azim Khan4b543232017-06-30 09:35:21 +0100332 func_name, args, func_code, func_dispatch = parse_function_code(funcs_f, deps, suite_deps)
Mohammad Azim Khanfff49042017-03-28 01:48:31 +0100333 suite_functions += func_code
334 # Generate dispatch code and enumeration info
335 assert func_name not in func_info, "file: %s - function %s re-declared at line %d" % \
Azim Khan4b543232017-06-30 09:35:21 +0100336 (funcs_f.name, func_name, funcs_f.line_no)
Mohammad Azim Khanfff49042017-03-28 01:48:31 +0100337 func_info[func_name] = (function_idx, args)
338 dispatch_code += '/* Function Id: %d */\n' % function_idx
339 dispatch_code += func_dispatch
340 function_idx += 1
341
342 ifdef, endif = gen_deps(suite_deps)
Azim Khan13c6bfb2017-06-15 14:45:56 +0100343 func_code = ifdef + suite_headers + suite_functions + endif
344 return suite_deps, dispatch_code, func_code, func_info
Mohammad Azim Khanfff49042017-03-28 01:48:31 +0100345
346
347def escaped_split(str, ch):
348 """
349 Split str on character ch but ignore escaped \{ch}
350
351 :param str:
352 :param ch:
353 :return:
354 """
355 if len(ch) > 1:
356 raise ValueError('Expected split character. Found string!')
357 out = []
358 part = ''
359 escape = False
360 for i in range(len(str)):
361 if not escape and str[i] == ch:
362 out.append(part)
363 part = ''
364 else:
Mohammad Azim Khanfff49042017-03-28 01:48:31 +0100365 escape = not escape and str[i] == '\\'
Azim Khan5e2ac1f2017-07-03 13:58:20 +0100366 if not escape:
367 part += str[i]
Mohammad Azim Khanfff49042017-03-28 01:48:31 +0100368 if len(part):
369 out.append(part)
370 return out
371
372
Azim Khan5e2ac1f2017-07-03 13:58:20 +0100373def parse_test_data(data_f, debug=False):
Mohammad Azim Khanfff49042017-03-28 01:48:31 +0100374 """
375 Parses .data file
376
377 :param data_f:
378 :return:
379 """
380 STATE_READ_NAME = 0
381 STATE_READ_ARGS = 1
382 state = STATE_READ_NAME
383 deps = []
Azim Khan5e2ac1f2017-07-03 13:58:20 +0100384 name = ''
Mohammad Azim Khanfff49042017-03-28 01:48:31 +0100385 for line in data_f:
386 line = line.strip()
387 if len(line) and line[0] == '#': # Skip comments
388 continue
389
Azim Khan5e2ac1f2017-07-03 13:58:20 +0100390 # Blank line indicates end of test
Mohammad Azim Khanfff49042017-03-28 01:48:31 +0100391 if len(line) == 0:
Azim Khan5e2ac1f2017-07-03 13:58:20 +0100392 assert state != STATE_READ_ARGS, "Newline before arguments. " \
393 "Test function and arguments missing for %s" % name
Mohammad Azim Khanfff49042017-03-28 01:48:31 +0100394 continue
395
396 if state == STATE_READ_NAME:
397 # Read test name
398 name = line
399 state = STATE_READ_ARGS
400 elif state == STATE_READ_ARGS:
401 # Check dependencies
402 m = re.search('depends_on\:(.*)', line)
403 if m:
Azim Khan5e2ac1f2017-07-03 13:58:20 +0100404 deps = [x.strip() for x in m.group(1).split(':') if len(x.strip())]
Mohammad Azim Khanfff49042017-03-28 01:48:31 +0100405 else:
406 # Read test vectors
407 parts = escaped_split(line, ':')
408 function = parts[0]
409 args = parts[1:]
410 yield name, function, deps, args
411 deps = []
412 state = STATE_READ_NAME
Azim Khan5e2ac1f2017-07-03 13:58:20 +0100413 assert state != STATE_READ_ARGS, "Newline before arguments. " \
414 "Test function and arguments missing for %s" % name
Mohammad Azim Khanfff49042017-03-28 01:48:31 +0100415
416
417def gen_dep_check(dep_id, dep):
418 """
419 Generate code for the dependency.
420
421 :param dep_id:
422 :param dep:
423 :return:
424 """
Azim Khan5e2ac1f2017-07-03 13:58:20 +0100425 assert dep_id > -1, "Dependency Id should be a positive integer."
426 noT, dep = ('!', dep[1:]) if dep[0] == '!' else ('', dep)
427 assert len(dep) > 0, "Dependency should not be an empty string."
Mohammad Azim Khanfff49042017-03-28 01:48:31 +0100428 dep_check = '''
429if ( dep_id == {id} )
430{{
431#if {noT}defined({macro})
432 return( DEPENDENCY_SUPPORTED );
433#else
434 return( DEPENDENCY_NOT_SUPPORTED );
435#endif
436}}
437else
438'''.format(noT=noT, macro=dep, id=dep_id)
Mohammad Azim Khanfff49042017-03-28 01:48:31 +0100439 return dep_check
440
441
442def gen_expression_check(exp_id, exp):
443 """
444 Generates code for expression check
445
446 :param exp_id:
447 :param exp:
448 :return:
449 """
Azim Khan5e2ac1f2017-07-03 13:58:20 +0100450 assert exp_id > -1, "Expression Id should be a positive integer."
451 assert len(exp) > 0, "Expression should not be an empty string."
Mohammad Azim Khanfff49042017-03-28 01:48:31 +0100452 exp_code = '''
453if ( exp_id == {exp_id} )
454{{
455 *out_value = {expression};
456}}
457else
458'''.format(exp_id=exp_id, expression=exp)
459 return exp_code
460
461
Azim Khan5e2ac1f2017-07-03 13:58:20 +0100462def find_unique_id(val, vals):
463 """
464 Check if val already in vals. Gives a unique Identifier for the val.
465 :param val:
466 :param vals:
467 :return:
468 """
469 if val not in vals:
470 vals.append(val)
471
472
Azim Khan13c6bfb2017-06-15 14:45:56 +0100473def gen_from_test_data(data_f, out_data_f, func_info, suite_deps):
Mohammad Azim Khanfff49042017-03-28 01:48:31 +0100474 """
475 Generates dependency checks, expression code and intermediate data file from test data file.
476
477 :param data_f:
478 :param out_data_f:
479 :param func_info:
Azim Khan13c6bfb2017-06-15 14:45:56 +0100480 :param suite_deps:
Mohammad Azim Khanfff49042017-03-28 01:48:31 +0100481 :return:
482 """
483 unique_deps = []
484 unique_expressions = []
485 dep_check_code = ''
486 expression_code = ''
487 for test_name, function_name, test_deps, test_args in parse_test_data(data_f):
488 out_data_f.write(test_name + '\n')
489
490 func_id, func_args = func_info['test_' + function_name]
491 if len(test_deps):
492 out_data_f.write('depends_on')
493 for dep in test_deps:
494 if dep not in unique_deps:
495 unique_deps.append(dep)
496 dep_id = unique_deps.index(dep)
497 dep_check_code += gen_dep_check(dep_id, dep)
498 else:
499 dep_id = unique_deps.index(dep)
500 out_data_f.write(':' + str(dep_id))
501 out_data_f.write('\n')
502
503 assert len(test_args) == len(func_args), \
504 "Invalid number of arguments in test %s. See function %s signature." % (test_name, function_name)
505 out_data_f.write(str(func_id))
506 for i in xrange(len(test_args)):
507 typ = func_args[i]
508 val = test_args[i]
509
510 # check if val is a non literal int val
511 if typ == 'int' and not re.match('\d+', val): # its an expression # FIXME: Handle hex format. Tip: instead try converting int(str, 10) and int(str, 16)
512 typ = 'exp'
513 if val not in unique_expressions:
514 unique_expressions.append(val)
515 # exp_id can be derived from len(). But for readability and consistency with case of existing let's
516 # use index().
517 exp_id = unique_expressions.index(val)
518 expression_code += gen_expression_check(exp_id, val)
519 val = exp_id
520 else:
521 val = unique_expressions.index(val)
522 out_data_f.write(':' + typ + ':' + str(val))
523 out_data_f.write('\n\n')
524
525 # void unused params
526 if len(dep_check_code) == 0:
527 dep_check_code = '(void) dep_id;\n'
528 if len(expression_code) == 0:
529 expression_code = '(void) exp_id;\n'
530 expression_code += '(void) out_value;\n'
Azim Khan13c6bfb2017-06-15 14:45:56 +0100531 ifdef = gen_deps_one_line(suite_deps)
532 if len(suite_deps):
533 dep_check_code = '''
534{ifdef}
535{code}
536#else
537(void) dep_id;
538#endif
539'''.format(ifdef=ifdef, code=dep_check_code)
540 expression_code = '''
541{ifdef}
542{code}
543#else
544(void) exp_id;
545(void) out_value;
546#endif
547'''.format(ifdef=ifdef, code=expression_code)
Mohammad Azim Khanfff49042017-03-28 01:48:31 +0100548 return dep_check_code, expression_code
549
550
Azim Khan1de892b2017-06-09 15:02:36 +0100551def generate_code(funcs_file, data_file, template_file, platform_file, help_file, suites_dir, c_file, out_data_file):
Mohammad Azim Khanfff49042017-03-28 01:48:31 +0100552 """
553 Generate mbed-os test code.
554
555 :param funcs_file:
556 :param dat a_file:
557 :param template_file:
558 :param platform_file:
559 :param help_file:
560 :param suites_dir:
561 :param c_file:
562 :param out_data_file:
563 :return:
564 """
565 for name, path in [('Functions file', funcs_file),
566 ('Data file', data_file),
567 ('Template file', template_file),
568 ('Platform file', platform_file),
569 ('Help code file', help_file),
570 ('Suites dir', suites_dir)]:
571 if not os.path.exists(path):
572 raise IOError("ERROR: %s [%s] not found!" % (name, path))
573
574 snippets = {'generator_script' : os.path.basename(__file__)}
575
576 # Read helpers
577 with open(help_file, 'r') as help_f, open(platform_file, 'r') as platform_f:
578 snippets['test_common_helper_file'] = help_file
579 snippets['test_common_helpers'] = help_f.read()
580 snippets['test_platform_file'] = platform_file
581 snippets['platform_code'] = platform_f.read().replace('DATA_FILE',
582 out_data_file.replace('\\', '\\\\')) # escape '\'
583
584 # Function code
585 with open(funcs_file, 'r') as funcs_f, open(data_file, 'r') as data_f, open(out_data_file, 'w') as out_data_f:
Azim Khan13c6bfb2017-06-15 14:45:56 +0100586 suite_deps, dispatch_code, func_code, func_info = parse_functions(funcs_f)
Mohammad Azim Khanfff49042017-03-28 01:48:31 +0100587 snippets['functions_code'] = func_code
588 snippets['dispatch_code'] = dispatch_code
Azim Khan13c6bfb2017-06-15 14:45:56 +0100589 dep_check_code, expression_code = gen_from_test_data(data_f, out_data_f, func_info, suite_deps)
Mohammad Azim Khanfff49042017-03-28 01:48:31 +0100590 snippets['dep_check_code'] = dep_check_code
591 snippets['expression_code'] = expression_code
592
593 snippets['test_file'] = c_file
594 snippets['test_main_file'] = template_file
595 snippets['test_case_file'] = funcs_file
596 snippets['test_case_data_file'] = data_file
597 # Read Template
598 # Add functions
599 #
600 with open(template_file, 'r') as template_f, open(c_file, 'w') as c_f:
601 line_no = 1
602 for line in template_f.readlines():
603 snippets['line_no'] = line_no + 1 # Increment as it sets next line number
604 code = line.format(**snippets)
605 c_f.write(code)
606 line_no += 1
607
608
609def check_cmd():
610 """
611 Command line parser.
612
613 :return:
614 """
615 parser = argparse.ArgumentParser(description='Generate code for mbed-os tests.')
616
617 parser.add_argument("-f", "--functions-file",
618 dest="funcs_file",
619 help="Functions file",
620 metavar="FUNCTIONS",
621 required=True)
622
623 parser.add_argument("-d", "--data-file",
624 dest="data_file",
625 help="Data file",
626 metavar="DATA",
627 required=True)
628
629 parser.add_argument("-t", "--template-file",
630 dest="template_file",
631 help="Template file",
632 metavar="TEMPLATE",
633 required=True)
634
635 parser.add_argument("-s", "--suites-dir",
636 dest="suites_dir",
637 help="Suites dir",
638 metavar="SUITES",
639 required=True)
640
641 parser.add_argument("--help-file",
642 dest="help_file",
643 help="Help file",
644 metavar="HELPER",
645 required=True)
646
647 parser.add_argument("-p", "--platform-file",
648 dest="platform_file",
649 help="Platform code file",
650 metavar="PLATFORM_FILE",
651 required=True)
652
653 parser.add_argument("-o", "--out-dir",
654 dest="out_dir",
655 help="Dir where generated code and scripts are copied",
656 metavar="OUT_DIR",
657 required=True)
658
659 args = parser.parse_args()
660
661 data_file_name = os.path.basename(args.data_file)
662 data_name = os.path.splitext(data_file_name)[0]
663
664 out_c_file = os.path.join(args.out_dir, data_name + '.c')
665 out_data_file = os.path.join(args.out_dir, data_file_name)
666
667 out_c_file_dir = os.path.dirname(out_c_file)
668 out_data_file_dir = os.path.dirname(out_data_file)
669 for d in [out_c_file_dir, out_data_file_dir]:
670 if not os.path.exists(d):
671 os.makedirs(d)
672
Azim Khan1de892b2017-06-09 15:02:36 +0100673 generate_code(args.funcs_file, args.data_file, args.template_file, args.platform_file,
Mohammad Azim Khanfff49042017-03-28 01:48:31 +0100674 args.help_file, args.suites_dir, out_c_file, out_data_file)
675
676
677if __name__ == "__main__":
678 check_cmd()