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