blob: e489a0055e2a81e0c7f1eee1c4f5360245a7f0b3 [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#
SimonB8ca7bc42016-04-17 23:24:50 +01005# This file is part of mbed TLS (https://tls.mbed.org)
6#
Simon Butcher64d60da2016-03-01 18:35:02 +00007# Copyright (c) 2009-2016, ARM Limited, All Rights Reserved
8#
SimonB152ea182016-02-15 23:27:28 +00009# Purpose
10#
SimonB3ddf3552016-02-10 23:50:28 +000011# Generates the test suite code given inputs of the test suite directory that
12# contain the test suites, and the test suite file names for the test code and
13# test data.
14#
15# Usage: generate_code.pl <suite dir> <code file> <data file> [main code file]
SimonB152ea182016-02-15 23:27:28 +000016#
17# Structure of files
18#
19# - main code file - 'main_test.function'
20# Template file that contains the main() function for the test suite,
21# test dispatch code as well as support functions. It contains the
22# following symbols which are substituted by this script during
23# processing:
SimonB15942102016-04-25 21:34:49 +010024# TESTCASE_FILENAME
25# TESTCODE_FILENAME
SimonB152ea182016-02-15 23:27:28 +000026# SUITE_PRE_DEP
27# MAPPING_CODE
28# FUNCTION CODE
29# SUITE_POST_DEP
30# DEP_CHECK_CODE
31# DISPATCH_FUNCTION
SimonB15942102016-04-25 21:34:49 +010032# !LINE_NO!
SimonB152ea182016-02-15 23:27:28 +000033#
34# - common helper code file - 'helpers.function'
35# Common helper functions
36#
37# - test suite code file - file name in the form 'test_suite_xxx.function'
38# Code file that contains the actual test cases. The file contains a
39# series of code sequences delimited by the following:
40# BEGIN_HEADER / END_HEADER - list of headers files
41# BEGIN_SUITE_HELPERS / END_SUITE_HELPERS - helper functions common to
42# the test suite
43# BEGIN_CASE / END_CASE - the test cases in the test suite. Each test
44# case contains at least one function that is used to create the
45# dispatch code.
46#
47# - test data file - file name in the form 'test_suite_xxxx.data'
48# The test case parameters to to be used in execution of the test. The
SimonB15942102016-04-25 21:34:49 +010049# file name is used to replace the symbol 'TESTCASE_FILENAME' in the main
50# code file above.
SimonB152ea182016-02-15 23:27:28 +000051#
Gilles Peskineb04e2c32017-09-29 15:45:12 +020052# A test data file consists of a sequence of paragraphs separated by
53# a single empty line. Line breaks may be in Unix (LF) or Windows (CRLF)
54# format. Lines starting with the character '#' are ignored
55# (the parser behaves as if they were not present).
56#
57# Each paragraph describes one test case and must consist of: (1) one
58# line which is the test case name; (2) an optional line starting with
59# the 11-character prefix "depends_on:"; (3) a line containing the test
60# function to execute and its parameters.
61#
62# A depends_on: line consists of a list of compile-time options
63# separated by the character ':', with no whitespace. The test case
64# is executed only if this compilation option is enabled in config.h.
65#
66# The last line of each paragraph contains a test function name and
67# a list of parameters separated by the character ':'. Running the
68# test case calls this function with the specified parameters. Each
69# parameter may either be an integer written in decimal or hexadecimal,
70# or a string surrounded by double quotes which may not contain the
71# ':' character.
72#
Paul Bakker367dae42009-06-28 21:50:27 +000073
74use strict;
75
76my $suite_dir = shift or die "Missing suite directory";
77my $suite_name = shift or die "Missing suite name";
Paul Bakker46c17942011-07-13 14:54:54 +000078my $data_name = shift or die "Missing data name";
Rich Evansf4253c72015-01-14 19:23:00 +000079my $test_main_file = do { my $arg = shift; defined($arg) ? $arg : $suite_dir."/main_test.function" };
Paul Bakker46c17942011-07-13 14:54:54 +000080my $test_file = $data_name.".c";
SimonB152ea182016-02-15 23:27:28 +000081my $test_common_helper_file = $suite_dir."/helpers.function";
Paul Bakker367dae42009-06-28 21:50:27 +000082my $test_case_file = $suite_dir."/".$suite_name.".function";
Paul Bakker19343182013-08-16 13:31:10 +020083my $test_case_data = $suite_dir."/".$data_name.".data";
Paul Bakker367dae42009-06-28 21:50:27 +000084
85my $line_separator = $/;
86undef $/;
87
SimonB15942102016-04-25 21:34:49 +010088
89#
90# Open and read in the input files
91#
92
SimonB152ea182016-02-15 23:27:28 +000093open(TEST_HELPERS, "$test_common_helper_file") or die "Opening test helpers
94'$test_common_helper_file': $!";
95my $test_common_helpers = <TEST_HELPERS>;
Paul Bakker367dae42009-06-28 21:50:27 +000096close(TEST_HELPERS);
97
Paul Bakker19343182013-08-16 13:31:10 +020098open(TEST_MAIN, "$test_main_file") or die "Opening test main '$test_main_file': $!";
SimonB15942102016-04-25 21:34:49 +010099my @test_main_lines = split/^/, <TEST_MAIN>;
100my $test_main;
SimonB43dba3d2016-05-02 21:31:51 +0100101my $index = 2;
SimonB15942102016-04-25 21:34:49 +0100102for my $line (@test_main_lines) {
103 $line =~ s/!LINE_NO!/$index/;
104 $test_main = $test_main.$line;
105 $index++;
106}
Paul Bakker19343182013-08-16 13:31:10 +0200107close(TEST_MAIN);
108
Paul Bakker367dae42009-06-28 21:50:27 +0000109open(TEST_CASES, "$test_case_file") or die "Opening test cases '$test_case_file': $!";
SimonB15942102016-04-25 21:34:49 +0100110my @test_cases_lines = split/^/, <TEST_CASES>;
111my $test_cases;
SimonB43dba3d2016-05-02 21:31:51 +0100112my $index = 2;
SimonB15942102016-04-25 21:34:49 +0100113for my $line (@test_cases_lines) {
SimonB37f26202016-05-02 21:58:19 +0100114 if ($line =~ /^\/\* BEGIN_SUITE_HELPERS .*\*\//)
115 {
116 $line = $line."#line $index \"$test_case_file\"\n";
117 }
118
SimonB15942102016-04-25 21:34:49 +0100119 if ($line =~ /^\/\* BEGIN_CASE .*\*\//)
120 {
121 $line = $line."#line $index \"$test_case_file\"\n";
122 }
123
SimonBc1d2eb32016-05-02 15:52:52 +0100124 $line =~ s/!LINE_NO!/$index/;
125
SimonB15942102016-04-25 21:34:49 +0100126 $test_cases = $test_cases.$line;
127 $index++;
128}
129
Paul Bakker367dae42009-06-28 21:50:27 +0000130close(TEST_CASES);
Paul Bakker19343182013-08-16 13:31:10 +0200131
132open(TEST_DATA, "$test_case_data") or die "Opening test data '$test_case_data': $!";
133my $test_data = <TEST_DATA>;
134close(TEST_DATA);
135
SimonB15942102016-04-25 21:34:49 +0100136
137#
138# Find the headers, dependencies, and suites in the test cases file
139#
140
Paul Bakker33b43f12013-08-20 11:48:36 +0200141my ( $suite_header ) = $test_cases =~ /\/\* BEGIN_HEADER \*\/\n(.*?)\n\/\* END_HEADER \*\//s;
142my ( $suite_defines ) = $test_cases =~ /\/\* BEGIN_DEPENDENCIES\n \* (.*?)\n \* END_DEPENDENCIES/s;
SimonB152ea182016-02-15 23:27:28 +0000143my ( $suite_helpers ) = $test_cases =~ /\/\* BEGIN_SUITE_HELPERS \*\/\n(.*?)\n\/\* END_SUITE_HELPERS \*\//s;
Paul Bakker5690efc2011-05-26 13:16:06 +0000144
145my $requirements;
146if ($suite_defines =~ /^depends_on:/)
147{
148 ( $requirements ) = $suite_defines =~ /^depends_on:(.*)$/;
149}
Paul Bakker19343182013-08-16 13:31:10 +0200150
Paul Bakker5690efc2011-05-26 13:16:06 +0000151my @var_req_arr = split(/:/, $requirements);
152my $suite_pre_code;
153my $suite_post_code;
Paul Bakker19343182013-08-16 13:31:10 +0200154my $dispatch_code;
155my $mapping_code;
156my %mapping_values;
Paul Bakker5690efc2011-05-26 13:16:06 +0000157
158while (@var_req_arr)
159{
160 my $req = shift @var_req_arr;
Manuel Pégourié-Gonnarde46c6c32015-03-23 13:59:10 +0100161 $req =~ s/(!?)(.*)/$1defined($2)/;
Paul Bakker5690efc2011-05-26 13:16:06 +0000162
Manuel Pégourié-Gonnarde46c6c32015-03-23 13:59:10 +0100163 $suite_pre_code .= "#if $req\n";
Paul Bakker5690efc2011-05-26 13:16:06 +0000164 $suite_post_code .= "#endif /* $req */\n";
165}
Paul Bakker367dae42009-06-28 21:50:27 +0000166
167$/ = $line_separator;
168
169open(TEST_FILE, ">$test_file") or die "Opening destination file '$test_file': $!";
170print TEST_FILE << "END";
SimonB152ea182016-02-15 23:27:28 +0000171/*
172 * *** THIS FILE HAS BEEN MACHINE GENERATED ***
173 *
174 * This file has been machine generated using the script: $0
175 *
176 * Test file : $test_file
177 *
178 * The following files were used to create this file.
179 *
180 * Main code file : $test_main_file
181 * Helper file : $test_common_helper_file
182 * Test suite file : $test_case_file
Simon Butcher64d60da2016-03-01 18:35:02 +0000183 * Test suite data : $test_case_data
SimonB152ea182016-02-15 23:27:28 +0000184 *
185 *
186 * This file is part of mbed TLS (https://tls.mbed.org)
187 */
188
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200189#if !defined(MBEDTLS_CONFIG_FILE)
Manuel Pégourié-Gonnard7f809972015-03-09 17:05:11 +0000190#include <mbedtls/config.h>
Manuel Pégourié-Gonnardcef4ad22014-04-29 12:39:06 +0200191#else
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200192#include MBEDTLS_CONFIG_FILE
Manuel Pégourié-Gonnardcef4ad22014-04-29 12:39:06 +0200193#endif
Paul Bakker5690efc2011-05-26 13:16:06 +0000194
SimonB152ea182016-02-15 23:27:28 +0000195
196/*----------------------------------------------------------------------------*/
SimonB0269dad2016-02-17 23:34:30 +0000197/* Common helper code */
SimonB152ea182016-02-15 23:27:28 +0000198
199$test_common_helpers
200
201
202/*----------------------------------------------------------------------------*/
203/* Test Suite Code */
Rich Evans00ab4702015-02-06 13:43:58 +0000204
Paul Bakkerde56ca12013-09-15 17:05:21 +0200205$suite_pre_code
Paul Bakker367dae42009-06-28 21:50:27 +0000206$suite_header
SimonB152ea182016-02-15 23:27:28 +0000207$suite_helpers
Paul Bakkerde56ca12013-09-15 17:05:21 +0200208$suite_post_code
Paul Bakker367dae42009-06-28 21:50:27 +0000209
Paul Bakker367dae42009-06-28 21:50:27 +0000210END
211
Paul Bakkerb34fef22013-08-20 12:06:33 +0200212$test_main =~ s/SUITE_PRE_DEP/$suite_pre_code/;
213$test_main =~ s/SUITE_POST_DEP/$suite_post_code/;
214
Paul Bakker33b43f12013-08-20 11:48:36 +0200215while($test_cases =~ /\/\* BEGIN_CASE *([\w:]*) \*\/\n(.*?)\n\/\* END_CASE \*\//msg)
Paul Bakker367dae42009-06-28 21:50:27 +0000216{
Paul Bakker19343182013-08-16 13:31:10 +0200217 my $function_deps = $1;
Paul Bakker33b43f12013-08-20 11:48:36 +0200218 my $function_decl = $2;
219
220 # Sanity checks of function
SimonB15942102016-04-25 21:34:49 +0100221 if ($function_decl !~ /^#line\s*.*\nvoid /)
Paul Bakker33b43f12013-08-20 11:48:36 +0200222 {
SimonB15942102016-04-25 21:34:49 +0100223 die "Test function does not have 'void' as return type.\n" .
224 "Function declaration:\n" .
225 $function_decl;
Paul Bakker33b43f12013-08-20 11:48:36 +0200226 }
SimonB15942102016-04-25 21:34:49 +0100227 if ($function_decl !~ /^(#line\s*.*)\nvoid (\w+)\(\s*(.*?)\s*\)\s*{(.*)}/ms)
Paul Bakker33b43f12013-08-20 11:48:36 +0200228 {
229 die "Function declaration not in expected format\n";
230 }
SimonB15942102016-04-25 21:34:49 +0100231 my $line_directive = $1;
232 my $function_name = $2;
233 my $function_params = $3;
Paul Bakker19343182013-08-16 13:31:10 +0200234 my $function_pre_code;
235 my $function_post_code;
Paul Bakker19343182013-08-16 13:31:10 +0200236 my $param_defs;
237 my $param_checks;
238 my @dispatch_params;
Paul Bakker33b43f12013-08-20 11:48:36 +0200239 my @var_def_arr = split(/,\s*/, $function_params);
Paul Bakker19343182013-08-16 13:31:10 +0200240 my $i = 1;
241 my $mapping_regex = "".$function_name;
242 my $mapping_count = 0;
Paul Bakker367dae42009-06-28 21:50:27 +0000243
SimonB15942102016-04-25 21:34:49 +0100244 $function_decl =~ s/(^#line\s*.*)\nvoid /$1\nvoid test_suite_/;
Paul Bakker33b43f12013-08-20 11:48:36 +0200245
Paul Bakker318d0fe2014-07-10 14:59:25 +0200246 # Add exit label if not present
247 if ($function_decl !~ /^exit:$/m)
248 {
249 $function_decl =~ s/}\s*$/\nexit:\n return;\n}/;
250 }
251
Paul Bakker19343182013-08-16 13:31:10 +0200252 if ($function_deps =~ /^depends_on:/)
Paul Bakkerccff1672009-10-03 19:57:10 +0000253 {
Paul Bakker19343182013-08-16 13:31:10 +0200254 ( $function_deps ) = $function_deps =~ /^depends_on:(.*)$/;
Paul Bakkerccff1672009-10-03 19:57:10 +0000255 }
256
Paul Bakker19343182013-08-16 13:31:10 +0200257 foreach my $req (split(/:/, $function_deps))
Paul Bakker367dae42009-06-28 21:50:27 +0000258 {
Paul Bakker19343182013-08-16 13:31:10 +0200259 $function_pre_code .= "#ifdef $req\n";
260 $function_post_code .= "#endif /* $req */\n";
Paul Bakker367dae42009-06-28 21:50:27 +0000261 }
Paul Bakker367dae42009-06-28 21:50:27 +0000262
Paul Bakker19343182013-08-16 13:31:10 +0200263 foreach my $def (@var_def_arr)
264 {
265 # Handle the different parameter types
Paul Bakker33b43f12013-08-20 11:48:36 +0200266 if( substr($def, 0, 4) eq "int " )
Paul Bakker19343182013-08-16 13:31:10 +0200267 {
268 $param_defs .= " int param$i;\n";
SimonB8ca7bc42016-04-17 23:24:50 +0100269 $param_checks .= " if( verify_int( params[$i], &param$i ) != 0 ) return( DISPATCH_INVALID_TEST_DATA );\n";
Paul Bakker19343182013-08-16 13:31:10 +0200270 push @dispatch_params, "param$i";
Paul Bakker367dae42009-06-28 21:50:27 +0000271
Paul Bakker19343182013-08-16 13:31:10 +0200272 $mapping_regex .= ":([\\d\\w |\\+\\-\\(\\)]+)";
273 $mapping_count++;
274 }
Paul Bakker33b43f12013-08-20 11:48:36 +0200275 elsif( substr($def, 0, 6) eq "char *" )
Paul Bakker19343182013-08-16 13:31:10 +0200276 {
277 $param_defs .= " char *param$i = params[$i];\n";
SimonB8ca7bc42016-04-17 23:24:50 +0100278 $param_checks .= " if( verify_string( &param$i ) != 0 ) return( DISPATCH_INVALID_TEST_DATA );\n";
Paul Bakker19343182013-08-16 13:31:10 +0200279 push @dispatch_params, "param$i";
Andres AG9060d4d2017-02-02 14:36:49 +0000280 $mapping_regex .= ":(?:\\\\.|[^:\n])+";
Paul Bakker19343182013-08-16 13:31:10 +0200281 }
Paul Bakker33b43f12013-08-20 11:48:36 +0200282 else
283 {
284 die "Parameter declaration not of supported type (int, char *)\n";
285 }
Paul Bakker19343182013-08-16 13:31:10 +0200286 $i++;
Paul Bakker367dae42009-06-28 21:50:27 +0000287
Paul Bakker19343182013-08-16 13:31:10 +0200288 }
289
290 # Find non-integer values we should map for this function
291 if( $mapping_count)
292 {
293 my @res = $test_data =~ /^$mapping_regex/msg;
294 foreach my $value (@res)
295 {
Manuel Pégourié-Gonnard18c443d2013-10-17 14:58:24 +0200296 next unless ($value !~ /^\d+$/);
297 if ( $mapping_values{$value} ) {
298 ${ $mapping_values{$value} }{$function_pre_code} = 1;
299 } else {
300 $mapping_values{$value} = { $function_pre_code => 1 };
301 }
Paul Bakker19343182013-08-16 13:31:10 +0200302 }
303 }
304
305 my $call_params = join ", ", @dispatch_params;
306 my $param_count = @var_def_arr + 1;
307 $dispatch_code .= << "END";
308if( strcmp( params[0], "$function_name" ) == 0 )
309{
310$function_pre_code
311$param_defs
312 if( cnt != $param_count )
313 {
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200314 mbedtls_fprintf( stderr, "\\nIncorrect argument count (%d != %d)\\n", cnt, $param_count );
SimonB8ca7bc42016-04-17 23:24:50 +0100315 return( DISPATCH_INVALID_TEST_DATA );
Paul Bakker19343182013-08-16 13:31:10 +0200316 }
317
318$param_checks
Paul Bakker33b43f12013-08-20 11:48:36 +0200319 test_suite_$function_name( $call_params );
SimonB8ca7bc42016-04-17 23:24:50 +0100320 return ( DISPATCH_TEST_SUCCESS );
Paul Bakker19343182013-08-16 13:31:10 +0200321$function_post_code
SimonB8ca7bc42016-04-17 23:24:50 +0100322 return ( DISPATCH_UNSUPPORTED_SUITE );
Paul Bakker19343182013-08-16 13:31:10 +0200323}
324else
325END
326
SimonB15942102016-04-25 21:34:49 +0100327 my $function_code = $function_pre_code . $function_decl . "\n" .
328 $function_post_code;
Paul Bakker33b43f12013-08-20 11:48:36 +0200329 $test_main =~ s/FUNCTION_CODE/$function_code\nFUNCTION_CODE/;
Paul Bakker19343182013-08-16 13:31:10 +0200330}
331
332# Find specific case dependencies that we should be able to check
333# and make check code
334my $dep_check_code;
335
Hanno Beckerf058f342017-07-23 10:24:22 +0100336my @res = $test_data =~ /^depends_on:([!:\w]+)/msg;
Paul Bakker19343182013-08-16 13:31:10 +0200337my %case_deps;
338foreach my $deps (@res)
339{
340 foreach my $dep (split(/:/, $deps))
341 {
342 $case_deps{$dep} = 1;
343 }
344}
345while( my ($key, $value) = each(%case_deps) )
346{
Hanno Beckerf058f342017-07-23 10:24:22 +0100347 if( substr($key, 0, 1) eq "!" )
348 {
349 my $key = substr($key, 1);
350 $dep_check_code .= << "END";
351 if( strcmp( str, "!$key" ) == 0 )
352 {
353#if !defined($key)
354 return( DEPENDENCY_SUPPORTED );
355#else
356 return( DEPENDENCY_NOT_SUPPORTED );
357#endif
358 }
359END
360 }
361 else
362 {
363 $dep_check_code .= << "END";
Paul Bakker19343182013-08-16 13:31:10 +0200364 if( strcmp( str, "$key" ) == 0 )
365 {
366#if defined($key)
SimonB8ca7bc42016-04-17 23:24:50 +0100367 return( DEPENDENCY_SUPPORTED );
Paul Bakker19343182013-08-16 13:31:10 +0200368#else
SimonB8ca7bc42016-04-17 23:24:50 +0100369 return( DEPENDENCY_NOT_SUPPORTED );
Paul Bakker19343182013-08-16 13:31:10 +0200370#endif
371 }
Paul Bakker367dae42009-06-28 21:50:27 +0000372END
Hanno Beckerf058f342017-07-23 10:24:22 +0100373 }
Paul Bakker367dae42009-06-28 21:50:27 +0000374}
375
Paul Bakker19343182013-08-16 13:31:10 +0200376# Make mapping code
377while( my ($key, $value) = each(%mapping_values) )
378{
Manuel Pégourié-Gonnard18c443d2013-10-17 14:58:24 +0200379 my $key_mapping_code = << "END";
Paul Bakker19343182013-08-16 13:31:10 +0200380 if( strcmp( str, "$key" ) == 0 )
381 {
382 *value = ( $key );
SimonB8ca7bc42016-04-17 23:24:50 +0100383 return( KEY_VALUE_MAPPING_FOUND );
Paul Bakker19343182013-08-16 13:31:10 +0200384 }
385END
Manuel Pégourié-Gonnard18c443d2013-10-17 14:58:24 +0200386
387 # handle depenencies, unless used at least one without depends
388 if ($value->{""}) {
389 $mapping_code .= $key_mapping_code;
390 next;
391 }
392 for my $ifdef ( keys %$value ) {
393 (my $endif = $ifdef) =~ s!ifdef!endif //!g;
394 $mapping_code .= $ifdef . $key_mapping_code . $endif;
395 }
Paul Bakker19343182013-08-16 13:31:10 +0200396}
397
398$dispatch_code =~ s/^(.+)/ $1/mg;
399
SimonB15942102016-04-25 21:34:49 +0100400$test_main =~ s/TESTCASE_FILENAME/$test_case_data/g;
401$test_main =~ s/TESTCODE_FILENAME/$test_case_file/g;
Paul Bakker19343182013-08-16 13:31:10 +0200402$test_main =~ s/FUNCTION_CODE//;
403$test_main =~ s/DEP_CHECK_CODE/$dep_check_code/;
404$test_main =~ s/DISPATCH_FUNCTION/$dispatch_code/;
405$test_main =~ s/MAPPING_CODE/$mapping_code/;
406
Paul Bakker367dae42009-06-28 21:50:27 +0000407print TEST_FILE << "END";
Paul Bakker19343182013-08-16 13:31:10 +0200408$test_main
Paul Bakker367dae42009-06-28 21:50:27 +0000409END
410
Paul Bakker367dae42009-06-28 21:50:27 +0000411close(TEST_FILE);