From ea73624e5fb3790cb67eda3ff2baf30981a0b16d Mon Sep 17 00:00:00 2001 From: Todd Fiala Date: Wed, 23 Sep 2015 15:21:28 +0000 Subject: [PATCH] Cleaned up results formatter options hand-off. * --results-formatter-options renamed to --results-formatter-option, with short version of -O * Multiple --results-formatter-option=OPTION can be specified. The comma-separating mechanism has been removed. * XunitFormatter options modified: -n and -r are now short forms of --ignore-skip-name and --ignore-skip-reason. Those long option names were tweaked lightly. They also can be specified multiple times on the command line. The comma-separating, multiple-pattern- per-option mechanism has been removed. One can now specify: dotest.py --results-file stdout -O-ndsym -O-nlldb-mi for example, to ignore reporting skips for dsym-related or lldb-mi-related tests in the xUnit report. llvm-svn: 248384 --- lldb/test/dosep.py | 115 ++++++++++++++++++++++++++------------ lldb/test/dotest.py | 8 +-- lldb/test/dotest_args.py | 12 ++-- lldb/test/test_results.py | 36 +++++++----- 4 files changed, 111 insertions(+), 60 deletions(-) diff --git a/lldb/test/dosep.py b/lldb/test/dosep.py index 81bc872d65d3..e5ab2aa4b44b 100755 --- a/lldb/test/dosep.py +++ b/lldb/test/dosep.py @@ -1068,43 +1068,87 @@ def get_test_runner_strategies(num_threads): } -def _remove_option(args, option_name, removal_count): +def _remove_option( + args, long_option_name, short_option_name, takes_arg): """Removes option and related option arguments from args array. + + This method removes all short/long options that match the given + arguments. + @param args the array of command line arguments (in/out) - @param option_name the full command line representation of the - option that will be removed (including '--' or '-'). - @param the count of elements to remove. A value of 1 will remove - just the found option, while 2 will remove the option and its first - argument. + + @param long_option_name the full command line representation of the + long-form option that will be removed (including '--'). + + @param short_option_name the short version of the command line option + that will be removed (including '-'). + + @param takes_arg True if the option takes an argument. + """ - try: - index = args.index(option_name) - # Handle the exact match case. - del args[index:index+removal_count] - return - except ValueError: - # Thanks to argparse not handling options with known arguments - # like other options parsing libraries (see - # https://bugs.python.org/issue9334), we need to support the - # --results-formatter-options={second-level-arguments} (note - # the equal sign to fool the first-level arguments parser into - # not treating the second-level arguments as first-level - # options). We're certainly at risk of getting this wrong - # since now we're forced into the business of trying to figure - # out what is an argument (although I think this - # implementation will suffice). - regex_string = "^" + option_name + "=" - regex = re.compile(regex_string) + if long_option_name is not None: + regex_string = "^" + long_option_name + "=" + long_regex = re.compile(regex_string) + if short_option_name is not None: + # Short options we only match the -X and assume + # any arg is one command line argument jammed together. + # i.e. -O--abc=1 is a single argument in the args list. + # We don't handle -O --abc=1, as argparse doesn't handle + # it, either. + regex_string = "^" + short_option_name + short_regex = re.compile(regex_string) + + def remove_long_internal(): + """Removes one matching long option from args. + @returns True if one was found and removed; False otherwise. + """ + try: + index = args.index(long_option_name) + # Handle the exact match case. + if takes_arg: + removal_count = 2 + else: + removal_count = 1 + del args[index:index+removal_count] + return True + except ValueError: + # Thanks to argparse not handling options with known arguments + # like other options parsing libraries (see + # https://bugs.python.org/issue9334), we need to support the + # --results-formatter-options={second-level-arguments} (note + # the equal sign to fool the first-level arguments parser into + # not treating the second-level arguments as first-level + # options). We're certainly at risk of getting this wrong + # since now we're forced into the business of trying to figure + # out what is an argument (although I think this + # implementation will suffice). + for index in range(len(args)): + match = long_regex.search(args[index]) + if match: + del args[index] + return True + return False + + def remove_short_internal(): + """Removes one matching short option from args. + @returns True if one was found and removed; False otherwise. + """ for index in range(len(args)): - match = regex.match(args[index]) + match = short_regex.search(args[index]) if match: del args[index] - return - print "failed to find regex '{}'".format(regex_string) + return True + return False - # We didn't find the option but we should have. - raise Exception("failed to find option '{}' in args '{}'".format( - option_name, args)) + removal_count = 0 + while long_option_name is not None and remove_long_internal(): + removal_count += 1 + while short_option_name is not None and remove_short_internal(): + removal_count += 1 + if removal_count == 0: + raise Exception( + "failed to find at least one of '{}', '{}' in options".format( + long_option_name, short_option_name)) def adjust_inferior_options(dotest_argv): @@ -1132,17 +1176,18 @@ def adjust_inferior_options(dotest_argv): # we'll have inferiors spawn with the --results-port option and # strip the original test runner options. if dotest_options.results_file is not None: - _remove_option(dotest_argv, "--results-file", 2) + _remove_option(dotest_argv, "--results-file", None, True) if dotest_options.results_port is not None: - _remove_option(dotest_argv, "--results-port", 2) + _remove_option(dotest_argv, "--results-port", None, True) if dotest_options.results_formatter is not None: - _remove_option(dotest_argv, "--results-formatter", 2) + _remove_option(dotest_argv, "--results-formatter", None, True) if dotest_options.results_formatter_options is not None: - _remove_option(dotest_argv, "--results-formatter-options", 2) + _remove_option(dotest_argv, "--results-formatter-option", "-O", + True) # Remove test runner name if present. if dotest_options.test_runner_name is not None: - _remove_option(dotest_argv, "--test-runner-name", 2) + _remove_option(dotest_argv, "--test-runner-name", None, True) def is_darwin_version_lower_than(target_version): diff --git a/lldb/test/dotest.py b/lldb/test/dotest.py index 9bcdc829196f..6b3deb9b9b7f 100755 --- a/lldb/test/dotest.py +++ b/lldb/test/dotest.py @@ -1000,12 +1000,10 @@ def setupTestResults(): # Handle formatter options for the results formatter class. formatter_arg_parser = clazz.arg_parser() if results_formatter_options and len(results_formatter_options) > 0: - import shlex - split_options = shlex.split(results_formatter_options) + formatter_options = formatter_arg_parser.parse_args( + results_formatter_options) else: - split_options = [] - - formatter_options = formatter_arg_parser.parse_args(split_options) + formatter_options = [] # Create the TestResultsFormatter given the processed options. results_formatter_object = clazz(results_file_object, formatter_options) diff --git a/lldb/test/dotest_args.py b/lldb/test/dotest_args.py index 481cd6436a39..ba79600f1ec4 100644 --- a/lldb/test/dotest_args.py +++ b/lldb/test/dotest_args.py @@ -172,11 +172,13 @@ def create_parser(): 'test events into some kind of meaningful report, written to ' 'the designated output results file-like object')) group.add_argument( - '--results-formatter-options', - action='store', - help=('Specify comma-separated options to pass to the formatter. ' - 'Use --results-formatter-options="--option1[,--option2[,...]]" ' - 'syntax. Note the "=" is critical, and don\'t use whitespace.')) + '--results-formatter-option', + '-O', + action='append', + dest='results_formatter_options', + help=('Specify an option to pass to the formatter. ' + 'Use --results-formatter-option="--option1=val1" ' + 'syntax. Note the "=" is critical, don\'t include whitespace.')) group.add_argument( '--event-add-entries', action='store', diff --git a/lldb/test/test_results.py b/lldb/test/test_results.py index 7a87ae78d2c5..88715df0dc83 100644 --- a/lldb/test/test_results.py +++ b/lldb/test/test_results.py @@ -538,19 +538,25 @@ class XunitFormatter(ResultsFormatter): help=('cause unknown test events to generate ' 'a python assert. Default is to ignore.')) parser.add_argument( - "--ignore-skip-matching-name", - action="store", - help=('one or more comma-separated python regex patterns, where ' + "--ignore-skip-name", + "-n", + metavar='PATTERN', + action="append", + dest='ignore_skip_name_patterns', + help=('a python regex pattern, where ' 'any skipped test with a test method name where regex ' 'matches (via search) will be ignored for xUnit test ' - 'result purposes.')) + 'result purposes. Can be specified multiple times.')) parser.add_argument( - "--ignore-skip-matching-reason", - action="store", - help=('one or more comma-separated python regex patterns, where ' + "--ignore-skip-reason", + "-r", + metavar='PATTERN', + action="append", + dest='ignore_skip_reason_patterns', + help=('a python regex pattern, where ' 'any skipped test with a skip reason where the regex ' 'matches (via search) will be ignored for xUnit test ' - 'result purposes.')) + 'result purposes. Can be specified multiple times.')) parser.add_argument( "--xpass", action="store", choices=results_mapping_choices, default=XunitFormatter.RM_FAILURE, @@ -564,7 +570,7 @@ class XunitFormatter(ResultsFormatter): return parser @staticmethod - def _build_regex_list_from_option(option): + def _build_regex_list_from_patterns(patterns): """Builds a list of compiled regexes from option value. @param option string containing a comma-separated list of regex @@ -574,8 +580,8 @@ class XunitFormatter(ResultsFormatter): patterns provided. """ regex_list = [] - if option is not None and len(option) > 0: - for pattern in option.split(","): + if patterns is not None: + for pattern in patterns: regex_list.append(re.compile(pattern)) return regex_list @@ -591,11 +597,11 @@ class XunitFormatter(ResultsFormatter): self.invalid_xml_re = XunitFormatter._build_illegal_xml_regex() self.total_test_count = 0 self.ignore_skip_name_regexes = ( - XunitFormatter._build_regex_list_from_option( - options.ignore_skip_matching_name)) + XunitFormatter._build_regex_list_from_patterns( + options.ignore_skip_name_patterns)) self.ignore_skip_reason_regexes = ( - XunitFormatter._build_regex_list_from_option( - options.ignore_skip_matching_reason)) + XunitFormatter._build_regex_list_from_patterns( + options.ignore_skip_reason_patterns)) self.elements = { "successes": [],