Skip to content

Commit 23f5478

Browse files
committed
🎨 decouple funtionality from the Utility header into seperate files
1 parent b1ef962 commit 23f5478

30 files changed

+1064
-784
lines changed

CMakeLists.txt

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -63,16 +63,26 @@ else()
6363
endfunction()
6464
endif()
6565

66+
test(example/GMock)
67+
test(example/GTest)
68+
test(example/GScenario)
69+
70+
include_directories(test)
6671
test(test/GMake)
6772
test(test/GMock)
6873
test(test/GScenario)
74+
test(test/Features/Calc/Steps/CalcSteps)
75+
test(test/Features/Table/Steps/TableSteps)
76+
test(test/Features/Tags/Steps/TagsSteps)
6977
test(test/GTest)
7078
test(test/GTest-Lite)
79+
test(test/Detail/FileUtils)
7180
test(test/Detail/Preprocessor)
81+
test(test/Detail/ProgUtils)
82+
test(test/Detail/RegexUtils)
83+
test(test/Detail/StringUtils)
7284
test(test/Detail/TypeTraits)
7385
test(test/Detail/Utility)
74-
test(example/GMock)
75-
test(example/GTest)
7686

7787
include_directories(benchmark)
7888
test(benchmark/GUnit/test)

example/GScenario.cpp

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
//
2+
// Copyright (c) 2016-2017 Kris Jusiak (kris at jusiak dot net)
3+
//
4+
// Distributed under the Boost Software License, Version 1.0.
5+
// (See accompanying file LICENSE_1_0.txt or copy at
6+
// http://www.boost.org/LICENSE_1_0.txt)
7+
//
8+
#include <vector>
9+
#include <string>
10+
#include <iostream>
11+
#include "GUnit/GScenario.h"
12+
#include "GUnit/GTest.h"
13+
14+
STEPS("Example*") = [](auto steps) {
15+
std::vector<std::string> given_steps{};
16+
17+
steps.Given("I have step {name}") = [&](const std::string& step) {
18+
given_steps.emplace_back(step);
19+
};
20+
21+
steps.When("I run the scenario") = []{
22+
std::cout << "Running...\n";
23+
};
24+
25+
steps.Then("The following steps should be shown on the screen", "steps") = [&](const testing::Table& table) {
26+
ASSERT_EQ(given_steps.size(), table.size());
27+
auto i = 0;
28+
for (auto row : table) {
29+
EXPECT_EQ(row["step"], given_steps[i++]);
30+
}
31+
};
32+
33+
return steps;
34+
};

example/GScenario.feature

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
Feature: Example
2+
In order to show off GScenario
3+
As a new user
4+
I want to be told how to use it
5+
6+
Scenario: Showing off
7+
Given I have step a
8+
And I have step b
9+
When I run the scenario
10+
Then The following steps should be shown on the screen
11+
| step |
12+
| a |
13+
| b |

include/GUnit/Detail/FileUtils.h

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
//
2+
// Copyright (c) 2016-2017 Kris Jusiak (kris at jusiak dot net)
3+
//
4+
// Distributed under the Boost Software License, Version 1.0.
5+
// (See accompanying file LICENSE_1_0.txt or copy at
6+
// http://www.boost.org/LICENSE_1_0.txt)
7+
//
8+
#pragma once
9+
10+
#include <string>
11+
#include <fstream>
12+
#include <stdexcept>
13+
14+
namespace testing {
15+
inline namespace v1 {
16+
namespace detail {
17+
18+
inline auto basename(const std::string &path) { return path.substr(path.find_last_of("/\\") + 1); }
19+
20+
inline std::wstring read_file(const std::string &feature) {
21+
std::ifstream file{feature};
22+
if (!file.good()) {
23+
throw std::runtime_error("File \"" + feature + "\" not found!");
24+
}
25+
return {(std::istreambuf_iterator<char>(file)), std::istreambuf_iterator<char>()};
26+
}
27+
28+
} // detail
29+
} // v1
30+
} // testing

