1 /**
2 Copyright: Copyright (c) 2017, Joakim Brännström. All rights reserved.
3 License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost Software License 1.0)
4 Author: Joakim Brännström (joakim.brannstrom@gmx.com)
5 
6 #TST-plugin_mutate_mutation_ror
7 */
8 module dextool_test.mutate_ror;
9 
10 import dextool_test.utility;
11 
12 import unit_threaded;
13 
14 // dfmt off
15 
16 @("shall produce all ROR mutations")
17 @Values("ror_primitive.cpp", "ror_overload.cpp")
18 unittest {
19     mixin(envSetup(globalTestdir, No.setupEnv));
20     testEnv.outputSuffix(getValue!string);
21     testEnv.setupEnv;
22 
23     makeDextoolAnalyze(testEnv)
24         .addInputArg(testData ~ getValue!string)
25         .run;
26     auto r = makeDextool(testEnv)
27         .addArg(["test"])
28         .addArg(["--mutant", "ror"])
29         .run;
30     verifyRor(r.stdout);
31 }
32 
33 void verifyRor(string[] txt) {
34     import std.algorithm;
35 
36     static struct Ex {
37         string[2] ops;
38         string expr;
39     }
40     Ex[string] tbl = [
41         "<": Ex(["<=", "!="], "false"),
42         ">": Ex([">=", "!="], "false"),
43         "<=": Ex(["<", "=="], "true"),
44         ">=": Ex([">", "=="], "true"),
45         "==": Ex(["<=", ">="], "false"),
46         "!=": Ex(["<", ">"], "true"),
47     ];
48 
49     foreach (mut; tbl.byKeyValue) {
50         foreach (op; mut.value.ops) {
51             auto expected = format("from '%s' to '%s'", mut.key, op);
52             dextoolYap("Testing: " ~ expected);
53             txt.sliceContains(expected).shouldBeTrue;
54         }
55 
56         auto expected = format("from 'a %s b' to '%s'", mut.key, mut.value.expr);
57         dextoolYap("Testing: " ~ expected);
58         txt.sliceContains(expected).shouldBeTrue;
59     }
60 }
61 
62 @("shall produce all ROR mutations according to the alternative schema when both types are floating point types")
63 unittest {
64     mixin(envSetup(globalTestdir));
65 
66     makeDextoolAnalyze(testEnv)
67         .addInputArg(testData ~ "ror_float_primitive.cpp")
68         .run;
69     auto r = makeDextool(testEnv)
70         .addArg(["test"])
71         .addArg(["--mutant", "ror"])
72         .run;
73     verifyFloatRor(r.stdout);
74 }
75 
76 void verifyFloatRor(string[] txt) {
77     import std.algorithm;
78 
79     static struct Ex {
80         string[] ops;
81         string expr;
82     }
83     Ex[string] tbl = [
84         "<": Ex([">"], "false"),
85         ">": Ex(["<"], "false"),
86         "<=": Ex([">"], "true"),
87         ">=": Ex(["<"], "true"),
88         "==": Ex(["<=", ">="], "false"),
89         "!=": Ex(["<", ">"], "true"),
90     ];
91 
92     foreach (mut; tbl.byKeyValue) {
93         foreach (op; mut.value.ops) {
94             auto expected = format("from '%s' to '%s'", mut.key, op);
95             dextoolYap("Testing: " ~ expected);
96             txt.sliceContains(expected).shouldBeTrue;
97         }
98 
99         auto expected = format("from 'a %s b' to '%s'", mut.key, mut.value.expr);
100         dextoolYap("Testing: " ~ expected);
101         txt.sliceContains(expected).shouldBeTrue;
102     }
103 }
104 
105 @("shall produce all ROR mutations according to the enum schema when both types are enum type and one is an enum const declaration")
106 unittest {
107     mixin(envSetup(globalTestdir));
108 
109     makeDextoolAnalyze(testEnv)
110         .addInputArg(testData ~ "ror_enum_primitive.cpp")
111         .run;
112     auto r = makeDextool(testEnv)
113         .addArg(["test"])
114         .addArg(["--mutant", "ror"])
115         .run;
116 
117     testConsecutiveSparseOrder!SubStr([
118         "from '<' to '<='",
119         "from '<' to '!='",
120         "from 'a < MyE::C' to 'false'",
121 
122         "from '<' to '<='",
123         "from '<' to '!='",
124         "from 'MyE::C < b' to 'false'",
125 
126         "from '>' to '>='",
127         "from '>' to '!='",
128         "from 'a > MyE::C' to 'false'",
129 
130         "from '>' to '>='",
131         "from '>' to '!='",
132         "from 'MyE::C > b' to 'false'",
133 
134         "from '<=' to '<'",
135         "from '<=' to '=='",
136         // this will always be true. Generating it for now because code like this should not exist
137         "from 'a <= MyE::C' to 'true'",
138 
139         // No test case can catch this. Generating it for now because code like this should not exist
140         "from '<=' to '<'",
141         "from '<=' to '=='",
142         "from 'MyE::C <= b' to 'true'",
143 
144         "from '>=' to '>'",
145         "from '>=' to '=='",
146         "from 'a >= MyE::C' to 'true'",
147 
148         "from '>=' to '>'",
149         "from '>=' to '=='",
150         "from 'MyE::C >= b' to 'true'",
151     ]).shouldBeIn(r.stdout);
152 }
153 
154 @("shall produce all ROR mutations according to the enum schema for equal when both types are enum type and one is an enum const declaration")
155 unittest {
156     mixin(envSetup(globalTestdir));
157 
158     makeDextoolAnalyze(testEnv)
159         .addInputArg(testData ~ "ror_enum_primitive_equal.cpp")
160         .run;
161     auto r = makeDextool(testEnv)
162         .addArg(["test"])
163         .addArg(["--mutant", "ror"])
164         .run;
165 
166     testConsecutiveSparseOrder!SubStr([
167         "from '==' to '<='",
168         "from '==' to '>='",
169         "from 'a == b' to 'false'",
170 
171         "from '==' to '<='",
172         "from 'MyE::A == b' to 'false'",
173 
174         "from '==' to '<='",
175         "from '==' to '>='",
176         "from 'MyE::B == b' to 'false'",
177 
178         "from '==' to '>='",
179         "from 'MyE::C == b' to 'false'",
180 
181         "from '==' to '>='",
182         "from 'a == MyE::A' to 'false'",
183 
184         "from '==' to '<='",
185         "from '==' to '>='",
186         "from 'a == MyE::B' to 'false'",
187 
188         "from '==' to '<='",
189         "from 'a == MyE::C' to 'false'",
190     ]).shouldBeIn(r.stdout);
191 
192     testConsecutiveSparseOrder!SubStr([
193         "from 'a == MyE::C' to 'false'",
194         // test that g4 do NOT generate a <= because the left side is already min
195         "from '==' to '<='",
196         "from '==' to '>='",
197         "from 'a == MyE::A' to 'false'",
198     ]).shouldNotBeIn(r.stdout);
199 }
200 
201 @("shall produce all ROR mutations according to the enum schema for not-equal when both types are enum type and one is an enum const declaration")
202 unittest {
203     mixin(envSetup(globalTestdir));
204 
205     makeDextoolAnalyze(testEnv)
206         .addInputArg(testData ~ "ror_enum_primitive_not_equal.cpp")
207         .run;
208     auto r = makeDextool(testEnv)
209         .addArg(["test"])
210         .addArg(["--mutant", "ror"])
211         .run;
212 
213     testConsecutiveSparseOrder!SubStr([
214         "from '!=' to '<'",
215         "from '!=' to '>'",
216         "from 'a != b' to 'true'",
217 
218         "from '!=' to '<'",
219         "from 'MyE::A != b' to 'true'",
220 
221         "from '!=' to '<'",
222         "from '!=' to '>'",
223         "from 'MyE::B != b' to 'true'",
224 
225         "from '!=' to '>'",
226         "from 'a != MyE::A' to 'true'",
227 
228         "from '!=' to '<'",
229         "from '!=' to '>'",
230         "from 'a != MyE::B' to 'true'",
231 
232         "from '!=' to '<'",
233         "from 'a != MyE::C' to 'true'",
234     ]).shouldBeIn(r.stdout);
235 }
236 
237 @("shall produce all ROR mutations according to floating point schema when either type are pointers")
238 unittest {
239     mixin(envSetup(globalTestdir));
240 
241     makeDextoolAnalyze(testEnv)
242         .addInputArg(testData ~ "ror_pointer_primitive.cpp")
243         .run;
244     auto r = makeDextool(testEnv)
245         .addArg(["test"])
246         .addArg(["--mutant", "rorp"])
247         .run;
248 
249     testConsecutiveSparseOrder!SubStr([
250         "from '==' to '!='",
251         "from 'a0 == a1' to 'false'",
252 
253         "from '!=' to '=='",
254         "from 'b0 != b1' to 'true'",
255 
256         "from '==' to '!='",
257         "from 'c0 == 0' to 'false'",
258 
259         "from '!=' to '=='",
260         "from 'd0 != 0' to 'true'",
261 
262         "from '==' to '<='",
263         "from '==' to '>='",
264         "from 'e0 == e1' to 'false'",
265 
266         "from '!=' to '<'",
267         "from '!=' to '>'",
268         "from 'f0 != f1' to 'true'",
269     ]).shouldBeIn(r.stdout);
270 }
271 
272 @("shall produce all ROR mutations according to floating point schema when either type are pointers")
273 unittest {
274     mixin(envSetup(globalTestdir));
275 
276     makeDextoolAnalyze(testEnv)
277         .addInputArg(testData ~ "ror_pointer_return_value.cpp")
278         .run;
279     auto r = makeDextool(testEnv)
280         .addArg(["test"])
281         .addArg(["--mutant", "rorp"])
282         .run;
283 
284     testConsecutiveSparseOrder!SubStr([
285         "from '!=' to '=='",
286         "from 'clone_ != &Foo::initRef' to 'true'",
287 
288         "from '==' to '!='",
289         "from 'a0() == a1()' to 'false'",
290 
291         "from '!=' to '=='",
292         "from 'b0() != b1()' to 'true'",
293 
294         "from '==' to '!='",
295         "from 'c0() == 0' to 'false'",
296 
297         "from '!=' to '=='",
298         "from 'd0() != 0' to 'true'",
299     ]).shouldBeIn(r.stdout);
300 }
301 
302 @("shall produce all ROR mutations according to the bool schema when both types are bools")
303 unittest {
304     mixin(envSetup(globalTestdir));
305 
306     makeDextoolAnalyze(testEnv)
307         .addInputArg(testData ~ "ror_bool_primitive.cpp")
308         .run;
309     auto r = makeDextool(testEnv)
310         .addArg(["test"])
311         .addArg(["--mutant", "ror"])
312         .run;
313 
314     testConsecutiveSparseOrder!SubStr([
315         "from '==' to '!='",
316         "from 'a0 == a1' to 'false'",
317 
318         "from '!=' to '=='",
319         "from 'b0 != b1' to 'true'",
320     ]).shouldBeIn(r.stdout);
321 }
322 
323 @("shall produce all ROR mutations according to the bool schema when both functions return type is bool")
324 unittest {
325     mixin(envSetup(globalTestdir));
326 
327     makeDextoolAnalyze(testEnv)
328         .addInputArg(testData ~ "ror_bool_return_value.cpp")
329         .run;
330     auto r = makeDextool(testEnv)
331         .addArg(["test"])
332         .addArg(["--mutant", "ror"])
333         .run;
334 
335     testConsecutiveSparseOrder!SubStr([
336         "from '==' to '!='",
337         "from 'a0() == a1()' to 'false'",
338 
339         "from '!=' to '=='",
340         "from 'b0() != b1()' to 'true'",
341     ]).shouldBeIn(r.stdout);
342 }