普通文本  |  1487行  |  60.05 KB

// 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/system/core.h"

#include <stdint.h>

#include <limits>

#include "base/threading/platform_thread.h"
#include "base/time/time.h"
#include "mojo/system/core_test_base.h"

namespace mojo {
namespace system {
namespace {

const MojoHandleSignalsState kEmptyMojoHandleSignalsState = {0u, 0u};
const MojoHandleSignalsState kFullMojoHandleSignalsState = {~0u, ~0u};

typedef test::CoreTestBase CoreTest;

TEST_F(CoreTest, GetTimeTicksNow) {
  const MojoTimeTicks start = core()->GetTimeTicksNow();
  EXPECT_NE(static_cast<MojoTimeTicks>(0), start)
      << "GetTimeTicksNow should return nonzero value";
  base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(15));
  const MojoTimeTicks finish = core()->GetTimeTicksNow();
  // Allow for some fuzz in sleep.
  EXPECT_GE((finish - start), static_cast<MojoTimeTicks>(8000))
      << "Sleeping should result in increasing time ticks";
}

TEST_F(CoreTest, Basic) {
  MockHandleInfo info;

  EXPECT_EQ(0u, info.GetCtorCallCount());
  MojoHandle h = CreateMockHandle(&info);
  EXPECT_EQ(1u, info.GetCtorCallCount());
  EXPECT_NE(h, MOJO_HANDLE_INVALID);

  EXPECT_EQ(0u, info.GetWriteMessageCallCount());
  EXPECT_EQ(MOJO_RESULT_OK,
            core()->WriteMessage(h,
                                 NullUserPointer(),
                                 0,
                                 NullUserPointer(),
                                 0,
                                 MOJO_WRITE_MESSAGE_FLAG_NONE));
  EXPECT_EQ(1u, info.GetWriteMessageCallCount());

  EXPECT_EQ(0u, info.GetReadMessageCallCount());
  uint32_t num_bytes = 0;
  EXPECT_EQ(MOJO_RESULT_OK,
            core()->ReadMessage(h,
                                NullUserPointer(),
                                MakeUserPointer(&num_bytes),
                                NullUserPointer(),
                                NullUserPointer(),
                                MOJO_READ_MESSAGE_FLAG_NONE));
  EXPECT_EQ(1u, info.GetReadMessageCallCount());
  EXPECT_EQ(MOJO_RESULT_OK,
            core()->ReadMessage(h,
                                NullUserPointer(),
                                NullUserPointer(),
                                NullUserPointer(),
                                NullUserPointer(),
                                MOJO_READ_MESSAGE_FLAG_NONE));
  EXPECT_EQ(2u, info.GetReadMessageCallCount());

  EXPECT_EQ(0u, info.GetWriteDataCallCount());
  EXPECT_EQ(
      MOJO_RESULT_UNIMPLEMENTED,
      core()->WriteData(
          h, NullUserPointer(), NullUserPointer(), MOJO_WRITE_DATA_FLAG_NONE));
  EXPECT_EQ(1u, info.GetWriteDataCallCount());

  EXPECT_EQ(0u, info.GetBeginWriteDataCallCount());
  EXPECT_EQ(
      MOJO_RESULT_UNIMPLEMENTED,
      core()->BeginWriteData(
          h, NullUserPointer(), NullUserPointer(), MOJO_WRITE_DATA_FLAG_NONE));
  EXPECT_EQ(1u, info.GetBeginWriteDataCallCount());

  EXPECT_EQ(0u, info.GetEndWriteDataCallCount());
  EXPECT_EQ(MOJO_RESULT_UNIMPLEMENTED, core()->EndWriteData(h, 0));
  EXPECT_EQ(1u, info.GetEndWriteDataCallCount());

  EXPECT_EQ(0u, info.GetReadDataCallCount());
  EXPECT_EQ(
      MOJO_RESULT_UNIMPLEMENTED,
      core()->ReadData(
          h, NullUserPointer(), NullUserPointer(), MOJO_READ_DATA_FLAG_NONE));
  EXPECT_EQ(1u, info.GetReadDataCallCount());

  EXPECT_EQ(0u, info.GetBeginReadDataCallCount());
  EXPECT_EQ(
      MOJO_RESULT_UNIMPLEMENTED,
      core()->BeginReadData(
          h, NullUserPointer(), NullUserPointer(), MOJO_READ_DATA_FLAG_NONE));
  EXPECT_EQ(1u, info.GetBeginReadDataCallCount());

  EXPECT_EQ(0u, info.GetEndReadDataCallCount());
  EXPECT_EQ(MOJO_RESULT_UNIMPLEMENTED, core()->EndReadData(h, 0));
  EXPECT_EQ(1u, info.GetEndReadDataCallCount());

  EXPECT_EQ(0u, info.GetAddWaiterCallCount());
  EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION,
            core()->Wait(h,
                         ~MOJO_HANDLE_SIGNAL_NONE,
                         MOJO_DEADLINE_INDEFINITE,
                         NullUserPointer()));
  EXPECT_EQ(1u, info.GetAddWaiterCallCount());
  EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION,
            core()->Wait(h, ~MOJO_HANDLE_SIGNAL_NONE, 0, NullUserPointer()));
  EXPECT_EQ(2u, info.GetAddWaiterCallCount());
  MojoHandleSignalsState hss = kFullMojoHandleSignalsState;
  EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION,
            core()->Wait(h,
                         ~MOJO_HANDLE_SIGNAL_NONE,
                         MOJO_DEADLINE_INDEFINITE,
                         MakeUserPointer(&hss)));
  EXPECT_EQ(3u, info.GetAddWaiterCallCount());
  EXPECT_EQ(0u, hss.satisfied_signals);
  EXPECT_EQ(0u, hss.satisfiable_signals);
  EXPECT_EQ(
      MOJO_RESULT_FAILED_PRECONDITION,
      core()->Wait(h, ~MOJO_HANDLE_SIGNAL_NONE, 10 * 1000, NullUserPointer()));
  EXPECT_EQ(4u, info.GetAddWaiterCallCount());
  hss = kFullMojoHandleSignalsState;
  EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION,
            core()->Wait(
                h, ~MOJO_HANDLE_SIGNAL_NONE, 10 * 1000, MakeUserPointer(&hss)));
  EXPECT_EQ(5u, info.GetAddWaiterCallCount());
  EXPECT_EQ(0u, hss.satisfied_signals);
  EXPECT_EQ(0u, hss.satisfiable_signals);

  MojoHandleSignals handle_signals = ~MOJO_HANDLE_SIGNAL_NONE;
  EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION,
            core()->WaitMany(MakeUserPointer(&h),
                             MakeUserPointer(&handle_signals),
                             1,
                             MOJO_DEADLINE_INDEFINITE,
                             NullUserPointer(),
                             NullUserPointer()));
  EXPECT_EQ(6u, info.GetAddWaiterCallCount());
  uint32_t result_index = static_cast<uint32_t>(-1);
  EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION,
            core()->WaitMany(MakeUserPointer(&h),
                             MakeUserPointer(&handle_signals),
                             1,
                             MOJO_DEADLINE_INDEFINITE,
                             MakeUserPointer(&result_index),
                             NullUserPointer()));
  EXPECT_EQ(7u, info.GetAddWaiterCallCount());
  EXPECT_EQ(0u, result_index);
  hss = kFullMojoHandleSignalsState;
  EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION,
            core()->WaitMany(MakeUserPointer(&h),
                             MakeUserPointer(&handle_signals),
                             1,
                             MOJO_DEADLINE_INDEFINITE,
                             NullUserPointer(),
                             MakeUserPointer(&hss)));
  EXPECT_EQ(8u, info.GetAddWaiterCallCount());
  EXPECT_EQ(0u, hss.satisfied_signals);
  EXPECT_EQ(0u, hss.satisfiable_signals);
  result_index = static_cast<uint32_t>(-1);
  hss = kFullMojoHandleSignalsState;
  EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION,
            core()->WaitMany(MakeUserPointer(&h),
                             MakeUserPointer(&handle_signals),
                             1,
                             MOJO_DEADLINE_INDEFINITE,
                             MakeUserPointer(&result_index),
                             MakeUserPointer(&hss)));
  EXPECT_EQ(9u, info.GetAddWaiterCallCount());
  EXPECT_EQ(0u, result_index);
  EXPECT_EQ(0u, hss.satisfied_signals);
  EXPECT_EQ(0u, hss.satisfiable_signals);

  EXPECT_EQ(0u, info.GetDtorCallCount());
  EXPECT_EQ(0u, info.GetCloseCallCount());
  EXPECT_EQ(0u, info.GetCancelAllWaitersCallCount());
  EXPECT_EQ(MOJO_RESULT_OK, core()->Close(h));
  EXPECT_EQ(1u, info.GetCancelAllWaitersCallCount());
  EXPECT_EQ(1u, info.GetCloseCallCount());
  EXPECT_EQ(1u, info.GetDtorCallCount());

  // No waiters should ever have ever been added.
  EXPECT_EQ(0u, info.GetRemoveWaiterCallCount());
}

