1710b3daa482eb100bdaae7ffb46724273bd404d5Alex Deymo// Copyright 2017 The Chromium OS Authors. All rights reserved. 2710b3daa482eb100bdaae7ffb46724273bd404d5Alex Deymo// Use of this source code is governed by a BSD-style license that can be 3710b3daa482eb100bdaae7ffb46724273bd404d5Alex Deymo// found in the LICENSE file. 4710b3daa482eb100bdaae7ffb46724273bd404d5Alex Deymo 5710b3daa482eb100bdaae7ffb46724273bd404d5Alex Deymo#include "bsdiff/endsley_patch_writer.h" 6710b3daa482eb100bdaae7ffb46724273bd404d5Alex Deymo 7710b3daa482eb100bdaae7ffb46724273bd404d5Alex Deymo#include <algorithm> 8710b3daa482eb100bdaae7ffb46724273bd404d5Alex Deymo 9710b3daa482eb100bdaae7ffb46724273bd404d5Alex Deymo#include <gtest/gtest.h> 10710b3daa482eb100bdaae7ffb46724273bd404d5Alex Deymo 11710b3daa482eb100bdaae7ffb46724273bd404d5Alex Deymonamespace { 12710b3daa482eb100bdaae7ffb46724273bd404d5Alex Deymo 13710b3daa482eb100bdaae7ffb46724273bd404d5Alex Deymostd::vector<uint8_t> VectorFromString(const std::string& s) { 14710b3daa482eb100bdaae7ffb46724273bd404d5Alex Deymo return std::vector<uint8_t>(s.data(), s.data() + s.size()); 15710b3daa482eb100bdaae7ffb46724273bd404d5Alex Deymo} 16710b3daa482eb100bdaae7ffb46724273bd404d5Alex Deymo 17710b3daa482eb100bdaae7ffb46724273bd404d5Alex Deymo} // namespace 18710b3daa482eb100bdaae7ffb46724273bd404d5Alex Deymo 19710b3daa482eb100bdaae7ffb46724273bd404d5Alex Deymonamespace bsdiff { 20710b3daa482eb100bdaae7ffb46724273bd404d5Alex Deymo 21710b3daa482eb100bdaae7ffb46724273bd404d5Alex Deymoclass EndsleyPatchWriterTest : public testing::Test { 22710b3daa482eb100bdaae7ffb46724273bd404d5Alex Deymo protected: 23710b3daa482eb100bdaae7ffb46724273bd404d5Alex Deymo // Return a subvector from |data_| starting at |start| of size at most |size|. 24710b3daa482eb100bdaae7ffb46724273bd404d5Alex Deymo std::vector<uint8_t> DataSubvector(size_t start, size_t size) { 25710b3daa482eb100bdaae7ffb46724273bd404d5Alex Deymo if (start > data_.size()) 26710b3daa482eb100bdaae7ffb46724273bd404d5Alex Deymo return std::vector<uint8_t>(); 27710b3daa482eb100bdaae7ffb46724273bd404d5Alex Deymo 28710b3daa482eb100bdaae7ffb46724273bd404d5Alex Deymo size = std::min(size, data_.size() - start); 29710b3daa482eb100bdaae7ffb46724273bd404d5Alex Deymo return std::vector<uint8_t>(data_.begin() + start, 30710b3daa482eb100bdaae7ffb46724273bd404d5Alex Deymo data_.begin() + start + size); 31710b3daa482eb100bdaae7ffb46724273bd404d5Alex Deymo } 32710b3daa482eb100bdaae7ffb46724273bd404d5Alex Deymo 33710b3daa482eb100bdaae7ffb46724273bd404d5Alex Deymo std::vector<uint8_t> data_; 3419fc575d869148d6b33407b115f40bee9b22e244Alex Deymo EndsleyPatchWriter patch_writer_{&data_, CompressorType::kNoCompression, 0}; 35710b3daa482eb100bdaae7ffb46724273bd404d5Alex Deymo}; 36710b3daa482eb100bdaae7ffb46724273bd404d5Alex Deymo 37710b3daa482eb100bdaae7ffb46724273bd404d5Alex Deymo// Smoke check that a patch includes the new_size and magic header. 38710b3daa482eb100bdaae7ffb46724273bd404d5Alex DeymoTEST_F(EndsleyPatchWriterTest, CreateEmptyPatchTest) { 39710b3daa482eb100bdaae7ffb46724273bd404d5Alex Deymo EXPECT_TRUE(patch_writer_.Init(0)); 40710b3daa482eb100bdaae7ffb46724273bd404d5Alex Deymo EXPECT_TRUE(patch_writer_.Close()); 41710b3daa482eb100bdaae7ffb46724273bd404d5Alex Deymo 42710b3daa482eb100bdaae7ffb46724273bd404d5Alex Deymo // The empty header is set to 24 bytes. 43710b3daa482eb100bdaae7ffb46724273bd404d5Alex Deymo EXPECT_EQ(24U, data_.size()); 44710b3daa482eb100bdaae7ffb46724273bd404d5Alex Deymo 45710b3daa482eb100bdaae7ffb46724273bd404d5Alex Deymo std::vector<uint8_t> empty_patch = { 46710b3daa482eb100bdaae7ffb46724273bd404d5Alex Deymo // Magic header. 47710b3daa482eb100bdaae7ffb46724273bd404d5Alex Deymo 'E', 'N', 'D', 'S', 'L', 'E', 'Y', '/', 'B', 'S', 'D', 'I', 'F', 'F', '4', 48710b3daa482eb100bdaae7ffb46724273bd404d5Alex Deymo '3', 49710b3daa482eb100bdaae7ffb46724273bd404d5Alex Deymo // 8 zeros for the |new_size| of zero bytes. 50710b3daa482eb100bdaae7ffb46724273bd404d5Alex Deymo 0, 0, 0, 0, 0, 0, 0, 0}; 51710b3daa482eb100bdaae7ffb46724273bd404d5Alex Deymo EXPECT_EQ(empty_patch, data_); 52710b3daa482eb100bdaae7ffb46724273bd404d5Alex Deymo} 53710b3daa482eb100bdaae7ffb46724273bd404d5Alex Deymo 5419fc575d869148d6b33407b115f40bee9b22e244Alex DeymoTEST_F(EndsleyPatchWriterTest, CreateCompressedPatchTest) { 5519fc575d869148d6b33407b115f40bee9b22e244Alex Deymo EndsleyPatchWriter compressed_writer(&data_, CompressorType::kBZ2, 9); 5619fc575d869148d6b33407b115f40bee9b22e244Alex Deymo 5719fc575d869148d6b33407b115f40bee9b22e244Alex Deymo auto text = VectorFromString("HelloWorld"); 5819fc575d869148d6b33407b115f40bee9b22e244Alex Deymo EXPECT_TRUE(compressed_writer.Init(text.size())); 5919fc575d869148d6b33407b115f40bee9b22e244Alex Deymo 6019fc575d869148d6b33407b115f40bee9b22e244Alex Deymo EXPECT_TRUE(compressed_writer.AddControlEntry(ControlEntry(5, 5, -2))); 6119fc575d869148d6b33407b115f40bee9b22e244Alex Deymo EXPECT_TRUE(compressed_writer.WriteDiffStream(text.data(), 5)); 6219fc575d869148d6b33407b115f40bee9b22e244Alex Deymo EXPECT_TRUE(compressed_writer.WriteExtraStream(text.data() + 5, 5)); 6319fc575d869148d6b33407b115f40bee9b22e244Alex Deymo 6419fc575d869148d6b33407b115f40bee9b22e244Alex Deymo // Check that the output patch had no data written to it before Close() is 6519fc575d869148d6b33407b115f40bee9b22e244Alex Deymo // called, since we are still compressing it. 6619fc575d869148d6b33407b115f40bee9b22e244Alex Deymo EXPECT_TRUE(data_.empty()); 6719fc575d869148d6b33407b115f40bee9b22e244Alex Deymo 6819fc575d869148d6b33407b115f40bee9b22e244Alex Deymo EXPECT_TRUE(compressed_writer.Close()); 6919fc575d869148d6b33407b115f40bee9b22e244Alex Deymo 7019fc575d869148d6b33407b115f40bee9b22e244Alex Deymo // Check that the whole file is compressed with BZ2 by looking at the header. 7119fc575d869148d6b33407b115f40bee9b22e244Alex Deymo const auto bz2_header = VectorFromString("BZh9"); 7219fc575d869148d6b33407b115f40bee9b22e244Alex Deymo data_.resize(4); 7319fc575d869148d6b33407b115f40bee9b22e244Alex Deymo EXPECT_EQ(bz2_header, data_); 7419fc575d869148d6b33407b115f40bee9b22e244Alex Deymo} 7519fc575d869148d6b33407b115f40bee9b22e244Alex Deymo 7619fc575d869148d6b33407b115f40bee9b22e244Alex DeymoTEST_F(EndsleyPatchWriterTest, CreateEmptyBrotliPatchTest) { 7719fc575d869148d6b33407b115f40bee9b22e244Alex Deymo EndsleyPatchWriter compressed_writer(&data_, CompressorType::kBrotli, 9); 7819fc575d869148d6b33407b115f40bee9b22e244Alex Deymo EXPECT_TRUE(compressed_writer.Init(0)); 7919fc575d869148d6b33407b115f40bee9b22e244Alex Deymo EXPECT_TRUE(compressed_writer.Close()); 8019fc575d869148d6b33407b115f40bee9b22e244Alex Deymo} 8119fc575d869148d6b33407b115f40bee9b22e244Alex Deymo 82710b3daa482eb100bdaae7ffb46724273bd404d5Alex Deymo// Test we generate the right patch when the control, diff and extra stream come 83710b3daa482eb100bdaae7ffb46724273bd404d5Alex Deymo// in the right order. 84710b3daa482eb100bdaae7ffb46724273bd404d5Alex DeymoTEST_F(EndsleyPatchWriterTest, DataInNiceOrderTest) { 85710b3daa482eb100bdaae7ffb46724273bd404d5Alex Deymo auto text = VectorFromString("abcdeFGHIJ"); 86710b3daa482eb100bdaae7ffb46724273bd404d5Alex Deymo EXPECT_TRUE(patch_writer_.Init(10)); 87710b3daa482eb100bdaae7ffb46724273bd404d5Alex Deymo 88710b3daa482eb100bdaae7ffb46724273bd404d5Alex Deymo EXPECT_TRUE(patch_writer_.AddControlEntry(ControlEntry(2, 3, -2))); 89710b3daa482eb100bdaae7ffb46724273bd404d5Alex Deymo EXPECT_TRUE(patch_writer_.WriteDiffStream(text.data(), 2)); 90710b3daa482eb100bdaae7ffb46724273bd404d5Alex Deymo EXPECT_TRUE(patch_writer_.WriteExtraStream(text.data() + 2, 3)); 91710b3daa482eb100bdaae7ffb46724273bd404d5Alex Deymo 92710b3daa482eb100bdaae7ffb46724273bd404d5Alex Deymo // Check that we are actually writing to the output vector as soon as we can. 93710b3daa482eb100bdaae7ffb46724273bd404d5Alex Deymo EXPECT_EQ(24U + 24U + 2U + 3U, data_.size()); 94710b3daa482eb100bdaae7ffb46724273bd404d5Alex Deymo 95710b3daa482eb100bdaae7ffb46724273bd404d5Alex Deymo EXPECT_TRUE(patch_writer_.AddControlEntry(ControlEntry(0, 5, 1024))); 96710b3daa482eb100bdaae7ffb46724273bd404d5Alex Deymo EXPECT_TRUE(patch_writer_.WriteExtraStream(text.data() + 5, 5)); 97710b3daa482eb100bdaae7ffb46724273bd404d5Alex Deymo 98710b3daa482eb100bdaae7ffb46724273bd404d5Alex Deymo EXPECT_TRUE(patch_writer_.Close()); 99710b3daa482eb100bdaae7ffb46724273bd404d5Alex Deymo 100710b3daa482eb100bdaae7ffb46724273bd404d5Alex Deymo // We have a header, 2 control entries and a total of 10 bytes of data. 101710b3daa482eb100bdaae7ffb46724273bd404d5Alex Deymo EXPECT_EQ(24U + 24U * 2 + 10U, data_.size()); 102710b3daa482eb100bdaae7ffb46724273bd404d5Alex Deymo 103710b3daa482eb100bdaae7ffb46724273bd404d5Alex Deymo // Verify that control entry values are encoded properly in little-endian. 104710b3daa482eb100bdaae7ffb46724273bd404d5Alex Deymo EXPECT_EQ((std::vector<uint8_t>{10, 0, 0, 0, 0, 0, 0, 0}), 105710b3daa482eb100bdaae7ffb46724273bd404d5Alex Deymo DataSubvector(16U, 8)); // new_size 106710b3daa482eb100bdaae7ffb46724273bd404d5Alex Deymo 107710b3daa482eb100bdaae7ffb46724273bd404d5Alex Deymo // Negative numbers are encoded with the sign bit in the most significant bit 108710b3daa482eb100bdaae7ffb46724273bd404d5Alex Deymo // of the 8-byte number. 109710b3daa482eb100bdaae7ffb46724273bd404d5Alex Deymo EXPECT_EQ((std::vector<uint8_t>{2, 0, 0, 0, 0, 0, 0, 0x80}), 110710b3daa482eb100bdaae7ffb46724273bd404d5Alex Deymo DataSubvector(24U + 16, 8)); 111710b3daa482eb100bdaae7ffb46724273bd404d5Alex Deymo 112710b3daa482eb100bdaae7ffb46724273bd404d5Alex Deymo // The second member on the last control entry (1024) encoded in 113710b3daa482eb100bdaae7ffb46724273bd404d5Alex Deymo // little-endian. 114710b3daa482eb100bdaae7ffb46724273bd404d5Alex Deymo EXPECT_EQ((std::vector<uint8_t>{0, 4, 0, 0, 0, 0, 0, 0}), 115710b3daa482eb100bdaae7ffb46724273bd404d5Alex Deymo DataSubvector(24U + 24U + 5U + 16U, 8)); 116710b3daa482eb100bdaae7ffb46724273bd404d5Alex Deymo 117710b3daa482eb100bdaae7ffb46724273bd404d5Alex Deymo // Check that the diff and extra data are sent one after the other in the 118710b3daa482eb100bdaae7ffb46724273bd404d5Alex Deymo // right order. 119710b3daa482eb100bdaae7ffb46724273bd404d5Alex Deymo EXPECT_EQ(VectorFromString("abcde"), DataSubvector(24U + 24U, 5)); 120710b3daa482eb100bdaae7ffb46724273bd404d5Alex Deymo} 121710b3daa482eb100bdaae7ffb46724273bd404d5Alex Deymo 122710b3daa482eb100bdaae7ffb46724273bd404d5Alex Deymo// When we send first the diff or extra data it shouldn't be possible to 123710b3daa482eb100bdaae7ffb46724273bd404d5Alex Deymo// write it to the patch, but at the end of the patch we should be able to 124710b3daa482eb100bdaae7ffb46724273bd404d5Alex Deymo// write it all. 125710b3daa482eb100bdaae7ffb46724273bd404d5Alex DeymoTEST_F(EndsleyPatchWriterTest, DataInBadOrderTest) { 126710b3daa482eb100bdaae7ffb46724273bd404d5Alex Deymo auto text = VectorFromString("abcdeFGHIJ"); 127710b3daa482eb100bdaae7ffb46724273bd404d5Alex Deymo EXPECT_TRUE(patch_writer_.Init(10)); 128710b3daa482eb100bdaae7ffb46724273bd404d5Alex Deymo EXPECT_TRUE(patch_writer_.WriteDiffStream(text.data(), 5)); 129710b3daa482eb100bdaae7ffb46724273bd404d5Alex Deymo EXPECT_TRUE(patch_writer_.WriteExtraStream(text.data() + 5, 5)); 130710b3daa482eb100bdaae7ffb46724273bd404d5Alex Deymo 131710b3daa482eb100bdaae7ffb46724273bd404d5Alex Deymo // Writ all the control entries at the end, only the header should have been 132710b3daa482eb100bdaae7ffb46724273bd404d5Alex Deymo // sent so far. 133710b3daa482eb100bdaae7ffb46724273bd404d5Alex Deymo EXPECT_EQ(24U, data_.size()); 134710b3daa482eb100bdaae7ffb46724273bd404d5Alex Deymo 135710b3daa482eb100bdaae7ffb46724273bd404d5Alex Deymo EXPECT_TRUE(patch_writer_.AddControlEntry(ControlEntry(2, 3, -2))); 136710b3daa482eb100bdaae7ffb46724273bd404d5Alex Deymo EXPECT_TRUE(patch_writer_.AddControlEntry(ControlEntry(2, 1, 1024))); 137710b3daa482eb100bdaae7ffb46724273bd404d5Alex Deymo EXPECT_TRUE(patch_writer_.AddControlEntry(ControlEntry(1, 1, 1024))); 138710b3daa482eb100bdaae7ffb46724273bd404d5Alex Deymo 139710b3daa482eb100bdaae7ffb46724273bd404d5Alex Deymo EXPECT_TRUE(patch_writer_.Close()); 140710b3daa482eb100bdaae7ffb46724273bd404d5Alex Deymo 141710b3daa482eb100bdaae7ffb46724273bd404d5Alex Deymo // We have a header, 3 control entries and a total of 10 bytes of data. 142710b3daa482eb100bdaae7ffb46724273bd404d5Alex Deymo EXPECT_EQ(24U + 24U * 3 + 10U, data_.size()); 143710b3daa482eb100bdaae7ffb46724273bd404d5Alex Deymo 144710b3daa482eb100bdaae7ffb46724273bd404d5Alex Deymo // The data from the first and second control entries: 145710b3daa482eb100bdaae7ffb46724273bd404d5Alex Deymo EXPECT_EQ(VectorFromString("abFGH"), DataSubvector(24U + 24U, 5)); 146710b3daa482eb100bdaae7ffb46724273bd404d5Alex Deymo EXPECT_EQ(VectorFromString("cdI"), DataSubvector(24U + 24U * 2 + 5, 3)); 147710b3daa482eb100bdaae7ffb46724273bd404d5Alex Deymo EXPECT_EQ(VectorFromString("eJ"), DataSubvector(24U + 24U * 3 + 8, 2)); 148710b3daa482eb100bdaae7ffb46724273bd404d5Alex Deymo} 149710b3daa482eb100bdaae7ffb46724273bd404d5Alex Deymo 150710b3daa482eb100bdaae7ffb46724273bd404d5Alex DeymoTEST_F(EndsleyPatchWriterTest, FlushOnlyWhenWorthItTest) { 151710b3daa482eb100bdaae7ffb46724273bd404d5Alex Deymo size_t kEntrySize = 1000; // must be even for this test. 152710b3daa482eb100bdaae7ffb46724273bd404d5Alex Deymo size_t kNumEntries = 3000; 153710b3daa482eb100bdaae7ffb46724273bd404d5Alex Deymo size_t kNewSize = kEntrySize * kNumEntries; // 3 MB 154710b3daa482eb100bdaae7ffb46724273bd404d5Alex Deymo 155710b3daa482eb100bdaae7ffb46724273bd404d5Alex Deymo EXPECT_TRUE(patch_writer_.Init(kNewSize)); 156710b3daa482eb100bdaae7ffb46724273bd404d5Alex Deymo // Write all the extra and diff data first. 157710b3daa482eb100bdaae7ffb46724273bd404d5Alex Deymo std::vector<uint8_t> zeros(kNewSize / 2, 0); 158710b3daa482eb100bdaae7ffb46724273bd404d5Alex Deymo EXPECT_TRUE(patch_writer_.WriteDiffStream(zeros.data(), zeros.size())); 159710b3daa482eb100bdaae7ffb46724273bd404d5Alex Deymo EXPECT_TRUE(patch_writer_.WriteExtraStream(zeros.data(), zeros.size())); 160710b3daa482eb100bdaae7ffb46724273bd404d5Alex Deymo 161710b3daa482eb100bdaae7ffb46724273bd404d5Alex Deymo // No patch data flushed so far, only the header. 162710b3daa482eb100bdaae7ffb46724273bd404d5Alex Deymo EXPECT_EQ(24U, data_.size()); 163710b3daa482eb100bdaae7ffb46724273bd404d5Alex Deymo 164710b3daa482eb100bdaae7ffb46724273bd404d5Alex Deymo ControlEntry entry(kEntrySize / 2, kEntrySize / 2, -1); 165710b3daa482eb100bdaae7ffb46724273bd404d5Alex Deymo for (size_t i = 0; i < 10; i++) { 166710b3daa482eb100bdaae7ffb46724273bd404d5Alex Deymo EXPECT_TRUE(patch_writer_.AddControlEntry(entry)); 167710b3daa482eb100bdaae7ffb46724273bd404d5Alex Deymo } 168710b3daa482eb100bdaae7ffb46724273bd404d5Alex Deymo 169710b3daa482eb100bdaae7ffb46724273bd404d5Alex Deymo // Even if all the diff and extra data is available and some control entries 170710b3daa482eb100bdaae7ffb46724273bd404d5Alex Deymo // are also available no information should have been flushed yet because we 171710b3daa482eb100bdaae7ffb46724273bd404d5Alex Deymo // don't want the overhead of updating the diff_data_ and extra_data_ vectors. 172710b3daa482eb100bdaae7ffb46724273bd404d5Alex Deymo EXPECT_EQ(24U, data_.size()); 173710b3daa482eb100bdaae7ffb46724273bd404d5Alex Deymo 174710b3daa482eb100bdaae7ffb46724273bd404d5Alex Deymo // Write the remaining entries. 175710b3daa482eb100bdaae7ffb46724273bd404d5Alex Deymo for (size_t i = 0; i < kNumEntries - 10; i++) { 176710b3daa482eb100bdaae7ffb46724273bd404d5Alex Deymo EXPECT_TRUE(patch_writer_.AddControlEntry(entry)); 177710b3daa482eb100bdaae7ffb46724273bd404d5Alex Deymo } 178710b3daa482eb100bdaae7ffb46724273bd404d5Alex Deymo 179710b3daa482eb100bdaae7ffb46724273bd404d5Alex Deymo // Even before Close() is called, we have enough control entries to make it 180710b3daa482eb100bdaae7ffb46724273bd404d5Alex Deymo // worth it calling flush at some point. 181710b3daa482eb100bdaae7ffb46724273bd404d5Alex Deymo EXPECT_LT(24U, data_.size()); 182710b3daa482eb100bdaae7ffb46724273bd404d5Alex Deymo 183710b3daa482eb100bdaae7ffb46724273bd404d5Alex Deymo EXPECT_TRUE(patch_writer_.Close()); 184710b3daa482eb100bdaae7ffb46724273bd404d5Alex Deymo} 185710b3daa482eb100bdaae7ffb46724273bd404d5Alex Deymo 186710b3daa482eb100bdaae7ffb46724273bd404d5Alex Deymo} // namespace bsdiff 187