1from __future__ import print_function
2from __future__ import absolute_import
3
4# System modules
5import argparse
6import sys
7import os
8import textwrap
9
10# Third-party modules
11
12# LLDB modules
13from . import configuration
14
15
16class ArgParseNamespace(object):
17    pass
18
19
20def parse_args(parser, argv):
21    """ Returns an argument object. LLDB_TEST_ARGUMENTS environment variable can
22        be used to pass additional arguments.
23    """
24    args = ArgParseNamespace()
25
26    if ('LLDB_TEST_ARGUMENTS' in os.environ):
27        print(
28            "Arguments passed through environment: '%s'" %
29            os.environ['LLDB_TEST_ARGUMENTS'])
30        args = parser.parse_args([sys.argv[0]].__add__(
31            os.environ['LLDB_TEST_ARGUMENTS'].split()), namespace=args)
32
33    return parser.parse_args(args=argv, namespace=args)
34
35
36def create_parser():
37    parser = argparse.ArgumentParser(
38        description='description',
39        prefix_chars='+-',
40        add_help=False)
41    group = None
42
43    # Helper function for boolean options (group will point to the current
44    # group when executing X)
45    X = lambda optstr, helpstr, **kwargs: group.add_argument(
46        optstr, help=helpstr, action='store_true', **kwargs)
47
48    group = parser.add_argument_group('Help')
49    group.add_argument(
50        '-h',
51        '--help',
52        dest='h',
53        action='store_true',
54        help="Print this help message and exit.  Add '-v' for more detailed help.")
55
56    # C and Python toolchain options
57    group = parser.add_argument_group('Toolchain options')
58    group.add_argument(
59        '-A',
60        '--arch',
61        metavar='arch',
62        dest='arch',
63        help=textwrap.dedent('''Specify the architecture(s) to test. This option can be specified more than once'''))
64    group.add_argument('-C', '--compiler', metavar='compiler', dest='compiler', help=textwrap.dedent(
65        '''Specify the compiler(s) used to build the inferior executables. The compiler path can be an executable basename or a full path to a compiler executable. This option can be specified multiple times.'''))
66    if sys.platform == 'darwin':
67        group.add_argument('--apple-sdk', metavar='apple_sdk', dest='apple_sdk', default="macosx", help=textwrap.dedent(
68            '''Specify the name of the Apple SDK (macosx, macosx.internal, iphoneos, iphoneos.internal, or path to SDK) and use the appropriate tools from that SDK's toolchain.'''))
69    # FIXME? This won't work for different extra flags according to each arch.
70    group.add_argument(
71        '-E',
72        metavar='extra-flags',
73        help=textwrap.dedent('''Specify the extra flags to be passed to the toolchain when building the inferior programs to be debugged
74                                                           suggestions: do not lump the "-A arch1 -A arch2" together such that the -E option applies to only one of the architectures'''))
75
76    group.add_argument('--dsymutil', metavar='dsymutil', dest='dsymutil', help=textwrap.dedent('Specify which dsymutil to use.'))
77
78    group.add_argument('--filecheck', metavar='filecheck', dest='filecheck', help=textwrap.dedent('Specify which FileCheck binary to use.'))
79
80    # Test filtering options
81    group = parser.add_argument_group('Test filtering options')
82    group.add_argument(
83        '-f',
84        metavar='filterspec',
85        action='append',
86        help='Specify a filter, which consists of the test class name, a dot, followed by the test method, to only admit such test into the test suite')  # FIXME: Example?
87    X('-l', "Don't skip long running tests")
88    group.add_argument(
89        '-p',
90        metavar='pattern',
91        help='Specify a regexp filename pattern for inclusion in the test suite')
92    group.add_argument('--excluded', metavar='exclusion-file', action='append', help=textwrap.dedent(
93        '''Specify a file for tests to exclude. File should contain lists of regular expressions for test files or methods,
94                                with each list under a matching header (xfail files, xfail methods, skip files, skip methods)'''))
95    group.add_argument(
96        '-G',
97        '--category',
98        metavar='category',
99        action='append',
100        dest='categoriesList',
101        help=textwrap.dedent('''Specify categories of test cases of interest. Can be specified more than once.'''))
102    group.add_argument(
103        '--skip-category',
104        metavar='category',
105        action='append',
106        dest='skipCategories',
107        help=textwrap.dedent('''Specify categories of test cases to skip. Takes precedence over -G. Can be specified more than once.'''))
108
109    # Configuration options
110    group = parser.add_argument_group('Configuration options')
111    group.add_argument(
112        '--framework',
113        metavar='framework-path',
114        help='The path to LLDB.framework')
115    group.add_argument(
116        '--executable',
117        metavar='executable-path',
118        help='The path to the lldb executable')
119    group.add_argument(
120        '--server',
121        metavar='server-path',
122        help='The path to the debug server executable to use')
123    group.add_argument(
124        '--out-of-tree-debugserver',
125        dest='out_of_tree_debugserver',
126        action='store_true',
127        help='A flag to indicate an out-of-tree debug server is being used')
128    group.add_argument(
129        '--dwarf-version',
130        metavar='dwarf_version',
131        dest='dwarf_version',
132        type=int,
133        help='Override the DWARF version.')
134    group.add_argument(
135        '-s',
136        metavar='name',
137        help='Specify the name of the dir created to store the session files of tests with errored or failed status. If not specified, the test driver uses the timestamp as the session dir name')
138    group.add_argument(
139        '-S',
140        '--session-file-format',
141        default=configuration.session_file_format,
142        metavar='format',
143        help='Specify session file name format.  See configuration.py for a description.')
144    group.add_argument(
145        '-y',
146        type=int,
147        metavar='count',
148        help="Specify the iteration count used to collect our benchmarks. An example is the number of times to do 'thread step-over' to measure stepping speed.")
149    group.add_argument(
150        '-#',
151        type=int,
152        metavar='sharp',
153        dest='sharp',
154        help='Repeat the test suite for a specified number of times')
155    group.add_argument('--channel', metavar='channel', dest='channels', action='append', help=textwrap.dedent(
156        "Specify the log channels (and optional categories) e.g. 'lldb all' or 'gdb-remote packets' if no categories are specified, 'default' is used"))
157    group.add_argument(
158        '--log-success',
159        dest='log_success',
160        action='store_true',
161        help="Leave logs/traces even for successful test runs (useful for creating reference log files during debugging.)")
162    group.add_argument(
163        '--codesign-identity',
164        metavar='Codesigning identity',
165        default='lldb_codesign',
166        help='The codesigning identity to use')
167    group.add_argument(
168        '--build-dir',
169        dest='test_build_dir',
170        metavar='Test build directory',
171        default='lldb-test-build.noindex',
172        help='The root build directory for the tests. It will be removed before running.')
173
174    # Configuration options
175    group = parser.add_argument_group('Remote platform options')
176    group.add_argument(
177        '--platform-name',
178        dest='lldb_platform_name',
179        metavar='platform-name',
180        help='The name of a remote platform to use')
181    group.add_argument(
182        '--platform-url',
183        dest='lldb_platform_url',
184        metavar='platform-url',
185        help='A LLDB platform URL to use when connecting to a remote platform to run the test suite')
186    group.add_argument(
187        '--platform-working-dir',
188        dest='lldb_platform_working_dir',
189        metavar='platform-working-dir',
190        help='The directory to use on the remote platform.')
191
192    # Test-suite behaviour
193    group = parser.add_argument_group('Runtime behaviour options')
194    X('-d', 'Suspend the process after launch to wait indefinitely for a debugger to attach')
195    X('-q', "Don't print extra output from this script.")
196    X('-t', 'Turn on tracing of lldb command and other detailed test executions')
197    group.add_argument(
198        '-u',
199        dest='unset_env_varnames',
200        metavar='variable',
201        action='append',
202        help='Specify an environment variable to unset before running the test cases. e.g., -u DYLD_INSERT_LIBRARIES -u MallocScribble')
203    group.add_argument(
204        '--env',
205        dest='set_env_vars',
206        metavar='variable',
207        action='append',
208        help='Specify an environment variable to set to the given value before running the test cases e.g.: --env CXXFLAGS=-O3 --env DYLD_INSERT_LIBRARIES')
209    group.add_argument(
210        '--inferior-env',
211        dest='set_inferior_env_vars',
212        metavar='variable',
213        action='append',
214        help='Specify an environment variable to set to the given value for the inferior.')
215    X('-v', 'Do verbose mode of unittest framework (print out each test case invocation)')
216    group.add_argument(
217        '--enable-crash-dialog',
218        dest='disable_crash_dialog',
219        action='store_false',
220        help='(Windows only) When LLDB crashes, display the Windows crash dialog.')
221    group.set_defaults(disable_crash_dialog=True)
222
223    # Test results support.
224    group = parser.add_argument_group('Test results options')
225    group.add_argument(
226        '--curses',
227        action='store_true',
228        help='Shortcut for specifying test results using the curses formatter')
229    group.add_argument(
230        '--results-file',
231        action='store',
232        help=('Specifies the file where test results will be written '
233              'according to the results-formatter class used'))
234    group.add_argument(
235        '--results-port',
236        action='store',
237        type=int,
238        help=('Specifies the localhost port to which the results '
239              'formatted output should be sent'))
240    group.add_argument(
241        '--results-formatter',
242        action='store',
243        help=('Specifies the full package/module/class name used to translate '
244              'test events into some kind of meaningful report, written to '
245              'the designated output results file-like object'))
246    group.add_argument(
247        '--results-formatter-option',
248        '-O',
249        action='append',
250        dest='results_formatter_options',
251        help=('Specify an option to pass to the formatter. '
252              'Use --results-formatter-option="--option1=val1" '
253              'syntax.  Note the "=" is critical, don\'t include whitespace.'))
254    group.add_argument(
255        '--event-add-entries',
256        action='store',
257        help=('Specify comma-separated KEY=VAL entries to add key and value '
258              'pairs to all test events generated by this test run.  VAL may '
259              'be specified as VAL:TYPE, where TYPE may be int to convert '
260              'the value to an int'))
261
262    # Re-run related arguments
263    group = parser.add_argument_group('Test Re-run Options')
264    group.add_argument(
265        '--rerun-all-issues',
266        action='store_true',
267        help=('Re-run all issues that occurred during the test run '
268              'irrespective of the test method\'s marking as flakey. '
269              'Default behavior is to apply re-runs only to flakey '
270              'tests that generate issues.'))
271    group.add_argument(
272        '--rerun-max-file-threshold',
273        action='store',
274        type=int,
275        default=50,
276        help=('Maximum number of files requiring a rerun beyond '
277              'which the rerun will not occur.  This is meant to '
278              'stop a catastrophically failing test suite from forcing '
279              'all tests to be rerun in the single-worker phase.'))
280
281    # Remove the reference to our helper function
282    del X
283
284    group = parser.add_argument_group('Test directories')
285    group.add_argument(
286        'args',
287        metavar='test-dir',
288        nargs='*',
289        help='Specify a list of directory names to search for test modules named after Test*.py (test discovery). If empty, search from the current working directory instead.')
290
291    return parser
292