TEST_F(CoreTest, InvalidArguments) {
  // |Close()|:
  {
    EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT, core()->Close(MOJO_HANDLE_INVALID));
    EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT, core()->Close(10));
    EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT, core()->Close(1000000000));

    // Test a double-close.
    MockHandleInfo info;
    MojoHandle h = CreateMockHandle(&info);
    EXPECT_EQ(MOJO_RESULT_OK, core()->Close(h));
    EXPECT_EQ(1u, info.GetCloseCallCount());
    EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT, core()->Close(h));
    EXPECT_EQ(1u, info.GetCloseCallCount());
  }

  // |Wait()|:
  {
    EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT,
              core()->Wait(MOJO_HANDLE_INVALID,
                           ~MOJO_HANDLE_SIGNAL_NONE,
                           MOJO_DEADLINE_INDEFINITE,
                           NullUserPointer()));
    EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT,
              core()->Wait(10,
                           ~MOJO_HANDLE_SIGNAL_NONE,
                           MOJO_DEADLINE_INDEFINITE,
                           NullUserPointer()));

    MojoHandleSignalsState hss = kFullMojoHandleSignalsState;
    EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT,
              core()->Wait(MOJO_HANDLE_INVALID,
                           ~MOJO_HANDLE_SIGNAL_NONE,
                           MOJO_DEADLINE_INDEFINITE,
                           MakeUserPointer(&hss)));
    // On invalid argument, it shouldn't modify the handle signals state.
    EXPECT_EQ(kFullMojoHandleSignalsState.satisfied_signals,
              hss.satisfied_signals);
    EXPECT_EQ(kFullMojoHandleSignalsState.satisfiable_signals,
              hss.satisfiable_signals);
    hss = kFullMojoHandleSignalsState;
    EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT,
              core()->Wait(10,
                           ~MOJO_HANDLE_SIGNAL_NONE,
                           MOJO_DEADLINE_INDEFINITE,
                           MakeUserPointer(&hss)));
    // On invalid argument, it shouldn't modify the handle signals state.
    EXPECT_EQ(kFullMojoHandleSignalsState.satisfied_signals,
              hss.satisfied_signals);
    EXPECT_EQ(kFullMojoHandleSignalsState.satisfiable_signals,
              hss.satisfiable_signals);
  }

  // |WaitMany()|:
  {
    MojoHandle handles[2] = {MOJO_HANDLE_INVALID, MOJO_HANDLE_INVALID};
    MojoHandleSignals signals[2] = {~MOJO_HANDLE_SIGNAL_NONE,
                                    ~MOJO_HANDLE_SIGNAL_NONE};
    EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT,
              core()->WaitMany(MakeUserPointer(handles),
                               MakeUserPointer(signals),
                               0,
                               MOJO_DEADLINE_INDEFINITE,
                               NullUserPointer(),
                               NullUserPointer()));
    EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT,
              core()->WaitMany(NullUserPointer(),
                               MakeUserPointer(signals),
                               0,
                               MOJO_DEADLINE_INDEFINITE,
                               NullUserPointer(),
                               NullUserPointer()));
    // If |num_handles| is invalid, it should leave |result_index| and
    // |signals_states| alone.
    // (We use -1 internally; make sure that doesn't leak.)
    uint32_t result_index = 123;
    MojoHandleSignalsState hss = kFullMojoHandleSignalsState;
    EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT,
              core()->WaitMany(NullUserPointer(),
                               MakeUserPointer(signals),
                               0,
                               MOJO_DEADLINE_INDEFINITE,
                               MakeUserPointer(&result_index),
                               MakeUserPointer(&hss)));
    EXPECT_EQ(123u, result_index);
    EXPECT_EQ(kFullMojoHandleSignalsState.satisfied_signals,
              hss.satisfied_signals);
    EXPECT_EQ(kFullMojoHandleSignalsState.satisfiable_signals,
              hss.satisfiable_signals);

    EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT,
              core()->WaitMany(MakeUserPointer(handles),
                               NullUserPointer(),
                               0,
                               MOJO_DEADLINE_INDEFINITE,
                               NullUserPointer(),
                               NullUserPointer()));
    EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT,
              core()->WaitMany(MakeUserPointer(handles),
                               MakeUserPointer(signals),
                               1,
                               MOJO_DEADLINE_INDEFINITE,
                               NullUserPointer(),
                               NullUserPointer()));
    // But if a handle is bad, then it should set |result_index| but still leave
    // |signals_states| alone.
    result_index = static_cast<uint32_t>(-1);
    hss = kFullMojoHandleSignalsState;
    EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT,
              core()->WaitMany(MakeUserPointer(handles),
                               MakeUserPointer(signals),
                               1,
                               MOJO_DEADLINE_INDEFINITE,
                               MakeUserPointer(&result_index),
                               MakeUserPointer(&hss)));
    EXPECT_EQ(0u, result_index);
    EXPECT_EQ(kFullMojoHandleSignalsState.satisfied_signals,
              hss.satisfied_signals);
    EXPECT_EQ(kFullMojoHandleSignalsState.satisfiable_signals,
              hss.satisfiable_signals);

    MockHandleInfo info[2];
    handles[0] = CreateMockHandle(&info[0]);

    result_index = static_cast<uint32_t>(-1);
    hss = kFullMojoHandleSignalsState;
    EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION,
              core()->WaitMany(MakeUserPointer(handles),
                               MakeUserPointer(signals),
                               1,
                               MOJO_DEADLINE_INDEFINITE,
                               MakeUserPointer(&result_index),
                               MakeUserPointer(&hss)));
    EXPECT_EQ(0u, result_index);
    EXPECT_EQ(0u, hss.satisfied_signals);
    EXPECT_EQ(0u, hss.satisfiable_signals);

    // On invalid argument, it'll leave |signals_states| alone.
    result_index = static_cast<uint32_t>(-1);
    hss = kFullMojoHandleSignalsState;
    EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT,
              core()->WaitMany(MakeUserPointer(handles),
                               MakeUserPointer(signals),
                               2,
                               MOJO_DEADLINE_INDEFINITE,
                               MakeUserPointer(&result_index),
                               MakeUserPointer(&hss)));
    EXPECT_EQ(1u, result_index);
    EXPECT_EQ(kFullMojoHandleSignalsState.satisfied_signals,
              hss.satisfied_signals);
    EXPECT_EQ(kFullMojoHandleSignalsState.satisfiable_signals,
              hss.satisfiable_signals);
    handles[1] = handles[0] + 1;  // Invalid handle.
    EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT,
              core()->WaitMany(MakeUserPointer(handles),
                               MakeUserPointer(signals),
                               2,
                               MOJO_DEADLINE_INDEFINITE,
                               NullUserPointer(),
                               NullUserPointer()));
    handles[1] = CreateMockHandle(&info[1]);
    EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION,
              core()->WaitMany(MakeUserPointer(handles),
                               MakeUserPointer(signals),
                               2,
                               MOJO_DEADLINE_INDEFINITE,
                               NullUserPointer(),
                               NullUserPointer()));

    // TODO(vtl): Test one where we get "failed precondition" only for the
    // second handle (and the first one is valid to wait on).

    EXPECT_EQ(MOJO_RESULT_OK, core()->Close(handles[0]));
    EXPECT_EQ(MOJO_RESULT_OK, core()->Close(handles[1]));
  }

  // |CreateMessagePipe()|: Nothing to check (apart from things that cause
  // death).

  // |WriteMessage()|:
  // Only check arguments checked by |Core|, namely |handle|, |handles|, and
  // |num_handles|.
  {
    EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT,
              core()->WriteMessage(MOJO_HANDLE_INVALID,
                                   NullUserPointer(),
                                   0,
                                   NullUserPointer(),
                                   0,
                                   MOJO_WRITE_MESSAGE_FLAG_NONE));

    MockHandleInfo info;
    MojoHandle h = CreateMockHandle(&info);
    MojoHandle handles[2] = {MOJO_HANDLE_INVALID, MOJO_HANDLE_INVALID};

    // Huge handle count (implausibly big on some systems -- more than can be
    // stored in a 32-bit address space).
    // Note: This may return either |MOJO_RESULT_INVALID_ARGUMENT| or
    // |MOJO_RESULT_RESOURCE_EXHAUSTED|, depending on whether it's plausible or
    // not.
    EXPECT_NE(MOJO_RESULT_OK,
              core()->WriteMessage(h,
                                   NullUserPointer(),
                                   0,
                                   MakeUserPointer(handles),
                                   std::numeric_limits<uint32_t>::max(),
                                   MOJO_WRITE_MESSAGE_FLAG_NONE));
    EXPECT_EQ(0u, info.GetWriteMessageCallCount());

    // Huge handle count (plausibly big).
    EXPECT_EQ(MOJO_RESULT_RESOURCE_EXHAUSTED,
              core()->WriteMessage(
                  h,
                  NullUserPointer(),
                  0,
                  MakeUserPointer(handles),
                  std::numeric_limits<uint32_t>::max() / sizeof(handles[0]),
                  MOJO_WRITE_MESSAGE_FLAG_NONE));
    EXPECT_EQ(0u, info.GetWriteMessageCallCount());

    // Invalid handle in |handles|.
    EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT,
              core()->WriteMessage(h,
                                   NullUserPointer(),
                                   0,
                                   MakeUserPointer(handles),
                                   1,
                                   MOJO_WRITE_MESSAGE_FLAG_NONE));
    EXPECT_EQ(0u, info.GetWriteMessageCallCount());

    // Two invalid handles in |handles|.
    EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT,
              core()->WriteMessage(h,
                                   NullUserPointer(),
                                   0,
                                   MakeUserPointer(handles),
                                   2,
                                   MOJO_WRITE_MESSAGE_FLAG_NONE));
    EXPECT_EQ(0u, info.GetWriteMessageCallCount());

    // Can't send a handle over itself.
    handles[0] = h;
    EXPECT_EQ(MOJO_RESULT_BUSY,
              core()->WriteMessage(h,
                                   NullUserPointer(),
                                   0,
                                   MakeUserPointer(handles),
                                   1,
                                   MOJO_WRITE_MESSAGE_FLAG_NONE));
    EXPECT_EQ(0u, info.GetWriteMessageCallCount());

    MockHandleInfo info2;
    MojoHandle h2 = CreateMockHandle(&info2);

    // This is "okay", but |MockDispatcher| doesn't implement it.
    handles[0] = h2;
    EXPECT_EQ(MOJO_RESULT_UNIMPLEMENTED,
              core()->WriteMessage(h,
                                   NullUserPointer(),
                                   0,
                                   MakeUserPointer(handles),
                                   1,
                                   MOJO_WRITE_MESSAGE_FLAG_NONE));
    EXPECT_EQ(1u, info.GetWriteMessageCallCount());

    // One of the |handles| is still invalid.
    EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT,
              core()->WriteMessage(h,
                                   NullUserPointer(),
                                   0,
                                   MakeUserPointer(handles),
                                   2,
                                   MOJO_WRITE_MESSAGE_FLAG_NONE));
    EXPECT_EQ(1u, info.GetWriteMessageCallCount());

    // One of the |handles| is the same as |handle|.
    handles[1] = h;
    EXPECT_EQ(MOJO_RESULT_BUSY,
              core()->WriteMessage(h,
                                   NullUserPointer(),
                                   0,
                                   MakeUserPointer(handles),
                                   2,
                                   MOJO_WRITE_MESSAGE_FLAG_NONE));
    EXPECT_EQ(1u, info.GetWriteMessageCallCount());

    // Can't send a handle twice in the same message.
    handles[1] = h2;
    EXPECT_EQ(MOJO_RESULT_BUSY,
              core()->WriteMessage(h,
                                   NullUserPointer(),
                                   0,
                                   MakeUserPointer(handles),
                                   2,
                                   MOJO_WRITE_MESSAGE_FLAG_NONE));
    EXPECT_EQ(1u, info.GetWriteMessageCallCount());

    // Note: Since we never successfully sent anything with it, |h2| should
    // still be valid.
    EXPECT_EQ(MOJO_RESULT_OK, core()->Close(h2));

    EXPECT_EQ(MOJO_RESULT_OK, core()->Close(h));
  }

  // |ReadMessage()|:
  // Only check arguments checked by |Core|, namely |handle|, |handles|, and
  // |num_handles|.
  {
    EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT,
              core()->ReadMessage(MOJO_HANDLE_INVALID,
                                  NullUserPointer(),
                                  NullUserPointer(),
                                  NullUserPointer(),
                                  NullUserPointer(),
                                  MOJO_READ_MESSAGE_FLAG_NONE));

    MockHandleInfo info;
    MojoHandle h = CreateMockHandle(&info);

    // Okay.
    uint32_t handle_count = 0;
    EXPECT_EQ(MOJO_RESULT_OK,
              core()->ReadMessage(h,
                                  NullUserPointer(),
                                  NullUserPointer(),
                                  NullUserPointer(),
                                  MakeUserPointer(&handle_count),
                                  MOJO_READ_MESSAGE_FLAG_NONE));
    // Checked by |Core|, shouldn't go through to the dispatcher.
    EXPECT_EQ(1u, info.GetReadMessageCallCount());

    EXPECT_EQ(MOJO_RESULT_OK, core()->Close(h));
  }
}

