|
6 | 6 | // *********************************************************************************************** |
7 | 7 | #include <gtest/gtest.h> |
8 | 8 | #include <map> |
9 | | -#include <type_traits> |
10 | 9 | #include <typeindex> |
11 | 10 | #include <unordered_map> |
12 | 11 |
|
@@ -39,11 +38,11 @@ TEST(SafePtrTest, GOLD_safeCreate_normal) |
39 | 38 | TEST(SafePtrTest, GOLD_unsafeCreate_forbid) |
40 | 39 | { |
41 | 40 | // SafePtr<int> ptr(raw); // compile-err |
42 | | - static_assert(!std::is_constructible<SafePtr<int>, int*>::value, |
| 41 | + static_assert(!is_constructible<SafePtr<int>, int*>::value, |
43 | 42 | "REQ: forbid unsafe raw pointer construction"); |
44 | 43 |
|
45 | 44 | // SafePtr<int> ptr(make_shared<int>()); // compile-err |
46 | | - static_assert(!std::is_constructible<SafePtr<int>, std::shared_ptr<int>>::value, |
| 45 | + static_assert(!is_constructible<SafePtr<int>, shared_ptr<int>>::value, |
47 | 46 | "REQ: forbid unsafe shared_ptr construction"); |
48 | 47 | } |
49 | 48 | TEST(SafePtrTest, safeCreate_default) |
@@ -169,32 +168,88 @@ TEST(SafePtrTest, GOLD_safeCp_toSameType) |
169 | 168 | } |
170 | 169 | TEST(SafePtrTest, GOLD_safeCp_toVoid) |
171 | 170 | { |
172 | | - auto b = make_safe<Base>(); |
173 | | - SafePtr<void> bv(b); |
174 | | - EXPECT_EQ(0, safe_cast<Base>(bv)->value()) << "REQ: simple cp"; |
175 | | - EXPECT_EQ(2, bv.use_count()) << "REQ: shared ownership"; |
176 | | - |
177 | | - SafePtr<const void> cv(b); |
178 | | - EXPECT_EQ(0, safe_cast<const Base>(cv)->value()) << "REQ: safe cp any->const void->const any"; |
| 171 | + auto db = SafePtr<Base>(make_safe<Derive>()); |
| 172 | + SafePtr<void> dbv(db); |
| 173 | + // check target |
| 174 | + EXPECT_EQ(1, safe_cast<Base>(dbv)->value ()) << "req: cp Derive->Base->void"; |
| 175 | + EXPECT_EQ(type_index(typeid(Derive)), dbv.realType()) << "REQ: cp to target"; |
| 176 | + EXPECT_EQ(type_index(typeid(Base )), dbv.lastType()) << "REQ: cp to target"; |
| 177 | + // check src |
| 178 | + EXPECT_EQ(2, db.use_count()) << "REQ: cp is shared"; |
| 179 | + EXPECT_EQ(1, safe_cast<Base>(db)->value ()) << "REQ: keep src after cp"; |
| 180 | + EXPECT_EQ(type_index(typeid(Derive)), db.realType ()) << "REQ: keep src after cp"; |
| 181 | + EXPECT_EQ(type_index(typeid(Base )), db.lastType ()) << "REQ: keep src after cp"; |
| 182 | + |
| 183 | + auto dbd = safe_cast<Derive>(db); |
| 184 | + SafePtr<void> dbdv(dbd); |
| 185 | + // check target |
| 186 | + EXPECT_EQ(1, safe_cast<Base>(dbdv)->value ()) << "req: cp Derive->Base->Derive->void"; |
| 187 | + EXPECT_EQ(type_index(typeid(Derive)), dbdv.realType()) << "REQ: cp to target"; |
| 188 | + EXPECT_EQ(type_index(typeid(Base )), dbdv.lastType()) << "REQ: cp to target"; |
| 189 | + // check src |
| 190 | + EXPECT_EQ(4, dbd.use_count()) << "REQ: cp is shared"; |
| 191 | + EXPECT_EQ(1, safe_cast<Base>(dbd)->value ()) << "REQ: keep src after cp"; |
| 192 | + EXPECT_EQ(type_index(typeid(Derive)), dbd.realType ()) << "REQ: keep src after cp"; |
| 193 | + EXPECT_EQ(type_index(typeid(Base )), dbd.lastType ()) << "REQ: keep src after cp"; |
179 | 194 | } |
180 | 195 | TEST(SafePtrTest, GOLD_safeCp_toPolyBase) |
181 | 196 | { |
182 | 197 | auto d = make_safe<Derive>(); |
183 | | - EXPECT_EQ(1, SafePtr< Base>(d)->value()) << "REQ: cp to Base"; |
184 | | - EXPECT_EQ(1, SafePtr<const Base>(d)->value()) << "REQ: cp to const Base"; |
| 198 | + SafePtr<Base> db(d); |
| 199 | + // check target |
| 200 | + EXPECT_EQ(1, db->value ()) << "REQ: cp to Base"; |
| 201 | + EXPECT_EQ(type_index(typeid(Derive)), db.realType()) << "REQ: cp to Base"; |
| 202 | + EXPECT_EQ(type_index(typeid(Base )), db.lastType()) << "REQ: keep diff"; |
| 203 | + // check src |
| 204 | + EXPECT_EQ(2, d.use_count()) << "REQ: cp is shared"; |
| 205 | + EXPECT_EQ(1, d->value ()) << "REQ: keep src after cp"; |
| 206 | + EXPECT_EQ(type_index(typeid(Derive)), d.realType ()) << "REQ: keep src after cp"; |
| 207 | + EXPECT_EQ(type_index(typeid(Derive)), d.lastType ()) << "REQ: keep src after cp"; |
| 208 | + |
| 209 | + SafePtr<const Base> dbc(d); |
| 210 | + // check target |
| 211 | + EXPECT_EQ(1, dbc->value ()) << "REQ: cp to const Base"; |
| 212 | + EXPECT_EQ(type_index(typeid(Derive)), dbc.realType()) << "REQ: cp to const Base"; |
| 213 | + EXPECT_EQ(type_index(typeid(const Base)), dbc.lastType()) << "REQ: keep diff"; |
| 214 | + // check src |
| 215 | + EXPECT_EQ(3, d.use_count()) << "REQ: cp is shared"; |
| 216 | + EXPECT_EQ(1, d->value ()) << "REQ: keep src after cp"; |
| 217 | + EXPECT_EQ(type_index(typeid(Derive)), d.realType ()) << "req: keep src after cp"; |
| 218 | + EXPECT_EQ(type_index(typeid(Derive)), d.lastType ()) << "req: keep src after cp"; |
185 | 219 | } |
186 | 220 | struct BS { int i = 10; }; |
187 | | -struct DS : public BS { DS() { i = 11; } }; |
| 221 | +struct DS : public BS { DS() { i = 20; } }; |
188 | 222 | TEST(SafePtrTest, safeCp_toStaticBase) |
189 | 223 | { |
190 | 224 | auto d = make_safe<DS>(); |
191 | | - EXPECT_EQ(11, SafePtr< BS>(d)->i) << "REQ: cp to static Base"; |
192 | | - EXPECT_EQ(11, SafePtr<const BS>(d)->i) << "REQ: cp to const static Base"; |
| 225 | + SafePtr<BS> db(d); |
| 226 | + // check target |
| 227 | + EXPECT_EQ(20, db->i ) << "REQ: cp to static Base"; |
| 228 | + EXPECT_EQ(type_index(typeid(DS)), db.realType()) << "REQ: cp to static Base"; |
| 229 | + EXPECT_EQ(type_index(typeid(BS)), db.lastType()) << "REQ: diff"; |
| 230 | + // check src |
| 231 | + EXPECT_EQ(2, d.use_count()) << "REQ: cp is shared"; |
| 232 | + EXPECT_EQ(20, d->i ) << "REQ: access same member"; |
| 233 | + EXPECT_EQ(type_index(typeid(DS)), d.realType ()) << "req: keep src after cp"; |
| 234 | + EXPECT_EQ(type_index(typeid(DS)), d.lastType ()) << "req: keep src after cp"; |
| 235 | + SafePtr<const BS> dbc(db); |
| 236 | + EXPECT_EQ(20, dbc->i ) << "REQ: cp to const static Base"; |
| 237 | + EXPECT_EQ(3, dbc.use_count()) << "REQ: share"; |
| 238 | +} |
| 239 | +TEST(SafePtrTest, safeCp_nullptr) |
| 240 | +{ |
| 241 | + auto d = SafePtr<Derive>(); |
| 242 | + SafePtr<void> dv(d); |
| 243 | + EXPECT_EQ(nullptr, dv.get()); |
| 244 | + EXPECT_EQ(type_index(typeid(void)), dv.realType()) << "REQ: cp nullptr as if cp fail, avoid confuse usr"; |
| 245 | + EXPECT_EQ(type_index(typeid(void)), dv.lastType()) << "REQ: cp nullptr as if cp fail, avoid confuse usr"; |
| 246 | + EXPECT_EQ(0, dv.use_count()) << "REQ: none"; |
| 247 | + EXPECT_EQ(0, d .use_count()) << "REQ: none"; |
193 | 248 | } |
194 | 249 | TEST(SafePtrTest, unsafeCp_toDiffType) |
195 | 250 | { |
196 | 251 | auto i = make_safe<int>(7); |
197 | | - //SafePtr<char>(i); // REQ: compile err for diff types |
| 252 | + //auto c = SafePtr<char>(i); // REQ: compile err for diff types |
198 | 253 | } |
199 | 254 | struct D_private : private Base {}; |
200 | 255 | struct D_protected : protected Base {}; |
@@ -223,44 +278,125 @@ TEST(SafePtrTest, unssafeCp_constToNon) |
223 | 278 | auto bc = make_safe<const Base>(); |
224 | 279 | //auto b = SafePtr<Base>(bc); // REQ: unsafe cp, compile err |
225 | 280 | } |
226 | | -TEST(SafePtrTest, invalidCp_compileErr) // cp's compile-err is safer than safe_cast that may ret nullptr |
227 | | -{ |
228 | | - //auto dv = SafePtr<void>(d); |
229 | | - //SafePtr<Derive>(dv); // bld err; safe but unsupport |
230 | | - |
231 | | - //SafePtr<Derive>(SafePtr<void>(make_safe<Derive>())); // void->origin: cp compile err, can safe_cast instead |
232 | | - //SafePtr<Base >(SafePtr<void>(make_safe<Derive>())); // Derive->void->Base: cp compile err, safe_cast ret nullptr |
233 | | - |
234 | | -// SafePtr<D> safe_dd = safe_const_d; // REQ: compile err to cp from const to non |
235 | | -// shared_ptr<D> share_dd = share_const_d; // REQ: compile err to cp from const to non |
236 | | -} |
237 | 281 |
|
238 | 282 | #define MOVE |
239 | 283 | // *********************************************************************************************** |
240 | | -TEST(SafePtrTest, GOLD_mtQ_req_mv) |
| 284 | +TEST(SafePtrTest, GOLD_safeMv_toSameType) |
241 | 285 | { |
242 | | - auto msg = SafePtr<Base>(make_safe<Derive>()); // Derive->Base |
243 | | - SafePtr<void> msgInQ = move(msg); |
244 | | - EXPECT_EQ(nullptr, msg.get()) << "REQ: src giveup"; |
245 | | - EXPECT_EQ(type_index(typeid(Base)), msg.realType()) << "REQ: reset src all"; |
246 | | - EXPECT_EQ(type_index(typeid(Base)), msg.lastType()) << "REQ: reset src all"; |
| 286 | + auto i = make_safe<int>(42); |
| 287 | + SafePtr<int> i2(move(i)); |
| 288 | + EXPECT_EQ(42, *i2.get()) << "REQ: mv to self"; |
| 289 | + EXPECT_EQ(1, i2.use_count()) << "REQ: mv ownership"; |
| 290 | + EXPECT_EQ(nullptr, i.get()) << "REQ: source is empty after move"; |
247 | 291 |
|
248 | | - EXPECT_EQ(1 , safe_cast<Base>(msgInQ)->value() ) << "REQ: takeover msg"; |
249 | | - EXPECT_EQ(type_index(typeid(Derive)), safe_cast<Base>(msgInQ).realType()) << "REQ: reset src all"; |
250 | | - EXPECT_EQ(type_index(typeid(Base )), safe_cast<Base>(msgInQ).lastType()) << "REQ: reset src all"; |
| 292 | + auto a = make_safe<A>(); |
| 293 | + SafePtr<const A> ac(move(a)); |
| 294 | + EXPECT_EQ(0, ac->value()) << "REQ: mv to const"; |
| 295 | + EXPECT_EQ(nullptr, a.get()) << "REQ: source is empty after mv"; |
251 | 296 | } |
252 | | -TEST(SafePtrTest, nothing_cp_mv_assign) |
| 297 | +TEST(SafePtrTest, GOLD_safeMv_toVoid) |
253 | 298 | { |
254 | | - SafePtr<Base> cp = SafePtr<Derive>(); // cp nullptr |
255 | | - EXPECT_EQ(type_index(typeid(Base)), cp.realType()) << "REQ/cov: cp-nothing=fail so origin is Base instead of Derive"; |
256 | | - |
257 | | - SafePtr<Base> mv = move(SafePtr<Derive>()); // mv nullptr |
258 | | - EXPECT_EQ(type_index(typeid(Base)), mv.realType()) << "REQ/cov: mv-nothing=fail so origin is Base instead of Derive"; |
| 299 | + auto db = SafePtr<Base>(make_safe<Derive>()); |
| 300 | + SafePtr<void> dbv(move(db)); |
| 301 | + // check target |
| 302 | + EXPECT_EQ(1, safe_cast<Base>(dbv)->value ()) << "req: mv Derive->Base->void"; |
| 303 | + EXPECT_EQ(type_index(typeid(Derive)), dbv.realType()) << "REQ: mv to target"; |
| 304 | + EXPECT_EQ(type_index(typeid(Base )), dbv.lastType()) << "REQ: mv to target"; |
| 305 | + // check src |
| 306 | + EXPECT_EQ(nullptr, db.get ()) << "REQ: reset src after mv"; |
| 307 | + EXPECT_EQ(type_index(typeid(Base)), db.realType()) << "REQ: reset src after mv"; |
| 308 | + EXPECT_EQ(type_index(typeid(Base)), db.lastType()) << "REQ: reset src after mv"; |
| 309 | + |
| 310 | + auto dbd = safe_cast<Derive>(SafePtr<Base>(make_safe<Derive>())); |
| 311 | + SafePtr<void> dbdv(move(dbd)); |
| 312 | + // check target |
| 313 | + EXPECT_EQ(1, safe_cast<Base>(dbdv)->value ()) << "req: mv Derive->Base->Derive->void"; |
| 314 | + EXPECT_EQ(type_index(typeid(Derive)), dbdv.realType()) << "REQ: mv to target"; |
| 315 | + EXPECT_EQ(type_index(typeid(Base )), dbdv.lastType()) << "REQ: mv to target"; |
| 316 | + // check src |
| 317 | + EXPECT_EQ(nullptr, dbd.get ()) << "REQ: reset src after mv"; |
| 318 | + EXPECT_EQ(type_index(typeid(Derive)), dbd.realType()) << "REQ: reset src after mv"; |
| 319 | + EXPECT_EQ(type_index(typeid(Derive)), dbd.lastType()) << "REQ: reset src after mv"; |
| 320 | +} |
| 321 | +TEST(SafePtrTest, GOLD_safeMv_toPolyBase) |
| 322 | +{ |
| 323 | + auto d = make_safe<Derive>(); |
| 324 | + SafePtr<Base> db(move(d)); |
| 325 | + // check target |
| 326 | + EXPECT_EQ(1, SafePtr<Base>(db)->value ()) << "REQ: mv to Base"; |
| 327 | + EXPECT_EQ(type_index(typeid(Derive)), db.realType()) << "REQ: mv to Base"; |
| 328 | + EXPECT_EQ(type_index(typeid(Base )), db.lastType()) << "REQ: keep diff"; |
| 329 | + // check src |
| 330 | + EXPECT_EQ(nullptr, d.get ()) << "REQ: reset src after mv"; |
| 331 | + EXPECT_EQ(type_index(typeid(Derive)), d.realType()) << "REQ: reset src after mv"; |
| 332 | + EXPECT_EQ(type_index(typeid(Derive)), d.lastType()) << "REQ: reset src after mv"; |
| 333 | + |
| 334 | + SafePtr<const Base> dbc(move(db)); |
| 335 | + // check target |
| 336 | + EXPECT_EQ(1, dbc->value ()) << "REQ: mv to const Base"; |
| 337 | + EXPECT_EQ(type_index(typeid(Derive )), dbc.realType()) << "REQ: mv to const Base"; |
| 338 | + EXPECT_EQ(type_index(typeid(const Base)), dbc.lastType()) << "REQ: keep diff"; |
| 339 | + // check src |
| 340 | + EXPECT_EQ(nullptr, db.get ()) << "req: reset src after mv"; |
| 341 | + EXPECT_EQ(type_index(typeid(Base)), db.realType()) << "REQ: reset src after mv"; |
| 342 | + EXPECT_EQ(type_index(typeid(Base)), db.lastType()) << "REQ: reset src after mv"; |
| 343 | +} |
| 344 | +TEST(SafePtrTest, safeMv_toStaticBase) |
| 345 | +{ |
| 346 | + auto d = make_safe<DS>(); |
| 347 | + SafePtr<BS> db(move(d)); |
| 348 | + // check target |
| 349 | + EXPECT_EQ(20, db->i ) << "REQ: mv to static Base"; |
| 350 | + EXPECT_EQ(type_index(typeid(DS)), db.realType()) << "REQ: mv to static Base"; |
| 351 | + EXPECT_EQ(type_index(typeid(BS)), db.lastType()) << "REQ: diff"; |
| 352 | + // check src |
| 353 | + EXPECT_EQ(nullptr, d.get ()) << "REQ: reset src after mv"; |
| 354 | + EXPECT_EQ(type_index(typeid(DS)), d.realType()) << "req: reset src after mv"; |
| 355 | + EXPECT_EQ(type_index(typeid(DS)), d.lastType()) << "req: reset src after mv"; |
| 356 | + |
| 357 | + SafePtr<const BS> dbc(move(db)); |
| 358 | + EXPECT_EQ(20, dbc->i ) << "REQ: mv to const static Base"; |
| 359 | + EXPECT_EQ(1, dbc.use_count()) << "REQ: mv ownership"; |
| 360 | +} |
| 361 | +TEST(SafePtrTest, safeMv_nullptr) |
| 362 | +{ |
| 363 | + auto d = SafePtr<Derive>(); |
| 364 | + SafePtr<void> dv(move(d)); |
| 365 | + EXPECT_EQ(nullptr, dv.get()); |
| 366 | + EXPECT_EQ(type_index(typeid(void)), dv.realType ()) << "REQ: mv nullptr as if mv fail, avoid confuse usr"; |
| 367 | + EXPECT_EQ(type_index(typeid(void)), dv.lastType ()) << "REQ: mv nullptr as if mv fail, avoid confuse usr"; |
| 368 | + EXPECT_EQ(0, dv.use_count()) << "REQ: none"; |
| 369 | + EXPECT_EQ(0, d .use_count()) << "REQ: none"; |
| 370 | +} |
| 371 | +TEST(SafePtrTest, unsafeMv_toDiffType) |
| 372 | +{ |
| 373 | + auto i = make_safe<int>(7); |
| 374 | + //auto c = SafePtr<char>(move(i)); // REQ: compile err for diff types |
| 375 | +} |
| 376 | +TEST(SafePtrTest, unsupportMv_toBase) |
| 377 | +{ |
| 378 | + auto b_pri = make_safe<D_private >(); |
| 379 | + //auto b = SafePtr<Base>(move(b_pri)); // c++ not allow |
| 380 | + auto b_pro = make_safe<D_protected>(); |
| 381 | + //auto b = SafePtr<Base>(move(b_pro)); // c++ not allow |
| 382 | +} |
| 383 | +TEST(SafePtrTest, unsupportMv_toDerive) |
| 384 | +{ |
| 385 | + auto b = make_safe<Base>(); |
| 386 | + //auto bd = SafePtr<Derive>(move(b)); // REQ: compile err Base->Derive - unsafe |
259 | 387 |
|
260 | | - SafePtr<Base> as; |
261 | | - EXPECT_EQ(type_index(typeid(Base)), mv.realType()); |
262 | | - as = SafePtr<Derive>(); |
263 | | - EXPECT_EQ(type_index(typeid(Base)), mv.realType()) << "REQ/cov: assign-nothing=fail so keep origin"; |
| 388 | + auto db = SafePtr<Base>(make_safe<Derive>()); |
| 389 | + //auto dbd = SafePtr<Derive>(move(db)); // safe but unsupport since need dynamic_cast that can't bld err if fail |
| 390 | +} |
| 391 | +TEST(SafePtrTest, unsupportMv_voidToNon) |
| 392 | +{ |
| 393 | + auto bv = SafePtr<void>(make_safe<Base>()); |
| 394 | + //auto bvb = SafePtr<Base>(move(bv)); // safe but unsupport since need dynamic check that can't bld err if fail |
| 395 | +} |
| 396 | +TEST(SafePtrTest, unssafeMv_constToNon) |
| 397 | +{ |
| 398 | + auto bc = make_safe<const Base>(); |
| 399 | + //auto b = SafePtr<Base>(move(bc)); // REQ: unsafe cp, compile err |
264 | 400 | } |
265 | 401 |
|
266 | 402 | #define ASSIGN |
|
0 commit comments