Line data Source code
1 : // Copyright (c) 2019-2024 Made to Order Software Corp. All Rights Reserved 2 : // 3 : // https://snapwebsites.org/project/snapdev 4 : // contact@m2osw.com 5 : // 6 : // This program is free software: you can redistribute it and/or modify 7 : // it under the terms of the GNU General Public License as published by 8 : // the Free Software Foundation, either version 3 of the License, or 9 : // (at your option) any later version. 10 : // 11 : // This program is distributed in the hope that it will be useful, 12 : // but WITHOUT ANY WARRANTY; without even the implied warranty of 13 : // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 : // GNU General Public License for more details. 15 : // 16 : // You should have received a copy of the GNU General Public License 17 : // along with this program. If not, see <https://www.gnu.org/licenses/>. 18 : 19 : /** \file 20 : * \brief Verify that the safe_object template works. 21 : * 22 : * This file implements tests for the safe_object template to make sure that 23 : * it works as expected. 24 : */ 25 : 26 : // self 27 : // 28 : #include <snapdev/safe_object.h> 29 : 30 : #include "catch_main.h" 31 : 32 : 33 : // snapdev 34 : // 35 : #include <snapdev/not_reached.h> 36 : 37 : 38 : // last include 39 : // 40 : #include <snapdev/poison.h> 41 : 42 : 43 : namespace 44 : { 45 : 46 : 47 : bool g_allocated = false; 48 : 49 59 : bool object_is_allocated() 50 : { 51 59 : return g_allocated; 52 : } 53 : 54 : class test_object 55 : { 56 : public: 57 12 : test_object() 58 : { 59 12 : g_allocated = true; 60 12 : } 61 : 62 12 : ~test_object() 63 : { 64 12 : g_allocated = false; 65 12 : } 66 : }; 67 : 68 : 69 : typedef int identifier_t; 70 : 71 : typedef std::map<identifier_t, bool> map_id_t; 72 : 73 : map_id_t g_map_ids = map_id_t(); 74 : 75 10 : identifier_t alloc_id() 76 : { 77 : for(;;) 78 : { 79 10 : identifier_t id(rand()); 80 10 : if(g_map_ids.find(id) == g_map_ids.end()) 81 : { 82 10 : g_map_ids[id] = true; 83 20 : return id; 84 : } 85 0 : } 86 : } 87 : 88 10 : void delete_id(identifier_t id) 89 : { 90 10 : auto it(g_map_ids.find(id)); 91 10 : CATCH_REQUIRE(it != g_map_ids.end()); 92 10 : g_map_ids.erase(it); 93 10 : } 94 : 95 50 : bool id_is_allocated(identifier_t id) 96 : { 97 50 : return g_map_ids.find(id) != g_map_ids.end(); 98 : } 99 : 100 : 101 : } // no name namespace 102 : 103 : 104 4 : CATCH_TEST_CASE("safe_object", "[raii]") 105 : { 106 4 : CATCH_START_SECTION("safe_object: expected usage") 107 : { 108 1 : snapdev::safe_object<test_object *> so; 109 1 : CATCH_REQUIRE_FALSE(object_is_allocated()); 110 1 : test_object * obj(new test_object); 111 1 : CATCH_REQUIRE(object_is_allocated()); 112 1 : so.make_safe(obj); 113 1 : CATCH_REQUIRE(obj != nullptr); // this is always true because if new fails, it throws bad_alloc 114 1 : CATCH_REQUIRE(object_is_allocated()); 115 1 : so.release(); 116 1 : CATCH_REQUIRE(object_is_allocated()); 117 1 : delete obj; 118 1 : CATCH_REQUIRE_FALSE(object_is_allocated()); 119 1 : } 120 4 : CATCH_END_SECTION() 121 : 122 4 : CATCH_START_SECTION("safe_object: with exception") 123 : { 124 : try 125 : { 126 1 : snapdev::safe_object<test_object *> so; 127 1 : CATCH_REQUIRE_FALSE(object_is_allocated()); 128 1 : test_object * obj(new test_object); 129 1 : CATCH_REQUIRE(object_is_allocated()); 130 1 : so.make_safe(obj); 131 1 : CATCH_REQUIRE(obj != nullptr); // this is always true because if new fails, it throws bad_alloc 132 1 : CATCH_REQUIRE(object_is_allocated()); 133 1 : throw std::range_error("test exception"); 134 : snapdev::NOT_REACHED(); 135 1 : } 136 1 : catch(std::exception const & e) 137 : { 138 1 : CATCH_REQUIRE_FALSE(object_is_allocated()); 139 1 : } 140 : } 141 4 : CATCH_END_SECTION() 142 : 143 4 : CATCH_START_SECTION("safe_object: test both ways") 144 : { 145 11 : for(int idx(0); idx < 10; ++idx) 146 : { 147 : try 148 : { 149 10 : snapdev::safe_object<test_object *> so; 150 10 : CATCH_REQUIRE_FALSE(object_is_allocated()); 151 10 : test_object * obj(new test_object); 152 10 : CATCH_REQUIRE(object_is_allocated()); 153 10 : so.make_safe(obj); 154 10 : CATCH_REQUIRE(obj != nullptr); // this is always true because if new fails, it throws bad_alloc 155 10 : CATCH_REQUIRE(object_is_allocated()); 156 10 : if((idx & 1) == 0) 157 : { 158 5 : throw std::range_error("test exception"); 159 : snapdev::NOT_REACHED(); 160 : } 161 5 : so.release(); 162 5 : CATCH_REQUIRE(object_is_allocated()); 163 5 : delete obj; 164 5 : CATCH_REQUIRE_FALSE(object_is_allocated()); 165 10 : } 166 5 : catch(std::exception const & e) 167 : { 168 : // prevent propagation 169 5 : } 170 10 : CATCH_REQUIRE_FALSE(object_is_allocated()); 171 : } 172 : } 173 4 : CATCH_END_SECTION() 174 : 175 4 : CATCH_START_SECTION("safe_object: test with resource identifiers") 176 : { 177 11 : for(int idx(0); idx < 10; ++idx) 178 : { 179 10 : identifier_t id(rand()); 180 : try 181 : { 182 10 : snapdev::safe_object<identifier_t, delete_id> so; 183 10 : CATCH_REQUIRE_FALSE(id_is_allocated(id)); 184 10 : id = alloc_id(); 185 10 : CATCH_REQUIRE(id_is_allocated(id)); 186 10 : so.make_safe(id); 187 10 : CATCH_REQUIRE(id_is_allocated(id)); 188 10 : if((idx & 1) == 0) 189 : { 190 5 : throw std::range_error("id exception"); 191 : snapdev::NOT_REACHED(); 192 : } 193 5 : so.release(); 194 5 : CATCH_REQUIRE(id_is_allocated(id)); 195 5 : delete_id(id); 196 5 : CATCH_REQUIRE_FALSE(id_is_allocated(id)); 197 10 : } 198 5 : catch(std::exception const & e) 199 : { 200 : // prevent propagation 201 5 : } 202 10 : CATCH_REQUIRE_FALSE(id_is_allocated(id)); 203 : } 204 : } 205 4 : CATCH_END_SECTION() 206 4 : } 207 : 208 : 209 : 210 : // vim: ts=4 sw=4 et 211 :