root/mojo/public/cpp/system/tests/core_unittest.cc

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. TEST
  2. TEST
  3. TEST

// 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.

// This file tests the C++ Mojo system core wrappers.
// TODO(vtl): Maybe rename "CoreCppTest" -> "CoreTest" if/when this gets
// compiled into a different binary from the C API tests.

#include "mojo/public/cpp/system/core.h"

#include <map>

#include "mojo/public/cpp/system/macros.h"
#include "testing/gtest/include/gtest/gtest.h"

namespace mojo {
namespace {

TEST(CoreCppTest, GetTimeTicksNow) {
  const MojoTimeTicks start = GetTimeTicksNow();
  EXPECT_NE(static_cast<MojoTimeTicks>(0), start)
      << "GetTimeTicksNow should return nonzero value";
}

TEST(CoreCppTest, Basic) {
  // Basic |Handle| implementation:
  {
    EXPECT_EQ(MOJO_HANDLE_INVALID, kInvalidHandleValue);

    Handle h0;
    EXPECT_EQ(kInvalidHandleValue, h0.value());
    EXPECT_EQ(kInvalidHandleValue, *h0.mutable_value());
    EXPECT_FALSE(h0.is_valid());

    Handle h1(static_cast<MojoHandle>(123));
    EXPECT_EQ(static_cast<MojoHandle>(123), h1.value());
    EXPECT_EQ(static_cast<MojoHandle>(123), *h1.mutable_value());
    EXPECT_TRUE(h1.is_valid());
    *h1.mutable_value() = static_cast<MojoHandle>(456);
    EXPECT_EQ(static_cast<MojoHandle>(456), h1.value());
    EXPECT_TRUE(h1.is_valid());

    h1.swap(h0);
    EXPECT_EQ(static_cast<MojoHandle>(456), h0.value());
    EXPECT_TRUE(h0.is_valid());
    EXPECT_FALSE(h1.is_valid());

    h1.set_value(static_cast<MojoHandle>(789));
    h0.swap(h1);
    EXPECT_EQ(static_cast<MojoHandle>(789), h0.value());
    EXPECT_TRUE(h0.is_valid());
    EXPECT_EQ(static_cast<MojoHandle>(456), h1.value());
    EXPECT_TRUE(h1.is_valid());

    // Make sure copy constructor works.
    Handle h2(h0);
    EXPECT_EQ(static_cast<MojoHandle>(789), h2.value());
    // And assignment.
    h2 = h1;
    EXPECT_EQ(static_cast<MojoHandle>(456), h2.value());

    // Make sure that we can put |Handle|s into |std::map|s.
    h0 = Handle(static_cast<MojoHandle>(987));
    h1 = Handle(static_cast<MojoHandle>(654));
    h2 = Handle(static_cast<MojoHandle>(321));
    Handle h3;
    std::map<Handle, int> handle_to_int;
    handle_to_int[h0] = 0;
    handle_to_int[h1] = 1;
    handle_to_int[h2] = 2;
    handle_to_int[h3] = 3;

    EXPECT_EQ(4u, handle_to_int.size());
    EXPECT_FALSE(handle_to_int.find(h0) == handle_to_int.end());
    EXPECT_EQ(0, handle_to_int[h0]);
    EXPECT_FALSE(handle_to_int.find(h1) == handle_to_int.end());
    EXPECT_EQ(1, handle_to_int[h1]);
    EXPECT_FALSE(handle_to_int.find(h2) == handle_to_int.end());
    EXPECT_EQ(2, handle_to_int[h2]);
    EXPECT_FALSE(handle_to_int.find(h3) == handle_to_int.end());
    EXPECT_EQ(3, handle_to_int[h3]);
    EXPECT_TRUE(handle_to_int.find(Handle(static_cast<MojoHandle>(13579))) ==
                    handle_to_int.end());

    // TODO(vtl): With C++11, support |std::unordered_map|s, etc. (Or figure out
    // how to support the variations of |hash_map|.)
  }

  // |Handle|/|ScopedHandle| functions:
  {
    ScopedHandle h;

    EXPECT_EQ(kInvalidHandleValue, h.get().value());

    // This should be a no-op.
    Close(h.Pass());

    // It should still be invalid.
    EXPECT_EQ(kInvalidHandleValue, h.get().value());

    EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT,
              Wait(h.get(), MOJO_WAIT_FLAG_EVERYTHING, 1000000));

    std::vector<Handle> wh;
    wh.push_back(h.get());
    std::vector<MojoWaitFlags> wf;
    wf.push_back(MOJO_WAIT_FLAG_EVERYTHING);
    EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT,
              WaitMany(wh, wf, MOJO_DEADLINE_INDEFINITE));
  }

