-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy pathaccessing_policy_tests.cpp
126 lines (107 loc) · 3.4 KB
/
accessing_policy_tests.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
#include <gtest/gtest.h>
#include "tracked/policy/accessing.hpp"
#include "tracked/tracked.hpp"
#include <thread>
using namespace policy;
class TestingClass {
public:
TestingClass() { }
~TestingClass() { }
// since tracked_ptr based on std::unique_ptr,
// we need to ensure that testing class will never copied.
TestingClass(const TestingClass&) = delete;
// but we can move object through tracked_ptr instances
TestingClass(TestingClass&&) = default;
int doubled(int val) {
return val * 2;
}
private:
};
using test_exception = std::exception;
template<template<class> class Policy, bool should_throw_on_created_thread>
struct helper_t {
using tracked_type = tracked_ptr<
TestingClass,
tracked_traits<TestingClass, dtl::default_deleter<TestingClass>, exceptions::throw_on_exception<test_exception>>,
Policy>;
explicit helper_t() : constructed_thread_id(std::this_thread::get_id()) { }
tracked_type get_tracked_ptr_from_thread()
{
tracked_type ptr;
std::thread th(&helper_t::thread_binder, this, std::ref(ptr));
th.join();
if (!ptr) {
// this should not happen!
std::terminate();
}
return ptr;
}
private:
void thread_binder(tracked_type& ptr)
{
// this should not happen!
if (constructed_thread_id == std::this_thread::get_id()) {
FAIL() << "jumping thread is a main thread.";
}
ptr = make_tracked_ptr<TestingClass, exceptions::throw_on_exception<test_exception>, Policy>();
if constexpr (should_throw_on_created_thread) {
ASSERT_THROW(ptr->doubled(1), test_exception);
}
else {
ASSERT_NO_THROW(ptr->doubled(1));
}
}
std::thread::id constructed_thread_id;
};
TEST(AccessingPolicy, AccessedFromSingleThread)
{
auto test_ptr =
make_tracked_ptr<TestingClass, exceptions::throw_on_exception<test_exception>, must_accessed_by_single_thread>();
auto test = [&test_ptr] {
std::thread th([&] {
ASSERT_THROW(test_ptr->doubled(0), test_exception); });
th.join();
};
ASSERT_NO_THROW(test_ptr->doubled(1));
test();
helper_t<must_accessed_by_single_thread, false> helper;
auto ptr = std::move(helper.get_tracked_ptr_from_thread());
ASSERT_THROW(ptr->doubled(1), test_exception);
}
TEST(AccessingPolicy, AccessedFromMainThread)
{
auto test_ptr =
make_tracked_ptr<TestingClass, exceptions::throw_on_exception<test_exception>, must_accessed_by_main_thread>();
ASSERT_NO_THROW(test_ptr->doubled(1));
auto test = [&test_ptr] {
std::thread th([&] { ASSERT_THROW(test_ptr->doubled(0), test_exception); });
th.join();
};
test();
helper_t<must_accessed_by_main_thread, true> helper;
auto ptr = std::move(helper.get_tracked_ptr_from_thread());
ASSERT_NO_THROW(ptr->doubled(1));
}
TEST(AccessingPolicy, AccessedFromMainThread_NoThrow)
{
auto test_ptr =
make_tracked_ptr<TestingClass, exceptions::default_do_nothing, must_accessed_by_main_thread>();
ASSERT_NO_THROW(test_ptr->doubled(1));
auto test = [&test_ptr] {
std::thread th([&] { ASSERT_NO_THROW(test_ptr->doubled(0)); });
th.join();
};
test();
}
TEST(AccessingPolicy, MustDestructBySameThread)
{
auto test_ptr = make_tracked_ptr<
TestingClass,
exceptions::throw_on_exception<test_exception>,
must_destruct_by_same_thread_constructed>();
ASSERT_NO_THROW(test_ptr->doubled(1));
std::thread th([&] {
ASSERT_THROW(test_ptr.reset(), test_exception);
});
th.join();
}