blob: e4f8de0e40d5cf1df353016095330df91d202de6 [file] [log] [blame]
// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "components/user_notes/browser/user_note_instance.h"
#include <memory>
#include <vector>
#include "base/memory/safe_ref.h"
#include "base/test/bind.h"
#include "base/unguessable_token.h"
#include "components/user_notes/browser/user_note_base_test.h"
#include "components/user_notes/model/user_note.h"
#include "components/user_notes/model/user_note_model_test_utils.h"
#include "content/public/browser/page.h"
#include "content/public/browser/render_frame_host.h"
#include "content/public/browser/web_contents.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/gfx/geometry/rect.h"
using testing::_;
using testing::Invoke;
using testing::Mock;
namespace user_notes {
namespace {
// Partially mock the object under test so calls to
// `InitializeHighlightInternal` can be intercepted to prevent side effects.
class MockUserNoteInstance : public UserNoteInstance {
public:
explicit MockUserNoteInstance(base::SafeRef<UserNote> model_ref,
UserNoteManager* manager,
const gfx::Rect& simulate_attach_rect)
: UserNoteInstance(model_ref, manager),
attach_rect_(simulate_attach_rect) {}
const gfx::Rect& attach_rect() { return attach_rect_; }
MOCK_METHOD(void, InitializeHighlightInternal, (), (override));
void MockInitializeHighlightInternal() { DidFinishAttachment(attach_rect_); }
private:
gfx::Rect attach_rect_;
};
} // namespace
class UserNoteInstanceTest : public UserNoteBaseTest {
public:
void AddNewNoteToService(UserNoteTarget::TargetType type) {
base::UnguessableToken id = base::UnguessableToken::Create();
note_ids_.emplace_back(id);
// Original text, target URL and selector are not used in these tests.
auto target = std::make_unique<UserNoteTarget>(
type, /*original_text=*/u"", GURL("https://www.example.com/"),
/*selector=*/"");
UserNoteService::ModelMapEntry entry(
std::make_unique<UserNote>(id, GetTestUserNoteMetadata(),
GetTestUserNoteBody(), std::move(target)));
note_service_->model_map_.emplace(id, std::move(entry));
}
std::unique_ptr<MockUserNoteInstance> CreateInstanceForId(
base::UnguessableToken note_id,
UserNoteManager* manager,
const gfx::Rect& simulate_attach_rect) {
const auto& entry_it = note_service_->model_map_.find(note_id);
return std::make_unique<MockUserNoteInstance>(
entry_it->second.model->GetSafeRef(), manager, simulate_attach_rect);
}
bool IsAttachmentFinished(UserNoteInstance* instance) {
return instance->finished_attachment_;
}
};
// Tests that async highlight initialization is skipped for page-level notes.
TEST_F(UserNoteInstanceTest, InitializeHighlightSkipForPageLevelNote) {
AddNewNoteToService(UserNoteTarget::TargetType::kPage);
UserNoteManager* manager = ConfigureNewManager();
// Page-level notes should expect an empty rect.
gfx::Rect empty_rect;
std::unique_ptr<MockUserNoteInstance> instance =
CreateInstanceForId(note_ids_[0], manager, empty_rect);
EXPECT_CALL(*instance, InitializeHighlightInternal).Times(0);
bool callback_called = false;
instance->InitializeHighlightIfNeeded(
base::BindLambdaForTesting([&]() { callback_called = true; }));
// The mocks ensure the callback is invoked synchronously, so verifications
// can happen immediately.
EXPECT_TRUE(callback_called);
EXPECT_FALSE(IsAttachmentFinished(instance.get()));
EXPECT_EQ(instance->rect(), empty_rect);
}
// Tests that async highlight initialization works as expected for text notes.
TEST_F(UserNoteInstanceTest, InitializeHighlightTextNote) {
AddNewNoteToService(UserNoteTarget::TargetType::kPageText);
UserNoteManager* manager = ConfigureNewManager();
gfx::Rect rect(10, 15, 100, 50);
std::unique_ptr<MockUserNoteInstance> instance =
CreateInstanceForId(note_ids_[0], manager, rect);
EXPECT_CALL(*instance, InitializeHighlightInternal)
.Times(1)
.WillOnce(Invoke(instance.get(),
&MockUserNoteInstance::MockInitializeHighlightInternal));
bool callback_called = false;
instance->InitializeHighlightIfNeeded(
base::BindLambdaForTesting([&]() { callback_called = true; }));
// The mocks ensure the callback is invoked synchronously, so verifications
// can happen immediately.
EXPECT_TRUE(callback_called);
EXPECT_TRUE(IsAttachmentFinished(instance.get()));
EXPECT_EQ(instance->rect(), rect);
}
} // namespace user_notes