1 /** 2 Copyright: Copyright (c) 2018, Joakim Brännström. All rights reserved. 3 License: MPL-2 4 Author: Joakim 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 #SPC-track_ctest 11 */ 12 module dextool.plugin.mutate.backend.test_mutant.ctest_post_analyze; 13 14 import std.exception : collectException; 15 import std.range : isInputRange, isOutputRange; 16 import logger = std.experimental.logger; 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 ctest test cases. 23 * 24 * Params: 25 * r = range that is chunked by line 26 * report = where the results are put. 27 */ 28 struct CtestParser { 29 import std.regex : regex, matchFirst; 30 31 private { 32 // example: Start 35: gtest_repeat_test 33 enum re_start_tc = regex(`^\s*Start\s*\d*:\s*(?P<tc>.*)`); 34 // example: 2/3 Test #2: gmock-cardinalities_test ................***Failed 0.00 sec 35 enum re_fail_tc = regex(`.*?Test.*:\s*(?P<tc>.*?)\s*\.*\*\*\*.*`); 36 37 StateData data; 38 } 39 40 void process(T)(T line, ref GatherTestCase report) { 41 auto start_tc_match = matchFirst(line, re_start_tc); 42 auto fail_tc_match = matchFirst(line, re_fail_tc); 43 44 data.hasStartTc = !start_tc_match.empty; 45 data.hasFailTc = !fail_tc_match.empty; 46 47 if (data.hasStartTc) 48 report.reportFound(TestCase(start_tc_match["tc"].idup)); 49 50 if (data.hasFailTc) 51 report.reportFailed(TestCase(fail_tc_match["tc"].idup)); 52 } 53 } 54 55 private: 56 57 struct StateData { 58 bool hasStartTc; 59 bool hasFailTc; 60 } 61 62 version (unittest) { 63 import std.algorithm : each, sort; 64 import std.array : array; 65 import unit_threaded : shouldEqual, shouldBeIn; 66 } 67 68 @("shall report the failed test cases") 69 unittest { 70 GatherTestCase app; 71 CtestParser parser; 72 testData2.each!(a => parser.process(a, app)); 73 74 // dfmt off 75 shouldEqual(app.failedAsArray.sort, 76 [TestCase("gmock-cardinalities_test")] 77 ); 78 // dfmt on 79 } 80 81 @("shall report the found test cases") 82 unittest { 83 GatherTestCase app; 84 CtestParser parser; 85 testData1.each!(a => parser.process(a, app)); 86 87 // dfmt off 88 shouldEqual(app.foundAsArray.sort, [ 89 TestCase("gmock-actions_test"), 90 TestCase("gmock-cardinalities_test"), 91 TestCase("gmock_ex_test") 92 ]); 93 // dfmt on 94 } 95 96 version (unittest) { 97 string[] testData1() { 98 // dfmt off 99 return [ 100 "Test project /home/joker/src/cpp/googletest/build", 101 " Start 1: gmock-actions_test", 102 " 1/3 Test #1: gmock-actions_test ...................... Passed 1.61 sec", 103 " Start 2: gmock-cardinalities_test", 104 " 2/3 Test #2: gmock-cardinalities_test ................ Passed 0.00 sec", 105 " Start 3: gmock_ex_test", 106 " 3/3 Test #3: gmock_ex_test ........................... Passed 0.01 sec", 107 "", 108 "100% tests passed, 0 tests failed out of 3", 109 "", 110 "Total Test time (real) = 7.10 sec", 111 ]; 112 // dfmt on 113 } 114 115 string[] testData2() { 116 // dfmt off 117 return [ 118 "Test project /home/joker/src/cpp/googletest/build", 119 " Start 1: gmock-actions_test", 120 " 1/3 Test #1: gmock-actions_test ...................... Passed 1.61 sec", 121 " Start 2: gmock-cardinalities_test", 122 " 2/3 Test #2: gmock-cardinalities_test ................***Failed 0.00 sec", 123 " Start 3: gmock_ex_test", 124 " 3/3 Test #3: gmock_ex_test ........................... Passed 0.01 sec", 125 "", 126 "100% tests passed, 0 tests failed out of 3", 127 "", 128 "Total Test time (real) = 7.10 sec", 129 "", 130 "The following tests FAILED:", 131 " 15 - gmock-cardinalities_test (Failed)", 132 ]; 133 // dfmt on 134 } 135 }