xref: /aosp_15_r20/external/bsdiff/endsley_patch_writer_unittest.cc (revision a3a45f308bd90ef1a6e6a5e8fb92fe449b895909)
1*a3a45f30SXin Li // Copyright 2017 The Chromium OS Authors. All rights reserved.
2*a3a45f30SXin Li // Use of this source code is governed by a BSD-style license that can be
3*a3a45f30SXin Li // found in the LICENSE file.
4*a3a45f30SXin Li 
5*a3a45f30SXin Li #include "bsdiff/endsley_patch_writer.h"
6*a3a45f30SXin Li 
7*a3a45f30SXin Li #include <algorithm>
8*a3a45f30SXin Li 
9*a3a45f30SXin Li #include <gtest/gtest.h>
10*a3a45f30SXin Li 
11*a3a45f30SXin Li namespace {
12*a3a45f30SXin Li 
VectorFromString(const std::string & s)13*a3a45f30SXin Li std::vector<uint8_t> VectorFromString(const std::string& s) {
14*a3a45f30SXin Li   return std::vector<uint8_t>(s.data(), s.data() + s.size());
15*a3a45f30SXin Li }
16*a3a45f30SXin Li 
17*a3a45f30SXin Li }  // namespace
18*a3a45f30SXin Li 
19*a3a45f30SXin Li namespace bsdiff {
20*a3a45f30SXin Li 
21*a3a45f30SXin Li class EndsleyPatchWriterTest : public testing::Test {
22*a3a45f30SXin Li  protected:
23*a3a45f30SXin Li   // Return a subvector from |data_| starting at |start| of size at most |size|.
DataSubvector(size_t start,size_t size)24*a3a45f30SXin Li   std::vector<uint8_t> DataSubvector(size_t start, size_t size) {
25*a3a45f30SXin Li     if (start > data_.size())
26*a3a45f30SXin Li       return std::vector<uint8_t>();
27*a3a45f30SXin Li 
28*a3a45f30SXin Li     size = std::min(size, data_.size() - start);
29*a3a45f30SXin Li     return std::vector<uint8_t>(data_.begin() + start,
30*a3a45f30SXin Li                                 data_.begin() + start + size);
31*a3a45f30SXin Li   }
32*a3a45f30SXin Li 
33*a3a45f30SXin Li   std::vector<uint8_t> data_;
34*a3a45f30SXin Li   EndsleyPatchWriter patch_writer_{&data_, CompressorType::kNoCompression, 0};
35*a3a45f30SXin Li };
36*a3a45f30SXin Li 
37*a3a45f30SXin Li // Smoke check that a patch includes the new_size and magic header.
TEST_F(EndsleyPatchWriterTest,CreateEmptyPatchTest)38*a3a45f30SXin Li TEST_F(EndsleyPatchWriterTest, CreateEmptyPatchTest) {
39*a3a45f30SXin Li   EXPECT_TRUE(patch_writer_.Init(0));
40*a3a45f30SXin Li   EXPECT_TRUE(patch_writer_.Close());
41*a3a45f30SXin Li 
42*a3a45f30SXin Li   // The empty header is set to 24 bytes.
43*a3a45f30SXin Li   EXPECT_EQ(24U, data_.size());
44*a3a45f30SXin Li 
45*a3a45f30SXin Li   std::vector<uint8_t> empty_patch = {
46*a3a45f30SXin Li       // Magic header.
47*a3a45f30SXin Li       'E', 'N', 'D', 'S', 'L', 'E', 'Y', '/', 'B', 'S', 'D', 'I', 'F', 'F', '4',
48*a3a45f30SXin Li       '3',
49*a3a45f30SXin Li       // 8 zeros for the |new_size| of zero bytes.
50*a3a45f30SXin Li       0, 0, 0, 0, 0, 0, 0, 0};
51*a3a45f30SXin Li   EXPECT_EQ(empty_patch, data_);
52*a3a45f30SXin Li }
53*a3a45f30SXin Li 
TEST_F(EndsleyPatchWriterTest,CreateCompressedPatchTest)54*a3a45f30SXin Li TEST_F(EndsleyPatchWriterTest, CreateCompressedPatchTest) {
55*a3a45f30SXin Li   EndsleyPatchWriter compressed_writer(&data_, CompressorType::kBZ2, 9);
56*a3a45f30SXin Li 
57*a3a45f30SXin Li   auto text = VectorFromString("HelloWorld");
58*a3a45f30SXin Li   EXPECT_TRUE(compressed_writer.Init(text.size()));
59*a3a45f30SXin Li 
60*a3a45f30SXin Li   EXPECT_TRUE(compressed_writer.AddControlEntry(ControlEntry(5, 5, -2)));
61*a3a45f30SXin Li   EXPECT_TRUE(compressed_writer.WriteDiffStream(text.data(), 5));
62*a3a45f30SXin Li   EXPECT_TRUE(compressed_writer.WriteExtraStream(text.data() + 5, 5));
63*a3a45f30SXin Li 
64*a3a45f30SXin Li   // Check that the output patch had no data written to it before Close() is
65*a3a45f30SXin Li   // called, since we are still compressing it.
66*a3a45f30SXin Li   EXPECT_TRUE(data_.empty());
67*a3a45f30SXin Li 
68*a3a45f30SXin Li   EXPECT_TRUE(compressed_writer.Close());
69*a3a45f30SXin Li 
70*a3a45f30SXin Li   // Check that the whole file is compressed with BZ2 by looking at the header.
71*a3a45f30SXin Li   const auto bz2_header = VectorFromString("BZh9");
72*a3a45f30SXin Li   data_.resize(4);
73*a3a45f30SXin Li   EXPECT_EQ(bz2_header, data_);
74*a3a45f30SXin Li }
75*a3a45f30SXin Li 
TEST_F(EndsleyPatchWriterTest,CreateEmptyBrotliPatchTest)76*a3a45f30SXin Li TEST_F(EndsleyPatchWriterTest, CreateEmptyBrotliPatchTest) {
77*a3a45f30SXin Li   EndsleyPatchWriter compressed_writer(&data_, CompressorType::kBrotli, 9);
78*a3a45f30SXin Li   EXPECT_TRUE(compressed_writer.Init(0));
79*a3a45f30SXin Li   EXPECT_TRUE(compressed_writer.Close());
80*a3a45f30SXin Li }
81*a3a45f30SXin Li 
82*a3a45f30SXin Li // Test we generate the right patch when the control, diff and extra stream come
83*a3a45f30SXin Li // in the right order.
TEST_F(EndsleyPatchWriterTest,DataInNiceOrderTest)84*a3a45f30SXin Li TEST_F(EndsleyPatchWriterTest, DataInNiceOrderTest) {
85*a3a45f30SXin Li   auto text = VectorFromString("abcdeFGHIJ");
86*a3a45f30SXin Li   EXPECT_TRUE(patch_writer_.Init(10));
87*a3a45f30SXin Li 
88*a3a45f30SXin Li   EXPECT_TRUE(patch_writer_.AddControlEntry(ControlEntry(2, 3, -2)));
89*a3a45f30SXin Li   EXPECT_TRUE(patch_writer_.WriteDiffStream(text.data(), 2));
90*a3a45f30SXin Li   EXPECT_TRUE(patch_writer_.WriteExtraStream(text.data() + 2, 3));
91*a3a45f30SXin Li 
92*a3a45f30SXin Li   // Check that we are actually writing to the output vector as soon as we can.
93*a3a45f30SXin Li   EXPECT_EQ(24U + 24U + 2U + 3U, data_.size());
94*a3a45f30SXin Li 
95*a3a45f30SXin Li   EXPECT_TRUE(patch_writer_.AddControlEntry(ControlEntry(0, 5, 1024)));
96*a3a45f30SXin Li   EXPECT_TRUE(patch_writer_.WriteExtraStream(text.data() + 5, 5));
97*a3a45f30SXin Li 
98*a3a45f30SXin Li   EXPECT_TRUE(patch_writer_.Close());
99*a3a45f30SXin Li 
100*a3a45f30SXin Li   // We have a header, 2 control entries and a total of 10 bytes of data.
101*a3a45f30SXin Li   EXPECT_EQ(24U + 24U * 2 + 10U, data_.size());
102*a3a45f30SXin Li 
103*a3a45f30SXin Li   // Verify that control entry values are encoded properly in little-endian.
104*a3a45f30SXin Li   EXPECT_EQ((std::vector<uint8_t>{10, 0, 0, 0, 0, 0, 0, 0}),
105*a3a45f30SXin Li             DataSubvector(16U, 8));  // new_size
106*a3a45f30SXin Li 
107*a3a45f30SXin Li   // Negative numbers are encoded with the sign bit in the most significant bit
108*a3a45f30SXin Li   // of the 8-byte number.
109*a3a45f30SXin Li   EXPECT_EQ((std::vector<uint8_t>{2, 0, 0, 0, 0, 0, 0, 0x80}),
110*a3a45f30SXin Li             DataSubvector(24U + 16, 8));
111*a3a45f30SXin Li 
112*a3a45f30SXin Li   // The second member on the last control entry (1024) encoded in
113*a3a45f30SXin Li   // little-endian.
114*a3a45f30SXin Li   EXPECT_EQ((std::vector<uint8_t>{0, 4, 0, 0, 0, 0, 0, 0}),
115*a3a45f30SXin Li             DataSubvector(24U + 24U + 5U + 16U, 8));
116*a3a45f30SXin Li 
117*a3a45f30SXin Li   // Check that the diff and extra data are sent one after the other in the
118*a3a45f30SXin Li   // right order.
119*a3a45f30SXin Li   EXPECT_EQ(VectorFromString("abcde"), DataSubvector(24U + 24U, 5));
120*a3a45f30SXin Li }
121*a3a45f30SXin Li 
122*a3a45f30SXin Li // When we send first the diff or extra data it shouldn't be possible to
123*a3a45f30SXin Li // write it to the patch, but at the end of the patch we should be able to
124*a3a45f30SXin Li // write it all.
TEST_F(EndsleyPatchWriterTest,DataInBadOrderTest)125*a3a45f30SXin Li TEST_F(EndsleyPatchWriterTest, DataInBadOrderTest) {
126*a3a45f30SXin Li   auto text = VectorFromString("abcdeFGHIJ");
127*a3a45f30SXin Li   EXPECT_TRUE(patch_writer_.Init(10));
128*a3a45f30SXin Li   EXPECT_TRUE(patch_writer_.WriteDiffStream(text.data(), 5));
129*a3a45f30SXin Li   EXPECT_TRUE(patch_writer_.WriteExtraStream(text.data() + 5, 5));
130*a3a45f30SXin Li 
131*a3a45f30SXin Li   // Writ all the control entries at the end, only the header should have been
132*a3a45f30SXin Li   // sent so far.
133*a3a45f30SXin Li   EXPECT_EQ(24U, data_.size());
134*a3a45f30SXin Li 
135*a3a45f30SXin Li   EXPECT_TRUE(patch_writer_.AddControlEntry(ControlEntry(2, 3, -2)));
136*a3a45f30SXin Li   EXPECT_TRUE(patch_writer_.AddControlEntry(ControlEntry(2, 1, 1024)));
137*a3a45f30SXin Li   EXPECT_TRUE(patch_writer_.AddControlEntry(ControlEntry(1, 1, 1024)));
138*a3a45f30SXin Li 
139*a3a45f30SXin Li   EXPECT_TRUE(patch_writer_.Close());
140*a3a45f30SXin Li 
141*a3a45f30SXin Li   // We have a header, 3 control entries and a total of 10 bytes of data.
142*a3a45f30SXin Li   EXPECT_EQ(24U + 24U * 3 + 10U, data_.size());
143*a3a45f30SXin Li 
144*a3a45f30SXin Li   // The data from the first and second control entries:
145*a3a45f30SXin Li   EXPECT_EQ(VectorFromString("abFGH"), DataSubvector(24U + 24U, 5));
146*a3a45f30SXin Li   EXPECT_EQ(VectorFromString("cdI"), DataSubvector(24U + 24U * 2 + 5, 3));
147*a3a45f30SXin Li   EXPECT_EQ(VectorFromString("eJ"), DataSubvector(24U + 24U * 3 + 8, 2));
148*a3a45f30SXin Li }
149*a3a45f30SXin Li 
TEST_F(EndsleyPatchWriterTest,FlushOnlyWhenWorthItTest)150*a3a45f30SXin Li TEST_F(EndsleyPatchWriterTest, FlushOnlyWhenWorthItTest) {
151*a3a45f30SXin Li   size_t kEntrySize = 1000;  // must be even for this test.
152*a3a45f30SXin Li   size_t kNumEntries = 3000;
153*a3a45f30SXin Li   size_t kNewSize = kEntrySize * kNumEntries;  // 3 MB
154*a3a45f30SXin Li 
155*a3a45f30SXin Li   EXPECT_TRUE(patch_writer_.Init(kNewSize));
156*a3a45f30SXin Li   // Write all the extra and diff data first.
157*a3a45f30SXin Li   std::vector<uint8_t> zeros(kNewSize / 2, 0);
158*a3a45f30SXin Li   EXPECT_TRUE(patch_writer_.WriteDiffStream(zeros.data(), zeros.size()));
159*a3a45f30SXin Li   EXPECT_TRUE(patch_writer_.WriteExtraStream(zeros.data(), zeros.size()));
160*a3a45f30SXin Li 
161*a3a45f30SXin Li   // No patch data flushed so far, only the header.
162*a3a45f30SXin Li   EXPECT_EQ(24U, data_.size());
163*a3a45f30SXin Li 
164*a3a45f30SXin Li   ControlEntry entry(kEntrySize / 2, kEntrySize / 2, -1);
165*a3a45f30SXin Li   for (size_t i = 0; i < 10; i++) {
166*a3a45f30SXin Li     EXPECT_TRUE(patch_writer_.AddControlEntry(entry));
167*a3a45f30SXin Li   }
168*a3a45f30SXin Li 
169*a3a45f30SXin Li   // Even if all the diff and extra data is available and some control entries
170*a3a45f30SXin Li   // are also available no information should have been flushed yet because we
171*a3a45f30SXin Li   // don't want the overhead of updating the diff_data_ and extra_data_ vectors.
172*a3a45f30SXin Li   EXPECT_EQ(24U, data_.size());
173*a3a45f30SXin Li 
174*a3a45f30SXin Li   // Write the remaining entries.
175*a3a45f30SXin Li   for (size_t i = 0; i < kNumEntries - 10; i++) {
176*a3a45f30SXin Li     EXPECT_TRUE(patch_writer_.AddControlEntry(entry));
177*a3a45f30SXin Li   }
178*a3a45f30SXin Li 
179*a3a45f30SXin Li   // Even before Close() is called, we have enough control entries to make it
180*a3a45f30SXin Li   // worth it calling flush at some point.
181*a3a45f30SXin Li   EXPECT_LT(24U, data_.size());
182*a3a45f30SXin Li 
183*a3a45f30SXin Li   EXPECT_TRUE(patch_writer_.Close());
184*a3a45f30SXin Li }
185*a3a45f30SXin Li 
186*a3a45f30SXin Li }  // namespace bsdiff
187