#include <optional>
#include "base/check_op.h"
#include "base/strings/utf_string_conversions.h"
#include "pdf/buildflags.h"
#include "pdf/document_layout.h"
#include "pdf/pdfium/pdfium_draw_selection_test_base.h"
#include "pdf/pdfium/pdfium_engine.h"
#include "pdf/pdfium/pdfium_test_base.h"
#include "pdf/test/test_client.h"
#include "pdf/text_search.h"
#include "testing/gmock/include/gmock/gmock.h"
using testing::_;
using testing::InSequence;
using testing::NiceMock;
using testing::Return;
namespace chrome_pdf {
namespace {
class FindTextTestClient : public TestClient {
public:
explicit FindTextTestClient(bool expected_case_sensitive)
: expected_case_sensitive_(expected_case_sensitive) {}
FindTextTestClient(const FindTextTestClient&) = delete;
FindTextTestClient& operator=(const FindTextTestClient&) = delete;
~FindTextTestClient() override = default;
MOCK_METHOD(void, NotifyNumberOfFindResultsChanged, (int, bool), (override));
MOCK_METHOD(void, NotifySelectedFindResultChanged, (int, bool), (override));
#if BUILDFLAG(ENABLE_PDF_INK2)
MOCK_METHOD(bool, IsInAnnotationMode, (), (const override));
#endif
std::vector<SearchStringResult> SearchString(const std::u16string& needle,
const std::u16string& haystack,
bool case_sensitive) override {
EXPECT_FALSE(needle.empty());
EXPECT_FALSE(haystack.empty());
EXPECT_EQ(case_sensitive, expected_case_sensitive_);
return TextSearch(needle, haystack, case_sensitive);
}
private:
const bool expected_case_sensitive_;
};
void ExpectInitialSearchResults(FindTextTestClient& client, int count) {
DCHECK_GE(count, 0);
if (count == 0) {
EXPECT_CALL(client,
NotifyNumberOfFindResultsChanged(0, true));
return;
}
InSequence sequence;
EXPECT_CALL(client,
NotifyNumberOfFindResultsChanged(1, false));
for (int i = 2; i < count + 1; ++i) {
EXPECT_CALL(client,
NotifyNumberOfFindResultsChanged(i, false));
}
EXPECT_CALL(client,
NotifyNumberOfFindResultsChanged(count, true));
}
}
using FindTextTest = PDFiumTestBase;
TEST_P(FindTextTest, FindText) {
FindTextTestClient client(true);
std::unique_ptr<PDFiumEngine> engine =
InitializeEngine(&client, FILE_PATH_LITERAL("hello_world2.pdf"));
ASSERT_TRUE(engine);
ExpectInitialSearchResults(client, 10);
engine->StartFind(u"o", true);
}
TEST_P(FindTextTest, FindHyphenatedText) {
FindTextTestClient client(true);
std::unique_ptr<PDFiumEngine> engine =
InitializeEngine(&client, FILE_PATH_LITERAL("spanner.pdf"));
ASSERT_TRUE(engine);
ExpectInitialSearchResults(client, 6);
engine->StartFind(u"application", true);
}
TEST_P(FindTextTest, FindLineBreakText) {
FindTextTestClient client(true);
std::unique_ptr<PDFiumEngine> engine =
InitializeEngine(&client, FILE_PATH_LITERAL("spanner.pdf"));
ASSERT_TRUE(engine);
ExpectInitialSearchResults(client, 1);
engine->StartFind(u"is the first system", true);
}
TEST_P(FindTextTest, FindSimpleQuotationMarkText) {
FindTextTestClient client(true);
std::unique_ptr<PDFiumEngine> engine =
InitializeEngine(&client, FILE_PATH_LITERAL("bug_142627.pdf"));
ASSERT_TRUE(engine);
ExpectInitialSearchResults(client, 2);
engine->StartFind(u"don't", true);
}
TEST_P(FindTextTest, FindFancyQuotationMarkText) {
FindTextTestClient client(true);
std::unique_ptr<PDFiumEngine> engine =
InitializeEngine(&client, FILE_PATH_LITERAL("bug_142627.pdf"));
ASSERT_TRUE(engine);
ExpectInitialSearchResults(client, 2);
engine->StartFind(u"don\u2019t", true);
}
TEST_P(FindTextTest, FindHiddenCroppedText) {
FindTextTestClient client(true);
std::unique_ptr<PDFiumEngine> engine =
InitializeEngine(&client, FILE_PATH_LITERAL("hello_world_cropped.pdf"));
ASSERT_TRUE(engine);
ExpectInitialSearchResults(client, 0);
engine->StartFind(u"Hello", true);
}
TEST_P(FindTextTest, FindVisibleCroppedText) {
FindTextTestClient client(true);
std::unique_ptr<PDFiumEngine> engine =
InitializeEngine(&client, FILE_PATH_LITERAL("hello_world_cropped.pdf"));
ASSERT_TRUE(engine);
ExpectInitialSearchResults(client, 1);
engine->StartFind(u"world", true);
}
TEST_P(FindTextTest, FindVisibleCroppedTextRepeatedly) {
FindTextTestClient client(true);
std::unique_ptr<PDFiumEngine> engine =
InitializeEngine(&client, FILE_PATH_LITERAL("hello_world_cropped.pdf"));
ASSERT_TRUE(engine);
ExpectInitialSearchResults(client, 1);
engine->StartFind(u"worl", true);
ExpectInitialSearchResults(client, 1);
engine->StartFind(u"world", true);
}
TEST_P(FindTextTest, SelectFindResult) {
NiceMock<FindTextTestClient> client(true);
std::unique_ptr<PDFiumEngine> engine =
InitializeEngine(&client, FILE_PATH_LITERAL("hello_world2.pdf"));
ASSERT_TRUE(engine);
ExpectInitialSearchResults(client, 4);
engine->StartFind(u"world", true);
ASSERT_TRUE(engine->SelectFindResult(true));
EXPECT_CALL(client, NotifyNumberOfFindResultsChanged(_, _)).Times(0);
EXPECT_CALL(client,
NotifySelectedFindResultChanged(1, true));
ASSERT_TRUE(engine->SelectFindResult(true));
EXPECT_CALL(client,
NotifySelectedFindResultChanged(2, true));
ASSERT_TRUE(engine->SelectFindResult(true));
EXPECT_CALL(client,
NotifySelectedFindResultChanged(1, true));
ASSERT_TRUE(engine->SelectFindResult(false));
}
TEST_P(FindTextTest, SelectFindResultAndSwitchToTwoUpView) {
FindTextTestClient client(false);
std::unique_ptr<PDFiumEngine> engine =
InitializeEngine(&client, FILE_PATH_LITERAL("hello_world2.pdf"));
ASSERT_TRUE(engine);
ExpectInitialSearchResults(client, 4);
engine->StartFind(u"world", false);
{
InSequence sequence;
EXPECT_CALL(client,
NotifySelectedFindResultChanged(0, true));
EXPECT_CALL(client,
NotifySelectedFindResultChanged(1, true));
}
ASSERT_TRUE(engine->SelectFindResult(true));
ASSERT_TRUE(engine->SelectFindResult(true));
{
InSequence sequence;
for (int i = 0; i < 5; ++i) {
EXPECT_CALL(client,
NotifyNumberOfFindResultsChanged(i, false));
}
EXPECT_CALL(client,
NotifyNumberOfFindResultsChanged(4, true));
}
engine->SetDocumentLayout(DocumentLayout::PageSpread::kTwoUpOdd);
{
InSequence sequence;
EXPECT_CALL(client,
NotifySelectedFindResultChanged(1, true));
}
ASSERT_TRUE(engine->SelectFindResult(true));
}
using FindTextDrawSelectionTest = PDFiumDrawSelectionTestBase;
TEST_P(FindTextDrawSelectionTest, DrawFindResult) {
NiceMock<FindTextTestClient> client(false);
std::unique_ptr<PDFiumEngine> engine =
InitializeEngine(&client, FILE_PATH_LITERAL("hello_world2.pdf"));
ASSERT_TRUE(engine);
engine->PluginSizeUpdated({500, 500});
constexpr int kPageIndex = 0;
DrawAndExpectBlank(*engine, kPageIndex,
gfx::Size(266, 266));
engine->StartFind(u"o", false);
EXPECT_TRUE(engine->SelectFindResult(true));
EXPECT_THAT(engine->GetSelectedText(), testing::IsEmpty());
DrawSelectionAndCompareWithPlatformExpectations(
*engine, kPageIndex, "hello_world_draw_find_result_0.png");
EXPECT_TRUE(engine->SelectFindResult(true));
EXPECT_THAT(engine->GetSelectedText(), testing::IsEmpty());
DrawSelectionAndCompareWithPlatformExpectations(
*engine, kPageIndex, "hello_world_draw_find_result_1.png");
SetSelection(*engine, kPageIndex, 1,
kPageIndex, 2);
EXPECT_EQ("e", engine->GetSelectedText());
DrawSelectionAndCompareWithPlatformExpectations(
*engine, kPageIndex, "hello_world_draw_find_result_2.png");
}
#if BUILDFLAG(ENABLE_PDF_INK2)
TEST_P(FindTextDrawSelectionTest, DrawFindResultInAnnotationMode) {
NiceMock<FindTextTestClient> client(false);
std::unique_ptr<PDFiumEngine> engine =
InitializeEngine(&client, FILE_PATH_LITERAL("hello_world2.pdf"));
ASSERT_TRUE(engine);
EXPECT_CALL(client, IsInAnnotationMode()).WillRepeatedly(Return(true));
engine->PluginSizeUpdated({500, 500});
constexpr int kPageIndex = 0;
DrawAndExpectBlank(*engine, kPageIndex,
gfx::Size(266, 266));
engine->StartFind(u"o", false);
EXPECT_TRUE(engine->SelectFindResult(true));
EXPECT_THAT(engine->GetSelectedText(), testing::IsEmpty());
DrawSelectionAndCompareWithPlatformExpectations(
*engine, kPageIndex, "hello_world_draw_find_result_0.png");
SetSelection(*engine, kPageIndex, 1,
kPageIndex, 2);
EXPECT_EQ("e", engine->GetSelectedText());
DrawSelectionAndCompareWithPlatformExpectations(
*engine, kPageIndex, "hello_world_draw_find_result_0.png");
}
#endif
INSTANTIATE_TEST_SUITE_P(All, FindTextTest, testing::Bool());
INSTANTIATE_TEST_SUITE_P(All, FindTextDrawSelectionTest, testing::Bool());
}