// These test invalid arguments that should cause death if we're being paranoid
// about checking arguments (which we would want to do if, e.g., we were in a
// true "kernel" situation, but we might not want to do otherwise for
// performance reasons). Probably blatant errors like passing in null pointers
// (for required pointer arguments) will still cause death, but perhaps not
// predictably.
TEST_F(CoreTest, InvalidArgumentsDeath) {
  const char kMemoryCheckFailedRegex[] = "Check failed";

  // |WaitMany()|:
  {
    MojoHandle handle = MOJO_HANDLE_INVALID;
    MojoHandleSignals signals = ~MOJO_HANDLE_SIGNAL_NONE;
    EXPECT_DEATH_IF_SUPPORTED(core()->WaitMany(NullUserPointer(),
                                               MakeUserPointer(&signals),
                                               1,
                                               MOJO_DEADLINE_INDEFINITE,
                                               NullUserPointer(),
                                               NullUserPointer()),
                              kMemoryCheckFailedRegex);
    EXPECT_DEATH_IF_SUPPORTED(core()->WaitMany(MakeUserPointer(&handle),
                                               NullUserPointer(),
                                               1,
                                               MOJO_DEADLINE_INDEFINITE,
                                               NullUserPointer(),
                                               NullUserPointer()),
                              kMemoryCheckFailedRegex);
    // TODO(vtl): |result_index| and |signals_states| are optional. Test them
    // with non-null invalid pointers?
  }

  // |CreateMessagePipe()|:
  {
    MojoHandle h;
    EXPECT_DEATH_IF_SUPPORTED(
        core()->CreateMessagePipe(
            NullUserPointer(), NullUserPointer(), NullUserPointer()),
        kMemoryCheckFailedRegex);
    EXPECT_DEATH_IF_SUPPORTED(
        core()->CreateMessagePipe(
            NullUserPointer(), MakeUserPointer(&h), NullUserPointer()),
        kMemoryCheckFailedRegex);
    EXPECT_DEATH_IF_SUPPORTED(
        core()->CreateMessagePipe(
            NullUserPointer(), NullUserPointer(), MakeUserPointer(&h)),
        kMemoryCheckFailedRegex);
  }

  // |WriteMessage()|:
  // Only check arguments checked by |Core|, namely |handle|, |handles|, and
  // |num_handles|.
  {
    MockHandleInfo info;
    MojoHandle h = CreateMockHandle(&info);

    // Null |handles| with nonzero |num_handles|.
    EXPECT_DEATH_IF_SUPPORTED(
        core()->WriteMessage(h,
                             NullUserPointer(),
                             0,
                             NullUserPointer(),
                             1,
                             MOJO_WRITE_MESSAGE_FLAG_NONE),
        kMemoryCheckFailedRegex);

    EXPECT_EQ(MOJO_RESULT_OK, core()->Close(h));
  }

  // |ReadMessage()|:
  // Only check arguments checked by |Core|, namely |handle|, |handles|, and
  // |num_handles|.
  {
    MockHandleInfo info;
    MojoHandle h = CreateMockHandle(&info);

    uint32_t handle_count = 1;
    EXPECT_DEATH_IF_SUPPORTED(
        core()->ReadMessage(h,
                            NullUserPointer(),
                            NullUserPointer(),
                            NullUserPointer(),
                            MakeUserPointer(&handle_count),
                            MOJO_READ_MESSAGE_FLAG_NONE),
        kMemoryCheckFailedRegex);

    EXPECT_EQ(MOJO_RESULT_OK, core()->Close(h));
  }
}

