xref: /haiku/src/tests/kits/net/netservices2/ExclusiveBorrowTest.cpp (revision bb83316a5811a550c4f850d07fa8e328e7ac0a94)
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:
28  	DeleteTestHelper(std::atomic<bool>& deleted)
29  		:
30  		fDeleted(deleted)
31  	{
32  	}
33  
34  	~DeleteTestHelper() { fDeleted.store(true); }
35  
36  private:
37  	std::atomic<bool>& fDeleted;
38  };
39  
40  
41  class Base
42  {
43  public:
44  	Base() {}
45  
46  
47  	virtual ~Base() {}
48  
49  
50  	virtual bool IsDerived() { return false; }
51  };
52  
53  
54  class Derived : public Base
55  {
56  public:
57  	Derived() {}
58  
59  
60  	virtual ~Derived() {}
61  
62  
63  	virtual bool IsDerived() override { return true; }
64  };
65  
66  
67  ExclusiveBorrowTest::ExclusiveBorrowTest()
68  {
69  }
70  
71  
72  void
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
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
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
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
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