mavtables  0.2.1
MAVLink router and firewall.
test_semaphore.cpp
Go to the documentation of this file.
1 // MAVLink router and firewall.
2 // Copyright (C) 2018 Michael R. Shannon <mrshannon.aerospace@gmail.com>
3 //
4 // This program is free software; you can redistribute it and/or modify
5 // it under the terms of the GNU General Public License as published by
6 // the Free Software Foundation; either version 2 of the License, or
7 // (at your option) any later version.
8 //
9 // This program is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU General Public License for more details.
13 //
14 // You should have received a copy of the GNU General Public License
15 // along with this program. If not, see <http://www.gnu.org/licenses/>.
16 
17 
18 #include <chrono>
19 #include <future>
20 
21 #include <catch.hpp>
22 
23 #include <semaphore.hpp>
24 
25 
26 using namespace std::chrono_literals;
27 
28 
29 TEST_CASE("semaphore's can be constructed.", "[semaphore]")
30 {
31  REQUIRE_NOTHROW(semaphore());
32  REQUIRE_NOTHROW(semaphore(10));
33 }
34 
35 
36 TEST_CASE("semaphore's 'wait' method waits until the semaphore can be "
37  "decremented.", "[semaphore]")
38 {
39  SECTION("Single wait.")
40  {
41  semaphore sp;
42  auto future = std::async(std::launch::async, [&]()
43  {
44  sp.wait();
45  });
46  REQUIRE(future.wait_for(0ms) != std::future_status::ready);
47  sp.notify();
48  REQUIRE(future.wait_for(10ms) == std::future_status::ready);
49  future.wait();
50  }
51  SECTION("Multiple wait.")
52  {
53  semaphore sp;
54  auto future = std::async(std::launch::async, [&]()
55  {
56  sp.wait();
57  sp.wait();
58  });
59  REQUIRE(future.wait_for(0ms) != std::future_status::ready);
60  sp.notify();
61  REQUIRE(future.wait_for(10ms) != std::future_status::ready);
62  sp.notify();
63  REQUIRE(future.wait_for(10ms) == std::future_status::ready);
64  future.wait();
65  }
66  SECTION("Single wait, with initial value by notification.")
67  {
68  semaphore sp;
69  sp.notify();
70  auto future = std::async(std::launch::async, [&]()
71  {
72  sp.wait();
73  });
74  REQUIRE(future.wait_for(10ms) == std::future_status::ready);
75  future.wait();
76  }
77  SECTION("Multiple wait, with initial value by notification.")
78  {
79  semaphore sp;
80  sp.notify();
81  auto future = std::async(std::launch::async, [&]()
82  {
83  sp.wait();
84  sp.wait();
85  });
86  REQUIRE(future.wait_for(10ms) != std::future_status::ready);
87  sp.notify();
88  REQUIRE(future.wait_for(10ms) == std::future_status::ready);
89  future.wait();
90  }
91  SECTION("Single wait, with initial value in constructor.")
92  {
93  semaphore sp(1);
94  auto future = std::async(std::launch::async, [&]()
95  {
96  sp.wait();
97  });
98  REQUIRE(future.wait_for(10ms) == std::future_status::ready);
99  future.wait();
100  }
101  SECTION("Multiple wait, with initial value in constructor.")
102  {
103  semaphore sp(2);
104  auto future = std::async(std::launch::async, [&]()
105  {
106  sp.wait();
107  sp.wait();
108  });
109  REQUIRE(future.wait_for(10ms) == std::future_status::ready);
110  future.wait();
111  }
112 }
113 
114 
115 TEST_CASE("semaphore's 'wait_for' method waits until the semaphore can be "
116  "decremented, or the timeout is reached (returning false if it "
117  "timed out).", "[semaphore]")
118 {
119  SECTION("Single wait (no timeout).")
120  {
121  semaphore sp;
122  auto future = std::async(std::launch::async, [&]()
123  {
124  return sp.wait_for(20ms);
125  });
126  REQUIRE(future.wait_for(0ms) != std::future_status::ready);
127  sp.notify();
128  REQUIRE(future.wait_for(5ms) == std::future_status::ready);
129  REQUIRE(future.get());
130  }
131  SECTION("Single wait (timeout).")
132  {
133  semaphore sp;
134  auto future = std::async(std::launch::async, [&]()
135  {
136  return sp.wait_for(5ms);
137  });
138  REQUIRE(future.wait_for(1ms) != std::future_status::ready);
139  REQUIRE(future.wait_for(20ms) == std::future_status::ready);
140  REQUIRE_FALSE(future.get());
141  // Ensure subsequent waits don't fail to wait. Tests for the "always
142  // decrement" bug.
143  future = std::async(std::launch::async, [&]()
144  {
145  return sp.wait_for(5ms);
146  });
147  REQUIRE(future.wait_for(1ms) != std::future_status::ready);
148  REQUIRE(future.wait_for(20ms) == std::future_status::ready);
149  REQUIRE_FALSE(future.get());
150  }
151  SECTION("Multiple wait (no timeout).")
152  {
153  semaphore sp;
154  auto future = std::async(std::launch::async, [&]()
155  {
156  return sp.wait_for(20ms) && sp.wait_for(20ms);
157  });
158  REQUIRE(future.wait_for(0ms) != std::future_status::ready);
159  sp.notify();
160  REQUIRE(future.wait_for(1ms) != std::future_status::ready);
161  sp.notify();
162  REQUIRE(future.wait_for(10ms) == std::future_status::ready);
163  REQUIRE(future.get());
164  }
165  SECTION("Multiple wait (timeout).")
166  {
167  semaphore sp;
168  auto future = std::async(std::launch::async, [&]()
169  {
170  return sp.wait_for(2ms) && sp.wait_for(2ms);
171  });
172  REQUIRE(future.wait_for(0ms) != std::future_status::ready);
173  REQUIRE(future.wait_for(10ms) == std::future_status::ready);
174  REQUIRE_FALSE(future.get());
175  // Ensure subsequent waits don't fail to wait. Tests for the "always
176  // decrement" bug.
177  future = std::async(std::launch::async, [&]()
178  {
179  return sp.wait_for(2ms) && sp.wait_for(2ms);
180  });
181  REQUIRE(future.wait_for(0ms) != std::future_status::ready);
182  REQUIRE(future.wait_for(10ms) == std::future_status::ready);
183  REQUIRE_FALSE(future.get());
184  }
185 }
186 
187 
188 TEST_CASE("semaphore's 'wait_until' method waits until the semaphore can be "
189  "decremented, or the timeout timepoint is reached (returning false "
190  "if it timed out).", "[semaphore]")
191 {
192  SECTION("Single wait (no timeout).")
193  {
194  semaphore sp;
195  auto future = std::async(std::launch::async, [&]()
196  {
197  return sp.wait_until(std::chrono::steady_clock::now() + 20ms);
198  });
199  REQUIRE(future.wait_for(0ms) != std::future_status::ready);
200  sp.notify();
201  REQUIRE(future.wait_for(10ms) == std::future_status::ready);
202  REQUIRE(future.get());
203  }
204  SECTION("Single wait (timeout).")
205  {
206  semaphore sp;
207  auto future = std::async(std::launch::async, [&]()
208  {
209  return sp.wait_until(std::chrono::steady_clock::now() + 2ms);
210  });
211  REQUIRE(future.wait_for(0ms) != std::future_status::ready);
212  REQUIRE(future.wait_for(10ms) == std::future_status::ready);
213  REQUIRE_FALSE(future.get());
214  // Ensure subsequent waits don't fail to wait. Tests for the "always
215  // decrement" bug.
216  future = std::async(std::launch::async, [&]()
217  {
218  return sp.wait_until(std::chrono::steady_clock::now() + 5ms);
219  });
220  REQUIRE(future.wait_for(1ms) != std::future_status::ready);
221  REQUIRE(future.wait_for(20ms) == std::future_status::ready);
222  REQUIRE_FALSE(future.get());
223  }
224  SECTION("Multiple wait (no timeout).")
225  {
226  semaphore sp;
227  auto future = std::async(std::launch::async, [&]()
228  {
229  return sp.wait_until(std::chrono::steady_clock::now() + 100ms) &&
230  sp.wait_until(std::chrono::steady_clock::now() + 100ms);
231  });
232  REQUIRE(future.wait_for(0ms) != std::future_status::ready);
233  sp.notify();
234  REQUIRE(future.wait_for(10ms) != std::future_status::ready);
235  sp.notify();
236  REQUIRE(future.wait_for(10ms) == std::future_status::ready);
237  REQUIRE(future.get());
238  }
239  SECTION("Multiple wait (timeout).")
240  {
241  semaphore sp;
242  auto future = std::async(std::launch::async, [&]()
243  {
244  return sp.wait_until(std::chrono::steady_clock::now() + 1ms) &&
245  sp.wait_until(std::chrono::steady_clock::now() + 1ms);
246  });
247  REQUIRE(future.wait_for(0ms) != std::future_status::ready);
248  REQUIRE(future.wait_for(10ms) == std::future_status::ready);
249  REQUIRE_FALSE(future.get());
250  // Ensure subsequent waits don't fail to wait. Tests for the "always
251  // decrement" bug.
252  future = std::async(std::launch::async, [&]()
253  {
254  return sp.wait_until(std::chrono::steady_clock::now() + 1ms) &&
255  sp.wait_until(std::chrono::steady_clock::now() + 1ms);
256  });
257  REQUIRE(future.wait_for(0ms) != std::future_status::ready);
258  REQUIRE(future.wait_for(10ms) == std::future_status::ready);
259  REQUIRE_FALSE(future.get());
260  }
261 }
void wait()
Definition: semaphore.cpp:52
bool wait_until(const std::chrono::time_point< Clock, Duration > &timeout_time)
Definition: semaphore.hpp:90
TEST_CASE("semaphore's can be constructed.", "[semaphore]")
void notify()
Definition: semaphore.cpp:38
bool wait_for(const std::chrono::duration< Rep, Period > &rel_time)
Definition: semaphore.hpp:66