// TODO(vtl): test |Wait()| and |WaitMany()| properly
//  - including |WaitMany()| with the same handle more than once (with
//    same/different signals)

TEST_F(CoreTest, MessagePipe) {
  MojoHandle h[2];
  MojoHandleSignalsState hss[2];
  uint32_t result_index;

  EXPECT_EQ(
      MOJO_RESULT_OK,
      core()->CreateMessagePipe(
          NullUserPointer(), MakeUserPointer(&h[0]), MakeUserPointer(&h[1])));
  // Should get two distinct, valid handles.
  EXPECT_NE(h[0], MOJO_HANDLE_INVALID);
  EXPECT_NE(h[1], MOJO_HANDLE_INVALID);
  EXPECT_NE(h[0], h[1]);

  // Neither should be readable.
  MojoHandleSignals signals[2] = {MOJO_HANDLE_SIGNAL_READABLE,
                                  MOJO_HANDLE_SIGNAL_READABLE};
  result_index = static_cast<uint32_t>(-1);
  hss[0] = kEmptyMojoHandleSignalsState;
  hss[1] = kEmptyMojoHandleSignalsState;
  EXPECT_EQ(MOJO_RESULT_DEADLINE_EXCEEDED,
            core()->WaitMany(MakeUserPointer(h),
                             MakeUserPointer(signals),
                             2,
                             0,
                             MakeUserPointer(&result_index),
                             MakeUserPointer(hss)));
  EXPECT_EQ(static_cast<uint32_t>(-1), result_index);
  EXPECT_EQ(MOJO_HANDLE_SIGNAL_WRITABLE, hss[0].satisfied_signals);
  EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE,
            hss[0].satisfiable_signals);
  EXPECT_EQ(MOJO_HANDLE_SIGNAL_WRITABLE, hss[1].satisfied_signals);
  EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE,
            hss[1].satisfiable_signals);

  // Try to read anyway.
  char buffer[1] = {'a'};
  uint32_t buffer_size = 1;
  EXPECT_EQ(MOJO_RESULT_SHOULD_WAIT,
            core()->ReadMessage(h[0],
                                UserPointer<void>(buffer),
                                MakeUserPointer(&buffer_size),
                                NullUserPointer(),
                                NullUserPointer(),
                                MOJO_READ_MESSAGE_FLAG_NONE));
  // Check that it left its inputs alone.
  EXPECT_EQ('a', buffer[0]);
  EXPECT_EQ(1u, buffer_size);

  // Both should be writable.
  hss[0] = kEmptyMojoHandleSignalsState;
  EXPECT_EQ(MOJO_RESULT_OK,
            core()->Wait(h[0],
                         MOJO_HANDLE_SIGNAL_WRITABLE,
                         1000000000,
                         MakeUserPointer(&hss[0])));
  EXPECT_EQ(MOJO_HANDLE_SIGNAL_WRITABLE, hss[0].satisfied_signals);
  EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE,
            hss[0].satisfiable_signals);
  hss[0] = kEmptyMojoHandleSignalsState;
  EXPECT_EQ(MOJO_RESULT_OK,
            core()->Wait(h[1],
                         MOJO_HANDLE_SIGNAL_WRITABLE,
                         1000000000,
                         MakeUserPointer(&hss[0])));
  EXPECT_EQ(MOJO_HANDLE_SIGNAL_WRITABLE, hss[0].satisfied_signals);
  EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE,
            hss[0].satisfiable_signals);

  // Also check that |h[1]| is writable using |WaitMany()|.
  signals[0] = MOJO_HANDLE_SIGNAL_READABLE;
  signals[1] = MOJO_HANDLE_SIGNAL_WRITABLE;
  result_index = static_cast<uint32_t>(-1);
  hss[0] = kEmptyMojoHandleSignalsState;
  hss[1] = kEmptyMojoHandleSignalsState;
  EXPECT_EQ(MOJO_RESULT_OK,
            core()->WaitMany(MakeUserPointer(h),
                             MakeUserPointer(signals),
                             2,
                             MOJO_DEADLINE_INDEFINITE,
                             MakeUserPointer(&result_index),
                             MakeUserPointer(hss)));
  EXPECT_EQ(1u, result_index);
  EXPECT_EQ(MOJO_HANDLE_SIGNAL_WRITABLE, hss[0].satisfied_signals);
  EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE,
            hss[0].satisfiable_signals);
  EXPECT_EQ(MOJO_HANDLE_SIGNAL_WRITABLE, hss[1].satisfied_signals);
  EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE,
            hss[1].satisfiable_signals);

  // Write to |h[1]|.
  buffer[0] = 'b';
  EXPECT_EQ(MOJO_RESULT_OK,
            core()->WriteMessage(h[1],
                                 UserPointer<const void>(buffer),
                                 1,
                                 NullUserPointer(),
                                 0,
                                 MOJO_WRITE_MESSAGE_FLAG_NONE));

  // Check that |h[0]| is now readable.
  signals[0] = MOJO_HANDLE_SIGNAL_READABLE;
  signals[1] = MOJO_HANDLE_SIGNAL_READABLE;
  result_index = static_cast<uint32_t>(-1);
  hss[0] = kEmptyMojoHandleSignalsState;
  hss[1] = kEmptyMojoHandleSignalsState;
  EXPECT_EQ(MOJO_RESULT_OK,
            core()->WaitMany(MakeUserPointer(h),
                             MakeUserPointer(signals),
                             2,
                             MOJO_DEADLINE_INDEFINITE,
                             MakeUserPointer(&result_index),
                             MakeUserPointer(hss)));
  EXPECT_EQ(0u, result_index);
  EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE,
            hss[0].satisfied_signals);
  EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE,
            hss[0].satisfiable_signals);
  EXPECT_EQ(MOJO_HANDLE_SIGNAL_WRITABLE, hss[1].satisfied_signals);
  EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE,
            hss[1].satisfiable_signals);

  // Read from |h[0]|.
  // First, get only the size.
  buffer_size = 0;
  EXPECT_EQ(MOJO_RESULT_RESOURCE_EXHAUSTED,
            core()->ReadMessage(h[0],
                                NullUserPointer(),
                                MakeUserPointer(&buffer_size),
                                NullUserPointer(),
                                NullUserPointer(),
                                MOJO_READ_MESSAGE_FLAG_NONE));
  EXPECT_EQ(1u, buffer_size);
  // Then actually read it.
  buffer[0] = 'c';
  buffer_size = 1;
  EXPECT_EQ(MOJO_RESULT_OK,
            core()->ReadMessage(h[0],
                                UserPointer<void>(buffer),
                                MakeUserPointer(&buffer_size),
                                NullUserPointer(),
                                NullUserPointer(),
                                MOJO_READ_MESSAGE_FLAG_NONE));
  EXPECT_EQ('b', buffer[0]);
  EXPECT_EQ(1u, buffer_size);

  // |h[0]| should no longer be readable.
  hss[0] = kEmptyMojoHandleSignalsState;
  EXPECT_EQ(
      MOJO_RESULT_DEADLINE_EXCEEDED,
      core()->Wait(
          h[0], MOJO_HANDLE_SIGNAL_READABLE, 0, MakeUserPointer(&hss[0])));
  EXPECT_EQ(MOJO_HANDLE_SIGNAL_WRITABLE, hss[0].satisfied_signals);
  EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE,
            hss[0].satisfiable_signals);

  // Write to |h[0]|.
  buffer[0] = 'd';
  EXPECT_EQ(MOJO_RESULT_OK,
            core()->WriteMessage(h[0],
                                 UserPointer<const void>(buffer),
                                 1,
                                 NullUserPointer(),
                                 0,
                                 MOJO_WRITE_MESSAGE_FLAG_NONE));

  // Close |h[0]|.
  EXPECT_EQ(MOJO_RESULT_OK, core()->Close(h[0]));

  // Check that |h[1]| is no longer writable (and will never be).
  hss[0] = kEmptyMojoHandleSignalsState;
  EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION,
            core()->Wait(h[1],
                         MOJO_HANDLE_SIGNAL_WRITABLE,
                         1000000000,
                         MakeUserPointer(&hss[0])));
  EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE, hss[0].satisfied_signals);
  EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE, hss[0].satisfiable_signals);

  // Check that |h[1]| is still readable (for the moment).
  hss[0] = kEmptyMojoHandleSignalsState;
  EXPECT_EQ(MOJO_RESULT_OK,
            core()->Wait(h[1],
                         MOJO_HANDLE_SIGNAL_READABLE,
                         1000000000,
                         MakeUserPointer(&hss[0])));
  EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE, hss[0].satisfied_signals);
  EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE, hss[0].satisfiable_signals);

  // Discard a message from |h[1]|.
  EXPECT_EQ(MOJO_RESULT_RESOURCE_EXHAUSTED,
            core()->ReadMessage(h[1],
                                NullUserPointer(),
                                NullUserPointer(),
                                NullUserPointer(),
                                NullUserPointer(),
                                MOJO_READ_MESSAGE_FLAG_MAY_DISCARD));

  // |h[1]| is no longer readable (and will never be).
  hss[0] = kFullMojoHandleSignalsState;
  EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION,
            core()->Wait(h[1],
                         MOJO_HANDLE_SIGNAL_READABLE,
                         1000000000,
                         MakeUserPointer(&hss[0])));
  EXPECT_EQ(0u, hss[0].satisfied_signals);
  EXPECT_EQ(0u, hss[0].satisfiable_signals);

  // Try writing to |h[1]|.
  buffer[0] = 'e';
  EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION,
            core()->WriteMessage(h[1],
                                 UserPointer<const void>(buffer),
                                 1,
                                 NullUserPointer(),
                                 0,
                                 MOJO_WRITE_MESSAGE_FLAG_NONE));

  EXPECT_EQ(MOJO_RESULT_OK, core()->Close(h[1]));
}