include/GUnit/Detail/ProgUtils.h

Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
//
2+
// Copyright (c) 2016-2017 Kris Jusiak (kris at jusiak dot net)
3+
//
4+
// Distributed under the Boost Software License, Version 1.0.
5+
// (See accompanying file LICENSE_1_0.txt or copy at
6+
// http://www.boost.org/LICENSE_1_0.txt)
7+
//
8+
#pragma once
9+
10+
#include <string>
11+
#include <memory>
12+
#include <cxxabi.h>
13+
#include <execinfo.h>
14+
#include "gtest/gtest.h"
15+
16+
#if defined(__APPLE__)
17+
#include <libproc.h>
18+
#elif defined(__linux__)
19+
extern const char *__progname_full;
20+
#endif
21+
22+
#if !defined(GUNIT_SHOW_STACK_SIZE)
23+
#define GUNIT_SHOW_STACK_SIZE 1
24+
#endif
25+
26+
namespace testing {
27+
inline namespace v1 {
28+
namespace detail {
29+
30+
inline std::string demangle(const std::string &mangled) {
31+
const auto demangled = abi::__cxa_demangle(mangled.c_str(), 0, 0, 0);
32+
if (demangled) {
33+
std::shared_ptr<char> free{demangled, std::free};
34+
return demangled;
35+
}
36+
return {};
37+
}
38+
39+
inline auto &progname() {
40+
#if defined(__linux__)
41+
static auto self = __progname_full;
42+
#elif defined(__APPLE__)
43+
static char self[PROC_PIDPATHINFO_MAXSIZE] = {};
44+
proc_pidpath(getpid(), self, sizeof(self));
45+
#endif
46+
return self;
47+
}
48+
49+
inline std::string call_stack(const std::string &newline, int stack_begin = 1, int stack_size = GUNIT_SHOW_STACK_SIZE) {
50+
static constexpr auto MAX_CALL_STACK_SIZE = 64;
51+
void *bt[MAX_CALL_STACK_SIZE];
52+
const auto frames = backtrace(bt, sizeof(bt) / sizeof(bt[0]));
53+
const auto symbols = backtrace_symbols(bt, frames);
54+
std::shared_ptr<char *> free{symbols, std::free};
55+
std::stringstream result;
56+
stack_size += stack_begin;
57+
58+
for (auto i = stack_begin; i < (frames > stack_size ? stack_size : frames); ++i) {
59+
const auto symbol = std::string{symbols[i]};
60+
const auto name_begin = symbol.find("(");
61+
const auto name_end = symbol.find("+");
62+
const auto address_begin = symbol.find("[");
63+
const auto address_end = symbol.find("]");
64+
65+
if (i > stack_begin) {
66+
result << newline;
67+
}
68+
if (name_begin != std::string::npos && name_end != std::string::npos && address_begin != std::string::npos &&
69+
address_end != std::string::npos) {
70+
result << demangle(symbol.substr(name_begin + 1, name_end - name_begin - 1)) << " "
71+
<< symbol.substr(address_begin, address_end - address_begin + 1);
72+
} else {
73+
result << symbol;
74+
}
75+
}
76+
return result.str();
77+
}
78+
79+
inline std::pair<std::string, int> addr2line(void *addr) {
80+
std::stringstream cmd;
81+
cmd << "addr2line -Cpe " << progname() << " " << addr;
82+
83+
std::string data;
84+
auto fp = popen(cmd.str().c_str(), "r");
85+
if (fp) {
86+
char buf[64] = {};
87+
while (fgets(buf, sizeof(buf), fp)) {
88+
data += buf;
89+
}
90+
} else {
91+
return {"", 0};
92+
}
93+
pclose(fp);
94+
95+
data.erase(std::remove(data.begin(), data.end(), '\n'), data.end());
96+
const auto space = data.find(" ");
97+
std::string res2 = data.substr(0, space);
98+
const auto colon = res2.find(":");
99+
return {res2.substr(0, colon), std::atoi(res2.substr(colon + 1).c_str())};
100+
}
101+
102+
} // detail
103+
} // v1
104+
} // testing

