diff options
author | Trent Apted <tapted@chromium.org> | 2014-10-03 11:51:20 +1000 |
---|---|---|
committer | Trent Apted <tapted@chromium.org> | 2014-10-03 01:52:13 +0000 |
commit | 5a14236a9c2a7b9191c31ddccc5f1d7a4f6278a9 (patch) | |
tree | f4107f31a06d889dc0dcee9cfd2f66d6d2f19575 /mojo/common | |
parent | 11cbd199704f82210205e8e956af686e179e2689 (diff) | |
download | chromium_src-5a14236a9c2a7b9191c31ddccc5f1d7a4f6278a9.zip chromium_src-5a14236a9c2a7b9191c31ddccc5f1d7a4f6278a9.tar.gz chromium_src-5a14236a9c2a7b9191c31ddccc5f1d7a4f6278a9.tar.bz2 |
Revert "Move mojo edk into mojo/edk"
This reverts commit ee7ff197a98da4636f33bd713de784948b487bd4.
Causing widespread checkdeps failures.
ERROR in src\content\browser\webui\web_ui_mojo_browsertest.cc
Illegal include: "mojo/edk/test/test_utils.h" Because of no rule applying.
TBR=jamesr@chromium.org
Review URL: https://codereview.chromium.org/623883002
Cr-Commit-Position: refs/heads/master@{#297966}
Diffstat (limited to 'mojo/common')
-rw-r--r-- | mojo/common/BUILD.gn | 3 | ||||
-rw-r--r-- | mojo/common/test/BUILD.gn | 23 | ||||
-rw-r--r-- | mojo/common/test/DEPS | 2 | ||||
-rw-r--r-- | mojo/common/test/multiprocess_test_helper.cc | 86 | ||||
-rw-r--r-- | mojo/common/test/multiprocess_test_helper.h | 91 | ||||
-rw-r--r-- | mojo/common/test/multiprocess_test_helper_unittest.cc | 157 | ||||
-rw-r--r-- | mojo/common/test/run_all_perftests.cc | 2 | ||||
-rw-r--r-- | mojo/common/test/run_all_unittests.cc | 2 | ||||
-rw-r--r-- | mojo/common/test/test_utils.h | 57 | ||||
-rw-r--r-- | mojo/common/test/test_utils_posix.cc | 100 | ||||
-rw-r--r-- | mojo/common/test/test_utils_win.cc | 128 |
11 files changed, 645 insertions, 6 deletions
diff --git a/mojo/common/BUILD.gn b/mojo/common/BUILD.gn index a825189..4e9f6f6 100644 --- a/mojo/common/BUILD.gn +++ b/mojo/common/BUILD.gn @@ -37,7 +37,7 @@ test("mojo_common_unittests") { "//base", "//base:message_loop_tests", "//mojo/common/test:run_all_unittests", - "//mojo/edk/test:test_support", + "//mojo/common/test:test_support", "//mojo/environment:chromium", "//mojo/public/cpp/bindings", "//mojo/public/cpp/test_support:test_utils", @@ -49,5 +49,6 @@ test("mojo_common_unittests") { "common_type_converters_unittest.cc", "handle_watcher_unittest.cc", "message_pump_mojo_unittest.cc", + "test/multiprocess_test_helper_unittest.cc", ] } diff --git a/mojo/common/test/BUILD.gn b/mojo/common/test/BUILD.gn index ebad97e..9be7ff1 100644 --- a/mojo/common/test/BUILD.gn +++ b/mojo/common/test/BUILD.gn @@ -9,8 +9,8 @@ source_set("run_all_unittests") { ":test_support_impl", "//base", "//base/test:test_support", - "//mojo/edk/system", "//mojo/public/c/test_support", + "//mojo/system", "//testing/gtest", ] @@ -24,8 +24,8 @@ source_set("run_all_perftests") { ":test_support_impl", "//base", "//base/test:test_support", - "//mojo/edk/system", "//mojo/public/c/test_support", + "//mojo/system", ] sources = [ "run_all_perftests.cc" ] @@ -44,3 +44,22 @@ source_set("test_support_impl") { "test_support_impl.h", ] } + +# GYP version: mojo/mojo_base.gyp:mojo_common_test_support +source_set("test_support") { + testonly = true + deps = [ + "//base", + "//base/test:test_support", + "//testing/gtest", + "//mojo/system", + ] + + sources = [ + "multiprocess_test_helper.cc", + "multiprocess_test_helper.h", + "test_utils.h", + "test_utils_posix.cc", + "test_utils_win.cc", + ] +} diff --git a/mojo/common/test/DEPS b/mojo/common/test/DEPS index 61ef5fec..26b3ad9b 100644 --- a/mojo/common/test/DEPS +++ b/mojo/common/test/DEPS @@ -1,3 +1,3 @@ include_rules = [ - "+mojo/edk/embedder", + "+mojo/embedder", ] diff --git a/mojo/common/test/multiprocess_test_helper.cc b/mojo/common/test/multiprocess_test_helper.cc new file mode 100644 index 0000000..7e9df3e --- /dev/null +++ b/mojo/common/test/multiprocess_test_helper.cc @@ -0,0 +1,86 @@ +// Copyright 2013 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 "mojo/common/test/multiprocess_test_helper.h" + +#include "base/command_line.h" +#include "base/logging.h" +#include "base/process/kill.h" +#include "base/process/process_handle.h" +#include "build/build_config.h" +#include "mojo/embedder/platform_channel_pair.h" + +namespace mojo { +namespace test { + +MultiprocessTestHelper::MultiprocessTestHelper() + : test_child_handle_(base::kNullProcessHandle) { + platform_channel_pair_.reset(new embedder::PlatformChannelPair()); + server_platform_handle = platform_channel_pair_->PassServerHandle(); +} + +MultiprocessTestHelper::~MultiprocessTestHelper() { + CHECK_EQ(test_child_handle_, base::kNullProcessHandle); + server_platform_handle.reset(); + platform_channel_pair_.reset(); +} + +void MultiprocessTestHelper::StartChild(const std::string& test_child_name) { + CHECK(platform_channel_pair_.get()); + CHECK(!test_child_name.empty()); + CHECK_EQ(test_child_handle_, base::kNullProcessHandle); + + std::string test_child_main = test_child_name + "TestChildMain"; + + base::CommandLine command_line( + base::GetMultiProcessTestChildBaseCommandLine()); + embedder::HandlePassingInformation handle_passing_info; + platform_channel_pair_->PrepareToPassClientHandleToChildProcess( + &command_line, &handle_passing_info); + + base::LaunchOptions options; +#if defined(OS_POSIX) + options.fds_to_remap = &handle_passing_info; +#elif defined(OS_WIN) + options.start_hidden = true; + options.handles_to_inherit = &handle_passing_info; +#else +#error "Not supported yet." +#endif + + test_child_handle_ = + base::SpawnMultiProcessTestChild(test_child_main, command_line, options); + platform_channel_pair_->ChildProcessLaunched(); + + CHECK_NE(test_child_handle_, base::kNullProcessHandle); +} + +int MultiprocessTestHelper::WaitForChildShutdown() { + CHECK_NE(test_child_handle_, base::kNullProcessHandle); + + int rv = -1; + CHECK(base::WaitForExitCodeWithTimeout( + test_child_handle_, &rv, TestTimeouts::action_timeout())); + base::CloseProcessHandle(test_child_handle_); + test_child_handle_ = base::kNullProcessHandle; + return rv; +} + +bool MultiprocessTestHelper::WaitForChildTestShutdown() { + return WaitForChildShutdown() == 0; +} + +// static +void MultiprocessTestHelper::ChildSetup() { + CHECK(base::CommandLine::InitializedForCurrentProcess()); + client_platform_handle = + embedder::PlatformChannelPair::PassClientHandleFromParentProcess( + *base::CommandLine::ForCurrentProcess()); +} + +// static +embedder::ScopedPlatformHandle MultiprocessTestHelper::client_platform_handle; + +} // namespace test +} // namespace mojo diff --git a/mojo/common/test/multiprocess_test_helper.h b/mojo/common/test/multiprocess_test_helper.h new file mode 100644 index 0000000..d518b6f --- /dev/null +++ b/mojo/common/test/multiprocess_test_helper.h @@ -0,0 +1,91 @@ +// Copyright 2013 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. + +#ifndef MOJO_COMMON_TEST_MULTIPROCESS_TEST_HELPER_H_ +#define MOJO_COMMON_TEST_MULTIPROCESS_TEST_HELPER_H_ + +#include <string> + +#include "base/basictypes.h" +#include "base/compiler_specific.h" +#include "base/process/process_handle.h" +#include "base/test/multiprocess_test.h" +#include "base/test/test_timeouts.h" +#include "mojo/embedder/scoped_platform_handle.h" +#include "testing/multiprocess_func_list.h" + +namespace mojo { + +namespace embedder { +class PlatformChannelPair; +} + +namespace test { + +class MultiprocessTestHelper { + public: + MultiprocessTestHelper(); + ~MultiprocessTestHelper(); + + // Start a child process and run the "main" function "named" |test_child_name| + // declared using |MOJO_MULTIPROCESS_TEST_CHILD_MAIN()| or + // |MOJO_MULTIPROCESS_TEST_CHILD_TEST()| (below). + void StartChild(const std::string& test_child_name); + // Wait for the child process to terminate. + // Returns the exit code of the child process. Note that, though it's declared + // to be an |int|, the exit code is subject to mangling by the OS. E.g., we + // usually return -1 on error in the child (e.g., if |test_child_name| was not + // found), but this is mangled to 255 on Linux. You should only rely on codes + // 0-127 being preserved, and -1 being outside the range 0-127. + int WaitForChildShutdown(); + + // Like |WaitForChildShutdown()|, but returns true on success (exit code of 0) + // and false otherwise. You probably want to do something like + // |EXPECT_TRUE(WaitForChildTestShutdown());|. Mainly for use with + // |MOJO_MULTIPROCESS_TEST_CHILD_TEST()|. + bool WaitForChildTestShutdown(); + + // For use by |MOJO_MULTIPROCESS_TEST_CHILD_MAIN()| only: + static void ChildSetup(); + + // For use in the main process: + embedder::ScopedPlatformHandle server_platform_handle; + + // For use (and only valid) in the child process: + static embedder::ScopedPlatformHandle client_platform_handle; + + private: + scoped_ptr<embedder::PlatformChannelPair> platform_channel_pair_; + + // Valid after |StartChild()| and before |WaitForChildShutdown()|. + base::ProcessHandle test_child_handle_; + + DISALLOW_COPY_AND_ASSIGN(MultiprocessTestHelper); +}; + +// Use this to declare the child process's "main()" function for tests using +// |MultiprocessTestHelper|. It returns an |int|, which will be the process's +// exit code (but see the comment about |WaitForChildShutdown()|). +#define MOJO_MULTIPROCESS_TEST_CHILD_MAIN(test_child_name) \ + MULTIPROCESS_TEST_MAIN_WITH_SETUP( \ + test_child_name ## TestChildMain, \ + ::mojo::test::MultiprocessTestHelper::ChildSetup) + +// Use this (and |WaitForChildTestShutdown()|) for the child process's "main()", +// if you want to use |EXPECT_...()| or |ASSERT_...()|; it has a |void| return +// type. (Note that while an |ASSERT_...()| failure will abort the test in the +// child, it will not abort the test in the parent.) +#define MOJO_MULTIPROCESS_TEST_CHILD_TEST(test_child_name) \ + void test_child_name ## TestChildTest(); \ + MOJO_MULTIPROCESS_TEST_CHILD_MAIN(test_child_name) { \ + test_child_name ## TestChildTest(); \ + return (::testing::Test::HasFatalFailure() || \ + ::testing::Test::HasNonfatalFailure()) ? 1 : 0; \ + } \ + void test_child_name ## TestChildTest() + +} // namespace test +} // namespace mojo + +#endif // MOJO_COMMON_TEST_MULTIPROCESS_TEST_HELPER_H_ diff --git a/mojo/common/test/multiprocess_test_helper_unittest.cc b/mojo/common/test/multiprocess_test_helper_unittest.cc new file mode 100644 index 0000000..0ed10e2 --- /dev/null +++ b/mojo/common/test/multiprocess_test_helper_unittest.cc @@ -0,0 +1,157 @@ +// Copyright 2013 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 "mojo/common/test/multiprocess_test_helper.h" + +#include "base/logging.h" +#include "build/build_config.h" +#include "mojo/common/test/test_utils.h" +#include "mojo/embedder/scoped_platform_handle.h" +#include "testing/gtest/include/gtest/gtest.h" + +#if defined(OS_POSIX) +#include <fcntl.h> +#endif + +namespace mojo { +namespace test { +namespace { + +bool IsNonBlocking(const embedder::PlatformHandle& handle) { +#if defined(OS_WIN) + // Haven't figured out a way to query whether a HANDLE was created with + // FILE_FLAG_OVERLAPPED. + return true; +#else + return fcntl(handle.fd, F_GETFL) & O_NONBLOCK; +#endif +} + +bool WriteByte(const embedder::PlatformHandle& handle, char c) { + size_t bytes_written = 0; + BlockingWrite(handle, &c, 1, &bytes_written); + return bytes_written == 1; +} + +bool ReadByte(const embedder::PlatformHandle& handle, char* c) { + size_t bytes_read = 0; + BlockingRead(handle, c, 1, &bytes_read); + return bytes_read == 1; +} + +typedef testing::Test MultiprocessTestHelperTest; + +TEST_F(MultiprocessTestHelperTest, RunChild) { + MultiprocessTestHelper helper; + EXPECT_TRUE(helper.server_platform_handle.is_valid()); + + helper.StartChild("RunChild"); + EXPECT_EQ(123, helper.WaitForChildShutdown()); +} + +MOJO_MULTIPROCESS_TEST_CHILD_MAIN(RunChild) { + CHECK(MultiprocessTestHelper::client_platform_handle.is_valid()); + return 123; +} + +TEST_F(MultiprocessTestHelperTest, TestChildMainNotFound) { + MultiprocessTestHelper helper; + helper.StartChild("NoSuchTestChildMain"); + int result = helper.WaitForChildShutdown(); + EXPECT_FALSE(result >= 0 && result <= 127); +} + +TEST_F(MultiprocessTestHelperTest, PassedChannel) { + MultiprocessTestHelper helper; + EXPECT_TRUE(helper.server_platform_handle.is_valid()); + helper.StartChild("PassedChannel"); + + // Take ownership of the handle. + embedder::ScopedPlatformHandle handle = helper.server_platform_handle.Pass(); + + // The handle should be non-blocking. + EXPECT_TRUE(IsNonBlocking(handle.get())); + + // Write a byte. + const char c = 'X'; + EXPECT_TRUE(WriteByte(handle.get(), c)); + + // It'll echo it back to us, incremented. + char d = 0; + EXPECT_TRUE(ReadByte(handle.get(), &d)); + EXPECT_EQ(c + 1, d); + + // And return it, incremented again. + EXPECT_EQ(c + 2, helper.WaitForChildShutdown()); +} + +MOJO_MULTIPROCESS_TEST_CHILD_MAIN(PassedChannel) { + CHECK(MultiprocessTestHelper::client_platform_handle.is_valid()); + + // Take ownership of the handle. + embedder::ScopedPlatformHandle handle = + MultiprocessTestHelper::client_platform_handle.Pass(); + + // The handle should be non-blocking. + EXPECT_TRUE(IsNonBlocking(handle.get())); + + // Read a byte. + char c = 0; + EXPECT_TRUE(ReadByte(handle.get(), &c)); + + // Write it back, incremented. + c++; + EXPECT_TRUE(WriteByte(handle.get(), c)); + + // And return it, incremented again. + c++; + return static_cast<int>(c); +} + +TEST_F(MultiprocessTestHelperTest, ChildTestPasses) { + MultiprocessTestHelper helper; + EXPECT_TRUE(helper.server_platform_handle.is_valid()); + helper.StartChild("ChildTestPasses"); + EXPECT_TRUE(helper.WaitForChildTestShutdown()); +} + +MOJO_MULTIPROCESS_TEST_CHILD_TEST(ChildTestPasses) { + ASSERT_TRUE(MultiprocessTestHelper::client_platform_handle.is_valid()); + EXPECT_TRUE(IsNonBlocking( + MultiprocessTestHelper::client_platform_handle.get())); +} + +TEST_F(MultiprocessTestHelperTest, ChildTestFailsAssert) { + MultiprocessTestHelper helper; + EXPECT_TRUE(helper.server_platform_handle.is_valid()); + helper.StartChild("ChildTestFailsAssert"); + EXPECT_FALSE(helper.WaitForChildTestShutdown()); +} + +MOJO_MULTIPROCESS_TEST_CHILD_TEST(ChildTestFailsAssert) { + ASSERT_FALSE(MultiprocessTestHelper::client_platform_handle.is_valid()) + << "DISREGARD: Expected failure in child process"; + ASSERT_FALSE(IsNonBlocking( + MultiprocessTestHelper::client_platform_handle.get())) << "Not reached"; + CHECK(false) << "Not reached"; +} + +TEST_F(MultiprocessTestHelperTest, ChildTestFailsExpect) { + MultiprocessTestHelper helper; + EXPECT_TRUE(helper.server_platform_handle.is_valid()); + helper.StartChild("ChildTestFailsExpect"); + EXPECT_FALSE(helper.WaitForChildTestShutdown()); +} + +MOJO_MULTIPROCESS_TEST_CHILD_TEST(ChildTestFailsExpect) { + EXPECT_FALSE(MultiprocessTestHelper::client_platform_handle.is_valid()) + << "DISREGARD: Expected failure #1 in child process"; + EXPECT_FALSE(IsNonBlocking( + MultiprocessTestHelper::client_platform_handle.get())) + << "DISREGARD: Expected failure #2 in child process"; +} + +} // namespace +} // namespace test +} // namespace mojo diff --git a/mojo/common/test/run_all_perftests.cc b/mojo/common/test/run_all_perftests.cc index e3f41aa..87e39ce 100644 --- a/mojo/common/test/run_all_perftests.cc +++ b/mojo/common/test/run_all_perftests.cc @@ -4,7 +4,7 @@ #include "base/test/perf_test_suite.h" #include "mojo/common/test/test_support_impl.h" -#include "mojo/edk/embedder/test_embedder.h" +#include "mojo/embedder/test_embedder.h" #include "mojo/public/tests/test_support_private.h" int main(int argc, char** argv) { diff --git a/mojo/common/test/run_all_unittests.cc b/mojo/common/test/run_all_unittests.cc index 48c054e..814a259 100644 --- a/mojo/common/test/run_all_unittests.cc +++ b/mojo/common/test/run_all_unittests.cc @@ -6,7 +6,7 @@ #include "base/test/launcher/unit_test_launcher.h" #include "base/test/test_suite.h" #include "mojo/common/test/test_support_impl.h" -#include "mojo/edk/embedder/test_embedder.h" +#include "mojo/embedder/test_embedder.h" #include "mojo/public/tests/test_support_private.h" #include "testing/gtest/include/gtest/gtest.h" diff --git a/mojo/common/test/test_utils.h b/mojo/common/test/test_utils.h new file mode 100644 index 0000000..711dfe4 --- /dev/null +++ b/mojo/common/test/test_utils.h @@ -0,0 +1,57 @@ +// Copyright 2014 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. + +#ifndef MOJO_COMMON_TEST_TEST_UTILS_H_ +#define MOJO_COMMON_TEST_TEST_UTILS_H_ + +#include <stddef.h> +#include <stdio.h> + +#include <string> + +#include "base/files/file_path.h" +#include "base/files/scoped_file.h" +#include "mojo/embedder/platform_handle.h" +#include "mojo/embedder/scoped_platform_handle.h" + +namespace mojo { +namespace test { + +// On success, |bytes_written| is updated to the number of bytes written; +// otherwise it is untouched. +bool BlockingWrite(const embedder::PlatformHandle& handle, + const void* buffer, + size_t bytes_to_write, + size_t* bytes_written); + +// On success, |bytes_read| is updated to the number of bytes read; otherwise it +// is untouched. +bool BlockingRead(const embedder::PlatformHandle& handle, + void* buffer, + size_t buffer_size, + size_t* bytes_read); + +// If the read is done successfully or would block, the function returns true +// and updates |bytes_read| to the number of bytes read (0 if the read would +// block); otherwise it returns false and leaves |bytes_read| untouched. +// |handle| must already be in non-blocking mode. +bool NonBlockingRead(const embedder::PlatformHandle& handle, + void* buffer, + size_t buffer_size, + size_t* bytes_read); + +// Gets a (scoped) |PlatformHandle| from the given (scoped) |FILE|. +embedder::ScopedPlatformHandle PlatformHandleFromFILE(base::ScopedFILE fp); + +// Gets a (scoped) |FILE| from a (scoped) |PlatformHandle|. +base::ScopedFILE FILEFromPlatformHandle(embedder::ScopedPlatformHandle h, + const char* mode); + +// Returns the path to the mojom js bindings file. +base::FilePath GetFilePathForJSResource(const std::string& path); + +} // namespace test +} // namespace mojo + +#endif // MOJO_COMMON_TEST_TEST_UTILS_H_ diff --git a/mojo/common/test/test_utils_posix.cc b/mojo/common/test/test_utils_posix.cc new file mode 100644 index 0000000..0072d0a --- /dev/null +++ b/mojo/common/test/test_utils_posix.cc @@ -0,0 +1,100 @@ +// Copyright 2014 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 "mojo/common/test/test_utils.h" + +#include <fcntl.h> +#include <unistd.h> + +#include "base/base_paths.h" +#include "base/path_service.h" +#include "base/posix/eintr_wrapper.h" + +namespace mojo { +namespace test { + +bool BlockingWrite(const embedder::PlatformHandle& handle, + const void* buffer, + size_t bytes_to_write, + size_t* bytes_written) { + int original_flags = fcntl(handle.fd, F_GETFL); + if (original_flags == -1 || + fcntl(handle.fd, F_SETFL, original_flags & (~O_NONBLOCK)) != 0) { + return false; + } + + ssize_t result = HANDLE_EINTR(write(handle.fd, buffer, bytes_to_write)); + + fcntl(handle.fd, F_SETFL, original_flags); + + if (result < 0) + return false; + + *bytes_written = result; + return true; +} + +bool BlockingRead(const embedder::PlatformHandle& handle, + void* buffer, + size_t buffer_size, + size_t* bytes_read) { + int original_flags = fcntl(handle.fd, F_GETFL); + if (original_flags == -1 || + fcntl(handle.fd, F_SETFL, original_flags & (~O_NONBLOCK)) != 0) { + return false; + } + + ssize_t result = HANDLE_EINTR(read(handle.fd, buffer, buffer_size)); + + fcntl(handle.fd, F_SETFL, original_flags); + + if (result < 0) + return false; + + *bytes_read = result; + return true; +} + +bool NonBlockingRead(const embedder::PlatformHandle& handle, + void* buffer, + size_t buffer_size, + size_t* bytes_read) { + ssize_t result = HANDLE_EINTR(read(handle.fd, buffer, buffer_size)); + + if (result < 0) { + if (errno != EAGAIN && errno != EWOULDBLOCK) + return false; + + *bytes_read = 0; + } else { + *bytes_read = result; + } + + return true; +} + +embedder::ScopedPlatformHandle PlatformHandleFromFILE(base::ScopedFILE fp) { + CHECK(fp); + int rv = dup(fileno(fp.get())); + PCHECK(rv != -1) << "dup"; + return embedder::ScopedPlatformHandle(embedder::PlatformHandle(rv)); +} + +base::ScopedFILE FILEFromPlatformHandle(embedder::ScopedPlatformHandle h, + const char* mode) { + CHECK(h.is_valid()); + base::ScopedFILE rv(fdopen(h.release().fd, mode)); + PCHECK(rv) << "fdopen"; + return rv.Pass(); +} + +base::FilePath GetFilePathForJSResource(const std::string& path) { + std::string binding_path = "gen/" + path + ".js"; + base::FilePath exe_dir; + PathService::Get(base::DIR_EXE, &exe_dir); + return exe_dir.AppendASCII(binding_path); +} + +} // namespace test +} // namespace mojo diff --git a/mojo/common/test/test_utils_win.cc b/mojo/common/test/test_utils_win.cc new file mode 100644 index 0000000..71efced --- /dev/null +++ b/mojo/common/test/test_utils_win.cc @@ -0,0 +1,128 @@ +// Copyright 2014 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 "mojo/common/test/test_utils.h" + +#include <fcntl.h> +#include <io.h> +#include <string.h> +#include <windows.h> + +#include "base/base_paths.h" +#include "base/path_service.h" +#include "base/strings/string_util.h" + +namespace mojo { +namespace test { + +bool BlockingWrite(const embedder::PlatformHandle& handle, + const void* buffer, + size_t bytes_to_write, + size_t* bytes_written) { + OVERLAPPED overlapped = { 0 }; + DWORD bytes_written_dword = 0; + + if (!WriteFile(handle.handle, buffer, static_cast<DWORD>(bytes_to_write), + &bytes_written_dword, &overlapped)) { + if (GetLastError() != ERROR_IO_PENDING || + !GetOverlappedResult(handle.handle, &overlapped, &bytes_written_dword, + TRUE)) { + return false; + } + } + + *bytes_written = bytes_written_dword; + return true; +} + +bool BlockingRead(const embedder::PlatformHandle& handle, + void* buffer, + size_t buffer_size, + size_t* bytes_read) { + OVERLAPPED overlapped = { 0 }; + DWORD bytes_read_dword = 0; + + if (!ReadFile(handle.handle, buffer, static_cast<DWORD>(buffer_size), + &bytes_read_dword, &overlapped)) { + if (GetLastError() != ERROR_IO_PENDING || + !GetOverlappedResult(handle.handle, &overlapped, &bytes_read_dword, + TRUE)) { + return false; + } + } + + *bytes_read = bytes_read_dword; + return true; +} + +bool NonBlockingRead(const embedder::PlatformHandle& handle, + void* buffer, + size_t buffer_size, + size_t* bytes_read) { + OVERLAPPED overlapped = { 0 }; + DWORD bytes_read_dword = 0; + + if (!ReadFile(handle.handle, buffer, static_cast<DWORD>(buffer_size), + &bytes_read_dword, &overlapped)) { + if (GetLastError() != ERROR_IO_PENDING) + return false; + + CancelIo(handle.handle); + + if (!GetOverlappedResult(handle.handle, &overlapped, &bytes_read_dword, + TRUE)) { + *bytes_read = 0; + return true; + } + } + + *bytes_read = bytes_read_dword; + return true; +} + +embedder::ScopedPlatformHandle PlatformHandleFromFILE(base::ScopedFILE fp) { + CHECK(fp); + + HANDLE rv = INVALID_HANDLE_VALUE; + PCHECK(DuplicateHandle( + GetCurrentProcess(), + reinterpret_cast<HANDLE>(_get_osfhandle(_fileno(fp.get()))), + GetCurrentProcess(), + &rv, + 0, + TRUE, + DUPLICATE_SAME_ACCESS)) << "DuplicateHandle"; + return embedder::ScopedPlatformHandle(embedder::PlatformHandle(rv)); +} + +base::ScopedFILE FILEFromPlatformHandle(embedder::ScopedPlatformHandle h, + const char* mode) { + CHECK(h.is_valid()); + // Microsoft's documentation for |_open_osfhandle()| only discusses these + // flags (and |_O_WTEXT|). Hmmm. + int flags = 0; + if (strchr(mode, 'a')) + flags |= _O_APPEND; + if (strchr(mode, 'r')) + flags |= _O_RDONLY; + if (strchr(mode, 't')) + flags |= _O_TEXT; + base::ScopedFILE rv( + _fdopen(_open_osfhandle(reinterpret_cast<intptr_t>(h.release().handle), + flags), + mode)); + PCHECK(rv) << "_fdopen"; + return rv.Pass(); +} + +base::FilePath GetFilePathForJSResource(const std::string& path) { + std::string binding_path = "gen/" + path + ".js"; + base::ReplaceChars(binding_path, "//", "\\", &binding_path); + base::FilePath exe_dir; + PathService::Get(base::DIR_EXE, &exe_dir); + return exe_dir.AppendASCII(binding_path); +} + +} // namespace test +} // namespace mojo |