blob: 9340279981dee13fa73450d86055ed5f418c1241 [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 Pesavento923ba442019-02-12 22:00:38 -05003 * Copyright (c) 2013-2019 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"
25#include "tests/identity-management-fixture.hpp"
Davide Pesaventoa84f4642017-08-23 16:14:51 -040026
Junxiao Shic1779882016-08-17 01:59:23 +000027#include <boost/filesystem.hpp>
Davide Pesavento6c6e3852019-08-05 20:20:35 -040028#include <boost/mpl/vector.hpp>
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -070029
Yingdi Yuf50098d2014-02-26 14:26:29 -080030namespace ndn {
Spyridon Mastorakis429634f2015-02-19 17:35:33 -080031namespace tests {
Yingdi Yuf50098d2014-02-26 14:26:29 -080032
Davide Pesavento6c6e3852019-08-05 20:20:35 -040033BOOST_AUTO_TEST_SUITE(Util)
34BOOST_AUTO_TEST_SUITE(TestIo)
35
36struct NoEncoding
37{
38 const io::IoEncoding encoding{io::NO_ENCODING};
39 const std::vector<uint8_t> blob{0xd1, 0x0, 0xb0, 0x1a};
40 std::istringstream stream{std::string("\xd1\x00\xb0\x1a", 4), std::ios_base::binary};
41};
42
43struct Base64Encoding
44{
45 const io::IoEncoding encoding = io::BASE64;
46 const std::vector<uint8_t> blob{0x42, 0x61, 0x73, 0x65, 0x36, 0x34, 0x45, 0x6e, 0x63};
47 std::istringstream stream{"QmFzZTY0RW5j\n", std::ios_base::binary};
48};
49
50struct HexEncoding
51{
52 const io::IoEncoding encoding = io::HEX;
53 const std::vector<uint8_t> blob{0x48, 0x65, 0x78, 0x45, 0x6e, 0x63};
54 std::istringstream stream{"486578456E63", std::ios_base::binary};
55};
56
57using Encodings = boost::mpl::vector<NoEncoding, Base64Encoding, HexEncoding>;
58
59BOOST_AUTO_TEST_CASE_TEMPLATE(LoadBuffer, T, Encodings)
60{
61 T t;
62 shared_ptr<Buffer> buf = io::loadBuffer(t.stream, t.encoding);
63 BOOST_CHECK_EQUAL_COLLECTIONS(buf->begin(), buf->end(), t.blob.begin(), t.blob.end());
64}
65
66BOOST_AUTO_TEST_CASE_TEMPLATE(SaveBuffer, T, Encodings)
67{
68 T t;
69 std::ostringstream os(std::ios_base::binary);
70 io::saveBuffer(t.blob.data(), t.blob.size(), os, t.encoding);
71 BOOST_CHECK_EQUAL(os.str(), t.stream.str());
72}
73
74BOOST_AUTO_TEST_CASE(LoadBufferException)
75{
76 std::ifstream in("this-file-does-not-exist", std::ios_base::binary);
77 BOOST_CHECK_THROW(io::loadBuffer(in, io::NO_ENCODING), io::Error);
78}
79
80BOOST_AUTO_TEST_CASE(SaveBufferException)
81{
82 class NullStreambuf : public std::streambuf
83 {
84 };
85
86 NullStreambuf nullbuf;
87 std::ostream out(&nullbuf);
88 const Buffer buffer(1);
89 BOOST_CHECK_THROW(io::saveBuffer(buffer.data(), buffer.size(), out, io::NO_ENCODING), io::Error);
90}
91
92BOOST_AUTO_TEST_CASE(UnknownIoEncoding)
93{
94 std::stringstream ss;
95 BOOST_CHECK_THROW(io::loadBuffer(ss, static_cast<io::IoEncoding>(5)), std::invalid_argument);
96 BOOST_CHECK_THROW(io::saveBuffer(nullptr, 0, ss, static_cast<io::IoEncoding>(5)), std::invalid_argument);
97}
98
99class FileIoFixture
Yingdi Yuf50098d2014-02-26 14:26:29 -0800100{
Junxiao Shic1779882016-08-17 01:59:23 +0000101protected:
Davide Pesavento6c6e3852019-08-05 20:20:35 -0400102 FileIoFixture()
103 : filepath(boost::filesystem::path(UNIT_TEST_CONFIG_PATH) / "TestIo")
Junxiao Shic1779882016-08-17 01:59:23 +0000104 , filename(filepath.string())
105 {
106 boost::filesystem::create_directories(filepath.parent_path());
107 }
108
Davide Pesavento6c6e3852019-08-05 20:20:35 -0400109 ~FileIoFixture()
Junxiao Shic1779882016-08-17 01:59:23 +0000110 {
111 boost::system::error_code ec;
112 boost::filesystem::remove(filepath, ec); // ignore error
113 }
114
115 /** \brief create a directory at filename, so that it's neither readable nor writable as a file
116 */
117 void
118 mkdir() const
119 {
120 boost::filesystem::create_directory(filepath);
121 }
122
Davide Pesavento6c6e3852019-08-05 20:20:35 -0400123 template<typename Container>
Junxiao Shic1779882016-08-17 01:59:23 +0000124 Container
125 readFile() const
126 {
127 Container container;
128 std::ifstream fs(filename, std::ios_base::binary);
Davide Pesavento6c6e3852019-08-05 20:20:35 -0400129 BOOST_REQUIRE_MESSAGE(fs, "error opening file");
Junxiao Shic1779882016-08-17 01:59:23 +0000130 char ch;
131 while (fs.get(ch)) {
Davide Pesavento6c6e3852019-08-05 20:20:35 -0400132 container.push_back(static_cast<typename Container::value_type>(ch));
Junxiao Shic1779882016-08-17 01:59:23 +0000133 }
134 return container;
135 }
136
Davide Pesavento6c6e3852019-08-05 20:20:35 -0400137 template<typename Container>
Junxiao Shic1779882016-08-17 01:59:23 +0000138 void
139 writeFile(const Container& content) const
140 {
141 std::ofstream fs(filename, std::ios_base::binary);
Davide Pesavento6c6e3852019-08-05 20:20:35 -0400142 BOOST_REQUIRE_MESSAGE(fs, "error opening file");
143 for (auto ch : content) {
Junxiao Shic1779882016-08-17 01:59:23 +0000144 fs.put(static_cast<char>(ch));
145 }
Junxiao Shic1779882016-08-17 01:59:23 +0000146 BOOST_REQUIRE_MESSAGE(fs, "error writing file");
147 }
148
149protected:
150 const boost::filesystem::path filepath;
151 const std::string filename;
152};
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 Pesavento6c6e3852019-08-05 20:20:35 -0400174template<bool SHOULD_THROW>
Junxiao Shi435bb552016-09-04 03:14:47 +0000175class DecodableTypeTpl
Junxiao Shic1779882016-08-17 01:59:23 +0000176{
177public:
Junxiao Shi435bb552016-09-04 03:14:47 +0000178 DecodableTypeTpl() = default;
179
180 explicit
181 DecodableTypeTpl(const Block& block)
Junxiao Shic1779882016-08-17 01:59:23 +0000182 {
Junxiao Shi435bb552016-09-04 03:14:47 +0000183 this->wireDecode(block);
184 }
Junxiao Shic1779882016-08-17 01:59:23 +0000185
186 void
Junxiao Shi435bb552016-09-04 03:14:47 +0000187 wireDecode(const Block& block)
Junxiao Shic1779882016-08-17 01:59:23 +0000188 {
Davide Pesavento6c6e3852019-08-05 20:20:35 -0400189 if (SHOULD_THROW) {
Davide Pesavento923ba442019-02-12 22:00:38 -0500190 NDN_THROW(tlv::Error("decode error"));
Junxiao Shic1779882016-08-17 01:59:23 +0000191 }
192
193 // block must be 0xBB, 0x01, 0xEE
194 BOOST_CHECK_EQUAL(block.type(), 0xBB);
195 BOOST_REQUIRE_EQUAL(block.value_size(), 1);
196 BOOST_CHECK_EQUAL(block.value()[0], 0xEE);
197 }
Junxiao Shic1779882016-08-17 01:59:23 +0000198};
199
Davide Pesavento6c6e3852019-08-05 20:20:35 -0400200using DecodableType = DecodableTypeTpl<false>;
201using DecodableTypeThrow = DecodableTypeTpl<true>;
Junxiao Shic1779882016-08-17 01:59:23 +0000202
203BOOST_AUTO_TEST_CASE(LoadNoEncoding)
204{
205 this->writeFile<std::vector<uint8_t>>({0xBB, 0x01, 0xEE});
206 shared_ptr<DecodableType> decoded = io::load<DecodableType>(filename, io::NO_ENCODING);
207 BOOST_CHECK(decoded != nullptr);
208}
209
210BOOST_AUTO_TEST_CASE(LoadBase64)
211{
212 this->writeFile<std::string>("uwHu\n"); // printf '\xBB\x01\xEE' | base64
Junxiao Shi4ce0bcf2016-09-03 07:09:03 +0000213 shared_ptr<DecodableType> decoded = io::load<DecodableType>(filename, io::BASE64);
214 BOOST_CHECK(decoded != nullptr);
215}
216
217BOOST_AUTO_TEST_CASE(LoadBase64Newline64)
218{
219 this->writeFile<std::string>(
220 "CEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
221 "AAAAAAAAAAAA\n");
222 // printf '\x08\x40\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00
223 // \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00
224 // \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00
225 // \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' | base64
226 shared_ptr<name::Component> decoded = io::load<name::Component>(filename, io::BASE64);
227 BOOST_CHECK(decoded != nullptr);
228}
229
230BOOST_AUTO_TEST_CASE(LoadBase64Newline32)
231{
232 this->writeFile<std::string>(
233 "CEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
234 "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
235 "AAAAAAAAAAAA\n");
236 shared_ptr<name::Component> decoded = io::load<name::Component>(filename, io::BASE64);
237 BOOST_CHECK(decoded != nullptr);
238}
239
240BOOST_AUTO_TEST_CASE(LoadBase64NewlineEnd)
241{
242 this->writeFile<std::string>(
243 "CEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n");
244 shared_ptr<name::Component> decoded = io::load<name::Component>(filename, io::BASE64);
245 BOOST_CHECK(decoded != nullptr);
246}
247
248BOOST_AUTO_TEST_CASE(LoadBase64NoNewline)
249{
250 this->writeFile<std::string>(
251 "CEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA");
252 shared_ptr<name::Component> decoded = io::load<name::Component>(filename, io::BASE64);
Junxiao Shic1779882016-08-17 01:59:23 +0000253 BOOST_CHECK(decoded != nullptr);
254}
255
256BOOST_AUTO_TEST_CASE(LoadHex)
257{
258 this->writeFile<std::string>("BB01EE");
259 shared_ptr<DecodableType> decoded = io::load<DecodableType>(filename, io::HEX);
260 BOOST_CHECK(decoded != nullptr);
261}
262
263BOOST_AUTO_TEST_CASE(LoadException)
264{
265 this->writeFile<std::vector<uint8_t>>({0xBB, 0x01, 0xEE});
266 shared_ptr<DecodableTypeThrow> decoded;
267 BOOST_CHECK_NO_THROW(decoded = io::load<DecodableTypeThrow>(filename, io::NO_ENCODING));
268 BOOST_CHECK(decoded == nullptr);
269}
270
271BOOST_AUTO_TEST_CASE(LoadNotHex)
272{
273 this->writeFile<std::string>("not-hex");
274 shared_ptr<DecodableType> decoded;
275 BOOST_CHECK_NO_THROW(decoded = io::load<DecodableType>(filename, io::HEX));
276 BOOST_CHECK(decoded == nullptr);
277}
278
279BOOST_AUTO_TEST_CASE(LoadFileNotReadable)
280{
Junxiao Shic1779882016-08-17 01:59:23 +0000281 shared_ptr<DecodableType> decoded;
282 BOOST_CHECK_NO_THROW(decoded = io::load<DecodableType>(filename, io::NO_ENCODING));
283 BOOST_CHECK(decoded == nullptr);
284}
285
286BOOST_AUTO_TEST_CASE(SaveNoEncoding)
287{
288 EncodableType encoded;
289 BOOST_CHECK_NO_THROW(io::save(encoded, filename, io::NO_ENCODING));
290 auto content = this->readFile<std::vector<uint8_t>>();
291 uint8_t expected[] = {0xAA, 0x01, 0xDD};
292 BOOST_CHECK_EQUAL_COLLECTIONS(content.begin(), content.end(),
293 expected, expected + sizeof(expected));
294}
295
296BOOST_AUTO_TEST_CASE(SaveBase64)
297{
298 EncodableType encoded;
Junxiao Shi4ce0bcf2016-09-03 07:09:03 +0000299 BOOST_CHECK_NO_THROW(io::save(encoded, filename, io::BASE64));
Junxiao Shic1779882016-08-17 01:59:23 +0000300 auto content = this->readFile<std::string>();
301 BOOST_CHECK_EQUAL(content, "qgHd\n"); // printf '\xAA\x01\xDD' | base64
302}
303
304BOOST_AUTO_TEST_CASE(SaveHex)
305{
306 EncodableType encoded;
307 BOOST_CHECK_NO_THROW(io::save(encoded, filename, io::HEX));
308 auto content = this->readFile<std::string>();
309 BOOST_CHECK_EQUAL(content, "AA01DD");
310}
311
312BOOST_AUTO_TEST_CASE(SaveException)
313{
314 EncodableType encoded;
315 encoded.shouldThrow = true;
316 BOOST_CHECK_THROW(io::save(encoded, filename, io::NO_ENCODING), io::Error);
317}
318
319BOOST_AUTO_TEST_CASE(SaveFileNotWritable)
320{
321 this->mkdir();
322 EncodableType encoded;
323 encoded.shouldThrow = true;
324 BOOST_CHECK_THROW(io::save(encoded, filename, io::NO_ENCODING), io::Error);
325}
326
Davide Pesavento6c6e3852019-08-05 20:20:35 -0400327BOOST_AUTO_TEST_SUITE_END() // FileIo
328
329class IdCertFixture : public FileIoFixture
Junxiao Shic1779882016-08-17 01:59:23 +0000330 , public IdentityManagementFixture
331{
332};
333
334BOOST_FIXTURE_TEST_CASE(IdCert, IdCertFixture)
335{
Alexander Afanasyev70244f42017-01-04 12:47:12 -0800336 auto identity = addIdentity("/TestIo/IdCert", RsaKeyParams());
337 const auto& cert = identity.getDefaultKey().getDefaultCertificate();
338 io::save(cert, filename);
Yingdi Yuf50098d2014-02-26 14:26:29 -0800339
Alexander Afanasyev70244f42017-01-04 12:47:12 -0800340 auto readCert = io::load<security::v2::Certificate>(filename);
Yingdi Yuf50098d2014-02-26 14:26:29 -0800341
Junxiao Shi4ce0bcf2016-09-03 07:09:03 +0000342 BOOST_REQUIRE(readCert != nullptr);
Alexander Afanasyev70244f42017-01-04 12:47:12 -0800343 BOOST_CHECK_EQUAL(cert.getName(), readCert->getName());
Ashlesh Gawandee84d1eb2018-01-04 20:46:44 -0600344
345 this->writeFile<std::string>("");
346 readCert = io::load<security::v2::Certificate>(filename);
347 BOOST_REQUIRE(readCert == nullptr);
Yingdi Yuf50098d2014-02-26 14:26:29 -0800348}
349
Junxiao Shic1779882016-08-17 01:59:23 +0000350BOOST_AUTO_TEST_SUITE_END() // TestIo
351BOOST_AUTO_TEST_SUITE_END() // Util
Yingdi Yuf50098d2014-02-26 14:26:29 -0800352
Spyridon Mastorakis429634f2015-02-19 17:35:33 -0800353} // namespace tests
Yingdi Yuf50098d2014-02-26 14:26:29 -0800354} // namespace ndn