  // |MakeScopedHandle| (just compilation tests):
  {
    EXPECT_FALSE(MakeScopedHandle(Handle()).is_valid());
    EXPECT_FALSE(MakeScopedHandle(MessagePipeHandle()).is_valid());
    EXPECT_FALSE(MakeScopedHandle(DataPipeProducerHandle()).is_valid());
    EXPECT_FALSE(MakeScopedHandle(DataPipeConsumerHandle()).is_valid());
    EXPECT_FALSE(MakeScopedHandle(SharedBufferHandle()).is_valid());
  }

  // |MessagePipeHandle|/|ScopedMessagePipeHandle| functions:
  {
    MessagePipeHandle h_invalid;
    EXPECT_FALSE(h_invalid.is_valid());
    EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT,
              WriteMessageRaw(h_invalid,
                              NULL, 0,
                              NULL, 0,
                              MOJO_WRITE_MESSAGE_FLAG_NONE));
    char buffer[10] = { 0 };
    EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT,
              WriteMessageRaw(h_invalid,
                              buffer, sizeof(buffer),
                              NULL, 0,
                              MOJO_WRITE_MESSAGE_FLAG_NONE));
    EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT,
              ReadMessageRaw(h_invalid,
                             NULL, NULL,
                             NULL, NULL,
                             MOJO_READ_MESSAGE_FLAG_NONE));
    uint32_t buffer_size = static_cast<uint32_t>(sizeof(buffer));
    EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT,
              ReadMessageRaw(h_invalid,
                             buffer, &buffer_size,
                             NULL, NULL,
                             MOJO_READ_MESSAGE_FLAG_NONE));

    // Basic tests of waiting and closing.
    MojoHandle hv0 = kInvalidHandleValue;
    {
      ScopedMessagePipeHandle h0;
      ScopedMessagePipeHandle h1;
      EXPECT_FALSE(h0.get().is_valid());
      EXPECT_FALSE(h1.get().is_valid());

      CreateMessagePipe(&h0, &h1);
      EXPECT_TRUE(h0.get().is_valid());
      EXPECT_TRUE(h1.get().is_valid());
      EXPECT_NE(h0.get().value(), h1.get().value());
      // Save the handle values, so we can check that things got closed
      // correctly.
      hv0 = h0.get().value();
      MojoHandle hv1 = h1.get().value();

      EXPECT_EQ(MOJO_RESULT_DEADLINE_EXCEEDED,
                Wait(h0.get(), MOJO_WAIT_FLAG_READABLE, 0));
      std::vector<Handle> wh;
      wh.push_back(h0.get());
      wh.push_back(h1.get());
      std::vector<MojoWaitFlags> wf;
      wf.push_back(MOJO_WAIT_FLAG_READABLE);
      wf.push_back(MOJO_WAIT_FLAG_WRITABLE);
      EXPECT_EQ(1, WaitMany(wh, wf, 1000));

      // Test closing |h1| explicitly.
      Close(h1.Pass());
      EXPECT_FALSE(h1.get().is_valid());

      // Make sure |h1| is closed.
      EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT,
                MojoWait(hv1, MOJO_WAIT_FLAG_EVERYTHING,
                         MOJO_DEADLINE_INDEFINITE));

      EXPECT_EQ(MOJO_RESULT_FAILED_PRECONDITION,
                Wait(h0.get(), MOJO_WAIT_FLAG_READABLE,
                     MOJO_DEADLINE_INDEFINITE));
    }
    // |hv0| should have been closed when |h0| went out of scope, so this close
    // should fail.
    EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT, MojoClose(hv0));

    // Actually test writing/reading messages.
    {
      ScopedMessagePipeHandle h0;
      ScopedMessagePipeHandle h1;
      CreateMessagePipe(&h0, &h1);

      const char kHello[] = "hello";
      const uint32_t kHelloSize = static_cast<uint32_t>(sizeof(kHello));
      EXPECT_EQ(MOJO_RESULT_OK,
                WriteMessageRaw(h0.get(),
                                kHello, kHelloSize,
                                NULL, 0,
                                MOJO_WRITE_MESSAGE_FLAG_NONE));
      EXPECT_EQ(MOJO_RESULT_OK,
                Wait(h1.get(), MOJO_WAIT_FLAG_READABLE,
                     MOJO_DEADLINE_INDEFINITE));
      char buffer[10] = { 0 };
      uint32_t buffer_size = static_cast<uint32_t>(sizeof(buffer));
      EXPECT_EQ(MOJO_RESULT_OK,
                ReadMessageRaw(h1.get(),
                               buffer, &buffer_size,
                               NULL, NULL,
                               MOJO_READ_MESSAGE_FLAG_NONE));
      EXPECT_EQ(kHelloSize, buffer_size);
      EXPECT_STREQ(kHello, buffer);

      // Send a handle over the previously-establish message pipe. Use the
      // |MessagePipe| wrapper (to test it), which automatically creates a
      // message pipe.
      MessagePipe mp;

      // Write a message to |mp.handle0|, before we send |mp.handle1|.
      const char kWorld[] = "world!";
      const uint32_t kWorldSize = static_cast<uint32_t>(sizeof(kWorld));
      EXPECT_EQ(MOJO_RESULT_OK,
                WriteMessageRaw(mp.handle0.get(),
                                kWorld, kWorldSize,
                                NULL, 0,
                                MOJO_WRITE_MESSAGE_FLAG_NONE));

      // Send |mp.handle1| over |h1| to |h0|.
      MojoHandle handles[5];
      handles[0] = mp.handle1.release().value();
      EXPECT_NE(kInvalidHandleValue, handles[0]);
      EXPECT_FALSE(mp.handle1.get().is_valid());
      uint32_t handles_count = 1;
      EXPECT_EQ(MOJO_RESULT_OK,
                WriteMessageRaw(h1.get(),
                                kHello, kHelloSize,
                                handles, handles_count,
                                MOJO_WRITE_MESSAGE_FLAG_NONE));
      // |handles[0]| should actually be invalid now.
      EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT, MojoClose(handles[0]));

      // Read "hello" and the sent handle.
      EXPECT_EQ(MOJO_RESULT_OK,
                Wait(h0.get(), MOJO_WAIT_FLAG_READABLE,
                     MOJO_DEADLINE_INDEFINITE));
      memset(buffer, 0, sizeof(buffer));
      buffer_size = static_cast<uint32_t>(sizeof(buffer));
      for (size_t i = 0; i < MOJO_ARRAYSIZE(handles); i++)
        handles[i] = kInvalidHandleValue;
      handles_count = static_cast<uint32_t>(MOJO_ARRAYSIZE(handles));
      EXPECT_EQ(MOJO_RESULT_OK,
                ReadMessageRaw(h0.get(),
                               buffer, &buffer_size,
                               handles, &handles_count,
                               MOJO_READ_MESSAGE_FLAG_NONE));
      EXPECT_EQ(kHelloSize, buffer_size);
      EXPECT_STREQ(kHello, buffer);
      EXPECT_EQ(1u, handles_count);
      EXPECT_NE(kInvalidHandleValue, handles[0]);

      // Read from the sent/received handle.
      mp.handle1.reset(MessagePipeHandle(handles[0]));
      // Save |handles[0]| to check that it gets properly closed.
      hv0 = handles[0];
      EXPECT_EQ(MOJO_RESULT_OK,
                Wait(mp.handle1.get(), MOJO_WAIT_FLAG_READABLE,
                     MOJO_DEADLINE_INDEFINITE));
      memset(buffer, 0, sizeof(buffer));
      buffer_size = static_cast<uint32_t>(sizeof(buffer));
      for (size_t i = 0; i < MOJO_ARRAYSIZE(handles); i++)
        handles[i] = kInvalidHandleValue;
      handles_count = static_cast<uint32_t>(MOJO_ARRAYSIZE(handles));
      EXPECT_EQ(MOJO_RESULT_OK,
                ReadMessageRaw(mp.handle1.get(),
                               buffer, &buffer_size,
                               handles, &handles_count,
                               MOJO_READ_MESSAGE_FLAG_NONE));
      EXPECT_EQ(kWorldSize, buffer_size);
      EXPECT_STREQ(kWorld, buffer);
      EXPECT_EQ(0u, handles_count);
    }
    EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT, MojoClose(hv0));
  }

  // TODO(vtl): Test |CloseRaw()|.
  // TODO(vtl): Test |reset()| more thoroughly?
}

