| Index: mojo/services/files/public/cpp/tests/input_stream_file_unittest.cc
|
| diff --git a/mojo/services/files/public/cpp/tests/input_stream_file_unittest.cc b/mojo/services/files/public/cpp/tests/input_stream_file_unittest.cc
|
| deleted file mode 100644
|
| index 71fb5bf1b1c6a6fa58a9059ac781c4a4b247284f..0000000000000000000000000000000000000000
|
| --- a/mojo/services/files/public/cpp/tests/input_stream_file_unittest.cc
|
| +++ /dev/null
|
| @@ -1,539 +0,0 @@
|
| -// Copyright 2015 The Chromium 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 "files/public/cpp/input_stream_file.h"
|
| -
|
| -#include <string.h>
|
| -
|
| -#include <string>
|
| -#include <utility>
|
| -
|
| -#include "files/public/interfaces/files.mojom.h"
|
| -#include "files/public/interfaces/types.mojom.h"
|
| -#include "mojo/public/cpp/application/application_test_base.h"
|
| -#include "mojo/public/cpp/bindings/interface_request.h"
|
| -#include "mojo/public/cpp/environment/logging.h"
|
| -#include "mojo/public/cpp/system/macros.h"
|
| -#include "mojo/public/cpp/utility/run_loop.h"
|
| -
|
| -namespace files_impl {
|
| -namespace {
|
| -
|
| -using InputStreamFileTest = mojo::test::ApplicationTestBase;
|
| -
|
| -void QuitMessageLoop() {
|
| - mojo::RunLoop::current()->Quit();
|
| -}
|
| -
|
| -void RunMessageLoop() {
|
| - mojo::RunLoop::current()->Run();
|
| -}
|
| -
|
| -void RunMessageLoopUntilIdle() {
|
| - mojo::RunLoop::current()->RunUntilIdle();
|
| -}
|
| -
|
| -void PostTaskToMessageLoop(const mojo::Closure& task) {
|
| - mojo::RunLoop::current()->PostDelayedTask(task, 0);
|
| -}
|
| -
|
| -// Converts a string to a |mojo::Array<uint8_t>|.
|
| -mojo::Array<uint8_t> StringToArray(const std::string& s) {
|
| - auto rv = mojo::Array<uint8_t>::New(s.size());
|
| - if (s.size())
|
| - memcpy(&rv[0], &s[0], s.size());
|
| - return rv;
|
| -}
|
| -
|
| -// Converts a |mojo::Array<uint8_t>| to a string. If the array is null, returns
|
| -// the string "ARRAY_IS_NULL".
|
| -std::string ArrayToString(const mojo::Array<uint8_t>& a) {
|
| - if (a.is_null())
|
| - return std::string("ARRAY_IS_NULL");
|
| - return a.size() ? std::string(reinterpret_cast<const char*>(&a[0]), a.size())
|
| - : std::string();
|
| -}
|
| -
|
| -class TestClient : public InputStreamFile::Client {
|
| - public:
|
| - TestClient() { Reset(); }
|
| - ~TestClient() override {}
|
| -
|
| - // Note: This doesn't reset |callback_|.
|
| - void Reset() {
|
| - data_ = StringToArray("OOPS");
|
| - complete_synchronously_ = true;
|
| - got_request_data_ = false;
|
| - got_on_closed_ = false;
|
| - }
|
| -
|
| - // Completes a pending callback. Note: |RequestData()| may be called again
|
| - // "inside" this (i.e., "inside" the callback).
|
| - void RunRequestDataCallback(mojo::Array<uint8_t> data) {
|
| - MOJO_CHECK(!callback_.is_null());
|
| - RequestDataCallback callback;
|
| - std::swap(callback, callback_);
|
| - callback.Run(mojo::files::Error::OK, data.Pass());
|
| - }
|
| -
|
| - void set_data(mojo::Array<uint8_t> data) {
|
| - MOJO_CHECK(!data.is_null());
|
| - data_ = data.Pass();
|
| - }
|
| - void set_complete_synchronously(bool complete_synchronously) {
|
| - complete_synchronously_ = complete_synchronously;
|
| - }
|
| -
|
| - bool got_request_data() const { return got_request_data_; }
|
| - bool got_on_closed() const { return got_on_closed_; }
|
| -
|
| - private:
|
| - // |InputStreamFile::Client|:
|
| - bool RequestData(size_t max_num_bytes,
|
| - mojo::files::Error* error,
|
| - mojo::Array<uint8_t>* data,
|
| - const RequestDataCallback& callback) override {
|
| - MOJO_CHECK(max_num_bytes);
|
| - MOJO_CHECK(error);
|
| - MOJO_CHECK(data);
|
| - MOJO_CHECK(!callback.is_null());
|
| -
|
| - // This shouldn't be called while a callback is pending.
|
| - MOJO_CHECK(callback_.is_null());
|
| -
|
| - got_request_data_ = true;
|
| - QuitMessageLoop();
|
| -
|
| - if (!complete_synchronously_) {
|
| - callback_ = callback;
|
| - return false;
|
| - }
|
| -
|
| - *error = mojo::files::Error::OK;
|
| - *data = data_.Clone();
|
| - return true;
|
| - }
|
| - void OnClosed() override {
|
| - got_on_closed_ = true;
|
| - QuitMessageLoop();
|
| - }
|
| -
|
| - mojo::Array<uint8_t> data_;
|
| - bool complete_synchronously_;
|
| -
|
| - bool got_request_data_;
|
| - bool got_on_closed_;
|
| -
|
| - RequestDataCallback callback_;
|
| -
|
| - MOJO_DISALLOW_COPY_AND_ASSIGN(TestClient);
|
| -};
|
| -
|
| -void TestReadSync(mojo::files::File* file,
|
| - TestClient* client,
|
| - const std::string& s) {
|
| - bool read_cb_called = false;
|
| - mojo::files::Error error = mojo::files::Error::INTERNAL;
|
| - mojo::Array<uint8_t> data;
|
| - file->Read(100u, 0, mojo::files::Whence::FROM_CURRENT,
|
| - [&read_cb_called, &error, &data](mojo::files::Error e,
|
| - mojo::Array<uint8_t> d) {
|
| - read_cb_called = true;
|
| - error = e;
|
| - data = d.Pass();
|
| - QuitMessageLoop();
|
| - });
|
| - if (client) {
|
| - // If there's a client, since we're running everything on one thread, the
|
| - // impl (which will call the client, which will quit the message loop) will
|
| - // get called before the callback.
|
| - client->Reset();
|
| - client->set_data(StringToArray(s));
|
| - RunMessageLoop();
|
| - EXPECT_TRUE(client->got_request_data());
|
| - EXPECT_FALSE(client->got_on_closed());
|
| - EXPECT_FALSE(read_cb_called);
|
| - // Spin the message loop again to get the callback.
|
| - client->Reset();
|
| - RunMessageLoop();
|
| - EXPECT_FALSE(client->got_request_data());
|
| - EXPECT_FALSE(client->got_on_closed());
|
| - EXPECT_TRUE(read_cb_called);
|
| - EXPECT_EQ(mojo::files::Error::OK, error);
|
| - EXPECT_EQ(s, ArrayToString(data));
|
| - } else {
|
| - // Otherwise, only the read callback will be called and quit the message
|
| - // loop.
|
| - RunMessageLoop();
|
| - EXPECT_TRUE(read_cb_called);
|
| - EXPECT_EQ(mojo::files::Error::UNAVAILABLE, error);
|
| - EXPECT_TRUE(data.is_null());
|
| - }
|
| -}
|
| -
|
| -void TestReadAsync(mojo::files::File* file,
|
| - TestClient* client,
|
| - const std::string& s) {
|
| - MOJO_CHECK(client);
|
| -
|
| - bool read_cb_called = false;
|
| - mojo::files::Error error = mojo::files::Error::INTERNAL;
|
| - mojo::Array<uint8_t> data;
|
| - file->Read(100u, 0, mojo::files::Whence::FROM_CURRENT,
|
| - [&read_cb_called, &error, &data](mojo::files::Error e,
|
| - mojo::Array<uint8_t> d) {
|
| - read_cb_called = true;
|
| - error = e;
|
| - data = d.Pass();
|
| - QuitMessageLoop();
|
| - });
|
| - client->Reset();
|
| - client->set_complete_synchronously(false);
|
| - RunMessageLoop();
|
| - EXPECT_TRUE(client->got_request_data());
|
| - EXPECT_FALSE(client->got_on_closed());
|
| - EXPECT_FALSE(read_cb_called);
|
| - // The read callback won't get called until we tell the client to run its
|
| - // callback.
|
| - client->Reset();
|
| - client->RunRequestDataCallback(StringToArray(s));
|
| - EXPECT_FALSE(client->got_request_data());
|
| - EXPECT_FALSE(client->got_on_closed());
|
| - EXPECT_FALSE(read_cb_called);
|
| - // Spin the message loop again to get the read callback.
|
| - client->Reset();
|
| - RunMessageLoop();
|
| - EXPECT_FALSE(client->got_request_data());
|
| - EXPECT_FALSE(client->got_on_closed());
|
| - EXPECT_TRUE(read_cb_called);
|
| - EXPECT_EQ(mojo::files::Error::OK, error);
|
| - EXPECT_EQ(s, ArrayToString(data));
|
| -}
|
| -
|
| -void TestClose(mojo::files::File* file, TestClient* client) {
|
| - bool close_cb_called = false;
|
| - mojo::files::Error error = mojo::files::Error::INTERNAL;
|
| - file->Close([&close_cb_called, &error](mojo::files::Error e) {
|
| - close_cb_called = true;
|
| - error = e;
|
| - QuitMessageLoop();
|
| - });
|
| - if (client) {
|
| - // (This is analogous to |TestReadSync()|.)
|
| - client->Reset();
|
| - RunMessageLoop();
|
| - EXPECT_FALSE(client->got_request_data());
|
| - EXPECT_TRUE(client->got_on_closed());
|
| - EXPECT_FALSE(close_cb_called);
|
| - client->Reset();
|
| - RunMessageLoop();
|
| - EXPECT_FALSE(client->got_request_data());
|
| - EXPECT_FALSE(client->got_on_closed());
|
| - } else {
|
| - RunMessageLoop();
|
| - }
|
| - EXPECT_TRUE(close_cb_called);
|
| - EXPECT_EQ(mojo::files::Error::OK, error);
|
| -}
|
| -
|
| -TEST_F(InputStreamFileTest, BasicSync) {
|
| - mojo::files::FilePtr file;
|
| - TestClient client;
|
| - std::unique_ptr<InputStreamFile> file_impl =
|
| - InputStreamFile::Create(&client, GetProxy(&file));
|
| -
|
| - TestReadSync(file.get(), &client, "hello");
|
| - TestReadSync(file.get(), &client, "world");
|
| - TestClose(file.get(), &client);
|
| -}
|
| -
|
| -TEST_F(InputStreamFileTest, BasicAsync) {
|
| - mojo::files::FilePtr file;
|
| - TestClient client;
|
| - std::unique_ptr<InputStreamFile> file_impl =
|
| - InputStreamFile::Create(&client, GetProxy(&file));
|
| -
|
| - TestReadAsync(file.get(), &client, "hello");
|
| - TestReadAsync(file.get(), &client, "world");
|
| - TestClose(file.get(), &client);
|
| -}
|
| -
|
| -TEST_F(InputStreamFileTest, SetClient) {
|
| - mojo::files::FilePtr file;
|
| - TestClient client1;
|
| - std::unique_ptr<InputStreamFile> file_impl =
|
| - InputStreamFile::Create(&client1, GetProxy(&file));
|
| -
|
| - TestReadSync(file.get(), &client1, "hello");
|
| -
|
| - TestClient client2;
|
| - file_impl->set_client(&client2);
|
| - TestReadSync(file.get(), &client2, "world");
|
| -
|
| - file_impl->set_client(&client1);
|
| - TestReadAsync(file.get(), &client1, "!");
|
| - TestClose(file.get(), &client1);
|
| -}
|
| -
|
| -TEST_F(InputStreamFileTest, NullClient) {
|
| - mojo::files::FilePtr file;
|
| - std::unique_ptr<InputStreamFile> file_impl =
|
| - InputStreamFile::Create(nullptr, GetProxy(&file));
|
| -
|
| - TestReadSync(file.get(), nullptr, "hello");
|
| - TestClose(file.get(), nullptr);
|
| -}
|
| -
|
| -TEST_F(InputStreamFileTest, SetNullClient) {
|
| - mojo::files::FilePtr file;
|
| - TestClient client;
|
| - std::unique_ptr<InputStreamFile> file_impl =
|
| - InputStreamFile::Create(&client, GetProxy(&file));
|
| -
|
| - TestReadSync(file.get(), &client, "hello");
|
| -
|
| - file_impl->set_client(nullptr);
|
| - client.Reset();
|
| - TestReadSync(file.get(), nullptr, "hello");
|
| - TestClose(file.get(), nullptr);
|
| - EXPECT_FALSE(client.got_request_data());
|
| - EXPECT_FALSE(client.got_on_closed());
|
| -}
|
| -
|
| -TEST_F(InputStreamFileTest, ImplOnlyClosesMessagePipeOnDestruction) {
|
| - mojo::files::FilePtr file;
|
| - std::unique_ptr<InputStreamFile> file_impl =
|
| - InputStreamFile::Create(nullptr, GetProxy(&file));
|
| - bool got_connection_error = false;
|
| - file.set_connection_error_handler([&got_connection_error]() {
|
| - got_connection_error = true;
|
| - QuitMessageLoop();
|
| - });
|
| -
|
| - TestClose(file.get(), nullptr);
|
| - // The impl should only close its end when it's destroyed (even if |Close()|
|
| - // has been called).
|
| - RunMessageLoopUntilIdle();
|
| - EXPECT_FALSE(got_connection_error);
|
| - file_impl.reset();
|
| - RunMessageLoop();
|
| - EXPECT_TRUE(got_connection_error);
|
| -}
|
| -
|
| -TEST_F(InputStreamFileTest, ClosingMessagePipeCausesOnClosed) {
|
| - mojo::files::FilePtr file;
|
| - TestClient client;
|
| - std::unique_ptr<InputStreamFile> file_impl =
|
| - InputStreamFile::Create(&client, GetProxy(&file));
|
| -
|
| - file.reset();
|
| - RunMessageLoop();
|
| - EXPECT_FALSE(client.got_request_data());
|
| - EXPECT_TRUE(client.got_on_closed());
|
| -}
|
| -
|
| -// Clients may own the impl (and this is a typical pattern). This client will
|
| -// own/destroy its impl on any |Client| call (and we'll test that this doesn't
|
| -// result in any additional calls to the client).
|
| -class TestClientDestroysImplClient : public InputStreamFile::Client {
|
| - public:
|
| - explicit TestClientDestroysImplClient(
|
| - mojo::InterfaceRequest<mojo::files::File> request)
|
| - : file_impl_(InputStreamFile::Create(this, request.Pass())) {}
|
| - ~TestClientDestroysImplClient() override {}
|
| -
|
| - private:
|
| - // InputStreamFile::Client|:
|
| - bool RequestData(size_t /*max_num_bytes*/,
|
| - mojo::files::Error* /*error*/,
|
| - mojo::Array<uint8_t>* /*data*/,
|
| - const RequestDataCallback& /*callback*/) override {
|
| - // We reset the impl on any call, and afterwards it shouldn't call us.
|
| - EXPECT_TRUE(file_impl_);
|
| - file_impl_.reset();
|
| - return true;
|
| - }
|
| - void OnClosed() override {
|
| - // We reset the impl on any call, and afterwards it shouldn't call us.
|
| - EXPECT_TRUE(file_impl_);
|
| - file_impl_.reset();
|
| - }
|
| -
|
| - std::unique_ptr<InputStreamFile> file_impl_;
|
| -
|
| - MOJO_DISALLOW_COPY_AND_ASSIGN(TestClientDestroysImplClient);
|
| -};
|
| -
|
| -TEST_F(InputStreamFileTest, ClientDestroysImpl) {
|
| - // Test destruction due to reading.
|
| - {
|
| - mojo::files::FilePtr file;
|
| - TestClientDestroysImplClient client(GetProxy(&file));
|
| - bool got_connection_error = false;
|
| - file.set_connection_error_handler([&got_connection_error]() {
|
| - got_connection_error = true;
|
| - QuitMessageLoop();
|
| - });
|
| - // If the impl is destroyed while trying to answer a read, it doesn't
|
| - // respond.
|
| - // TODO(vtl): I'm not sure if this is the best behavior. Maybe it should
|
| - // respond with an error?
|
| - file->Read(100u, 0, mojo::files::Whence::FROM_CURRENT,
|
| - [](mojo::files::Error, mojo::Array<uint8_t>) {
|
| - MOJO_CHECK(false) << "Not reached";
|
| - });
|
| - RunMessageLoop();
|
| - EXPECT_TRUE(got_connection_error);
|
| - }
|
| -
|
| - // Test destruction due to closing.
|
| - {
|
| - mojo::files::FilePtr file;
|
| - TestClientDestroysImplClient client(GetProxy(&file));
|
| - bool got_connection_error = false;
|
| - file.set_connection_error_handler([&got_connection_error]() {
|
| - got_connection_error = true;
|
| - QuitMessageLoop();
|
| - });
|
| - TestClose(file.get(), nullptr);
|
| - if (!got_connection_error)
|
| - RunMessageLoop();
|
| - EXPECT_TRUE(got_connection_error);
|
| - }
|
| -}
|
| -
|
| -// This responds synchronously to any (non-zero-byte) read with a single byte,
|
| -// starting with 0 and incrementing each time.
|
| -class TestClientFifoSync : public InputStreamFile::Client {
|
| - public:
|
| - explicit TestClientFifoSync(mojo::InterfaceRequest<mojo::files::File> request)
|
| - : file_impl_(InputStreamFile::Create(this, request.Pass())),
|
| - next_byte_(0u) {}
|
| - ~TestClientFifoSync() override {}
|
| -
|
| - private:
|
| - // InputStreamFile::Client|:
|
| - bool RequestData(size_t max_num_bytes,
|
| - mojo::files::Error* error,
|
| - mojo::Array<uint8_t>* data,
|
| - const RequestDataCallback& callback) override {
|
| - *error = mojo::files::Error::OK;
|
| - data->resize(1);
|
| - (*data)[0] = next_byte_++;
|
| - return true;
|
| - }
|
| - void OnClosed() override {}
|
| -
|
| - std::unique_ptr<InputStreamFile> file_impl_;
|
| - uint8_t next_byte_;
|
| -
|
| - MOJO_DISALLOW_COPY_AND_ASSIGN(TestClientFifoSync);
|
| -};
|
| -
|
| -// Like |TestClientFifoSync|, but asynchronous.
|
| -class TestClientFifoAsync : public InputStreamFile::Client {
|
| - public:
|
| - explicit TestClientFifoAsync(
|
| - mojo::InterfaceRequest<mojo::files::File> request)
|
| - : file_impl_(InputStreamFile::Create(this, request.Pass())),
|
| - next_byte_(0u) {}
|
| - ~TestClientFifoAsync() override {}
|
| -
|
| - private:
|
| - // InputStreamFile::Client|:
|
| - bool RequestData(size_t max_num_bytes,
|
| - mojo::files::Error* error,
|
| - mojo::Array<uint8_t>* data,
|
| - const RequestDataCallback& callback) override {
|
| - PostTaskToMessageLoop([this, callback]() {
|
| - mojo::Array<uint8_t> data;
|
| - data.push_back(next_byte_++);
|
| - callback.Run(mojo::files::Error::OK, data.Pass());
|
| - });
|
| - return false;
|
| - }
|
| - void OnClosed() override {}
|
| -
|
| - std::unique_ptr<InputStreamFile> file_impl_;
|
| - uint8_t next_byte_;
|
| -
|
| - MOJO_DISALLOW_COPY_AND_ASSIGN(TestClientFifoAsync);
|
| -};
|
| -
|
| -void TestFifo(mojo::files::File* file) {
|
| - int expect_callback = 0;
|
| - uint8_t expect_byte = 0;
|
| -
|
| - // Test a couple of zero-byte reads.
|
| - file->Read(0u, 0, mojo::files::Whence::FROM_CURRENT,
|
| - [&expect_callback](mojo::files::Error e, mojo::Array<uint8_t> a) {
|
| - EXPECT_EQ(0, expect_callback++);
|
| - EXPECT_EQ(mojo::files::Error::OK, e);
|
| - EXPECT_EQ(0u, a.size());
|
| - });
|
| - file->Read(0u, 0, mojo::files::Whence::FROM_CURRENT,
|
| - [&expect_callback](mojo::files::Error e, mojo::Array<uint8_t> a) {
|
| - EXPECT_EQ(1, expect_callback++);
|
| - EXPECT_EQ(mojo::files::Error::OK, e);
|
| - EXPECT_EQ(0u, a.size());
|
| - });
|
| -
|
| - // Test a couple of non-zero-byte reads.
|
| - file->Read(100u, 0, mojo::files::Whence::FROM_CURRENT,
|
| - [&expect_callback, &expect_byte](mojo::files::Error e,
|
| - mojo::Array<uint8_t> a) {
|
| - EXPECT_EQ(2, expect_callback++);
|
| - EXPECT_EQ(mojo::files::Error::OK, e);
|
| - EXPECT_EQ(1u, a.size());
|
| - EXPECT_EQ(expect_byte++, a[0]);
|
| - });
|
| - file->Read(100u, 0, mojo::files::Whence::FROM_CURRENT,
|
| - [&expect_callback, &expect_byte](mojo::files::Error e,
|
| - mojo::Array<uint8_t> a) {
|
| - EXPECT_EQ(3, expect_callback++);
|
| - EXPECT_EQ(mojo::files::Error::OK, e);
|
| - EXPECT_EQ(1u, a.size());
|
| - EXPECT_EQ(expect_byte++, a[0]);
|
| - });
|
| - // Throw in a zero-byte read.
|
| - file->Read(0u, 0, mojo::files::Whence::FROM_CURRENT,
|
| - [&expect_callback](mojo::files::Error e, mojo::Array<uint8_t> a) {
|
| - EXPECT_EQ(4, expect_callback++);
|
| - EXPECT_EQ(mojo::files::Error::OK, e);
|
| - EXPECT_EQ(0u, a.size());
|
| - });
|
| - // And a final non-zero-byte read (we'll quit the message loop).
|
| - file->Read(100u, 0, mojo::files::Whence::FROM_CURRENT,
|
| - [&expect_callback, &expect_byte](mojo::files::Error e,
|
| - mojo::Array<uint8_t> a) {
|
| - EXPECT_EQ(5, expect_callback++);
|
| - EXPECT_EQ(mojo::files::Error::OK, e);
|
| - EXPECT_EQ(1u, a.size());
|
| - EXPECT_EQ(expect_byte++, a[0]);
|
| - QuitMessageLoop();
|
| - });
|
| - RunMessageLoop();
|
| -
|
| - // Check that all the callbacks ran.
|
| - EXPECT_EQ(6, expect_callback);
|
| - EXPECT_EQ(3u, expect_byte);
|
| -}
|
| -
|
| -// Tests that if multiple reads are sent, they are completed in FIFO order. This
|
| -// tests the synchronous completion path.
|
| -TEST_F(InputStreamFileTest, FifoSync) {
|
| - mojo::files::FilePtr file;
|
| - TestClientFifoSync client(GetProxy(&file));
|
| - TestFifo(file.get());
|
| -}
|
| -
|
| -// Like |InputStreamFileTest.FifoSync|, but asynchronous.
|
| -TEST_F(InputStreamFileTest, FifoAsync) {
|
| - mojo::files::FilePtr file;
|
| - TestClientFifoAsync client(GetProxy(&file));
|
| - TestFifo(file.get());
|
| -}
|
| -
|
| -} // namespace
|
| -} // namespace files_impl
|
|
|