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 dextool.plugin.mutate.backend.test_mutant.interface_ : TestCaseReport, 17 GatherTestCase; 18 import dextool.plugin.mutate.backend.type : TestCase; 19 import dextool.type : AbsolutePath; 20 21 /** Parse input for the first makefile targets that fail. 22 * 23 * It is important that it is the first failing to avoid possible problems with 24 * recursive makefiles which would end with multiple makefile targets that 25 * fail. I assume that the first one is the most specific and relevant. 26 * 27 * TODO: if that isn't good enough maybe another approach would be to 28 * concatenate them to one big target? It would reflect in a "chain" of targets 29 * that lead up to the error. 30 * 31 * Params: 32 * r = range that is chunked by line 33 * report = where the results are put. 34 */ 35 struct MakefileParser { 36 import std.regex : regex, ctRegex, matchFirst; 37 38 private { 39 bool isDone; 40 41 // example: binary exiting with something else than zero. 42 //make: *** [exit1] Error 1 43 //make: *** [exit2] Error 2 44 //make: *** [segfault] Segmentation fault (core dumped) 45 enum re_exit_with_error_code = ctRegex!(`.*make:\s*\*\*\*\s*\[(?P<tc>.*)\].*`); 46 } 47 48 void process(T)(T line, TestCaseReport report) { 49 import std.range : put; 50 import std.string : strip; 51 52 if (isDone) 53 return; 54 55 auto exit_with_error_code_match = matchFirst(line, re_exit_with_error_code); 56 57 if (!exit_with_error_code_match.empty) { 58 report.reportFailed(TestCase(exit_with_error_code_match["tc"].strip.idup)); 59 isDone = true; 60 } 61 } 62 } 63 64 version (unittest) { 65 import std.algorithm : each; 66 import std.array : array; 67 import unit_threaded : shouldEqual, shouldBeIn; 68 } 69 70 @("shall report the failed test case") 71 unittest { 72 auto app = new GatherTestCase; 73 74 MakefileParser parser; 75 // dfmt off 76 foreach (a; [ 77 `./a.out segfault`, 78 `segfault`, 79 `makefile:4: recipe for target 'segfault' failed`, 80 `make: *** [segfault] Segmentation fault (core dumped)`, 81 `make: *** [exit1] Error 1`, 82 `make: *** [exit2] Error 2`, 83 ]) parser.process(a, app); 84 // dfmt on 85 86 shouldEqual(app.failed.byKey.array, [TestCase("segfault")]); 87 }