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, 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 : ctRegex, matchFirst; 30 31 private { 32 // example: Start 35: gtest_repeat_test 33 enum re_start_tc = ctRegex!(`^\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 = ctRegex!(`.*?Test.*:\s*(?P<tc>.*?)\s*\.*\*\*\*.*`); 36 37 StateData data; 38 } 39 40 void process(T)(T line, TestCaseReport 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 dextool.type : FileName; 66 import unit_threaded : shouldEqual, shouldBeIn; 67 } 68 69 @("shall report the failed test cases") 70 unittest { 71 auto app = new GatherTestCase; 72 CtestParser parser; 73 testData2.each!(a => parser.process(a, app)); 74 75 // dfmt off 76 shouldEqual(app.failedAsArray.sort, 77 [TestCase("gmock-cardinalities_test")] 78 ); 79 // dfmt on 80 } 81 82 @("shall report the found test cases") 83 unittest { 84 auto app = new GatherTestCase; 85 CtestParser parser; 86 testData1.each!(a => parser.process(a, app)); 87 88 // dfmt off 89 shouldEqual(app.foundAsArray.sort, [ 90 TestCase("gmock-actions_test"), 91 TestCase("gmock-cardinalities_test"), 92 TestCase("gmock_ex_test") 93 ]); 94 // dfmt on 95 } 96 97 version (unittest) { 98 string[] testData1() { 99 // dfmt off 100 return [ 101 "Test project /home/joker/src/cpp/googletest/build", 102 " Start 1: gmock-actions_test", 103 " 1/3 Test #1: gmock-actions_test ...................... Passed 1.61 sec", 104 " Start 2: gmock-cardinalities_test", 105 " 2/3 Test #2: gmock-cardinalities_test ................ Passed 0.00 sec", 106 " Start 3: gmock_ex_test", 107 " 3/3 Test #3: gmock_ex_test ........................... Passed 0.01 sec", 108 "", 109 "100% tests passed, 0 tests failed out of 3", 110 "", 111 "Total Test time (real) = 7.10 sec", 112 ]; 113 // dfmt on 114 } 115 116 string[] testData2() { 117 // dfmt off 118 return [ 119 "Test project /home/joker/src/cpp/googletest/build", 120 " Start 1: gmock-actions_test", 121 " 1/3 Test #1: gmock-actions_test ...................... Passed 1.61 sec", 122 " Start 2: gmock-cardinalities_test", 123 " 2/3 Test #2: gmock-cardinalities_test ................***Failed 0.00 sec", 124 " Start 3: gmock_ex_test", 125 " 3/3 Test #3: gmock_ex_test ........................... Passed 0.01 sec", 126 "", 127 "100% tests passed, 0 tests failed out of 3", 128 "", 129 "Total Test time (real) = 7.10 sec", 130 "", 131 "The following tests FAILED:", 132 " 15 - gmock-cardinalities_test (Failed)", 133 ]; 134 // dfmt on 135 } 136 }