mavtables  0.2.1
MAVLink router and firewall.
test_PacketVersion1.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 <memory>
19 #include <optional>
20 #include <stdexcept>
21 #include <utility>
22 
23 #include <catch.hpp>
24 #include <fakeit.hpp>
25 
26 #include "config.hpp"
27 #include "Connection.hpp"
28 #include "InvalidPacketIDError.hpp"
29 #include "MAVAddress.hpp"
30 #include "mavlink.hpp"
31 #include "PacketVersion1.hpp"
32 #include "utility.hpp"
33 
34 #include "common.hpp"
35 #include "common_Packet.hpp"
36 
37 
38 TEST_CASE("'packet_v1::header_complete' determines whether the given bytes "
39  "at least represent a complete header.", "[packet_v1]")
40 {
41  auto heartbeat = to_vector(HeartbeatV1());
42  auto ping = to_vector(PingV1());
43  auto set_mode = to_vector(SetModeV1());
44  auto encapsulated_data = to_vector(EncapsulatedDataV1());
45  SECTION("Returns true when at least a complete header is given.")
46  {
47  heartbeat.resize(6);
48  ping.resize(10);
49  set_mode.resize(15);
52  REQUIRE(packet_v1::header_complete(set_mode));
53  REQUIRE(packet_v1::header_complete(encapsulated_data));
54  }
55  SECTION("Returns false when an incomplete header is given.")
56  {
57  heartbeat.resize(5);
58  ping.resize(4);
59  set_mode.resize(3);
60  encapsulated_data.resize(0);
61  REQUIRE_FALSE(packet_v1::header_complete(heartbeat));
62  REQUIRE_FALSE(packet_v1::header_complete(ping));
63  REQUIRE_FALSE(packet_v1::header_complete(set_mode));
64  REQUIRE_FALSE(packet_v1::header_complete(encapsulated_data));
65  }
66  SECTION("Returns false when the magic byte is wrong.")
67  {
68  heartbeat.front() = 0xAD;
69  ping.front() = 0xBC;
70  set_mode.front() = 0xFD;
71  encapsulated_data.front() = 0xFD;
72  REQUIRE_FALSE(packet_v1::header_complete(heartbeat));
73  REQUIRE_FALSE(packet_v1::header_complete(ping));
74  REQUIRE_FALSE(packet_v1::header_complete(set_mode));
75  REQUIRE_FALSE(packet_v1::header_complete(encapsulated_data));
76  }
77 }
78 
79 
80 TEST_CASE("'packet_v1::header' returns a structure pointer to the given "
81  "header data.", "[packet_v1]")
82 {
83  auto heartbeat = to_vector(HeartbeatV1());
84  auto ping = to_vector(PingV1());
85  auto set_mode = to_vector(SetModeV1());
86  auto encapsulated_data = to_vector(EncapsulatedDataV1());
87  SECTION("Header contains a magic value.")
88  {
89  REQUIRE(packet_v1::header(heartbeat)->magic == 0xFE);
90  REQUIRE(packet_v1::header(ping)->magic == 0xFE);
91  REQUIRE(packet_v1::header(set_mode)->magic == 0xFE);
92  REQUIRE(packet_v1::header(encapsulated_data)->magic == 0xFE);
93  }
94  SECTION("Header stores the payload length.")
95  {
96  REQUIRE(packet_v1::header(heartbeat)->len == 9);
97  REQUIRE(packet_v1::header(ping)->len == 14);
98  REQUIRE(packet_v1::header(set_mode)->len == 6);
99  REQUIRE(packet_v1::header(encapsulated_data)->len == 255);
100  }
101  SECTION("Header has a sequence number.")
102  {
103  REQUIRE(packet_v1::header(heartbeat)->seq == 0xFE);
104  REQUIRE(packet_v1::header(ping)->seq == 0xFE);
105  REQUIRE(packet_v1::header(set_mode)->seq == 0xFE);
106  REQUIRE(packet_v1::header(encapsulated_data)->seq == 0xFE);
107  }
108  SECTION("Header has a system ID.")
109  {
110  REQUIRE(packet_v1::header(heartbeat)->sysid == 127);
111  REQUIRE(packet_v1::header(ping)->sysid == 192);
112  REQUIRE(packet_v1::header(set_mode)->sysid == 172);
113  REQUIRE(packet_v1::header(encapsulated_data)->sysid == 224);
114  }
115  SECTION("Header has a component ID.")
116  {
117  REQUIRE(packet_v1::header(heartbeat)->compid == 1);
118  REQUIRE(packet_v1::header(ping)->compid == 168);
119  REQUIRE(packet_v1::header(set_mode)->compid == 0);
120  REQUIRE(packet_v1::header(encapsulated_data)->compid == 255);
121  }
122  SECTION("Header has a message ID.")
123  {
124  REQUIRE(packet_v1::header(heartbeat)->msgid == 0);
125  REQUIRE(packet_v1::header(ping)->msgid == 4);
126  REQUIRE(packet_v1::header(set_mode)->msgid == 11);
127  REQUIRE(packet_v1::header(encapsulated_data)->msgid == 131);
128  }
129  SECTION("Returns nullptr when an incomplete header is given.")
130  {
131  heartbeat.resize(5);
132  ping.resize(4);
133  set_mode.resize(3);
134  encapsulated_data.resize(0);
135  REQUIRE(packet_v1::header(heartbeat) == nullptr);
136  REQUIRE(packet_v1::header(ping) == nullptr);
137  REQUIRE(packet_v1::header(set_mode) == nullptr);
138  REQUIRE(packet_v1::header(encapsulated_data) == nullptr);
139  }
140  SECTION("Returns nullptr when the magic byte is wrong.")
141  {
142  heartbeat.front() = 0xAD;
143  ping.front() = 0xBC;
144  set_mode.front() = 0xFD;
145  encapsulated_data.front() = 0xFD;
146  REQUIRE(packet_v1::header(heartbeat) == nullptr);
147  REQUIRE(packet_v1::header(ping) == nullptr);
148  REQUIRE(packet_v1::header(set_mode) == nullptr);
149  REQUIRE(packet_v1::header(encapsulated_data) == nullptr);
150  }
151 }
152 
153 
154 TEST_CASE("'packet_v1::packet_complete' determines whether the given bytes "
155  "represent a complete packet.", "[packet_v1]")
156 {
157  auto heartbeat = to_vector(HeartbeatV1());
158  auto ping = to_vector(PingV1());
159  auto set_mode = to_vector(SetModeV1());
160  auto encapsulated_data = to_vector(EncapsulatedDataV1());
161  SECTION("Returns true when a complete packet is given.")
162  {
165  REQUIRE(packet_v1::packet_complete(set_mode));
166  REQUIRE(packet_v1::packet_complete(encapsulated_data));
167  }
168  SECTION("Returns false when the magic byte is wrong.")
169  {
170  heartbeat.front() = 0xAD;
171  ping.front() = 0xBC;
172  set_mode.front() = 0xFD;
173  encapsulated_data.front() = 0xFD;
174  REQUIRE_FALSE(packet_v1::packet_complete(heartbeat));
175  REQUIRE_FALSE(packet_v1::packet_complete(ping));
176  REQUIRE_FALSE(packet_v1::packet_complete(set_mode));
177  REQUIRE_FALSE(packet_v1::packet_complete(encapsulated_data));
178  }
179  SECTION("Returns false when the packet is too short.")
180  {
181  heartbeat.pop_back();
182  ping.pop_back();
183  set_mode.pop_back();
184  encapsulated_data.pop_back();
185  REQUIRE_FALSE(packet_v1::packet_complete(heartbeat));
186  REQUIRE_FALSE(packet_v1::packet_complete(ping));
187  REQUIRE_FALSE(packet_v1::packet_complete(set_mode));
188  REQUIRE_FALSE(packet_v1::packet_complete(encapsulated_data));
189  }
190  SECTION("Returns false when the packet is too long.")
191  {
192  heartbeat.push_back(0x00);
193  ping.push_back(0x00);
194  set_mode.push_back(0x00);
195  encapsulated_data.push_back(0x00);
196  REQUIRE_FALSE(packet_v1::packet_complete(heartbeat));
197  REQUIRE_FALSE(packet_v1::packet_complete(ping));
198  REQUIRE_FALSE(packet_v1::packet_complete(set_mode));
199  REQUIRE_FALSE(packet_v1::packet_complete(encapsulated_data));
200  }
201 }
202 
203 
204 TEST_CASE("packet_v1::Packet's can be constructed.", "[packet_v1::Packet]")
205 {
206  HeartbeatV1 heartbeat;
207  PingV1 ping;
208  SetModeV1 set_mode;
209  EncapsulatedDataV1 encapsulated_data;
210  SECTION("With proper arguments.")
211  {
212  REQUIRE_NOTHROW(packet_v1::Packet(to_vector(heartbeat)));
213  REQUIRE_NOTHROW(packet_v1::Packet(to_vector(ping)));
214  REQUIRE_NOTHROW(packet_v1::Packet(to_vector(set_mode)));
215  REQUIRE_NOTHROW(packet_v1::Packet(to_vector(encapsulated_data)));
216  }
217  SECTION("And ensures a complete header is given.")
218  {
219  REQUIRE_THROWS_AS(packet_v1::Packet({}), std::length_error);
220  REQUIRE_THROWS_WITH(packet_v1::Packet({}), "Packet is empty.");
221  REQUIRE_THROWS_AS(
222  packet_v1::Packet({0xFE, 2, 3, 4, 5}), std::length_error);
223  REQUIRE_THROWS_WITH(
224  packet_v1::Packet({0xFE, 2, 3, 4, 5}),
225  "Packet (5 bytes) is shorter than a v1.0 header (6 bytes).");
226  }
227  SECTION("And ensures packets begins with the magic byte (0xFE).")
228  {
229  ping.magic = 0xAD;
230  REQUIRE_THROWS_AS(
231  packet_v1::Packet(to_vector(ping)), std::invalid_argument);
232  REQUIRE_THROWS_WITH(
233  packet_v1::Packet(to_vector(ping)),
234  "Invalid packet starting byte (0xAD), "
235  "v1.0 packets should start with 0xFE.");
236  }
237  SECTION("And ensures the message ID is valid.")
238  {
239  ping.msgid = 255; // ID 255 is not currently valid.
240  REQUIRE_THROWS_AS(
242  REQUIRE_THROWS_WITH(
243  packet_v1::Packet(to_vector(ping)),
244  "Packet ID (#255) is not part of the '"
245  MAVLINK_DIALECT "' MAVLink dialect.");
246  }
247  SECTION("And ensures the packet is the correct length.")
248  {
249  // HEARTBEAT (no target system/component).
250  auto heartbeat_data = to_vector(heartbeat);
251  heartbeat_data.pop_back();
252  REQUIRE_THROWS_AS(
253  packet_v1::Packet(heartbeat_data), std::length_error);
254  REQUIRE_THROWS_WITH(
255  packet_v1::Packet(heartbeat_data),
256  "Packet is 16 bytes, should be 17 bytes.");
257  // PING (with target system/component).
258  auto ping_data = to_vector(ping);
259  ping_data.push_back(0x00);
260  REQUIRE_THROWS_AS(
261  packet_v1::Packet(ping_data), std::length_error);
262  REQUIRE_THROWS_WITH(
263  packet_v1::Packet(ping_data),
264  "Packet is 23 bytes, should be 22 bytes.");
265  // SET_MODE (target system only, no target component).
266  auto set_mode_data = to_vector(set_mode);
267  set_mode_data.pop_back();
268  REQUIRE_THROWS_AS(
269  packet_v1::Packet(set_mode_data), std::length_error);
270  REQUIRE_THROWS_WITH(
271  packet_v1::Packet(set_mode_data),
272  "Packet is 13 bytes, should be 14 bytes.");
273  // ENCAPSULATED_DATA (longest packet).
274  auto encapsulated_data_data = to_vector(encapsulated_data);
275  encapsulated_data_data.push_back(0x00);
276  REQUIRE_THROWS_AS(
277  packet_v1::Packet(encapsulated_data_data), std::length_error);
278  REQUIRE_THROWS_WITH(
279  packet_v1::Packet(encapsulated_data_data),
280  "Packet is 264 bytes, should be 263 bytes.");
281  }
282 }
283 
284 
285 TEST_CASE("packet_v1::Packet's are comparable.", "[packet_v1::Packet]")
286 {
287  SECTION("with ==")
288  {
289  REQUIRE(
290  packet_v1::Packet(to_vector(PingV1())) ==
291  packet_v1::Packet(to_vector(PingV1())));
292  REQUIRE_FALSE(
293  packet_v1::Packet(to_vector(PingV1())) ==
294  packet_v1::Packet(to_vector(SetModeV1())));
295  }
296  SECTION("with !=")
297  {
298  REQUIRE(
299  packet_v1::Packet(to_vector(PingV1())) !=
300  packet_v1::Packet(to_vector(SetModeV1())));
301  REQUIRE_FALSE(
302  packet_v1::Packet(to_vector(PingV1())) !=
303  packet_v1::Packet(to_vector(PingV1())));
304  }
305 }
306 
307 
308 TEST_CASE("packet_v1::Packet's are copyable.", "[packet_v1::Packet]")
309 {
310  packet_v1::Packet original(to_vector(PingV1()));
311  packet_v1::Packet copy(original);
312  REQUIRE(copy == packet_v1::Packet(to_vector(PingV1())));
313 }
314 
315 
316 TEST_CASE("packet_v1::Packet's are movable.", "[packet_v1::Packet]")
317 {
318  packet_v1::Packet original(to_vector(PingV1()));
319  packet_v1::Packet moved(std::move(original));
320  REQUIRE(moved == packet_v1::Packet(to_vector(PingV1())));
321 }
322 
323 
324 TEST_CASE("packet_v1::Packet's are assignable.", "[Packet]")
325 {
326  packet_v1::Packet packet_a(to_vector(PingV1()));
327  packet_v1::Packet packet_b(to_vector(SetModeV1()));
328  REQUIRE(packet_a == packet_v1::Packet(to_vector(PingV1())));
329  packet_a = packet_b;
330  REQUIRE(packet_b == packet_v1::Packet(to_vector(SetModeV1())));
331 }
332 
333 
334 TEST_CASE("packet_v1::Packet's are assignable (by move semantics).", "[Packet]")
335 {
336  packet_v1::Packet packet_a(to_vector(PingV1()));
337  packet_v1::Packet packet_b(to_vector(SetModeV1()));
338  REQUIRE(packet_a == packet_v1::Packet(to_vector(PingV1())));
340  REQUIRE(packet_b == packet_v1::Packet(to_vector(SetModeV1())));
341 }
342 
343 
344 TEST_CASE("packet_v1::Packet's contain raw packet data and make it accessible.",
345  "[packet_v1::Packet]")
346 {
347  auto heartbeat = to_vector(HeartbeatV1());
348  auto ping = to_vector(PingV1());
349  auto set_mode = to_vector(SetModeV1());
350  auto encapsulated_data = to_vector(EncapsulatedDataV1());
351  REQUIRE(packet_v1::Packet(heartbeat).data() == heartbeat);
352  REQUIRE(packet_v1::Packet(ping).data() == ping);
353  REQUIRE(packet_v1::Packet(set_mode).data() == set_mode);
354  REQUIRE(packet_v1::Packet(encapsulated_data).data() == encapsulated_data);
355 }
356 
357 
358 TEST_CASE("packet_v1::Packet's have a version.", "[packet_v1::Packet]")
359 {
360  auto heartbeat = to_vector(HeartbeatV1());
361  auto ping = to_vector(PingV1());
362  auto set_mode = to_vector(SetModeV1());
363  auto encapsulated_data = to_vector(EncapsulatedDataV1());
364  // All should read 0x0100 for v1.0.
365  REQUIRE(packet_v1::Packet(heartbeat).version() == Packet::V1);
366  REQUIRE(packet_v1::Packet(ping).version() == Packet::V1);
367  REQUIRE(packet_v1::Packet(set_mode).version() == 0x100);
368  REQUIRE(packet_v1::Packet(encapsulated_data).version() == 0x100);
369 }
370 
371 
372 TEST_CASE("packet_v1::Packet's have an ID.", "[packet_v1::Packet]")
373 {
374  auto heartbeat = to_vector(HeartbeatV1());
375  auto ping = to_vector(PingV1());
376  auto set_mode = to_vector(SetModeV1());
377  auto encapsulated_data = to_vector(EncapsulatedDataV1());
378  REQUIRE(packet_v1::Packet(heartbeat).id() == 0);
379  REQUIRE(packet_v1::Packet(ping).id() == 4);
380  REQUIRE(packet_v1::Packet(set_mode).id() == 11);
381  REQUIRE(packet_v1::Packet(encapsulated_data).id() == 131);
382 }
383 
384 
385 TEST_CASE("packet_v1::Packet's have a name.", "[packet_v1::Packet]")
386 {
387  auto heartbeat = to_vector(HeartbeatV1());
388  auto ping = to_vector(PingV1());
389  auto set_mode = to_vector(SetModeV1());
390  auto encapsulated_data = to_vector(EncapsulatedDataV1());
391  REQUIRE(packet_v1::Packet(heartbeat).name() == "HEARTBEAT");
392  REQUIRE(packet_v1::Packet(ping).name() == "PING");
393  REQUIRE(packet_v1::Packet(set_mode).name() == "SET_MODE");
394  REQUIRE(packet_v1::Packet(encapsulated_data).name() == "ENCAPSULATED_DATA");
395 }
396 
397 
398 TEST_CASE("packet_v1::Packet's have a source address.", "[packet_v1::Packet]")
399 {
400  auto heartbeat = to_vector(HeartbeatV1());
401  auto ping = to_vector(PingV1());
402  auto set_mode = to_vector(SetModeV1());
403  auto encapsulated_data = to_vector(EncapsulatedDataV1());
404  REQUIRE(packet_v1::Packet(heartbeat).source() == MAVAddress("127.1"));
405  REQUIRE(packet_v1::Packet(ping).source() == MAVAddress("192.168"));
406  REQUIRE(packet_v1::Packet(set_mode).source() == MAVAddress("172.0"));
407  REQUIRE(
408  packet_v1::Packet(encapsulated_data).source() == MAVAddress("224.255"));
409 }
410 
411 
412 TEST_CASE("packet_v1::Packet's optionally have a destination address.",
413  "[packet_v1::Packet]")
414 {
415  auto heartbeat = to_vector(HeartbeatV1());
416  auto ping = to_vector(PingV1());
417  auto set_mode = to_vector(SetModeV1());
418  auto encapsulated_data = to_vector(EncapsulatedDataV1());
419  REQUIRE_THROWS_AS(
420  packet_v1::Packet(heartbeat).dest().value(), std::bad_optional_access);
421  REQUIRE(packet_v1::Packet(ping).dest().value() == MAVAddress("127.1"));
422  REQUIRE(packet_v1::Packet(set_mode).dest().value() == MAVAddress("123.0"));
423  REQUIRE_THROWS_AS(
424  packet_v1::Packet(encapsulated_data).dest().value(),
425  std::bad_optional_access);
426 }
427 
428 
429 TEST_CASE("packet_v1::Packet's optionally have a source connection.",
430  "[packet_v1::Packet]")
431 {
432  auto heartbeat = packet_v1::Packet(to_vector(HeartbeatV1()));
433  SECTION("Defaults to nullptr.")
434  {
435  REQUIRE(heartbeat.connection() == nullptr);
436  }
437  SECTION("Can be set with the 'connection' method.")
438  {
439  fakeit::Mock<Filter> mock_filter;
440  auto filter = mock_shared(mock_filter);
441  auto conn = std::make_shared<Connection>("SOURCE", filter);
442  heartbeat.connection(conn);
443  REQUIRE(heartbeat.connection() != nullptr);
444  REQUIRE(heartbeat.connection() == conn);
445  REQUIRE(str(*heartbeat.connection()) == "SOURCE");
446  }
447 }
448 
449 
450 TEST_CASE("packet_v1::Packet's are printable.", "[packet_v1::Packet]")
451 {
452  auto heartbeat = to_vector(HeartbeatV1());
453  auto ping = to_vector(PingV1());
454  auto set_mode = to_vector(SetModeV1());
455  auto encapsulated_data = to_vector(EncapsulatedDataV1());
456  REQUIRE(
458  "HEARTBEAT (#0) from 127.1 (v1.0)");
459  REQUIRE(
461  "PING (#4) from 192.168 to 127.1 (v1.0)");
462  REQUIRE(
463  str(packet_v1::Packet(set_mode)) ==
464  "SET_MODE (#11) from 172.0 to 123.0 (v1.0)");
465  REQUIRE(
466  str(packet_v1::Packet(encapsulated_data)) ==
467  "ENCAPSULATED_DATA (#131) from 224.255 (v1.0)");
468 }
std::string str(const T &object)
Definition: utility.hpp:128
TEST_CASE("'packet_v1::header_complete' determines whether the given bytes " "at least represent a complete header.", "[packet_v1]")
def heartbeat(mav)
Definition: logger.py:42
std::shared_ptr< T > mock_shared(fakeit::Mock< T > &mock)
Definition: common.hpp:33
auto ping
Definition: test_Call.cpp:229
bool header_complete(const std::vector< uint8_t > &data)
packet_v1::Packet packet_b(to_vector(SetModeV1()))
const struct mavlink::v1_header * header(const std::vector< uint8_t > &data)
MAVLink Version 1.0.
Definition: Packet.hpp:49
bool packet_complete(const std::vector< uint8_t > &data)