basedOpinionated utility library |
git clone git://git.dimitrijedobrota.com/based.git |
Log | Files | Refs | README | LICENSE | HACKING | CONTRIBUTING | CODE_OF_CONDUCT | BUILDING |
commit | 9eca6e4aef6bd73e894a009f5ab5ee22707d4c50 |
parent | 4d76aec6d751582155fc6ca5802dd8c7932cc8f4 |
author | Dimitrije Dobrota < mail@dimitrijedobrota.com > |
date | Tue, 29 Apr 2025 15:00:43 +0200 |
Test scopeguard, fix some issues
* Found bug in gcc
M | include/based/template.hpp | | | +++++++++++++ -------------- |
M | test/CMakeLists.txt | | | + |
A | test/source/scopeguard_test.cpp | | | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
3 files changed, 152 insertions(+), 14 deletions(-)
diff --git a/ include/based/template.hpp b/ include/based/template.hpp
@@ -7,7 +7,6 @@
#include <type_traits>
#include <utility>
#include "based/type_traits.hpp"
#include "based/utility.hpp"
namespace based
@@ -372,19 +371,19 @@
template<typename T>
function(T) -> function<typename signature<std::decay_t<T>>::sig_type>;
*/
template<Procedure Func, bool on_success = false, bool on_failure = false>
template<typename Func, bool on_success = false, bool on_failure = false>
class scopeguard
{
uncaught_exception_detector m_detector;
Func m_func;
public:
explicit scopeguard(Func&& func)
scopeguard(Func&& func) // NOLINT explicit
: m_func(std::move(func))
{
}
explicit scopeguard(const Func& func)
scopeguard(const Func& func) // NOLINT explicit
: m_func(func)
{
}
@@ -392,8 +391,8 @@
public:
scopeguard(const scopeguard&) = delete;
scopeguard& operator=(const scopeguard&) = delete;
scopeguard(scopeguard&&) = default;
scopeguard& operator=(scopeguard&&) = default;
scopeguard(scopeguard&&) = delete;
scopeguard& operator=(scopeguard&&) = delete;
~scopeguard()
{
@@ -403,19 +402,19 @@
public:
}
};
template<Procedure Func>
template<typename Func>
class scopeguard<Func, false, false>
{
bool m_commit = false;
Func m_func;
public:
explicit scopeguard(Func&& func)
scopeguard(Func&& func) // NOLINT explicit
: m_func(std::move(func))
{
}
explicit scopeguard(const Func& func)
scopeguard(const Func& func) // NOLINT explicit
: m_func(func)
{
}
@@ -423,8 +422,8 @@
public:
scopeguard(const scopeguard&) = delete;
scopeguard& operator=(const scopeguard&) = delete;
scopeguard(scopeguard&&) = default;
scopeguard& operator=(scopeguard&&) = default;
scopeguard(scopeguard&&) = delete;
scopeguard& operator=(scopeguard&&) = delete;
~scopeguard()
{
@@ -435,13 +434,13 @@
public:
void commit() { m_commit = true; }
};
template<Procedure Func>
template<typename Func>
using scopeguard_exit = scopeguard<Func, true, true>;
template<Procedure Func>
template<typename Func>
using scopeguard_success = scopeguard<Func, true, false>;
template<Procedure Func>
template<typename Func>
using scopeguard_failure = scopeguard<Func, false, true>;
} // namespace based
diff --git a/ test/CMakeLists.txt b/ test/CMakeLists.txt
@@ -68,6 +68,7 @@
add_test(string_literal_test)
add_test(signature_test)
add_test(buffer_test)
add_test(function_test)
add_test(scopeguard_test)
# ---- End-of-file commands ----
diff --git a/ test/source/scopeguard_test.cpp b/ test/source/scopeguard_test.cpp
@@ -0,0 +1,138 @@
#define CATCH_CONFIG_RUNTIME_STATIC_REQUIRE
#include <stdexcept>
#include <catch2/catch_test_macros.hpp>
#include "based/template.hpp"
// NOLINTBEGIN cognitive-complexity
struct set
{
set(int& val)
: m_val(&val)
{
}
void operator()() const { *m_val = 1; }
private:
int* m_val;
};
template class based::scopeguard<set>;
TEST_CASE("manual", "[template/scopeguard]")
{
SECTION("commit")
{
int test = 0;
try {
based::scopeguard guard = set(test);
guard.commit();
} catch (...) {
REQUIRE(false);
}
REQUIRE(test == 1);
}
// breaks coverage for some reason
SECTION("no commit")
{
int test = 0;
try {
based::scopeguard guard = set(test);
} catch (...) {
test *= 1;
}
REQUIRE(test == 0);
}
}
TEST_CASE("on success", "[template/scopeguard]")
{
SECTION("success")
{
int test = 0;
auto func = set(test);
try {
const based::scopeguard_success guard = func;
} catch (...) {
test *= 1;
}
REQUIRE(test == 1);
}
// breaks coverage for some reason
SECTION("failure")
{
int test = 0;
auto func = set(test);
try {
const based::scopeguard_success guard = func;
throw std::runtime_error {"should not leak"};
} catch (...) {
test *= 1;
}
REQUIRE(test == 0);
}
}
TEST_CASE("on failure", "[template/scopeguard]")
{
SECTION("success")
{
int test = 0;
try {
const based::scopeguard_failure guard = set(test);
} catch (...) {
test *= 1;
}
REQUIRE(test == 0);
}
// breaks coverage for some reason
SECTION("failure")
{
int test = 0;
try {
const based::scopeguard_failure guard = set(test);
throw std::runtime_error {"should not leak"};
} catch (...) {
REQUIRE(true);
}
REQUIRE(test == 1);
}
}
TEST_CASE("exit", "[template/scopeguard]")
{
SECTION("success")
{
int test = 0;
try {
const based::scopeguard_exit guard = set(test);
} catch (...) {
REQUIRE(false);
}
REQUIRE(test == 1);
}
// breaks coverage for some reason
SECTION("failure")
{
int test = 0;
try {
const based::scopeguard_exit guard = set(test);
throw std::runtime_error {"should not leak"};
} catch (...) {
test *= 1;
}
REQUIRE(test == 1);
}
}
// NOLINTEND cognitive-complexity