blob: 8ab68e0e6dc53bd6522b36a1c65f3cf7be73614d [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#
5# Generates the test suite code given inputs of the test suite directory that
6# contain the test suites, and the test suite file names for the test code and
7# test data.
8#
9# Usage: generate_code.pl <suite dir> <code file> <data file> [main code file]
Paul Bakker367dae42009-06-28 21:50:27 +000010#
Gilles Peskinee38900b2017-09-29 15:45:12 +020011# A test data file consists of a sequence of paragraphs separated by
12# a single empty line. Line breaks may be in Unix (LF) or Windows (CRLF)
13# format. Lines starting with the character '#' are ignored
14# (the parser behaves as if they were not present).
15#
16# Each paragraph describes one test case and must consist of: (1) one
17# line which is the test case name; (2) an optional line starting with
18# the 11-character prefix "depends_on:"; (3) a line containing the test
19# function to execute and its parameters.
20#
21# A depends_on: line consists of a list of compile-time options
22# separated by the character ':', with no whitespace. The test case
23# is executed only if this compilation option is enabled in config.h.
24#
25# The last line of each paragraph contains a test function name and
26# a list of parameters separated by the character ':'. Running the
27# test case calls this function with the specified parameters. Each
28# parameter may either be an integer written in decimal or hexadecimal,
29# or a string surrounded by double quotes which may not contain the
30# ':' character.
Paul Bakker367dae42009-06-28 21:50:27 +000031
32use strict;
33
34my $suite_dir = shift or die "Missing suite directory";
35my $suite_name = shift or die "Missing suite name";
Paul Bakker46c17942011-07-13 14:54:54 +000036my $data_name = shift or die "Missing data name";
Rich Evansf4253c72015-01-14 19:23:00 +000037my $test_main_file = do { my $arg = shift; defined($arg) ? $arg : $suite_dir."/main_test.function" };
Paul Bakker46c17942011-07-13 14:54:54 +000038my $test_file = $data_name.".c";
Paul Bakker367dae42009-06-28 21:50:27 +000039my $test_helper_file = $suite_dir."/helpers.function";
40my $test_case_file = $suite_dir."/".$suite_name.".function";
Paul Bakker19343182013-08-16 13:31:10 +020041my $test_case_data = $suite_dir."/".$data_name.".data";
Paul Bakker367dae42009-06-28 21:50:27 +000042
43my $line_separator = $/;
44undef $/;
45
46open(TEST_HELPERS, "$test_helper_file") or die "Opening test helpers '$test_helper_file': $!";
47my $test_helpers = <TEST_HELPERS>;
48close(TEST_HELPERS);
49
Paul Bakker19343182013-08-16 13:31:10 +020050open(TEST_MAIN, "$test_main_file") or die "Opening test main '$test_main_file': $!";
51my $test_main = <TEST_MAIN>;
52close(TEST_MAIN);
53
Paul Bakker367dae42009-06-28 21:50:27 +000054open(TEST_CASES, "$test_case_file") or die "Opening test cases '$test_case_file': $!";
55my $test_cases = <TEST_CASES>;
56close(TEST_CASES);
Paul Bakker19343182013-08-16 13:31:10 +020057
58open(TEST_DATA, "$test_case_data") or die "Opening test data '$test_case_data': $!";
59my $test_data = <TEST_DATA>;
60close(TEST_DATA);
61
Paul Bakker33b43f12013-08-20 11:48:36 +020062my ( $suite_header ) = $test_cases =~ /\/\* BEGIN_HEADER \*\/\n(.*?)\n\/\* END_HEADER \*\//s;
63my ( $suite_defines ) = $test_cases =~ /\/\* BEGIN_DEPENDENCIES\n \* (.*?)\n \* END_DEPENDENCIES/s;
Paul Bakker5690efc2011-05-26 13:16:06 +000064
65my $requirements;
66if ($suite_defines =~ /^depends_on:/)
67{
68 ( $requirements ) = $suite_defines =~ /^depends_on:(.*)$/;
69}
Paul Bakker19343182013-08-16 13:31:10 +020070
Paul Bakker5690efc2011-05-26 13:16:06 +000071my @var_req_arr = split(/:/, $requirements);
72my $suite_pre_code;
73my $suite_post_code;
Paul Bakker19343182013-08-16 13:31:10 +020074my $dispatch_code;
75my $mapping_code;
76my %mapping_values;
Paul Bakker5690efc2011-05-26 13:16:06 +000077
78while (@var_req_arr)
79{
80 my $req = shift @var_req_arr;
Manuel Pégourié-Gonnarde46c6c32015-03-23 13:59:10 +010081 $req =~ s/(!?)(.*)/$1defined($2)/;
Paul Bakker5690efc2011-05-26 13:16:06 +000082
Manuel Pégourié-Gonnarde46c6c32015-03-23 13:59:10 +010083 $suite_pre_code .= "#if $req\n";
Paul Bakker5690efc2011-05-26 13:16:06 +000084 $suite_post_code .= "#endif /* $req */\n";
85}
Paul Bakker367dae42009-06-28 21:50:27 +000086
87$/ = $line_separator;
88
89open(TEST_FILE, ">$test_file") or die "Opening destination file '$test_file': $!";
90print TEST_FILE << "END";
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +020091#if !defined(MBEDTLS_CONFIG_FILE)
Manuel Pégourié-Gonnard7f809972015-03-09 17:05:11 +000092#include <mbedtls/config.h>
Manuel Pégourié-Gonnardcef4ad22014-04-29 12:39:06 +020093#else
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +020094#include MBEDTLS_CONFIG_FILE
Manuel Pégourié-Gonnardcef4ad22014-04-29 12:39:06 +020095#endif
Paul Bakker5690efc2011-05-26 13:16:06 +000096
Rich Evans00ab4702015-02-06 13:43:58 +000097$test_helpers
98
Paul Bakkerde56ca12013-09-15 17:05:21 +020099$suite_pre_code
Paul Bakker367dae42009-06-28 21:50:27 +0000100$suite_header
Paul Bakkerde56ca12013-09-15 17:05:21 +0200101$suite_post_code
Paul Bakker367dae42009-06-28 21:50:27 +0000102
Paul Bakker367dae42009-06-28 21:50:27 +0000103END
104
Paul Bakkerb34fef22013-08-20 12:06:33 +0200105$test_main =~ s/SUITE_PRE_DEP/$suite_pre_code/;
106$test_main =~ s/SUITE_POST_DEP/$suite_post_code/;
107
Paul Bakker33b43f12013-08-20 11:48:36 +0200108while($test_cases =~ /\/\* BEGIN_CASE *([\w:]*) \*\/\n(.*?)\n\/\* END_CASE \*\//msg)
Paul Bakker367dae42009-06-28 21:50:27 +0000109{
Paul Bakker19343182013-08-16 13:31:10 +0200110 my $function_deps = $1;
Paul Bakker33b43f12013-08-20 11:48:36 +0200111 my $function_decl = $2;
112
113 # Sanity checks of function
114 if ($function_decl !~ /^void /)
115 {
116 die "Test function does not have 'void' as return type\n";
117 }
Paul Bakker318d0fe2014-07-10 14:59:25 +0200118 if ($function_decl !~ /^void (\w+)\(\s*(.*?)\s*\)\s*{(.*)}/ms)
Paul Bakker33b43f12013-08-20 11:48:36 +0200119 {
120 die "Function declaration not in expected format\n";
121 }
122 my $function_name = $1;
123 my $function_params = $2;
Paul Bakker19343182013-08-16 13:31:10 +0200124 my $function_pre_code;
125 my $function_post_code;
Paul Bakker19343182013-08-16 13:31:10 +0200126 my $param_defs;
127 my $param_checks;
128 my @dispatch_params;
Paul Bakker33b43f12013-08-20 11:48:36 +0200129 my @var_def_arr = split(/,\s*/, $function_params);
Paul Bakker19343182013-08-16 13:31:10 +0200130 my $i = 1;
131 my $mapping_regex = "".$function_name;
132 my $mapping_count = 0;
Paul Bakker367dae42009-06-28 21:50:27 +0000133
Paul Bakker33b43f12013-08-20 11:48:36 +0200134 $function_decl =~ s/^void /void test_suite_/;
135
Paul Bakker318d0fe2014-07-10 14:59:25 +0200136 # Add exit label if not present
137 if ($function_decl !~ /^exit:$/m)
138 {
139 $function_decl =~ s/}\s*$/\nexit:\n return;\n}/;
140 }
141
Paul Bakker19343182013-08-16 13:31:10 +0200142 if ($function_deps =~ /^depends_on:/)
Paul Bakkerccff1672009-10-03 19:57:10 +0000143 {
Paul Bakker19343182013-08-16 13:31:10 +0200144 ( $function_deps ) = $function_deps =~ /^depends_on:(.*)$/;
Paul Bakkerccff1672009-10-03 19:57:10 +0000145 }
146
Paul Bakker19343182013-08-16 13:31:10 +0200147 foreach my $req (split(/:/, $function_deps))
Paul Bakker367dae42009-06-28 21:50:27 +0000148 {
Paul Bakker19343182013-08-16 13:31:10 +0200149 $function_pre_code .= "#ifdef $req\n";
150 $function_post_code .= "#endif /* $req */\n";
Paul Bakker367dae42009-06-28 21:50:27 +0000151 }
Paul Bakker367dae42009-06-28 21:50:27 +0000152
Paul Bakker19343182013-08-16 13:31:10 +0200153 foreach my $def (@var_def_arr)
154 {
155 # Handle the different parameter types
Paul Bakker33b43f12013-08-20 11:48:36 +0200156 if( substr($def, 0, 4) eq "int " )
Paul Bakker19343182013-08-16 13:31:10 +0200157 {
158 $param_defs .= " int param$i;\n";
159 $param_checks .= " if( verify_int( params[$i], &param$i ) != 0 ) return( 2 );\n";
160 push @dispatch_params, "param$i";
Paul Bakker367dae42009-06-28 21:50:27 +0000161
Paul Bakker19343182013-08-16 13:31:10 +0200162 $mapping_regex .= ":([\\d\\w |\\+\\-\\(\\)]+)";
163 $mapping_count++;
164 }
Paul Bakker33b43f12013-08-20 11:48:36 +0200165 elsif( substr($def, 0, 6) eq "char *" )
Paul Bakker19343182013-08-16 13:31:10 +0200166 {
167 $param_defs .= " char *param$i = params[$i];\n";
168 $param_checks .= " if( verify_string( &param$i ) != 0 ) return( 2 );\n";
169 push @dispatch_params, "param$i";
Andres AGf083b312017-02-02 14:36:49 +0000170 $mapping_regex .= ":(?:\\\\.|[^:\n])+";
Paul Bakker19343182013-08-16 13:31:10 +0200171 }
Paul Bakker33b43f12013-08-20 11:48:36 +0200172 else
173 {
174 die "Parameter declaration not of supported type (int, char *)\n";
175 }
Paul Bakker19343182013-08-16 13:31:10 +0200176 $i++;
Paul Bakker367dae42009-06-28 21:50:27 +0000177
Paul Bakker19343182013-08-16 13:31:10 +0200178 }
179
180 # Find non-integer values we should map for this function
181 if( $mapping_count)
182 {
183 my @res = $test_data =~ /^$mapping_regex/msg;
184 foreach my $value (@res)
185 {
Manuel Pégourié-Gonnard18c443d2013-10-17 14:58:24 +0200186 next unless ($value !~ /^\d+$/);
187 if ( $mapping_values{$value} ) {
188 ${ $mapping_values{$value} }{$function_pre_code} = 1;
189 } else {
190 $mapping_values{$value} = { $function_pre_code => 1 };
191 }
Paul Bakker19343182013-08-16 13:31:10 +0200192 }
193 }
194
195 my $call_params = join ", ", @dispatch_params;
196 my $param_count = @var_def_arr + 1;
197 $dispatch_code .= << "END";
198if( strcmp( params[0], "$function_name" ) == 0 )
199{
200$function_pre_code
201$param_defs
202 if( cnt != $param_count )
203 {
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200204 mbedtls_fprintf( stderr, "\\nIncorrect argument count (%d != %d)\\n", cnt, $param_count );
Paul Bakker19343182013-08-16 13:31:10 +0200205 return( 2 );
206 }
207
208$param_checks
Paul Bakker33b43f12013-08-20 11:48:36 +0200209 test_suite_$function_name( $call_params );
210 return ( 0 );
Paul Bakker19343182013-08-16 13:31:10 +0200211$function_post_code
212 return ( 3 );
213}
214else
215END
216
Paul Bakker33b43f12013-08-20 11:48:36 +0200217 my $function_code = $function_pre_code . $function_decl . "\n" . $function_post_code;
218 $test_main =~ s/FUNCTION_CODE/$function_code\nFUNCTION_CODE/;
Paul Bakker19343182013-08-16 13:31:10 +0200219}
220
221# Find specific case dependencies that we should be able to check
222# and make check code
223my $dep_check_code;
224
Hanno Becker276d5302017-07-23 10:24:22 +0100225my @res = $test_data =~ /^depends_on:([!:\w]+)/msg;
Paul Bakker19343182013-08-16 13:31:10 +0200226my %case_deps;
227foreach my $deps (@res)
228{
229 foreach my $dep (split(/:/, $deps))
230 {
231 $case_deps{$dep} = 1;
232 }
233}
234while( my ($key, $value) = each(%case_deps) )
235{
Hanno Becker276d5302017-07-23 10:24:22 +0100236 if( substr($key, 0, 1) eq "!" )
237 {
238 my $key = substr($key, 1);
239 $dep_check_code .= << "END";
240 if( strcmp( str, "!$key" ) == 0 )
241 {
242#if !defined($key)
243 return( 0 );
244#else
245 return( 1 );
246#endif
247 }
248END
249 }
250 else
251 {
252 $dep_check_code .= << "END";
Paul Bakker19343182013-08-16 13:31:10 +0200253 if( strcmp( str, "$key" ) == 0 )
254 {
255#if defined($key)
256 return( 0 );
257#else
258 return( 1 );
259#endif
260 }
Paul Bakker367dae42009-06-28 21:50:27 +0000261END
Hanno Becker276d5302017-07-23 10:24:22 +0100262 }
Paul Bakker367dae42009-06-28 21:50:27 +0000263}
264
Paul Bakker19343182013-08-16 13:31:10 +0200265# Make mapping code
266while( my ($key, $value) = each(%mapping_values) )
267{
Manuel Pégourié-Gonnard18c443d2013-10-17 14:58:24 +0200268 my $key_mapping_code = << "END";
Paul Bakker19343182013-08-16 13:31:10 +0200269 if( strcmp( str, "$key" ) == 0 )
270 {
271 *value = ( $key );
272 return( 0 );
273 }
274END
Manuel Pégourié-Gonnard18c443d2013-10-17 14:58:24 +0200275
276 # handle depenencies, unless used at least one without depends
277 if ($value->{""}) {
278 $mapping_code .= $key_mapping_code;
279 next;
280 }
281 for my $ifdef ( keys %$value ) {
282 (my $endif = $ifdef) =~ s!ifdef!endif //!g;
283 $mapping_code .= $ifdef . $key_mapping_code . $endif;
284 }
Paul Bakker19343182013-08-16 13:31:10 +0200285}
286
287$dispatch_code =~ s/^(.+)/ $1/mg;
288
289$test_main =~ s/TEST_FILENAME/$test_case_data/;
290$test_main =~ s/FUNCTION_CODE//;
291$test_main =~ s/DEP_CHECK_CODE/$dep_check_code/;
292$test_main =~ s/DISPATCH_FUNCTION/$dispatch_code/;
293$test_main =~ s/MAPPING_CODE/$mapping_code/;
294
Paul Bakker367dae42009-06-28 21:50:27 +0000295print TEST_FILE << "END";
Paul Bakker19343182013-08-16 13:31:10 +0200296$test_main
Paul Bakker367dae42009-06-28 21:50:27 +0000297END
298
Paul Bakker367dae42009-06-28 21:50:27 +0000299close(TEST_FILE);