1*07fb1d06SElliott Hughes // Copyright 2017 The ChromiumOS Authors
2*07fb1d06SElliott Hughes // Use of this source code is governed by a BSD-style license that can be
3*07fb1d06SElliott Hughes // found in the LICENSE file.
4*07fb1d06SElliott Hughes
5*07fb1d06SElliott Hughes #include <string>
6*07fb1d06SElliott Hughes #include <vector>
7*07fb1d06SElliott Hughes
8*07fb1d06SElliott Hughes #include "gtest/gtest.h"
9*07fb1d06SElliott Hughes
10*07fb1d06SElliott Hughes #include "puffin/memory_stream.h"
11*07fb1d06SElliott Hughes #include "puffin/src/include/puffin/common.h"
12*07fb1d06SElliott Hughes #include "puffin/src/include/puffin/puffdiff.h"
13*07fb1d06SElliott Hughes #include "puffin/src/include/puffin/puffpatch.h"
14*07fb1d06SElliott Hughes #include "puffin/src/include/puffin/utils.h"
15*07fb1d06SElliott Hughes #include "puffin/src/logging.h"
16*07fb1d06SElliott Hughes #include "puffin/src/puffin_stream.h"
17*07fb1d06SElliott Hughes #include "puffin/src/unittest_common.h"
18*07fb1d06SElliott Hughes
19*07fb1d06SElliott Hughes #define PRINT_SAMPLE 0 // Set to 1 if you want to print the generated samples.
20*07fb1d06SElliott Hughes
21*07fb1d06SElliott Hughes using std::string;
22*07fb1d06SElliott Hughes using std::vector;
23*07fb1d06SElliott Hughes
24*07fb1d06SElliott Hughes namespace puffin {
25*07fb1d06SElliott Hughes
26*07fb1d06SElliott Hughes namespace {
27*07fb1d06SElliott Hughes
28*07fb1d06SElliott Hughes #if PRINT_SAMPLE
29*07fb1d06SElliott Hughes // Print an array into hex-format to the output. This can be used to create
30*07fb1d06SElliott Hughes // static arrays for unit testing of the puffer/huffer.
PrintArray(const string & name,const Buffer & array)31*07fb1d06SElliott Hughes void PrintArray(const string& name, const Buffer& array) {
32*07fb1d06SElliott Hughes std::cout << "const Buffer " << name << " = {" << std::endl << " ";
33*07fb1d06SElliott Hughes for (size_t idx = 0; idx < array.size(); idx++) {
34*07fb1d06SElliott Hughes std::cout << " 0x" << std::hex << std::uppercase << std::setfill('0')
35*07fb1d06SElliott Hughes << std::setw(2) << uint(array[idx]);
36*07fb1d06SElliott Hughes if (idx == array.size() - 1) {
37*07fb1d06SElliott Hughes std::cout << std::dec << "};" << std::endl;
38*07fb1d06SElliott Hughes return;
39*07fb1d06SElliott Hughes }
40*07fb1d06SElliott Hughes std::cout << ",";
41*07fb1d06SElliott Hughes if ((idx + 1) % 12 == 0) {
42*07fb1d06SElliott Hughes std::cout << std::endl << " ";
43*07fb1d06SElliott Hughes }
44*07fb1d06SElliott Hughes }
45*07fb1d06SElliott Hughes }
46*07fb1d06SElliott Hughes #endif
47*07fb1d06SElliott Hughes
48*07fb1d06SElliott Hughes const Buffer kPatch1To2 = {
49*07fb1d06SElliott Hughes 0x50, 0x55, 0x46, 0x31, 0x00, 0x00, 0x00, 0x51, 0x08, 0x01, 0x12, 0x27,
50*07fb1d06SElliott Hughes 0x0A, 0x04, 0x08, 0x10, 0x10, 0x32, 0x0A, 0x04, 0x08, 0x50, 0x10, 0x0A,
51*07fb1d06SElliott Hughes 0x0A, 0x04, 0x08, 0x60, 0x10, 0x12, 0x12, 0x04, 0x08, 0x10, 0x10, 0x58,
52*07fb1d06SElliott Hughes 0x12, 0x04, 0x08, 0x78, 0x10, 0x28, 0x12, 0x05, 0x08, 0xA8, 0x01, 0x10,
53*07fb1d06SElliott Hughes 0x38, 0x18, 0x1F, 0x1A, 0x24, 0x0A, 0x02, 0x10, 0x32, 0x0A, 0x04, 0x08,
54*07fb1d06SElliott Hughes 0x48, 0x10, 0x50, 0x0A, 0x05, 0x08, 0x98, 0x01, 0x10, 0x12, 0x12, 0x02,
55*07fb1d06SElliott Hughes 0x10, 0x58, 0x12, 0x04, 0x08, 0x70, 0x10, 0x58, 0x12, 0x05, 0x08, 0xC8,
56*07fb1d06SElliott Hughes 0x01, 0x10, 0x38, 0x18, 0x21, 0x42, 0x53, 0x44, 0x46, 0x32, 0x01, 0x01,
57*07fb1d06SElliott Hughes 0x01, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00,
58*07fb1d06SElliott Hughes 0x00, 0x00, 0x00, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
59*07fb1d06SElliott Hughes 0x00, 0x42, 0x5A, 0x68, 0x39, 0x31, 0x41, 0x59, 0x26, 0x53, 0x59, 0xD1,
60*07fb1d06SElliott Hughes 0x20, 0xBB, 0x7E, 0x00, 0x00, 0x03, 0x60, 0x40, 0x78, 0x0E, 0x08, 0x00,
61*07fb1d06SElliott Hughes 0x40, 0x00, 0x20, 0x00, 0x31, 0x06, 0x4C, 0x40, 0x92, 0x8F, 0x46, 0xA7,
62*07fb1d06SElliott Hughes 0xA8, 0xE0, 0xF3, 0xD6, 0x21, 0x12, 0xF4, 0xBC, 0x43, 0x32, 0x1F, 0x17,
63*07fb1d06SElliott Hughes 0x72, 0x45, 0x38, 0x50, 0x90, 0xD1, 0x20, 0xBB, 0x7E, 0x42, 0x5A, 0x68,
64*07fb1d06SElliott Hughes 0x39, 0x31, 0x41, 0x59, 0x26, 0x53, 0x59, 0xF1, 0x20, 0x5F, 0x0D, 0x00,
65*07fb1d06SElliott Hughes 0x00, 0x02, 0x41, 0x15, 0x42, 0x08, 0x20, 0x00, 0x40, 0x00, 0x00, 0x02,
66*07fb1d06SElliott Hughes 0x40, 0x00, 0x20, 0x00, 0x22, 0x3D, 0x23, 0x10, 0x86, 0x03, 0x96, 0x54,
67*07fb1d06SElliott Hughes 0x11, 0x16, 0x5F, 0x17, 0x72, 0x45, 0x38, 0x50, 0x90, 0xF1, 0x20, 0x5F,
68*07fb1d06SElliott Hughes 0x0D, 0x42, 0x5A, 0x68, 0x39, 0x31, 0x41, 0x59, 0x26, 0x53, 0x59, 0x07,
69*07fb1d06SElliott Hughes 0xD4, 0xCB, 0x6E, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x20, 0x00,
70*07fb1d06SElliott Hughes 0x21, 0x18, 0x46, 0x82, 0xEE, 0x48, 0xA7, 0x0A, 0x12, 0x00, 0xFA, 0x99,
71*07fb1d06SElliott Hughes 0x6D, 0xC0};
72*07fb1d06SElliott Hughes
73*07fb1d06SElliott Hughes const Buffer kPatch2To1 = {
74*07fb1d06SElliott Hughes 0x50, 0x55, 0x46, 0x31, 0x00, 0x00, 0x00, 0x51, 0x08, 0x01, 0x12, 0x24,
75*07fb1d06SElliott Hughes 0x0A, 0x02, 0x10, 0x32, 0x0A, 0x04, 0x08, 0x48, 0x10, 0x50, 0x0A, 0x05,
76*07fb1d06SElliott Hughes 0x08, 0x98, 0x01, 0x10, 0x12, 0x12, 0x02, 0x10, 0x58, 0x12, 0x04, 0x08,
77*07fb1d06SElliott Hughes 0x70, 0x10, 0x58, 0x12, 0x05, 0x08, 0xC8, 0x01, 0x10, 0x38, 0x18, 0x21,
78*07fb1d06SElliott Hughes 0x1A, 0x27, 0x0A, 0x04, 0x08, 0x10, 0x10, 0x32, 0x0A, 0x04, 0x08, 0x50,
79*07fb1d06SElliott Hughes 0x10, 0x0A, 0x0A, 0x04, 0x08, 0x60, 0x10, 0x12, 0x12, 0x04, 0x08, 0x10,
80*07fb1d06SElliott Hughes 0x10, 0x58, 0x12, 0x04, 0x08, 0x78, 0x10, 0x28, 0x12, 0x05, 0x08, 0xA8,
81*07fb1d06SElliott Hughes 0x01, 0x10, 0x38, 0x18, 0x1F, 0x42, 0x53, 0x44, 0x46, 0x32, 0x01, 0x01,
82*07fb1d06SElliott Hughes 0x01, 0x33, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x25, 0x00, 0x00,
83*07fb1d06SElliott Hughes 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
84*07fb1d06SElliott Hughes 0x00, 0x42, 0x5A, 0x68, 0x39, 0x31, 0x41, 0x59, 0x26, 0x53, 0x59, 0x3D,
85*07fb1d06SElliott Hughes 0xBD, 0x08, 0x91, 0x00, 0x00, 0x01, 0xE0, 0x40, 0x5C, 0x0A, 0x40, 0x00,
86*07fb1d06SElliott Hughes 0x40, 0x00, 0x20, 0x00, 0x31, 0x0C, 0x08, 0x23, 0xD2, 0x34, 0xD1, 0xB1,
87*07fb1d06SElliott Hughes 0x73, 0x60, 0x44, 0x54, 0xE4, 0xFC, 0x5D, 0xC9, 0x14, 0xE1, 0x42, 0x40,
88*07fb1d06SElliott Hughes 0xF6, 0xF4, 0x22, 0x44, 0x42, 0x5A, 0x68, 0x39, 0x31, 0x41, 0x59, 0x26,
89*07fb1d06SElliott Hughes 0x53, 0x59, 0x41, 0x62, 0x2E, 0xF0, 0x00, 0x00, 0x00, 0x40, 0x00, 0x40,
90*07fb1d06SElliott Hughes 0x20, 0x20, 0x00, 0x21, 0x00, 0x82, 0x83, 0x17, 0x72, 0x45, 0x38, 0x50,
91*07fb1d06SElliott Hughes 0x90, 0x41, 0x62, 0x2E, 0xF0, 0x42, 0x5A, 0x68, 0x39, 0x31, 0x41, 0x59,
92*07fb1d06SElliott Hughes 0x26, 0x53, 0x59, 0xE0, 0x20, 0x04, 0x57, 0x00, 0x00, 0x04, 0x76, 0x50,
93*07fb1d06SElliott Hughes 0xE0, 0x00, 0x20, 0x00, 0x10, 0x00, 0x04, 0x00, 0x02, 0x00, 0x20, 0x00,
94*07fb1d06SElliott Hughes 0x40, 0x00, 0x00, 0x00, 0xA0, 0x00, 0x21, 0xA1, 0xA3, 0x10, 0x83, 0x26,
95*07fb1d06SElliott Hughes 0x21, 0x5E, 0xB2, 0x69, 0xAC, 0x70, 0x60, 0x53, 0xC5, 0xDC, 0x91, 0x4E,
96*07fb1d06SElliott Hughes 0x14, 0x24, 0x38, 0x08, 0x01, 0x15, 0xC0};
97*07fb1d06SElliott Hughes
98*07fb1d06SElliott Hughes const Buffer kPatch1ToEmpty = {
99*07fb1d06SElliott Hughes 0x50, 0x55, 0x46, 0x31, 0x00, 0x00, 0x00, 0x2D, 0x08, 0x01, 0x12, 0x27,
100*07fb1d06SElliott Hughes 0x0A, 0x04, 0x08, 0x10, 0x10, 0x32, 0x0A, 0x04, 0x08, 0x50, 0x10, 0x0A,
101*07fb1d06SElliott Hughes 0x0A, 0x04, 0x08, 0x60, 0x10, 0x12, 0x12, 0x04, 0x08, 0x10, 0x10, 0x58,
102*07fb1d06SElliott Hughes 0x12, 0x04, 0x08, 0x78, 0x10, 0x28, 0x12, 0x05, 0x08, 0xA8, 0x01, 0x10,
103*07fb1d06SElliott Hughes 0x38, 0x18, 0x1F, 0x1A, 0x00, 0x42, 0x53, 0x44, 0x46, 0x32, 0x01, 0x01,
104*07fb1d06SElliott Hughes 0x01, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x00,
105*07fb1d06SElliott Hughes 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
106*07fb1d06SElliott Hughes 0x00, 0x42, 0x5A, 0x68, 0x39, 0x17, 0x72, 0x45, 0x38, 0x50, 0x90, 0x00,
107*07fb1d06SElliott Hughes 0x00, 0x00, 0x00, 0x42, 0x5A, 0x68, 0x39, 0x17, 0x72, 0x45, 0x38, 0x50,
108*07fb1d06SElliott Hughes 0x90, 0x00, 0x00, 0x00, 0x00, 0x42, 0x5A, 0x68, 0x39, 0x17, 0x72, 0x45,
109*07fb1d06SElliott Hughes 0x38, 0x50, 0x90, 0x00, 0x00, 0x00, 0x00};
110*07fb1d06SElliott Hughes
111*07fb1d06SElliott Hughes const Buffer kPatch1ToNoDeflate = {
112*07fb1d06SElliott Hughes 0x50, 0x55, 0x46, 0x31, 0x00, 0x00, 0x00, 0x2F, 0x08, 0x01, 0x12, 0x27,
113*07fb1d06SElliott Hughes 0x0A, 0x04, 0x08, 0x10, 0x10, 0x32, 0x0A, 0x04, 0x08, 0x50, 0x10, 0x0A,
114*07fb1d06SElliott Hughes 0x0A, 0x04, 0x08, 0x60, 0x10, 0x12, 0x12, 0x04, 0x08, 0x10, 0x10, 0x58,
115*07fb1d06SElliott Hughes 0x12, 0x04, 0x08, 0x78, 0x10, 0x28, 0x12, 0x05, 0x08, 0xA8, 0x01, 0x10,
116*07fb1d06SElliott Hughes 0x38, 0x18, 0x1F, 0x1A, 0x02, 0x18, 0x04, 0x42, 0x53, 0x44, 0x46, 0x32,
117*07fb1d06SElliott Hughes 0x01, 0x01, 0x01, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0E,
118*07fb1d06SElliott Hughes 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00,
119*07fb1d06SElliott Hughes 0x00, 0x00, 0x00, 0x42, 0x5A, 0x68, 0x39, 0x31, 0x41, 0x59, 0x26, 0x53,
120*07fb1d06SElliott Hughes 0x59, 0xBA, 0x8D, 0x7F, 0x2D, 0x00, 0x00, 0x00, 0x40, 0x00, 0x44, 0x08,
121*07fb1d06SElliott Hughes 0x20, 0x00, 0x30, 0xCC, 0x09, 0x32, 0x54, 0x65, 0x38, 0xBB, 0x92, 0x29,
122*07fb1d06SElliott Hughes 0xC2, 0x84, 0x85, 0xD4, 0x6B, 0xF9, 0x68, 0x42, 0x5A, 0x68, 0x39, 0x17,
123*07fb1d06SElliott Hughes 0x72, 0x45, 0x38, 0x50, 0x90, 0x00, 0x00, 0x00, 0x00, 0x42, 0x5A, 0x68,
124*07fb1d06SElliott Hughes 0x39, 0x31, 0x41, 0x59, 0x26, 0x53, 0x59, 0xE7, 0xAA, 0xF1, 0xFC, 0x00,
125*07fb1d06SElliott Hughes 0x00, 0x00, 0x70, 0x00, 0x00, 0x08, 0x01, 0x00, 0x20, 0x04, 0x20, 0x00,
126*07fb1d06SElliott Hughes 0x21, 0x9A, 0x68, 0x33, 0x4D, 0x13, 0x3C, 0x5D, 0xC9, 0x14, 0xE1, 0x42,
127*07fb1d06SElliott Hughes 0x43, 0x9E, 0xAB, 0xC7, 0xF0};
128*07fb1d06SElliott Hughes
129*07fb1d06SElliott Hughes } // namespace
130*07fb1d06SElliott Hughes
TestPatching(const Buffer & src_buf,const Buffer & dst_buf,const vector<BitExtent> & src_deflates,const vector<BitExtent> & dst_deflates,const Buffer patch)131*07fb1d06SElliott Hughes void TestPatching(const Buffer& src_buf,
132*07fb1d06SElliott Hughes const Buffer& dst_buf,
133*07fb1d06SElliott Hughes const vector<BitExtent>& src_deflates,
134*07fb1d06SElliott Hughes const vector<BitExtent>& dst_deflates,
135*07fb1d06SElliott Hughes const Buffer patch) {
136*07fb1d06SElliott Hughes Buffer patch_out;
137*07fb1d06SElliott Hughes string patch_path;
138*07fb1d06SElliott Hughes ASSERT_TRUE(MakeTempFile(&patch_path, nullptr));
139*07fb1d06SElliott Hughes ScopedPathUnlinker scoped_unlinker(patch_path);
140*07fb1d06SElliott Hughes ASSERT_TRUE(PuffDiff(src_buf, dst_buf, src_deflates, dst_deflates,
141*07fb1d06SElliott Hughes {bsdiff::CompressorType::kBZ2}, patch_path, &patch_out));
142*07fb1d06SElliott Hughes
143*07fb1d06SElliott Hughes #if PRINT_SAMPLE
144*07fb1d06SElliott Hughes PrintArray("kPatchXXXXX", patch_out);
145*07fb1d06SElliott Hughes #endif
146*07fb1d06SElliott Hughes
147*07fb1d06SElliott Hughes EXPECT_EQ(patch_out, patch);
148*07fb1d06SElliott Hughes
149*07fb1d06SElliott Hughes auto src_stream = MemoryStream::CreateForRead(src_buf);
150*07fb1d06SElliott Hughes Buffer dst_buf_out(dst_buf.size());
151*07fb1d06SElliott Hughes auto dst_stream = MemoryStream::CreateForWrite(&dst_buf_out);
152*07fb1d06SElliott Hughes ASSERT_TRUE(PuffPatch(std::move(src_stream), std::move(dst_stream),
153*07fb1d06SElliott Hughes patch.data(), patch.size()));
154*07fb1d06SElliott Hughes EXPECT_EQ(dst_buf_out, dst_buf);
155*07fb1d06SElliott Hughes }
156*07fb1d06SElliott Hughes
TEST(PatchingTest,Patching1To2Test)157*07fb1d06SElliott Hughes TEST(PatchingTest, Patching1To2Test) {
158*07fb1d06SElliott Hughes TestPatching(kDeflatesSample1, kDeflatesSample2,
159*07fb1d06SElliott Hughes kSubblockDeflateExtentsSample1, kSubblockDeflateExtentsSample2,
160*07fb1d06SElliott Hughes kPatch1To2);
161*07fb1d06SElliott Hughes }
162*07fb1d06SElliott Hughes
TEST(PatchingTest,Patching2To1Test)163*07fb1d06SElliott Hughes TEST(PatchingTest, Patching2To1Test) {
164*07fb1d06SElliott Hughes TestPatching(kDeflatesSample2, kDeflatesSample1,
165*07fb1d06SElliott Hughes kSubblockDeflateExtentsSample2, kSubblockDeflateExtentsSample1,
166*07fb1d06SElliott Hughes kPatch2To1);
167*07fb1d06SElliott Hughes }
168*07fb1d06SElliott Hughes
TEST(PatchingTest,Patching1ToEmptyTest)169*07fb1d06SElliott Hughes TEST(PatchingTest, Patching1ToEmptyTest) {
170*07fb1d06SElliott Hughes TestPatching(kDeflatesSample1, {}, kSubblockDeflateExtentsSample1, {},
171*07fb1d06SElliott Hughes kPatch1ToEmpty);
172*07fb1d06SElliott Hughes }
173*07fb1d06SElliott Hughes
TEST(PatchingTest,Patching1ToNoDeflateTest)174*07fb1d06SElliott Hughes TEST(PatchingTest, Patching1ToNoDeflateTest) {
175*07fb1d06SElliott Hughes TestPatching(kDeflatesSample1, {11, 22, 33, 44},
176*07fb1d06SElliott Hughes kSubblockDeflateExtentsSample1, {}, kPatch1ToNoDeflate);
177*07fb1d06SElliott Hughes }
178*07fb1d06SElliott Hughes
179*07fb1d06SElliott Hughes // TODO(ahassani): add tests for:
180*07fb1d06SElliott Hughes // TestPatchingEmptyTo2
181*07fb1d06SElliott Hughes // TestPatchingNoDeflateTo2
182*07fb1d06SElliott Hughes
183*07fb1d06SElliott Hughes // TODO(ahassani): Change tests data if you decided to compress the header of
184*07fb1d06SElliott Hughes // the patch.
185*07fb1d06SElliott Hughes
186*07fb1d06SElliott Hughes } // namespace puffin
187