1/*
2 * Distributed under the Boost Software License, Version 1.0.
3 * (See accompanying file LICENSE_1_0.txt or copy at
4 * https://www.boost.org/LICENSE_1_0.txt)
5 *
6 * Copyright (c) 2023-2024 Andrey Semashev
7 */
8/*!
9 * \file defer_guard.cpp
10 * \author Andrey Semashev
11 *
12 * \brief This file contains tests for \c defer_guard.
13 */
14
15#include <boost/scope/defer.hpp>
16#include <boost/core/lightweight_test.hpp>
17#include <boost/core/lightweight_test_trait.hpp>
18#include <boost/config.hpp>
19#include <utility>
20#include <stdexcept>
21#include "function_types.hpp"
22
23#if defined(_MSC_VER) && !defined(__clang__)
24// warning C4702: unreachable code
25// This warning is triggered by tests that unconditionally throw exception at some point
26// and have code after that (e.g. parts of scope guard constructor and a check that verifies
27// that the following code is not reached).
28#pragma warning(disable: 4702)
29#endif
30
31int g_n = 0;
32
33void check_normal()
34{
35 int n = 0;
36 {
37 boost::scope::defer_guard< normal_func > guard{ normal_func(n) };
38 }
39 BOOST_TEST_EQ(n, 1);
40
41 n = 0;
42 {
43 normal_func func(n);
44 boost::scope::defer_guard< normal_func& > guard(func);
45 }
46 BOOST_TEST_EQ(n, 1);
47
48 struct local
49 {
50 static void raw_func()
51 {
52 ++g_n;
53 }
54 };
55
56 g_n = 0;
57 {
58 boost::scope::defer_guard< void (&)() > guard(local::raw_func);
59 }
60 BOOST_TEST_EQ(g_n, 1);
61}
62
63void check_throw()
64{
65 int n = 0;
66 try
67 {
68 boost::scope::defer_guard< normal_func > guard{ normal_func(n) };
69 throw std::runtime_error("error");
70 }
71 catch (...) {}
72 BOOST_TEST_EQ(n, 1);
73
74 n = 0;
75 try
76 {
77 boost::scope::defer_guard< throw_on_copy_func > guard{ throw_on_copy_func(n) };
78 BOOST_ERROR("An exception is expected to be thrown by throw_on_copy_func");
79 }
80 catch (...) {}
81 BOOST_TEST_EQ(n, 1);
82
83 n = 0;
84 try
85 {
86 boost::scope::defer_guard< throw_on_move_func > guard{ throw_on_move_func(n) };
87 }
88 catch (...)
89 {
90 BOOST_ERROR("An exception is not expected to be thrown by throw_on_move_func (copy ctor should be used)");
91 }
92 BOOST_TEST_EQ(n, 1);
93
94 n = 0;
95 bool scope_ended = false, exception_thrown = false, func_destroyed = false;
96 try
97 {
98 boost::scope::defer_guard< throw_on_call_func > guard{ throw_on_call_func(n, func_destroyed) };
99 func_destroyed = false;
100 scope_ended = true;
101 }
102 catch (...)
103 {
104 exception_thrown = true;
105 }
106 BOOST_TEST_EQ(n, 1);
107 BOOST_TEST(scope_ended);
108 BOOST_TEST(exception_thrown);
109 BOOST_TEST(func_destroyed);
110}
111
112void check_deduction()
113{
114#if !defined(BOOST_NO_CXX17_DEDUCTION_GUIDES)
115 int n = 0;
116 {
117 boost::scope::defer_guard guard{ normal_func(n) };
118 BOOST_TEST_TRAIT_SAME(decltype(guard), boost::scope::defer_guard< normal_func >);
119 }
120 BOOST_TEST_EQ(n, 1);
121
122 n = 0;
123 {
124 boost::scope::defer_guard guard([&n] { ++n; });
125 }
126 BOOST_TEST_EQ(n, 1);
127
128 struct local
129 {
130 static void raw_func()
131 {
132 ++g_n;
133 }
134
135#if !defined(BOOST_SCOPE_NO_CXX17_NOEXCEPT_FUNCTION_TYPES)
136 static void raw_func_noexcept() noexcept
137 {
138 ++g_n;
139 }
140#endif
141 };
142
143 g_n = 0;
144 {
145 boost::scope::defer_guard guard{ local::raw_func };
146 BOOST_TEST_TRAIT_SAME(decltype(guard), boost::scope::defer_guard< void (*)() >);
147 }
148 BOOST_TEST_EQ(g_n, 1);
149
150#if !defined(BOOST_SCOPE_NO_CXX17_NOEXCEPT_FUNCTION_TYPES)
151 g_n = 0;
152 {
153 boost::scope::defer_guard guard{ local::raw_func_noexcept };
154 BOOST_TEST_TRAIT_SAME(decltype(guard), boost::scope::defer_guard< void (*)() noexcept >);
155 }
156 BOOST_TEST_EQ(g_n, 1);
157#endif
158
159 n = 0;
160 {
161 BOOST_SCOPE_DEFER [&n] { ++n; };
162 BOOST_SCOPE_DEFER [&n] { ++n; };
163 }
164 BOOST_TEST_EQ(n, 2);
165#endif // !defined(BOOST_NO_CXX17_DEDUCTION_GUIDES)
166}
167
168int main()
169{
170 check_normal();
171 check_throw();
172 check_deduction();
173
174 return boost::report_errors();
175}
176

source code of boost/libs/scope/test/run/defer_guard.cpp