// Copyright 2017 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/public/cpp/bindings/callback_helpers.h"

#include <memory>
#include <string>
#include <utility>

#include "base/bind.h"
#include "base/callback.h"
#include "base/callback_helpers.h"
#include "base/memory/ptr_util.h"
#include "testing/gtest/include/gtest/gtest.h"

namespace mojo {

namespace {

void SetBool(bool* var, bool val) {
  *var = val;
}

void SetBoolFromRawPtr(bool* var, bool* val) {
  *var = *val;
}

void SetIntegers(int* a_var, int* b_var, int a_val, int b_val) {
  *a_var = a_val;
  *b_var = b_val;
}

void SetIntegerFromUniquePtr(int* var, std::unique_ptr<int> val) {
  *var = *val;
}

void SetString(std::string* var, const std::string val) {
  *var = val;
}

void CallClosure(base::OnceClosure cl) {
  std::move(cl).Run();
}

}  // namespace

TEST(CallbackWithDeleteTest, SetIntegers_Run) {
  int a = 0;
  int b = 0;
  auto cb =
      WrapCallbackWithDropHandler(base::BindOnce(&SetIntegers, &a, &b),
                                  base::BindOnce(&SetIntegers, &a, &b, 3, 4));
  std::move(cb).Run(1, 2);
  EXPECT_EQ(a, 1);
  EXPECT_EQ(b, 2);
}

TEST(CallbackWithDeleteTest, SetIntegers_Destruction) {
  int a = 0;
  int b = 0;
  {
    auto cb =
        WrapCallbackWithDropHandler(base::BindOnce(&SetIntegers, &a, &b),
                                    base::BindOnce(&SetIntegers, &a, &b, 3, 4));
  }
  EXPECT_EQ(a, 3);
  EXPECT_EQ(b, 4);
}

TEST(CallbackWithDefaultTest, CallClosure_Run) {
  int a = 0;
  int b = 0;
  auto cb = WrapCallbackWithDefaultInvokeIfNotRun(
      base::BindOnce(&CallClosure), base::BindOnce(&SetIntegers, &a, &b, 3, 4));
  std::move(cb).Run(base::BindOnce(&SetIntegers, &a, &b, 1, 2));
  EXPECT_EQ(a, 1);
  EXPECT_EQ(b, 2);
}

TEST(CallbackWithDefaultTest, CallClosure_Destruction) {
  int a = 0;
  int b = 0;
  {
    auto cb = WrapCallbackWithDefaultInvokeIfNotRun(
        base::BindOnce(&CallClosure),
        base::BindOnce(&SetIntegers, &a, &b, 3, 4));
  }
  EXPECT_EQ(a, 3);
  EXPECT_EQ(b, 4);
}

TEST(CallbackWithDefaultTest, Closure_Run) {
  bool a = false;
  auto cb =
      WrapCallbackWithDefaultInvokeIfNotRun(base::BindOnce(&SetBool, &a, true));
  std::move(cb).Run();
  EXPECT_TRUE(a);
}

TEST(CallbackWithDefaultTest, Closure_Destruction) {
  bool a = false;
  {
    auto cb = WrapCallbackWithDefaultInvokeIfNotRun(
        base::BindOnce(&SetBool, &a, true));
  }
  EXPECT_TRUE(a);
}

TEST(CallbackWithDefaultTest, SetBool_Run) {
  bool a = false;
  auto cb =
      WrapCallbackWithDefaultInvokeIfNotRun(base::BindOnce(&SetBool, &a), true);
  std::move(cb).Run(true);
  EXPECT_TRUE(a);
}

TEST(CallbackWithDefaultTest, SetBoolFromRawPtr_Run) {
  bool a = false;
  bool* b = new bool(false);
  bool c = true;
  auto cb = WrapCallbackWithDefaultInvokeIfNotRun(
      base::BindOnce(&SetBoolFromRawPtr, &a), base::Owned(b));
  std::move(cb).Run(&c);
  EXPECT_TRUE(a);
}

TEST(CallbackWithDefaultTest, SetBoolFromRawPtr_Destruction) {
  bool a = false;
  bool* b = new bool(true);
  {
    auto cb = WrapCallbackWithDefaultInvokeIfNotRun(
        base::BindOnce(&SetBoolFromRawPtr, &a), base::Owned(b));
  }
  EXPECT_TRUE(a);
}

TEST(CallbackWithDefaultTest, SetBool_Destruction) {
  bool a = false;
  {
    auto cb = WrapCallbackWithDefaultInvokeIfNotRun(
        base::BindOnce(&SetBool, &a), true);
  }
  EXPECT_TRUE(a);
}

TEST(CallbackWithDefaultTest, SetIntegers_Run) {
  int a = 0;
  int b = 0;
  auto cb = WrapCallbackWithDefaultInvokeIfNotRun(
      base::BindOnce(&SetIntegers, &a, &b), 3, 4);
  std::move(cb).Run(1, 2);
  EXPECT_EQ(a, 1);
  EXPECT_EQ(b, 2);
}

TEST(CallbackWithDefaultTest, SetIntegers_Destruction) {
  int a = 0;
  int b = 0;
  {
    auto cb = WrapCallbackWithDefaultInvokeIfNotRun(
        base::BindOnce(&SetIntegers, &a, &b), 3, 4);
  }
  EXPECT_EQ(a, 3);
  EXPECT_EQ(b, 4);
}

TEST(CallbackWithDefaultTest, SetIntegerFromUniquePtr_Run) {
  int a = 0;
  auto cb = WrapCallbackWithDefaultInvokeIfNotRun(
      base::BindOnce(&SetIntegerFromUniquePtr, &a), std::make_unique<int>(1));
  std::move(cb).Run(std::make_unique<int>(2));
  EXPECT_EQ(a, 2);
}

TEST(CallbackWithDefaultTest, SetIntegerFromUniquePtr_Destruction) {
  int a = 0;
  {
    auto cb = WrapCallbackWithDefaultInvokeIfNotRun(
        base::BindOnce(&SetIntegerFromUniquePtr, &a), std::make_unique<int>(1));
  }
  EXPECT_EQ(a, 1);
}

TEST(CallbackWithDefaultTest, SetString_Run) {
  std::string a;
  auto cb = WrapCallbackWithDefaultInvokeIfNotRun(
      base::BindOnce(&SetString, &a), "hello");
  std::move(cb).Run("world");
  EXPECT_EQ(a, "world");
}

TEST(CallbackWithDefaultTest, SetString_Destruction) {
  std::string a;
  {
    auto cb = WrapCallbackWithDefaultInvokeIfNotRun(
        base::BindOnce(&SetString, &a), "hello");
  }
  EXPECT_EQ(a, "hello");
}

}  // namespace mojo
