1 /*
2 * Copyright 2022 Haiku Inc. All rights reserved.
3 * Distributed under the terms of the MIT License.
4 *
5 * Authors:
6 * Niels Sascha Reedijk, niels.reedijk@gmail.com
7 */
8
9 #include "ExclusiveBorrowTest.h"
10
11 #include <atomic>
12 #include <tuple>
13
14 #include <cppunit/TestCaller.h>
15 #include <cppunit/TestSuite.h>
16
17 #include <ExclusiveBorrow.h>
18
19 using BPrivate::Network::BBorrow;
20 using BPrivate::Network::BBorrowError;
21 using BPrivate::Network::BExclusiveBorrow;
22 using BPrivate::Network::make_exclusive_borrow;
23
24
25 class DeleteTestHelper
26 {
27 public:
DeleteTestHelper(std::atomic<bool> & deleted)28 DeleteTestHelper(std::atomic<bool>& deleted)
29 :
30 fDeleted(deleted)
31 {
32 }
33
~DeleteTestHelper()34 ~DeleteTestHelper() { fDeleted.store(true); }
35
36 private:
37 std::atomic<bool>& fDeleted;
38 };
39
40
41 class Base
42 {
43 public:
Base()44 Base() {}
45
46
~Base()47 virtual ~Base() {}
48
49
IsDerived()50 virtual bool IsDerived() { return false; }
51 };
52
53
54 class Derived : public Base
55 {
56 public:
Derived()57 Derived() {}
58
59
~Derived()60 virtual ~Derived() {}
61
62
IsDerived()63 virtual bool IsDerived() override { return true; }
64 };
65
66
ExclusiveBorrowTest()67 ExclusiveBorrowTest::ExclusiveBorrowTest()
68 {
69 }
70
71
72 void
ObjectDeleteTest()73 ExclusiveBorrowTest::ObjectDeleteTest()
74 {
75 // Case 1: object never gets borrowed and goes out of scope
76 std::atomic<bool> deleted = false;
77 {
78 auto object = make_exclusive_borrow<DeleteTestHelper>(deleted);
79 }
80 CPPUNIT_ASSERT_EQUAL_MESSAGE("(1) Expected object to be deleted", true, deleted.load());
81
82 // Case 2: object gets borrowed, returned and then goes out of scope
83 deleted.store(false);
84 {
85 auto object = make_exclusive_borrow<DeleteTestHelper>(deleted);
86 {
87 auto borrow = BBorrow<DeleteTestHelper>(object);
88 }
89 CPPUNIT_ASSERT_EQUAL_MESSAGE("(2) Object should not be deleted", false, deleted.load());
90 }
91 CPPUNIT_ASSERT_EQUAL_MESSAGE("(2) Expected object to be deleted", true, deleted.load());
92
93 // Case 3: object gets borrowed, forfeited and then borrow goes out of scope
94 deleted.store(false);
95 {
96 auto borrow = BBorrow<DeleteTestHelper>(nullptr);
97 {
98 auto object = make_exclusive_borrow<DeleteTestHelper>(deleted);
99 borrow = BBorrow<DeleteTestHelper>(object);
100 }
101 CPPUNIT_ASSERT_EQUAL_MESSAGE("(3) Object should not be deleted", false, deleted.load());
102 }
103 CPPUNIT_ASSERT_EQUAL_MESSAGE("(3) Expected object to be deleted", true, deleted.load());
104 }
105
106
107 void
OwnershipTest()108 ExclusiveBorrowTest::OwnershipTest()
109 {
110 auto ownedObject = make_exclusive_borrow<int>(1);
111 CPPUNIT_ASSERT(*ownedObject == 1);
112
113 auto borrow = BBorrow<int>(ownedObject);
114 try {
115 std::ignore = *ownedObject == 1;
116 CPPUNIT_FAIL("Unexpected access to the owned object while borrowed");
117 } catch (const BBorrowError& e) {
118 // expected
119 }
120
121 try {
122 std::ignore = *borrow == 1;
123 // should succeed
124 } catch (const BBorrowError& e) {
125 CPPUNIT_FAIL("Unexpected error accessing the borrowed object");
126 }
127
128 try {
129 auto borrowAgain = BBorrow<int>(ownedObject);
130 CPPUNIT_FAIL("Unexpectedly able to borrow the owned object again");
131 } catch (const BBorrowError& e) {
132 // expected
133 }
134
135 try {
136 borrow = BBorrow<int>(nullptr);
137 std::ignore = *borrow == 1;
138 CPPUNIT_FAIL("Unexpected access to an empty borrowed object");
139 } catch (const BBorrowError& e) {
140 // expected
141 }
142
143 try {
144 std::ignore = *ownedObject == 1;
145 } catch (const BBorrowError& e) {
146 CPPUNIT_FAIL("Unexpected error accessing the owned object");
147 }
148 }
149
150
151 void
PolymorphismTest()152 ExclusiveBorrowTest::PolymorphismTest()
153 {
154 auto owned = make_exclusive_borrow<Derived>();
155 {
156 auto borrowDerived = BBorrow<Derived>(owned);
157 CPPUNIT_ASSERT_EQUAL(true, borrowDerived->IsDerived());
158 }
159 {
160 auto borrowBase = BBorrow<Base>(owned);
161 CPPUNIT_ASSERT_EQUAL(true, borrowBase->IsDerived());
162 }
163 }
164
165
166 void
ReleaseTest()167 ExclusiveBorrowTest::ReleaseTest()
168 {
169 auto ownedObject = make_exclusive_borrow<int>(1);
170 auto ownedPointer = std::addressof(*ownedObject);
171 try {
172 auto borrow = BBorrow<int>(ownedObject);
173 auto invalidClaimedPointer = ownedObject.Release();
174 CPPUNIT_FAIL("Unexpectedly able to release a borrowed pointer");
175 } catch (const BBorrowError&) {
176 // expected to fail
177 }
178
179 auto validClaimedPointer = ownedObject.Release();
180 CPPUNIT_ASSERT_EQUAL_MESSAGE("Expected released pointer to point to the same object",
181 validClaimedPointer.get(), ownedPointer);
182 }
183
184
185 /* static */ void
AddTests(BTestSuite & parent)186 ExclusiveBorrowTest::AddTests(BTestSuite& parent)
187 {
188 CppUnit::TestSuite& suite = *new CppUnit::TestSuite("ExclusiveBorrowTest");
189
190 suite.addTest(new CppUnit::TestCaller<ExclusiveBorrowTest>(
191 "ExclusiveBorrowTest::ObjectDeleteTest", &ExclusiveBorrowTest::ObjectDeleteTest));
192 suite.addTest(new CppUnit::TestCaller<ExclusiveBorrowTest>(
193 "ExclusiveBorrowTest::OwnershipTest", &ExclusiveBorrowTest::OwnershipTest));
194 suite.addTest(new CppUnit::TestCaller<ExclusiveBorrowTest>(
195 "ExclusiveBorrowTest::PolymorphismTest", &ExclusiveBorrowTest::PolymorphismTest));
196 suite.addTest(new CppUnit::TestCaller<ExclusiveBorrowTest>(
197 "ExclusiveBorrowTest::ReleaseTest", &ExclusiveBorrowTest::ReleaseTest));
198
199 parent.addTest("ExclusiveBorrowTest", &suite);
200 }
201