Skip to content

Commit d4c223c

Browse files
committed
additional unique_resource tests
1 parent 410bd2d commit d4c223c

File tree

1 file changed

+158
-19
lines changed

1 file changed

+158
-19
lines changed

tests/unique_resource.test.cpp

Lines changed: 158 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,170 @@
11
#include <memory>
22
#include <cstdio>
3+
#include <stdexcept>
34
#include <beman/scope/scope.hpp>
45

5-
constexpr bool open_file_good = false;
6-
constexpr bool close_file_good = false;
6+
// clang-format off
77

8-
// define only in one cpp file
98
#define CATCH_CONFIG_MAIN
109
#include <catch2/catch_all.hpp>
1110

12-
TEST_CASE("Construct file unique_resource") {
13-
14-
{
15-
auto file = beman::scope::unique_resource(
16-
fopen("example.txt", "w"), // Acquire the FILE*
17-
[](FILE* f) {
18-
if (f) {
19-
fclose(f); // Release (cleanup) the resource
20-
close_file_good = true;
21-
}
22-
}
11+
using namespace beman::scope;
12+
TEST_CASE("Construct file unique_resource", "[unique_resource]") {
13+
bool open_file_good = false;
14+
bool close_file_good = false;
15+
16+
{
17+
auto file = beman::scope::unique_resource(
18+
fopen("example.txt", "w"), // Acquire the FILE*
19+
[](FILE* f) { if (f) {
20+
fclose(f); // Release (cleanup) the resource
21+
close_file_good = true;
22+
}
23+
} );
24+
25+
if (!file.get()) {
26+
throw std::runtime_error("file didn't open");
27+
}
28+
}
29+
REQUIRE(open_file_good == true);
30+
REQUIRE(close_file_good == true);
31+
}
32+
33+
struct DummyResource {
34+
bool* cleanedUp;
35+
36+
DummyResource(bool* flag) : cleanedUp(flag) {
37+
*cleanedUp = false;
38+
}
39+
40+
void do_something() {}
41+
};
42+
43+
TEST_CASE("unique_resource calls cleanup on destruction", "[unique_resource]") {
44+
bool cleaned = false;
45+
46+
{
47+
auto res = unique_resource(
48+
DummyResource(&cleaned),
49+
[](DummyResource r) { *(r.cleanedUp) = true; }
50+
);
51+
52+
res.get().do_something();
53+
}
54+
55+
REQUIRE(cleaned == true);
56+
}
57+
58+
TEST_CASE("unique_resource does not clean up after release", "[unique_resource]") {
59+
bool cleaned = false;
60+
61+
{
62+
auto res = unique_resource(
63+
DummyResource(&cleaned),
64+
[](DummyResource r) { *(r.cleanedUp) = true; }
65+
);
66+
67+
[[maybe_unused]] auto raw = res.release();
68+
}
69+
70+
REQUIRE(cleaned == false);
71+
}
72+
73+
TEST_CASE("unique_resource moves properly", "[unique_resource]") {
74+
bool cleaned = false;
75+
76+
unique_resource<DummyResource, void(*)(DummyResource)> res1(
77+
DummyResource(&cleaned),
78+
[](DummyResource r) { *(r.cleanedUp) = true; }
79+
);
80+
81+
{
82+
auto res2 = std::move(res1);
83+
res2.get().do_something();
84+
}
85+
86+
REQUIRE(cleaned == true);
87+
}
88+
89+
TEST_CASE("unique_resource reset cleans up old resource", "[unique_resource]") {
90+
bool cleaned1 = false;
91+
bool cleaned2 = false;
92+
93+
DummyResource res1(&cleaned1);
94+
DummyResource res2(&cleaned2);
95+
96+
auto ur = unique_resource(
97+
res1,
98+
[](DummyResource r) { *(r.cleanedUp) = true; }
99+
);
100+
101+
ur.reset(res2); // should clean up res1 and now manage res2
102+
103+
REQUIRE(cleaned1 == true);
104+
REQUIRE(cleaned2 == false);
105+
}
106+
107+
// Simulates throwing in the middle of a function using unique_resource
108+
void simulate_exception(bool* cleanup_flag) {
109+
auto res = unique_resource(
110+
DummyResource(cleanup_flag),
111+
[](DummyResource r) { *(r.cleanedUp) = true; }
23112
);
24113

25-
if (!file.get()) {
26-
return 1;
114+
throw std::runtime_error("Something went wrong");
115+
}
116+
117+
TEST_CASE("unique_resource cleans up on exception", "[unique_resource][exception]") {
118+
bool cleaned = false;
119+
120+
try {
121+
simulate_exception(&cleaned);
122+
} catch (const std::exception& e) {
123+
// Expected
27124
}
28-
}
29-
REQUIRE(open_file_good == true);
30-
REQUIRE(close_file_good == true);
125+
126+
REQUIRE(cleaned == true);
127+
}
128+
129+
TEST_CASE("unique_resource does not clean up if released before exception", "[unique_resource][exception]") {
130+
bool cleaned = false;
131+
132+
try {
133+
auto res = unique_resource(
134+
DummyResource(&cleaned),
135+
[](DummyResource r) { *(r.cleanedUp) = true; }
136+
);
137+
138+
[[maybe_unused]] auto raw = res.release(); // disables cleanup
139+
140+
throw std::runtime_error("Throwing after release");
141+
142+
} catch (...) {
143+
// expected
144+
}
145+
146+
REQUIRE(cleaned == false);
147+
}
148+
149+
TEST_CASE("unique_resource handles exception during reset", "[unique_resource][exception]") {
150+
bool cleaned1 = false;
151+
bool cleaned2 = false;
152+
153+
DummyResource res1(&cleaned1);
154+
DummyResource res2(&cleaned2);
155+
156+
auto ur = unique_resource(
157+
res1,
158+
[](DummyResource r) { *(r.cleanedUp) = true; }
159+
);
160+
161+
try {
162+
ur.reset(res2);
163+
throw std::runtime_error("Exception after reset");
164+
} catch (...) {
165+
// expected
166+
}
167+
168+
REQUIRE(cleaned1 == true);
169+
REQUIRE(cleaned2 == false);
31170
}

0 commit comments

Comments
 (0)