blob: b00319bad7bfa351b267d63bf3c9e72a5a8d5579 [file] [log] [blame]
Gilles Peskineba94b582019-09-16 19:18:40 +02001#!/usr/bin/env python3
2
3"""Sanity checks for test data.
Gilles Peskinebbb36642020-07-03 00:30:12 +02004
5This program contains a class for traversing test cases that can be used
6independently of the checks.
Gilles Peskineba94b582019-09-16 19:18:40 +02007"""
8
Bence Szépkúti1e148272020-08-07 13:07:28 +02009# Copyright The Mbed TLS Contributors
Dave Rodgman16799db2023-11-02 19:47:20 +000010# SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
Gilles Peskineba94b582019-09-16 19:18:40 +020011
Gilles Peskine1fb7aea2019-12-02 14:26:04 +010012import argparse
Gilles Peskineba94b582019-09-16 19:18:40 +020013import re
14import sys
Tomás González754f8cd2023-08-17 15:11:10 +010015
Gilles Peskine13985562024-10-03 19:11:27 +020016import scripts_path # pylint: disable=unused-import
Gilles Peskine31e31522024-10-03 17:23:53 +020017import collect_test_cases
Gilles Peskine13985562024-10-03 19:11:27 +020018
Pengyu Lvce980e62023-11-30 16:53:31 +080019
Gilles Peskineeba00972024-10-03 17:35:52 +020020class DescriptionChecker(collect_test_cases.TestDescriptionExplorer):
Gilles Peskine78c45db2020-06-25 16:34:11 +020021 """Check all test case descriptions.
22
23* Check that each description is valid (length, allowed character set, etc.).
24* Check that there is no duplicated description inside of one test suite.
25"""
26
27 def __init__(self, results):
28 self.results = results
29
Gilles Peskinebbb36642020-07-03 00:30:12 +020030 def new_per_file_state(self):
Gilles Peskine6f6ff332020-06-25 16:40:10 +020031 """Dictionary mapping descriptions to their line number."""
Gilles Peskine78c45db2020-06-25 16:34:11 +020032 return {}
33
34 def process_test_case(self, per_file_state,
35 file_name, line_number, description):
Gilles Peskine6f6ff332020-06-25 16:40:10 +020036 """Check test case descriptions for errors."""
37 results = self.results
38 seen = per_file_state
39 if description in seen:
40 results.error(file_name, line_number,
41 'Duplicate description (also line {})',
42 seen[description])
43 return
44 if re.search(br'[\t;]', description):
45 results.error(file_name, line_number,
46 'Forbidden character \'{}\' in description',
47 re.search(br'[\t;]', description).group(0).decode('ascii'))
48 if re.search(br'[^ -~]', description):
49 results.error(file_name, line_number,
50 'Non-ASCII character in description')
51 if len(description) > 66:
52 results.warning(file_name, line_number,
53 'Test description too long ({} > 66)',
54 len(description))
55 seen[description] = line_number
Gilles Peskineba94b582019-09-16 19:18:40 +020056
57def main():
Gilles Peskine1fb7aea2019-12-02 14:26:04 +010058 parser = argparse.ArgumentParser(description=__doc__)
Gilles Peskine7e091052022-01-07 15:58:55 +010059 parser.add_argument('--list-all',
60 action='store_true',
61 help='List all test cases, without doing checks')
Gilles Peskine1fb7aea2019-12-02 14:26:04 +010062 parser.add_argument('--quiet', '-q',
63 action='store_true',
64 help='Hide warnings')
65 parser.add_argument('--verbose', '-v',
66 action='store_false', dest='quiet',
67 help='Show warnings (default: on; undoes --quiet)')
68 options = parser.parse_args()
Gilles Peskine7e091052022-01-07 15:58:55 +010069 if options.list_all:
Gilles Peskineeba00972024-10-03 17:35:52 +020070 descriptions = collect_test_cases.collect_available_test_cases()
Gilles Peskine7e091052022-01-07 15:58:55 +010071 sys.stdout.write('\n'.join(descriptions + ['']))
72 return
Gilles Peskineeba00972024-10-03 17:35:52 +020073 results = collect_test_cases.Results(options)
Gilles Peskine78c45db2020-06-25 16:34:11 +020074 checker = DescriptionChecker(results)
Pengyu Lvce980e62023-11-30 16:53:31 +080075 try:
76 checker.walk_all()
Gilles Peskineeba00972024-10-03 17:35:52 +020077 except collect_test_cases.ScriptOutputError as e:
Pengyu Lvce980e62023-11-30 16:53:31 +080078 results.error(e.script_name, e.idx,
79 '"{}" should be listed as "<suite_name>;<description>"',
80 e.line)
Gilles Peskine1fb7aea2019-12-02 14:26:04 +010081 if (results.warnings or results.errors) and not options.quiet:
Gilles Peskineba94b582019-09-16 19:18:40 +020082 sys.stderr.write('{}: {} errors, {} warnings\n'
83 .format(sys.argv[0], results.errors, results.warnings))
84 sys.exit(1 if results.errors else 0)
85
86if __name__ == '__main__':
87 main()