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