1 // Copyright 2019 The Crashpad Authors. All rights reserved.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 #include "util/stream/base94_output_stream.h"
16
17 #include <string.h>
18
19 #include <algorithm>
20 #include <sstream>
21
22 #include "base/macros.h"
23 #include "base/rand_util.h"
24 #include "base/stl_util.h"
25 #include "base/strings/stringprintf.h"
26 #include "gtest/gtest.h"
27 #include "util/stream/test_output_stream.h"
28
29 namespace crashpad {
30 namespace test {
31 namespace {
32
33 constexpr size_t kLongDataLength = 4096 * 10;
34
DumpInput(const uint8_t * input,size_t size)35 std::string DumpInput(const uint8_t* input, size_t size) {
36 std::stringstream s;
37 size_t index = 0;
38 size_t byte_count = 0;
39 while (index < size) {
40 s << "0x" << std::hex << static_cast<int>(*(input + index++)) << ",";
41 if (byte_count++ > 1024) {
42 s << "\n";
43 byte_count = 0;
44 }
45 }
46 return s.str();
47 }
48
49 class Base94OutputStreamTest : public testing::Test {
50 public:
Base94OutputStreamTest()51 Base94OutputStreamTest() {}
52
53 protected:
SetUp()54 void SetUp() override {
55 auto output_stream = std::make_unique<TestOutputStream>();
56 encode_test_output_stream_ = output_stream.get();
57 encoder_ = std::make_unique<Base94OutputStream>(
58 Base94OutputStream::Mode::kEncode, std::move(output_stream));
59 output_stream = std::make_unique<TestOutputStream>();
60 decode_test_output_stream_ = output_stream.get();
61 decoder_ = std::make_unique<Base94OutputStream>(
62 Base94OutputStream::Mode::kDecode, std::move(output_stream));
63 output_stream = std::make_unique<TestOutputStream>();
64 round_trip_test_output_stream_ = output_stream.get();
65 round_trip_ = std::make_unique<Base94OutputStream>(
66 Base94OutputStream::Mode::kEncode,
67 std::make_unique<Base94OutputStream>(Base94OutputStream::Mode::kDecode,
68 std::move(output_stream)));
69 }
70
BuildDeterministicInput(size_t size)71 const uint8_t* BuildDeterministicInput(size_t size) {
72 deterministic_input_ = std::make_unique<uint8_t[]>(size);
73 uint8_t* deterministic_input_base = deterministic_input_.get();
74 while (size-- > 0)
75 deterministic_input_base[size] = static_cast<uint8_t>(size);
76 return deterministic_input_base;
77 }
78
BuildRandomInput(size_t size)79 const uint8_t* BuildRandomInput(size_t size) {
80 input_ = std::make_unique<uint8_t[]>(size);
81 base::RandBytes(&input_[0], size);
82 return input_.get();
83 }
84
round_trip() const85 Base94OutputStream* round_trip() const { return round_trip_.get(); }
round_trip_test_output_stream() const86 const TestOutputStream& round_trip_test_output_stream() const {
87 return *round_trip_test_output_stream_;
88 }
89
VerifyEncoding(const TestOutputStream & out,const std::string & expected)90 static void VerifyEncoding(const TestOutputStream& out,
91 const std::string& expected) {
92 EXPECT_EQ(out.all_data().size(), expected.size());
93 EXPECT_EQ(memcmp(out.all_data().data(), expected.data(), expected.size()),
94 0);
95 }
96
VerifyDecoding(const TestOutputStream & out,const std::vector<uint8_t> & expected)97 static void VerifyDecoding(const TestOutputStream& out,
98 const std::vector<uint8_t>& expected) {
99 EXPECT_EQ(out.all_data().size(), expected.size());
100 EXPECT_EQ(memcmp(out.all_data().data(), expected.data(), expected.size()),
101 0);
102 }
103
RunTest(const std::string & text,const std::vector<uint8_t> & binary)104 void RunTest(const std::string& text, const std::vector<uint8_t>& binary) {
105 EXPECT_TRUE(encoder_->Write(binary.data(), binary.size()));
106 EXPECT_TRUE(encoder_->Flush());
107 VerifyEncoding(*encode_test_output_stream_, text);
108 EXPECT_TRUE(decoder_->Write(reinterpret_cast<const uint8_t*>(text.data()),
109 text.size()));
110 EXPECT_TRUE(decoder_->Flush());
111 VerifyDecoding(*decode_test_output_stream_, binary);
112 }
113
VerifyRoundTrip(const std::vector<uint8_t> & expected)114 void VerifyRoundTrip(const std::vector<uint8_t>& expected) {
115 TestOutputStream* out = round_trip_test_output_stream_;
116 EXPECT_EQ(out->all_data().size(), expected.size());
117 EXPECT_EQ(memcmp(out->all_data().data(), expected.data(), expected.size()),
118 0);
119 }
120
121 private:
122 std::unique_ptr<Base94OutputStream> encoder_;
123 std::unique_ptr<Base94OutputStream> decoder_;
124 std::unique_ptr<Base94OutputStream> round_trip_;
125 TestOutputStream* encode_test_output_stream_;
126 TestOutputStream* decode_test_output_stream_;
127 TestOutputStream* round_trip_test_output_stream_;
128 std::unique_ptr<uint8_t[]> input_;
129 std::unique_ptr<uint8_t[]> deterministic_input_;
130
131 DISALLOW_COPY_AND_ASSIGN(Base94OutputStreamTest);
132 };
133
TEST_F(Base94OutputStreamTest,Encoding)134 TEST_F(Base94OutputStreamTest, Encoding) {
135 std::vector<uint8_t> binary = {0x0};
136 std::string text("!");
137 RunTest(text, binary);
138 }
139
TEST_F(Base94OutputStreamTest,Encoding1)140 TEST_F(Base94OutputStreamTest, Encoding1) {
141 std::vector<uint8_t> binary = {0x0, 0x0};
142 std::string text("!!!");
143 RunTest(text, binary);
144 }
145
TEST_F(Base94OutputStreamTest,Encoding2)146 TEST_F(Base94OutputStreamTest, Encoding2) {
147 std::vector<uint8_t> binary = {0x0, 0x0, 0x0};
148 std::string text("!!!!");
149 RunTest(text, binary);
150 }
151
TEST_F(Base94OutputStreamTest,Encoding3)152 TEST_F(Base94OutputStreamTest, Encoding3) {
153 std::vector<uint8_t> binary = {0x0, 0x0, 0x0, 0x0};
154 std::string text("!!!!!");
155 RunTest(text, binary);
156 }
157
TEST_F(Base94OutputStreamTest,Encoding4)158 TEST_F(Base94OutputStreamTest, Encoding4) {
159 std::vector<uint8_t> binary = {0x0, 0x0, 0x0, 0x0, 0x0};
160 std::string text("!!!!!!");
161 RunTest(text, binary);
162 }
163
TEST_F(Base94OutputStreamTest,Encoding10)164 TEST_F(Base94OutputStreamTest, Encoding10) {
165 std::vector<uint8_t> binary = {0xFF};
166 std::string text("d#");
167 RunTest(text, binary);
168 }
169
TEST_F(Base94OutputStreamTest,Encoding11)170 TEST_F(Base94OutputStreamTest, Encoding11) {
171 std::vector<uint8_t> binary = {0xFF, 0xFF};
172 std::string text(".x(");
173 RunTest(text, binary);
174 }
175
TEST_F(Base94OutputStreamTest,Encoding12)176 TEST_F(Base94OutputStreamTest, Encoding12) {
177 std::vector<uint8_t> binary = {0xFF, 0xFF, 0xFF};
178 std::string text(".xj6");
179 RunTest(text, binary);
180 }
181
TEST_F(Base94OutputStreamTest,Encoding13)182 TEST_F(Base94OutputStreamTest, Encoding13) {
183 std::vector<uint8_t> binary = {0xFF, 0xFF, 0xFF, 0xFF};
184 std::string text(".x.x`");
185 RunTest(text, binary);
186 }
187
TEST_F(Base94OutputStreamTest,Encoding14)188 TEST_F(Base94OutputStreamTest, Encoding14) {
189 std::vector<uint8_t> binary = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
190 std::string text(".x.x.x\"");
191 RunTest(text, binary);
192 }
193
TEST_F(Base94OutputStreamTest,Printable94)194 TEST_F(Base94OutputStreamTest, Printable94) {
195 std::vector<uint8_t> binary = {
196 0x5e, 0x0, 0x47, 0xa0, 0x1d, 0x60, 0xa, 0xab, 0x41, 0x41, 0xa4, 0x9,
197 0x64, 0x71, 0x32, 0xc, 0x47, 0xf9, 0x20, 0x22, 0xa3, 0x44, 0xa0, 0x84,
198 0x15, 0xe0, 0xf2, 0x61, 0xfc, 0x4c, 0xb7, 0xe1, 0x39, 0x9b, 0x47, 0xff,
199 0x64, 0x21, 0x5c, 0x74, 0x91, 0xec, 0x52, 0x75, 0xa2, 0x51, 0x93, 0x4a,
200 0x5e, 0x45, 0x2d, 0xd8, 0xf5, 0xc0, 0xdc, 0x58, 0x33, 0x63, 0x69, 0x8b,
201 0x4d, 0xbd, 0x25, 0x39, 0x54, 0x77, 0xf0, 0xcc, 0x5e, 0xf1, 0x23, 0x81,
202 0x6, 0x21, 0x71, 0x28, 0x28, 0x2};
203 std::string text(
204 "!\"#$%&'()*+,-./"
205 "0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`"
206 "abcdefghijklmnopqrstuvwxyz{|}~!");
207 RunTest(text, binary);
208 }
209
TEST_F(Base94OutputStreamTest,WriteLongDataMultipleTimes)210 TEST_F(Base94OutputStreamTest, WriteLongDataMultipleTimes) {
211 const uint8_t* input = BuildRandomInput(kLongDataLength);
212 SCOPED_TRACE(base::StringPrintf("Input: %s",
213 DumpInput(input, kLongDataLength).c_str()));
214 // Call Write() a random number of times.
215 size_t index = 0;
216 while (index < kLongDataLength) {
217 size_t write_length =
218 std::min(static_cast<size_t>(base::RandInt(0, 4096 * 2)),
219 kLongDataLength - index);
220 SCOPED_TRACE(
221 base::StringPrintf("index %zu, write_length %zu", index, write_length));
222 EXPECT_TRUE(round_trip()->Write(input + index, write_length));
223 index += write_length;
224 }
225 EXPECT_TRUE(round_trip()->Flush());
226 EXPECT_EQ(round_trip_test_output_stream().all_data().size(), kLongDataLength);
227 EXPECT_EQ(memcmp(round_trip_test_output_stream().all_data().data(),
228 input,
229 kLongDataLength),
230 0);
231 }
232
TEST_F(Base94OutputStreamTest,WriteDeterministicLongDataMultipleTimes)233 TEST_F(Base94OutputStreamTest, WriteDeterministicLongDataMultipleTimes) {
234 const uint8_t* input = BuildDeterministicInput(kLongDataLength);
235
236 static constexpr size_t kWriteLengths[] = {
237 4, 96, 40, kLongDataLength - 4 - 96 - 40};
238
239 size_t offset = 0;
240 for (size_t index = 0; index < base::size(kWriteLengths); ++index) {
241 const size_t write_length = kWriteLengths[index];
242 SCOPED_TRACE(base::StringPrintf(
243 "offset %zu, write_length %zu", offset, write_length));
244 EXPECT_TRUE(round_trip()->Write(input + offset, write_length));
245 offset += write_length;
246 }
247 EXPECT_TRUE(round_trip()->Flush());
248 EXPECT_EQ(round_trip_test_output_stream().all_data().size(), kLongDataLength);
249 EXPECT_EQ(memcmp(round_trip_test_output_stream().all_data().data(),
250 input,
251 kLongDataLength),
252 0);
253 }
254
TEST_F(Base94OutputStreamTest,NoWriteOrFlush)255 TEST_F(Base94OutputStreamTest, NoWriteOrFlush) {
256 EXPECT_EQ(round_trip_test_output_stream().write_count(), 0u);
257 EXPECT_EQ(round_trip_test_output_stream().flush_count(), 0u);
258 EXPECT_TRUE(round_trip_test_output_stream().all_data().empty());
259 }
260
TEST_F(Base94OutputStreamTest,FlushWithoutWrite)261 TEST_F(Base94OutputStreamTest, FlushWithoutWrite) {
262 EXPECT_TRUE(round_trip()->Flush());
263 EXPECT_EQ(round_trip_test_output_stream().write_count(), 0u);
264 EXPECT_EQ(round_trip_test_output_stream().flush_count(), 1u);
265 EXPECT_TRUE(round_trip_test_output_stream().all_data().empty());
266 }
267
TEST_F(Base94OutputStreamTest,WriteEmptyData)268 TEST_F(Base94OutputStreamTest, WriteEmptyData) {
269 std::vector<uint8_t> empty_data;
270 EXPECT_TRUE(round_trip()->Write(
271 static_cast<const uint8_t*>(empty_data.data()), empty_data.size()));
272 EXPECT_TRUE(round_trip()->Flush());
273 EXPECT_TRUE(round_trip()->Flush());
274 EXPECT_EQ(round_trip_test_output_stream().write_count(), 0u);
275 EXPECT_EQ(round_trip_test_output_stream().flush_count(), 2u);
276 EXPECT_TRUE(round_trip_test_output_stream().all_data().empty());
277 }
278
TEST_F(Base94OutputStreamTest,Process7bitsInFinishDecoding)279 TEST_F(Base94OutputStreamTest, Process7bitsInFinishDecoding) {
280 std::vector<uint8_t> input = {
281 0xff, 0xff, 0xff, 0xff, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
282 EXPECT_TRUE(round_trip()->Write(static_cast<const uint8_t*>(input.data()),
283 input.size()));
284 EXPECT_TRUE(round_trip()->Flush());
285 VerifyRoundTrip(input);
286 }
287
288 } // namespace
289 } // namespace test
290 } // namespace crashpad
291