2 # -*- coding: utf-8 -*-
4 # Copyright © 2018 Endless Mobile, Inc.
6 # This library is free software; you can redistribute it and/or
7 # modify it under the terms of the GNU Lesser General Public
8 # License as published by the Free Software Foundation; either
9 # version 2.1 of the License, or (at your option) any later version.
11 # This library is distributed in the hope that it will be useful,
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 # Lesser General Public License for more details.
16 # You should have received a copy of the GNU Lesser General Public
17 # License along with this library; if not, write to the Free Software
18 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
21 """Integration tests for glib-mkenums utility."""
31 class TestMkenums(unittest
.TestCase
):
32 """Integration test for running glib-mkenums.
34 This can be run when installed or uninstalled. When uninstalled, it
35 requires G_TEST_BUILDDIR and G_TEST_SRCDIR to be set.
37 The idea with this test harness is to test the glib-mkenums utility, its
38 handling of command line arguments, its exit statuses, and its handling of
39 various C source codes. In future we could split the core glib-mkenums
40 parsing and generation code out into a library and unit test that, and
41 convert this test to just check command line behaviour.
45 self
.timeout_seconds
= 10 # seconds per test
46 self
.tmpdir
= tempfile
.TemporaryDirectory()
47 os
.chdir(self
.tmpdir
.name
)
48 print('tmpdir:', self
.tmpdir
.name
)
49 if 'G_TEST_BUILDDIR' in os
.environ
:
51 os
.path
.join(os
.environ
['G_TEST_BUILDDIR'], '..',
54 self
.__mkenums
= os
.path
.join('/', 'usr', 'bin', 'glib-mkenums')
55 print('mkenums:', self
.__mkenums
)
60 def runMkenums(self
, *args
):
61 argv
= [self
.__mkenums
]
63 print('Running:', argv
)
65 env
= os
.environ
.copy()
66 env
['LC_ALL'] = 'C.UTF-8'
67 print('Environment:', env
)
69 info
= subprocess
.run(argv
, timeout
=self
.timeout_seconds
,
70 stdout
=subprocess
.PIPE
,
71 stderr
=subprocess
.PIPE
,
73 print('Output:', info
.stdout
.decode('utf-8'))
76 def runMkenumsWithHeader(self
, h_contents
, encoding
='utf-8', *args
):
77 template_contents
= '''
78 /*** BEGIN file-header ***/
82 /*** END file-header ***/
84 /*** BEGIN file-production ***/
88 /*** END file-production ***/
90 /*** BEGIN enumeration-production ***/
91 enumeration-production
93 enum_name: @enum_name@
95 ENUMSHORT: @ENUMSHORT@
96 ENUMPREFIX: @ENUMPREFIX@
100 /*** END enumeration-production ***/
102 /*** BEGIN value-header ***/
105 enum_name: @enum_name@
107 ENUMSHORT: @ENUMSHORT@
108 ENUMPREFIX: @ENUMPREFIX@
112 /*** END value-header ***/
114 /*** BEGIN value-production ***/
116 VALUENAME: @VALUENAME@
117 valuenick: @valuenick@
122 /*** END value-production ***/
124 /*** BEGIN value-tail ***/
127 enum_name: @enum_name@
129 ENUMSHORT: @ENUMSHORT@
130 ENUMPREFIX: @ENUMPREFIX@
134 /*** END value-tail ***/
136 /*** BEGIN comment ***/
139 /*** END comment ***/
141 /*** BEGIN file-tail ***/
145 /*** END file-tail ***/
148 with tempfile
.NamedTemporaryFile(dir=self
.tmpdir
.name
,
149 suffix
='.template') as template_file
, \
150 tempfile
.NamedTemporaryFile(dir=self
.tmpdir
.name
,
151 suffix
='.h') as h_file
:
152 # Write out the template.
153 template_file
.write(template_contents
.encode('utf-8'))
154 print(template_file
.name
+ ':', template_contents
)
156 # Write out the header to be scanned.
157 h_file
.write(h_contents
.encode(encoding
))
158 print(h_file
.name
+ ':', h_contents
)
160 template_file
.flush()
163 # Run glib-mkenums with a template which outputs all substitutions.
164 info
= self
.runMkenums('--template', template_file
.name
,
166 info
.check_returncode()
167 out
= info
.stdout
.decode('utf-8').strip()
168 err
= info
.stderr
.decode('utf-8').strip()
170 # Known substitutions for generated filenames.
172 'filename': h_file
.name
,
173 'basename': os
.path
.basename(h_file
.name
),
174 'standard_top_comment':
175 'This file is generated by glib-mkenums, do not modify '
176 'it. This code is licensed under the same license as the '
177 'containing project. Note that it links to GLib, so must '
178 'comply with the LGPL linking clauses.',
179 'standard_bottom_comment': 'Generated data ends here'
182 return (info
, out
, err
, subs
)
184 def assertSingleEnum(self
, out
, subs
, enum_name_camel
, enum_name_lower
,
185 enum_name_upper
, enum_name_short
, enum_prefix
,
186 type_lower
, type_camel
, type_upper
,
187 value_name
, value_nick
, value_num
):
188 """Assert that out (from runMkenumsWithHeader()) contains a single
189 enum and value matching the given arguments."""
191 'enum_name_camel': enum_name_camel
,
192 'enum_name_lower': enum_name_lower
,
193 'enum_name_upper': enum_name_upper
,
194 'enum_name_short': enum_name_short
,
195 'enum_prefix': enum_prefix
,
196 'type_lower': type_lower
,
197 'type_camel': type_camel
,
198 'type_upper': type_upper
,
199 'value_name': value_name
,
200 'value_nick': value_nick
,
201 'value_num': value_num
,
206 comment: {standard_top_comment}
215 enumeration-production
216 EnumName: {enum_name_camel}
217 enum_name: {enum_name_lower}
218 ENUMNAME: {enum_name_upper}
219 ENUMSHORT: {enum_name_short}
220 ENUMPREFIX: {enum_prefix}
225 EnumName: {enum_name_camel}
226 enum_name: {enum_name_lower}
227 ENUMNAME: {enum_name_upper}
228 ENUMSHORT: {enum_name_short}
229 ENUMPREFIX: {enum_prefix}
234 VALUENAME: {value_name}
235 valuenick: {value_nick}
236 valuenum: {value_num}
241 EnumName: {enum_name_camel}
242 enum_name: {enum_name_lower}
243 ENUMNAME: {enum_name_upper}
244 ENUMSHORT: {enum_name_short}
245 ENUMPREFIX: {enum_prefix}
254 comment: {standard_bottom_comment}
255 '''.format(**subs
).strip(), out
)
258 """Test the --help argument."""
259 info
= self
.runMkenums('--help')
260 info
.check_returncode()
262 out
= info
.stdout
.decode('utf-8').strip()
263 self
.assertIn('usage: glib-mkenums', out
)
265 def test_empty_header(self
):
266 """Test an empty header."""
267 (info
, out
, err
, subs
) = self
.runMkenumsWithHeader('')
268 self
.assertEqual('', err
)
271 comment: {standard_top_comment}
282 comment: {standard_bottom_comment}
283 '''.format(**subs
).strip(), out
)
285 def test_enum_name(self
):
286 """Test typedefs with an enum and a typedef name. Bug #794506."""
288 typedef enum _SomeEnumIdentifier {
290 } SomeEnumIdentifier;
292 (info
, out
, err
, subs
) = self
.runMkenumsWithHeader(h_contents
)
293 self
.assertEqual('', err
)
294 self
.assertSingleEnum(out
, subs
, 'SomeEnumIdentifier',
295 'some_enum_identifier', 'SOME_ENUM_IDENTIFIER',
296 'ENUM_IDENTIFIER', 'SOME', 'enum', 'Enum',
297 'ENUM', 'ENUM_VALUE', 'value', '0')
299 def test_non_utf8_encoding(self
):
300 """Test source files with non-UTF-8 encoding. Bug #785113."""
302 /* Copyright © La Peña */
305 } SomeEnumIdentifier;
307 (info
, out
, err
, subs
) = \
308 self
.runMkenumsWithHeader(h_contents
, encoding
='iso-8859-1')
309 self
.assertIn('WARNING: UnicodeWarning: ', err
)
310 self
.assertSingleEnum(out
, subs
, 'SomeEnumIdentifier',
311 'some_enum_identifier', 'SOME_ENUM_IDENTIFIER',
312 'ENUM_IDENTIFIER', 'SOME', 'enum', 'Enum',
313 'ENUM', 'ENUM_VALUE', 'value', '0')
315 def test_reproducible(self
):
316 """Test builds are reproducible regardless of file ordering.
330 with tempfile
.NamedTemporaryFile(dir=self
.tmpdir
.name
,
331 suffix
='.template') as template_file
, \
332 tempfile
.NamedTemporaryFile(dir=self
.tmpdir
.name
,
333 suffix
='1.h') as h_file1
, \
334 tempfile
.NamedTemporaryFile(dir=self
.tmpdir
.name
,
335 suffix
='2.h') as h_file2
:
336 # Write out the template and headers.
337 template_file
.write('template'.encode('utf-8'))
338 h_file1
.write(h_contents1
.encode('utf-8'))
339 h_file2
.write(h_contents2
.encode('utf-8'))
341 template_file
.flush()
345 # Run glib-mkenums with the headers in one order, and then again
347 info1
= self
.runMkenums('--template', template_file
.name
,
348 h_file1
.name
, h_file2
.name
)
349 info1
.check_returncode()
350 out1
= info1
.stdout
.decode('utf-8').strip()
351 self
.assertEqual('', info1
.stderr
.decode('utf-8').strip())
353 info2
= self
.runMkenums('--template', template_file
.name
,
354 h_file2
.name
, h_file1
.name
)
355 info2
.check_returncode()
356 out2
= info2
.stdout
.decode('utf-8').strip()
357 self
.assertEqual('', info2
.stderr
.decode('utf-8').strip())
359 # The output should be the same.
360 self
.assertEqual(out1
, out2
)
362 def test_no_nick(self
):
363 """Test trigraphs with a desc but no nick. Issue #1360."""
366 GEGL_SAMPLER_NEAREST = 0, /*< desc="nearest" >*/
369 (info
, out
, err
, subs
) = self
.runMkenumsWithHeader(h_contents
)
370 self
.assertEqual('', err
)
371 self
.assertSingleEnum(out
, subs
, 'GeglSamplerType',
372 'gegl_sampler_type', 'GEGL_SAMPLER_TYPE',
373 'SAMPLER_TYPE', 'GEGL', 'enum', 'Enum',
374 'ENUM', 'GEGL_SAMPLER_NEAREST', 'nearest', '0')
377 if __name__
== '__main__':
378 unittest
.main(testRunner
=taptestrunner
.TAPTestRunner())