Use Black stable to format python code
[babeltrace.git] / tests / utils / python / tap / parser.py
CommitLineData
0235b0db
MJ
1# SPDX-License-Identifier: BSD-2-Clause
2#
b85894a3
MJ
3# Copyright (c) 2016, Matt Layman
4
5from io import StringIO
6import re
7import sys
8
9from tap.directive import Directive
10from tap.i18n import _
11from tap.line import Bail, Diagnostic, Plan, Result, Unknown, Version
12
13
14class Parser(object):
15 """A parser for TAP files and lines."""
16
17 # ok and not ok share most of the same characteristics.
18 result_base = r"""
19 \s* # Optional whitespace.
20 (?P<number>\d*) # Optional test number.
21 \s* # Optional whitespace.
22 (?P<description>[^#]*) # Optional description before #.
23 \#? # Optional directive marker.
24 \s* # Optional whitespace.
25 (?P<directive>.*) # Optional directive text.
26 """
27 ok = re.compile(r'^ok' + result_base, re.VERBOSE)
28 not_ok = re.compile(r'^not\ ok' + result_base, re.VERBOSE)
768f9bcb
MJ
29 plan = re.compile(
30 r"""
b85894a3
MJ
31 ^1..(?P<expected>\d+) # Match the plan details.
32 [^#]* # Consume any non-hash character to confirm only
33 # directives appear with the plan details.
34 \#? # Optional directive marker.
35 \s* # Optional whitespace.
36 (?P<directive>.*) # Optional directive text.
768f9bcb
MJ
37 """,
38 re.VERBOSE,
39 )
b85894a3 40 diagnostic = re.compile(r'^#')
768f9bcb
MJ
41 bail = re.compile(
42 r"""
b85894a3
MJ
43 ^Bail\ out!
44 \s* # Optional whitespace.
45 (?P<reason>.*) # Optional reason.
768f9bcb
MJ
46 """,
47 re.VERBOSE,
48 )
b85894a3
MJ
49 version = re.compile(r'^TAP version (?P<version>\d+)$')
50
51 TAP_MINIMUM_DECLARED_VERSION = 13
52
53 def parse_file(self, filename):
54 """Parse a TAP file to an iterable of tap.line.Line objects.
55
56 This is a generator method that will yield an object for each
57 parsed line. The file given by `filename` is assumed to exist.
58 """
59 return self.parse(open(filename, 'r'))
60
61 def parse_stdin(self):
62 """Parse a TAP stream from standard input.
63
64 Note: this has the side effect of closing the standard input
65 filehandle after parsing.
66 """
67 return self.parse(sys.stdin)
68
69 def parse_text(self, text):
70 """Parse a string containing one or more lines of TAP output."""
71 return self.parse(StringIO(text))
72
73 def parse(self, fh):
74 """Generate tap.line.Line objects, given a file-like object `fh`.
75
76 `fh` may be any object that implements both the iterator and
77 context management protocol (i.e. it can be used in both a
78 "with" statement and a "for...in" statement.)
79
80 Trailing whitespace and newline characters will be automatically
81 stripped from the input lines.
82 """
83 with fh:
84 for line in fh:
85 yield self.parse_line(line.rstrip())
86
87 def parse_line(self, text):
88 """Parse a line into whatever TAP category it belongs."""
89 match = self.ok.match(text)
90 if match:
91 return self._parse_result(True, match)
92
93 match = self.not_ok.match(text)
94 if match:
95 return self._parse_result(False, match)
96
97 if self.diagnostic.match(text):
98 return Diagnostic(text)
99
100 match = self.plan.match(text)
101 if match:
102 return self._parse_plan(match)
103
104 match = self.bail.match(text)
105 if match:
106 return Bail(match.group('reason'))
107
108 match = self.version.match(text)
109 if match:
110 return self._parse_version(match)
111
112 return Unknown()
113
114 def _parse_plan(self, match):
115 """Parse a matching plan line."""
116 expected_tests = int(match.group('expected'))
117 directive = Directive(match.group('directive'))
118
119 # Only SKIP directives are allowed in the plan.
120 if directive.text and not directive.skip:
121 return Unknown()
122
123 return Plan(expected_tests, directive)
124
125 def _parse_result(self, ok, match):
126 """Parse a matching result line into a result instance."""
127 return Result(
768f9bcb
MJ
128 ok,
129 match.group('number'),
130 match.group('description').strip(),
131 Directive(match.group('directive')),
132 )
b85894a3
MJ
133
134 def _parse_version(self, match):
135 version = int(match.group('version'))
136 if version < self.TAP_MINIMUM_DECLARED_VERSION:
768f9bcb
MJ
137 raise ValueError(
138 _('It is an error to explicitly specify ' 'any version lower than 13.')
139 )
b85894a3 140 return Version(version)
This page took 0.057838 seconds and 4 git commands to generate.