File: bubble_closer_unittest.mm

package info (click to toggle)
chromium 138.0.7204.183-1
  • links: PTS, VCS
  • area: main
  • in suites: trixie
  • size: 6,071,908 kB
  • sloc: cpp: 34,937,088; ansic: 7,176,967; javascript: 4,110,704; python: 1,419,953; asm: 946,768; xml: 739,971; pascal: 187,324; sh: 89,623; perl: 88,663; objc: 79,944; sql: 50,304; cs: 41,786; fortran: 24,137; makefile: 21,806; php: 13,980; tcl: 13,166; yacc: 8,925; ruby: 7,485; awk: 3,720; lisp: 3,096; lex: 1,327; ada: 727; jsp: 228; sed: 36
file content (131 lines) | stat: -rw-r--r-- 4,460 bytes parent folder | download | duplicates (4)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
// Copyright 2017 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "ui/base/cocoa/bubble_closer.h"

#include "base/functional/bind.h"
#import "ui/base/test/cocoa_helper.h"
#import "ui/base/test/menu_test_observer.h"
#import "ui/events/test/cocoa_test_event_utils.h"
#include "ui/gfx/native_widget_types.h"

namespace ui {

class BubbleCloserTest : public CocoaTest {
 public:
  enum Button { LEFT, RIGHT };
  enum InOrOut { INSIDE, OUTSIDE };

  BubbleCloserTest() = default;

  BubbleCloserTest(const BubbleCloserTest&) = delete;
  BubbleCloserTest& operator=(const BubbleCloserTest&) = delete;

  void SetUp() override {
    CocoaTest::SetUp();
    bubble_window_ =
        [[NSWindow alloc] initWithContentRect:NSMakeRect(100, 100, 320, 200)
                                    styleMask:NSWindowStyleMaskBorderless
                                      backing:NSBackingStoreBuffered
                                        defer:NO];
    bubble_window_.releasedWhenClosed = NO;
    [bubble_window_ makeKeyAndOrderFront:nil];
    bubble_closer_ = std::make_unique<BubbleCloser>(
        gfx::NativeWindow(bubble_window_),
        base::BindRepeating([](int* i) { *i += 1; }, &click_outside_count_));
  }

  void TearDown() override {
    [bubble_window_ close];
    bubble_closer_ = nullptr;
    bubble_window_ = nil;
    CocoaTest::TearDown();
  }

  void SendClick(Button left_or_right, InOrOut in_or_out) {
    NSWindow* window = in_or_out == INSIDE ? bubble_window_ : test_window();
    NSEvent* event =
        left_or_right == LEFT
            ? cocoa_test_event_utils::LeftMouseDownAtPointInWindow(
                  NSMakePoint(10, 10), window)
            : cocoa_test_event_utils::RightMouseDownAtPointInWindow(
                  NSMakePoint(10, 10), window);
    [NSApp sendEvent:event];
  }

  void ResetCloser() { bubble_closer_ = nullptr; }

 protected:
  int click_outside_count() const { return click_outside_count_; }
  NSWindow* bubble_window() { return bubble_window_; }
  bool IsCloserReset() const { return !bubble_closer_; }

 private:
  NSWindow* __strong bubble_window_;
  std::unique_ptr<BubbleCloser> bubble_closer_;
  int click_outside_count_ = 0;
};

// Test for lifetime issues around NSEvent monitors.
TEST_F(BubbleCloserTest, SecondBubbleCloser) {
  auto resetter = [](BubbleCloserTest* me) { me->ResetCloser(); };
  auto deleter = std::make_unique<BubbleCloser>(
      gfx::NativeWindow(bubble_window()), base::BindRepeating(resetter, this));
  SendClick(LEFT, OUTSIDE);

  // The order is non-deterministic, so click_outside_count() may not change.
  // But either way, the closer should have been reset.
  EXPECT_TRUE(IsCloserReset());
}

// Test that clicking outside the window fires the callback and clicking inside
// does not.
TEST_F(BubbleCloserTest, ClickInsideAndOut) {
  EXPECT_EQ(0, click_outside_count());
  SendClick(LEFT, OUTSIDE);
  EXPECT_EQ(1, click_outside_count());
  SendClick(RIGHT, OUTSIDE);
  EXPECT_EQ(2, click_outside_count());
  SendClick(LEFT, INSIDE);
  EXPECT_EQ(2, click_outside_count());
  SendClick(RIGHT, INSIDE);
  EXPECT_EQ(2, click_outside_count());
}

// Test that right-clicking the window to display a context menu works.
TEST_F(BubbleCloserTest, RightClickOutsideClosesWithContextMenu) {
  NSMenu* context_menu = [[NSMenu alloc] initWithTitle:@""];
  [context_menu addItemWithTitle:@"ContextMenuTest"
                          action:nil
                   keyEquivalent:@""];

  // Set the menu as the contextual menu of contentView of test_window().
  [test_window().contentView setMenu:context_menu];

  MenuTestObserver* menu_observer =
      [[MenuTestObserver alloc] initWithMenu:context_menu];
  menu_observer.closeAfterOpening = YES;
  menu_observer.openCallback = ^(MenuTestObserver* observer) {
    // Verify click is seen when contextual menu is open.
    EXPECT_TRUE(observer.isOpen);
    EXPECT_EQ(1, click_outside_count());
  };

  EXPECT_FALSE(menu_observer.isOpen);
  EXPECT_FALSE(menu_observer.didOpen);

  EXPECT_EQ(0, click_outside_count());

  // RightMouseDown in test_window() would close the bubble window and then
  // display the contextual menu.
  SendClick(RIGHT, OUTSIDE);

  // When we got here, menu has already run its RunLoop.
  EXPECT_EQ(1, click_outside_count());

  EXPECT_FALSE(menu_observer.isOpen);
  EXPECT_TRUE(menu_observer.didOpen);
}

}  // namespace ui