blob: 5c623f8a744e8cc3b9110db4e44d9500ba184ebb [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#
Simon Butcher64d60da2016-03-01 18:35:02 +00005# Copyright (c) 2009-2016, ARM Limited, All Rights Reserved
6#
SimonB152ea182016-02-15 23:27:28 +00007# Purpose
8#
SimonB3ddf3552016-02-10 23:50:28 +00009# Generates the test suite code given inputs of the test suite directory that
10# contain the test suites, and the test suite file names for the test code and
11# test data.
12#
13# Usage: generate_code.pl <suite dir> <code file> <data file> [main code file]
SimonB152ea182016-02-15 23:27:28 +000014#
15# Structure of files
16#
17# - main code file - 'main_test.function'
18# Template file that contains the main() function for the test suite,
19# test dispatch code as well as support functions. It contains the
20# following symbols which are substituted by this script during
21# processing:
22# TEST_FILENAME
23# SUITE_PRE_DEP
24# MAPPING_CODE
25# FUNCTION CODE
26# SUITE_POST_DEP
27# DEP_CHECK_CODE
28# DISPATCH_FUNCTION
29#
30# - common helper code file - 'helpers.function'
31# Common helper functions
32#
33# - test suite code file - file name in the form 'test_suite_xxx.function'
34# Code file that contains the actual test cases. The file contains a
35# series of code sequences delimited by the following:
36# BEGIN_HEADER / END_HEADER - list of headers files
37# BEGIN_SUITE_HELPERS / END_SUITE_HELPERS - helper functions common to
38# the test suite
39# BEGIN_CASE / END_CASE - the test cases in the test suite. Each test
40# case contains at least one function that is used to create the
41# dispatch code.
42#
43# - test data file - file name in the form 'test_suite_xxxx.data'
44# The test case parameters to to be used in execution of the test. The
45# file name is used to replace the symbol 'TEST_FILENAME' in the main code
46# file above.
47#
Paul Bakker367dae42009-06-28 21:50:27 +000048
49use strict;
50
51my $suite_dir = shift or die "Missing suite directory";
52my $suite_name = shift or die "Missing suite name";
Paul Bakker46c17942011-07-13 14:54:54 +000053my $data_name = shift or die "Missing data name";
Rich Evansf4253c72015-01-14 19:23:00 +000054my $test_main_file = do { my $arg = shift; defined($arg) ? $arg : $suite_dir."/main_test.function" };
Paul Bakker46c17942011-07-13 14:54:54 +000055my $test_file = $data_name.".c";
SimonB152ea182016-02-15 23:27:28 +000056my $test_common_helper_file = $suite_dir."/helpers.function";
Paul Bakker367dae42009-06-28 21:50:27 +000057my $test_case_file = $suite_dir."/".$suite_name.".function";
Paul Bakker19343182013-08-16 13:31:10 +020058my $test_case_data = $suite_dir."/".$data_name.".data";
Paul Bakker367dae42009-06-28 21:50:27 +000059
60my $line_separator = $/;
61undef $/;
62
SimonB152ea182016-02-15 23:27:28 +000063open(TEST_HELPERS, "$test_common_helper_file") or die "Opening test helpers
64'$test_common_helper_file': $!";
65my $test_common_helpers = <TEST_HELPERS>;
Paul Bakker367dae42009-06-28 21:50:27 +000066close(TEST_HELPERS);
67
Paul Bakker19343182013-08-16 13:31:10 +020068open(TEST_MAIN, "$test_main_file") or die "Opening test main '$test_main_file': $!";
69my $test_main = <TEST_MAIN>;
70close(TEST_MAIN);
71
Paul Bakker367dae42009-06-28 21:50:27 +000072open(TEST_CASES, "$test_case_file") or die "Opening test cases '$test_case_file': $!";
73my $test_cases = <TEST_CASES>;
74close(TEST_CASES);
Paul Bakker19343182013-08-16 13:31:10 +020075
76open(TEST_DATA, "$test_case_data") or die "Opening test data '$test_case_data': $!";
77my $test_data = <TEST_DATA>;
78close(TEST_DATA);
79
Paul Bakker33b43f12013-08-20 11:48:36 +020080my ( $suite_header ) = $test_cases =~ /\/\* BEGIN_HEADER \*\/\n(.*?)\n\/\* END_HEADER \*\//s;
81my ( $suite_defines ) = $test_cases =~ /\/\* BEGIN_DEPENDENCIES\n \* (.*?)\n \* END_DEPENDENCIES/s;
SimonB152ea182016-02-15 23:27:28 +000082my ( $suite_helpers ) = $test_cases =~ /\/\* BEGIN_SUITE_HELPERS \*\/\n(.*?)\n\/\* END_SUITE_HELPERS \*\//s;
Paul Bakker5690efc2011-05-26 13:16:06 +000083
84my $requirements;
85if ($suite_defines =~ /^depends_on:/)
86{
87 ( $requirements ) = $suite_defines =~ /^depends_on:(.*)$/;
88}
Paul Bakker19343182013-08-16 13:31:10 +020089
Paul Bakker5690efc2011-05-26 13:16:06 +000090my @var_req_arr = split(/:/, $requirements);
91my $suite_pre_code;
92my $suite_post_code;
Paul Bakker19343182013-08-16 13:31:10 +020093my $dispatch_code;
94my $mapping_code;
95my %mapping_values;
Paul Bakker5690efc2011-05-26 13:16:06 +000096
97while (@var_req_arr)
98{
99 my $req = shift @var_req_arr;
Manuel Pégourié-Gonnarde46c6c32015-03-23 13:59:10 +0100100 $req =~ s/(!?)(.*)/$1defined($2)/;
Paul Bakker5690efc2011-05-26 13:16:06 +0000101
Manuel Pégourié-Gonnarde46c6c32015-03-23 13:59:10 +0100102 $suite_pre_code .= "#if $req\n";
Paul Bakker5690efc2011-05-26 13:16:06 +0000103 $suite_post_code .= "#endif /* $req */\n";
104}
Paul Bakker367dae42009-06-28 21:50:27 +0000105
106$/ = $line_separator;
107
108open(TEST_FILE, ">$test_file") or die "Opening destination file '$test_file': $!";
109print TEST_FILE << "END";
SimonB152ea182016-02-15 23:27:28 +0000110/*
111 * *** THIS FILE HAS BEEN MACHINE GENERATED ***
112 *
113 * This file has been machine generated using the script: $0
114 *
115 * Test file : $test_file
116 *
117 * The following files were used to create this file.
118 *
119 * Main code file : $test_main_file
120 * Helper file : $test_common_helper_file
121 * Test suite file : $test_case_file
Simon Butcher64d60da2016-03-01 18:35:02 +0000122 * Test suite data : $test_case_data
SimonB152ea182016-02-15 23:27:28 +0000123 *
124 *
125 * This file is part of mbed TLS (https://tls.mbed.org)
126 */
127
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200128#if !defined(MBEDTLS_CONFIG_FILE)
Manuel Pégourié-Gonnard7f809972015-03-09 17:05:11 +0000129#include <mbedtls/config.h>
Manuel Pégourié-Gonnardcef4ad22014-04-29 12:39:06 +0200130#else
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200131#include MBEDTLS_CONFIG_FILE
Manuel Pégourié-Gonnardcef4ad22014-04-29 12:39:06 +0200132#endif
Paul Bakker5690efc2011-05-26 13:16:06 +0000133
SimonB152ea182016-02-15 23:27:28 +0000134
135/*----------------------------------------------------------------------------*/
SimonB0269dad2016-02-17 23:34:30 +0000136/* Common helper code */
SimonB152ea182016-02-15 23:27:28 +0000137
138$test_common_helpers
139
140
141/*----------------------------------------------------------------------------*/
142/* Test Suite Code */
Rich Evans00ab4702015-02-06 13:43:58 +0000143
Paul Bakkerde56ca12013-09-15 17:05:21 +0200144$suite_pre_code
Paul Bakker367dae42009-06-28 21:50:27 +0000145$suite_header
SimonB152ea182016-02-15 23:27:28 +0000146$suite_helpers
Paul Bakkerde56ca12013-09-15 17:05:21 +0200147$suite_post_code
Paul Bakker367dae42009-06-28 21:50:27 +0000148
Paul Bakker367dae42009-06-28 21:50:27 +0000149END
150
Paul Bakkerb34fef22013-08-20 12:06:33 +0200151$test_main =~ s/SUITE_PRE_DEP/$suite_pre_code/;
152$test_main =~ s/SUITE_POST_DEP/$suite_post_code/;
153
Paul Bakker33b43f12013-08-20 11:48:36 +0200154while($test_cases =~ /\/\* BEGIN_CASE *([\w:]*) \*\/\n(.*?)\n\/\* END_CASE \*\//msg)
Paul Bakker367dae42009-06-28 21:50:27 +0000155{
Paul Bakker19343182013-08-16 13:31:10 +0200156 my $function_deps = $1;
Paul Bakker33b43f12013-08-20 11:48:36 +0200157 my $function_decl = $2;
158
159 # Sanity checks of function
160 if ($function_decl !~ /^void /)
161 {
162 die "Test function does not have 'void' as return type\n";
163 }
Paul Bakker318d0fe2014-07-10 14:59:25 +0200164 if ($function_decl !~ /^void (\w+)\(\s*(.*?)\s*\)\s*{(.*)}/ms)
Paul Bakker33b43f12013-08-20 11:48:36 +0200165 {
166 die "Function declaration not in expected format\n";
167 }
168 my $function_name = $1;
169 my $function_params = $2;
Paul Bakker19343182013-08-16 13:31:10 +0200170 my $function_pre_code;
171 my $function_post_code;
Paul Bakker19343182013-08-16 13:31:10 +0200172 my $param_defs;
173 my $param_checks;
174 my @dispatch_params;
Paul Bakker33b43f12013-08-20 11:48:36 +0200175 my @var_def_arr = split(/,\s*/, $function_params);
Paul Bakker19343182013-08-16 13:31:10 +0200176 my $i = 1;
177 my $mapping_regex = "".$function_name;
178 my $mapping_count = 0;
Paul Bakker367dae42009-06-28 21:50:27 +0000179
Paul Bakker33b43f12013-08-20 11:48:36 +0200180 $function_decl =~ s/^void /void test_suite_/;
181
Paul Bakker318d0fe2014-07-10 14:59:25 +0200182 # Add exit label if not present
183 if ($function_decl !~ /^exit:$/m)
184 {
185 $function_decl =~ s/}\s*$/\nexit:\n return;\n}/;
186 }
187
Paul Bakker19343182013-08-16 13:31:10 +0200188 if ($function_deps =~ /^depends_on:/)
Paul Bakkerccff1672009-10-03 19:57:10 +0000189 {
Paul Bakker19343182013-08-16 13:31:10 +0200190 ( $function_deps ) = $function_deps =~ /^depends_on:(.*)$/;
Paul Bakkerccff1672009-10-03 19:57:10 +0000191 }
192
Paul Bakker19343182013-08-16 13:31:10 +0200193 foreach my $req (split(/:/, $function_deps))
Paul Bakker367dae42009-06-28 21:50:27 +0000194 {
Paul Bakker19343182013-08-16 13:31:10 +0200195 $function_pre_code .= "#ifdef $req\n";
196 $function_post_code .= "#endif /* $req */\n";
Paul Bakker367dae42009-06-28 21:50:27 +0000197 }
Paul Bakker367dae42009-06-28 21:50:27 +0000198
Paul Bakker19343182013-08-16 13:31:10 +0200199 foreach my $def (@var_def_arr)
200 {
201 # Handle the different parameter types
Paul Bakker33b43f12013-08-20 11:48:36 +0200202 if( substr($def, 0, 4) eq "int " )
Paul Bakker19343182013-08-16 13:31:10 +0200203 {
204 $param_defs .= " int param$i;\n";
205 $param_checks .= " if( verify_int( params[$i], &param$i ) != 0 ) return( 2 );\n";
206 push @dispatch_params, "param$i";
Paul Bakker367dae42009-06-28 21:50:27 +0000207
Paul Bakker19343182013-08-16 13:31:10 +0200208 $mapping_regex .= ":([\\d\\w |\\+\\-\\(\\)]+)";
209 $mapping_count++;
210 }
Paul Bakker33b43f12013-08-20 11:48:36 +0200211 elsif( substr($def, 0, 6) eq "char *" )
Paul Bakker19343182013-08-16 13:31:10 +0200212 {
213 $param_defs .= " char *param$i = params[$i];\n";
214 $param_checks .= " if( verify_string( &param$i ) != 0 ) return( 2 );\n";
215 push @dispatch_params, "param$i";
Manuel Pégourié-Gonnard23c06082015-04-17 10:22:30 +0200216 $mapping_regex .= ":[^:\n]+";
Paul Bakker19343182013-08-16 13:31:10 +0200217 }
Paul Bakker33b43f12013-08-20 11:48:36 +0200218 else
219 {
220 die "Parameter declaration not of supported type (int, char *)\n";
221 }
Paul Bakker19343182013-08-16 13:31:10 +0200222 $i++;
Paul Bakker367dae42009-06-28 21:50:27 +0000223
Paul Bakker19343182013-08-16 13:31:10 +0200224 }
225
226 # Find non-integer values we should map for this function
227 if( $mapping_count)
228 {
229 my @res = $test_data =~ /^$mapping_regex/msg;
230 foreach my $value (@res)
231 {
Manuel Pégourié-Gonnard18c443d2013-10-17 14:58:24 +0200232 next unless ($value !~ /^\d+$/);
233 if ( $mapping_values{$value} ) {
234 ${ $mapping_values{$value} }{$function_pre_code} = 1;
235 } else {
236 $mapping_values{$value} = { $function_pre_code => 1 };
237 }
Paul Bakker19343182013-08-16 13:31:10 +0200238 }
239 }
240
241 my $call_params = join ", ", @dispatch_params;
242 my $param_count = @var_def_arr + 1;
243 $dispatch_code .= << "END";
244if( strcmp( params[0], "$function_name" ) == 0 )
245{
246$function_pre_code
247$param_defs
248 if( cnt != $param_count )
249 {
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200250 mbedtls_fprintf( stderr, "\\nIncorrect argument count (%d != %d)\\n", cnt, $param_count );
Paul Bakker19343182013-08-16 13:31:10 +0200251 return( 2 );
252 }
253
254$param_checks
Paul Bakker33b43f12013-08-20 11:48:36 +0200255 test_suite_$function_name( $call_params );
256 return ( 0 );
Paul Bakker19343182013-08-16 13:31:10 +0200257$function_post_code
258 return ( 3 );
259}
260else
261END
262
Paul Bakker33b43f12013-08-20 11:48:36 +0200263 my $function_code = $function_pre_code . $function_decl . "\n" . $function_post_code;
264 $test_main =~ s/FUNCTION_CODE/$function_code\nFUNCTION_CODE/;
Paul Bakker19343182013-08-16 13:31:10 +0200265}
266
267# Find specific case dependencies that we should be able to check
268# and make check code
269my $dep_check_code;
270
271my @res = $test_data =~ /^depends_on:([\w:]+)/msg;
272my %case_deps;
273foreach my $deps (@res)
274{
275 foreach my $dep (split(/:/, $deps))
276 {
277 $case_deps{$dep} = 1;
278 }
279}
280while( my ($key, $value) = each(%case_deps) )
281{
282 $dep_check_code .= << "END";
283 if( strcmp( str, "$key" ) == 0 )
284 {
285#if defined($key)
286 return( 0 );
287#else
288 return( 1 );
289#endif
290 }
Paul Bakker367dae42009-06-28 21:50:27 +0000291END
292}
293
Paul Bakker19343182013-08-16 13:31:10 +0200294# Make mapping code
295while( my ($key, $value) = each(%mapping_values) )
296{
Manuel Pégourié-Gonnard18c443d2013-10-17 14:58:24 +0200297 my $key_mapping_code = << "END";
Paul Bakker19343182013-08-16 13:31:10 +0200298 if( strcmp( str, "$key" ) == 0 )
299 {
300 *value = ( $key );
301 return( 0 );
302 }
303END
Manuel Pégourié-Gonnard18c443d2013-10-17 14:58:24 +0200304
305 # handle depenencies, unless used at least one without depends
306 if ($value->{""}) {
307 $mapping_code .= $key_mapping_code;
308 next;
309 }
310 for my $ifdef ( keys %$value ) {
311 (my $endif = $ifdef) =~ s!ifdef!endif //!g;
312 $mapping_code .= $ifdef . $key_mapping_code . $endif;
313 }
Paul Bakker19343182013-08-16 13:31:10 +0200314}
315
316$dispatch_code =~ s/^(.+)/ $1/mg;
317
318$test_main =~ s/TEST_FILENAME/$test_case_data/;
319$test_main =~ s/FUNCTION_CODE//;
320$test_main =~ s/DEP_CHECK_CODE/$dep_check_code/;
321$test_main =~ s/DISPATCH_FUNCTION/$dispatch_code/;
322$test_main =~ s/MAPPING_CODE/$mapping_code/;
323
Paul Bakker367dae42009-06-28 21:50:27 +0000324print TEST_FILE << "END";
Paul Bakker19343182013-08-16 13:31:10 +0200325$test_main
Paul Bakker367dae42009-06-28 21:50:27 +0000326END
327
Paul Bakker367dae42009-06-28 21:50:27 +0000328close(TEST_FILE);