// Copyright 2009 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// This test is a simple sanity check to make sure gmock is able to build/link
// correctly.  It just instantiates a mock object and runs through a couple of
// the basic mock features.

#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"

// Gmock matchers and actions that we use below.
using testing::AnyOf;
using testing::Eq;
using testing::Return;
using testing::SetArgPointee;
using testing::WithArg;
using testing::_;

namespace {

// Simple class that we can mock out the behavior for.  Everything is virtual
// for easy mocking.
class SampleClass {
 public:
  SampleClass() = default;
  virtual ~SampleClass() = default;

  virtual int ReturnSomething() {
    return -1;
  }

  virtual void ReturnNothingConstly() const {
  }

  virtual void OutputParam(int* a) {
  }

  virtual int ReturnSecond(int a, int b) {
    return b;
  }
};

// Declare a mock for the class.
class MockSampleClass : public SampleClass {
 public:
  MOCK_METHOD(int, ReturnSomething, ());
  MOCK_METHOD(void, ReturnNothingConstly, (), (const));
  MOCK_METHOD(void, OutputParam, (int* a));
  MOCK_METHOD(int, ReturnSecond, (int a, int b));
};

// Create a couple of custom actions.  Custom actions can be used for adding
// more complex behavior into your mock...though if you start needing these, ask
// if you're asking your mock to do too much.
ACTION(ReturnVal) {
  // Return the first argument received.
  return arg0;
}
ACTION(ReturnSecond) {
  // Returns the second argument.  This basically implemetns ReturnSecond.
  return arg1;
}

TEST(GmockTest, SimpleMatchAndActions) {
  // Basic test of some simple gmock matchers, actions, and cardinality
  // expectations.
  MockSampleClass mock;

  EXPECT_CALL(mock, ReturnSomething())
      .WillOnce(Return(1))
      .WillOnce(Return(2))
      .WillOnce(Return(3));
  EXPECT_EQ(1, mock.ReturnSomething());
  EXPECT_EQ(2, mock.ReturnSomething());
  EXPECT_EQ(3, mock.ReturnSomething());

  EXPECT_CALL(mock, ReturnNothingConstly()).Times(2);
  mock.ReturnNothingConstly();
  mock.ReturnNothingConstly();
}

TEST(GmockTest, AssignArgument) {
  // Capture an argument for examination.
  MockSampleClass mock;

  EXPECT_CALL(mock, OutputParam(_)).WillRepeatedly(SetArgPointee<0>(5));

  int arg = 0;
  mock.OutputParam(&arg);
  EXPECT_EQ(5, arg);
}

TEST(GmockTest, SideEffects) {
  // Capture an argument for examination.
  MockSampleClass mock;

  EXPECT_CALL(mock, OutputParam(_)).WillRepeatedly(SetArgPointee<0>(5));

  int arg = 0;
  mock.OutputParam(&arg);
  EXPECT_EQ(5, arg);
}

TEST(GmockTest, CustomAction_ReturnSecond) {
  // Test a mock of the ReturnSecond behavior using an action that provides an
  // alternate implementation of the function.  Danger here though, this is
  // starting to add too much behavior of the mock, which means the mock
  // implementation might start to have bugs itself.
  MockSampleClass mock;

  EXPECT_CALL(mock, ReturnSecond(_, AnyOf(Eq(4), Eq(5))))
      .WillRepeatedly(ReturnSecond());
  EXPECT_EQ(4, mock.ReturnSecond(-1, 4));
  EXPECT_EQ(5, mock.ReturnSecond(0, 5));
  EXPECT_EQ(4, mock.ReturnSecond(0xdeadbeef, 4));
  EXPECT_EQ(4, mock.ReturnSecond(112358, 4));
  EXPECT_EQ(5, mock.ReturnSecond(1337, 5));
}

TEST(GmockTest, CustomAction_ReturnVal) {
  // Alternate implemention of ReturnSecond using a more general custom action,
  // and a WithArg adapter to bridge the interfaces.
  MockSampleClass mock;

  EXPECT_CALL(mock, ReturnSecond(_, AnyOf(Eq(4), Eq(5))))
      .WillRepeatedly(WithArg<1>(ReturnVal()));
  EXPECT_EQ(4, mock.ReturnSecond(-1, 4));
  EXPECT_EQ(5, mock.ReturnSecond(0, 5));
  EXPECT_EQ(4, mock.ReturnSecond(0xdeadbeef, 4));
  EXPECT_EQ(4, mock.ReturnSecond(112358, 4));
  EXPECT_EQ(5, mock.ReturnSecond(1337, 5));
}

}  // namespace