TEST(CoreCppTest, TearDownWithMessagesEnqueued) {
  // Tear down a message pipe which still has a message enqueued, with the
  // message also having a valid message pipe handle.
  {
    ScopedMessagePipeHandle h0;
    ScopedMessagePipeHandle h1;
    CreateMessagePipe(&h0, &h1);

    // Send a handle over the previously-establish message pipe.
    ScopedMessagePipeHandle h2;
    ScopedMessagePipeHandle h3;
    CreateMessagePipe(&h2, &h3);

    // Write a message to |h2|, before we send |h3|.
    const char kWorld[] = "world!";
    const uint32_t kWorldSize = static_cast<uint32_t>(sizeof(kWorld));
    EXPECT_EQ(MOJO_RESULT_OK,
              WriteMessageRaw(h2.get(),
                              kWorld, kWorldSize,
                              NULL, 0,
                              MOJO_WRITE_MESSAGE_FLAG_NONE));
    // And also a message to |h3|.
    EXPECT_EQ(MOJO_RESULT_OK,
              WriteMessageRaw(h3.get(),
                              kWorld, kWorldSize,
                              NULL, 0,
                              MOJO_WRITE_MESSAGE_FLAG_NONE));

    // Send |h3| over |h1| to |h0|.
    const char kHello[] = "hello";
    const uint32_t kHelloSize = static_cast<uint32_t>(sizeof(kHello));
    MojoHandle h3_value;
    h3_value = h3.release().value();
    EXPECT_NE(kInvalidHandleValue, h3_value);
    EXPECT_FALSE(h3.get().is_valid());
    EXPECT_EQ(MOJO_RESULT_OK,
              WriteMessageRaw(h1.get(),
                              kHello, kHelloSize,
                              &h3_value, 1,
                              MOJO_WRITE_MESSAGE_FLAG_NONE));
    // |h3_value| should actually be invalid now.
    EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT, MojoClose(h3_value));

    EXPECT_EQ(MOJO_RESULT_OK, MojoClose(h0.release().value()));
    EXPECT_EQ(MOJO_RESULT_OK, MojoClose(h1.release().value()));
    EXPECT_EQ(MOJO_RESULT_OK, MojoClose(h2.release().value()));
  }

  // Do this in a different order: make the enqueued message pipe handle only
  // half-alive.
  {
    ScopedMessagePipeHandle h0;
    ScopedMessagePipeHandle h1;
    CreateMessagePipe(&h0, &h1);

    // Send a handle over the previously-establish message pipe.
    ScopedMessagePipeHandle h2;
    ScopedMessagePipeHandle h3;
    CreateMessagePipe(&h2, &h3);

    // Write a message to |h2|, before we send |h3|.
    const char kWorld[] = "world!";
    const uint32_t kWorldSize = static_cast<uint32_t>(sizeof(kWorld));
    EXPECT_EQ(MOJO_RESULT_OK,
              WriteMessageRaw(h2.get(),
                              kWorld, kWorldSize,
                              NULL, 0,
                              MOJO_WRITE_MESSAGE_FLAG_NONE));
    // And also a message to |h3|.
    EXPECT_EQ(MOJO_RESULT_OK,
              WriteMessageRaw(h3.get(),
                              kWorld, kWorldSize,
                              NULL, 0,
                              MOJO_WRITE_MESSAGE_FLAG_NONE));

    // Send |h3| over |h1| to |h0|.
    const char kHello[] = "hello";
    const uint32_t kHelloSize = static_cast<uint32_t>(sizeof(kHello));
    MojoHandle h3_value;
    h3_value = h3.release().value();
    EXPECT_NE(kInvalidHandleValue, h3_value);
    EXPECT_FALSE(h3.get().is_valid());
    EXPECT_EQ(MOJO_RESULT_OK,
              WriteMessageRaw(h1.get(),
                              kHello, kHelloSize,
                              &h3_value, 1,
                              MOJO_WRITE_MESSAGE_FLAG_NONE));
    // |h3_value| should actually be invalid now.
    EXPECT_EQ(MOJO_RESULT_INVALID_ARGUMENT, MojoClose(h3_value));

    EXPECT_EQ(MOJO_RESULT_OK, MojoClose(h2.release().value()));
    EXPECT_EQ(MOJO_RESULT_OK, MojoClose(h0.release().value()));
    EXPECT_EQ(MOJO_RESULT_OK, MojoClose(h1.release().value()));
  }
}

// TODO(vtl): Write data pipe tests.

}  // namespace
}  // namespace mojo

/* [<][>][^][v][top][bottom][index][help] */