aboutsummaryrefslogtreecommitdiff
path: root/docs/markdown/Unit-tests.md
blob: 60fcad216c7cfe5dcc0a7806d94252ae2da8bf40 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
---
short-description: Meson's own unit-test system
...

# Unit tests

Meson comes with a fully functional unit test system. To use it simply build
an executable and then use it in a test.

```meson
e = executable('prog', 'testprog.c')
test('name of test', e)
```

You can add as many tests as you want. They are run with the command `meson
test`.

Meson captures the output of all tests and writes it in the log file
`meson-logs/testlog.txt`.

## Test parameters

Some tests require the use of command line arguments or environment
variables. These are simple to define.

```meson
test('command line test', exe, args : ['first', 'second'])
test('envvar test', exe2, env : ['key1=value1', 'key2=value2'])
```

Note how you need to specify multiple values as an array.

### MALLOC_PERTURB_

By default, environment variable
[`MALLOC_PERTURB_`](http://man7.org/linux/man-pages/man3/mallopt.3.html) is
set to a random value between 1..255. This can help find memory leaks on
configurations using glibc, including with non-GCC compilers. This feature
can be disabled as discussed in [test()](Reference-manual.md#test).

## Coverage

If you enable coverage measurements by giving Meson the command line flag
`-Db_coverage=true`, you can generate coverage reports after running the
tests (running the tests is required to gather the list of functions that get
called). Meson will autodetect what coverage generator tools you have
installed and will generate the corresponding targets. These targets are
`coverage-xml` and `coverage-text` which are both provided by
[Gcovr](http://gcovr.com) (version 3.3 or higher) and `coverage-html`, which
requires [Lcov](https://ltp.sourceforge.io/coverage/lcov.php) and
[GenHTML](https://linux.die.net/man/1/genhtml) or [Gcovr](http://gcovr.com).
As a convenience, a high-level `coverage` target is also generated which will
produce all 3 coverage report types, if possible.

The output of these commands is written to the log directory `meson-logs` in
your build directory.

## Parallelism

To reduce test times, Meson will by default run multiple unit tests in
parallel. It is common to have some tests which can not be run in parallel
because they require unique hold on some resource such as a file or a D-Bus
name. You have to specify these tests with a keyword argument.

```meson
test('unique test', t, is_parallel : false)
```

Meson will then make sure that no other unit test is running at the same
time. Non-parallel tests take longer to run so it is recommended that you
write your unit tests to be parallel executable whenever possible.

By default Meson uses as many concurrent processes as there are cores on the
test machine. You can override this with the environment variable
`MESON_TESTTHREADS` like this.

```console
$ MESON_TESTTHREADS=5 meson test
```

## Priorities

*(added in version 0.52.0)*

Tests can be assigned a priority that determines when a test is *started*.
Tests with higher priority are started first, tests with lower priority
started later. The default priority is 0, meson makes no guarantee on the
ordering of tests with identical priority.

```meson
test('started second', t, priority : 0)
test('started third', t, priority : -50)
test('started first', t, priority : 1000)
```

Note that the test priority only affects the starting order of tests and
subsequent tests are affected by how long it takes previous tests to
complete. It is thus possible that a higher-priority test is still running
when lower-priority tests with a shorter runtime have completed.

## Skipped tests and hard errors

Sometimes a test can only determine at runtime that it can not be run.

For the default `exitcode` testing protocol, the GNU standard approach in
this case is to exit the program with error code 77. Meson will detect this
and report these tests as skipped rather than failed. This behavior was added
in version 0.37.0.

For TAP-based tests, skipped tests should print a single line starting with
`1..0 # SKIP`.

In addition, sometimes a test fails set up so that it should fail even if it
is marked as an expected failure. The GNU standard approach in this case is
to exit the program with error code 99. Again, Meson will detect this and
report these tests as `ERROR`, ignoring the setting of `should_fail`. This
behavior was added in version 0.50.0.

## Testing tool

The goal of the meson test tool is to provide a simple way to run tests in a
variety of different ways. The tool is designed to be run in the build
directory.

The simplest thing to do is just to run all tests.

```console
$ meson test
```

### Run subsets of tests

For clarity, consider the meson.build containing:

```meson

test('A', ..., suite: 'foo')
test('B', ..., suite: ['foo', 'bar'])
test('C', ..., suite: 'bar')
test('D', ..., suite: 'baz')

```

Specify test(s) by name like:

```console
$ meson test A D
```

Tests belonging to a suite `suite` can be run as follows

```console
$ meson test --suite (sub)project_name:suite
```

Since version *0.46*, `(sub)project_name` can be omitted if it is the
top-level project.

Multiple suites are specified like:

```console
$ meson test --suite foo --suite bar
```

NOTE: If you choose to specify both suite(s) and specific test name(s), the
test name(s) must be contained in the suite(s). This however is redundant--
it would be more useful to specify either specific test names or suite(s).

### Other test options

Sometimes you need to run the tests multiple times, which is done like this:

```console
$ meson test --repeat=10
```

Invoking tests via a helper executable such as Valgrind can be done with the
`--wrap` argument

```console
$ meson test --wrap=valgrind testname
```

Arguments to the wrapper binary can be given like this:

```console
$ meson test --wrap='valgrind --tool=helgrind' testname
```

Meson also supports running the tests under GDB. Just doing this:

```console
$ meson test --gdb testname
```

Meson will launch `gdb` all set up to run the test. Just type `run` in the
GDB command prompt to start the program.

The second use case is a test that segfaults only rarely. In this case you
can invoke the following command:

```console
$ meson test --gdb --repeat=10000 testname
```

This runs the test up to 10 000 times under GDB automatically. If the program
crashes, GDB will halt and the user can debug the application. Note that
testing timeouts are disabled in this case so `meson test` will not kill
`gdb` while the developer is still debugging it. The downside is that if the
test binary freezes, the test runner will wait forever.

Sometimes, the GDB binary is not in the PATH variable or the user wants to
use a GDB replacement. Therefore, the invoked GDB program can be specified
*(added 0.52.0)*:

```console
$ meson test --gdb --gdb-path /path/to/gdb testname
```

```console
$ meson test --print-errorlogs
```

Meson will report the output produced by the failing tests along with other
useful information as the environmental variables. This is useful, for
example, when you run the tests on Travis-CI, Jenkins and the like.

For further information see the command line help of Meson by running `meson
test -h`.

## Legacy notes

If `meson test` does not work for you, you likely have a old version of
Meson. In that case you should call `mesontest` instead. If `mesontest`
doesn't work either you have a very old version prior to 0.37.0 and should
upgrade.

## Test outputs

Meson will write several different files with detailed results of running
tests. These will be written into $builddir/meson-logs/

### testlog.json

This is not a proper json file, but a file containing one valid json object
per line. This is file is designed so each line is streamed out as each test
is run, so it can be read as a stream while the test harness is running

### testlog.junit.xml

This is a valid JUnit XML description of all tests run. It is not streamed
out, and is written only once all tests complete running.

When tests use the `tap` protocol each test will be recorded as a testsuite
container, with each case named by the number of the result.

When tests use the `gtest` protocol meson will inject arguments to the test
to generate it's own JUnit XML, which meson will include as part of this XML
file.

*New in 0.55.0*