@@ -9,29 +9,35 @@ mutants and generate mutation testing reports.
9
9
**TL;DR version **: if you want to run a single copy and paste example, scroll
10
10
down to ``Killing mutants again, all killed `` below.
11
11
12
+ __Note: Clang 9 or newer is required!__
13
+
12
14
----
13
15
14
16
Step 1: Checking version
15
17
------------------------
16
18
17
- The tutorial assumes that you have `installed <Installation.html >`_ Mull on your system and
18
- have the `mull-cxx ` executable available:
19
+ Mull comes in a form of a compiler plugin and therefore tied to specific versions
20
+ of Clang and LLVM. As a consequence of that, tools and plugins have a suffix with
21
+ the actual Clang/LLVM version.
22
+
23
+ This tutorial assumes that you are using Clang 12 and that you have
24
+ `installed <Installation.html >`_ Mull on your system and have the ``mull-runner-12 ``
25
+ executable available:
19
26
20
27
.. code-block :: bash
21
28
22
- $ mull-cxx -version
29
+ $ mull-runner-12 -version
23
30
Mull: LLVM-based mutation testing
24
31
https://github.com/mull-project/mull
25
- Version: 0.8 .0
26
- Commit: f94f38ed
27
- Date: 04 Jan 2021
28
- LLVM: 9 .0.0
32
+ Version: 0.15 .0
33
+ Commit: a4be349e
34
+ Date: 18 Jan 2022
35
+ LLVM: 12 .0.1
29
36
30
- Step 2: Enabling Bitcode
31
- ------------------------
37
+ Step 2: Enabling compiler plugin
38
+ --------------------------------
32
39
33
- The most important thing that Mull needs to know is the path to your program
34
- which must be a valid C or C++ executable. Let's create a C program:
40
+ Let's create a C++ program:
35
41
36
42
.. code-block :: c
37
43
@@ -43,61 +49,53 @@ and compile it:
43
49
44
50
.. code-block :: bash
45
51
46
- $ clang main.cpp -o hello-world
52
+ $ clang-12 main.cpp -o hello-world
47
53
48
- We can already try running ``mull-cxx `` and see what happens:
54
+ We can already try using ``mull-runner `` and see what happens:
49
55
50
56
.. code-block :: text
51
57
52
- $ mull-cxx hello-world
53
- [info] Extracting bitcode from executable (threads: 1)
54
- [warning] No bitcode: x86_64
55
- [################################] 1/1. Finished in 3ms
56
- [info] Sanity check run (threads: 1)
57
- [################################] 1/1. Finished in 409ms
58
- [info] Gathering functions under test (threads: 1)
59
- [################################] 1/1. Finished in 0ms
58
+ $ mull-runner-12 ./hello-world
59
+ [info] Warm up run (threads: 1)
60
+ [################################] 1/1. Finished in 5ms
61
+ [info] Baseline run (threads: 1)
62
+ [################################] 1/1. Finished in 4ms
60
63
[info] No mutants found. Mutation score: infinitely high
61
- [info] Total execution time: 413ms
64
+ [info] Total execution time: 10ms
65
+
66
+ Notice the ``No mutants found `` message! Now, Mull is ready to work with the executable
67
+ but there are no mutants: we haven't compiled the program with the compiler plugin that embeds
68
+ mutants into our executable.
62
69
63
- Notice the ``No bitcode: x86_64 `` warning! Now Mull is already trying to work
64
- with our executable but there is still one important detail that is missing: we
65
- haven't compiled the program with a special option that embeds LLVM bitcode
66
- into our executable.
70
+ Let's fix that!
71
+ To pass the plugin to Clang, you need to add a few compiler flags.
67
72
68
- Mull works on a level of LLVM Bitcode relying on debug information to show
69
- results, therefore you should build your project with ``-fembed-bitcode `` and
70
- ``-g `` flags enabled.
73
+ .. code-block :: text
74
+
75
+ $ clang-12 -fexperimental-new-pass-manager \
76
+ -fpass-plugin=/usr/local/lib/mull-ir-frontend-12 \
77
+ -g -grecord-command-line \
78
+ main.cpp -o hello-world
79
+ [warning] Mull cannot find config (mull.yml). Using some defaults.
80
+
81
+ Notice the warning: Mull needs a config.
82
+ However, in this tutorial we can ignore the warning and rely on the defaults.
71
83
72
- Let's try again:
84
+ You can learn more about the config `here <TODO >`_.
85
+
86
+ Let's run ``mull-runner `` again:
73
87
74
88
.. code-block :: text
75
89
76
- $ clang -fembed-bitcode -g main.cpp -o hello-world
77
- $ mull-cxx hello-world
78
- [info] Extracting bitcode from executable (threads: 1)
79
- [################################] 1/1. Finished in 5ms
80
- [info] Loading bitcode files (threads: 1)
81
- [################################] 1/1. Finished in 11ms
82
- [info] Sanity check run (threads: 1)
83
- [################################] 1/1. Finished in 336ms
84
- [info] Gathering functions under test (threads: 1)
85
- [################################] 1/1. Finished in 1ms
86
- [info] Applying function filter: no debug info (threads: 1)
87
- [################################] 1/1. Finished in 10ms
88
- [info] Applying function filter: file path (threads: 1)
89
- [################################] 1/1. Finished in 10ms
90
- [info] Instruction selection (threads: 1)
91
- [################################] 1/1. Finished in 13ms
92
- [info] Searching mutants across functions (threads: 1)
93
- [################################] 1/1. Finished in 11ms
90
+ $ mull-runner-12 ./hello-world
91
+ [info] Warm up run (threads: 1)
92
+ [################################] 1/1. Finished in 4ms
93
+ [info] Baseline run (threads: 1)
94
+ [################################] 1/1. Finished in 6ms
94
95
[info] No mutants found. Mutation score: infinitely high
95
- [info] Total execution time: 400ms
96
+ [info] Total execution time: 12ms
96
97
97
- The ``No bitcode: x86_64 `` warning has gone and now we can focus on another
98
- important part of the output: ``No mutants found. Mutation score: infinitely
99
- high ``. We have our executable but we don't have any code so there is nothing
100
- Mull could work on.
98
+ Still no mutants, but this time it is because we don't have any code Mull can mutate.
101
99
102
100
Step 3: Killing mutants, one survived
103
101
-------------------------------------
@@ -114,13 +112,13 @@ Let's add some code:
114
112
}
115
113
116
114
int main() {
117
- int test1 = valid_age(25) == true;
115
+ bool test1 = valid_age(25) == true;
118
116
if (!test1) {
119
117
/// test failed
120
118
return 1;
121
119
}
122
120
123
- int test2 = valid_age(20) == false;
121
+ bool test2 = valid_age(20) == false;
124
122
if (!test2) {
125
123
/// test failed
126
124
return 1;
@@ -130,74 +128,41 @@ Let's add some code:
130
128
return 0;
131
129
}
132
130
133
- We compile this new code using the bitcode flags and run the Mull again. This
134
- time we also want to add additional flag ``-ide-reporter-show-killed `` which
131
+ We re- compile this new code using the plugin and run the Mull again. This
132
+ time we also want to add an additional flag ``-ide-reporter-show-killed `` which
135
133
tells Mull to print killed mutations. Normally we are not interested in seeing
136
- killed mutations in console output but in this tutorial we want to be more
134
+ killed mutants in console output but in this tutorial we want to be more
137
135
verbose.
138
136
139
137
.. code-block :: text
140
138
141
- $ clang -fembed-bitcode -g main.cpp -o hello-world
142
- $ mull-cxx -ide-reporter-show-killed hello-world
143
- [info] Extracting bitcode from executable (threads: 1)
144
- [################################] 1/1. Finished in 6ms
145
- [info] Loading bitcode files (threads: 1)
146
- [################################] 1/1. Finished in 11ms
147
- [info] Sanity check run (threads: 1)
148
- [################################] 1/1. Finished in 341ms
149
- [info] Gathering functions under test (threads: 1)
150
- [################################] 1/1. Finished in 0ms
151
- [info] Applying function filter: no debug info (threads: 3)
152
- [################################] 3/3. Finished in 0ms
153
- [info] Applying function filter: file path (threads: 2)
154
- [################################] 2/2. Finished in 0ms
155
- [info] Instruction selection (threads: 2)
156
- [################################] 2/2. Finished in 11ms
157
- [info] Searching mutants across functions (threads: 2)
158
- [################################] 2/2. Finished in 10ms
159
- [info] Applying filter: no debug info (threads: 6)
160
- [################################] 6/6. Finished in 1ms
161
- [info] Applying filter: file path (threads: 6)
162
- [################################] 6/6. Finished in 0ms
163
- [info] Applying filter: junk (threads: 6)
164
- [################################] 6/6. Finished in 11ms
165
- [info] Prepare mutations (threads: 1)
166
- [################################] 1/1. Finished in 0ms
167
- [info] Cloning functions for mutation (threads: 1)
168
- [################################] 1/1. Finished in 11ms
169
- [info] Removing original functions (threads: 1)
170
- [################################] 1/1. Finished in 10ms
171
- [info] Redirect mutated functions (threads: 1)
172
- [################################] 1/1. Finished in 10ms
173
- [info] Applying mutations (threads: 1)
174
- [################################] 4/4. Finished in 12ms
175
- [info] Compiling original code (threads: 1)
176
- [################################] 1/1. Finished in 11ms
177
- [info] Link mutated program (threads: 1)
178
- [################################] 1/1. Finished in 109ms
139
+ $ clang-12 -fexperimental-new-pass-manager \
140
+ -fpass-plugin=/usr/local/lib/mull-ir-frontend-12 \
141
+ -g -grecord-command-line \
142
+ main.cpp -o hello-world
143
+ $ mull-runner-12 -ide-reporter-show-killed hello-world
179
144
[info] Warm up run (threads: 1)
180
- [################################] 1/1. Finished in 360ms
145
+ [################################] 1/1. Finished in 151ms
181
146
[info] Baseline run (threads: 1)
182
- [################################] 1/1. Finished in 18ms
147
+ [################################] 1/1. Finished in 3ms
183
148
[info] Running mutants (threads: 4)
184
- [################################] 4/4. Finished in 63ms
149
+ [################################] 4/4. Finished in 10ms
185
150
[info] Killed mutants (3/4):
186
- /tmp/sc-PzmaCNIRu /main.cpp:2:15 : warning: Killed: Replaced >= with < [cxx_ge_to_lt]
187
- if (age >= 21) {
188
- ^
189
- /tmp/sc-PzmaCNIRu /main.cpp:9:33 : warning: Killed: Replaced == with != [cxx_eq_to_ne]
190
- int test1 = valid_age(25) == true;
191
- ^
192
- /tmp/sc-PzmaCNIRu /main.cpp:15:33 : warning: Killed: Replaced == with != [cxx_eq_to_ne]
193
- int test2 = valid_age(20) == false;
194
- ^
151
+ /tmp/sc-tTV8a84lL /main.cpp:2:11 : warning: Killed: Replaced >= with < [cxx_ge_to_lt]
152
+ if (age >= 21) {
153
+ ^
154
+ /tmp/sc-tTV8a84lL /main.cpp:9:30 : warning: Killed: Replaced == with != [cxx_eq_to_ne]
155
+ bool test1 = valid_age(25) == true;
156
+ ^
157
+ /tmp/sc-tTV8a84lL /main.cpp:15:30 : warning: Killed: Replaced == with != [cxx_eq_to_ne]
158
+ bool test2 = valid_age(20) == false;
159
+ ^
195
160
[info] Survived mutants (1/4):
196
- /tmp/sc-PzmaCNIRu /main.cpp:2:15 : warning: Survived: Replaced >= with > [cxx_ge_to_gt]
197
- if (age >= 21) {
198
- ^
161
+ /tmp/sc-tTV8a84lL /main.cpp:2:11 : warning: Survived: Replaced >= with > [cxx_ge_to_gt]
162
+ if (age >= 21) {
163
+ ^
199
164
[info] Mutation score: 75%
200
- [info] Total execution time: 996ms
165
+ [info] Total execution time: 167ms
201
166
202
167
What we are seeing now is four mutations: three mutations are ``Killed ``, another
203
168
one is ``Survived ``. If we take a closer look at the code and the contents
@@ -247,84 +212,53 @@ The code:
247
212
248
213
.. code-block :: text
249
214
250
- $ clang -fembed-bitcode -g main.cpp -o hello-world
251
- $ mull-cxx -ide-reporter-show-killed hello-world
252
- [info] Extracting bitcode from executable (threads: 1)
253
- [################################] 1/1. Finished in 4ms
254
- [info] Loading bitcode files (threads: 1)
255
- [################################] 1/1. Finished in 11ms
256
- [info] Sanity check run (threads: 1)
257
- [################################] 1/1. Finished in 7ms
258
- [info] Gathering functions under test (threads: 1)
259
- [################################] 1/1. Finished in 0ms
260
- [info] Applying function filter: no debug info (threads: 3)
261
- [################################] 3/3. Finished in 0ms
262
- [info] Applying function filter: file path (threads: 2)
263
- [################################] 2/2. Finished in 0ms
264
- [info] Instruction selection (threads: 2)
265
- [################################] 2/2. Finished in 12ms
266
- [info] Searching mutants across functions (threads: 2)
267
- [################################] 2/2. Finished in 10ms
268
- [info] Applying filter: no debug info (threads: 5)
269
- [################################] 5/5. Finished in 0ms
270
- [info] Applying filter: file path (threads: 5)
271
- [################################] 5/5. Finished in 1ms
272
- [info] Applying filter: junk (threads: 5)
273
- [################################] 5/5. Finished in 12ms
274
- [info] Prepare mutations (threads: 1)
275
- [################################] 1/1. Finished in 0ms
276
- [info] Cloning functions for mutation (threads: 1)
277
- [################################] 1/1. Finished in 10ms
278
- [info] Removing original functions (threads: 1)
279
- [################################] 1/1. Finished in 11ms
280
- [info] Redirect mutated functions (threads: 1)
281
- [################################] 1/1. Finished in 10ms
282
- [info] Applying mutations (threads: 1)
283
- [################################] 5/5. Finished in 0ms
284
- [info] Compiling original code (threads: 1)
285
- [################################] 1/1. Finished in 11ms
286
- [info] Link mutated program (threads: 1)
287
- [################################] 1/1. Finished in 62ms
215
+ $ clang-12 -fexperimental-new-pass-manager \
216
+ -fpass-plugin=/usr/local/lib/mull-ir-frontend-12 \
217
+ -g -grecord-command-line \
218
+ main.cpp -o hello-world
219
+ $ mull-runner-12 -ide-reporter-show-killed hello-world
288
220
[info] Warm up run (threads: 1)
289
- [################################] 1/1. Finished in 311ms
221
+ [################################] 1/1. Finished in 469ms
290
222
[info] Baseline run (threads: 1)
291
- [################################] 1/1. Finished in 19ms
223
+ [################################] 1/1. Finished in 4ms
292
224
[info] Running mutants (threads: 5)
293
- [################################] 5/5. Finished in 63ms
225
+ [################################] 5/5. Finished in 12ms
294
226
[info] Killed mutants (5/5):
295
- /tmp/sc-PzmaCNIRu /main.cpp:2:15 : warning: Killed: Replaced >= with > [cxx_ge_to_gt]
296
- if (age >= 21) {
297
- ^
298
- /tmp/sc-PzmaCNIRu /main.cpp:2:15 : warning: Killed: Replaced >= with < [cxx_ge_to_lt]
299
- if (age >= 21) {
300
- ^
301
- /tmp/sc-PzmaCNIRu /main.cpp:9:34 : warning: Killed: Replaced == with != [cxx_eq_to_ne]
302
- bool test1 = valid_age(25) == true;
303
- ^
304
- /tmp/sc-PzmaCNIRu /main.cpp:15:34 : warning: Killed: Replaced == with != [cxx_eq_to_ne]
305
- bool test2 = valid_age(20) == false;
306
- ^
307
- /tmp/sc-PzmaCNIRu /main.cpp:21:34 : warning: Killed: Replaced == with != [cxx_eq_to_ne]
308
- bool test3 = valid_age(21) == true;
309
- ^
227
+ /tmp/sc-tTV8a84lL /main.cpp:2:11 : warning: Killed: Replaced >= with > [cxx_ge_to_gt]
228
+ if (age >= 21) {
229
+ ^
230
+ /tmp/sc-tTV8a84lL /main.cpp:2:11 : warning: Killed: Replaced >= with < [cxx_ge_to_lt]
231
+ if (age >= 21) {
232
+ ^
233
+ /tmp/sc-tTV8a84lL /main.cpp:9:30 : warning: Killed: Replaced == with != [cxx_eq_to_ne]
234
+ bool test1 = valid_age(25) == true;
235
+ ^
236
+ /tmp/sc-tTV8a84lL /main.cpp:15:30 : warning: Killed: Replaced == with != [cxx_eq_to_ne]
237
+ bool test2 = valid_age(20) == false;
238
+ ^
239
+ /tmp/sc-tTV8a84lL /main.cpp:21:30 : warning: Killed: Replaced == with != [cxx_eq_to_ne]
240
+ bool test3 = valid_age(21) == true;
241
+ ^
310
242
[info] All mutations have been killed
311
243
[info] Mutation score: 100%
312
- [info] Total execution time: 554ms
244
+ [info] Total execution time: 487ms
313
245
314
246
In this last run, we see that all mutants were killed since we covered with tests
315
247
all cases around the ``<= ``.
316
248
317
249
Summary
318
250
-------
319
251
320
- This is a short summary of what we have learned in the tutorial.
321
- Your code has to be compiled with ``-fembed-bitcode -g `` compile flags:
252
+ As a summary, all you need to enable Mull is to add a few compiler flags to the
253
+ build system and then run ``mull-runner `` against the resulting executable.
254
+ Just to recap:
322
255
323
- - Mull expects embedded bitcode files to be present in a binary executable
324
- (ensured by ``-fembed-bitcode ``).
256
+ .. code-block :: text
325
257
326
- - Mull needs debug information to be included by the compiler (enabled by
327
- ``-g ``). Mull uses this information to find mutations in bitcode and source
328
- code.
258
+ $ clang-12 -fexperimental-new-pass-manager \
259
+ -fpass-plugin=/usr/local/lib/mull-ir-frontend-12 \
260
+ -g -grecord-command-line \
261
+ main.cpp -o hello-world
262
+ $ mull-runner-12 hello-world
329
263
330
264
The next step is to learn about `Compilation Database and Junk Mutations <CompilationDatabaseAndJunk.html >`_
0 commit comments