Move to kernel style SPDX license identifiers
[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)
29 plan = re.compile(r"""
30 ^1..(?P<expected>\d+) # Match the plan details.
31 [^#]* # Consume any non-hash character to confirm only
32 # directives appear with the plan details.
33 \#? # Optional directive marker.
34 \s* # Optional whitespace.
35 (?P<directive>.*) # Optional directive text.
36 """, re.VERBOSE)
37 diagnostic = re.compile(r'^#')
38 bail = re.compile(r"""
39 ^Bail\ out!
40 \s* # Optional whitespace.
41 (?P<reason>.*) # Optional reason.
42 """, re.VERBOSE)
43 version = re.compile(r'^TAP version (?P<version>\d+)$')
44
45 TAP_MINIMUM_DECLARED_VERSION = 13
46
47 def parse_file(self, filename):
48 """Parse a TAP file to an iterable of tap.line.Line objects.
49
50 This is a generator method that will yield an object for each
51 parsed line. The file given by `filename` is assumed to exist.
52 """
53 return self.parse(open(filename, 'r'))
54
55 def parse_stdin(self):
56 """Parse a TAP stream from standard input.
57
58 Note: this has the side effect of closing the standard input
59 filehandle after parsing.
60 """
61 return self.parse(sys.stdin)
62
63 def parse_text(self, text):
64 """Parse a string containing one or more lines of TAP output."""
65 return self.parse(StringIO(text))
66
67 def parse(self, fh):
68 """Generate tap.line.Line objects, given a file-like object `fh`.
69
70 `fh` may be any object that implements both the iterator and
71 context management protocol (i.e. it can be used in both a
72 "with" statement and a "for...in" statement.)
73
74 Trailing whitespace and newline characters will be automatically
75 stripped from the input lines.
76 """
77 with fh:
78 for line in fh:
79 yield self.parse_line(line.rstrip())
80
81 def parse_line(self, text):
82 """Parse a line into whatever TAP category it belongs."""
83 match = self.ok.match(text)
84 if match:
85 return self._parse_result(True, match)
86
87 match = self.not_ok.match(text)
88 if match:
89 return self._parse_result(False, match)
90
91 if self.diagnostic.match(text):
92 return Diagnostic(text)
93
94 match = self.plan.match(text)
95 if match:
96 return self._parse_plan(match)
97
98 match = self.bail.match(text)
99 if match:
100 return Bail(match.group('reason'))
101
102 match = self.version.match(text)
103 if match:
104 return self._parse_version(match)
105
106 return Unknown()
107
108 def _parse_plan(self, match):
109 """Parse a matching plan line."""
110 expected_tests = int(match.group('expected'))
111 directive = Directive(match.group('directive'))
112
113 # Only SKIP directives are allowed in the plan.
114 if directive.text and not directive.skip:
115 return Unknown()
116
117 return Plan(expected_tests, directive)
118
119 def _parse_result(self, ok, match):
120 """Parse a matching result line into a result instance."""
121 return Result(
122 ok, match.group('number'), match.group('description').strip(),
123 Directive(match.group('directive')))
124
125 def _parse_version(self, match):
126 version = int(match.group('version'))
127 if version < self.TAP_MINIMUM_DECLARED_VERSION:
128 raise ValueError(_('It is an error to explicitly specify '
129 'any version lower than 13.'))
130 return Version(version)
This page took 0.051838 seconds and 4 git commands to generate.