diff options
author | Hans Goudey <h.goudey@me.com> | 2020-09-01 20:35:14 +0300 |
---|---|---|
committer | Hans Goudey <h.goudey@me.com> | 2020-09-01 20:38:05 +0300 |
commit | baca8611e5fe4b3dcd6f5065fb125bc0a9d65934 (patch) | |
tree | bb1230387cd53b15f9621f10c4d0e5e2050b5580 /source/blender/blenlib/tests/BLI_exception_safety_test_utils.hh | |
parent | 31705201dddebf7e3be5c4533b89f380aad1ede1 (diff) | |
parent | 2930d4fcea405985f2212c5f28c061af7c4849f8 (diff) |
Merge branch 'master' into active-fcurve-keyframeactive-fcurve-keyframe
Diffstat (limited to 'source/blender/blenlib/tests/BLI_exception_safety_test_utils.hh')
-rw-r--r-- | source/blender/blenlib/tests/BLI_exception_safety_test_utils.hh | 102 |
1 files changed, 102 insertions, 0 deletions
diff --git a/source/blender/blenlib/tests/BLI_exception_safety_test_utils.hh b/source/blender/blenlib/tests/BLI_exception_safety_test_utils.hh new file mode 100644 index 00000000000..91270767a25 --- /dev/null +++ b/source/blender/blenlib/tests/BLI_exception_safety_test_utils.hh @@ -0,0 +1,102 @@ +#include "BLI_hash.hh" +#include "BLI_utildefines.h" +#include "MEM_guardedalloc.h" +#include "testing/testing.h" + +namespace blender::tests { + +class ExceptionThrower { + private: + /* Use some random values that are unlikely to exist at the memory location already. */ + static constexpr uint32_t is_alive_state = 0x21254634; + static constexpr uint32_t is_destructed_state = 0xFA4BC327; + + uint32_t state_; + + /* Make use of leak detector to check if this value has been destructed. */ + void *my_memory_; + + public: + mutable bool throw_during_copy; + mutable bool throw_during_move; + /* Used for hashing and comparing. */ + int value; + + ExceptionThrower(int value = 0) + : state_(is_alive_state), + my_memory_(MEM_mallocN(1, AT)), + throw_during_copy(false), + throw_during_move(false), + value(value) + { + } + + ExceptionThrower(const ExceptionThrower &other) : ExceptionThrower(other.value) + { + EXPECT_EQ(other.state_, is_alive_state); + if (other.throw_during_copy) { + throw std::runtime_error("throwing during copy, as requested"); + } + } + + ExceptionThrower(ExceptionThrower &&other) : ExceptionThrower(other.value) + { + EXPECT_EQ(other.state_, is_alive_state); + if (other.throw_during_move) { + throw std::runtime_error("throwing during move, as requested"); + } + } + + ExceptionThrower &operator=(const ExceptionThrower &other) + { + EXPECT_EQ(other.state_, is_alive_state); + if (throw_during_copy || other.throw_during_copy) { + throw std::runtime_error("throwing during copy, as requested"); + } + value = other.value; + return *this; + } + + ExceptionThrower &operator=(ExceptionThrower &&other) + { + EXPECT_EQ(other.state_, is_alive_state); + if (throw_during_move || other.throw_during_move) { + throw std::runtime_error("throwing during move, as requested"); + } + value = other.value; + return *this; + } + + ~ExceptionThrower() + { + const char *message = ""; + if (state_ != is_alive_state) { + if (state_ == is_destructed_state) { + message = "Trying to destruct an already destructed instance."; + } + else { + message = "Trying to destruct an uninitialized instance."; + } + } + EXPECT_EQ(state_, is_alive_state) << message; + state_ = is_destructed_state; + MEM_freeN(my_memory_); + } + + uint64_t hash() const + { + return static_cast<uint64_t>(value); + } + + friend bool operator==(const ExceptionThrower &a, const ExceptionThrower &b) + { + return a.value == b.value; + } + + friend bool operator!=(const ExceptionThrower &a, const ExceptionThrower &b) + { + return !(a == b); + } +}; + +} // namespace blender::tests |