// Tests passing a message pipe handle.
TEST_F(CoreTest, MessagePipeBasicLocalHandlePassing1) {
  const char kHello[] = "hello";
  const uint32_t kHelloSize = static_cast<uint32_t>(sizeof(kHello));
  const char kWorld[] = "world!!!";
  const uint32_t kWorldSize = static_cast<uint32_t>(sizeof(kWorld));
  char buffer[100];
  const uint32_t kBufferSize = static_cast<uint32_t>(sizeof(buffer));
  uint32_t num_bytes;
  MojoHandle handles[10];
  uint32_t num_handles;
  MojoHandleSignalsState hss;
  MojoHandle h_received;

  MojoHandle h_passing[2];
  EXPECT_EQ(MOJO_RESULT_OK,
            core()->CreateMessagePipe(NullUserPointer(),
                                      MakeUserPointer(&h_passing[0]),
                                      MakeUserPointer(&h_passing[1])));

  // Make sure that |h_passing[]| work properly.
  EXPECT_EQ(MOJO_RESULT_OK,
            core()->WriteMessage(h_passing[0],
                                 UserPointer<const void>(kHello),
                                 kHelloSize,
                                 NullUserPointer(),
                                 0,
                                 MOJO_WRITE_MESSAGE_FLAG_NONE));
  hss = kEmptyMojoHandleSignalsState;
  EXPECT_EQ(MOJO_RESULT_OK,
            core()->Wait(h_passing[1],
                         MOJO_HANDLE_SIGNAL_READABLE,
                         1000000000,
                         MakeUserPointer(&hss)));
  EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE,
            hss.satisfied_signals);
  EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE,
            hss.satisfiable_signals);
  num_bytes = kBufferSize;
  num_handles = arraysize(handles);
  EXPECT_EQ(MOJO_RESULT_OK,
            core()->ReadMessage(h_passing[1],
                                UserPointer<void>(buffer),
                                MakeUserPointer(&num_bytes),
                                MakeUserPointer(handles),
                                MakeUserPointer(&num_handles),
                                MOJO_READ_MESSAGE_FLAG_NONE));
  EXPECT_EQ(kHelloSize, num_bytes);
  EXPECT_STREQ(kHello, buffer);
  EXPECT_EQ(0u, num_handles);

  // Make sure that you can't pass either of the message pipe's handles over
  // itself.
  EXPECT_EQ(MOJO_RESULT_BUSY,
            core()->WriteMessage(h_passing[0],
                                 UserPointer<const void>(kHello),
                                 kHelloSize,
                                 MakeUserPointer(&h_passing[0]),
                                 1,
                                 MOJO_WRITE_MESSAGE_FLAG_NONE));
  EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT,
            core()->WriteMessage(h_passing[0],
                                 UserPointer<const void>(kHello),
                                 kHelloSize,
                                 MakeUserPointer(&h_passing[1]),
                                 1,
                                 MOJO_WRITE_MESSAGE_FLAG_NONE));

  MojoHandle h_passed[2];
  EXPECT_EQ(MOJO_RESULT_OK,
            core()->CreateMessagePipe(NullUserPointer(),
                                      MakeUserPointer(&h_passed[0]),
                                      MakeUserPointer(&h_passed[1])));

  // Make sure that |h_passed[]| work properly.
  EXPECT_EQ(MOJO_RESULT_OK,
            core()->WriteMessage(h_passed[0],
                                 UserPointer<const void>(kHello),
                                 kHelloSize,
                                 NullUserPointer(),
                                 0,
                                 MOJO_WRITE_MESSAGE_FLAG_NONE));
  hss = kEmptyMojoHandleSignalsState;
  EXPECT_EQ(MOJO_RESULT_OK,
            core()->Wait(h_passed[1],
                         MOJO_HANDLE_SIGNAL_READABLE,
                         1000000000,
                         MakeUserPointer(&hss)));
  EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE,
            hss.satisfied_signals);
  EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE,
            hss.satisfiable_signals);
  num_bytes = kBufferSize;
  num_handles = arraysize(handles);
  EXPECT_EQ(MOJO_RESULT_OK,
            core()->ReadMessage(h_passed[1],
                                UserPointer<void>(buffer),
                                MakeUserPointer(&num_bytes),
                                MakeUserPointer(handles),
                                MakeUserPointer(&num_handles),
                                MOJO_READ_MESSAGE_FLAG_NONE));
  EXPECT_EQ(kHelloSize, num_bytes);
  EXPECT_STREQ(kHello, buffer);
  EXPECT_EQ(0u, num_handles);

  // Send |h_passed[1]| from |h_passing[0]| to |h_passing[1]|.
  EXPECT_EQ(MOJO_RESULT_OK,
            core()->WriteMessage(h_passing[0],
                                 UserPointer<const void>(kWorld),
                                 kWorldSize,
                                 MakeUserPointer(&h_passed[1]),
                                 1,
                                 MOJO_WRITE_MESSAGE_FLAG_NONE));
  hss = kEmptyMojoHandleSignalsState;
  EXPECT_EQ(MOJO_RESULT_OK,
            core()->Wait(h_passing[1],
                         MOJO_HANDLE_SIGNAL_READABLE,
                         1000000000,
                         MakeUserPointer(&hss)));
  EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE,
            hss.satisfied_signals);
  EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE,
            hss.satisfiable_signals);
  num_bytes = kBufferSize;
  num_handles = arraysize(handles);
  EXPECT_EQ(MOJO_RESULT_OK,
            core()->ReadMessage(h_passing[1],
                                UserPointer<void>(buffer),
                                MakeUserPointer(&num_bytes),
                                MakeUserPointer(handles),
                                MakeUserPointer(&num_handles),
                                MOJO_READ_MESSAGE_FLAG_NONE));
  EXPECT_EQ(kWorldSize, num_bytes);
  EXPECT_STREQ(kWorld, buffer);
  EXPECT_EQ(1u, num_handles);
  h_received = handles[0];
  EXPECT_NE(h_received, MOJO_HANDLE_INVALID);
  EXPECT_NE(h_received, h_passing[0]);
  EXPECT_NE(h_received, h_passing[1]);
  EXPECT_NE(h_received, h_passed[0]);

  // Note: We rely on the Mojo system not re-using handle values very often.
  EXPECT_NE(h_received, h_passed[1]);

  // |h_passed[1]| should no longer be valid; check that trying to close it
  // fails. See above note.
  EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT, core()->Close(h_passed[1]));

  // Write to |h_passed[0]|. Should receive on |h_received|.
  EXPECT_EQ(MOJO_RESULT_OK,
            core()->WriteMessage(h_passed[0],
                                 UserPointer<const void>(kHello),
                                 kHelloSize,
                                 NullUserPointer(),
                                 0,
                                 MOJO_WRITE_MESSAGE_FLAG_NONE));
  hss = kEmptyMojoHandleSignalsState;
  EXPECT_EQ(MOJO_RESULT_OK,
            core()->Wait(h_received,
                         MOJO_HANDLE_SIGNAL_READABLE,
                         1000000000,
                         MakeUserPointer(&hss)));
  EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE,
            hss.satisfied_signals);
  EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE,
            hss.satisfiable_signals);
  num_bytes = kBufferSize;
  num_handles = arraysize(handles);
  EXPECT_EQ(MOJO_RESULT_OK,
            core()->ReadMessage(h_received,
                                UserPointer<void>(buffer),
                                MakeUserPointer(&num_bytes),
                                MakeUserPointer(handles),
                                MakeUserPointer(&num_handles),
                                MOJO_READ_MESSAGE_FLAG_NONE));
  EXPECT_EQ(kHelloSize, num_bytes);
  EXPECT_STREQ(kHello, buffer);
  EXPECT_EQ(0u, num_handles);

  EXPECT_EQ(MOJO_RESULT_OK, core()->Close(h_passing[0]));
  EXPECT_EQ(MOJO_RESULT_OK, core()->Close(h_passing[1]));
  EXPECT_EQ(MOJO_RESULT_OK, core()->Close(h_passed[0]));
  EXPECT_EQ(MOJO_RESULT_OK, core()->Close(h_received));
}

