| // Copyright 2024 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/android/modal_dialog_wrapper.h" |
| |
| #include "base/android/jni_android.h" |
| #include "base/android/scoped_java_ref.h" |
| #include "base/functional/bind.h" |
| #include "base/functional/callback.h" |
| #include "base/functional/callback_helpers.h" |
| #include "base/memory/weak_ptr.h" |
| #include "base/test/bind.h" |
| #include "base/test/gtest_util.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| #include "third_party/skia/include/core/SkBitmap.h" |
| #include "third_party/skia/include/core/SkColor.h" |
| #include "ui/android/fake_modal_dialog_manager_bridge.h" |
| #include "ui/android/window_android.h" |
| #include "ui/base/interaction/element_identifier.h" |
| #include "ui/base/models/dialog_model.h" |
| #include "ui/color/color_provider.h" |
| #include "ui/color/color_provider_key.h" |
| #include "ui/color/color_provider_manager.h" |
| #include "ui/gfx/image/image.h" |
| #include "ui/gfx/image/image_skia.h" |
| #include "ui/gfx/image/image_unittest_util.h" |
| #include "ui/gfx/vector_icon_types.h" |
| |
| namespace ui { |
| |
| namespace { |
| DEFINE_LOCAL_ELEMENT_IDENTIFIER_VALUE(kCheckboxId); |
| // Icons used in tests below. |
| constexpr int kIconDim = 24; |
| const gfx::PathElement kTestIconPath[] = { |
| // A 16x16 canvas. |
| gfx::CANVAS_DIMENSIONS, |
| 16, |
| // A square path. |
| gfx::MOVE_TO, |
| 0, |
| 0, |
| gfx::LINE_TO, |
| 16, |
| 0, |
| gfx::LINE_TO, |
| 16, |
| 16, |
| gfx::LINE_TO, |
| 0, |
| 16, |
| gfx::CLOSE, |
| }; |
| const gfx::VectorIconRep kTestIconReps[] = { |
| {.path = kTestIconPath}, |
| }; |
| const gfx::VectorIcon kTestIcon(kTestIconReps, |
| std::size(kTestIconReps), |
| "test_icon"); |
| |
| ui::ImageModel CreateBitmapImage(SkColor color) { |
| SkBitmap bitmap; |
| bitmap.allocN32Pixels(kIconDim, kIconDim); |
| bitmap.eraseColor(color); |
| return ui::ImageModel::FromImage(gfx::Image::CreateFrom1xBitmap(bitmap)); |
| } |
| |
| } // namespace |
| |
| class ModalDialogWrapperTest : public testing::Test { |
| protected: |
| // Test helper class to build a DialogModel with a fluent interface. |
| class DialogModelBuilder { |
| public: |
| explicit DialogModelBuilder(bool* dialog_destroyed_flag) |
| : dialog_destroyed_flag_(dialog_destroyed_flag) {} |
| |
| DialogModelBuilder& WithOkButton( |
| base::OnceClosure callback, |
| ui::ButtonStyle style = ui::ButtonStyle::kDefault) { |
| ok_callback_ = std::move(callback); |
| ok_button_style_ = style; |
| return *this; |
| } |
| |
| DialogModelBuilder& WithCancelButton( |
| base::OnceClosure callback, |
| ui::ButtonStyle style = ui::ButtonStyle::kDefault) { |
| has_cancel_button_ = true; |
| cancel_callback_ = std::move(callback); |
| cancel_button_style_ = style; |
| return *this; |
| } |
| |
| DialogModelBuilder& WithCloseAction(base::OnceClosure callback) { |
| close_callback_ = std::move(callback); |
| return *this; |
| } |
| |
| DialogModelBuilder& OverrideDefaultButton( |
| mojom::DialogButton override_button) { |
| override_button_ = override_button; |
| return *this; |
| } |
| |
| DialogModelBuilder& WithParagraphs( |
| const std::vector<std::u16string>& paragraphs) { |
| paragraphs_ = paragraphs; |
| return *this; |
| } |
| |
| DialogModelBuilder& WithCheckbox(bool is_checked) { |
| has_checkbox_ = true; |
| checkbox_is_checked_ = is_checked; |
| return *this; |
| } |
| |
| DialogModelBuilder& WithIcon(ui::ImageModel icon) { |
| icon_ = std::move(icon); |
| return *this; |
| } |
| |
| DialogModelBuilder& AddMenuItem(ui::ImageModel icon, |
| const std::u16string& label) { |
| menu_items_.emplace_back(std::move(icon), label, base::DoNothing()); |
| return *this; |
| } |
| |
| DialogModelBuilder& AddMenuItemWithCallback( |
| ui::ImageModel icon, |
| const std::u16string& label, |
| base::RepeatingClosure callback) { |
| menu_items_.emplace_back(std::move(icon), label, std::move(callback)); |
| return *this; |
| } |
| |
| std::unique_ptr<ui::DialogModel> Build() { |
| ui::DialogModel::Builder dialog_builder; |
| dialog_builder.SetTitle(u"title"); |
| |
| if (icon_) { |
| dialog_builder.SetIcon(*icon_); |
| } |
| |
| for (const auto& paragraph_text : paragraphs_) { |
| dialog_builder.AddParagraph(ui::DialogModelLabel(paragraph_text)); |
| } |
| |
| for (auto& item : menu_items_) { |
| dialog_builder.AddMenuItem( |
| std::move(std::get<0>(item)), std::get<1>(item), |
| base::BindRepeating([](base::RepeatingClosure callback, |
| int event_flags) { callback.Run(); }, |
| std::move(std::get<2>(item)))); |
| } |
| |
| if (has_checkbox_) { |
| dialog_builder.AddCheckbox( |
| kCheckboxId, ui::DialogModelLabel(u"checkbox label"), |
| ui::DialogModelCheckbox::Params().SetIsChecked( |
| checkbox_is_checked_)); |
| } |
| |
| dialog_builder.AddOkButton( |
| std::move(ok_callback_), |
| ui::DialogModel::Button::Params().SetLabel(u"ok").SetStyle( |
| ok_button_style_)); |
| |
| if (has_cancel_button_) { |
| dialog_builder.AddCancelButton( |
| std::move(cancel_callback_), |
| ui::DialogModel::Button::Params().SetLabel(u"cancel").SetStyle( |
| cancel_button_style_)); |
| } |
| |
| // Capture the pointer to the destruction flag by value. This prevents |
| // the lambda from holding a dangling reference to the temporary builder |
| // instance. |
| bool* flag_ptr = dialog_destroyed_flag_; |
| dialog_builder.SetCloseActionCallback(std::move(close_callback_)) |
| .SetDialogDestroyingCallback( |
| base::BindLambdaForTesting([flag_ptr]() { *flag_ptr = true; })); |
| |
| if (override_button_) { |
| dialog_builder.OverrideDefaultButton(*override_button_); |
| } |
| return dialog_builder.Build(); |
| } |
| |
| private: |
| raw_ptr<bool> dialog_destroyed_flag_; |
| |
| // Default values match the original CreateDialogModel function. |
| base::OnceClosure ok_callback_ = base::DoNothing(); |
| ui::ButtonStyle ok_button_style_ = ui::ButtonStyle::kDefault; |
| |
| bool has_cancel_button_ = false; |
| base::OnceClosure cancel_callback_ = base::DoNothing(); |
| ui::ButtonStyle cancel_button_style_ = ui::ButtonStyle::kDefault; |
| |
| base::OnceClosure close_callback_ = base::DoNothing(); |
| std::optional<mojom::DialogButton> override_button_; |
| std::vector<std::u16string> paragraphs_ = {u"paragraph"}; |
| std::vector< |
| std::tuple<ui::ImageModel, std::u16string, base::RepeatingClosure>> |
| menu_items_; |
| |
| bool has_checkbox_ = false; |
| bool checkbox_is_checked_ = false; |
| std::optional<ui::ImageModel> icon_; |
| }; |
| |
| void SetUp() override { |
| window_ = ui::WindowAndroid::CreateForTesting(); |
| fake_dialog_manager_ = FakeModalDialogManagerBridge::CreateForTab( |
| window_->get(), /*use_empty_java_presenter=*/false); |
| } |
| |
| bool dialog_destroyed_ = false; |
| std::unique_ptr<ui::WindowAndroid::ScopedWindowAndroidForTesting> window_; |
| std::unique_ptr<FakeModalDialogManagerBridge> fake_dialog_manager_; |
| }; |
| |
| TEST_F(ModalDialogWrapperTest, CallOkButton) { |
| bool ok_called = false; |
| |
| auto dialog_model = |
| DialogModelBuilder(&dialog_destroyed_) |
| .WithOkButton(base::BindLambdaForTesting([&]() { ok_called = true; })) |
| .Build(); |
| |
| ModalDialogWrapper::ShowTabModal(std::move(dialog_model), window_->get()); |
| fake_dialog_manager_->ClickPositiveButton(); |
| |
| EXPECT_TRUE(ok_called); |
| EXPECT_TRUE(dialog_destroyed_); |
| } |
| |
| TEST_F(ModalDialogWrapperTest, CallCancelButton) { |
| bool ok_called = false, cancel_called = false; |
| |
| auto dialog_model = |
| DialogModelBuilder(&dialog_destroyed_) |
| .WithOkButton(base::BindLambdaForTesting([&]() { ok_called = true; })) |
| .WithCancelButton( |
| base::BindLambdaForTesting([&]() { cancel_called = true; })) |
| .Build(); |
| |
| ModalDialogWrapper::ShowTabModal(std::move(dialog_model), window_->get()); |
| fake_dialog_manager_->ClickNegativeButton(); |
| |
| EXPECT_FALSE(ok_called); |
| EXPECT_TRUE(cancel_called); |
| EXPECT_TRUE(dialog_destroyed_); |
| } |
| |
| TEST_F(ModalDialogWrapperTest, CloseDialogFromNative) { |
| bool ok_called = false, cancel_called = false, closed = false; |
| |
| auto dialog_model = |
| DialogModelBuilder(&dialog_destroyed_) |
| .WithOkButton(base::BindLambdaForTesting([&]() { ok_called = true; })) |
| .WithCancelButton( |
| base::BindLambdaForTesting([&]() { cancel_called = true; })) |
| .WithCloseAction(base::BindLambdaForTesting([&]() { closed = true; })) |
| .Build(); |
| |
| ModalDialogWrapper::ShowTabModal(std::move(dialog_model), window_->get()); |
| ModalDialogWrapper::GetDialogForTesting()->Close(); |
| |
| EXPECT_FALSE(ok_called); |
| EXPECT_FALSE(cancel_called); |
| EXPECT_TRUE(closed); |
| EXPECT_TRUE(dialog_destroyed_); |
| } |
| |
| TEST_F(ModalDialogWrapperTest, ModalButtonsNoProminent) { |
| auto dialog_model = DialogModelBuilder(&dialog_destroyed_).Build(); |
| |
| ModalDialogWrapper::ShowTabModal(std::move(dialog_model), window_->get()); |
| |
| EXPECT_EQ(static_cast<ui::ModalDialogWrapper::ModalDialogButtonStyles>( |
| fake_dialog_manager_->GetButtonStyles()), |
| ui::ModalDialogWrapper::ModalDialogButtonStyles:: |
| kPrimaryOutlineNegativeOutline); |
| EXPECT_FALSE(dialog_destroyed_); |
| } |
| |
| TEST_F(ModalDialogWrapperTest, ModalButtonsPrimaryProminentNoNegative) { |
| auto dialog_model = |
| DialogModelBuilder(&dialog_destroyed_) |
| .WithOkButton(base::DoNothing(), ui::ButtonStyle::kProminent) |
| .Build(); |
| |
| ModalDialogWrapper::ShowTabModal(std::move(dialog_model), window_->get()); |
| |
| EXPECT_EQ(static_cast<ui::ModalDialogWrapper::ModalDialogButtonStyles>( |
| fake_dialog_manager_->GetButtonStyles()), |
| ui::ModalDialogWrapper::ModalDialogButtonStyles:: |
| kPrimaryFilledNoNegative); |
| EXPECT_FALSE(dialog_destroyed_); |
| } |
| |
| TEST_F(ModalDialogWrapperTest, ModalButtonsPrimaryProminent) { |
| auto dialog_model = |
| DialogModelBuilder(&dialog_destroyed_) |
| .WithOkButton(base::DoNothing(), ui::ButtonStyle::kProminent) |
| .WithCancelButton(base::DoNothing()) |
| .Build(); |
| |
| ModalDialogWrapper::ShowTabModal(std::move(dialog_model), window_->get()); |
| |
| EXPECT_EQ(static_cast<ui::ModalDialogWrapper::ModalDialogButtonStyles>( |
| fake_dialog_manager_->GetButtonStyles()), |
| ui::ModalDialogWrapper::ModalDialogButtonStyles:: |
| kPrimaryFilledNegativeOutline); |
| EXPECT_FALSE(dialog_destroyed_); |
| } |
| |
| TEST_F(ModalDialogWrapperTest, ModalButtonsNegativeProminent) { |
| auto dialog_model = |
| DialogModelBuilder(&dialog_destroyed_) |
| .WithCancelButton(base::DoNothing(), ui::ButtonStyle::kProminent) |
| .Build(); |
| |
| ModalDialogWrapper::ShowTabModal(std::move(dialog_model), window_->get()); |
| |
| EXPECT_EQ(static_cast<ui::ModalDialogWrapper::ModalDialogButtonStyles>( |
| fake_dialog_manager_->GetButtonStyles()), |
| ui::ModalDialogWrapper::ModalDialogButtonStyles:: |
| kPrimaryOutlineNegativeFilled); |
| EXPECT_FALSE(dialog_destroyed_); |
| } |
| |
| TEST_F(ModalDialogWrapperTest, ModalButtonsOverriddenNone) { |
| auto dialog_model = |
| DialogModelBuilder(&dialog_destroyed_) |
| .WithOkButton(base::DoNothing(), ui::ButtonStyle::kProminent) |
| .WithCancelButton(base::DoNothing(), ui::ButtonStyle::kProminent) |
| .OverrideDefaultButton(ui::mojom::DialogButton::kNone) |
| .Build(); |
| |
| ModalDialogWrapper::ShowTabModal(std::move(dialog_model), window_->get()); |
| |
| EXPECT_EQ(static_cast<ui::ModalDialogWrapper::ModalDialogButtonStyles>( |
| fake_dialog_manager_->GetButtonStyles()), |
| ui::ModalDialogWrapper::ModalDialogButtonStyles:: |
| kPrimaryOutlineNegativeOutline); |
| EXPECT_FALSE(dialog_destroyed_); |
| } |
| |
| TEST_F(ModalDialogWrapperTest, ModalButtonsOverriddenPositive) { |
| auto dialog_model = |
| DialogModelBuilder(&dialog_destroyed_) |
| .WithCancelButton(base::DoNothing(), ui::ButtonStyle::kProminent) |
| .OverrideDefaultButton(ui::mojom::DialogButton::kOk) |
| .Build(); |
| |
| ModalDialogWrapper::ShowTabModal(std::move(dialog_model), window_->get()); |
| |
| EXPECT_EQ(static_cast<ui::ModalDialogWrapper::ModalDialogButtonStyles>( |
| fake_dialog_manager_->GetButtonStyles()), |
| ui::ModalDialogWrapper::ModalDialogButtonStyles:: |
| kPrimaryFilledNegativeOutline); |
| EXPECT_FALSE(dialog_destroyed_); |
| } |
| |
| TEST_F(ModalDialogWrapperTest, ModalButtonsOverriddenNegative) { |
| auto dialog_model = |
| DialogModelBuilder(&dialog_destroyed_) |
| .WithOkButton(base::DoNothing(), ui::ButtonStyle::kProminent) |
| .WithCancelButton(base::DoNothing()) |
| .OverrideDefaultButton(ui::mojom::DialogButton::kCancel) |
| .Build(); |
| |
| ModalDialogWrapper::ShowTabModal(std::move(dialog_model), window_->get()); |
| |
| EXPECT_EQ(static_cast<ui::ModalDialogWrapper::ModalDialogButtonStyles>( |
| fake_dialog_manager_->GetButtonStyles()), |
| ui::ModalDialogWrapper::ModalDialogButtonStyles:: |
| kPrimaryOutlineNegativeFilled); |
| EXPECT_FALSE(dialog_destroyed_); |
| } |
| |
| TEST_F(ModalDialogWrapperTest, ParagraphsAreSetAndReplaced) { |
| std::vector<std::u16string> paragraphs = {u"This is the first paragraph.", |
| u"This is the second paragraph."}; |
| |
| auto dialog_model_1 = |
| DialogModelBuilder(&dialog_destroyed_).WithParagraphs(paragraphs).Build(); |
| |
| ModalDialogWrapper::ShowTabModal(std::move(dialog_model_1), window_->get()); |
| |
| std::vector<std::u16string> displayed_paragraphs_1 = |
| fake_dialog_manager_->GetMessageParagraphs(); |
| ASSERT_EQ(displayed_paragraphs_1.size(), 2u); |
| EXPECT_EQ(displayed_paragraphs_1.front(), paragraphs.front()); |
| EXPECT_EQ(displayed_paragraphs_1.back(), paragraphs.back()); |
| |
| // Remove the last element and confirm the behavior. |
| paragraphs.pop_back(); |
| |
| auto dialog_model_2 = |
| DialogModelBuilder(&dialog_destroyed_).WithParagraphs(paragraphs).Build(); |
| |
| ModalDialogWrapper::ShowTabModal(std::move(dialog_model_2), window_->get()); |
| |
| std::vector<std::u16string> displayed_paragraphs_2 = |
| fake_dialog_manager_->GetMessageParagraphs(); |
| ASSERT_EQ(displayed_paragraphs_2.size(), 1u); |
| EXPECT_EQ(displayed_paragraphs_2.front(), paragraphs.front()); |
| } |
| |
| TEST_F(ModalDialogWrapperTest, Checkbox_InitialStateUnchecked) { |
| auto dialog_model = |
| DialogModelBuilder(&dialog_destroyed_).WithCheckbox(false).Build(); |
| ModalDialogWrapper::ShowTabModal(std::move(dialog_model), window_->get()); |
| |
| EXPECT_FALSE(fake_dialog_manager_->IsCheckboxChecked()); |
| } |
| |
| TEST_F(ModalDialogWrapperTest, Checkbox_InitialStateChecked) { |
| auto dialog_model = |
| DialogModelBuilder(&dialog_destroyed_).WithCheckbox(true).Build(); |
| ModalDialogWrapper::ShowTabModal(std::move(dialog_model), window_->get()); |
| |
| EXPECT_TRUE(fake_dialog_manager_->IsCheckboxChecked()); |
| } |
| |
| TEST_F(ModalDialogWrapperTest, Checkbox_StateSynchronizedAfterToggle) { |
| auto dialog_model = |
| DialogModelBuilder(&dialog_destroyed_).WithCheckbox(false).Build(); |
| // Get a raw pointer to the model before it's moved. |
| auto* dialog_model_ptr = dialog_model.get(); |
| |
| ModalDialogWrapper::ShowTabModal(std::move(dialog_model), window_->get()); |
| |
| // Verify initial state. |
| EXPECT_FALSE(fake_dialog_manager_->IsCheckboxChecked()); |
| EXPECT_FALSE( |
| dialog_model_ptr->GetCheckboxByUniqueId(kCheckboxId)->is_checked()); |
| |
| // Simulate a UI click on the checkbox. |
| fake_dialog_manager_->ToggleCheckbox(); |
| |
| // Verify both the Java model (via fake manager) and C++ model are updated. |
| EXPECT_TRUE(fake_dialog_manager_->IsCheckboxChecked()); |
| EXPECT_TRUE( |
| dialog_model_ptr->GetCheckboxByUniqueId(kCheckboxId)->is_checked()); |
| |
| // Toggle it back. |
| fake_dialog_manager_->ToggleCheckbox(); |
| |
| EXPECT_FALSE(fake_dialog_manager_->IsCheckboxChecked()); |
| EXPECT_FALSE( |
| dialog_model_ptr->GetCheckboxByUniqueId(kCheckboxId)->is_checked()); |
| } |
| |
| TEST_F(ModalDialogWrapperTest, TitleIcon_ShowsVectorIcon) { |
| auto icon = |
| ui::ImageModel::FromVectorIcon(kTestIcon, SK_ColorBLACK, kIconDim); |
| |
| // Convert icon to bitmap for comparison. |
| ui::ColorProvider color_provider; |
| color_provider.GenerateColorMapForTesting(); |
| const SkBitmap expected_bitmap = *icon.Rasterize(&color_provider).bitmap(); |
| |
| auto dialog_model = |
| DialogModelBuilder(&dialog_destroyed_).WithIcon(std::move(icon)).Build(); |
| |
| ModalDialogWrapper::ShowTabModal(std::move(dialog_model), window_->get()); |
| |
| SkBitmap actual_bitmap = fake_dialog_manager_->GetTitleIcon(); |
| |
| EXPECT_TRUE(gfx::test::AreBitmapsEqual(expected_bitmap, actual_bitmap)); |
| EXPECT_FALSE(dialog_destroyed_); |
| } |
| |
| TEST_F(ModalDialogWrapperTest, TitleIcon_ShowsGfxImage) { |
| auto icon = CreateBitmapImage(SK_ColorGREEN); |
| ui::ColorProvider color_provider; |
| color_provider.GenerateColorMapForTesting(); |
| const SkBitmap expected_bitmap = *icon.Rasterize(&color_provider).bitmap(); |
| |
| auto dialog_model = |
| DialogModelBuilder(&dialog_destroyed_).WithIcon(std::move(icon)).Build(); |
| |
| ModalDialogWrapper::ShowTabModal(std::move(dialog_model), window_->get()); |
| |
| SkBitmap actual_bitmap = fake_dialog_manager_->GetTitleIcon(); |
| |
| EXPECT_TRUE(gfx::test::AreBitmapsEqual(expected_bitmap, actual_bitmap)); |
| EXPECT_FALSE(dialog_destroyed_); |
| } |
| |
| TEST_F(ModalDialogWrapperTest, ShowsMenuItems) { |
| // --- Item 1: SkBitmap-based --- |
| auto icon1 = CreateBitmapImage(SK_ColorRED); |
| ui::ColorProvider color_provider; |
| color_provider.GenerateColorMapForTesting(); |
| const SkBitmap expected_bitmap1 = *icon1.Rasterize(&color_provider).bitmap(); |
| const std::u16string label1 = u"Red Bitmap Item"; |
| |
| // --- Item 2: VectorIcon-based --- |
| auto icon2 = |
| ui::ImageModel::FromVectorIcon(kTestIcon, SK_ColorBLUE, kIconDim); |
| const SkBitmap expected_bitmap2 = *icon2.Rasterize(&color_provider).bitmap(); |
| const std::u16string label2 = u"Blue Vector Item"; |
| |
| // --- Build and Show --- |
| auto dialog_model = DialogModelBuilder(&dialog_destroyed_) |
| .AddMenuItem(std::move(icon1), label1) |
| .AddMenuItem(std::move(icon2), label2) |
| .Build(); |
| ModalDialogWrapper::ShowTabModal(std::move(dialog_model), window_->get()); |
| |
| // --- Assert --- |
| std::vector<std::u16string> actual_labels = |
| fake_dialog_manager_->GetMenuItemTexts(); |
| std::vector<SkBitmap> actual_icons = fake_dialog_manager_->GetMenuItemIcons(); |
| // Try a null callback |
| fake_dialog_manager_->ClickMenuItem(0); |
| |
| ASSERT_EQ(actual_labels.size(), 2u); |
| ASSERT_EQ(actual_icons.size(), 2u); |
| |
| EXPECT_EQ(actual_labels[0], label1); |
| EXPECT_EQ(actual_labels[1], label2); |
| EXPECT_TRUE(gfx::test::AreBitmapsEqual(actual_icons[0], expected_bitmap1)); |
| EXPECT_TRUE(gfx::test::AreBitmapsEqual(actual_icons[1], expected_bitmap2)); |
| |
| EXPECT_FALSE(dialog_destroyed_); |
| } |
| |
| TEST_F(ModalDialogWrapperTest, MenuItem_Callbacks) { |
| bool callback1_called = false; |
| bool callback2_called = false; |
| auto icon = CreateBitmapImage(SK_ColorRED); |
| |
| auto dialog_model = |
| DialogModelBuilder(&dialog_destroyed_) |
| .AddMenuItemWithCallback( |
| icon, u"Item 1", |
| base::BindLambdaForTesting([&]() { callback1_called = true; })) |
| .AddMenuItemWithCallback( |
| icon, u"Item 2", |
| base::BindLambdaForTesting([&]() { callback2_called = true; })) |
| .Build(); |
| ModalDialogWrapper::ShowTabModal(std::move(dialog_model), window_->get()); |
| |
| fake_dialog_manager_->ClickMenuItem(1); |
| |
| EXPECT_FALSE(callback1_called); |
| EXPECT_TRUE(callback2_called); |
| |
| fake_dialog_manager_->ClickMenuItem(0); |
| EXPECT_TRUE(callback1_called); |
| } |
| |
| TEST_F(ModalDialogWrapperTest, MenuItem_CallbackDismissesDialog) { |
| auto dialog_model = |
| DialogModelBuilder(&dialog_destroyed_) |
| .AddMenuItemWithCallback( |
| CreateBitmapImage(SK_ColorRED), u"Item", |
| base::BindLambdaForTesting([&]() { |
| ModalDialogWrapper::GetDialogForTesting()->Close(); |
| })) |
| .Build(); |
| ModalDialogWrapper::ShowTabModal(std::move(dialog_model), window_->get()); |
| |
| fake_dialog_manager_->ClickMenuItem(0); |
| |
| EXPECT_TRUE(dialog_destroyed_); |
| } |
| |
| } // namespace ui |