zip_unittest.cc revision ab5a0af8e6ebac0211da5b08010e4855ce463108
1//
2// Copyright (C) 2011 The Android Open Source Project
3//
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at
7//
8//      http://www.apache.org/licenses/LICENSE-2.0
9//
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS,
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
15//
16
17#include <string.h>
18#include <unistd.h>
19
20#include <memory>
21#include <string>
22#include <vector>
23
24#include <gtest/gtest.h>
25
26#include "update_engine/common/test_utils.h"
27#include "update_engine/payload_consumer/bzip_extent_writer.h"
28#include "update_engine/payload_consumer/extent_writer.h"
29#include "update_engine/payload_consumer/xz_extent_writer.h"
30#include "update_engine/payload_generator/bzip.h"
31#include "update_engine/payload_generator/xz.h"
32
33using chromeos_update_engine::test_utils::kRandomString;
34using google::protobuf::RepeatedPtrField;
35using std::string;
36using std::vector;
37
38namespace chromeos_update_engine {
39
40namespace {
41
42// ExtentWriter class that writes to memory, used to test the decompression
43// step with the corresponding extent writer.
44class MemoryExtentWriter : public ExtentWriter {
45 public:
46  // Creates the ExtentWriter that will write all the bytes to the passed |data|
47  // blob.
48  explicit MemoryExtentWriter(brillo::Blob* data) : data_(data) {
49    data_->clear();
50  }
51  ~MemoryExtentWriter() override = default;
52
53  bool Init(FileDescriptorPtr fd,
54            const RepeatedPtrField<Extent>& extents,
55            uint32_t block_size) override {
56    return true;
57  }
58  bool Write(const void* bytes, size_t count) override {
59    data_->reserve(data_->size() + count);
60    data_->insert(data_->end(),
61                  static_cast<const uint8_t*>(bytes),
62                  static_cast<const uint8_t*>(bytes) + count);
63    return true;
64  }
65  bool EndImpl() override { return true; }
66
67 private:
68  brillo::Blob* data_;
69};
70
71template <typename W>
72bool DecompressWithWriter(const brillo::Blob& in, brillo::Blob* out) {
73  std::unique_ptr<ExtentWriter> writer(
74      new W(std::make_unique<MemoryExtentWriter>(out)));
75  // Init() parameters are ignored by the testing MemoryExtentWriter.
76  bool ok = writer->Init(nullptr, {}, 1);
77  ok = writer->Write(in.data(), in.size()) && ok;
78  // Call End() even if the Write failed.
79  ok = writer->End() && ok;
80  return ok;
81}
82
83}  // namespace
84
85template <typename T>
86class ZipTest : public ::testing::Test {
87 public:
88  bool ZipCompress(const brillo::Blob& in, brillo::Blob* out) const = 0;
89  bool ZipDecompress(const brillo::Blob& in, brillo::Blob* out) const = 0;
90};
91
92class BzipTest {};
93
94template <>
95class ZipTest<BzipTest> : public ::testing::Test {
96 public:
97  bool ZipCompress(const brillo::Blob& in, brillo::Blob* out) const {
98    return BzipCompress(in, out);
99  }
100  bool ZipDecompress(const brillo::Blob& in, brillo::Blob* out) const {
101    return DecompressWithWriter<BzipExtentWriter>(in, out);
102  }
103};
104
105class XzTest {};
106
107template <>
108class ZipTest<XzTest> : public ::testing::Test {
109 public:
110  bool ZipCompress(const brillo::Blob& in, brillo::Blob* out) const {
111    return XzCompress(in, out);
112  }
113  bool ZipDecompress(const brillo::Blob& in, brillo::Blob* out) const {
114    return DecompressWithWriter<XzExtentWriter>(in, out);
115  }
116};
117
118#ifdef __ANDROID__
119typedef ::testing::Types<BzipTest, XzTest> ZipTestTypes;
120#else
121// Chrome OS implementation of Xz compressor just returns false.
122typedef ::testing::Types<BzipTest> ZipTestTypes;
123#endif  // __ANDROID__
124
125TYPED_TEST_CASE(ZipTest, ZipTestTypes);
126
127TYPED_TEST(ZipTest, SimpleTest) {
128  string in_str(
129      "this should compress well xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
130      "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
131      "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
132      "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
133      "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
134      "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
135  brillo::Blob in(in_str.begin(), in_str.end());
136  brillo::Blob out;
137  EXPECT_TRUE(this->ZipCompress(in, &out));
138  EXPECT_LT(out.size(), in.size());
139  EXPECT_GT(out.size(), 0U);
140  brillo::Blob decompressed;
141  EXPECT_TRUE(this->ZipDecompress(out, &decompressed));
142  EXPECT_EQ(in.size(), decompressed.size());
143  EXPECT_TRUE(!memcmp(in.data(), decompressed.data(), in.size()));
144}
145
146TYPED_TEST(ZipTest, PoorCompressionTest) {
147  brillo::Blob in(std::begin(kRandomString), std::end(kRandomString));
148  brillo::Blob out;
149  EXPECT_TRUE(this->ZipCompress(in, &out));
150  EXPECT_GT(out.size(), in.size());
151  brillo::Blob decompressed;
152  EXPECT_TRUE(this->ZipDecompress(out, &decompressed));
153  EXPECT_EQ(in.size(), decompressed.size());
154  EXPECT_EQ(in, decompressed);
155}
156
157TYPED_TEST(ZipTest, MalformedZipTest) {
158  brillo::Blob in(std::begin(kRandomString), std::end(kRandomString));
159  brillo::Blob out;
160  EXPECT_FALSE(this->ZipDecompress(in, &out));
161}
162
163TYPED_TEST(ZipTest, EmptyInputsTest) {
164  brillo::Blob in;
165  brillo::Blob out;
166  EXPECT_TRUE(this->ZipDecompress(in, &out));
167  EXPECT_EQ(0U, out.size());
168
169  EXPECT_TRUE(this->ZipCompress(in, &out));
170  EXPECT_EQ(0U, out.size());
171}
172
173}  // namespace chromeos_update_engine
174