TEST_F(CoreTest, DataPipe) {
  MojoHandle ph, ch;  // p is for producer and c is for consumer.
  MojoHandleSignalsState hss;

  EXPECT_EQ(MOJO_RESULT_OK,
            core()->CreateDataPipe(
                NullUserPointer(), MakeUserPointer(&ph), MakeUserPointer(&ch)));
  // Should get two distinct, valid handles.
  EXPECT_NE(ph, MOJO_HANDLE_INVALID);
  EXPECT_NE(ch, MOJO_HANDLE_INVALID);
  EXPECT_NE(ph, ch);

  // Producer should be never-readable, but already writable.
  hss = kEmptyMojoHandleSignalsState;
  EXPECT_EQ(
      MOJO_RESULT_FAILED_PRECONDITION,
      core()->Wait(ph, MOJO_HANDLE_SIGNAL_READABLE, 0, MakeUserPointer(&hss)));
  EXPECT_EQ(MOJO_HANDLE_SIGNAL_WRITABLE, hss.satisfied_signals);
  EXPECT_EQ(MOJO_HANDLE_SIGNAL_WRITABLE, hss.satisfiable_signals);
  hss = kEmptyMojoHandleSignalsState;
  EXPECT_EQ(
      MOJO_RESULT_OK,
      core()->Wait(ph, MOJO_HANDLE_SIGNAL_WRITABLE, 0, MakeUserPointer(&hss)));
  EXPECT_EQ(MOJO_HANDLE_SIGNAL_WRITABLE, hss.satisfied_signals);
  EXPECT_EQ(MOJO_HANDLE_SIGNAL_WRITABLE, hss.satisfiable_signals);

  // Consumer should be never-writable, and not yet readable.
  hss = kFullMojoHandleSignalsState;
  EXPECT_EQ(
      MOJO_RESULT_FAILED_PRECONDITION,
      core()->Wait(ch, MOJO_HANDLE_SIGNAL_WRITABLE, 0, MakeUserPointer(&hss)));
  EXPECT_EQ(0u, hss.satisfied_signals);
  EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE, hss.satisfiable_signals);
  hss = kFullMojoHandleSignalsState;
  EXPECT_EQ(
      MOJO_RESULT_DEADLINE_EXCEEDED,
      core()->Wait(ch, MOJO_HANDLE_SIGNAL_READABLE, 0, MakeUserPointer(&hss)));
  EXPECT_EQ(0u, hss.satisfied_signals);
  EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE, hss.satisfiable_signals);

  // Write.
  char elements[2] = {'A', 'B'};
  uint32_t num_bytes = 2u;
  EXPECT_EQ(MOJO_RESULT_OK,
            core()->WriteData(ph,
                              UserPointer<const void>(elements),
                              MakeUserPointer(&num_bytes),
                              MOJO_WRITE_DATA_FLAG_NONE));
  EXPECT_EQ(2u, num_bytes);

  // Consumer should now be readable.
  hss = kEmptyMojoHandleSignalsState;
  EXPECT_EQ(
      MOJO_RESULT_OK,
      core()->Wait(ch, MOJO_HANDLE_SIGNAL_READABLE, 0, MakeUserPointer(&hss)));
  EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE, hss.satisfied_signals);
  EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE, hss.satisfiable_signals);

  // Read one character.
  elements[0] = -1;
  elements[1] = -1;
  num_bytes = 1u;
  EXPECT_EQ(MOJO_RESULT_OK,
            core()->ReadData(ch,
                             UserPointer<void>(elements),
                             MakeUserPointer(&num_bytes),
                             MOJO_READ_DATA_FLAG_NONE));
  EXPECT_EQ('A', elements[0]);
  EXPECT_EQ(-1, elements[1]);

  // Two-phase write.
  void* write_ptr = nullptr;
  num_bytes = 0u;
  ASSERT_EQ(MOJO_RESULT_OK,
            core()->BeginWriteData(ph,
                                   MakeUserPointer(&write_ptr),
                                   MakeUserPointer(&num_bytes),
                                   MOJO_WRITE_DATA_FLAG_NONE));
  // We count on the default options providing a decent buffer size.
  ASSERT_GE(num_bytes, 3u);

  // Trying to do a normal write during a two-phase write should fail.
  elements[0] = 'X';
  num_bytes = 1u;
  EXPECT_EQ(MOJO_RESULT_BUSY,
            core()->WriteData(ph,
                              UserPointer<const void>(elements),
                              MakeUserPointer(&num_bytes),
                              MOJO_WRITE_DATA_FLAG_NONE));

  // Actually write the data, and complete it now.
  static_cast<char*>(write_ptr)[0] = 'C';
  static_cast<char*>(write_ptr)[1] = 'D';
  static_cast<char*>(write_ptr)[2] = 'E';
  EXPECT_EQ(MOJO_RESULT_OK, core()->EndWriteData(ph, 3u));

  // Query how much data we have.
  num_bytes = 0;
  EXPECT_EQ(MOJO_RESULT_OK,
            core()->ReadData(ch,
                             NullUserPointer(),
                             MakeUserPointer(&num_bytes),
                             MOJO_READ_DATA_FLAG_QUERY));
  EXPECT_EQ(4u, num_bytes);

  // Try to discard ten characters, in all-or-none mode. Should fail.
  num_bytes = 10;
  EXPECT_EQ(MOJO_RESULT_OUT_OF_RANGE,
            core()->ReadData(
                ch,
                NullUserPointer(),
                MakeUserPointer(&num_bytes),
                MOJO_READ_DATA_FLAG_DISCARD | MOJO_READ_DATA_FLAG_ALL_OR_NONE));

  // Discard two characters.
  num_bytes = 2;
  EXPECT_EQ(MOJO_RESULT_OK,
            core()->ReadData(
                ch,
                NullUserPointer(),
                MakeUserPointer(&num_bytes),
                MOJO_READ_DATA_FLAG_DISCARD | MOJO_READ_DATA_FLAG_ALL_OR_NONE));

  // Read the remaining two characters, in two-phase mode (all-or-none).
  const void* read_ptr = nullptr;
  num_bytes = 2;
  ASSERT_EQ(MOJO_RESULT_OK,
            core()->BeginReadData(ch,
                                  MakeUserPointer(&read_ptr),
                                  MakeUserPointer(&num_bytes),
                                  MOJO_READ_DATA_FLAG_ALL_OR_NONE));
  // Note: Count on still being able to do the contiguous read here.
  ASSERT_EQ(2u, num_bytes);

  // Discarding right now should fail.
  num_bytes = 1;
  EXPECT_EQ(MOJO_RESULT_BUSY,
            core()->ReadData(ch,
                             NullUserPointer(),
                             MakeUserPointer(&num_bytes),
                             MOJO_READ_DATA_FLAG_DISCARD));

  // Actually check our data and end the two-phase read.
  EXPECT_EQ('D', static_cast<const char*>(read_ptr)[0]);
  EXPECT_EQ('E', static_cast<const char*>(read_ptr)[1]);
  EXPECT_EQ(MOJO_RESULT_OK, core()->EndReadData(ch, 2u));

  // Consumer should now be no longer readable.
  hss = kFullMojoHandleSignalsState;
  EXPECT_EQ(
      MOJO_RESULT_DEADLINE_EXCEEDED,
      core()->Wait(ch, MOJO_HANDLE_SIGNAL_READABLE, 0, MakeUserPointer(&hss)));
  EXPECT_EQ(0u, hss.satisfied_signals);
  EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE, hss.satisfiable_signals);

  // TODO(vtl): More.

  // Close the producer.
  EXPECT_EQ(MOJO_RESULT_OK, core()->Close(ph));

  // The consumer should now be never-readable.
  hss = kFullMojoHandleSignalsState;
  EXPECT_EQ(
      MOJO_RESULT_FAILED_PRECONDITION,
      core()->Wait(ch, MOJO_HANDLE_SIGNAL_READABLE, 0, MakeUserPointer(&hss)));
  EXPECT_EQ(0u, hss.satisfied_signals);
  EXPECT_EQ(0u, hss.satisfiable_signals);

  EXPECT_EQ(MOJO_RESULT_OK, core()->Close(ch));
}

