blob: 284f6b1da942289a30037b8bc713a4ebb86c49ab [file] [log] [blame]
Markus Pfeiffera26a0052014-04-22 20:16:15 +00001#!/usr/bin/env perl
SimonBe39088a2016-02-10 23:50:28 +00002
3# generate_code.pl
4#
SimonB0284f582016-02-15 23:27:28 +00005# Purpose
6#
SimonBe39088a2016-02-10 23:50:28 +00007# Generates the test suite code given inputs of the test suite directory that
8# contain the test suites, and the test suite file names for the test code and
9# test data.
10#
11# Usage: generate_code.pl <suite dir> <code file> <data file> [main code file]
Paul Bakker367dae42009-06-28 21:50:27 +000012#
SimonB0284f582016-02-15 23:27:28 +000013# Structure of files
14#
15# - main code file - 'main_test.function'
16# Template file that contains the main() function for the test suite,
17# test dispatch code as well as support functions. It contains the
18# following symbols which are substituted by this script during
19# processing:
20# TEST_FILENAME
21# SUITE_PRE_DEP
22# MAPPING_CODE
23# FUNCTION CODE
24# SUITE_POST_DEP
25# DEP_CHECK_CODE
26# DISPATCH_FUNCTION
27#
28# - common helper code file - 'helpers.function'
29# Common helper functions
30#
31# - test suite code file - file name in the form 'test_suite_xxx.function'
32# Code file that contains the actual test cases. The file contains a
33# series of code sequences delimited by the following:
34# BEGIN_HEADER / END_HEADER - list of headers files
35# BEGIN_SUITE_HELPERS / END_SUITE_HELPERS - helper functions common to
36# the test suite
37# BEGIN_CASE / END_CASE - the test cases in the test suite. Each test
38# case contains at least one function that is used to create the
39# dispatch code.
40#
41# - test data file - file name in the form 'test_suite_xxxx.data'
42# The test case parameters to to be used in execution of the test. The
43# file name is used to replace the symbol 'TEST_FILENAME' in the main
44# code file above.
45#
Gilles Peskinee38900b2017-09-29 15:45:12 +020046# A test data file consists of a sequence of paragraphs separated by
47# a single empty line. Line breaks may be in Unix (LF) or Windows (CRLF)
48# format. Lines starting with the character '#' are ignored
49# (the parser behaves as if they were not present).
50#
51# Each paragraph describes one test case and must consist of: (1) one
52# line which is the test case name; (2) an optional line starting with
53# the 11-character prefix "depends_on:"; (3) a line containing the test
54# function to execute and its parameters.
55#
56# A depends_on: line consists of a list of compile-time options
57# separated by the character ':', with no whitespace. The test case
58# is executed only if this compilation option is enabled in config.h.
59#
60# The last line of each paragraph contains a test function name and
61# a list of parameters separated by the character ':'. Running the
62# test case calls this function with the specified parameters. Each
63# parameter may either be an integer written in decimal or hexadecimal,
64# or a string surrounded by double quotes which may not contain the
65# ':' character.
SimonB0284f582016-02-15 23:27:28 +000066#
Paul Bakker367dae42009-06-28 21:50:27 +000067
68use strict;
69
70my $suite_dir = shift or die "Missing suite directory";
71my $suite_name = shift or die "Missing suite name";
Paul Bakker46c17942011-07-13 14:54:54 +000072my $data_name = shift or die "Missing data name";
Rich Evansf4253c72015-01-14 19:23:00 +000073my $test_main_file = do { my $arg = shift; defined($arg) ? $arg : $suite_dir."/main_test.function" };
Paul Bakker46c17942011-07-13 14:54:54 +000074my $test_file = $data_name.".c";
SimonB0284f582016-02-15 23:27:28 +000075my $test_common_helper_file = $suite_dir."/helpers.function";
Paul Bakker367dae42009-06-28 21:50:27 +000076my $test_case_file = $suite_dir."/".$suite_name.".function";
Paul Bakker19343182013-08-16 13:31:10 +020077my $test_case_data = $suite_dir."/".$data_name.".data";
Paul Bakker367dae42009-06-28 21:50:27 +000078
79my $line_separator = $/;
80undef $/;
81
SimonB0284f582016-02-15 23:27:28 +000082open(TEST_HELPERS, "$test_common_helper_file") or die "Opening test helpers
83'$test_common_helper_file': $!";
84my $test_common_helpers = <TEST_HELPERS>;
Paul Bakker367dae42009-06-28 21:50:27 +000085close(TEST_HELPERS);
86
Paul Bakker19343182013-08-16 13:31:10 +020087open(TEST_MAIN, "$test_main_file") or die "Opening test main '$test_main_file': $!";
88my $test_main = <TEST_MAIN>;
89close(TEST_MAIN);
90
Paul Bakker367dae42009-06-28 21:50:27 +000091open(TEST_CASES, "$test_case_file") or die "Opening test cases '$test_case_file': $!";
92my $test_cases = <TEST_CASES>;
93close(TEST_CASES);
Paul Bakker19343182013-08-16 13:31:10 +020094
95open(TEST_DATA, "$test_case_data") or die "Opening test data '$test_case_data': $!";
96my $test_data = <TEST_DATA>;
97close(TEST_DATA);
98
Paul Bakker33b43f12013-08-20 11:48:36 +020099my ( $suite_header ) = $test_cases =~ /\/\* BEGIN_HEADER \*\/\n(.*?)\n\/\* END_HEADER \*\//s;
100my ( $suite_defines ) = $test_cases =~ /\/\* BEGIN_DEPENDENCIES\n \* (.*?)\n \* END_DEPENDENCIES/s;
SimonB0284f582016-02-15 23:27:28 +0000101my ( $suite_helpers ) = $test_cases =~ /\/\* BEGIN_SUITE_HELPERS \*\/\n(.*?)\n\/\* END_SUITE_HELPERS \*\//s;
Paul Bakker5690efc2011-05-26 13:16:06 +0000102
103my $requirements;
104if ($suite_defines =~ /^depends_on:/)
105{
106 ( $requirements ) = $suite_defines =~ /^depends_on:(.*)$/;
107}
Paul Bakker19343182013-08-16 13:31:10 +0200108
Paul Bakker5690efc2011-05-26 13:16:06 +0000109my @var_req_arr = split(/:/, $requirements);
110my $suite_pre_code;
111my $suite_post_code;
Paul Bakker19343182013-08-16 13:31:10 +0200112my $dispatch_code;
113my $mapping_code;
114my %mapping_values;
Paul Bakker5690efc2011-05-26 13:16:06 +0000115
116while (@var_req_arr)
117{
118 my $req = shift @var_req_arr;
Manuel Pégourié-Gonnarde46c6c32015-03-23 13:59:10 +0100119 $req =~ s/(!?)(.*)/$1defined($2)/;
Paul Bakker5690efc2011-05-26 13:16:06 +0000120
Manuel Pégourié-Gonnarde46c6c32015-03-23 13:59:10 +0100121 $suite_pre_code .= "#if $req\n";
Paul Bakker5690efc2011-05-26 13:16:06 +0000122 $suite_post_code .= "#endif /* $req */\n";
123}
Paul Bakker367dae42009-06-28 21:50:27 +0000124
125$/ = $line_separator;
126
127open(TEST_FILE, ">$test_file") or die "Opening destination file '$test_file': $!";
128print TEST_FILE << "END";
SimonB0284f582016-02-15 23:27:28 +0000129/*
130 * *** THIS FILE HAS BEEN MACHINE GENERATED ***
131 *
132 * This file has been machine generated using the script: $0
133 *
134 * Test file : $test_file
135 *
136 * The following files were used to create this file.
137 *
138 * Main code file : $test_main_file
139 * Helper file : $test_common_helper_file
140 * Test suite file : $test_case_file
141 * Test suite daya : $test_case_data
142 *
143 *
144 * This file is part of mbed TLS (https://tls.mbed.org)
145 */
146
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200147#if !defined(MBEDTLS_CONFIG_FILE)
Manuel Pégourié-Gonnard7f809972015-03-09 17:05:11 +0000148#include <mbedtls/config.h>
Manuel Pégourié-Gonnardcef4ad22014-04-29 12:39:06 +0200149#else
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200150#include MBEDTLS_CONFIG_FILE
Manuel Pégourié-Gonnardcef4ad22014-04-29 12:39:06 +0200151#endif
Paul Bakker5690efc2011-05-26 13:16:06 +0000152
SimonB0284f582016-02-15 23:27:28 +0000153
154/*----------------------------------------------------------------------------*/
155/* Common helper functions */
156
157$test_common_helpers
158
159
160/*----------------------------------------------------------------------------*/
161/* Test Suite Code */
Rich Evans00ab4702015-02-06 13:43:58 +0000162
Paul Bakkerde56ca12013-09-15 17:05:21 +0200163$suite_pre_code
Paul Bakker367dae42009-06-28 21:50:27 +0000164$suite_header
SimonB0284f582016-02-15 23:27:28 +0000165$suite_helpers
Paul Bakkerde56ca12013-09-15 17:05:21 +0200166$suite_post_code
Paul Bakker367dae42009-06-28 21:50:27 +0000167
Paul Bakker367dae42009-06-28 21:50:27 +0000168END
169
Paul Bakkerb34fef22013-08-20 12:06:33 +0200170$test_main =~ s/SUITE_PRE_DEP/$suite_pre_code/;
171$test_main =~ s/SUITE_POST_DEP/$suite_post_code/;
172
Paul Bakker33b43f12013-08-20 11:48:36 +0200173while($test_cases =~ /\/\* BEGIN_CASE *([\w:]*) \*\/\n(.*?)\n\/\* END_CASE \*\//msg)
Paul Bakker367dae42009-06-28 21:50:27 +0000174{
Paul Bakker19343182013-08-16 13:31:10 +0200175 my $function_deps = $1;
Paul Bakker33b43f12013-08-20 11:48:36 +0200176 my $function_decl = $2;
177
178 # Sanity checks of function
179 if ($function_decl !~ /^void /)
180 {
181 die "Test function does not have 'void' as return type\n";
182 }
Paul Bakker318d0fe2014-07-10 14:59:25 +0200183 if ($function_decl !~ /^void (\w+)\(\s*(.*?)\s*\)\s*{(.*)}/ms)
Paul Bakker33b43f12013-08-20 11:48:36 +0200184 {
185 die "Function declaration not in expected format\n";
186 }
187 my $function_name = $1;
188 my $function_params = $2;
Paul Bakker19343182013-08-16 13:31:10 +0200189 my $function_pre_code;
190 my $function_post_code;
Paul Bakker19343182013-08-16 13:31:10 +0200191 my $param_defs;
192 my $param_checks;
193 my @dispatch_params;
Paul Bakker33b43f12013-08-20 11:48:36 +0200194 my @var_def_arr = split(/,\s*/, $function_params);
Paul Bakker19343182013-08-16 13:31:10 +0200195 my $i = 1;
196 my $mapping_regex = "".$function_name;
197 my $mapping_count = 0;
Paul Bakker367dae42009-06-28 21:50:27 +0000198
Paul Bakker33b43f12013-08-20 11:48:36 +0200199 $function_decl =~ s/^void /void test_suite_/;
200
Paul Bakker318d0fe2014-07-10 14:59:25 +0200201 # Add exit label if not present
202 if ($function_decl !~ /^exit:$/m)
203 {
204 $function_decl =~ s/}\s*$/\nexit:\n return;\n}/;
205 }
206
Paul Bakker19343182013-08-16 13:31:10 +0200207 if ($function_deps =~ /^depends_on:/)
Paul Bakkerccff1672009-10-03 19:57:10 +0000208 {
Paul Bakker19343182013-08-16 13:31:10 +0200209 ( $function_deps ) = $function_deps =~ /^depends_on:(.*)$/;
Paul Bakkerccff1672009-10-03 19:57:10 +0000210 }
211
Paul Bakker19343182013-08-16 13:31:10 +0200212 foreach my $req (split(/:/, $function_deps))
Paul Bakker367dae42009-06-28 21:50:27 +0000213 {
Paul Bakker19343182013-08-16 13:31:10 +0200214 $function_pre_code .= "#ifdef $req\n";
215 $function_post_code .= "#endif /* $req */\n";
Paul Bakker367dae42009-06-28 21:50:27 +0000216 }
Paul Bakker367dae42009-06-28 21:50:27 +0000217
Paul Bakker19343182013-08-16 13:31:10 +0200218 foreach my $def (@var_def_arr)
219 {
220 # Handle the different parameter types
Paul Bakker33b43f12013-08-20 11:48:36 +0200221 if( substr($def, 0, 4) eq "int " )
Paul Bakker19343182013-08-16 13:31:10 +0200222 {
223 $param_defs .= " int param$i;\n";
224 $param_checks .= " if( verify_int( params[$i], &param$i ) != 0 ) return( 2 );\n";
225 push @dispatch_params, "param$i";
Paul Bakker367dae42009-06-28 21:50:27 +0000226
Paul Bakker19343182013-08-16 13:31:10 +0200227 $mapping_regex .= ":([\\d\\w |\\+\\-\\(\\)]+)";
228 $mapping_count++;
229 }
Paul Bakker33b43f12013-08-20 11:48:36 +0200230 elsif( substr($def, 0, 6) eq "char *" )
Paul Bakker19343182013-08-16 13:31:10 +0200231 {
232 $param_defs .= " char *param$i = params[$i];\n";
233 $param_checks .= " if( verify_string( &param$i ) != 0 ) return( 2 );\n";
234 push @dispatch_params, "param$i";
Andres AGf083b312017-02-02 14:36:49 +0000235 $mapping_regex .= ":(?:\\\\.|[^:\n])+";
Paul Bakker19343182013-08-16 13:31:10 +0200236 }
Paul Bakker33b43f12013-08-20 11:48:36 +0200237 else
238 {
239 die "Parameter declaration not of supported type (int, char *)\n";
240 }
Paul Bakker19343182013-08-16 13:31:10 +0200241 $i++;
Paul Bakker367dae42009-06-28 21:50:27 +0000242
Paul Bakker19343182013-08-16 13:31:10 +0200243 }
244
245 # Find non-integer values we should map for this function
246 if( $mapping_count)
247 {
248 my @res = $test_data =~ /^$mapping_regex/msg;
249 foreach my $value (@res)
250 {
Manuel Pégourié-Gonnard18c443d2013-10-17 14:58:24 +0200251 next unless ($value !~ /^\d+$/);
252 if ( $mapping_values{$value} ) {
253 ${ $mapping_values{$value} }{$function_pre_code} = 1;
254 } else {
255 $mapping_values{$value} = { $function_pre_code => 1 };
256 }
Paul Bakker19343182013-08-16 13:31:10 +0200257 }
258 }
259
260 my $call_params = join ", ", @dispatch_params;
261 my $param_count = @var_def_arr + 1;
262 $dispatch_code .= << "END";
263if( strcmp( params[0], "$function_name" ) == 0 )
264{
265$function_pre_code
266$param_defs
267 if( cnt != $param_count )
268 {
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200269 mbedtls_fprintf( stderr, "\\nIncorrect argument count (%d != %d)\\n", cnt, $param_count );
Paul Bakker19343182013-08-16 13:31:10 +0200270 return( 2 );
271 }
272
273$param_checks
Paul Bakker33b43f12013-08-20 11:48:36 +0200274 test_suite_$function_name( $call_params );
275 return ( 0 );
Paul Bakker19343182013-08-16 13:31:10 +0200276$function_post_code
277 return ( 3 );
278}
279else
280END
281
Paul Bakker33b43f12013-08-20 11:48:36 +0200282 my $function_code = $function_pre_code . $function_decl . "\n" . $function_post_code;
283 $test_main =~ s/FUNCTION_CODE/$function_code\nFUNCTION_CODE/;
Paul Bakker19343182013-08-16 13:31:10 +0200284}
285
286# Find specific case dependencies that we should be able to check
287# and make check code
288my $dep_check_code;
289
Hanno Becker276d5302017-07-23 10:24:22 +0100290my @res = $test_data =~ /^depends_on:([!:\w]+)/msg;
Paul Bakker19343182013-08-16 13:31:10 +0200291my %case_deps;
292foreach my $deps (@res)
293{
294 foreach my $dep (split(/:/, $deps))
295 {
296 $case_deps{$dep} = 1;
297 }
298}
299while( my ($key, $value) = each(%case_deps) )
300{
Hanno Becker276d5302017-07-23 10:24:22 +0100301 if( substr($key, 0, 1) eq "!" )
302 {
303 my $key = substr($key, 1);
304 $dep_check_code .= << "END";
305 if( strcmp( str, "!$key" ) == 0 )
306 {
307#if !defined($key)
308 return( 0 );
309#else
310 return( 1 );
311#endif
312 }
313END
314 }
315 else
316 {
317 $dep_check_code .= << "END";
Paul Bakker19343182013-08-16 13:31:10 +0200318 if( strcmp( str, "$key" ) == 0 )
319 {
320#if defined($key)
321 return( 0 );
322#else
323 return( 1 );
324#endif
325 }
Paul Bakker367dae42009-06-28 21:50:27 +0000326END
Hanno Becker276d5302017-07-23 10:24:22 +0100327 }
Paul Bakker367dae42009-06-28 21:50:27 +0000328}
329
Paul Bakker19343182013-08-16 13:31:10 +0200330# Make mapping code
331while( my ($key, $value) = each(%mapping_values) )
332{
Manuel Pégourié-Gonnard18c443d2013-10-17 14:58:24 +0200333 my $key_mapping_code = << "END";
Paul Bakker19343182013-08-16 13:31:10 +0200334 if( strcmp( str, "$key" ) == 0 )
335 {
336 *value = ( $key );
337 return( 0 );
338 }
339END
Manuel Pégourié-Gonnard18c443d2013-10-17 14:58:24 +0200340
341 # handle depenencies, unless used at least one without depends
342 if ($value->{""}) {
343 $mapping_code .= $key_mapping_code;
344 next;
345 }
346 for my $ifdef ( keys %$value ) {
347 (my $endif = $ifdef) =~ s!ifdef!endif //!g;
348 $mapping_code .= $ifdef . $key_mapping_code . $endif;
349 }
Paul Bakker19343182013-08-16 13:31:10 +0200350}
351
352$dispatch_code =~ s/^(.+)/ $1/mg;
353
354$test_main =~ s/TEST_FILENAME/$test_case_data/;
355$test_main =~ s/FUNCTION_CODE//;
356$test_main =~ s/DEP_CHECK_CODE/$dep_check_code/;
357$test_main =~ s/DISPATCH_FUNCTION/$dispatch_code/;
358$test_main =~ s/MAPPING_CODE/$mapping_code/;
359
Paul Bakker367dae42009-06-28 21:50:27 +0000360print TEST_FILE << "END";
Paul Bakker19343182013-08-16 13:31:10 +0200361$test_main
Paul Bakker367dae42009-06-28 21:50:27 +0000362END
363
Paul Bakker367dae42009-06-28 21:50:27 +0000364close(TEST_FILE);