blob: 96dd94bdbe7455edebd4dfbd3d39eba2c72ae49e [file] [log] [blame]
Gilles Peskinebdffaea2021-01-12 00:37:38 +01001#!/usr/bin/env python3
2
3"""Edit test cases to use PSA dependencies instead of classic dependencies.
4"""
5
6# Copyright The Mbed TLS Contributors
7# SPDX-License-Identifier: Apache-2.0
8#
9# Licensed under the Apache License, Version 2.0 (the "License"); you may
10# not use this file except in compliance with the License.
11# You may obtain a copy of the License at
12#
13# http://www.apache.org/licenses/LICENSE-2.0
14#
15# Unless required by applicable law or agreed to in writing, software
16# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
17# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18# See the License for the specific language governing permissions and
19# limitations under the License.
20
21import os
Gilles Peskine82ebaa42021-01-12 00:45:14 +010022import re
Gilles Peskinebdffaea2021-01-12 00:37:38 +010023import sys
24
Gilles Peskine82ebaa42021-01-12 00:45:14 +010025def updated_dependencies(file_name, function_name, arguments, dependencies):
26 """Rework the list of dependencies into PSA_WANT_xxx.
27
28 Remove classic crypto dependencies such as MBEDTLS_RSA_C,
29 MBEDTLS_PKCS1_V15, etc.
30
31 Add systematic PSA_WANT_xxx dependencies based on the called function and
32 its arguments, replacing existing PSA_WANT_xxx dependencies.
33 """
34 return dependencies #TODO
35
Gilles Peskinebdffaea2021-01-12 00:37:38 +010036def process_data_stanza(stanza, file_name, test_case_number):
37 """Update PSA crypto dependencies in one Mbed TLS test case.
38
39 stanza is the test case text (including the description, the dependencies,
40 the line with the function and arguments, and optionally comments). Return
41 a new stanza with an updated dependency line, preserving everything else
42 (description, comments, arguments, etc.).
43 """
Gilles Peskine82ebaa42021-01-12 00:45:14 +010044 if not stanza.lstrip('\n'):
45 # Just blank lines
46 return stanza
47 # Expect 2 or 3 non-comment lines: description, optional dependencies,
48 # function-and-arguments.
49 content_matches = list(re.finditer(r'^[\t ]*([^\t #].*)$', stanza, re.M))
50 if len(content_matches) < 2:
51 raise Exception('Not enough content lines in paragraph {} in {}'
52 .format(test_case_number, file_name))
53 if len(content_matches) > 3:
54 raise Exception('Too many content lines in paragraph {} in {}'
55 .format(test_case_number, file_name))
56 arguments = content_matches[-1].group(0).split(':')
57 function_name = arguments.pop(0)
58 if len(content_matches) == 2:
59 # Insert a line for the dependencies. If it turns out that there are
60 # no dependencies, we'll remove that empty line below.
61 dependencies_location = content_matches[-1].start()
62 text_before = stanza[:dependencies_location]
63 text_after = '\n' + stanza[dependencies_location:]
64 old_dependencies = []
65 dependencies_leader = 'depends_on:'
66 else:
67 dependencies_match = content_matches[-2]
68 text_before = stanza[:dependencies_match.start()]
69 text_after = stanza[dependencies_match.end():]
70 old_dependencies = dependencies_match.group(0).split(':')
71 dependencies_leader = old_dependencies.pop(0) + ':'
72 if dependencies_leader != 'depends_on:':
73 raise Exception('Next-to-last line does not start with "depends_on:"'
74 ' in paragraph {} in {}'
75 .format(test_case_number, file_name))
76 new_dependencies = updated_dependencies(file_name, function_name, arguments,
77 old_dependencies)
78 if new_dependencies:
79 stanza = (text_before +
80 dependencies_leader + ':'.join(new_dependencies) +
81 text_after)
82 else:
83 # The dependencies have become empty. Remove the depends_on: line.
84 assert text_after[0] == '\n'
85 stanza = text_before + text_after[1:]
Gilles Peskinebdffaea2021-01-12 00:37:38 +010086 return stanza
87
88def process_data_file(file_name, old_content):
89 """Update PSA crypto dependencies in an Mbed TLS test suite data file.
90
91 Process old_content (the old content of the file) and return the new content.
92 """
93 old_stanzas = old_content.split('\n\n')
94 new_stanzas = [process_data_stanza(stanza, file_name, n)
95 for n, stanza in enumerate(old_stanzas, start=1)]
96 return '\n\n'.join(new_stanzas)
97
98def update_file(file_name, old_content, new_content):
99 """Update the given file with the given new content.
100
101 Replace the existing file. The previous version is renamed to *.bak.
102 Don't modify the file if the content was unchanged.
103 """
104 if new_content == old_content:
105 return
106 backup = file_name + '.bak'
107 tmp = file_name + '.tmp'
108 with open(tmp, 'w', encoding='utf-8') as new_file:
109 new_file.write(new_content)
110 os.replace(file_name, backup)
111 os.replace(tmp, file_name)
112
113def process_file(file_name):
114 """Update PSA crypto dependencies in an Mbed TLS test suite data file.
115
116 Replace the existing file. The previous version is renamed to *.bak.
117 Don't modify the file if the content was unchanged.
118 """
119 old_content = open(file_name, encoding='utf-8').read()
120 if file_name.endswith('.data'):
121 new_content = process_data_file(file_name, old_content)
122 else:
123 raise Exception('File type not recognized: {}'
124 .format(file_name))
125 update_file(file_name, old_content, new_content)
126
127def main(args):
128 for file_name in args:
129 process_file(file_name)
130
131if __name__ == '__main__':
132 main(sys.argv[1:])