tests/tracing: use pytest_collect_file() hook for YAML files
[deliverable/barectf.git] / tests / tracing / conftest.py
... / ...
CommitLineData
1# The MIT License (MIT)
2#
3# Copyright (c) 2020 Philippe Proulx <pproulx@efficios.com>
4#
5# Permission is hereby granted, free of charge, to any person obtaining
6# a copy of this software and associated documentation files (the
7# "Software"), to deal in the Software without restriction, including
8# without limitation the rights to use, copy, modify, merge, publish,
9# distribute, sublicense, and/or sell copies of the Software, and to
10# permit persons to whom the Software is furnished to do so, subject to
11# the following conditions:
12#
13# The above copyright notice and this permission notice shall be
14# included in all copies or substantial portions of the Software.
15#
16# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
19# IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
20# CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
21# TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
22# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23
24import pytest
25import os
26import os.path
27import barectf
28import shutil
29import subprocess
30import tempfile
31
32
33def pytest_collect_file(parent, path):
34 yaml_ext = '.yaml'
35
36 if path.ext != yaml_ext:
37 # not a YAML file: cancel
38 return
39
40 # At the end of this loop, if `path` is
41 # `/home/jo/barectf/tests/tracing/configs/succeed/static-array/of-str.yaml`,
42 # for example, then `elems` is:
43 #
44 # * `of-str.yaml`
45 # * `static-array`
46 # * `succeed`
47 path_str = str(path)
48 elems = []
49
50 while True:
51 elem = os.path.basename(path_str)
52
53 if elem == 'configs':
54 break
55
56 elems.append(elem)
57 path_str = os.path.dirname(path_str)
58
59 # create C source, expectation file, and support directory paths
60 base_dir = os.path.dirname(path_str)
61 base_name = elems[0].replace(yaml_ext, '')
62 rel_dir = os.path.join(*list(reversed(elems[1:])))
63 src_path = os.path.join(*[base_dir, 'src', rel_dir, f'{base_name}.c'])
64 data_expect_path = os.path.join(*([base_dir, 'expect', rel_dir, f'{base_name}.data.expect']))
65 metadata_expect_path = os.path.join(*([base_dir, 'expect', rel_dir, f'{base_name}.metadata.expect']))
66 support_dir_path = os.path.join(base_dir, 'support')
67
68 # create a unique test name
69 name = f'test-{"-".join(reversed(elems))}'.replace(yaml_ext, '')
70
71 # create the file node
72 return _YamlFile.from_parent(parent, fspath=path, src_path=src_path,
73 data_expect_path=data_expect_path,
74 metadata_expect_path=metadata_expect_path,
75 support_dir_path=support_dir_path, name=name)
76
77
78class _YamlFile(pytest.File):
79 def __init__(self, parent, fspath, src_path, data_expect_path, metadata_expect_path,
80 support_dir_path, name):
81 super().__init__(parent=parent, fspath=fspath)
82 self._name = name
83 self._src_path = src_path
84 self._data_expect_path = data_expect_path
85 self._metadata_expect_path = metadata_expect_path
86 self._support_dir_path = support_dir_path
87
88 def collect(self):
89 # yield a single item
90 yield _YamlItem.from_parent(self, name=self._name, src_path=self._src_path,
91 data_expect_path=self._data_expect_path,
92 metadata_expect_path=self._metadata_expect_path,
93 support_dir_path=self._support_dir_path)
94
95
96class _YamlItem(pytest.Item):
97 def __init__(self, parent, name, src_path, data_expect_path, metadata_expect_path,
98 support_dir_path):
99 super().__init__(parent=parent, name=name)
100 self._src_path = src_path
101 self._data_expect_path = data_expect_path
102 self._metadata_expect_path = metadata_expect_path
103 self._support_dir_path = support_dir_path
104
105 def runtest(self):
106 # create a temporary directory
107 tmpdir = tempfile.TemporaryDirectory(prefix='pytest-barectf')
108
109 # create barectf configuration
110 with open(self.fspath) as f:
111 cfg = barectf.configuration_from_file(f)
112
113 # generate and write C code files
114 cg = barectf.CodeGenerator(cfg)
115 files = cg.generate_c_headers()
116 files += cg.generate_c_sources()
117
118 for file in files:
119 with open(os.path.join(tmpdir.name, file.name), 'w') as f:
120 f.write(file.contents)
121
122 # generate metadata stream, stripping the version and date
123 file = cg.generate_metadata_stream()
124 lines = file.contents.split('\n')
125 new_lines = []
126 discard_patterns = [
127 'Copyright (c)',
128 'The following code was generated',
129 '* on ',
130 'barectf_gen_date =',
131 'tracer_major =',
132 'tracer_minor =',
133 'tracer_patch =',
134 ]
135
136 for line in lines:
137 skip = False
138
139 for pattern in discard_patterns:
140 if pattern in line:
141 skip = True
142
143 if skip:
144 continue
145
146 new_lines.append(line)
147
148 actual_metadata = '\n'.join(new_lines)
149
150 # copy Makefile to build directory
151 shutil.copy(os.path.join(self._support_dir_path, 'Makefile'), tmpdir.name)
152
153 # copy platform files to build directory
154 shutil.copy(os.path.join(self._support_dir_path, 'test-platform.c'), tmpdir.name)
155 shutil.copy(os.path.join(self._support_dir_path, 'test-platform.h'), tmpdir.name)
156
157 # copy specific source code file to build directory
158 shutil.copy(self._src_path, os.path.join(tmpdir.name, 'test.c'))
159
160 # build the test
161 subprocess.check_output(['make'], cwd=tmpdir.name)
162
163 # run the test (produce the data stream)
164 subprocess.check_output(['./test'], cwd=tmpdir.name)
165
166 # read actual stream
167 with open(os.path.join(tmpdir.name, 'stream'), 'rb') as f:
168 actual_stream = f.read()
169
170 # read data stream expectation file
171 with open(self._data_expect_path, 'rb') as f:
172 expected_stream = f.read()
173
174 # read metadata stream expectation file
175 with open(self._metadata_expect_path, 'r') as f:
176 expected_metadata = f.read()
177
178 # validate streams
179 assert actual_metadata == expected_metadata
180 assert actual_stream == expected_stream
181
182 # delete temporary directory
183 tmpdir.cleanup()
184
185 def repr_failure(self, excinfo, style=None):
186 return f'`{self.fspath}` failed: {excinfo}.'
187
188 def reportinfo(self):
189 return self.fspath, None, self.name
This page took 0.022053 seconds and 4 git commands to generate.