diff options
Diffstat (limited to 'brillo/streams/stream_utils_unittest.cc')
-rw-r--r-- | brillo/streams/stream_utils_unittest.cc | 300 |
1 files changed, 300 insertions, 0 deletions
diff --git a/brillo/streams/stream_utils_unittest.cc b/brillo/streams/stream_utils_unittest.cc new file mode 100644 index 0000000..8145027 --- /dev/null +++ b/brillo/streams/stream_utils_unittest.cc @@ -0,0 +1,300 @@ +// Copyright 2015 The Chromium OS Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include <brillo/streams/stream_utils.h> + +#include <limits> + +#include <base/bind.h> +#include <brillo/message_loops/fake_message_loop.h> +#include <brillo/message_loops/message_loop.h> +#include <brillo/streams/mock_stream.h> +#include <brillo/streams/stream_errors.h> +#include <gmock/gmock.h> +#include <gtest/gtest.h> + +using testing::DoAll; +using testing::InSequence; +using testing::Return; +using testing::StrictMock; +using testing::_; + +ACTION_TEMPLATE(InvokeAsyncCallback, + HAS_1_TEMPLATE_PARAMS(int, k), + AND_1_VALUE_PARAMS(size)) { + brillo::MessageLoop::current()->PostTask( + FROM_HERE, base::Bind(std::get<k>(args), size)); + return true; +} + +ACTION_TEMPLATE(InvokeAsyncCallback, + HAS_1_TEMPLATE_PARAMS(int, k), + AND_0_VALUE_PARAMS()) { + brillo::MessageLoop::current()->PostTask(FROM_HERE, std::get<k>(args)); + return true; +} + +ACTION_TEMPLATE(InvokeAsyncErrorCallback, + HAS_1_TEMPLATE_PARAMS(int, k), + AND_1_VALUE_PARAMS(code)) { + brillo::ErrorPtr error; + brillo::Error::AddTo(&error, FROM_HERE, "test", code, "message"); + brillo::MessageLoop::current()->PostTask( + FROM_HERE, base::Bind(std::get<k>(args), base::Owned(error.release()))); + return true; +} + +namespace brillo { + +TEST(StreamUtils, ErrorStreamClosed) { + ErrorPtr error; + EXPECT_FALSE(stream_utils::ErrorStreamClosed(FROM_HERE, &error)); + EXPECT_EQ(errors::stream::kDomain, error->GetDomain()); + EXPECT_EQ(errors::stream::kStreamClosed, error->GetCode()); + EXPECT_EQ("Stream is closed", error->GetMessage()); +} + +TEST(StreamUtils, ErrorOperationNotSupported) { + ErrorPtr error; + EXPECT_FALSE(stream_utils::ErrorOperationNotSupported(FROM_HERE, &error)); + EXPECT_EQ(errors::stream::kDomain, error->GetDomain()); + EXPECT_EQ(errors::stream::kOperationNotSupported, error->GetCode()); + EXPECT_EQ("Stream operation not supported", error->GetMessage()); +} + +TEST(StreamUtils, ErrorReadPastEndOfStream) { + ErrorPtr error; + EXPECT_FALSE(stream_utils::ErrorReadPastEndOfStream(FROM_HERE, &error)); + EXPECT_EQ(errors::stream::kDomain, error->GetDomain()); + EXPECT_EQ(errors::stream::kPartialData, error->GetCode()); + EXPECT_EQ("Reading past the end of stream", error->GetMessage()); +} + +TEST(StreamUtils, CheckInt64Overflow) { + const int64_t max_int64 = std::numeric_limits<int64_t>::max(); + const uint64_t max_uint64 = std::numeric_limits<uint64_t>::max(); + EXPECT_TRUE(stream_utils::CheckInt64Overflow(FROM_HERE, 0, 0, nullptr)); + EXPECT_TRUE(stream_utils::CheckInt64Overflow( + FROM_HERE, 0, max_int64, nullptr)); + EXPECT_TRUE(stream_utils::CheckInt64Overflow( + FROM_HERE, max_int64, 0, nullptr)); + EXPECT_TRUE(stream_utils::CheckInt64Overflow(FROM_HERE, 100, -90, nullptr)); + EXPECT_TRUE(stream_utils::CheckInt64Overflow( + FROM_HERE, 1000, -1000, nullptr)); + + ErrorPtr error; + EXPECT_FALSE(stream_utils::CheckInt64Overflow(FROM_HERE, 100, -101, &error)); + EXPECT_EQ(errors::stream::kDomain, error->GetDomain()); + EXPECT_EQ(errors::stream::kInvalidParameter, error->GetCode()); + EXPECT_EQ("The stream offset value is out of range", error->GetMessage()); + + EXPECT_FALSE(stream_utils::CheckInt64Overflow( + FROM_HERE, max_int64, 1, nullptr)); + EXPECT_FALSE(stream_utils::CheckInt64Overflow( + FROM_HERE, max_uint64, 0, nullptr)); + EXPECT_FALSE(stream_utils::CheckInt64Overflow( + FROM_HERE, max_uint64, max_int64, nullptr)); +} + +TEST(StreamUtils, CalculateStreamPosition) { + using Whence = Stream::Whence; + const uint64_t current_pos = 1234; + const uint64_t end_pos = 2000; + uint64_t pos = 0; + + EXPECT_TRUE(stream_utils::CalculateStreamPosition( + FROM_HERE, 0, Whence::FROM_BEGIN, current_pos, end_pos, &pos, nullptr)); + EXPECT_EQ(0u, pos); + + EXPECT_TRUE(stream_utils::CalculateStreamPosition( + FROM_HERE, 0, Whence::FROM_CURRENT, current_pos, end_pos, &pos, nullptr)); + EXPECT_EQ(current_pos, pos); + + EXPECT_TRUE(stream_utils::CalculateStreamPosition( + FROM_HERE, 0, Whence::FROM_END, current_pos, end_pos, &pos, nullptr)); + EXPECT_EQ(end_pos, pos); + + EXPECT_TRUE(stream_utils::CalculateStreamPosition( + FROM_HERE, 10, Whence::FROM_BEGIN, current_pos, end_pos, &pos, nullptr)); + EXPECT_EQ(10u, pos); + + EXPECT_TRUE(stream_utils::CalculateStreamPosition( + FROM_HERE, 10, Whence::FROM_CURRENT, current_pos, end_pos, &pos, + nullptr)); + EXPECT_EQ(current_pos + 10, pos); + + EXPECT_TRUE(stream_utils::CalculateStreamPosition( + FROM_HERE, 10, Whence::FROM_END, current_pos, end_pos, &pos, nullptr)); + EXPECT_EQ(end_pos + 10, pos); + + EXPECT_TRUE(stream_utils::CalculateStreamPosition( + FROM_HERE, -10, Whence::FROM_CURRENT, current_pos, end_pos, &pos, + nullptr)); + EXPECT_EQ(current_pos - 10, pos); + + EXPECT_TRUE(stream_utils::CalculateStreamPosition( + FROM_HERE, -10, Whence::FROM_END, current_pos, end_pos, &pos, nullptr)); + EXPECT_EQ(end_pos - 10, pos); + + ErrorPtr error; + EXPECT_FALSE(stream_utils::CalculateStreamPosition( + FROM_HERE, -1, Whence::FROM_BEGIN, current_pos, end_pos, &pos, &error)); + EXPECT_EQ(errors::stream::kInvalidParameter, error->GetCode()); + EXPECT_EQ("The stream offset value is out of range", error->GetMessage()); + + EXPECT_FALSE(stream_utils::CalculateStreamPosition( + FROM_HERE, -1001, Whence::FROM_CURRENT, 1000, end_pos, &pos, nullptr)); + + const uint64_t max_int64 = std::numeric_limits<int64_t>::max(); + EXPECT_FALSE(stream_utils::CalculateStreamPosition( + FROM_HERE, 1, Whence::FROM_CURRENT, max_int64, end_pos, &pos, nullptr)); +} + +class CopyStreamDataTest : public testing::Test { + public: + void SetUp() override { + fake_loop_.SetAsCurrent(); + in_stream_.reset(new StrictMock<MockStream>{}); + out_stream_.reset(new StrictMock<MockStream>{}); + } + + FakeMessageLoop fake_loop_{nullptr}; + std::unique_ptr<StrictMock<MockStream>> in_stream_; + std::unique_ptr<StrictMock<MockStream>> out_stream_; + bool succeeded_{false}; + bool failed_{false}; + + void OnSuccess(uint64_t expected, + StreamPtr in_stream, + StreamPtr out_stream, + uint64_t copied) { + EXPECT_EQ(expected, copied); + succeeded_ = true; + } + + void OnError(const std::string& expected_error, + StreamPtr in_stream, + StreamPtr out_stream, + const Error* error) { + EXPECT_EQ(expected_error, error->GetCode()); + failed_ = true; + } + + void ExpectSuccess() { + EXPECT_TRUE(succeeded_); + EXPECT_FALSE(failed_); + } + + void ExpectFailure() { + EXPECT_FALSE(succeeded_); + EXPECT_TRUE(failed_); + } +}; + +TEST_F(CopyStreamDataTest, CopyAllAtOnce) { + { + InSequence seq; + EXPECT_CALL(*in_stream_, ReadAsync(_, 100, _, _, _)) + .WillOnce(InvokeAsyncCallback<2>(100)); + EXPECT_CALL(*out_stream_, WriteAllAsync(_, 100, _, _, _)) + .WillOnce(InvokeAsyncCallback<2>()); + } + stream_utils::CopyData( + std::move(in_stream_), std::move(out_stream_), 100, 4096, + base::Bind(&CopyStreamDataTest::OnSuccess, base::Unretained(this), 100), + base::Bind(&CopyStreamDataTest::OnError, base::Unretained(this), "")); + fake_loop_.Run(); + ExpectSuccess(); +} + +TEST_F(CopyStreamDataTest, CopyInBlocks) { + { + InSequence seq; + EXPECT_CALL(*in_stream_, ReadAsync(_, 100, _, _, _)) + .WillOnce(InvokeAsyncCallback<2>(60)); + EXPECT_CALL(*out_stream_, WriteAllAsync(_, 60, _, _, _)) + .WillOnce(InvokeAsyncCallback<2>()); + EXPECT_CALL(*in_stream_, ReadAsync(_, 40, _, _, _)) + .WillOnce(InvokeAsyncCallback<2>(40)); + EXPECT_CALL(*out_stream_, WriteAllAsync(_, 40, _, _, _)) + .WillOnce(InvokeAsyncCallback<2>()); + } + stream_utils::CopyData( + std::move(in_stream_), std::move(out_stream_), 100, 4096, + base::Bind(&CopyStreamDataTest::OnSuccess, base::Unretained(this), 100), + base::Bind(&CopyStreamDataTest::OnError, base::Unretained(this), "")); + fake_loop_.Run(); + ExpectSuccess(); +} + +TEST_F(CopyStreamDataTest, CopyTillEndOfStream) { + { + InSequence seq; + EXPECT_CALL(*in_stream_, ReadAsync(_, 100, _, _, _)) + .WillOnce(InvokeAsyncCallback<2>(60)); + EXPECT_CALL(*out_stream_, WriteAllAsync(_, 60, _, _, _)) + .WillOnce(InvokeAsyncCallback<2>()); + EXPECT_CALL(*in_stream_, ReadAsync(_, 40, _, _, _)) + .WillOnce(InvokeAsyncCallback<2>(0)); + } + stream_utils::CopyData( + std::move(in_stream_), std::move(out_stream_), 100, 4096, + base::Bind(&CopyStreamDataTest::OnSuccess, base::Unretained(this), 60), + base::Bind(&CopyStreamDataTest::OnError, base::Unretained(this), "")); + fake_loop_.Run(); + ExpectSuccess(); +} + +TEST_F(CopyStreamDataTest, CopyInSmallBlocks) { + { + InSequence seq; + EXPECT_CALL(*in_stream_, ReadAsync(_, 60, _, _, _)) + .WillOnce(InvokeAsyncCallback<2>(60)); + EXPECT_CALL(*out_stream_, WriteAllAsync(_, 60, _, _, _)) + .WillOnce(InvokeAsyncCallback<2>()); + EXPECT_CALL(*in_stream_, ReadAsync(_, 40, _, _, _)) + .WillOnce(InvokeAsyncCallback<2>(40)); + EXPECT_CALL(*out_stream_, WriteAllAsync(_, 40, _, _, _)) + .WillOnce(InvokeAsyncCallback<2>()); + } + stream_utils::CopyData( + std::move(in_stream_), std::move(out_stream_), 100, 60, + base::Bind(&CopyStreamDataTest::OnSuccess, base::Unretained(this), 100), + base::Bind(&CopyStreamDataTest::OnError, base::Unretained(this), "")); + fake_loop_.Run(); + ExpectSuccess(); +} + +TEST_F(CopyStreamDataTest, ErrorRead) { + { + InSequence seq; + EXPECT_CALL(*in_stream_, ReadAsync(_, 60, _, _, _)) + .WillOnce(InvokeAsyncErrorCallback<3>("read")); + } + stream_utils::CopyData( + std::move(in_stream_), std::move(out_stream_), 100, 60, + base::Bind(&CopyStreamDataTest::OnSuccess, base::Unretained(this), 0), + base::Bind(&CopyStreamDataTest::OnError, base::Unretained(this), "read")); + fake_loop_.Run(); + ExpectFailure(); +} + +TEST_F(CopyStreamDataTest, ErrorWrite) { + { + InSequence seq; + EXPECT_CALL(*in_stream_, ReadAsync(_, 60, _, _, _)) + .WillOnce(InvokeAsyncCallback<2>(60)); + EXPECT_CALL(*out_stream_, WriteAllAsync(_, 60, _, _, _)) + .WillOnce(InvokeAsyncErrorCallback<3>("write")); + } + stream_utils::CopyData( + std::move(in_stream_), std::move(out_stream_), 100, 60, + base::Bind(&CopyStreamDataTest::OnSuccess, base::Unretained(this), 0), + base::Bind(&CopyStreamDataTest::OnError, base::Unretained(this), + "write")); + fake_loop_.Run(); + ExpectFailure(); +} + +} // namespace brillo |