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