include/GUnit/Detail/RegexUtils.h

Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
1+
//
2+
// Copyright (c) 2016-2017 Kris Jusiak (kris at jusiak dot net)
3+
//
4+
// Distributed under the Boost Software License, Version 1.0.
5+
// (See accompanying file LICENSE_1_0.txt or copy at
6+
// http://www.boost.org/LICENSE_1_0.txt)
7+
//
8+
#pragma once
9+
10+
#include <string>
11+
#include <vector>
12+
13+
#include "GUnit/Detail/StringUtils.h"
14+
15+
namespace testing {
16+
inline namespace v1 {
17+
namespace detail {
18+
19+
template <class T>
20+
inline constexpr auto args_size(T str) {
21+
auto args = 0;
22+
for (auto i = 0u; i < str.size(); ++i) {
23+
if (str[i] == '{') {
24+
++args;
25+
}
26+
}
27+
return args;
28+
}
29+
30+
template <class T>
31+
inline auto matches(T pattern, const std::string &str) {
32+
std::vector<std::string> matches{};
33+
auto pi = 0u, si = 0u;
34+
35+
const auto matcher = [&](char b, char e) {
36+
const auto match = si;
37+
while (str[si] && str[si] != b) ++si;
38+
matches.emplace_back(str.substr(match, si - match));
39+
while (pattern[pi] && pattern[pi] != e) ++pi;
40+
pi++;
41+
};
42+
43+
while (pi < pattern.size() && si < str.size()) {
44+
if (pattern[pi] == '\'' && str[si] == '\'' && pattern[pi + 1] == '{') {
45+
++si;
46+
matcher('\'', '}');
47+
} else if (pattern[pi] == '{') {
48+
matcher(' ', '}');
49+
} else if (pattern[pi] != str[si]) {
50+
return std::vector<std::string>{};
51+
}
52+
++pi, ++si;
53+
}
54+
55+
return matches;
56+
}
57+
58+
template <class T>
59+
inline auto match(T pattern, const std::string &str) {
60+
return not matches(pattern, str).empty() || std::string{pattern.c_str()} == str;
61+
}
62+
63+
inline bool PatternMatchesString(const char* pattern, const char* str) {
64+
switch (*pattern) {
65+
case '\0':
66+
case ':': // Either ':' or '\0' marks the end of the pattern.
67+
return *str == '\0';
68+
case '?': // Matches any single character.
69+
return *str != '\0' && PatternMatchesString(pattern + 1, str + 1);
70+
case '*': // Matches any string (possibly empty) of characters.
71+
return (*str != '\0' && PatternMatchesString(pattern, str + 1)) || PatternMatchesString(pattern + 1, str);
72+
default: // Non-special character. Matches itself.
73+
return *pattern == *str && PatternMatchesString(pattern + 1, str + 1);
74+
}
75+
}
76+
77+
inline bool MatchesFilter(const std::string& name, const char* filter) {
78+
const char* cur_pattern = filter;
79+
for (;;) {
80+
if (PatternMatchesString(cur_pattern, name.c_str())) {
81+
return true;
82+
}
83+
84+
// Finds the next pattern in the filter.
85+
cur_pattern = strchr(cur_pattern, ':');
86+
87+
// Returns if no more pattern can be found.
88+
if (cur_pattern == nullptr) {
89+
return false;
90+
}
91+
92+
// Skips the pattern separater (the ':' character).
93+
cur_pattern++;
94+
}
95+
}
96+
97+
inline bool FilterMatchesShould(const std::string& name, const std::string& should) {
98+
// Split --gtest_filter at '-', if there is one, to separate into
99+
// positive filter and negative filter portions
100+
const char* const p = should.c_str();
101+
const char* const dash = strchr(p, '-');
102+
std::string positive;
103+
std::string negative;
104+
if (dash == nullptr) {
105+
positive = should.c_str(); // Whole string is a positive filter
106+
negative = "";
107+
} else {
108+
positive = std::string(p, dash); // Everything up to the dash
109+
negative = std::string(dash + 1); // Everything after the dash
110+
if (positive.empty()) {
111+
// Treat '-test1' as the same as '*-test1'
112+
positive = "*";
113+
}
114+
}
115+
116+
return MatchesFilter(name, positive.c_str()) && !MatchesFilter(name, negative.c_str());
117+
}
118+
119+
} // detail
120+
121+
#if defined(__clang__)
122+
#pragma clang diagnostic ignored "-Wgnu-string-literal-operator-template"
123+
#endif
124+
125+
template <class T, T... Chrs>
126+
constexpr auto operator""_step() {
127+
return detail::string<Chrs...>{};
128+
}
129+
130+
} // v1
131+
} // testing

0 commit comments

Comments
 (0)