#include "TestAsyncReturns.h"

#include "IPDLUnitTests.h"  // fail etc.

#include "mozilla/AbstractThread.h"
#include "mozilla/Unused.h"

namespace mozilla {
namespace _ipdltest {

static uint32_t sMagic1 = 0x105b59fb;
static uint32_t sMagic2 = 0x09b6f5e3;

//-----------------------------------------------------------------------------
// parent

TestAsyncReturnsParent::TestAsyncReturnsParent() {
  MOZ_COUNT_CTOR(TestAsyncReturnsParent);
}

TestAsyncReturnsParent::~TestAsyncReturnsParent() {
  MOZ_COUNT_DTOR(TestAsyncReturnsParent);
}

void TestAsyncReturnsParent::Main() {
  SendNoReturn()->Then(
      MessageLoop::current()->SerialEventTarget(), __func__,
      [](bool unused) { fail("resolve handler should not be called"); },
      [](ResponseRejectReason&& aReason) {
        // MozPromise asserts in debug build if the
        // handler is not called
        if (aReason != ResponseRejectReason::ChannelClosed) {
          fail("reject with wrong reason");
        }
        passed("reject handler called on channel close");
      });
  SendPing()->Then(
      MessageLoop::current()->SerialEventTarget(), __func__,
      [this](bool one) {
        if (one) {
          passed("take one argument");
        } else {
          fail("get one argument but has wrong value");
        }

        // Also try with the callback-based API.
        SendPing(
            [this](bool one) {
              if (one) {
                passed("take one argument");
              } else {
                fail("get one argument but has wrong value");
              }
              Close();
            },
            [](ResponseRejectReason&& aReason) { fail("sending Ping"); });
      },
      [](ResponseRejectReason&& aReason) { fail("sending Ping"); });
}

mozilla::ipc::IPCResult TestAsyncReturnsParent::RecvPong(
    PongResolver&& aResolve) {
  aResolve(std::tuple<const uint32_t&, const uint32_t&>(sMagic1, sMagic2));
  return IPC_OK();
}

//-----------------------------------------------------------------------------
// child

TestAsyncReturnsChild::TestAsyncReturnsChild() {
  MOZ_COUNT_CTOR(TestAsyncReturnsChild);
}

TestAsyncReturnsChild::~TestAsyncReturnsChild() {
  MOZ_COUNT_DTOR(TestAsyncReturnsChild);
}

mozilla::ipc::IPCResult TestAsyncReturnsChild::RecvNoReturn(
    NoReturnResolver&& aResolve) {
  // Not resolving the promise intentionally
  return IPC_OK();
}

mozilla::ipc::IPCResult TestAsyncReturnsChild::RecvPing(
    PingResolver&& aResolve) {
  SendPong()->Then(
      MessageLoop::current()->SerialEventTarget(), __func__,
      [aResolve](const std::tuple<uint32_t, uint32_t>& aParam) {
        if (std::get<0>(aParam) == sMagic1 && std::get<1>(aParam) == sMagic2) {
          passed("take two arguments");
        } else {
          fail("get two argument but has wrong value");
        }
        aResolve(true);
      },
      [](ResponseRejectReason&& aReason) { fail("sending Pong"); });
  return IPC_OK();
}

}  // namespace _ipdltest
}  // namespace mozilla
