// Copyright 2015 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 "ui/events/scoped_target_handler.h"

#include <memory>
#include <utility>

#include "base/macros.h"
#include "base/memory/ptr_util.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/events/event_handler.h"
#include "ui/events/event_target.h"
#include "ui/events/event_target_iterator.h"
#include "ui/events/event_utils.h"

namespace ui {

namespace {

class TestEventTargetIterator : public EventTargetIterator {
 public:
  TestEventTargetIterator() {}

  // EventTargetIterator:
  EventTarget* GetNextTarget() override { return nullptr; }

private:
  DISALLOW_COPY_AND_ASSIGN(TestEventTargetIterator);
};

// An EventTarget that holds ownership of its target and delegate EventHandlers.
class TestEventTarget : public EventTarget {
 public:
  TestEventTarget() {}
  ~TestEventTarget() override {}

  void SetHandler(std::unique_ptr<EventHandler> target_handler,
                  std::unique_ptr<EventHandler> delegate) {
    target_handler_ = std::move(target_handler);
    delegate_ = std::move(delegate);
  }

  // EventTarget:
  void DispatchEvent(Event* event) { target_handler()->OnEvent(event); }
  bool CanAcceptEvent(const Event& event) override { return true; }
  EventTarget* GetParentTarget() override { return nullptr; }
  std::unique_ptr<EventTargetIterator> GetChildIterator() const override {
    return base::WrapUnique(new TestEventTargetIterator);
  }
  EventTargeter* GetEventTargeter() override { return nullptr; }

 private:
  std::unique_ptr<EventHandler> target_handler_;
  std::unique_ptr<EventHandler> delegate_;

  DISALLOW_COPY_AND_ASSIGN(TestEventTarget);
};

// An EventHandler that sets itself as a target handler for an EventTarget and
// can recursively dispatch an Event.
class NestedEventHandler : public EventHandler {
 public:
  NestedEventHandler(TestEventTarget* target, int nesting)
      : target_(target), nesting_(nesting) {
    original_handler_ = target_->SetTargetHandler(this);
  }
  ~NestedEventHandler() override {
    EventHandler* handler = target_->SetTargetHandler(original_handler_);
    DCHECK_EQ(this, handler);
  }

 protected:
  void OnEvent(Event* event) override {
    if (--nesting_ == 0)
      return;
    target_->DispatchEvent(event);
  }

 private:
  TestEventTarget* target_;
  int nesting_;
  EventHandler* original_handler_;

  DISALLOW_COPY_AND_ASSIGN(NestedEventHandler);
};

// An EventHandler that sets itself as a target handler for an EventTarget and
// destroys that EventTarget when handling an Event, possibly after recursively
// handling the Event.
class TargetDestroyingEventHandler : public EventHandler {
 public:
  TargetDestroyingEventHandler(TestEventTarget* target, int nesting)
      : target_(target), nesting_(nesting) {
    original_handler_ = target_->SetTargetHandler(this);
  }
  ~TargetDestroyingEventHandler() override {
    EventHandler* handler = target_->SetTargetHandler(original_handler_);
    DCHECK_EQ(this, handler);
  }

 protected:
  void OnEvent(Event* event) override {
    if (--nesting_ == 0) {
      delete target_;
      return;
    }
    target_->DispatchEvent(event);
  }

 private:
  TestEventTarget* target_;
  int nesting_;
  EventHandler* original_handler_;

  DISALLOW_COPY_AND_ASSIGN(TargetDestroyingEventHandler);
};

// An EventHandler that can be set to receive events in addition to the target
// handler and counts the Events that it receives.
class EventCountingEventHandler : public EventHandler {
 public:
  EventCountingEventHandler(EventTarget* target, int* count)
      : scoped_target_handler_(new ScopedTargetHandler(target, this)),
        count_(count) {}
  ~EventCountingEventHandler() override {}

 protected:
  void OnEvent(Event* event) override { (*count_)++; }

 private:
  std::unique_ptr<ScopedTargetHandler> scoped_target_handler_;
  int* count_;

  DISALLOW_COPY_AND_ASSIGN(EventCountingEventHandler);
};

}  // namespace

// Tests that a ScopedTargetHandler invokes both the target and a delegate.
TEST(ScopedTargetHandlerTest, HandlerInvoked) {
  int count = 0;
  TestEventTarget* target = new TestEventTarget;
  std::unique_ptr<NestedEventHandler> target_handler(
      new NestedEventHandler(target, 1));
  std::unique_ptr<EventCountingEventHandler> delegate(
      new EventCountingEventHandler(target, &count));
  target->SetHandler(std::move(target_handler), std::move(delegate));
  MouseEvent event(ET_MOUSE_PRESSED, gfx::Point(), gfx::Point(),
                   EventTimeForNow(), EF_LEFT_MOUSE_BUTTON,
                   EF_LEFT_MOUSE_BUTTON);
  target->DispatchEvent(&event);
  EXPECT_EQ(1, count);
  delete target;
}

// Tests that a ScopedTargetHandler invokes both the target and a delegate when
// an Event is dispatched recursively such as with synthetic events.
TEST(ScopedTargetHandlerTest, HandlerInvokedNested) {
  int count = 0;
  TestEventTarget* target = new TestEventTarget;
  std::unique_ptr<NestedEventHandler> target_handler(
      new NestedEventHandler(target, 2));
  std::unique_ptr<EventCountingEventHandler> delegate(
      new EventCountingEventHandler(target, &count));
  target->SetHandler(std::move(target_handler), std::move(delegate));
  MouseEvent event(ET_MOUSE_PRESSED, gfx::Point(), gfx::Point(),
                   EventTimeForNow(), EF_LEFT_MOUSE_BUTTON,
                   EF_LEFT_MOUSE_BUTTON);
  target->DispatchEvent(&event);
  EXPECT_EQ(2, count);
  delete target;
}

// Tests that a it is safe to delete a ScopedTargetHandler while handling an
// event.
TEST(ScopedTargetHandlerTest, SafeToDestroy) {
  int count = 0;
  TestEventTarget* target = new TestEventTarget;
  std::unique_ptr<TargetDestroyingEventHandler> target_handler(
      new TargetDestroyingEventHandler(target, 1));
  std::unique_ptr<EventCountingEventHandler> delegate(
      new EventCountingEventHandler(target, &count));
  target->SetHandler(std::move(target_handler), std::move(delegate));
  MouseEvent event(ET_MOUSE_PRESSED, gfx::Point(), gfx::Point(),
                   EventTimeForNow(), EF_LEFT_MOUSE_BUTTON,
                   EF_LEFT_MOUSE_BUTTON);
  target->DispatchEvent(&event);
  EXPECT_EQ(0, count);
}

// Tests that a it is safe to delete a ScopedTargetHandler while handling an
// event recursively.
TEST(ScopedTargetHandlerTest, SafeToDestroyNested) {
  int count = 0;
  TestEventTarget* target = new TestEventTarget;
  std::unique_ptr<TargetDestroyingEventHandler> target_handler(
      new TargetDestroyingEventHandler(target, 2));
  std::unique_ptr<EventCountingEventHandler> delegate(
      new EventCountingEventHandler(target, &count));
  target->SetHandler(std::move(target_handler), std::move(delegate));
  MouseEvent event(ET_MOUSE_PRESSED, gfx::Point(), gfx::Point(),
                   EventTimeForNow(), EF_LEFT_MOUSE_BUTTON,
                   EF_LEFT_MOUSE_BUTTON);
  target->DispatchEvent(&event);
  EXPECT_EQ(0, count);
}

}  // namespace ui
