blob: f8595c93f3c4920b1f3ed74f7ffd4c13aad30404 [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>
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -070028
Yingdi Yuf50098d2014-02-26 14:26:29 -080029namespace ndn {
Spyridon Mastorakis429634f2015-02-19 17:35:33 -080030namespace tests {
Yingdi Yuf50098d2014-02-26 14:26:29 -080031
Junxiao Shic1779882016-08-17 01:59:23 +000032class IoFixture
Yingdi Yuf50098d2014-02-26 14:26:29 -080033{
Junxiao Shic1779882016-08-17 01:59:23 +000034protected:
35 IoFixture()
36 : filepath(boost::filesystem::path(UNIT_TEST_CONFIG_PATH) /= "TestIo")
37 , filename(filepath.string())
38 {
39 boost::filesystem::create_directories(filepath.parent_path());
40 }
41
42 ~IoFixture()
43 {
44 boost::system::error_code ec;
45 boost::filesystem::remove(filepath, ec); // ignore error
46 }
47
48 /** \brief create a directory at filename, so that it's neither readable nor writable as a file
49 */
50 void
51 mkdir() const
52 {
53 boost::filesystem::create_directory(filepath);
54 }
55
56 template<typename Container, typename CharT = typename Container::value_type>
57 Container
58 readFile() const
59 {
60 Container container;
61 std::ifstream fs(filename, std::ios_base::binary);
62 char ch;
63 while (fs.get(ch)) {
64 container.push_back(static_cast<CharT>(ch));
65 }
66 return container;
67 }
68
69 template<typename Container, typename CharT = typename Container::value_type>
70 void
71 writeFile(const Container& content) const
72 {
73 std::ofstream fs(filename, std::ios_base::binary);
74 for (CharT ch : content) {
75 fs.put(static_cast<char>(ch));
76 }
77 fs.close();
78 BOOST_REQUIRE_MESSAGE(fs, "error writing file");
79 }
80
81protected:
82 const boost::filesystem::path filepath;
83 const std::string filename;
84};
85
86BOOST_AUTO_TEST_SUITE(Util)
87BOOST_FIXTURE_TEST_SUITE(TestIo, IoFixture)
88
89class EncodableType
90{
91public:
Junxiao Shic1779882016-08-17 01:59:23 +000092 Block
93 wireEncode() const
94 {
95 if (shouldThrow) {
Davide Pesavento923ba442019-02-12 22:00:38 -050096 NDN_THROW(tlv::Error("encode error"));
Junxiao Shic1779882016-08-17 01:59:23 +000097 }
98
99 // block will be 0xAA, 0x01, 0xDD
100 return makeNonNegativeIntegerBlock(0xAA, 0xDD);
101 }
102
103public:
104 bool shouldThrow = false;
105};
106
Junxiao Shi435bb552016-09-04 03:14:47 +0000107template<bool SHOULD_THROW = false>
108class DecodableTypeTpl
Junxiao Shic1779882016-08-17 01:59:23 +0000109{
110public:
Junxiao Shi435bb552016-09-04 03:14:47 +0000111 DecodableTypeTpl() = default;
112
113 explicit
114 DecodableTypeTpl(const Block& block)
Junxiao Shic1779882016-08-17 01:59:23 +0000115 {
Junxiao Shi435bb552016-09-04 03:14:47 +0000116 this->wireDecode(block);
117 }
Junxiao Shic1779882016-08-17 01:59:23 +0000118
119 void
Junxiao Shi435bb552016-09-04 03:14:47 +0000120 wireDecode(const Block& block)
Junxiao Shic1779882016-08-17 01:59:23 +0000121 {
Junxiao Shi435bb552016-09-04 03:14:47 +0000122 if (m_shouldThrow) {
Davide Pesavento923ba442019-02-12 22:00:38 -0500123 NDN_THROW(tlv::Error("decode error"));
Junxiao Shic1779882016-08-17 01:59:23 +0000124 }
125
126 // block must be 0xBB, 0x01, 0xEE
127 BOOST_CHECK_EQUAL(block.type(), 0xBB);
128 BOOST_REQUIRE_EQUAL(block.value_size(), 1);
129 BOOST_CHECK_EQUAL(block.value()[0], 0xEE);
130 }
131
Junxiao Shi435bb552016-09-04 03:14:47 +0000132private:
133 bool m_shouldThrow = SHOULD_THROW;
Junxiao Shic1779882016-08-17 01:59:23 +0000134};
135
Junxiao Shi435bb552016-09-04 03:14:47 +0000136typedef DecodableTypeTpl<false> DecodableType;
137typedef DecodableTypeTpl<true> DecodableTypeThrow;
Junxiao Shic1779882016-08-17 01:59:23 +0000138
139BOOST_AUTO_TEST_CASE(LoadNoEncoding)
140{
141 this->writeFile<std::vector<uint8_t>>({0xBB, 0x01, 0xEE});
142 shared_ptr<DecodableType> decoded = io::load<DecodableType>(filename, io::NO_ENCODING);
143 BOOST_CHECK(decoded != nullptr);
144}
145
146BOOST_AUTO_TEST_CASE(LoadBase64)
147{
148 this->writeFile<std::string>("uwHu\n"); // printf '\xBB\x01\xEE' | base64
Junxiao Shi4ce0bcf2016-09-03 07:09:03 +0000149 shared_ptr<DecodableType> decoded = io::load<DecodableType>(filename, io::BASE64);
150 BOOST_CHECK(decoded != nullptr);
151}
152
153BOOST_AUTO_TEST_CASE(LoadBase64Newline64)
154{
155 this->writeFile<std::string>(
156 "CEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
157 "AAAAAAAAAAAA\n");
158 // printf '\x08\x40\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00
159 // \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00
160 // \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00
161 // \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' | base64
162 shared_ptr<name::Component> decoded = io::load<name::Component>(filename, io::BASE64);
163 BOOST_CHECK(decoded != nullptr);
164}
165
166BOOST_AUTO_TEST_CASE(LoadBase64Newline32)
167{
168 this->writeFile<std::string>(
169 "CEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
170 "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
171 "AAAAAAAAAAAA\n");
172 shared_ptr<name::Component> decoded = io::load<name::Component>(filename, io::BASE64);
173 BOOST_CHECK(decoded != nullptr);
174}
175
176BOOST_AUTO_TEST_CASE(LoadBase64NewlineEnd)
177{
178 this->writeFile<std::string>(
179 "CEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n");
180 shared_ptr<name::Component> decoded = io::load<name::Component>(filename, io::BASE64);
181 BOOST_CHECK(decoded != nullptr);
182}
183
184BOOST_AUTO_TEST_CASE(LoadBase64NoNewline)
185{
186 this->writeFile<std::string>(
187 "CEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA");
188 shared_ptr<name::Component> decoded = io::load<name::Component>(filename, io::BASE64);
Junxiao Shic1779882016-08-17 01:59:23 +0000189 BOOST_CHECK(decoded != nullptr);
190}
191
192BOOST_AUTO_TEST_CASE(LoadHex)
193{
194 this->writeFile<std::string>("BB01EE");
195 shared_ptr<DecodableType> decoded = io::load<DecodableType>(filename, io::HEX);
196 BOOST_CHECK(decoded != nullptr);
197}
198
199BOOST_AUTO_TEST_CASE(LoadException)
200{
201 this->writeFile<std::vector<uint8_t>>({0xBB, 0x01, 0xEE});
202 shared_ptr<DecodableTypeThrow> decoded;
203 BOOST_CHECK_NO_THROW(decoded = io::load<DecodableTypeThrow>(filename, io::NO_ENCODING));
204 BOOST_CHECK(decoded == nullptr);
205}
206
207BOOST_AUTO_TEST_CASE(LoadNotHex)
208{
209 this->writeFile<std::string>("not-hex");
210 shared_ptr<DecodableType> decoded;
211 BOOST_CHECK_NO_THROW(decoded = io::load<DecodableType>(filename, io::HEX));
212 BOOST_CHECK(decoded == nullptr);
213}
214
215BOOST_AUTO_TEST_CASE(LoadFileNotReadable)
216{
Junxiao Shic1779882016-08-17 01:59:23 +0000217 shared_ptr<DecodableType> decoded;
218 BOOST_CHECK_NO_THROW(decoded = io::load<DecodableType>(filename, io::NO_ENCODING));
219 BOOST_CHECK(decoded == nullptr);
220}
221
222BOOST_AUTO_TEST_CASE(SaveNoEncoding)
223{
224 EncodableType encoded;
225 BOOST_CHECK_NO_THROW(io::save(encoded, filename, io::NO_ENCODING));
226 auto content = this->readFile<std::vector<uint8_t>>();
227 uint8_t expected[] = {0xAA, 0x01, 0xDD};
228 BOOST_CHECK_EQUAL_COLLECTIONS(content.begin(), content.end(),
229 expected, expected + sizeof(expected));
230}
231
232BOOST_AUTO_TEST_CASE(SaveBase64)
233{
234 EncodableType encoded;
Junxiao Shi4ce0bcf2016-09-03 07:09:03 +0000235 BOOST_CHECK_NO_THROW(io::save(encoded, filename, io::BASE64));
Junxiao Shic1779882016-08-17 01:59:23 +0000236 auto content = this->readFile<std::string>();
237 BOOST_CHECK_EQUAL(content, "qgHd\n"); // printf '\xAA\x01\xDD' | base64
238}
239
240BOOST_AUTO_TEST_CASE(SaveHex)
241{
242 EncodableType encoded;
243 BOOST_CHECK_NO_THROW(io::save(encoded, filename, io::HEX));
244 auto content = this->readFile<std::string>();
245 BOOST_CHECK_EQUAL(content, "AA01DD");
246}
247
248BOOST_AUTO_TEST_CASE(SaveException)
249{
250 EncodableType encoded;
251 encoded.shouldThrow = true;
252 BOOST_CHECK_THROW(io::save(encoded, filename, io::NO_ENCODING), io::Error);
253}
254
255BOOST_AUTO_TEST_CASE(SaveFileNotWritable)
256{
257 this->mkdir();
258 EncodableType encoded;
259 encoded.shouldThrow = true;
260 BOOST_CHECK_THROW(io::save(encoded, filename, io::NO_ENCODING), io::Error);
261}
262
263class IdCertFixture : public IoFixture
264 , public IdentityManagementFixture
265{
266};
267
268BOOST_FIXTURE_TEST_CASE(IdCert, IdCertFixture)
269{
Alexander Afanasyev70244f42017-01-04 12:47:12 -0800270 auto identity = addIdentity("/TestIo/IdCert", RsaKeyParams());
271 const auto& cert = identity.getDefaultKey().getDefaultCertificate();
272 io::save(cert, filename);
Yingdi Yuf50098d2014-02-26 14:26:29 -0800273
Alexander Afanasyev70244f42017-01-04 12:47:12 -0800274 auto readCert = io::load<security::v2::Certificate>(filename);
Yingdi Yuf50098d2014-02-26 14:26:29 -0800275
Junxiao Shi4ce0bcf2016-09-03 07:09:03 +0000276 BOOST_REQUIRE(readCert != nullptr);
Alexander Afanasyev70244f42017-01-04 12:47:12 -0800277 BOOST_CHECK_EQUAL(cert.getName(), readCert->getName());
Ashlesh Gawandee84d1eb2018-01-04 20:46:44 -0600278
279 this->writeFile<std::string>("");
280 readCert = io::load<security::v2::Certificate>(filename);
281 BOOST_REQUIRE(readCert == nullptr);
Yingdi Yuf50098d2014-02-26 14:26:29 -0800282}
283
Junxiao Shic1779882016-08-17 01:59:23 +0000284BOOST_AUTO_TEST_SUITE_END() // TestIo
285BOOST_AUTO_TEST_SUITE_END() // Util
Yingdi Yuf50098d2014-02-26 14:26:29 -0800286
Spyridon Mastorakis429634f2015-02-19 17:35:33 -0800287} // namespace tests
Yingdi Yuf50098d2014-02-26 14:26:29 -0800288} // namespace ndn