Skip to content

Commit 5a7d4ee

Browse files
author
Vlada Kanivets
committed
add tests for EResource
1 parent 28fa365 commit 5a7d4ee

2 files changed

Lines changed: 229 additions & 0 deletions

File tree

test/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ wdk_add_driver(kf-test WINVER NTDDI_WIN10 STL
5353
VariableSizeStructTest.cpp
5454
ScopeFailureTest.cpp
5555
Base64Test.cpp
56+
EResourceTest.cpp
5657
)
5758

5859
target_link_libraries(kf-test kf::kf kmtest::kmtest)

test/EResourceTest.cpp

Lines changed: 228 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,228 @@
1+
#include "pch.h"
2+
#include <kf/EResource.h>
3+
#include <kf/Thread.h>
4+
5+
SCENARIO("kf::EResource")
6+
{
7+
GIVEN("An EResource object")
8+
{
9+
kf::EResource resource;
10+
11+
THEN("The resource is initialized and not acquired immediatly")
12+
{
13+
REQUIRE(resource.isAcquiredExclusive() == false);
14+
REQUIRE(resource.isAcquiredShared() == 0);
15+
}
16+
17+
WHEN("The resource is acquired exclusively")
18+
{
19+
bool acquired = resource.acquireExclusive();
20+
21+
//The system considers exclusive access to be a subset of shared access.
22+
//Therefore, a thread that has exclusive access to a resource also has shared access to the resource.
23+
THEN("The exclusive and shared locks are acquired")
24+
{
25+
REQUIRE(acquired == true);
26+
REQUIRE(resource.isAcquiredExclusive() == true);
27+
REQUIRE(resource.isAcquiredShared() == 1);
28+
}
29+
30+
WHEN("The exclusive lock is released")
31+
{
32+
resource.release();
33+
34+
THEN("The resource is no longer locked")
35+
{
36+
REQUIRE(resource.isAcquiredExclusive() == false);
37+
REQUIRE(resource.isAcquiredShared() == 0);
38+
}
39+
}
40+
}
41+
}
42+
43+
GIVEN("The EResource is acquired shared")
44+
{
45+
kf::EResource resource;
46+
bool acquired = resource.acquireShared();
47+
48+
THEN("The only shared lock is acquired")
49+
{
50+
REQUIRE(acquired == true);
51+
REQUIRE(resource.isAcquiredExclusive() == false);
52+
REQUIRE(resource.isAcquiredShared() > 0);
53+
}
54+
55+
WHEN("The shared lock is released")
56+
{
57+
resource.release();
58+
59+
THEN("The resource is no longer locked")
60+
{
61+
REQUIRE(resource.isAcquiredExclusive() == false);
62+
REQUIRE(resource.isAcquiredShared() == 0);
63+
}
64+
}
65+
}
66+
67+
GIVEN("The EResource acquired exclusive")
68+
{
69+
kf::EResource resource;
70+
71+
WHEN("The resource is converted to shared")
72+
{
73+
bool exclusiveAcquired = resource.acquireExclusive();
74+
REQUIRE(exclusiveAcquired == true);
75+
76+
resource.convertExclusiveToShared();
77+
78+
THEN("The lock is converted to shared")
79+
{
80+
REQUIRE(resource.isAcquiredExclusive() == false);
81+
REQUIRE(resource.isAcquiredShared() > 0);
82+
}
83+
84+
WHEN("The shared lock is released")
85+
{
86+
resource.release();
87+
88+
THEN("The resource is no longer locked")
89+
{
90+
REQUIRE(resource.isAcquiredExclusive() == false);
91+
REQUIRE(resource.isAcquiredShared() == 0);
92+
}
93+
}
94+
}
95+
}
96+
97+
GIVEN("The EResource locked using the lock function")
98+
{
99+
kf::EResource resource;
100+
resource.lock();
101+
102+
THEN("The resource is acquired exclusively and shared")
103+
{
104+
REQUIRE(resource.isAcquiredExclusive() == true);
105+
REQUIRE(resource.isAcquiredShared() == 1);
106+
}
107+
108+
WHEN("The resource is unlocked")
109+
{
110+
resource.unlock();
111+
112+
THEN("The resource is no longer locked")
113+
{
114+
REQUIRE(resource.isAcquiredExclusive() == false);
115+
REQUIRE(resource.isAcquiredShared() == 0);
116+
}
117+
}
118+
}
119+
120+
GIVEN("The EResource is locked shared using the lock_shared function")
121+
{
122+
kf::EResource resource;
123+
resource.lock_shared();
124+
125+
THEN("The resource is acquired shared")
126+
{
127+
REQUIRE(resource.isAcquiredExclusive() == false);
128+
REQUIRE(resource.isAcquiredShared() > 0);
129+
}
130+
131+
WHEN("The resource is unlocked shared")
132+
{
133+
resource.unlock_shared();
134+
135+
THEN("The resource is no longer locked")
136+
{
137+
REQUIRE(resource.isAcquiredExclusive() == false);
138+
REQUIRE(resource.isAcquiredShared() == 0);
139+
}
140+
}
141+
}
142+
143+
GIVEN("The EResource and 2 threads")
144+
{
145+
WHEN("Multiple threads attempt to acquire exclusive the resource")
146+
{
147+
kf::EResource resource;
148+
kf::Thread thread1, thread2;
149+
struct Context
150+
{
151+
kf::EResource* resource;
152+
bool wasAcquiredByFirst = false;
153+
bool wasAcquiredBySecond = false;
154+
};
155+
Context context{ &resource };
156+
157+
thread1.start([](void* context) {
158+
auto res = static_cast<Context*>(context);
159+
res->wasAcquiredByFirst = res->resource->acquireExclusive();
160+
res->resource->release();
161+
},
162+
&context);
163+
164+
thread2.start([](void* context) {
165+
auto res = static_cast<Context*>(context);
166+
res->wasAcquiredBySecond = res->resource->acquireExclusive();
167+
res->resource->release();
168+
},
169+
&context);
170+
171+
thread1.join();
172+
thread2.join();
173+
174+
THEN("Both threads can acquire and release the resource without deadlock")
175+
{
176+
REQUIRE(context.wasAcquiredByFirst);
177+
REQUIRE(context.wasAcquiredBySecond);
178+
REQUIRE(resource.isAcquiredExclusive() == false);
179+
REQUIRE(resource.isAcquiredShared() == 0);
180+
}
181+
}
182+
183+
WHEN("Multiple threads attempt to acquire shared the resource")
184+
{
185+
kf::EResource resource;
186+
kf::Thread thread1, thread2;
187+
struct Context
188+
{
189+
kf::EResource* resource;
190+
bool wasAcquiredByFirst = false;
191+
bool wasAcquiredBySecond = false;
192+
};
193+
Context context{ &resource };
194+
195+
thread1.start([](void* context) {
196+
auto res = static_cast<Context*>(context);
197+
res->wasAcquiredByFirst = res->resource->acquireShared();
198+
199+
LARGE_INTEGER interval;
200+
interval.QuadPart = -10'000'000; // ~1s
201+
KeDelayExecutionThread(KernelMode, FALSE, &interval);
202+
203+
res->resource->release();
204+
},
205+
&context);
206+
207+
thread2.start([](void* context) {
208+
auto res = static_cast<Context*>(context);
209+
210+
res->wasAcquiredBySecond = res->resource->acquireShared();
211+
LARGE_INTEGER interval;
212+
interval.QuadPart = -10'000'000; // ~1s
213+
KeDelayExecutionThread(KernelMode, FALSE, &interval);
214+
215+
res->resource->release();
216+
},
217+
&context);
218+
219+
THEN("Both threads can acquire and release the resource without deadlock")
220+
{
221+
thread1.join();
222+
thread2.join();
223+
REQUIRE(context.wasAcquiredByFirst);
224+
REQUIRE(context.wasAcquiredBySecond);
225+
}
226+
}
227+
}
228+
}

0 commit comments

Comments
 (0)