summaryrefslogtreecommitdiffstats
path: root/mojo/common
diff options
context:
space:
mode:
authorTrent Apted <tapted@chromium.org>2014-10-03 11:51:20 +1000
committerTrent Apted <tapted@chromium.org>2014-10-03 01:52:13 +0000
commit5a14236a9c2a7b9191c31ddccc5f1d7a4f6278a9 (patch)
treef4107f31a06d889dc0dcee9cfd2f66d6d2f19575 /mojo/common
parent11cbd199704f82210205e8e956af686e179e2689 (diff)
downloadchromium_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.gn3
-rw-r--r--mojo/common/test/BUILD.gn23
-rw-r--r--mojo/common/test/DEPS2
-rw-r--r--mojo/common/test/multiprocess_test_helper.cc86
-rw-r--r--mojo/common/test/multiprocess_test_helper.h91
-rw-r--r--mojo/common/test/multiprocess_test_helper_unittest.cc157
-rw-r--r--mojo/common/test/run_all_perftests.cc2
-rw-r--r--mojo/common/test/run_all_unittests.cc2
-rw-r--r--mojo/common/test/test_utils.h57
-rw-r--r--mojo/common/test/test_utils_posix.cc100
-rw-r--r--mojo/common/test/test_utils_win.cc128
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