mavtables  0.2.1
MAVLink router and firewall.
test_PacketParser.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 <cstdint>
19 #include <memory>
20 #include <optional>
21 #include <stdexcept>
22 #include <utility>
23 #include <vector>
24 
25 #include <boost/range/irange.hpp>
26 #include <catch.hpp>
27 
28 #include "config.hpp"
29 #include "Packet.hpp"
30 #include "PacketParser.hpp"
31 #include "PacketVersion1.hpp"
32 #include "PacketVersion2.hpp"
33 
34 #include "common.hpp"
35 #include "common_Packet.hpp"
36 
37 
38 namespace
39 {
40 
41  // Forward defines of local functions.
42  std::unique_ptr<Packet> test_packet_parser(PacketParser &parser,
43  const std::vector<uint8_t> &data, size_t packet_end);
44  void add_bytes(std::vector<uint8_t> &data, size_t num_bytes);
45 
46 
47  /** Test a PacketParser instance on data.
48  *
49  * Uses the REQUIRE macro from Catch C++ internally for testing.
50  *
51  * \param parser The instance of the packet parser to use.
52  * \param data The data to give to the parser.
53  * \param packet_end The byte (1 indexed) that the packet is supposed to
54  * end on.
55  *
56  * \returns The packet parsed from the given \p data.
57  */
58  std::unique_ptr<Packet> test_packet_parser(PacketParser &parser,
59  const std::vector<uint8_t> &data, size_t packet_end)
60  {
61  std::unique_ptr<Packet> packet;
62 
63  for (auto i : boost::irange(static_cast<size_t>(0), packet_end - 1))
64  {
65  REQUIRE(parser.parse_byte(data[i]) == nullptr);
66  }
67 
68  REQUIRE((packet = parser.parse_byte(data[packet_end - 1])) != nullptr);
69 
70  for (auto i : boost::irange(packet_end, data.size()))
71  {
72  REQUIRE(parser.parse_byte(data[i]) == nullptr);
73  }
74 
75  return packet;
76  }
77 
78 
79  /** Add bytes to either side of a vector.
80  *
81  * Used for testing.
82  *
83  * \param data A reference to the vector to modify.
84  * \param num_bytes Number of bytes to add on either end the \p data
85  * vector.
86  */
87  void add_bytes(std::vector<uint8_t> &data, size_t num_bytes)
88  {
89  for (auto i : boost::irange(static_cast<size_t>(0), num_bytes))
90  {
91  data.insert(data.begin(), static_cast<uint8_t>(i));
92  }
93 
94  for (auto i : boost::irange(static_cast<size_t>(0), num_bytes))
95  {
96  data.push_back(static_cast<uint8_t>(i));
97  }
98  }
99 
100 }
101 
102 
103 TEST_CASE("PacketParser's can be constructed.", "[PacketParser]")
104 {
105  REQUIRE_NOTHROW(PacketParser());
106 }
107 
108 
109 TEST_CASE("PacketParser's can parse packets with 'parse_byte'.",
110  "[PacketParser]")
111 {
112  PacketParser parser;
113  SECTION("Can parse v1.0 packets.")
114  {
115  auto data = to_vector(PingV1());
116  add_bytes(data, 3);
117  auto packet = test_packet_parser(parser, data, sizeof(PingV1) + 3);
118  REQUIRE(*packet == packet_v1::Packet(to_vector(PingV1())));
119  }
120  SECTION("Can parse v2.0 packets.")
121  {
122  auto data = to_vector(PingV2());
123  add_bytes(data, 3);
124  auto packet = test_packet_parser(parser, data, sizeof(PingV2) + 3);
125  REQUIRE(*packet == packet_v2::Packet(to_vector(PingV2())));
126  }
127  SECTION("Can parse v2.0 packets with signature.")
128  {
129  auto data = to_vector_with_sig(PingV2());
130  add_bytes(data, 3);
131  auto packet = test_packet_parser(
132  parser, data,
133  sizeof(PingV2) + packet_v2::SIGNATURE_LENGTH + 3);
134  REQUIRE(*packet == packet_v2::Packet(to_vector_with_sig(PingV2())));
135  }
136  SECTION("Prints error and clears buffer if message ID is invalid.")
137  {
138  // std::stringstream buffer;
139  // std::streambuf *sbuf = std::cerr.rdbuf();
140  // std::cerr.rdbuf(buffer.rdbuf());
141  MockCErr mock_cerr;
142  auto data = to_vector(PingV1());
143  data[5] = 255;
144  std::unique_ptr<Packet> packet;
145 
146  for (auto byte : data)
147  {
148  packet = parser.parse_byte(byte);
149  }
150 
151  REQUIRE(packet == nullptr);
152  REQUIRE(
153  mock_cerr.buffer() ==
154  "Packet ID (#255) is not part of the '"
155  MAVLINK_DIALECT "' MAVLink dialect.\n");
156  REQUIRE(parser.bytes_parsed() == 0);
157  // std::cerr.rdbuf(sbuf);
158  }
159  SECTION("Can parse multiple packets back to back.")
160  {
161  auto data1 = to_vector(PingV1());
162  auto data2 = to_vector(PingV2());
163  auto data3 = to_vector_with_sig(PingV2());
164  auto packet1 = test_packet_parser(parser, data1, sizeof(PingV1));
165  auto packet2 = test_packet_parser(parser, data2, sizeof(PingV2));
166  auto packet3 = test_packet_parser(
167  parser, data3,
168  sizeof(PingV2) + packet_v2::SIGNATURE_LENGTH);
169  REQUIRE(*packet1 == packet_v1::Packet(to_vector(PingV1())));
170  REQUIRE(*packet2 == packet_v2::Packet(to_vector(PingV2())));
171  REQUIRE(*packet3 == packet_v2::Packet(to_vector_with_sig(PingV2())));
172  }
173  SECTION("Can parse multiple packets with random bytes interspersed.")
174  {
175  auto data1 = to_vector(PingV1());
176  auto data2 = to_vector(PingV2());
177  auto data3 = to_vector_with_sig(PingV2());
178  add_bytes(data1, 3);
179  add_bytes(data2, 3);
180  add_bytes(data3, 3);
181  auto packet1 = test_packet_parser(parser, data1, sizeof(PingV1) + 3);
182  auto packet2 = test_packet_parser(parser, data2, sizeof(PingV2) + 3);
183  auto packet3 = test_packet_parser(
184  parser, data3,
185  sizeof(PingV2) + packet_v2::SIGNATURE_LENGTH + 3);
186  REQUIRE(*packet1 == packet_v1::Packet(to_vector(PingV1())));
187  REQUIRE(*packet2 == packet_v2::Packet(to_vector(PingV2())));
188  REQUIRE(*packet3 == packet_v2::Packet(to_vector_with_sig(PingV2())));
189  }
190 }
191 
192 
193 TEST_CASE("PacketParser's can be cleared with 'clear'.", "[PacketParser]")
194 {
195  PacketParser parser;
196  parser.parse_byte(0xFE);
197  parser.parse_byte(14);
198  parser.parse_byte(3);
199  parser.clear();
200  auto data = to_vector(PingV1());
201  auto packet = test_packet_parser(parser, data, sizeof(PingV1));
202  REQUIRE(*packet == packet_v1::Packet(to_vector(PingV1())));
203 }
204 
205 
206 TEST_CASE("PacketParser's keep track of how many bytes they have parsed of "
207  "the current packet.", "[PacketParser]")
208 {
209  PacketParser parser;
210  REQUIRE(parser.bytes_parsed() == 0);
211  parser.parse_byte(1);
212  REQUIRE(parser.bytes_parsed() == 0);
213  parser.parse_byte(2);
214  REQUIRE(parser.bytes_parsed() == 0);
215  parser.parse_byte(3);
216  REQUIRE(parser.bytes_parsed() == 0);
217  parser.parse_byte(0xFD);
218  REQUIRE(parser.bytes_parsed() == 1);
219  parser.parse_byte(14);
220  REQUIRE(parser.bytes_parsed() == 2);
221  parser.parse_byte(3);
222  REQUIRE(parser.bytes_parsed() == 3);
223  parser.clear();
224  REQUIRE(parser.bytes_parsed() == 0);
225  parser.parse_byte(1);
226  REQUIRE(parser.bytes_parsed() == 0);
227 }
TEST_CASE("PacketParser's can be constructed.", "[PacketParser]")
std::string buffer()
Definition: common.hpp:114
size_t bytes_parsed() const
const size_t SIGNATURE_LENGTH
std::unique_ptr< Packet > parse_byte(uint8_t byte)