Skip to content

Commit 7390e02

Browse files
Ulmo-Fkris-jusiak
authored andcommitted
Add doc/GTest-friend.md
1 parent be0934f commit 7390e02

File tree

1 file changed

+57
-0
lines changed

1 file changed

+57
-0
lines changed

docs/GTest-friend.md

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
There already are many good resources which explains why you shouldn't test private parts of your implementation and how to avoid it.
2+
3+
If you want to make make your classes friend with their test, here are some ways to achieve it:
4+
5+
* <font size="1">Add `#define private public` & `#define protected public` before including production headers to your test sources. But I never said this.</font>
6+
7+
* You can declare your test with an existing class instead of a string :
8+
`GTEST(SomeClass) { ... }`
9+
With this syntax, the test will inherit from `SomeClass`, so you can access to protected members.
10+
11+
This is the least intrusive way, as there is nothing added to the tested class - apart from maybe replace private by protected.
12+
13+
* You can declare your class `friend` with the test class `GTEST(SomeClass)` :
14+
```// Forward declare some GUnit classes
15+
template <typename ...> struct GTEST;
16+
namespace testing::detail { template <char ...> struct string; }
17+
18+
class SomeClass {
19+
friend struct GTEST<SomeClass, testing::detail::string<> >;
20+
};
21+
22+
GTEST(Game) { ... }
23+
```
24+
* You can also declare friend with the test class `GTEST("SomeTest")`, it is more cumbersome :
25+
```// Forward declare some GUnit classes
26+
template <typename ...> struct GTEST;
27+
namespace testing::detail { template <char ...> struct string; }
28+
29+
class SomeClass {
30+
friend struct GTEST<testing::detail::string<'\"', 'S', 'o', 'm', 'e', 'T', ,'e', 's', 't', '\"', '\000'>, testing::detail::string<> >;
31+
};
32+
33+
GTEST("SomeTest") { ... }
34+
```
35+
36+
* You can even declare friendness with `GTEST("SomeTest")` by importing some GUnit magic - but we're polluting our production code:
37+
```
38+
#ifndef __GUNIT_CAT
39+
#define __GUNIT_PRIMITIVE_CAT(arg, ...) arg##__VA_ARGS__
40+
#define __GUNIT_CAT(arg, ...) __GUNIT_PRIMITIVE_CAT(arg, __VA_ARGS__)
41+
#endif
42+
namespace {
43+
template <char ...> struct string {};
44+
template <class TStr, std::size_t N, char... Chrs> struct make_string : make_string<TStr, N - 1, TStr().chrs[N - 1], Chrs...> {};
45+
template <class TStr, char... Chrs> struct make_string<TStr, 0, Chrs...> { using type = string<Chrs...>; };
46+
}
47+
48+
#define FRIEND_GTEST(name) \
49+
struct __GUNIT_CAT(GTEST_STRING_, __LINE__) { static constexpr const char* chrs = #name; }; \
50+
friend struct GTEST<decltype(::make_string<__GUNIT_CAT(GTEST_STRING_, __LINE__), sizeof(#name)>::type()), ::string<>>;
51+
52+
class SomeClass {
53+
FRIEND_GTEST("SomeTest")
54+
};
55+
56+
GTEST("SomeTest") { ... }
57+
```

0 commit comments

Comments
 (0)