mirror of
https://github.com/chromium/crashpad.git
synced 2025-03-09 14:06:33 +00:00
[Log minidump] OutputStream interface and zlib implementation
This is the 1st patch for logging minidump in Android. it adds OutputStream interface and zlib implementation for output pipline. Bug: crashpad:308 Change-Id: I4738b8f223886049e6e259b9b25c00e5120156e5 Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/1745355 Commit-Queue: Tao Bai <michaelbai@chromium.org> Reviewed-by: Mark Mentovai <mark@chromium.org>
This commit is contained in:
parent
e3bf3a5fde
commit
9a62344612
@ -49,7 +49,8 @@ if (crashpad_is_mac) {
|
||||
if (!use_system_xcode) {
|
||||
import("//build/config/clang/clang.gni")
|
||||
import("//build/config/mac/mac_sdk.gni")
|
||||
clang_path = rebase_path("$clang_base_path/bin/", root_build_dir) + "clang"
|
||||
clang_path =
|
||||
rebase_path("$clang_base_path/bin/", root_build_dir) + "clang"
|
||||
mig_path = "$mac_bin_path" + "mig"
|
||||
migcom_path = "$mac_bin_path" + "../libexec/migcom"
|
||||
|
||||
@ -165,6 +166,9 @@ static_library("util") {
|
||||
"stdlib/strnlen.cc",
|
||||
"stdlib/strnlen.h",
|
||||
"stdlib/thread_safe_vector.h",
|
||||
"stream/output_stream_interface.h",
|
||||
"stream/zlib_output_stream.cc",
|
||||
"stream/zlib_output_stream.h",
|
||||
"string/split_string.cc",
|
||||
"string/split_string.h",
|
||||
"synchronization/semaphore.h",
|
||||
@ -177,6 +181,8 @@ static_library("util") {
|
||||
"thread/worker_thread.h",
|
||||
]
|
||||
|
||||
defines = [ "ZLIB_CONST" ]
|
||||
|
||||
if (crashpad_is_posix || crashpad_is_fuchsia) {
|
||||
sources += [
|
||||
"file/directory_reader_posix.cc",
|
||||
@ -593,6 +599,9 @@ source_set("util_test") {
|
||||
"stdlib/strlcpy_test.cc",
|
||||
"stdlib/strnlen_test.cc",
|
||||
"stdlib/thread_safe_vector_test.cc",
|
||||
"stream/test_output_stream.cc",
|
||||
"stream/test_output_stream.h",
|
||||
"stream/zlib_output_stream_test.cc",
|
||||
"string/split_string_test.cc",
|
||||
"synchronization/semaphore_test.cc",
|
||||
"thread/thread_log_messages_test.cc",
|
||||
|
64
util/stream/output_stream_interface.h
Normal file
64
util/stream/output_stream_interface.h
Normal file
@ -0,0 +1,64 @@
|
||||
// Copyright 2019 The Crashpad Authors. All rights reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#ifndef CRASHPAD_UTIL_STREAM_OUTPUT_STREAM_INTERFACE_H_
|
||||
#define CRASHPAD_UTIL_STREAM_OUTPUT_STREAM_INTERFACE_H_
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
namespace crashpad {
|
||||
|
||||
//! \brief The interface for an output stream pipeline.
|
||||
//!
|
||||
//! Example:
|
||||
//! <code>
|
||||
//! class OutputStreamInterfaceImpl : public OutputStreamInterface {
|
||||
//! ...
|
||||
//! };
|
||||
//!
|
||||
//! // Create a OutputStream.
|
||||
//! OutputStreamInterfaceImpl impl(...);
|
||||
//! // Write the data multiple times.
|
||||
//! while (has_data) {
|
||||
//! impl.Write(data, size);
|
||||
//! ...
|
||||
//! }
|
||||
//! // Flush internal buffer to indicate all data has been written.
|
||||
//! impl.Flush();
|
||||
//! </code>
|
||||
//!
|
||||
class OutputStreamInterface {
|
||||
public:
|
||||
virtual ~OutputStreamInterface() = default;
|
||||
|
||||
//! \brief Writes \a data to this stream. This method may be called multiple
|
||||
//! times for streaming.
|
||||
//!
|
||||
//! \param[in] data The data that should be written.
|
||||
//! \param[in] size The size of \a data.
|
||||
//!
|
||||
//! \return `true` on success.
|
||||
virtual bool Write(const uint8_t* data, size_t size) = 0;
|
||||
|
||||
//! \brief Flush the internal buffer after all data has been written.
|
||||
//!
|
||||
//! Write() can't be called afterwards.
|
||||
//! \return `true` on success.
|
||||
virtual bool Flush() = 0;
|
||||
};
|
||||
|
||||
} // namespace crashpad
|
||||
|
||||
#endif // CRASHPAD_UTIL_STREAM_OUTPUT_STREAM_INTERFACE_H_
|
48
util/stream/test_output_stream.cc
Normal file
48
util/stream/test_output_stream.cc
Normal file
@ -0,0 +1,48 @@
|
||||
// Copyright 2019 The Crashpad Authors. All rights reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "util/stream/test_output_stream.h"
|
||||
#include "base/logging.h"
|
||||
|
||||
namespace crashpad {
|
||||
namespace test {
|
||||
|
||||
TestOutputStream::TestOutputStream()
|
||||
: last_written_data_(),
|
||||
all_data_(),
|
||||
write_count_(0),
|
||||
flush_count_(0),
|
||||
flush_needed_(false) {}
|
||||
|
||||
TestOutputStream::~TestOutputStream() {
|
||||
DCHECK(!flush_needed_);
|
||||
}
|
||||
|
||||
bool TestOutputStream::Write(const uint8_t* data, size_t size) {
|
||||
last_written_data_.assign(data, data + size);
|
||||
all_data_.insert(all_data_.end(), data, data + size);
|
||||
|
||||
flush_needed_ = true;
|
||||
write_count_++;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool TestOutputStream::Flush() {
|
||||
flush_needed_ = false;
|
||||
flush_count_++;
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace test
|
||||
} // namespace crashpad
|
66
util/stream/test_output_stream.h
Normal file
66
util/stream/test_output_stream.h
Normal file
@ -0,0 +1,66 @@
|
||||
// Copyright 2019 The Crashpad Authors. All rights reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#ifndef CRASHPAD_UTIL_STREAM_TEST_OUTPUT_STREAM_H_
|
||||
#define CRASHPAD_UTIL_STREAM_TEST_OUTPUT_STREAM_H_
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "base/macros.h"
|
||||
#include "util/stream/output_stream_interface.h"
|
||||
|
||||
namespace crashpad {
|
||||
namespace test {
|
||||
|
||||
//! \brief The help class for \a OutputStreamInterface related tests.
|
||||
class TestOutputStream : public OutputStreamInterface {
|
||||
public:
|
||||
TestOutputStream();
|
||||
~TestOutputStream() override;
|
||||
|
||||
// OutputStreamInterface:
|
||||
bool Write(const uint8_t* data, size_t size) override;
|
||||
bool Flush() override;
|
||||
|
||||
//! \return the data that has been received by the last call of Write().
|
||||
const std::vector<uint8_t>& last_written_data() const {
|
||||
return last_written_data_;
|
||||
}
|
||||
|
||||
//! \return all data that has been received.
|
||||
const std::vector<uint8_t>& all_data() const { return all_data_; }
|
||||
|
||||
//! \return the number of times Write() has been called.
|
||||
size_t write_count() const { return write_count_; }
|
||||
|
||||
//! \return the number of times Flush() has been called.
|
||||
size_t flush_count() const { return flush_count_; }
|
||||
|
||||
private:
|
||||
std::vector<uint8_t> last_written_data_;
|
||||
std::vector<uint8_t> all_data_;
|
||||
size_t write_count_;
|
||||
size_t flush_count_;
|
||||
bool flush_needed_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(TestOutputStream);
|
||||
};
|
||||
|
||||
} // namespace test
|
||||
} // namespace crashpad
|
||||
|
||||
#endif // CRASHPAD_UTIL_STREAM_TEST_OUTPUT_STREAM_H_
|
139
util/stream/zlib_output_stream.cc
Normal file
139
util/stream/zlib_output_stream.cc
Normal file
@ -0,0 +1,139 @@
|
||||
// Copyright 2019 The Crashpad Authors. All rights reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "util/stream/zlib_output_stream.h"
|
||||
|
||||
#include "base/logging.h"
|
||||
#include "base/numerics/safe_conversions.h"
|
||||
#include "base/stl_util.h"
|
||||
#include "util/misc/zlib.h"
|
||||
|
||||
namespace crashpad {
|
||||
|
||||
ZlibOutputStream::ZlibOutputStream(
|
||||
Mode mode,
|
||||
std::unique_ptr<OutputStreamInterface> output_stream)
|
||||
: output_stream_(std::move(output_stream)),
|
||||
mode_(mode),
|
||||
initialized_(),
|
||||
flush_needed_(false) {}
|
||||
|
||||
ZlibOutputStream::~ZlibOutputStream() {
|
||||
if (!initialized_.is_valid())
|
||||
return;
|
||||
DCHECK(!flush_needed_);
|
||||
if (mode_ == Mode::kCompress) {
|
||||
if (deflateEnd(&zlib_stream_) != Z_OK)
|
||||
LOG(ERROR) << "deflateEnd: " << zlib_stream_.msg;
|
||||
} else if (mode_ == Mode::kDecompress) {
|
||||
if (inflateEnd(&zlib_stream_) != Z_OK)
|
||||
LOG(ERROR) << "inflateEnd: " << zlib_stream_.msg;
|
||||
}
|
||||
}
|
||||
|
||||
bool ZlibOutputStream::Write(const uint8_t* data, size_t size) {
|
||||
if (initialized_.is_uninitialized()) {
|
||||
initialized_.set_invalid();
|
||||
|
||||
zlib_stream_.zalloc = Z_NULL;
|
||||
zlib_stream_.zfree = Z_NULL;
|
||||
zlib_stream_.opaque = Z_NULL;
|
||||
|
||||
if (mode_ == Mode::kDecompress) {
|
||||
int result = inflateInit(&zlib_stream_);
|
||||
if (result != Z_OK) {
|
||||
LOG(ERROR) << "inflateInit: " << ZlibErrorString(result);
|
||||
return false;
|
||||
}
|
||||
} else if (mode_ == Mode::kCompress) {
|
||||
int result = deflateInit(&zlib_stream_, Z_BEST_COMPRESSION);
|
||||
if (result != Z_OK) {
|
||||
LOG(ERROR) << "deflateInit: " << ZlibErrorString(result);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
zlib_stream_.next_out = buffer_;
|
||||
zlib_stream_.avail_out = base::saturated_cast<uInt>(base::size(buffer_));
|
||||
initialized_.set_valid();
|
||||
}
|
||||
|
||||
if (!initialized_.is_valid())
|
||||
return false;
|
||||
|
||||
zlib_stream_.next_in = data;
|
||||
zlib_stream_.avail_in = base::saturated_cast<uInt>(size);
|
||||
flush_needed_ = false;
|
||||
while (zlib_stream_.avail_in > 0) {
|
||||
if (mode_ == Mode::kCompress) {
|
||||
if (deflate(&zlib_stream_, Z_NO_FLUSH) != Z_OK) {
|
||||
LOG(ERROR) << "deflate: " << zlib_stream_.msg;
|
||||
return false;
|
||||
}
|
||||
} else if (mode_ == Mode::kDecompress) {
|
||||
int result = inflate(&zlib_stream_, Z_NO_FLUSH);
|
||||
if (result == Z_STREAM_END) {
|
||||
if (zlib_stream_.avail_in > 0) {
|
||||
LOG(ERROR) << "inflate: unconsumed input";
|
||||
return false;
|
||||
}
|
||||
} else if (result != Z_OK) {
|
||||
LOG(ERROR) << "inflate: " << zlib_stream_.msg;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (!WriteOutputStream())
|
||||
return false;
|
||||
}
|
||||
flush_needed_ = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ZlibOutputStream::Flush() {
|
||||
if (initialized_.is_valid() && flush_needed_) {
|
||||
flush_needed_ = false;
|
||||
int result = Z_OK;
|
||||
do {
|
||||
if (mode_ == Mode::kCompress) {
|
||||
result = deflate(&zlib_stream_, Z_FINISH);
|
||||
if (result != Z_STREAM_END && result != Z_BUF_ERROR && result != Z_OK) {
|
||||
LOG(ERROR) << "deflate: " << zlib_stream_.msg;
|
||||
return false;
|
||||
}
|
||||
} else if (mode_ == Mode::kDecompress) {
|
||||
result = inflate(&zlib_stream_, Z_FINISH);
|
||||
if (result != Z_STREAM_END && result != Z_BUF_ERROR && result != Z_OK) {
|
||||
LOG(ERROR) << "inflate: " << zlib_stream_.msg;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (!WriteOutputStream())
|
||||
return false;
|
||||
} while (result != Z_STREAM_END);
|
||||
}
|
||||
return output_stream_->Flush();
|
||||
}
|
||||
|
||||
bool ZlibOutputStream::WriteOutputStream() {
|
||||
auto valid_size = base::size(buffer_) - zlib_stream_.avail_out;
|
||||
if (valid_size > 0 && !output_stream_->Write(buffer_, valid_size))
|
||||
return false;
|
||||
|
||||
zlib_stream_.next_out = buffer_;
|
||||
zlib_stream_.avail_out = base::saturated_cast<uInt>(base::size(buffer_));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace crashpad
|
82
util/stream/zlib_output_stream.h
Normal file
82
util/stream/zlib_output_stream.h
Normal file
@ -0,0 +1,82 @@
|
||||
// Copyright 2019 The Crashpad Authors. All rights reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#ifndef CRASHPAD_UTIL_STREAM_ZLIB_OUTPUT_STREAM_H_
|
||||
#define CRASHPAD_UTIL_STREAM_ZLIB_OUTPUT_STREAM_H_
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "base/macros.h"
|
||||
#include "third_party/zlib/zlib_crashpad.h"
|
||||
#include "util/misc/initialization_state.h"
|
||||
#include "util/stream/output_stream_interface.h"
|
||||
|
||||
namespace crashpad {
|
||||
|
||||
//! \brief The class wraps zlib into \a OutputStreamInterface.
|
||||
class ZlibOutputStream : public OutputStreamInterface {
|
||||
public:
|
||||
//! \brief Whether this object is configured to compress or decompress data.
|
||||
enum class Mode : bool {
|
||||
//! \brief Data passed through this object is compressed.
|
||||
kCompress = false,
|
||||
//! \brief Data passed through this object is decompressed.
|
||||
kDecompress = true
|
||||
};
|
||||
|
||||
//! \param[in] mode The work mode of this object.
|
||||
//! \param[in] output_stream The output_stream that this object writes to.
|
||||
//!
|
||||
//! To construct an output pipeline, the output stream needs an output stream
|
||||
//! to write the result to. For example, the code below constructs a
|
||||
//! compress->base94-encoding->log output stream pipline.
|
||||
//!
|
||||
//! <code>
|
||||
//! ZlibOutputStream zlib_output_stream(
|
||||
//! ZlibOutputStream::Mode::kDeflate,
|
||||
//! std::make_unique<Base94OutputStream>(
|
||||
//! Base94OutputStream::Mode::kEncode,
|
||||
//! std::make_unique<LogOutputStream>()));
|
||||
//! </code>
|
||||
//!
|
||||
//!
|
||||
ZlibOutputStream(Mode mode,
|
||||
std::unique_ptr<OutputStreamInterface> output_stream);
|
||||
~ZlibOutputStream() override;
|
||||
|
||||
// OutputStreamInterface:
|
||||
bool Write(const uint8_t* data, size_t size) override;
|
||||
bool Flush() override;
|
||||
|
||||
private:
|
||||
// Write compressed/decompressed data to |output_stream_| and empty the output
|
||||
// buffer in |zlib_stream_|.
|
||||
bool WriteOutputStream();
|
||||
|
||||
uint8_t buffer_[4096];
|
||||
z_stream zlib_stream_;
|
||||
std::unique_ptr<OutputStreamInterface> output_stream_;
|
||||
Mode mode_;
|
||||
InitializationState initialized_; // protects zlib_stream_
|
||||
bool flush_needed_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(ZlibOutputStream);
|
||||
};
|
||||
|
||||
} // namespace crashpad
|
||||
|
||||
#endif // CRASHPAD_UTIL_STREAM_ZLIB_OUTPUT_STREAM_H_
|
186
util/stream/zlib_output_stream_test.cc
Normal file
186
util/stream/zlib_output_stream_test.cc
Normal file
@ -0,0 +1,186 @@
|
||||
// Copyright 2019 The Crashpad Authors. All rights reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "util/stream/zlib_output_stream.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include "base/rand_util.h"
|
||||
#include "base/stl_util.h"
|
||||
#include "base/strings/stringprintf.h"
|
||||
#include "gtest/gtest.h"
|
||||
#include "util/stream/test_output_stream.h"
|
||||
|
||||
namespace crashpad {
|
||||
namespace test {
|
||||
namespace {
|
||||
|
||||
constexpr size_t kShortDataLength = 10;
|
||||
constexpr size_t kLongDataLength = 4096 * 10;
|
||||
|
||||
class ZlibOutputStreamTest : public testing::Test {
|
||||
public:
|
||||
ZlibOutputStreamTest() : input_(), deterministic_input_() {
|
||||
auto test_output_stream = std::make_unique<TestOutputStream>();
|
||||
test_output_stream_ = test_output_stream.get();
|
||||
zlib_output_stream_ = std::make_unique<ZlibOutputStream>(
|
||||
ZlibOutputStream::Mode::kCompress,
|
||||
std::make_unique<ZlibOutputStream>(ZlibOutputStream::Mode::kDecompress,
|
||||
std::move(test_output_stream)));
|
||||
}
|
||||
|
||||
const uint8_t* BuildDeterministicInput(size_t size) {
|
||||
deterministic_input_ = std::make_unique<uint8_t[]>(size);
|
||||
uint8_t* deterministic_input_base = deterministic_input_.get();
|
||||
while (size-- > 0)
|
||||
deterministic_input_base[size] = static_cast<uint8_t>(size);
|
||||
return deterministic_input_base;
|
||||
}
|
||||
|
||||
const uint8_t* BuildRandomInput(size_t size) {
|
||||
input_ = std::make_unique<uint8_t[]>(size);
|
||||
base::RandBytes(&input_[0], size);
|
||||
return input_.get();
|
||||
}
|
||||
|
||||
const TestOutputStream& test_output_stream() const {
|
||||
return *test_output_stream_;
|
||||
}
|
||||
|
||||
ZlibOutputStream* zlib_output_stream() const {
|
||||
return zlib_output_stream_.get();
|
||||
}
|
||||
|
||||
private:
|
||||
std::unique_ptr<ZlibOutputStream> zlib_output_stream_;
|
||||
std::unique_ptr<uint8_t[]> input_;
|
||||
std::unique_ptr<uint8_t[]> deterministic_input_;
|
||||
TestOutputStream* test_output_stream_; // weak, owned by zlib_output_stream_
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(ZlibOutputStreamTest);
|
||||
};
|
||||
|
||||
TEST_F(ZlibOutputStreamTest, WriteDeterministicShortData) {
|
||||
const uint8_t* input = BuildDeterministicInput(kShortDataLength);
|
||||
EXPECT_TRUE(zlib_output_stream()->Write(input, kShortDataLength));
|
||||
EXPECT_TRUE(zlib_output_stream()->Flush());
|
||||
EXPECT_EQ(test_output_stream().last_written_data().size(), kShortDataLength);
|
||||
EXPECT_EQ(memcmp(test_output_stream().last_written_data().data(),
|
||||
input,
|
||||
kShortDataLength),
|
||||
0);
|
||||
}
|
||||
|
||||
TEST_F(ZlibOutputStreamTest, WriteDeterministicLongDataOneTime) {
|
||||
const uint8_t* input = BuildDeterministicInput(kLongDataLength);
|
||||
EXPECT_TRUE(zlib_output_stream()->Write(input, kLongDataLength));
|
||||
EXPECT_TRUE(zlib_output_stream()->Flush());
|
||||
EXPECT_EQ(test_output_stream().all_data().size(), kLongDataLength);
|
||||
EXPECT_EQ(
|
||||
memcmp(test_output_stream().all_data().data(), input, kLongDataLength),
|
||||
0);
|
||||
}
|
||||
|
||||
TEST_F(ZlibOutputStreamTest, WriteDeterministicLongDataMultipleTimes) {
|
||||
const uint8_t* input = BuildDeterministicInput(kLongDataLength);
|
||||
|
||||
static constexpr size_t kWriteLengths[] = {
|
||||
4, 96, 40, kLongDataLength - 4 - 96 - 40};
|
||||
|
||||
size_t offset = 0;
|
||||
for (size_t index = 0; index < base::size(kWriteLengths); ++index) {
|
||||
const size_t write_length = kWriteLengths[index];
|
||||
SCOPED_TRACE(base::StringPrintf(
|
||||
"offset %zu, write_length %zu", offset, write_length));
|
||||
EXPECT_TRUE(zlib_output_stream()->Write(input + offset, write_length));
|
||||
offset += write_length;
|
||||
}
|
||||
EXPECT_TRUE(zlib_output_stream()->Flush());
|
||||
EXPECT_EQ(test_output_stream().all_data().size(), kLongDataLength);
|
||||
EXPECT_EQ(
|
||||
memcmp(test_output_stream().all_data().data(), input, kLongDataLength),
|
||||
0);
|
||||
}
|
||||
|
||||
TEST_F(ZlibOutputStreamTest, WriteShortData) {
|
||||
const uint8_t* input = BuildRandomInput(kShortDataLength);
|
||||
EXPECT_TRUE(zlib_output_stream()->Write(input, kShortDataLength));
|
||||
EXPECT_TRUE(zlib_output_stream()->Flush());
|
||||
EXPECT_EQ(memcmp(test_output_stream().last_written_data().data(),
|
||||
input,
|
||||
kShortDataLength),
|
||||
0);
|
||||
EXPECT_EQ(test_output_stream().last_written_data().size(), kShortDataLength);
|
||||
}
|
||||
|
||||
TEST_F(ZlibOutputStreamTest, WriteLongDataOneTime) {
|
||||
const uint8_t* input = BuildRandomInput(kLongDataLength);
|
||||
EXPECT_TRUE(zlib_output_stream()->Write(input, kLongDataLength));
|
||||
EXPECT_TRUE(zlib_output_stream()->Flush());
|
||||
EXPECT_EQ(test_output_stream().all_data().size(), kLongDataLength);
|
||||
EXPECT_EQ(
|
||||
memcmp(test_output_stream().all_data().data(), input, kLongDataLength),
|
||||
0);
|
||||
}
|
||||
|
||||
TEST_F(ZlibOutputStreamTest, WriteLongDataMultipleTimes) {
|
||||
const uint8_t* input = BuildRandomInput(kLongDataLength);
|
||||
|
||||
// Call Write() a random number of times.
|
||||
size_t index = 0;
|
||||
while (index < kLongDataLength) {
|
||||
size_t write_length =
|
||||
std::min(static_cast<size_t>(base::RandInt(0, 4096 * 2)),
|
||||
kLongDataLength - index);
|
||||
SCOPED_TRACE(
|
||||
base::StringPrintf("index %zu, write_length %zu", index, write_length));
|
||||
EXPECT_TRUE(zlib_output_stream()->Write(input + index, write_length));
|
||||
index += write_length;
|
||||
}
|
||||
EXPECT_TRUE(zlib_output_stream()->Flush());
|
||||
EXPECT_EQ(test_output_stream().all_data().size(), kLongDataLength);
|
||||
EXPECT_EQ(
|
||||
memcmp(test_output_stream().all_data().data(), input, kLongDataLength),
|
||||
0);
|
||||
}
|
||||
|
||||
TEST_F(ZlibOutputStreamTest, NoWriteOrFlush) {
|
||||
EXPECT_EQ(test_output_stream().write_count(), 0u);
|
||||
EXPECT_EQ(test_output_stream().flush_count(), 0u);
|
||||
EXPECT_TRUE(test_output_stream().all_data().empty());
|
||||
}
|
||||
|
||||
TEST_F(ZlibOutputStreamTest, FlushWithoutWrite) {
|
||||
EXPECT_TRUE(zlib_output_stream()->Flush());
|
||||
EXPECT_EQ(test_output_stream().write_count(), 0u);
|
||||
EXPECT_EQ(test_output_stream().flush_count(), 1u);
|
||||
EXPECT_TRUE(test_output_stream().all_data().empty());
|
||||
}
|
||||
|
||||
TEST_F(ZlibOutputStreamTest, WriteEmptyData) {
|
||||
std::vector<uint8_t> empty_data;
|
||||
EXPECT_TRUE(zlib_output_stream()->Write(
|
||||
static_cast<const uint8_t*>(empty_data.data()), empty_data.size()));
|
||||
EXPECT_TRUE(zlib_output_stream()->Flush());
|
||||
EXPECT_TRUE(zlib_output_stream()->Flush());
|
||||
EXPECT_EQ(test_output_stream().write_count(), 0u);
|
||||
EXPECT_EQ(test_output_stream().flush_count(), 2u);
|
||||
EXPECT_TRUE(test_output_stream().all_data().empty());
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace test
|
||||
} // namespace crashpad
|
Loading…
x
Reference in New Issue
Block a user