1 /** 2 Copyright: Copyright (c) 2018, Joakim Brännström. All rights reserved. 3 License: MPL-2 4 Author: Joakim Brännströmoakim Brännström (joakim.brannstrom@gmx.com) 5 6 This Source Code Form is subject to the terms of the Mozilla Public License, 7 v.2.0. If a copy of the MPL was not distributed with this file, You can obtain 8 one at http://mozilla.org/MPL/2.0/. 9 */ 10 module dextool.plugin.mutate.backend.test_mutant.makefile_post_analyze; 11 12 import std.exception : collectException; 13 import std.range : isInputRange, isOutputRange; 14 import logger = std.experimental.logger; 15 16 import my.set; 17 18 import dextool.plugin.mutate.backend.test_mutant.test_case_analyze : GatherTestCase; 19 import dextool.plugin.mutate.backend.type : TestCase; 20 import dextool.type : AbsolutePath; 21 22 /** Parse input for the first makefile targets that fail. 23 * 24 * It is important that it is the first failing to avoid possible problems with 25 * recursive makefiles which would end with multiple makefile targets that 26 * fail. I assume that the first one is the most specific and relevant. 27 * 28 * TODO: if that isn't good enough maybe another approach would be to 29 * concatenate them to one big target? It would reflect in a "chain" of targets 30 * that lead up to the error. 31 * 32 * Params: 33 * r = range that is chunked by line 34 * report = where the results are put. 35 */ 36 struct MakefileParser { 37 import std.regex : regex, matchFirst; 38 39 private { 40 bool isDone; 41 42 // example: binary exiting with something else than zero. 43 //make: *** [exit1] Error 1 44 //make: *** [exit2] Error 2 45 //make: *** [segfault] Segmentation fault (core dumped) 46 enum re_exit_with_error_code = regex(`.*make:\s*\*\*\*\s*\[(?P<tc>.*)\].*`); 47 } 48 49 void process(T)(T line, ref GatherTestCase report) { 50 import std.range : put; 51 import std..string : strip; 52 53 if (isDone) 54 return; 55 56 auto exit_with_error_code_match = matchFirst(line, re_exit_with_error_code); 57 58 if (!exit_with_error_code_match.empty) { 59 report.reportFailed(TestCase(exit_with_error_code_match["tc"].strip.idup)); 60 isDone = true; 61 } 62 } 63 } 64 65 version (unittest) { 66 import std.algorithm : each; 67 import std.array : array; 68 import unit_threaded : shouldEqual, shouldBeIn; 69 } 70 71 @("shall report the failed test case") 72 unittest { 73 GatherTestCase app; 74 75 MakefileParser parser; 76 // dfmt off 77 foreach (a; [ 78 `./a.out segfault`, 79 `segfault`, 80 `makefile:4: recipe for target 'segfault' failed`, 81 `make: *** [segfault] Segmentation fault (core dumped)`, 82 `make: *** [exit1] Error 1`, 83 `make: *** [exit2] Error 2`, 84 ]) parser.process(a, app); 85 // dfmt on 86 87 shouldEqual(app.failed.toArray, [TestCase("segfault")]); 88 }