1 // Copyright 2015 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/bsdiff.h"
6 
7 #include <gtest/gtest.h>
8 #include <algorithm>
9 #include <random>
10 #include <string>
11 #include <vector>
12 
13 #include "bsdiff/fake_patch_writer.h"
14 
15 namespace {
16 
17 // Generate deterministic random data in the output buffer. The buffer must be
18 // already allocated with the desired size. The data generated depends on the
19 // selected size.
20 void GenerateRandomBuffer(std::vector<uint8_t>* buffer) {
21   std::minstd_rand prng(1234 + buffer->size());
22   std::generate(buffer->begin(), buffer->end(), prng);
23 }
24 
25 }  // namespace
26 
27 namespace bsdiff {
28 
29 class BsdiffTest : public testing::Test {
30  protected:
31   BsdiffTest() = default;
32   ~BsdiffTest() override = default;
33 
34   void RunBsdiff() {
35     EXPECT_EQ(0, bsdiff(old_file_.data(), old_file_.size(), new_file_.data(),
36                         new_file_.size(), min_len_, &patch_writer_, nullptr));
37   }
38 
39   std::vector<uint8_t> old_file_;
40   std::vector<uint8_t> new_file_;
41   size_t min_len_ = 0;  // 0 means the default.
42   FakePatchWriter patch_writer_;
43 };
44 
45 // Check that a file with no changes has a very small patch (no extra data).
46 TEST_F(BsdiffTest, EqualEmptyFiles) {
47   // Empty old and new files.
48   RunBsdiff();
49 
50   // No entries should be generated on an empty new file.
51   EXPECT_TRUE(patch_writer_.entries().empty());
52 }
53 
54 TEST_F(BsdiffTest, EqualSmallFiles) {
55   std::string some_text = "Hello world!";
56   old_file_.insert(old_file_.begin(), some_text.begin(), some_text.end());
57   new_file_.insert(new_file_.begin(), some_text.begin(), some_text.end());
58   RunBsdiff();
59 
60   EXPECT_EQ(1U, patch_writer_.entries().size());
61   ControlEntry entry = patch_writer_.entries()[0];
62   EXPECT_EQ(some_text.size(), entry.diff_size);
63   EXPECT_EQ(0U, entry.extra_size);
64 }
65 
66 TEST_F(BsdiffTest, FileWithSmallErrorsTest) {
67   old_file_.resize(100);
68   GenerateRandomBuffer(&old_file_);
69   new_file_ = old_file_;
70   // Break a few bytes somewhere in the middle.
71   new_file_[20]++;
72   new_file_[30] += 2;
73   new_file_[31] += 2;
74 
75   RunBsdiff();
76 
77   // We expect that the result has only one entry with all in the diff stream
78   // since the two files are very similar.
79   EXPECT_EQ(1U, patch_writer_.entries().size());
80   ControlEntry entry = patch_writer_.entries()[0];
81   EXPECT_EQ(100U, entry.diff_size);
82   EXPECT_EQ(0U, entry.extra_size);
83 }
84 
85 TEST_F(BsdiffTest, MinLengthConsideredTest) {
86   old_file_.resize(100);
87   GenerateRandomBuffer(&old_file_);
88   new_file_ = old_file_;
89   // Copy the first 10 bytes to the middle.
90   for (size_t i = 0; i < 10; i++) {
91     new_file_[50 + i] = old_file_[i];
92   }
93 
94   min_len_ = 12;
95   RunBsdiff();
96 
97   // We expect that the 10 bytes in the middle that match the beginning are
98   // ignored and just emitted as diff data because the min_len is bigger than
99   // 10.
100   EXPECT_EQ(1U, patch_writer_.entries().size());
101   ControlEntry entry = patch_writer_.entries()[0];
102   EXPECT_EQ(100U, entry.diff_size);
103   EXPECT_EQ(0U, entry.extra_size);
104 }
105 
106 }  // namespace bsdiff
107