blob: 581320e2d92ad2e3728717808ca390e90f33e903 [file] [log] [blame]
Markus Pfeiffera26a0052014-04-22 20:16:15 +00001#!/usr/bin/env perl
SimonB3ddf3552016-02-10 23:50:28 +00002
3# generate_code.pl
Paul Bakker367dae42009-06-28 21:50:27 +00004#
SimonB3ddf3552016-02-10 23:50:28 +00005# 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
11use strict;
12
13my $suite_dir = shift or die "Missing suite directory";
14my $suite_name = shift or die "Missing suite name";
Paul Bakker46c17942011-07-13 14:54:54 +000015my $data_name = shift or die "Missing data name";
Rich Evansf4253c72015-01-14 19:23:00 +000016my $test_main_file = do { my $arg = shift; defined($arg) ? $arg : $suite_dir."/main_test.function" };
Paul Bakker46c17942011-07-13 14:54:54 +000017my $test_file = $data_name.".c";
Paul Bakker367dae42009-06-28 21:50:27 +000018my $test_helper_file = $suite_dir."/helpers.function";
19my $test_case_file = $suite_dir."/".$suite_name.".function";
Paul Bakker19343182013-08-16 13:31:10 +020020my $test_case_data = $suite_dir."/".$data_name.".data";
Paul Bakker367dae42009-06-28 21:50:27 +000021
22my $line_separator = $/;
23undef $/;
24
25open(TEST_HELPERS, "$test_helper_file") or die "Opening test helpers '$test_helper_file': $!";
26my $test_helpers = <TEST_HELPERS>;
27close(TEST_HELPERS);
28
Paul Bakker19343182013-08-16 13:31:10 +020029open(TEST_MAIN, "$test_main_file") or die "Opening test main '$test_main_file': $!";
30my $test_main = <TEST_MAIN>;
31close(TEST_MAIN);
32
Paul Bakker367dae42009-06-28 21:50:27 +000033open(TEST_CASES, "$test_case_file") or die "Opening test cases '$test_case_file': $!";
34my $test_cases = <TEST_CASES>;
35close(TEST_CASES);
Paul Bakker19343182013-08-16 13:31:10 +020036
37open(TEST_DATA, "$test_case_data") or die "Opening test data '$test_case_data': $!";
38my $test_data = <TEST_DATA>;
39close(TEST_DATA);
40
Paul Bakker33b43f12013-08-20 11:48:36 +020041my ( $suite_header ) = $test_cases =~ /\/\* BEGIN_HEADER \*\/\n(.*?)\n\/\* END_HEADER \*\//s;
42my ( $suite_defines ) = $test_cases =~ /\/\* BEGIN_DEPENDENCIES\n \* (.*?)\n \* END_DEPENDENCIES/s;
Paul Bakker5690efc2011-05-26 13:16:06 +000043
44my $requirements;
45if ($suite_defines =~ /^depends_on:/)
46{
47 ( $requirements ) = $suite_defines =~ /^depends_on:(.*)$/;
48}
Paul Bakker19343182013-08-16 13:31:10 +020049
Paul Bakker5690efc2011-05-26 13:16:06 +000050my @var_req_arr = split(/:/, $requirements);
51my $suite_pre_code;
52my $suite_post_code;
Paul Bakker19343182013-08-16 13:31:10 +020053my $dispatch_code;
54my $mapping_code;
55my %mapping_values;
Paul Bakker5690efc2011-05-26 13:16:06 +000056
57while (@var_req_arr)
58{
59 my $req = shift @var_req_arr;
Manuel Pégourié-Gonnarde46c6c32015-03-23 13:59:10 +010060 $req =~ s/(!?)(.*)/$1defined($2)/;
Paul Bakker5690efc2011-05-26 13:16:06 +000061
Manuel Pégourié-Gonnarde46c6c32015-03-23 13:59:10 +010062 $suite_pre_code .= "#if $req\n";
Paul Bakker5690efc2011-05-26 13:16:06 +000063 $suite_post_code .= "#endif /* $req */\n";
64}
Paul Bakker367dae42009-06-28 21:50:27 +000065
66$/ = $line_separator;
67
68open(TEST_FILE, ">$test_file") or die "Opening destination file '$test_file': $!";
69print TEST_FILE << "END";
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +020070#if !defined(MBEDTLS_CONFIG_FILE)
Manuel Pégourié-Gonnard7f809972015-03-09 17:05:11 +000071#include <mbedtls/config.h>
Manuel Pégourié-Gonnardcef4ad22014-04-29 12:39:06 +020072#else
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +020073#include MBEDTLS_CONFIG_FILE
Manuel Pégourié-Gonnardcef4ad22014-04-29 12:39:06 +020074#endif
Paul Bakker5690efc2011-05-26 13:16:06 +000075
Rich Evans00ab4702015-02-06 13:43:58 +000076$test_helpers
77
Paul Bakkerde56ca12013-09-15 17:05:21 +020078$suite_pre_code
Paul Bakker367dae42009-06-28 21:50:27 +000079$suite_header
Paul Bakkerde56ca12013-09-15 17:05:21 +020080$suite_post_code
Paul Bakker367dae42009-06-28 21:50:27 +000081
Paul Bakker367dae42009-06-28 21:50:27 +000082END
83
Paul Bakkerb34fef22013-08-20 12:06:33 +020084$test_main =~ s/SUITE_PRE_DEP/$suite_pre_code/;
85$test_main =~ s/SUITE_POST_DEP/$suite_post_code/;
86
Paul Bakker33b43f12013-08-20 11:48:36 +020087while($test_cases =~ /\/\* BEGIN_CASE *([\w:]*) \*\/\n(.*?)\n\/\* END_CASE \*\//msg)
Paul Bakker367dae42009-06-28 21:50:27 +000088{
Paul Bakker19343182013-08-16 13:31:10 +020089 my $function_deps = $1;
Paul Bakker33b43f12013-08-20 11:48:36 +020090 my $function_decl = $2;
91
92 # Sanity checks of function
93 if ($function_decl !~ /^void /)
94 {
95 die "Test function does not have 'void' as return type\n";
96 }
Paul Bakker318d0fe2014-07-10 14:59:25 +020097 if ($function_decl !~ /^void (\w+)\(\s*(.*?)\s*\)\s*{(.*)}/ms)
Paul Bakker33b43f12013-08-20 11:48:36 +020098 {
99 die "Function declaration not in expected format\n";
100 }
101 my $function_name = $1;
102 my $function_params = $2;
Paul Bakker19343182013-08-16 13:31:10 +0200103 my $function_pre_code;
104 my $function_post_code;
Paul Bakker19343182013-08-16 13:31:10 +0200105 my $param_defs;
106 my $param_checks;
107 my @dispatch_params;
Paul Bakker33b43f12013-08-20 11:48:36 +0200108 my @var_def_arr = split(/,\s*/, $function_params);
Paul Bakker19343182013-08-16 13:31:10 +0200109 my $i = 1;
110 my $mapping_regex = "".$function_name;
111 my $mapping_count = 0;
Paul Bakker367dae42009-06-28 21:50:27 +0000112
Paul Bakker33b43f12013-08-20 11:48:36 +0200113 $function_decl =~ s/^void /void test_suite_/;
114
Paul Bakker318d0fe2014-07-10 14:59:25 +0200115 # Add exit label if not present
116 if ($function_decl !~ /^exit:$/m)
117 {
118 $function_decl =~ s/}\s*$/\nexit:\n return;\n}/;
119 }
120
Paul Bakker19343182013-08-16 13:31:10 +0200121 if ($function_deps =~ /^depends_on:/)
Paul Bakkerccff1672009-10-03 19:57:10 +0000122 {
Paul Bakker19343182013-08-16 13:31:10 +0200123 ( $function_deps ) = $function_deps =~ /^depends_on:(.*)$/;
Paul Bakkerccff1672009-10-03 19:57:10 +0000124 }
125
Paul Bakker19343182013-08-16 13:31:10 +0200126 foreach my $req (split(/:/, $function_deps))
Paul Bakker367dae42009-06-28 21:50:27 +0000127 {
Paul Bakker19343182013-08-16 13:31:10 +0200128 $function_pre_code .= "#ifdef $req\n";
129 $function_post_code .= "#endif /* $req */\n";
Paul Bakker367dae42009-06-28 21:50:27 +0000130 }
Paul Bakker367dae42009-06-28 21:50:27 +0000131
Paul Bakker19343182013-08-16 13:31:10 +0200132 foreach my $def (@var_def_arr)
133 {
134 # Handle the different parameter types
Paul Bakker33b43f12013-08-20 11:48:36 +0200135 if( substr($def, 0, 4) eq "int " )
Paul Bakker19343182013-08-16 13:31:10 +0200136 {
137 $param_defs .= " int param$i;\n";
138 $param_checks .= " if( verify_int( params[$i], &param$i ) != 0 ) return( 2 );\n";
139 push @dispatch_params, "param$i";
Paul Bakker367dae42009-06-28 21:50:27 +0000140
Paul Bakker19343182013-08-16 13:31:10 +0200141 $mapping_regex .= ":([\\d\\w |\\+\\-\\(\\)]+)";
142 $mapping_count++;
143 }
Paul Bakker33b43f12013-08-20 11:48:36 +0200144 elsif( substr($def, 0, 6) eq "char *" )
Paul Bakker19343182013-08-16 13:31:10 +0200145 {
146 $param_defs .= " char *param$i = params[$i];\n";
147 $param_checks .= " if( verify_string( &param$i ) != 0 ) return( 2 );\n";
148 push @dispatch_params, "param$i";
Manuel Pégourié-Gonnard23c06082015-04-17 10:22:30 +0200149 $mapping_regex .= ":[^:\n]+";
Paul Bakker19343182013-08-16 13:31:10 +0200150 }
Paul Bakker33b43f12013-08-20 11:48:36 +0200151 else
152 {
153 die "Parameter declaration not of supported type (int, char *)\n";
154 }
Paul Bakker19343182013-08-16 13:31:10 +0200155 $i++;
Paul Bakker367dae42009-06-28 21:50:27 +0000156
Paul Bakker19343182013-08-16 13:31:10 +0200157 }
158
159 # Find non-integer values we should map for this function
160 if( $mapping_count)
161 {
162 my @res = $test_data =~ /^$mapping_regex/msg;
163 foreach my $value (@res)
164 {
Manuel Pégourié-Gonnard18c443d2013-10-17 14:58:24 +0200165 next unless ($value !~ /^\d+$/);
166 if ( $mapping_values{$value} ) {
167 ${ $mapping_values{$value} }{$function_pre_code} = 1;
168 } else {
169 $mapping_values{$value} = { $function_pre_code => 1 };
170 }
Paul Bakker19343182013-08-16 13:31:10 +0200171 }
172 }
173
174 my $call_params = join ", ", @dispatch_params;
175 my $param_count = @var_def_arr + 1;
176 $dispatch_code .= << "END";
177if( strcmp( params[0], "$function_name" ) == 0 )
178{
179$function_pre_code
180$param_defs
181 if( cnt != $param_count )
182 {
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200183 mbedtls_fprintf( stderr, "\\nIncorrect argument count (%d != %d)\\n", cnt, $param_count );
Paul Bakker19343182013-08-16 13:31:10 +0200184 return( 2 );
185 }
186
187$param_checks
Paul Bakker33b43f12013-08-20 11:48:36 +0200188 test_suite_$function_name( $call_params );
189 return ( 0 );
Paul Bakker19343182013-08-16 13:31:10 +0200190$function_post_code
191 return ( 3 );
192}
193else
194END
195
Paul Bakker33b43f12013-08-20 11:48:36 +0200196 my $function_code = $function_pre_code . $function_decl . "\n" . $function_post_code;
197 $test_main =~ s/FUNCTION_CODE/$function_code\nFUNCTION_CODE/;
Paul Bakker19343182013-08-16 13:31:10 +0200198}
199
200# Find specific case dependencies that we should be able to check
201# and make check code
202my $dep_check_code;
203
204my @res = $test_data =~ /^depends_on:([\w:]+)/msg;
205my %case_deps;
206foreach my $deps (@res)
207{
208 foreach my $dep (split(/:/, $deps))
209 {
210 $case_deps{$dep} = 1;
211 }
212}
213while( my ($key, $value) = each(%case_deps) )
214{
215 $dep_check_code .= << "END";
216 if( strcmp( str, "$key" ) == 0 )
217 {
218#if defined($key)
219 return( 0 );
220#else
221 return( 1 );
222#endif
223 }
Paul Bakker367dae42009-06-28 21:50:27 +0000224END
225}
226
Paul Bakker19343182013-08-16 13:31:10 +0200227# Make mapping code
228while( my ($key, $value) = each(%mapping_values) )
229{
Manuel Pégourié-Gonnard18c443d2013-10-17 14:58:24 +0200230 my $key_mapping_code = << "END";
Paul Bakker19343182013-08-16 13:31:10 +0200231 if( strcmp( str, "$key" ) == 0 )
232 {
233 *value = ( $key );
234 return( 0 );
235 }
236END
Manuel Pégourié-Gonnard18c443d2013-10-17 14:58:24 +0200237
238 # handle depenencies, unless used at least one without depends
239 if ($value->{""}) {
240 $mapping_code .= $key_mapping_code;
241 next;
242 }
243 for my $ifdef ( keys %$value ) {
244 (my $endif = $ifdef) =~ s!ifdef!endif //!g;
245 $mapping_code .= $ifdef . $key_mapping_code . $endif;
246 }
Paul Bakker19343182013-08-16 13:31:10 +0200247}
248
249$dispatch_code =~ s/^(.+)/ $1/mg;
250
251$test_main =~ s/TEST_FILENAME/$test_case_data/;
252$test_main =~ s/FUNCTION_CODE//;
253$test_main =~ s/DEP_CHECK_CODE/$dep_check_code/;
254$test_main =~ s/DISPATCH_FUNCTION/$dispatch_code/;
255$test_main =~ s/MAPPING_CODE/$mapping_code/;
256
Paul Bakker367dae42009-06-28 21:50:27 +0000257print TEST_FILE << "END";
Paul Bakker19343182013-08-16 13:31:10 +0200258$test_main
Paul Bakker367dae42009-06-28 21:50:27 +0000259END
260
Paul Bakker367dae42009-06-28 21:50:27 +0000261close(TEST_FILE);