blob: 8ffab078dd32bb791a2b26281c8b25a92b77fe5f [file] [log] [blame]
Alexander Afanasyevc169a812014-05-20 20:37:29 -04001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
Yingdi Yuf50098d2014-02-26 14:26:29 -08002/**
Alexander Afanasyeve4f8c3b2016-06-23 16:03:48 -07003 * Copyright (c) 2013-2016 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
Yingdi Yuf50098d2014-02-26 14:26:29 -080022#include "util/io.hpp"
23#include "security/key-chain.hpp"
24
Alexander Afanasyevb1db7c62014-04-03 14:57:25 -070025#include "boost-test.hpp"
Junxiao Shic1779882016-08-17 01:59:23 +000026#include "identity-management-fixture.hpp"
27#include <boost/filesystem.hpp>
28#include <fstream>
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
Junxiao Shic1779882016-08-17 01:59:23 +000033class IoFixture
Yingdi Yuf50098d2014-02-26 14:26:29 -080034{
Junxiao Shic1779882016-08-17 01:59:23 +000035protected:
36 IoFixture()
37 : filepath(boost::filesystem::path(UNIT_TEST_CONFIG_PATH) /= "TestIo")
38 , filename(filepath.string())
39 {
40 boost::filesystem::create_directories(filepath.parent_path());
41 }
42
43 ~IoFixture()
44 {
45 boost::system::error_code ec;
46 boost::filesystem::remove(filepath, ec); // ignore error
47 }
48
49 /** \brief create a directory at filename, so that it's neither readable nor writable as a file
50 */
51 void
52 mkdir() const
53 {
54 boost::filesystem::create_directory(filepath);
55 }
56
57 template<typename Container, typename CharT = typename Container::value_type>
58 Container
59 readFile() const
60 {
61 Container container;
62 std::ifstream fs(filename, std::ios_base::binary);
63 char ch;
64 while (fs.get(ch)) {
65 container.push_back(static_cast<CharT>(ch));
66 }
67 return container;
68 }
69
70 template<typename Container, typename CharT = typename Container::value_type>
71 void
72 writeFile(const Container& content) const
73 {
74 std::ofstream fs(filename, std::ios_base::binary);
75 for (CharT ch : content) {
76 fs.put(static_cast<char>(ch));
77 }
78 fs.close();
79 BOOST_REQUIRE_MESSAGE(fs, "error writing file");
80 }
81
82protected:
83 const boost::filesystem::path filepath;
84 const std::string filename;
85};
86
87BOOST_AUTO_TEST_SUITE(Util)
88BOOST_FIXTURE_TEST_SUITE(TestIo, IoFixture)
89
90class EncodableType
91{
92public:
Junxiao Shic1779882016-08-17 01:59:23 +000093 Block
94 wireEncode() const
95 {
96 if (shouldThrow) {
Junxiao Shi435bb552016-09-04 03:14:47 +000097 BOOST_THROW_EXCEPTION(tlv::Error("encode error"));
Junxiao Shic1779882016-08-17 01:59:23 +000098 }
99
100 // block will be 0xAA, 0x01, 0xDD
101 return makeNonNegativeIntegerBlock(0xAA, 0xDD);
102 }
103
104public:
105 bool shouldThrow = false;
106};
107
Junxiao Shi435bb552016-09-04 03:14:47 +0000108template<bool SHOULD_THROW = false>
109class DecodableTypeTpl
Junxiao Shic1779882016-08-17 01:59:23 +0000110{
111public:
Junxiao Shi435bb552016-09-04 03:14:47 +0000112 DecodableTypeTpl() = default;
113
114 explicit
115 DecodableTypeTpl(const Block& block)
Junxiao Shic1779882016-08-17 01:59:23 +0000116 {
Junxiao Shi435bb552016-09-04 03:14:47 +0000117 this->wireDecode(block);
118 }
Junxiao Shic1779882016-08-17 01:59:23 +0000119
120 void
Junxiao Shi435bb552016-09-04 03:14:47 +0000121 wireDecode(const Block& block)
Junxiao Shic1779882016-08-17 01:59:23 +0000122 {
Junxiao Shi435bb552016-09-04 03:14:47 +0000123 if (m_shouldThrow) {
124 BOOST_THROW_EXCEPTION(tlv::Error("decode error"));
Junxiao Shic1779882016-08-17 01:59:23 +0000125 }
126
127 // block must be 0xBB, 0x01, 0xEE
128 BOOST_CHECK_EQUAL(block.type(), 0xBB);
129 BOOST_REQUIRE_EQUAL(block.value_size(), 1);
130 BOOST_CHECK_EQUAL(block.value()[0], 0xEE);
131 }
132
Junxiao Shi435bb552016-09-04 03:14:47 +0000133private:
134 bool m_shouldThrow = SHOULD_THROW;
Junxiao Shic1779882016-08-17 01:59:23 +0000135};
136
Junxiao Shi435bb552016-09-04 03:14:47 +0000137typedef DecodableTypeTpl<false> DecodableType;
138typedef DecodableTypeTpl<true> DecodableTypeThrow;
Junxiao Shic1779882016-08-17 01:59:23 +0000139
140BOOST_AUTO_TEST_CASE(LoadNoEncoding)
141{
142 this->writeFile<std::vector<uint8_t>>({0xBB, 0x01, 0xEE});
143 shared_ptr<DecodableType> decoded = io::load<DecodableType>(filename, io::NO_ENCODING);
144 BOOST_CHECK(decoded != nullptr);
145}
146
147BOOST_AUTO_TEST_CASE(LoadBase64)
148{
149 this->writeFile<std::string>("uwHu\n"); // printf '\xBB\x01\xEE' | base64
Junxiao Shi4ce0bcf2016-09-03 07:09:03 +0000150 shared_ptr<DecodableType> decoded = io::load<DecodableType>(filename, io::BASE64);
151 BOOST_CHECK(decoded != nullptr);
152}
153
154BOOST_AUTO_TEST_CASE(LoadBase64Newline64)
155{
156 this->writeFile<std::string>(
157 "CEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
158 "AAAAAAAAAAAA\n");
159 // printf '\x08\x40\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\x00\x00
162 // \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00' | base64
163 shared_ptr<name::Component> decoded = io::load<name::Component>(filename, io::BASE64);
164 BOOST_CHECK(decoded != nullptr);
165}
166
167BOOST_AUTO_TEST_CASE(LoadBase64Newline32)
168{
169 this->writeFile<std::string>(
170 "CEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
171 "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n"
172 "AAAAAAAAAAAA\n");
173 shared_ptr<name::Component> decoded = io::load<name::Component>(filename, io::BASE64);
174 BOOST_CHECK(decoded != nullptr);
175}
176
177BOOST_AUTO_TEST_CASE(LoadBase64NewlineEnd)
178{
179 this->writeFile<std::string>(
180 "CEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n");
181 shared_ptr<name::Component> decoded = io::load<name::Component>(filename, io::BASE64);
182 BOOST_CHECK(decoded != nullptr);
183}
184
185BOOST_AUTO_TEST_CASE(LoadBase64NoNewline)
186{
187 this->writeFile<std::string>(
188 "CEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA");
189 shared_ptr<name::Component> decoded = io::load<name::Component>(filename, io::BASE64);
Junxiao Shic1779882016-08-17 01:59:23 +0000190 BOOST_CHECK(decoded != nullptr);
191}
192
193BOOST_AUTO_TEST_CASE(LoadHex)
194{
195 this->writeFile<std::string>("BB01EE");
196 shared_ptr<DecodableType> decoded = io::load<DecodableType>(filename, io::HEX);
197 BOOST_CHECK(decoded != nullptr);
198}
199
200BOOST_AUTO_TEST_CASE(LoadException)
201{
202 this->writeFile<std::vector<uint8_t>>({0xBB, 0x01, 0xEE});
203 shared_ptr<DecodableTypeThrow> decoded;
204 BOOST_CHECK_NO_THROW(decoded = io::load<DecodableTypeThrow>(filename, io::NO_ENCODING));
205 BOOST_CHECK(decoded == nullptr);
206}
207
208BOOST_AUTO_TEST_CASE(LoadNotHex)
209{
210 this->writeFile<std::string>("not-hex");
211 shared_ptr<DecodableType> decoded;
212 BOOST_CHECK_NO_THROW(decoded = io::load<DecodableType>(filename, io::HEX));
213 BOOST_CHECK(decoded == nullptr);
214}
215
216BOOST_AUTO_TEST_CASE(LoadFileNotReadable)
217{
Junxiao Shic1779882016-08-17 01:59:23 +0000218 shared_ptr<DecodableType> decoded;
219 BOOST_CHECK_NO_THROW(decoded = io::load<DecodableType>(filename, io::NO_ENCODING));
220 BOOST_CHECK(decoded == nullptr);
221}
222
223BOOST_AUTO_TEST_CASE(SaveNoEncoding)
224{
225 EncodableType encoded;
226 BOOST_CHECK_NO_THROW(io::save(encoded, filename, io::NO_ENCODING));
227 auto content = this->readFile<std::vector<uint8_t>>();
228 uint8_t expected[] = {0xAA, 0x01, 0xDD};
229 BOOST_CHECK_EQUAL_COLLECTIONS(content.begin(), content.end(),
230 expected, expected + sizeof(expected));
231}
232
233BOOST_AUTO_TEST_CASE(SaveBase64)
234{
235 EncodableType encoded;
Junxiao Shi4ce0bcf2016-09-03 07:09:03 +0000236 BOOST_CHECK_NO_THROW(io::save(encoded, filename, io::BASE64));
Junxiao Shic1779882016-08-17 01:59:23 +0000237 auto content = this->readFile<std::string>();
238 BOOST_CHECK_EQUAL(content, "qgHd\n"); // printf '\xAA\x01\xDD' | base64
239}
240
241BOOST_AUTO_TEST_CASE(SaveHex)
242{
243 EncodableType encoded;
244 BOOST_CHECK_NO_THROW(io::save(encoded, filename, io::HEX));
245 auto content = this->readFile<std::string>();
246 BOOST_CHECK_EQUAL(content, "AA01DD");
247}
248
249BOOST_AUTO_TEST_CASE(SaveException)
250{
251 EncodableType encoded;
252 encoded.shouldThrow = true;
253 BOOST_CHECK_THROW(io::save(encoded, filename, io::NO_ENCODING), io::Error);
254}
255
256BOOST_AUTO_TEST_CASE(SaveFileNotWritable)
257{
258 this->mkdir();
259 EncodableType encoded;
260 encoded.shouldThrow = true;
261 BOOST_CHECK_THROW(io::save(encoded, filename, io::NO_ENCODING), io::Error);
262}
263
264class IdCertFixture : public IoFixture
265 , public IdentityManagementFixture
266{
267};
268
269BOOST_FIXTURE_TEST_CASE(IdCert, IdCertFixture)
270{
271 Name identity("/TestIo/IdCert");
Alexander Afanasyevaa0e7da2014-03-17 14:37:33 -0700272 identity.appendVersion();
Yingdi Yu3ed09d02014-10-13 16:24:08 -0700273 BOOST_REQUIRE(addIdentity(identity, RsaKeyParams()));
274 Name certName = m_keyChain.getDefaultCertificateNameForIdentity(identity);
Alexander Afanasyev2fa59392016-07-29 17:24:23 -0700275 shared_ptr<security::v1::IdentityCertificate> idCert;
Yingdi Yu3ed09d02014-10-13 16:24:08 -0700276 BOOST_REQUIRE_NO_THROW(idCert = m_keyChain.getCertificate(certName));
Yingdi Yuf50098d2014-02-26 14:26:29 -0800277
Junxiao Shic1779882016-08-17 01:59:23 +0000278 io::save(*idCert, filename);
Alexander Afanasyev2fa59392016-07-29 17:24:23 -0700279 shared_ptr<security::v1::IdentityCertificate> readCert = io::load<security::v1::IdentityCertificate>(filename);
Yingdi Yuf50098d2014-02-26 14:26:29 -0800280
Junxiao Shi4ce0bcf2016-09-03 07:09:03 +0000281 BOOST_REQUIRE(readCert != nullptr);
Junxiao Shic1779882016-08-17 01:59:23 +0000282 BOOST_CHECK_EQUAL(idCert->getName(), readCert->getName());
Yingdi Yuf50098d2014-02-26 14:26:29 -0800283}
284
Junxiao Shic1779882016-08-17 01:59:23 +0000285BOOST_AUTO_TEST_SUITE_END() // TestIo
286BOOST_AUTO_TEST_SUITE_END() // Util
Yingdi Yuf50098d2014-02-26 14:26:29 -0800287
Spyridon Mastorakis429634f2015-02-19 17:35:33 -0800288} // namespace tests
Yingdi Yuf50098d2014-02-26 14:26:29 -0800289} // namespace ndn