blob: 548c68cd283187c3fe216f0dab548fc9e21bf18f [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#
Simon Butcher60411a82016-03-01 18:35:02 +00005# Copyright (c) 2009-2016, ARM Limited, All Rights Reserved
6#
SimonB0284f582016-02-15 23:27:28 +00007# Purpose
8#
SimonBe39088a2016-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]
Paul Bakker367dae42009-06-28 21:50:27 +000014#
SimonB0284f582016-02-15 23:27:28 +000015# 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
46# code file above.
47#
Gilles Peskinee38900b2017-09-29 15:45:12 +020048# A test data file consists of a sequence of paragraphs separated by
49# a single empty line. Line breaks may be in Unix (LF) or Windows (CRLF)
50# format. Lines starting with the character '#' are ignored
51# (the parser behaves as if they were not present).
52#
53# Each paragraph describes one test case and must consist of: (1) one
54# line which is the test case name; (2) an optional line starting with
55# the 11-character prefix "depends_on:"; (3) a line containing the test
56# function to execute and its parameters.
57#
58# A depends_on: line consists of a list of compile-time options
59# separated by the character ':', with no whitespace. The test case
60# is executed only if this compilation option is enabled in config.h.
61#
62# The last line of each paragraph contains a test function name and
63# a list of parameters separated by the character ':'. Running the
64# test case calls this function with the specified parameters. Each
65# parameter may either be an integer written in decimal or hexadecimal,
66# or a string surrounded by double quotes which may not contain the
67# ':' character.
SimonB0284f582016-02-15 23:27:28 +000068#
Paul Bakker367dae42009-06-28 21:50:27 +000069
70use strict;
71
72my $suite_dir = shift or die "Missing suite directory";
73my $suite_name = shift or die "Missing suite name";
Paul Bakker46c17942011-07-13 14:54:54 +000074my $data_name = shift or die "Missing data name";
Rich Evansf4253c72015-01-14 19:23:00 +000075my $test_main_file = do { my $arg = shift; defined($arg) ? $arg : $suite_dir."/main_test.function" };
Paul Bakker46c17942011-07-13 14:54:54 +000076my $test_file = $data_name.".c";
SimonB0284f582016-02-15 23:27:28 +000077my $test_common_helper_file = $suite_dir."/helpers.function";
Paul Bakker367dae42009-06-28 21:50:27 +000078my $test_case_file = $suite_dir."/".$suite_name.".function";
Paul Bakker19343182013-08-16 13:31:10 +020079my $test_case_data = $suite_dir."/".$data_name.".data";
Paul Bakker367dae42009-06-28 21:50:27 +000080
81my $line_separator = $/;
82undef $/;
83
SimonB0284f582016-02-15 23:27:28 +000084open(TEST_HELPERS, "$test_common_helper_file") or die "Opening test helpers
85'$test_common_helper_file': $!";
86my $test_common_helpers = <TEST_HELPERS>;
Paul Bakker367dae42009-06-28 21:50:27 +000087close(TEST_HELPERS);
88
Paul Bakker19343182013-08-16 13:31:10 +020089open(TEST_MAIN, "$test_main_file") or die "Opening test main '$test_main_file': $!";
Gilles Peskinebe807262018-03-13 16:07:01 +010090my @test_main_lines = split/^/, <TEST_MAIN>;
91my $test_main;
92my $index = 2;
93for my $line (@test_main_lines) {
94 $line =~ s/!LINE_NO!/$index/;
95 $test_main = $test_main.$line;
96 $index++;
97}
Paul Bakker19343182013-08-16 13:31:10 +020098close(TEST_MAIN);
99
Paul Bakker367dae42009-06-28 21:50:27 +0000100open(TEST_CASES, "$test_case_file") or die "Opening test cases '$test_case_file': $!";
Gilles Peskinebe807262018-03-13 16:07:01 +0100101my @test_cases_lines = split/^/, <TEST_CASES>;
102my $test_cases;
103my $index = 2;
104for my $line (@test_cases_lines) {
105 if ($line =~ /^\/\* BEGIN_SUITE_HELPERS .*\*\//)
106 {
107 $line = $line."#line $index \"$test_case_file\"\n";
108 }
109
110 if ($line =~ /^\/\* BEGIN_CASE .*\*\//)
111 {
112 $line = $line."#line $index \"$test_case_file\"\n";
113 }
114
115 $line =~ s/!LINE_NO!/$index/;
116
117 $test_cases = $test_cases.$line;
118 $index++;
119}
120
Paul Bakker367dae42009-06-28 21:50:27 +0000121close(TEST_CASES);
Paul Bakker19343182013-08-16 13:31:10 +0200122
123open(TEST_DATA, "$test_case_data") or die "Opening test data '$test_case_data': $!";
124my $test_data = <TEST_DATA>;
125close(TEST_DATA);
126
Paul Bakker33b43f12013-08-20 11:48:36 +0200127my ( $suite_header ) = $test_cases =~ /\/\* BEGIN_HEADER \*\/\n(.*?)\n\/\* END_HEADER \*\//s;
128my ( $suite_defines ) = $test_cases =~ /\/\* BEGIN_DEPENDENCIES\n \* (.*?)\n \* END_DEPENDENCIES/s;
SimonB0284f582016-02-15 23:27:28 +0000129my ( $suite_helpers ) = $test_cases =~ /\/\* BEGIN_SUITE_HELPERS \*\/\n(.*?)\n\/\* END_SUITE_HELPERS \*\//s;
Paul Bakker5690efc2011-05-26 13:16:06 +0000130
131my $requirements;
132if ($suite_defines =~ /^depends_on:/)
133{
134 ( $requirements ) = $suite_defines =~ /^depends_on:(.*)$/;
135}
Paul Bakker19343182013-08-16 13:31:10 +0200136
Paul Bakker5690efc2011-05-26 13:16:06 +0000137my @var_req_arr = split(/:/, $requirements);
138my $suite_pre_code;
139my $suite_post_code;
Paul Bakker19343182013-08-16 13:31:10 +0200140my $dispatch_code;
141my $mapping_code;
142my %mapping_values;
Paul Bakker5690efc2011-05-26 13:16:06 +0000143
144while (@var_req_arr)
145{
146 my $req = shift @var_req_arr;
Manuel Pégourié-Gonnarde46c6c32015-03-23 13:59:10 +0100147 $req =~ s/(!?)(.*)/$1defined($2)/;
Paul Bakker5690efc2011-05-26 13:16:06 +0000148
Manuel Pégourié-Gonnarde46c6c32015-03-23 13:59:10 +0100149 $suite_pre_code .= "#if $req\n";
Paul Bakker5690efc2011-05-26 13:16:06 +0000150 $suite_post_code .= "#endif /* $req */\n";
151}
Paul Bakker367dae42009-06-28 21:50:27 +0000152
153$/ = $line_separator;
154
155open(TEST_FILE, ">$test_file") or die "Opening destination file '$test_file': $!";
156print TEST_FILE << "END";
SimonB0284f582016-02-15 23:27:28 +0000157/*
158 * *** THIS FILE HAS BEEN MACHINE GENERATED ***
159 *
160 * This file has been machine generated using the script: $0
161 *
162 * Test file : $test_file
163 *
164 * The following files were used to create this file.
165 *
166 * Main code file : $test_main_file
167 * Helper file : $test_common_helper_file
168 * Test suite file : $test_case_file
Simon Butcher60411a82016-03-01 18:35:02 +0000169 * Test suite data : $test_case_data
SimonB0284f582016-02-15 23:27:28 +0000170 *
171 *
172 * This file is part of mbed TLS (https://tls.mbed.org)
173 */
174
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200175#if !defined(MBEDTLS_CONFIG_FILE)
Manuel Pégourié-Gonnard7f809972015-03-09 17:05:11 +0000176#include <mbedtls/config.h>
Manuel Pégourié-Gonnardcef4ad22014-04-29 12:39:06 +0200177#else
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200178#include MBEDTLS_CONFIG_FILE
Manuel Pégourié-Gonnardcef4ad22014-04-29 12:39:06 +0200179#endif
Paul Bakker5690efc2011-05-26 13:16:06 +0000180
SimonB0284f582016-02-15 23:27:28 +0000181
182/*----------------------------------------------------------------------------*/
SimonB8bcd5492016-02-17 23:34:30 +0000183/* Common helper code */
SimonB0284f582016-02-15 23:27:28 +0000184
185$test_common_helpers
186
187
188/*----------------------------------------------------------------------------*/
189/* Test Suite Code */
Rich Evans00ab4702015-02-06 13:43:58 +0000190
Paul Bakkerde56ca12013-09-15 17:05:21 +0200191$suite_pre_code
Paul Bakker367dae42009-06-28 21:50:27 +0000192$suite_header
SimonB0284f582016-02-15 23:27:28 +0000193$suite_helpers
Paul Bakkerde56ca12013-09-15 17:05:21 +0200194$suite_post_code
Paul Bakker367dae42009-06-28 21:50:27 +0000195
Paul Bakker367dae42009-06-28 21:50:27 +0000196END
197
Paul Bakkerb34fef22013-08-20 12:06:33 +0200198$test_main =~ s/SUITE_PRE_DEP/$suite_pre_code/;
199$test_main =~ s/SUITE_POST_DEP/$suite_post_code/;
200
Paul Bakker33b43f12013-08-20 11:48:36 +0200201while($test_cases =~ /\/\* BEGIN_CASE *([\w:]*) \*\/\n(.*?)\n\/\* END_CASE \*\//msg)
Paul Bakker367dae42009-06-28 21:50:27 +0000202{
Paul Bakker19343182013-08-16 13:31:10 +0200203 my $function_deps = $1;
Paul Bakker33b43f12013-08-20 11:48:36 +0200204 my $function_decl = $2;
205
206 # Sanity checks of function
Gilles Peskinebe807262018-03-13 16:07:01 +0100207 if ($function_decl !~ /^#line\s*.*\nvoid /)
Paul Bakker33b43f12013-08-20 11:48:36 +0200208 {
209 die "Test function does not have 'void' as return type\n";
Gilles Peskinebe807262018-03-13 16:07:01 +0100210 "Function declaration:\n" .
211 $function_decl;
Paul Bakker33b43f12013-08-20 11:48:36 +0200212 }
Gilles Peskinebe807262018-03-13 16:07:01 +0100213 if ($function_decl !~ /^(#line\s*.*)\nvoid (\w+)\(\s*(.*?)\s*\)\s*{(.*)}/ms)
Paul Bakker33b43f12013-08-20 11:48:36 +0200214 {
215 die "Function declaration not in expected format\n";
216 }
Gilles Peskinebe807262018-03-13 16:07:01 +0100217 my $line_directive = $1;
218 my $function_name = $2;
219 my $function_params = $3;
Paul Bakker19343182013-08-16 13:31:10 +0200220 my $function_pre_code;
221 my $function_post_code;
Paul Bakker19343182013-08-16 13:31:10 +0200222 my $param_defs;
223 my $param_checks;
224 my @dispatch_params;
Paul Bakker33b43f12013-08-20 11:48:36 +0200225 my @var_def_arr = split(/,\s*/, $function_params);
Paul Bakker19343182013-08-16 13:31:10 +0200226 my $i = 1;
227 my $mapping_regex = "".$function_name;
228 my $mapping_count = 0;
Paul Bakker367dae42009-06-28 21:50:27 +0000229
Gilles Peskinebe807262018-03-13 16:07:01 +0100230 $function_decl =~ s/(^#line\s*.*)\nvoid /$1\nvoid test_suite_/;
Paul Bakker33b43f12013-08-20 11:48:36 +0200231
Paul Bakker318d0fe2014-07-10 14:59:25 +0200232 # Add exit label if not present
233 if ($function_decl !~ /^exit:$/m)
234 {
235 $function_decl =~ s/}\s*$/\nexit:\n return;\n}/;
236 }
237
Paul Bakker19343182013-08-16 13:31:10 +0200238 if ($function_deps =~ /^depends_on:/)
Paul Bakkerccff1672009-10-03 19:57:10 +0000239 {
Paul Bakker19343182013-08-16 13:31:10 +0200240 ( $function_deps ) = $function_deps =~ /^depends_on:(.*)$/;
Paul Bakkerccff1672009-10-03 19:57:10 +0000241 }
242
Paul Bakker19343182013-08-16 13:31:10 +0200243 foreach my $req (split(/:/, $function_deps))
Paul Bakker367dae42009-06-28 21:50:27 +0000244 {
Paul Bakker19343182013-08-16 13:31:10 +0200245 $function_pre_code .= "#ifdef $req\n";
246 $function_post_code .= "#endif /* $req */\n";
Paul Bakker367dae42009-06-28 21:50:27 +0000247 }
Paul Bakker367dae42009-06-28 21:50:27 +0000248
Paul Bakker19343182013-08-16 13:31:10 +0200249 foreach my $def (@var_def_arr)
250 {
251 # Handle the different parameter types
Paul Bakker33b43f12013-08-20 11:48:36 +0200252 if( substr($def, 0, 4) eq "int " )
Paul Bakker19343182013-08-16 13:31:10 +0200253 {
254 $param_defs .= " int param$i;\n";
255 $param_checks .= " if( verify_int( params[$i], &param$i ) != 0 ) return( 2 );\n";
256 push @dispatch_params, "param$i";
Paul Bakker367dae42009-06-28 21:50:27 +0000257
Paul Bakker19343182013-08-16 13:31:10 +0200258 $mapping_regex .= ":([\\d\\w |\\+\\-\\(\\)]+)";
259 $mapping_count++;
260 }
Paul Bakker33b43f12013-08-20 11:48:36 +0200261 elsif( substr($def, 0, 6) eq "char *" )
Paul Bakker19343182013-08-16 13:31:10 +0200262 {
263 $param_defs .= " char *param$i = params[$i];\n";
264 $param_checks .= " if( verify_string( &param$i ) != 0 ) return( 2 );\n";
265 push @dispatch_params, "param$i";
Andres AGf083b312017-02-02 14:36:49 +0000266 $mapping_regex .= ":(?:\\\\.|[^:\n])+";
Paul Bakker19343182013-08-16 13:31:10 +0200267 }
Paul Bakker33b43f12013-08-20 11:48:36 +0200268 else
269 {
270 die "Parameter declaration not of supported type (int, char *)\n";
271 }
Paul Bakker19343182013-08-16 13:31:10 +0200272 $i++;
Paul Bakker367dae42009-06-28 21:50:27 +0000273
Paul Bakker19343182013-08-16 13:31:10 +0200274 }
275
276 # Find non-integer values we should map for this function
277 if( $mapping_count)
278 {
279 my @res = $test_data =~ /^$mapping_regex/msg;
280 foreach my $value (@res)
281 {
Manuel Pégourié-Gonnard18c443d2013-10-17 14:58:24 +0200282 next unless ($value !~ /^\d+$/);
283 if ( $mapping_values{$value} ) {
284 ${ $mapping_values{$value} }{$function_pre_code} = 1;
285 } else {
286 $mapping_values{$value} = { $function_pre_code => 1 };
287 }
Paul Bakker19343182013-08-16 13:31:10 +0200288 }
289 }
290
291 my $call_params = join ", ", @dispatch_params;
292 my $param_count = @var_def_arr + 1;
293 $dispatch_code .= << "END";
294if( strcmp( params[0], "$function_name" ) == 0 )
295{
296$function_pre_code
297$param_defs
298 if( cnt != $param_count )
299 {
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200300 mbedtls_fprintf( stderr, "\\nIncorrect argument count (%d != %d)\\n", cnt, $param_count );
Paul Bakker19343182013-08-16 13:31:10 +0200301 return( 2 );
302 }
303
304$param_checks
Paul Bakker33b43f12013-08-20 11:48:36 +0200305 test_suite_$function_name( $call_params );
306 return ( 0 );
Paul Bakker19343182013-08-16 13:31:10 +0200307$function_post_code
308 return ( 3 );
309}
310else
311END
312
Paul Bakker33b43f12013-08-20 11:48:36 +0200313 my $function_code = $function_pre_code . $function_decl . "\n" . $function_post_code;
314 $test_main =~ s/FUNCTION_CODE/$function_code\nFUNCTION_CODE/;
Paul Bakker19343182013-08-16 13:31:10 +0200315}
316
317# Find specific case dependencies that we should be able to check
318# and make check code
319my $dep_check_code;
320
Hanno Becker276d5302017-07-23 10:24:22 +0100321my @res = $test_data =~ /^depends_on:([!:\w]+)/msg;
Paul Bakker19343182013-08-16 13:31:10 +0200322my %case_deps;
323foreach my $deps (@res)
324{
325 foreach my $dep (split(/:/, $deps))
326 {
327 $case_deps{$dep} = 1;
328 }
329}
330while( my ($key, $value) = each(%case_deps) )
331{
Hanno Becker276d5302017-07-23 10:24:22 +0100332 if( substr($key, 0, 1) eq "!" )
333 {
334 my $key = substr($key, 1);
335 $dep_check_code .= << "END";
336 if( strcmp( str, "!$key" ) == 0 )
337 {
338#if !defined($key)
339 return( 0 );
340#else
341 return( 1 );
342#endif
343 }
344END
345 }
346 else
347 {
348 $dep_check_code .= << "END";
Paul Bakker19343182013-08-16 13:31:10 +0200349 if( strcmp( str, "$key" ) == 0 )
350 {
351#if defined($key)
352 return( 0 );
353#else
354 return( 1 );
355#endif
356 }
Paul Bakker367dae42009-06-28 21:50:27 +0000357END
Hanno Becker276d5302017-07-23 10:24:22 +0100358 }
Paul Bakker367dae42009-06-28 21:50:27 +0000359}
360
Paul Bakker19343182013-08-16 13:31:10 +0200361# Make mapping code
362while( my ($key, $value) = each(%mapping_values) )
363{
Manuel Pégourié-Gonnard18c443d2013-10-17 14:58:24 +0200364 my $key_mapping_code = << "END";
Paul Bakker19343182013-08-16 13:31:10 +0200365 if( strcmp( str, "$key" ) == 0 )
366 {
367 *value = ( $key );
368 return( 0 );
369 }
370END
Manuel Pégourié-Gonnard18c443d2013-10-17 14:58:24 +0200371
372 # handle depenencies, unless used at least one without depends
373 if ($value->{""}) {
374 $mapping_code .= $key_mapping_code;
375 next;
376 }
377 for my $ifdef ( keys %$value ) {
378 (my $endif = $ifdef) =~ s!ifdef!endif //!g;
379 $mapping_code .= $ifdef . $key_mapping_code . $endif;
380 }
Paul Bakker19343182013-08-16 13:31:10 +0200381}
382
383$dispatch_code =~ s/^(.+)/ $1/mg;
384
385$test_main =~ s/TEST_FILENAME/$test_case_data/;
386$test_main =~ s/FUNCTION_CODE//;
387$test_main =~ s/DEP_CHECK_CODE/$dep_check_code/;
388$test_main =~ s/DISPATCH_FUNCTION/$dispatch_code/;
389$test_main =~ s/MAPPING_CODE/$mapping_code/;
390
Paul Bakker367dae42009-06-28 21:50:27 +0000391print TEST_FILE << "END";
Paul Bakker19343182013-08-16 13:31:10 +0200392$test_main
Paul Bakker367dae42009-06-28 21:50:27 +0000393END
394
Paul Bakker367dae42009-06-28 21:50:27 +0000395close(TEST_FILE);