blob: 226ff1dace87d28ecd449ba9359fa5494bf11af6 [file] [log] [blame]
# © 2021 and later: Unicode, Inc. and others.
# License & terms of use: http://www.unicode.org/copyright.html
"""Executes uconfig variations check.
See
http://site.icu-project.org/processes/release/tasks/healthy-code#TOC-Test-uconfig.h-variations
for more information.
"""
import getopt
import os
import re
import subprocess
import sys
excluded_unit_test_flags = ['UCONFIG_NO_CONVERSION', 'UCONFIG_NO_FILE_IO'];
def ReadFile(filename):
"""Reads a file and returns the content of the file
Args:
command: string with the filename.
Returns:
Content of file.
"""
with open(filename, 'r') as file_handle:
return file_handle.read()
def RunCmd(command):
"""Executes the command, returns output and exit code, writes output to log
Args:
command: string with the command.
Returns:
stdout and exit code of command execution.
"""
command += ' >> uconfig_test.log 2>&1'
print(command)
p = subprocess.Popen(command, shell=True, stdout=subprocess.PIPE,
stderr=subprocess.STDOUT, close_fds=True)
stdout, _ = p.communicate()
return stdout, p.returncode
def ExtractUConfigNoXXX(uconfig_file):
"""Parses uconfig.h and returns a list of UCONFIG_NO_XXX labels.
Initializes test result structure.
Args:
uconfig_file: common/unicode/uconfig.h as string.
Returns:
List of all UCONFIG_NO_XXX flags found in uconfig.h, initialized test
result structure.
"""
uconfig_no_flags_all = []
test_results = {}
uconfig_no_regex = r'UCONFIG_NO_[A-Z_]*'
# Collect all distinct occurences of UCONFIG_NO_XXX matches in uconfig.h.
for uconfig_no_flag in re.finditer(uconfig_no_regex, uconfig_file):
if uconfig_no_flag.group(0) not in uconfig_no_flags_all:
uconfig_no_flags_all.append(uconfig_no_flag.group(0))
# All UCONFIG_NO_XXX flags found in uconfig.h come in form of a guarded
# definition. Verify the existence, report error if not found.
for uconfig_no_flag in uconfig_no_flags_all:
uconfig_no_def_regex = r'(?m)#ifndef %s\n#\s+define %s\s+0\n#endif$' % (
uconfig_no_flag, uconfig_no_flag)
uconfig_no_def_match = re.search(uconfig_no_def_regex, uconfig_file)
if not uconfig_no_def_match:
print('No definition for flag %s found!\n' % uconfig_no_flag)
sys.exit(1)
test_results = {f: {'unit_test': False, 'hdr_test': False} for f in uconfig_no_flags_all}
test_results['all_flags'] = {'unit_test': False, 'hdr_test' : False}
return uconfig_no_flags_all, test_results
def BuildAllFlags(uconfig_no_list):
"""Builds sequence of -Dflag=1 with each flag from the list."""
flag_list = ['-D' + uconfig_no + '=1' for uconfig_no in uconfig_no_list]
return ' '.join(flag_list)
def RunUnitTests(uconfig_no_list, test_results):
"""Iterates over all flags, sets each individually during ICU configuration
and executes the ICU4C unit tests.
Args:
uconfig_no_list: list of all UCONFIG_NO_XXX flags to test with.
test_results: dictionary to record test run results.
Returns:
test_results: updated test result entries.
"""
for uconfig_no in uconfig_no_list:
_, exit_code = RunCmd(
'./runConfigureICU Linux CPPFLAGS=\"-D%s=1"' % uconfig_no)
if exit_code != 0:
print('ICU4C configuration for flag %s failed' % uconfig_no)
sys.exit(1)
print('Running unit tests with %s set to 1.' % uconfig_no)
_, exit_code = RunCmd('make -j2 check')
test_results[uconfig_no]['unit_test'] = (exit_code == 0)
RunCmd('make clean')
# Configure ICU with all UCONFIG_NO_XXX flags set to 1 and execute
# the ICU4C unit tests.
all_unit_test_config_no = BuildAllFlags(uconfig_no_list)
_, exit_code = RunCmd(
'CPPFLAGS=\"%s\" ./runConfigureICU Linux' % all_unit_test_config_no)
if exit_code != 0:
print('ICU configuration with all flags set failed')
sys.exit(1)
print('Running unit tests with all flags set to 1.')
_, exit_code = RunCmd('make -j2 check')
test_results['all_flags']['unit_test'] = (exit_code == 0)
RunCmd('make clean')
return test_results
def RunHeaderTests(uconfig_no_list, test_results):
"""Iterates over all flags and executes the header test.
Args:
uconfig_no_list: list of all UCONFIG_NO_XXX flags to test with.
test_results: dictionary to record test run results.
Returns:
test_results: updated test result entries.
"""
# Header tests needs different setup.
RunCmd('mkdir /tmp/icu_cnfg')
out, exit_code = RunCmd('./runConfigureICU Linux --prefix=/tmp/icu_cnfg')
if exit_code != 0:
print('ICU4C configuration for header test failed!')
print(out)
sys.exit(1)
_, exit_code = RunCmd('make -j2 install')
if exit_code != 0:
print('make install failed!')
sys.exit(1)
for uconfig_no in uconfig_no_list:
print('Running header tests with %s set to 1.' % uconfig_no)
_, exit_code = RunCmd(
'PATH=/tmp/icu_cnfg/bin:$PATH make -C test/hdrtst UCONFIG_NO=\"-D%s=1\" check' % uconfig_no)
test_results[uconfig_no]['hdr_test'] = (exit_code == 0)
all_hdr_test_flags = BuildAllFlags(uconfig_no_list)
print('Running header tests with all flags set to 1.')
_, exit_code = RunCmd(
'PATH=/tmp/icu_cnfg/bin:$PATH make -C test/hdrtst UCONFIG_NO=\"%s\" check' % all_hdr_test_flags)
test_results['all_flags']['hdr_test'] = (exit_code == 0)
return test_results
def main():
# Read the options and determine what to run.
run_hdr = False
run_unit = False
optlist, _ = getopt.getopt(sys.argv[1:], "pu")
for o, _ in optlist:
if o == "-p":
run_hdr = True
elif o == "-u":
run_unit = True
os.chdir('icu4c/source')
orig_uconfig_file = ReadFile('common/unicode/uconfig.h')
all_uconfig_no_flags, test_results = ExtractUConfigNoXXX(orig_uconfig_file)
if not all_uconfig_no_flags:
print('No UCONFIG_NO_XXX flags found!\n')
sys.exit(1)
if run_unit:
RunUnitTests(
[u for u in all_uconfig_no_flags if u not in excluded_unit_test_flags],
test_results)
if run_hdr:
RunHeaderTests(all_uconfig_no_flags, test_results)
# Review test results and report any failures.
# 'outcome' will be returned by sys.exit(); 0 indicates success, any
# other value indicates failure.
outcome = 0
print('Summary:\n')
for uconfig_no in all_uconfig_no_flags:
if run_unit and (uconfig_no not in excluded_unit_test_flags):
if not test_results[uconfig_no]['unit_test']:
outcome = 1
print('%s: unit tests fail' % uconfig_no)
if run_hdr and not test_results[uconfig_no]['hdr_test']:
outcome = 1
print('%s: header tests fails' % uconfig_no)
if run_unit and not test_results['all_flags']['unit_test']:
outcome = 1
print('all flags to 1: unit tests fail!')
if run_hdr and not test_results['all_flags']['hdr_test']:
outcome = 1
print('all flags to 1: header tests fail!')
if outcome == 0:
print('Tests pass for all uconfig variations!')
sys.exit(outcome)
if __name__ == '__main__':
main()