blob: 350abf6b67aad403e20f181961741c13171ac9f8 [file] [log] [blame]
Alexander Afanasyevc169a812014-05-20 20:37:29 -04001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
Davide Pesaventoa84f4642017-08-23 16:14:51 -04002/*
Davide Pesavento0c526032024-01-31 21:14:01 -05003 * Copyright (c) 2013-2024 Regents of the University of California.
Alexander Afanasyevdfa52c42014-04-24 21:10:11 -07004 *
5 * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
Alexander Afanasyevdfa52c42014-04-24 21:10:11 -07006 *
Alexander Afanasyevc169a812014-05-20 20:37:29 -04007 * ndn-cxx library is free software: you can redistribute it and/or modify it under the
8 * terms of the GNU Lesser General Public License as published by the Free Software
9 * Foundation, either version 3 of the License, or (at your option) any later version.
10 *
11 * ndn-cxx library is distributed in the hope that it will be useful, but WITHOUT ANY
12 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
13 * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
14 *
15 * You should have received copies of the GNU General Public License and GNU Lesser
16 * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see
17 * <http://www.gnu.org/licenses/>.
18 *
19 * See AUTHORS.md for complete list of ndn-cxx authors and contributors.
Yingdi Yuf50098d2014-02-26 14:26:29 -080020 */
21
Davide Pesavento7e780642018-11-24 15:51:34 -050022#include "ndn-cxx/util/io.hpp"
Yingdi Yuf50098d2014-02-26 14:26:29 -080023
Davide Pesavento7e780642018-11-24 15:51:34 -050024#include "tests/boost-test.hpp"
Davide Pesavento4c1ad4c2020-11-16 21:12:02 -050025#include "tests/key-chain-fixture.hpp"
Davide Pesaventoa84f4642017-08-23 16:14:51 -040026
Davide Pesavento49e1e872023-11-11 00:45:23 -050027#include <boost/mp11/list.hpp>
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -070028
Davide Pesavento51974f62024-12-21 20:42:45 -050029#include <filesystem>
30#include <system_error>
31
Davide Pesavento47ce2ee2023-05-09 01:33:33 -040032namespace ndn::tests {
Yingdi Yuf50098d2014-02-26 14:26:29 -080033
Davide Pesavento6c6e3852019-08-05 20:20:35 -040034BOOST_AUTO_TEST_SUITE(Util)
35BOOST_AUTO_TEST_SUITE(TestIo)
36
37struct NoEncoding
38{
Davide Pesavento0c526032024-01-31 21:14:01 -050039 static constexpr io::IoEncoding encoding = io::NO_ENCODING;
40 static inline const std::vector<uint8_t> blob{0xd1, 0x0, 0xb0, 0x1a};
Davide Pesavento6c6e3852019-08-05 20:20:35 -040041 std::istringstream stream{std::string("\xd1\x00\xb0\x1a", 4), std::ios_base::binary};
42};
43
44struct Base64Encoding
45{
Davide Pesavento0c526032024-01-31 21:14:01 -050046 static constexpr io::IoEncoding encoding = io::BASE64;
47 static inline const std::vector<uint8_t> blob{0x42, 0x61, 0x73, 0x65, 0x36, 0x34, 0x45, 0x6e, 0x63};
Davide Pesavento6c6e3852019-08-05 20:20:35 -040048 std::istringstream stream{"QmFzZTY0RW5j\n", std::ios_base::binary};
49};
50
51struct HexEncoding
52{
Davide Pesavento0c526032024-01-31 21:14:01 -050053 static constexpr io::IoEncoding encoding = io::HEX;
54 static inline const std::vector<uint8_t> blob{0x48, 0x65, 0x78, 0x45, 0x6e, 0x63};
Davide Pesavento6c6e3852019-08-05 20:20:35 -040055 std::istringstream stream{"486578456E63", std::ios_base::binary};
56};
57
Davide Pesavento49e1e872023-11-11 00:45:23 -050058using Encodings = boost::mp11::mp_list<NoEncoding, Base64Encoding, HexEncoding>;
Davide Pesavento6c6e3852019-08-05 20:20:35 -040059
60BOOST_AUTO_TEST_CASE_TEMPLATE(LoadBuffer, T, Encodings)
61{
62 T t;
Davide Pesavento0c526032024-01-31 21:14:01 -050063 shared_ptr<Buffer> buf = io::loadBuffer(t.stream, T::encoding);
64 BOOST_CHECK_EQUAL_COLLECTIONS(buf->begin(), buf->end(), T::blob.begin(), T::blob.end());
Davide Pesavento6c6e3852019-08-05 20:20:35 -040065}
66
67BOOST_AUTO_TEST_CASE_TEMPLATE(SaveBuffer, T, Encodings)
68{
69 T t;
70 std::ostringstream os(std::ios_base::binary);
Davide Pesavento0c526032024-01-31 21:14:01 -050071 io::saveBuffer(T::blob, os, T::encoding);
Davide Pesavento6c6e3852019-08-05 20:20:35 -040072 BOOST_CHECK_EQUAL(os.str(), t.stream.str());
73}
74
75BOOST_AUTO_TEST_CASE(LoadBufferException)
76{
77 std::ifstream in("this-file-does-not-exist", std::ios_base::binary);
78 BOOST_CHECK_THROW(io::loadBuffer(in, io::NO_ENCODING), io::Error);
79}
80
81BOOST_AUTO_TEST_CASE(SaveBufferException)
82{
83 class NullStreambuf : public std::streambuf
84 {
85 };
86
87 NullStreambuf nullbuf;
88 std::ostream out(&nullbuf);
89 const Buffer buffer(1);
Davide Pesaventofbea4fc2022-02-08 07:26:04 -050090 BOOST_CHECK_THROW(io::saveBuffer(buffer, out, io::NO_ENCODING), io::Error);
Davide Pesavento6c6e3852019-08-05 20:20:35 -040091}
92
93BOOST_AUTO_TEST_CASE(UnknownIoEncoding)
94{
95 std::stringstream ss;
Davide Pesavento949075a2021-10-17 22:07:07 -040096 BOOST_CHECK_THROW(io::loadTlv<Name>(ss, static_cast<io::IoEncoding>(5)), std::invalid_argument);
Davide Pesavento6c6e3852019-08-05 20:20:35 -040097 BOOST_CHECK_THROW(io::loadBuffer(ss, static_cast<io::IoEncoding>(5)), std::invalid_argument);
Davide Pesaventofbea4fc2022-02-08 07:26:04 -050098 BOOST_CHECK_THROW(io::saveBuffer({}, ss, static_cast<io::IoEncoding>(5)), std::invalid_argument);
Davide Pesavento6c6e3852019-08-05 20:20:35 -040099}
100
101class FileIoFixture
Yingdi Yuf50098d2014-02-26 14:26:29 -0800102{
Junxiao Shic1779882016-08-17 01:59:23 +0000103protected:
Davide Pesavento6c6e3852019-08-05 20:20:35 -0400104 FileIoFixture()
Junxiao Shic1779882016-08-17 01:59:23 +0000105 {
Davide Pesavento51974f62024-12-21 20:42:45 -0500106 std::filesystem::create_directories(filename.parent_path());
Junxiao Shic1779882016-08-17 01:59:23 +0000107 }
108
Davide Pesavento6c6e3852019-08-05 20:20:35 -0400109 ~FileIoFixture()
Junxiao Shic1779882016-08-17 01:59:23 +0000110 {
Davide Pesavento51974f62024-12-21 20:42:45 -0500111 std::error_code ec;
112 std::filesystem::remove(filename, ec); // ignore error
Junxiao Shic1779882016-08-17 01:59:23 +0000113 }
114
Davide Pesavento949075a2021-10-17 22:07:07 -0400115 /**
Davide Pesavento51974f62024-12-21 20:42:45 -0500116 * \brief Create a directory at `filename`, so that it's neither readable nor writable as a file.
Junxiao Shic1779882016-08-17 01:59:23 +0000117 */
118 void
119 mkdir() const
120 {
Davide Pesavento51974f62024-12-21 20:42:45 -0500121 std::filesystem::create_directory(filename);
Junxiao Shic1779882016-08-17 01:59:23 +0000122 }
123
Davide Pesavento6c6e3852019-08-05 20:20:35 -0400124 template<typename Container>
Junxiao Shic1779882016-08-17 01:59:23 +0000125 Container
126 readFile() const
127 {
128 Container container;
129 std::ifstream fs(filename, std::ios_base::binary);
Davide Pesavento6c6e3852019-08-05 20:20:35 -0400130 BOOST_REQUIRE_MESSAGE(fs, "error opening file");
Junxiao Shic1779882016-08-17 01:59:23 +0000131 char ch;
132 while (fs.get(ch)) {
Davide Pesavento6c6e3852019-08-05 20:20:35 -0400133 container.push_back(static_cast<typename Container::value_type>(ch));
Junxiao Shic1779882016-08-17 01:59:23 +0000134 }
135 return container;
136 }
137
Davide Pesavento6c6e3852019-08-05 20:20:35 -0400138 template<typename Container>
Junxiao Shic1779882016-08-17 01:59:23 +0000139 void
140 writeFile(const Container& content) const
141 {
142 std::ofstream fs(filename, std::ios_base::binary);
Davide Pesavento6c6e3852019-08-05 20:20:35 -0400143 BOOST_REQUIRE_MESSAGE(fs, "error opening file");
144 for (auto ch : content) {
Junxiao Shic1779882016-08-17 01:59:23 +0000145 fs.put(static_cast<char>(ch));
146 }
Junxiao Shic1779882016-08-17 01:59:23 +0000147 BOOST_REQUIRE_MESSAGE(fs, "error writing file");
148 }
149
150protected:
Davide Pesavento51974f62024-12-21 20:42:45 -0500151 const std::filesystem::path filename{std::filesystem::path(UNIT_TESTS_TMPDIR) / "TestIo"};
Junxiao Shic1779882016-08-17 01:59:23 +0000152};
153
Davide Pesavento6c6e3852019-08-05 20:20:35 -0400154BOOST_FIXTURE_TEST_SUITE(FileIo, FileIoFixture)
Junxiao Shic1779882016-08-17 01:59:23 +0000155
156class EncodableType
157{
158public:
Junxiao Shic1779882016-08-17 01:59:23 +0000159 Block
160 wireEncode() const
161 {
162 if (shouldThrow) {
Davide Pesavento923ba442019-02-12 22:00:38 -0500163 NDN_THROW(tlv::Error("encode error"));
Junxiao Shic1779882016-08-17 01:59:23 +0000164 }
165
166 // block will be 0xAA, 0x01, 0xDD
167 return makeNonNegativeIntegerBlock(0xAA, 0xDD);
168 }
169
170public:
171 bool shouldThrow = false;
172};
173
Davide Pesavento949075a2021-10-17 22:07:07 -0400174class DecodableType
Junxiao Shic1779882016-08-17 01:59:23 +0000175{
176public:
Davide Pesavento949075a2021-10-17 22:07:07 -0400177 DecodableType() = default;
Junxiao Shi435bb552016-09-04 03:14:47 +0000178
179 explicit
Davide Pesavento949075a2021-10-17 22:07:07 -0400180 DecodableType(const Block& block)
Junxiao Shic1779882016-08-17 01:59:23 +0000181 {
Davide Pesavento949075a2021-10-17 22:07:07 -0400182 wireDecode(block);
Junxiao Shi435bb552016-09-04 03:14:47 +0000183 }
Junxiao Shic1779882016-08-17 01:59:23 +0000184
185 void
Junxiao Shi435bb552016-09-04 03:14:47 +0000186 wireDecode(const Block& block)
Junxiao Shic1779882016-08-17 01:59:23 +0000187 {
Davide Pesavento258d51a2022-02-27 21:26:28 -0500188 BOOST_TEST(block == "BB01EE"_block);
Junxiao Shic1779882016-08-17 01:59:23 +0000189 }
Junxiao Shic1779882016-08-17 01:59:23 +0000190};
191
Davide Pesavento949075a2021-10-17 22:07:07 -0400192class DecodableTypeThrow
193{
194public:
195 DecodableTypeThrow() = default;
196
197 explicit
198 DecodableTypeThrow(const Block& block)
199 {
200 wireDecode(block);
201 }
202
203 void
204 wireDecode(const Block&)
205 {
206 NDN_THROW(tlv::Error("decode error"));
207 }
208};
Junxiao Shic1779882016-08-17 01:59:23 +0000209
210BOOST_AUTO_TEST_CASE(LoadNoEncoding)
211{
212 this->writeFile<std::vector<uint8_t>>({0xBB, 0x01, 0xEE});
213 shared_ptr<DecodableType> decoded = io::load<DecodableType>(filename, io::NO_ENCODING);
214 BOOST_CHECK(decoded != nullptr);
Davide Pesavento949075a2021-10-17 22:07:07 -0400215
216 std::ifstream ifs(filename);
217 BOOST_CHECK_NO_THROW(io::loadTlv<DecodableType>(ifs, io::NO_ENCODING));
Junxiao Shic1779882016-08-17 01:59:23 +0000218}
219
220BOOST_AUTO_TEST_CASE(LoadBase64)
221{
222 this->writeFile<std::string>("uwHu\n"); // printf '\xBB\x01\xEE' | base64
Junxiao Shi4ce0bcf2016-09-03 07:09:03 +0000223 shared_ptr<DecodableType> decoded = io::load<DecodableType>(filename, io::BASE64);
224 BOOST_CHECK(decoded != nullptr);
Davide Pesavento949075a2021-10-17 22:07:07 -0400225
226 std::ifstream ifs(filename);
227 BOOST_CHECK_NO_THROW(io::loadTlv<DecodableType>(ifs, io::BASE64));
Junxiao Shi4ce0bcf2016-09-03 07:09:03 +0000228}
229
230BOOST_AUTO_TEST_CASE(LoadBase64Newline64)
231{
232 this->writeFile<std::string>(
233 "CEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
234 "AAAAAAAAAAAA\n");
235 // printf '\x08\x40\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00
236 // \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00
237 // \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00
238 // \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' | base64
239 shared_ptr<name::Component> decoded = io::load<name::Component>(filename, io::BASE64);
240 BOOST_CHECK(decoded != nullptr);
Davide Pesavento949075a2021-10-17 22:07:07 -0400241
242 std::ifstream ifs(filename);
243 BOOST_CHECK_NO_THROW(io::loadTlv<name::Component>(ifs, io::BASE64));
Junxiao Shi4ce0bcf2016-09-03 07:09:03 +0000244}
245
246BOOST_AUTO_TEST_CASE(LoadBase64Newline32)
247{
248 this->writeFile<std::string>(
249 "CEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
250 "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
251 "AAAAAAAAAAAA\n");
252 shared_ptr<name::Component> decoded = io::load<name::Component>(filename, io::BASE64);
253 BOOST_CHECK(decoded != nullptr);
Davide Pesavento949075a2021-10-17 22:07:07 -0400254
255 std::ifstream ifs(filename);
256 BOOST_CHECK_NO_THROW(io::loadTlv<name::Component>(ifs, io::BASE64));
Junxiao Shi4ce0bcf2016-09-03 07:09:03 +0000257}
258
259BOOST_AUTO_TEST_CASE(LoadBase64NewlineEnd)
260{
261 this->writeFile<std::string>(
262 "CEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n");
263 shared_ptr<name::Component> decoded = io::load<name::Component>(filename, io::BASE64);
264 BOOST_CHECK(decoded != nullptr);
Davide Pesavento949075a2021-10-17 22:07:07 -0400265
266 std::ifstream ifs(filename);
267 BOOST_CHECK_NO_THROW(io::loadTlv<name::Component>(ifs, io::BASE64));
Junxiao Shi4ce0bcf2016-09-03 07:09:03 +0000268}
269
270BOOST_AUTO_TEST_CASE(LoadBase64NoNewline)
271{
272 this->writeFile<std::string>(
273 "CEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA");
274 shared_ptr<name::Component> decoded = io::load<name::Component>(filename, io::BASE64);
Junxiao Shic1779882016-08-17 01:59:23 +0000275 BOOST_CHECK(decoded != nullptr);
Davide Pesavento949075a2021-10-17 22:07:07 -0400276
277 std::ifstream ifs(filename);
278 BOOST_CHECK_NO_THROW(io::loadTlv<name::Component>(ifs, io::BASE64));
Junxiao Shic1779882016-08-17 01:59:23 +0000279}
280
281BOOST_AUTO_TEST_CASE(LoadHex)
282{
283 this->writeFile<std::string>("BB01EE");
284 shared_ptr<DecodableType> decoded = io::load<DecodableType>(filename, io::HEX);
285 BOOST_CHECK(decoded != nullptr);
Davide Pesavento949075a2021-10-17 22:07:07 -0400286
287 std::ifstream ifs(filename);
288 BOOST_CHECK_NO_THROW(io::loadTlv<DecodableType>(ifs, io::HEX));
Junxiao Shic1779882016-08-17 01:59:23 +0000289}
290
Davide Pesavento949075a2021-10-17 22:07:07 -0400291BOOST_AUTO_TEST_CASE(LoadDecodeException)
Junxiao Shic1779882016-08-17 01:59:23 +0000292{
293 this->writeFile<std::vector<uint8_t>>({0xBB, 0x01, 0xEE});
294 shared_ptr<DecodableTypeThrow> decoded;
295 BOOST_CHECK_NO_THROW(decoded = io::load<DecodableTypeThrow>(filename, io::NO_ENCODING));
296 BOOST_CHECK(decoded == nullptr);
Davide Pesavento949075a2021-10-17 22:07:07 -0400297
298 std::ifstream ifs(filename);
299 BOOST_CHECK_THROW(io::loadTlv<DecodableTypeThrow>(ifs, io::NO_ENCODING), io::Error);
Junxiao Shic1779882016-08-17 01:59:23 +0000300}
301
302BOOST_AUTO_TEST_CASE(LoadNotHex)
303{
304 this->writeFile<std::string>("not-hex");
305 shared_ptr<DecodableType> decoded;
306 BOOST_CHECK_NO_THROW(decoded = io::load<DecodableType>(filename, io::HEX));
307 BOOST_CHECK(decoded == nullptr);
Davide Pesavento949075a2021-10-17 22:07:07 -0400308
309 std::ifstream ifs(filename);
310 BOOST_CHECK_THROW(io::loadTlv<DecodableType>(ifs, io::HEX), io::Error);
311}
312
313BOOST_AUTO_TEST_CASE(LoadEmpty)
314{
315 this->writeFile<std::vector<uint8_t>>({});
316 shared_ptr<DecodableType> decoded;
317 BOOST_CHECK_NO_THROW(decoded = io::load<DecodableType>(filename, io::NO_ENCODING));
318 BOOST_CHECK(decoded == nullptr);
319
320 std::ifstream ifs(filename);
321 BOOST_CHECK_THROW(io::loadTlv<DecodableType>(ifs, io::NO_ENCODING), io::Error);
Junxiao Shic1779882016-08-17 01:59:23 +0000322}
323
324BOOST_AUTO_TEST_CASE(LoadFileNotReadable)
325{
Junxiao Shic1779882016-08-17 01:59:23 +0000326 shared_ptr<DecodableType> decoded;
327 BOOST_CHECK_NO_THROW(decoded = io::load<DecodableType>(filename, io::NO_ENCODING));
328 BOOST_CHECK(decoded == nullptr);
329}
330
331BOOST_AUTO_TEST_CASE(SaveNoEncoding)
332{
333 EncodableType encoded;
334 BOOST_CHECK_NO_THROW(io::save(encoded, filename, io::NO_ENCODING));
335 auto content = this->readFile<std::vector<uint8_t>>();
336 uint8_t expected[] = {0xAA, 0x01, 0xDD};
337 BOOST_CHECK_EQUAL_COLLECTIONS(content.begin(), content.end(),
338 expected, expected + sizeof(expected));
339}
340
341BOOST_AUTO_TEST_CASE(SaveBase64)
342{
343 EncodableType encoded;
Junxiao Shi4ce0bcf2016-09-03 07:09:03 +0000344 BOOST_CHECK_NO_THROW(io::save(encoded, filename, io::BASE64));
Junxiao Shic1779882016-08-17 01:59:23 +0000345 auto content = this->readFile<std::string>();
346 BOOST_CHECK_EQUAL(content, "qgHd\n"); // printf '\xAA\x01\xDD' | base64
347}
348
349BOOST_AUTO_TEST_CASE(SaveHex)
350{
351 EncodableType encoded;
352 BOOST_CHECK_NO_THROW(io::save(encoded, filename, io::HEX));
353 auto content = this->readFile<std::string>();
354 BOOST_CHECK_EQUAL(content, "AA01DD");
355}
356
357BOOST_AUTO_TEST_CASE(SaveException)
358{
359 EncodableType encoded;
360 encoded.shouldThrow = true;
361 BOOST_CHECK_THROW(io::save(encoded, filename, io::NO_ENCODING), io::Error);
362}
363
364BOOST_AUTO_TEST_CASE(SaveFileNotWritable)
365{
366 this->mkdir();
367 EncodableType encoded;
368 encoded.shouldThrow = true;
369 BOOST_CHECK_THROW(io::save(encoded, filename, io::NO_ENCODING), io::Error);
370}
371
Davide Pesavento6c6e3852019-08-05 20:20:35 -0400372BOOST_AUTO_TEST_SUITE_END() // FileIo
373
374class IdCertFixture : public FileIoFixture
Davide Pesavento4c1ad4c2020-11-16 21:12:02 -0500375 , public KeyChainFixture
Junxiao Shic1779882016-08-17 01:59:23 +0000376{
377};
378
379BOOST_FIXTURE_TEST_CASE(IdCert, IdCertFixture)
380{
Davide Pesavento4c1ad4c2020-11-16 21:12:02 -0500381 auto identity = m_keyChain.createIdentity("/TestIo/IdCert", RsaKeyParams());
Davide Pesaventod09d52b2023-02-15 14:15:06 -0500382 auto key = identity.getDefaultKey();
383 const auto& cert = key.getDefaultCertificate();
Alexander Afanasyev70244f42017-01-04 12:47:12 -0800384 io::save(cert, filename);
Yingdi Yuf50098d2014-02-26 14:26:29 -0800385
Davide Pesavento4c1ad4c2020-11-16 21:12:02 -0500386 auto readCert = io::load<security::Certificate>(filename);
Yingdi Yuf50098d2014-02-26 14:26:29 -0800387
Junxiao Shi4ce0bcf2016-09-03 07:09:03 +0000388 BOOST_REQUIRE(readCert != nullptr);
Alexander Afanasyev70244f42017-01-04 12:47:12 -0800389 BOOST_CHECK_EQUAL(cert.getName(), readCert->getName());
Ashlesh Gawandee84d1eb2018-01-04 20:46:44 -0600390
391 this->writeFile<std::string>("");
Davide Pesavento4c1ad4c2020-11-16 21:12:02 -0500392 readCert = io::load<security::Certificate>(filename);
Ashlesh Gawandee84d1eb2018-01-04 20:46:44 -0600393 BOOST_REQUIRE(readCert == nullptr);
Yingdi Yuf50098d2014-02-26 14:26:29 -0800394}
395
Junxiao Shic1779882016-08-17 01:59:23 +0000396BOOST_AUTO_TEST_SUITE_END() // TestIo
397BOOST_AUTO_TEST_SUITE_END() // Util
Yingdi Yuf50098d2014-02-26 14:26:29 -0800398
Davide Pesavento47ce2ee2023-05-09 01:33:33 -0400399} // namespace ndn::tests