// Tests passing data pipe producer and consumer handles.
TEST_F(CoreTest, MessagePipeBasicLocalHandlePassing2) {
  const char kHello[] = "hello";
  const uint32_t kHelloSize = static_cast<uint32_t>(sizeof(kHello));
  const char kWorld[] = "world!!!";
  const uint32_t kWorldSize = static_cast<uint32_t>(sizeof(kWorld));
  char buffer[100];
  const uint32_t kBufferSize = static_cast<uint32_t>(sizeof(buffer));
  uint32_t num_bytes;
  MojoHandle handles[10];
  uint32_t num_handles;
  MojoHandleSignalsState hss;

  MojoHandle h_passing[2];
  EXPECT_EQ(MOJO_RESULT_OK,
            core()->CreateMessagePipe(NullUserPointer(),
                                      MakeUserPointer(&h_passing[0]),
                                      MakeUserPointer(&h_passing[1])));

  MojoHandle ph, ch;
  EXPECT_EQ(MOJO_RESULT_OK,
            core()->CreateDataPipe(
                NullUserPointer(), MakeUserPointer(&ph), MakeUserPointer(&ch)));

  // Send |ch| from |h_passing[0]| to |h_passing[1]|.
  EXPECT_EQ(MOJO_RESULT_OK,
            core()->WriteMessage(h_passing[0],
                                 UserPointer<const void>(kHello),
                                 kHelloSize,
                                 MakeUserPointer(&ch),
                                 1,
                                 MOJO_WRITE_MESSAGE_FLAG_NONE));
  hss = kEmptyMojoHandleSignalsState;
  EXPECT_EQ(MOJO_RESULT_OK,
            core()->Wait(h_passing[1],
                         MOJO_HANDLE_SIGNAL_READABLE,
                         1000000000,
                         MakeUserPointer(&hss)));
  EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE,
            hss.satisfied_signals);
  EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE,
            hss.satisfiable_signals);
  num_bytes = kBufferSize;
  num_handles = arraysize(handles);
  EXPECT_EQ(MOJO_RESULT_OK,
            core()->ReadMessage(h_passing[1],
                                UserPointer<void>(buffer),
                                MakeUserPointer(&num_bytes),
                                MakeUserPointer(handles),
                                MakeUserPointer(&num_handles),
                                MOJO_READ_MESSAGE_FLAG_NONE));
  EXPECT_EQ(kHelloSize, num_bytes);
  EXPECT_STREQ(kHello, buffer);
  EXPECT_EQ(1u, num_handles);
  MojoHandle ch_received = handles[0];
  EXPECT_NE(ch_received, MOJO_HANDLE_INVALID);
  EXPECT_NE(ch_received, h_passing[0]);
  EXPECT_NE(ch_received, h_passing[1]);
  EXPECT_NE(ch_received, ph);

  // Note: We rely on the Mojo system not re-using handle values very often.
  EXPECT_NE(ch_received, ch);

  // |ch| should no longer be valid; check that trying to close it fails. See
  // above note.
  EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT, core()->Close(ch));

  // Write to |ph|. Should receive on |ch_received|.
  num_bytes = kWorldSize;
  EXPECT_EQ(MOJO_RESULT_OK,
            core()->WriteData(ph,
                              UserPointer<const void>(kWorld),
                              MakeUserPointer(&num_bytes),
                              MOJO_WRITE_DATA_FLAG_ALL_OR_NONE));
  hss = kEmptyMojoHandleSignalsState;
  EXPECT_EQ(MOJO_RESULT_OK,
            core()->Wait(ch_received,
                         MOJO_HANDLE_SIGNAL_READABLE,
                         1000000000,
                         MakeUserPointer(&hss)));
  EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE, hss.satisfied_signals);
  EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE, hss.satisfiable_signals);
  num_bytes = kBufferSize;
  EXPECT_EQ(MOJO_RESULT_OK,
            core()->ReadData(ch_received,
                             UserPointer<void>(buffer),
                             MakeUserPointer(&num_bytes),
                             MOJO_READ_MESSAGE_FLAG_NONE));
  EXPECT_EQ(kWorldSize, num_bytes);
  EXPECT_STREQ(kWorld, buffer);

  // Now pass |ph| in the same direction.
  EXPECT_EQ(MOJO_RESULT_OK,
            core()->WriteMessage(h_passing[0],
                                 UserPointer<const void>(kWorld),
                                 kWorldSize,
                                 MakeUserPointer(&ph),
                                 1,
                                 MOJO_WRITE_MESSAGE_FLAG_NONE));
  hss = kEmptyMojoHandleSignalsState;
  EXPECT_EQ(MOJO_RESULT_OK,
            core()->Wait(h_passing[1],
                         MOJO_HANDLE_SIGNAL_READABLE,
                         1000000000,
                         MakeUserPointer(&hss)));
  EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE,
            hss.satisfied_signals);
  EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE,
            hss.satisfiable_signals);
  num_bytes = kBufferSize;
  num_handles = arraysize(handles);
  EXPECT_EQ(MOJO_RESULT_OK,
            core()->ReadMessage(h_passing[1],
                                UserPointer<void>(buffer),
                                MakeUserPointer(&num_bytes),
                                MakeUserPointer(handles),
                                MakeUserPointer(&num_handles),
                                MOJO_READ_MESSAGE_FLAG_NONE));
  EXPECT_EQ(kWorldSize, num_bytes);
  EXPECT_STREQ(kWorld, buffer);
  EXPECT_EQ(1u, num_handles);
  MojoHandle ph_received = handles[0];
  EXPECT_NE(ph_received, MOJO_HANDLE_INVALID);
  EXPECT_NE(ph_received, h_passing[0]);
  EXPECT_NE(ph_received, h_passing[1]);
  EXPECT_NE(ph_received, ch_received);

  // Again, rely on the Mojo system not re-using handle values very often.
  EXPECT_NE(ph_received, ph);

  // |ph| should no longer be valid; check that trying to close it fails. See
  // above note.
  EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT, core()->Close(ph));

  // Write to |ph_received|. Should receive on |ch_received|.
  num_bytes = kHelloSize;
  EXPECT_EQ(MOJO_RESULT_OK,
            core()->WriteData(ph_received,
                              UserPointer<const void>(kHello),
                              MakeUserPointer(&num_bytes),
                              MOJO_WRITE_DATA_FLAG_ALL_OR_NONE));
  hss = kEmptyMojoHandleSignalsState;
  EXPECT_EQ(MOJO_RESULT_OK,
            core()->Wait(ch_received,
                         MOJO_HANDLE_SIGNAL_READABLE,
                         1000000000,
                         MakeUserPointer(&hss)));
  EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE, hss.satisfied_signals);
  EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE, hss.satisfiable_signals);
  num_bytes = kBufferSize;
  EXPECT_EQ(MOJO_RESULT_OK,
            core()->ReadData(ch_received,
                             UserPointer<void>(buffer),
                             MakeUserPointer(&num_bytes),
                             MOJO_READ_MESSAGE_FLAG_NONE));
  EXPECT_EQ(kHelloSize, num_bytes);
  EXPECT_STREQ(kHello, buffer);

  ph = ph_received;
  ph_received = MOJO_HANDLE_INVALID;
  ch = ch_received;
  ch_received = MOJO_HANDLE_INVALID;

  // Make sure that |ph| can't be sent if it's in a two-phase write.
  void* write_ptr = nullptr;
  num_bytes = 0;
  ASSERT_EQ(MOJO_RESULT_OK,
            core()->BeginWriteData(ph,
                                   MakeUserPointer(&write_ptr),
                                   MakeUserPointer(&num_bytes),
                                   MOJO_WRITE_DATA_FLAG_NONE));
  ASSERT_GE(num_bytes, 1u);
  EXPECT_EQ(MOJO_RESULT_BUSY,
            core()->WriteMessage(h_passing[0],
                                 UserPointer<const void>(kHello),
                                 kHelloSize,
                                 MakeUserPointer(&ph),
                                 1,
                                 MOJO_WRITE_MESSAGE_FLAG_NONE));

  // But |ch| can, even if |ph| is in a two-phase write.
  EXPECT_EQ(MOJO_RESULT_OK,
            core()->WriteMessage(h_passing[0],
                                 UserPointer<const void>(kHello),
                                 kHelloSize,
                                 MakeUserPointer(&ch),
                                 1,
                                 MOJO_WRITE_MESSAGE_FLAG_NONE));
  ch = MOJO_HANDLE_INVALID;
  EXPECT_EQ(MOJO_RESULT_OK,
            core()->Wait(h_passing[1],
                         MOJO_HANDLE_SIGNAL_READABLE,
                         1000000000,
                         NullUserPointer()));
  num_bytes = kBufferSize;
  num_handles = arraysize(handles);
  EXPECT_EQ(MOJO_RESULT_OK,
            core()->ReadMessage(h_passing[1],
                                UserPointer<void>(buffer),
                                MakeUserPointer(&num_bytes),
                                MakeUserPointer(handles),
                                MakeUserPointer(&num_handles),
                                MOJO_READ_MESSAGE_FLAG_NONE));
  EXPECT_EQ(kHelloSize, num_bytes);
  EXPECT_STREQ(kHello, buffer);
  EXPECT_EQ(1u, num_handles);
  ch = handles[0];
  EXPECT_NE(ch, MOJO_HANDLE_INVALID);

  // Complete the two-phase write.
  static_cast<char*>(write_ptr)[0] = 'x';
  EXPECT_EQ(MOJO_RESULT_OK, core()->EndWriteData(ph, 1));

  // Wait for |ch| to be readable.
  hss = kEmptyMojoHandleSignalsState;
  EXPECT_EQ(
      MOJO_RESULT_OK,
      core()->Wait(
          ch, MOJO_HANDLE_SIGNAL_READABLE, 1000000000, MakeUserPointer(&hss)));
  EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE, hss.satisfied_signals);
  EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE, hss.satisfiable_signals);

  // Make sure that |ch| can't be sent if it's in a two-phase read.
  const void* read_ptr = nullptr;
  num_bytes = 1;
  ASSERT_EQ(MOJO_RESULT_OK,
            core()->BeginReadData(ch,
                                  MakeUserPointer(&read_ptr),
                                  MakeUserPointer(&num_bytes),
                                  MOJO_READ_DATA_FLAG_ALL_OR_NONE));
  EXPECT_EQ(MOJO_RESULT_BUSY,
            core()->WriteMessage(h_passing[0],
                                 UserPointer<const void>(kHello),
                                 kHelloSize,
                                 MakeUserPointer(&ch),
                                 1,
                                 MOJO_WRITE_MESSAGE_FLAG_NONE));

  // But |ph| can, even if |ch| is in a two-phase read.
  EXPECT_EQ(MOJO_RESULT_OK,
            core()->WriteMessage(h_passing[0],
                                 UserPointer<const void>(kWorld),
                                 kWorldSize,
                                 MakeUserPointer(&ph),
                                 1,
                                 MOJO_WRITE_MESSAGE_FLAG_NONE));
  ph = MOJO_HANDLE_INVALID;
  hss = kEmptyMojoHandleSignalsState;
  EXPECT_EQ(MOJO_RESULT_OK,
            core()->Wait(h_passing[1],
                         MOJO_HANDLE_SIGNAL_READABLE,
                         1000000000,
                         MakeUserPointer(&hss)));
  EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE,
            hss.satisfied_signals);
  EXPECT_EQ(MOJO_HANDLE_SIGNAL_READABLE | MOJO_HANDLE_SIGNAL_WRITABLE,
            hss.satisfiable_signals);
  num_bytes = kBufferSize;
  num_handles = arraysize(handles);
  EXPECT_EQ(MOJO_RESULT_OK,
            core()->ReadMessage(h_passing[1],
                                UserPointer<void>(buffer),
                                MakeUserPointer(&num_bytes),
                                MakeUserPointer(handles),
                                MakeUserPointer(&num_handles),
                                MOJO_READ_MESSAGE_FLAG_NONE));
  EXPECT_EQ(kWorldSize, num_bytes);
  EXPECT_STREQ(kWorld, buffer);
  EXPECT_EQ(1u, num_handles);
  ph = handles[0];
  EXPECT_NE(ph, MOJO_HANDLE_INVALID);

  // Complete the two-phase read.
  EXPECT_EQ('x', static_cast<const char*>(read_ptr)[0]);
  EXPECT_EQ(MOJO_RESULT_OK, core()->EndReadData(ch, 1));

  EXPECT_EQ(MOJO_RESULT_OK, core()->Close(h_passing[0]));
  EXPECT_EQ(MOJO_RESULT_OK, core()->Close(h_passing[1]));
  EXPECT_EQ(MOJO_RESULT_OK, core()->Close(ph));
  EXPECT_EQ(MOJO_RESULT_OK, core()->Close(ch));
}

// TODO(vtl): Test |DuplicateBufferHandle()| and |MapBuffer()|.

}  // namespace
}  // namespace system
}  // namespace mojo