Alex Deymo | e1140a2 | 2017-10-02 21:01:15 +0200 | [diff] [blame] | 1 | // Copyright 2017 The Chromium OS Authors. All rights reserved. |
| 2 | // Use of this source code is governed by a BSD-style license that can be |
| 3 | // found in the LICENSE file. |
| 4 | |
| 5 | #include "bsdiff/split_patch_writer.h" |
| 6 | |
| 7 | #include <memory> |
| 8 | #include <vector> |
| 9 | |
| 10 | #include <gtest/gtest.h> |
| 11 | |
| 12 | #include "bsdiff/fake_patch_writer.h" |
| 13 | #include "bsdiff/test_utils.h" |
| 14 | |
| 15 | namespace bsdiff { |
| 16 | |
| 17 | class SplitPatchWriterTest : public testing::Test { |
| 18 | protected: |
Alex Deymo | 4dadd8b | 2017-10-26 16:19:33 +0200 | [diff] [blame] | 19 | void SetUpForSize(size_t num_chunks, |
| 20 | uint64_t new_chunk_size, |
| 21 | size_t new_size) { |
Alex Deymo | e1140a2 | 2017-10-02 21:01:15 +0200 | [diff] [blame] | 22 | fake_patches_.resize(num_chunks); |
| 23 | std::vector<PatchWriterInterface*> patches; |
| 24 | for (auto& fake_patch : fake_patches_) |
| 25 | patches.push_back(&fake_patch); |
| 26 | |
| 27 | patch_writer_.reset(new SplitPatchWriter(new_chunk_size, patches)); |
Alex Deymo | 4dadd8b | 2017-10-26 16:19:33 +0200 | [diff] [blame] | 28 | EXPECT_TRUE(patch_writer_->Init(new_size)); |
Alex Deymo | e1140a2 | 2017-10-02 21:01:15 +0200 | [diff] [blame] | 29 | } |
| 30 | |
| 31 | std::vector<FakePatchWriter> fake_patches_; |
| 32 | std::unique_ptr<SplitPatchWriter> patch_writer_; |
| 33 | }; |
| 34 | |
Alex Deymo | 4dadd8b | 2017-10-26 16:19:33 +0200 | [diff] [blame] | 35 | TEST_F(SplitPatchWriterTest, InvalidNumberOfPatchesForSizeTest) { |
| 36 | FakePatchWriter p; |
| 37 | std::vector<PatchWriterInterface*> patches = {&p}; |
| 38 | patch_writer_.reset(new SplitPatchWriter(10, patches)); |
| 39 | // We should have pass two patches. |
| 40 | EXPECT_FALSE(patch_writer_->Init(15)); |
| 41 | } |
| 42 | |
Alex Deymo | e1140a2 | 2017-10-02 21:01:15 +0200 | [diff] [blame] | 43 | // A single empty patch is allowed. |
| 44 | TEST_F(SplitPatchWriterTest, NonSplitEmptyPatchTest) { |
Alex Deymo | 4dadd8b | 2017-10-26 16:19:33 +0200 | [diff] [blame] | 45 | SetUpForSize(1, 100, 0); |
Alex Deymo | e1140a2 | 2017-10-02 21:01:15 +0200 | [diff] [blame] | 46 | EXPECT_TRUE(patch_writer_->Close()); |
| 47 | |
| 48 | EXPECT_TRUE(fake_patches_[0].entries().empty()); |
| 49 | } |
| 50 | |
| 51 | // Leaving patches at the end that are empty is considered an error. |
| 52 | TEST_F(SplitPatchWriterTest, NotAllPatchesWrittenErrorTest) { |
Alex Deymo | 4dadd8b | 2017-10-26 16:19:33 +0200 | [diff] [blame] | 53 | SetUpForSize(2, 100, 200); |
Alex Deymo | e1140a2 | 2017-10-02 21:01:15 +0200 | [diff] [blame] | 54 | // We write less than the amount needed for two patches, which should fail. |
| 55 | EXPECT_FALSE(patch_writer_->Close()); |
| 56 | } |
| 57 | |
| 58 | TEST_F(SplitPatchWriterTest, MissingDiffBytesErrorTest) { |
Alex Deymo | 4dadd8b | 2017-10-26 16:19:33 +0200 | [diff] [blame] | 59 | SetUpForSize(2, 10, 20); |
Alex Deymo | e1140a2 | 2017-10-02 21:01:15 +0200 | [diff] [blame] | 60 | |
| 61 | EXPECT_TRUE(patch_writer_->AddControlEntry(ControlEntry(15, 5, 0))); |
| 62 | std::vector<uint8_t> zeros(20, 0); |
| 63 | // We write 12 diff bytes instead of the expected 15. This should fail on |
| 64 | // Close(). |
| 65 | EXPECT_TRUE(patch_writer_->WriteDiffStream(zeros.data(), 12)); |
| 66 | EXPECT_TRUE(patch_writer_->WriteExtraStream(zeros.data(), 5)); |
| 67 | EXPECT_FALSE(patch_writer_->Close()); |
| 68 | } |
| 69 | |
| 70 | TEST_F(SplitPatchWriterTest, MissingExtraBytesErrorTest) { |
Alex Deymo | 4dadd8b | 2017-10-26 16:19:33 +0200 | [diff] [blame] | 71 | SetUpForSize(2, 10, 20); |
Alex Deymo | e1140a2 | 2017-10-02 21:01:15 +0200 | [diff] [blame] | 72 | |
| 73 | std::vector<uint8_t> zeros(20, 0); |
| 74 | EXPECT_TRUE(patch_writer_->AddControlEntry(ControlEntry(5, 15, -5))); |
| 75 | EXPECT_TRUE(patch_writer_->WriteDiffStream(zeros.data(), 5)); |
| 76 | // We write a little less than the expected 15. This operation should succeed, |
| 77 | // since we could write the rest later. |
| 78 | EXPECT_TRUE(patch_writer_->WriteExtraStream(zeros.data(), 10)); |
| 79 | EXPECT_FALSE(patch_writer_->Close()); |
| 80 | } |
| 81 | |
| 82 | // Test all sort of corner cases when splitting the ControlEntry across multiple |
| 83 | // patches |
| 84 | TEST_F(SplitPatchWriterTest, SplitControlAcrossSeveralPatchesTest) { |
Alex Deymo | 4dadd8b | 2017-10-26 16:19:33 +0200 | [diff] [blame] | 85 | SetUpForSize(4, 10, 40); |
Alex Deymo | e1140a2 | 2017-10-02 21:01:15 +0200 | [diff] [blame] | 86 | // The middle control entry would be split in tree different patches. |
| 87 | EXPECT_TRUE(patch_writer_->AddControlEntry(ControlEntry(5, 1, -5))); |
| 88 | EXPECT_TRUE(patch_writer_->AddControlEntry(ControlEntry(4, 0, -4))); |
| 89 | // old_pos at this point is 0. This is the end of the first patch. |
| 90 | EXPECT_TRUE(patch_writer_->AddControlEntry(ControlEntry(6, 0, -1))); |
| 91 | // old_pos at this point is 5. |
| 92 | EXPECT_TRUE(patch_writer_->AddControlEntry(ControlEntry(1, 18, 2))); |
| 93 | // old_pos at this point is 8. |
| 94 | EXPECT_TRUE(patch_writer_->AddControlEntry(ControlEntry(1, 0, 1))); |
| 95 | EXPECT_TRUE(patch_writer_->AddControlEntry(ControlEntry(4, 0, -5))); |
| 96 | |
| 97 | std::vector<uint8_t> zeros(40, 0); |
| 98 | EXPECT_TRUE( |
| 99 | patch_writer_->WriteDiffStream(zeros.data(), 5 + 4 + 6 + 1 + 1 + 4)); |
| 100 | EXPECT_TRUE(patch_writer_->WriteExtraStream(zeros.data(), 1 + 18)); |
| 101 | EXPECT_TRUE(patch_writer_->Close()); |
| 102 | |
| 103 | EXPECT_EQ((std::vector<ControlEntry>{ |
| 104 | ControlEntry(5, 1, -5), |
| 105 | ControlEntry(4, 0, 0), // (4, 0, -4) but the -4 is not needed. |
| 106 | }), |
| 107 | fake_patches_[0].entries()); |
| 108 | EXPECT_EQ((std::vector<ControlEntry>{ |
| 109 | // No need for dummy entry because the old_pos is already at 0. |
| 110 | ControlEntry(6, 0, -1), |
| 111 | ControlEntry(1, 3, 0), // the first part of (1, 18, 2) |
| 112 | }), |
| 113 | fake_patches_[1].entries()); |
| 114 | EXPECT_EQ((std::vector<ControlEntry>{ |
| 115 | // No need for dummy entry because the first entry is all in |
| 116 | // the extra stream and this is the last entry. |
| 117 | ControlEntry(0, 10, 0), // the middle part of (1, 18, 2) |
| 118 | }), |
| 119 | fake_patches_[2].entries()); |
| 120 | EXPECT_EQ((std::vector<ControlEntry>{ |
| 121 | // No need for dummy entry because the first entry is all in |
| 122 | // the extra stream, so use that. |
| 123 | ControlEntry(0, 5, 8), // the last part of (1, 18, 2), plus the |
| 124 | // old_pos 5. 8 = 1 + 2 + 5. |
| 125 | ControlEntry(1, 0, 1), // (1, 0, 1) copied |
| 126 | ControlEntry(4, 0, 0), // (4, 0, -5) ignoring the offset. |
| 127 | }), |
| 128 | fake_patches_[3].entries()); |
Alex Deymo | 4dadd8b | 2017-10-26 16:19:33 +0200 | [diff] [blame] | 129 | |
| 130 | for (size_t i = 0; i < fake_patches_.size(); ++i) { |
| 131 | EXPECT_EQ(10U, fake_patches_[i].new_size()) << "where i = " << i; |
| 132 | } |
Alex Deymo | e1140a2 | 2017-10-02 21:01:15 +0200 | [diff] [blame] | 133 | } |
| 134 | |
| 135 | TEST_F(SplitPatchWriterTest, WriteStreamsAfterControlAcrossPatchesTest) { |
| 136 | std::vector<uint8_t> numbers(40); |
| 137 | for (size_t i = 0; i < numbers.size(); ++i) |
| 138 | numbers[i] = 'A' + i; |
| 139 | |
Alex Deymo | 4dadd8b | 2017-10-26 16:19:33 +0200 | [diff] [blame] | 140 | SetUpForSize(4, 10, 40); |
Alex Deymo | e1140a2 | 2017-10-02 21:01:15 +0200 | [diff] [blame] | 141 | // The sequence is 15 diff, 10 extra, 15 diff. |
| 142 | EXPECT_TRUE(patch_writer_->AddControlEntry(ControlEntry(15, 10, 0))); |
| 143 | EXPECT_TRUE(patch_writer_->AddControlEntry(ControlEntry(15, 0, 0))); |
| 144 | // Numbers [0, 30) for the diff stream, and [30, 40) for the extra stream. |
| 145 | EXPECT_TRUE(patch_writer_->WriteDiffStream(numbers.data(), 30)); |
| 146 | EXPECT_TRUE(patch_writer_->WriteExtraStream(numbers.data() + 30, 10)); |
| 147 | EXPECT_TRUE(patch_writer_->Close()); |
| 148 | |
| 149 | EXPECT_EQ(std::vector<uint8_t>(numbers.begin(), numbers.begin() + 10), |
| 150 | fake_patches_[0].diff_stream()); |
| 151 | EXPECT_TRUE(fake_patches_[0].extra_stream().empty()); |
| 152 | |
| 153 | // 5 diff, then 5 extra. |
| 154 | EXPECT_EQ(std::vector<uint8_t>(numbers.begin() + 10, numbers.begin() + 15), |
| 155 | fake_patches_[1].diff_stream()); |
| 156 | EXPECT_EQ(std::vector<uint8_t>(numbers.begin() + 30, numbers.begin() + 35), |
| 157 | fake_patches_[1].extra_stream()); |
| 158 | |
| 159 | // 5 extra, then 5 diff. |
| 160 | EXPECT_EQ(std::vector<uint8_t>(numbers.begin() + 15, numbers.begin() + 20), |
| 161 | fake_patches_[2].diff_stream()); |
| 162 | EXPECT_EQ(std::vector<uint8_t>(numbers.begin() + 35, numbers.begin() + 40), |
| 163 | fake_patches_[2].extra_stream()); |
| 164 | |
| 165 | EXPECT_EQ(std::vector<uint8_t>(numbers.begin() + 20, numbers.begin() + 30), |
| 166 | fake_patches_[3].diff_stream()); |
| 167 | EXPECT_TRUE(fake_patches_[3].extra_stream().empty()); |
| 168 | } |
| 169 | |
| 170 | } // namespace bsdiff |