xref: /haiku/src/tests/kits/net/netservices2/ExclusiveBorrowTest.cpp (revision 71e29bbeea760848317843508c711f2a0b446fbb)
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