3555844094037db6ba646023b04788c514f7e9df
[barectf.git] / tests / tracing / conftest.py
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
24 import pytest
25 import os
26 import os.path
27 import barectf
28 import shutil
29 import subprocess
30 import tempfile
31
32
33 def 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 # If `path` is
41 # `/home/jo/barectf/tests/tracing/configs/basic/static-array/of-str.yaml`,
42 # for example, then:
43 #
44 # `cat`:
45 # `basic`
46 #
47 # `subcat`:
48 # `static-array`
49 #
50 # `file_name`:
51 # `of-str.yaml`
52 path_str = str(path)
53 file_name = os.path.basename(path_str)
54 subcat_dir = os.path.dirname(path_str)
55 subcat = os.path.basename(subcat_dir)
56 cat_dir = os.path.dirname(subcat_dir)
57 cat = os.path.basename(cat_dir)
58 configs_dir = os.path.dirname(cat_dir)
59 valid_cats = {
60 'basic',
61 'counter-clock',
62 'basic-extra-pc-ft-members',
63 }
64
65 if cat not in valid_cats or os.path.basename(configs_dir) != 'configs':
66 # not a YAML configuration test
67 return
68
69 # create C source, expectation file, and support directory paths
70 base_dir = os.path.dirname(configs_dir)
71 base_name = file_name.replace(yaml_ext, '')
72 subcat_rel_dir = os.path.join(cat, subcat)
73 src_path = os.path.join(base_dir, 'src', subcat_rel_dir, f'{base_name}.c')
74 data_expect_path = os.path.join(base_dir, 'expect', subcat_rel_dir, f'{base_name}.data.expect')
75 metadata_expect_path = os.path.join(base_dir, 'expect', subcat_rel_dir,
76 f'{base_name}.metadata.expect')
77 support_dir_path = os.path.join(base_dir, 'support', cat)
78
79 # create the file node
80 return _YamlFile.from_parent(parent, fspath=path, src_path=src_path,
81 data_expect_path=data_expect_path,
82 metadata_expect_path=metadata_expect_path,
83 support_dir_path=support_dir_path,
84 name=f'test-{cat}-{subcat}-{base_name}')
85
86
87 class _YamlFile(pytest.File):
88 def __init__(self, parent, fspath, src_path, data_expect_path, metadata_expect_path,
89 support_dir_path, name):
90 super().__init__(parent=parent, fspath=fspath)
91 self._name = name
92 self._src_path = src_path
93 self._data_expect_path = data_expect_path
94 self._metadata_expect_path = metadata_expect_path
95 self._support_dir_path = support_dir_path
96
97 def collect(self):
98 # yield a single item
99 yield _YamlItem.from_parent(self, name=self._name, src_path=self._src_path,
100 data_expect_path=self._data_expect_path,
101 metadata_expect_path=self._metadata_expect_path,
102 support_dir_path=self._support_dir_path)
103
104
105 class _YamlItem(pytest.Item):
106 def __init__(self, parent, name, src_path, data_expect_path, metadata_expect_path,
107 support_dir_path):
108 super().__init__(parent=parent, name=name)
109 self._src_path = src_path
110 self._data_expect_path = data_expect_path
111 self._metadata_expect_path = metadata_expect_path
112 self._support_dir_path = support_dir_path
113
114 def runtest(self):
115 # create a temporary directory
116 tmpdir = tempfile.TemporaryDirectory(prefix='pytest-barectf')
117
118 # create barectf configuration
119 with open(self.fspath) as f:
120 cfg = barectf.configuration_from_file(f, inclusion_directories=[self._support_dir_path])
121
122 # generate and write C code files
123 cg = barectf.CodeGenerator(cfg)
124 files = cg.generate_c_headers()
125 files += cg.generate_c_sources()
126
127 for file in files:
128 with open(os.path.join(tmpdir.name, file.name), 'w') as f:
129 f.write(file.contents)
130
131 # generate metadata stream, stripping the version and date
132 file = cg.generate_metadata_stream()
133 lines = file.contents.split('\n')
134 new_lines = []
135 discard_patterns = [
136 'Copyright (c)',
137 'The following code was generated',
138 '* on ',
139 'barectf_gen_date =',
140 'tracer_major =',
141 'tracer_minor =',
142 'tracer_patch =',
143 'tracer_pre =',
144 ]
145
146 for line in lines:
147 skip = False
148
149 for pattern in discard_patterns:
150 if pattern in line:
151 skip = True
152
153 if skip:
154 continue
155
156 new_lines.append(line)
157
158 actual_metadata = '\n'.join(new_lines)
159
160 # copy Makefile to build directory
161 shutil.copy(os.path.join(self._support_dir_path, 'Makefile'), tmpdir.name)
162
163 # copy platform files to build directory
164 shutil.copy(os.path.join(self._support_dir_path, 'test-platform.c'), tmpdir.name)
165 shutil.copy(os.path.join(self._support_dir_path, 'test-platform.h'), tmpdir.name)
166
167 # copy specific source code file to build directory
168 shutil.copy(self._src_path, os.path.join(tmpdir.name, 'test.c'))
169
170 # build the test
171 subprocess.check_output(['make'], cwd=tmpdir.name)
172
173 # run the test (produce the data stream)
174 subprocess.check_output(['./test'], cwd=tmpdir.name)
175
176 # read actual stream
177 with open(os.path.join(tmpdir.name, 'stream'), 'rb') as f:
178 actual_stream = f.read()
179
180 # read data stream expectation file
181 with open(self._data_expect_path, 'rb') as f:
182 expected_stream = f.read()
183
184 # read metadata stream expectation file
185 with open(self._metadata_expect_path, 'r') as f:
186 expected_metadata = f.read()
187
188 # validate streams
189 assert actual_metadata == expected_metadata
190 assert actual_stream == expected_stream
191
192 # delete temporary directory
193 tmpdir.cleanup()
194
195 def repr_failure(self, excinfo, style=None):
196 return f'`{self.fspath}` failed: {excinfo}.'
197
198 def reportinfo(self):
199 return self.fspath, None, self.name
This page took 0.034418 seconds and 3 git commands to generate.