diff options
author | Dan Sinclair <dsinclair@chromium.org> | 2017-08-30 12:16:16 -0400 |
---|---|---|
committer | Chromium commit bot <commit-bot@chromium.org> | 2017-08-30 16:26:12 +0000 |
commit | 68eefa6a6f6bbab73000a29e2cac3e104be1cc81 (patch) | |
tree | b48dbf0932022bc551ae06e2400262c203856942 /xfa/fde/cfde_texteditengine_unittest.cpp | |
parent | aa3a9cd82df9dff1ef136797259e606a39c18b75 (diff) | |
download | pdfium-68eefa6a6f6bbab73000a29e2cac3e104be1cc81.tar.xz |
Rebuild CFDE_TextEditEngine.
This CL rebuilds the text edit engine in a simpler fashion. Instead of
depending on multiple pages, paragraphs and buffer fields there is a
single text edit engine which contains a gap buffer.
This makes the code easier to understand and follow.
Change-Id: I10fe85603fa9ed15a647eaac2d931f113cd0c7b0
Reviewed-on: https://pdfium-review.googlesource.com/11990
Commit-Queue: dsinclair <dsinclair@chromium.org>
Reviewed-by: Henrique Nakashima <hnakashima@chromium.org>
Reviewed-by: Ryan Harrison <rharrison@chromium.org>
Diffstat (limited to 'xfa/fde/cfde_texteditengine_unittest.cpp')
-rw-r--r-- | xfa/fde/cfde_texteditengine_unittest.cpp | 418 |
1 files changed, 418 insertions, 0 deletions
diff --git a/xfa/fde/cfde_texteditengine_unittest.cpp b/xfa/fde/cfde_texteditengine_unittest.cpp new file mode 100644 index 0000000000..da11e46daa --- /dev/null +++ b/xfa/fde/cfde_texteditengine_unittest.cpp @@ -0,0 +1,418 @@ +// Copyright 2017 PDFium 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 "xfa/fde/cfde_texteditengine.h" + +#include "testing/gtest/include/gtest/gtest.h" +#include "testing/test_support.h" +#include "third_party/base/ptr_util.h" + +class CFDE_TextEditEngineTest : public testing::Test { + public: + class Delegate : public CFDE_TextEditEngine::Delegate { + public: + void Reset() { + text_is_full = false; + fail_validation = false; + } + + void NotifyTextFull() override { text_is_full = true; } + + void OnCaretChanged() override {} + void OnTextChanged(const CFX_WideString& prevText) override {} + void OnSelChanged() override {} + bool OnValidate(const CFX_WideString& wsText) override { + return !fail_validation; + } + void SetScrollOffset(float fScrollOffset) override {} + + bool fail_validation = false; + bool text_is_full = false; + }; + + CFDE_TextEditEngineTest() {} + ~CFDE_TextEditEngineTest() override {} + + void SetUp() override { + font_ = + CFGAS_GEFont::LoadFont(L"Arial Black", 0, 0, GetGlobalFontManager()); + ASSERT(font_.Get() != nullptr); + + engine_ = pdfium::MakeUnique<CFDE_TextEditEngine>(); + engine_->SetFont(font_); + engine_->SetFontSize(12.0f); + } + + void TearDown() override { engine_.reset(); } + + CFDE_TextEditEngine* engine() const { return engine_.get(); } + + private: + CFX_RetainPtr<CFGAS_GEFont> font_; + std::unique_ptr<CFDE_TextEditEngine> engine_; +}; + +TEST_F(CFDE_TextEditEngineTest, Insert) { + EXPECT_STREQ(L"", engine()->GetText().c_str()); + + engine()->Insert(0, L""); + EXPECT_STREQ(L"", engine()->GetText().c_str()); + EXPECT_EQ(0U, engine()->GetLength()); + + engine()->Insert(0, L"Hello"); + EXPECT_STREQ(L"Hello", engine()->GetText().c_str()); + EXPECT_EQ(5U, engine()->GetLength()); + + engine()->Insert(5, L" World"); + EXPECT_STREQ(L"Hello World", engine()->GetText().c_str()); + EXPECT_EQ(11U, engine()->GetLength()); + + engine()->Insert(5, L" New"); + EXPECT_STREQ(L"Hello New World", engine()->GetText().c_str()); + + engine()->Insert(100, L" Cat"); + EXPECT_STREQ(L"Hello New World Cat", engine()->GetText().c_str()); + + engine()->Clear(); + + engine()->SetHasCharacterLimit(true); + engine()->SetCharacterLimit(5); + engine()->Insert(0, L"Hello"); + + // No delegate + engine()->Insert(5, L" World"); + EXPECT_STREQ(L"Hello", engine()->GetText().c_str()); + + engine()->SetCharacterLimit(8); + engine()->Insert(5, L" World"); + EXPECT_STREQ(L"Hello Wo", engine()->GetText().c_str()); + + engine()->Clear(); + + // With Delegate + auto delegate = pdfium::MakeUnique<CFDE_TextEditEngineTest::Delegate>(); + engine()->SetDelegate(delegate.get()); + + engine()->SetCharacterLimit(5); + engine()->Insert(0, L"Hello"); + + // Insert when full. + engine()->Insert(5, L" World"); + EXPECT_TRUE(delegate->text_is_full); + EXPECT_STREQ(L"Hello", engine()->GetText().c_str()); + delegate->Reset(); + + engine()->SetCharacterLimit(8); + engine()->Insert(5, L" World"); + EXPECT_TRUE(delegate->text_is_full); + EXPECT_STREQ(L"Hello Wo", engine()->GetText().c_str()); + delegate->Reset(); + engine()->SetHasCharacterLimit(false); + + engine()->Clear(); + engine()->Insert(0, L"Hello"); + + // Insert Invalid text + delegate->fail_validation = true; + engine()->EnableValidation(true); + engine()->Insert(5, L" World"); + EXPECT_STREQ(L"Hello", engine()->GetText().c_str()); + + delegate->fail_validation = false; + engine()->Insert(5, L" World"); + EXPECT_STREQ(L"Hello World", engine()->GetText().c_str()); + engine()->EnableValidation(false); + + engine()->Clear(); + + engine()->Insert(0, L"Hello\nWorld"); + EXPECT_FALSE(delegate->text_is_full); + EXPECT_STREQ(L"Hello\nWorld", engine()->GetText().c_str()); + delegate->Reset(); + engine()->Clear(); + + // Insert with limited area and over-fill + engine()->LimitHorizontalScroll(true); + engine()->SetAvailableWidth(60.0f); // Fits 'Hello Wo'. + engine()->Insert(0, L"Hello"); + EXPECT_FALSE(delegate->text_is_full); + engine()->Insert(5, L" World"); + EXPECT_TRUE(delegate->text_is_full); + EXPECT_STREQ(L"Hello Wo", engine()->GetText().c_str()); + engine()->LimitHorizontalScroll(false); + + delegate->Reset(); + engine()->Clear(); + + engine()->SetLineSpace(12.0f); + engine()->LimitVerticalScroll(true); + // Default is one line of text. + engine()->Insert(0, L"Hello"); + EXPECT_FALSE(delegate->text_is_full); + engine()->Insert(5, L" Wo\nrld"); + EXPECT_TRUE(delegate->text_is_full); + EXPECT_STREQ(L"Hello Wo\n", engine()->GetText().c_str()); + engine()->LimitVerticalScroll(false); + + engine()->SetDelegate(nullptr); +} + +TEST_F(CFDE_TextEditEngineTest, Delete) { + EXPECT_STREQ(L"", engine()->Delete(0, 50).c_str()); + EXPECT_STREQ(L"", engine()->GetText().c_str()); + + engine()->Insert(0, L"Hello World"); + EXPECT_STREQ(L" World", engine()->Delete(5, 6).c_str()); + EXPECT_STREQ(L"Hello", engine()->GetText().c_str()); + + engine()->Clear(); + engine()->Insert(0, L"Hello World"); + EXPECT_STREQ(L" ", engine()->Delete(5, 1).c_str()); + EXPECT_STREQ(L"HelloWorld", engine()->GetText().c_str()); + + EXPECT_STREQ(L"elloWorld", engine()->Delete(1, 50).c_str()); + EXPECT_STREQ(L"H", engine()->GetText().c_str()); +} + +TEST_F(CFDE_TextEditEngineTest, Clear) { + EXPECT_STREQ(L"", engine()->GetText().c_str()); + + engine()->Clear(); + EXPECT_STREQ(L"", engine()->GetText().c_str()); + + engine()->Insert(0, L"Hello World"); + EXPECT_STREQ(L"Hello World", engine()->GetText().c_str()); + + engine()->Clear(); + EXPECT_STREQ(L"", engine()->GetText().c_str()); + EXPECT_EQ(0U, engine()->GetLength()); +} + +TEST_F(CFDE_TextEditEngineTest, GetChar) { + // Out of bounds. + EXPECT_EQ(L'\0', engine()->GetChar(0)); + + engine()->Insert(0, L"Hello World"); + EXPECT_EQ(L'H', engine()->GetChar(0)); + EXPECT_EQ(L'd', engine()->GetChar(engine()->GetLength() - 1)); + EXPECT_EQ(L' ', engine()->GetChar(5)); + + engine()->Insert(5, L" A"); + EXPECT_STREQ(L"Hello A World", engine()->GetText().c_str()); + EXPECT_EQ(L'W', engine()->GetChar(8)); + + engine()->EnablePasswordMode(true); + EXPECT_EQ(L'*', engine()->GetChar(8)); + + engine()->SetAliasChar(L'+'); + EXPECT_EQ(L'+', engine()->GetChar(8)); +} + +TEST_F(CFDE_TextEditEngineTest, GetWidthOfChar) { + // Out of Bounds. + EXPECT_EQ(0U, engine()->GetWidthOfChar(0)); + + engine()->Insert(0, L"Hello World"); + EXPECT_EQ(199920U, engine()->GetWidthOfChar(0)); + EXPECT_EQ(159840U, engine()->GetWidthOfChar(1)); + + engine()->Insert(0, L"\t"); + EXPECT_EQ(0U, engine()->GetWidthOfChar(0)); +} + +TEST_F(CFDE_TextEditEngineTest, GetDisplayPos) { + EXPECT_EQ(0U, engine()->GetDisplayPos(FDE_TEXTEDITPIECE()).size()); +} + +TEST_F(CFDE_TextEditEngineTest, Selection) { + EXPECT_FALSE(engine()->HasSelection()); + engine()->SelectAll(); + EXPECT_FALSE(engine()->HasSelection()); + + engine()->Insert(0, L"Hello World"); + EXPECT_STREQ(L"", engine()->DeleteSelectedText().c_str()); + + EXPECT_FALSE(engine()->HasSelection()); + engine()->SelectAll(); + EXPECT_TRUE(engine()->HasSelection()); + EXPECT_STREQ(L"Hello World", engine()->GetSelectedText().c_str()); + + engine()->ClearSelection(); + EXPECT_FALSE(engine()->HasSelection()); + EXPECT_STREQ(L"", engine()->GetSelectedText().c_str()); + + engine()->SelectAll(); + size_t start_idx; + size_t end_idx; + std::tie(start_idx, end_idx) = engine()->GetSelection(); + EXPECT_EQ(0U, start_idx); + EXPECT_EQ(10U, end_idx); + + // Selection before gap. + EXPECT_STREQ(L"Hello World", engine()->GetSelectedText().c_str()); + EXPECT_TRUE(engine()->HasSelection()); + EXPECT_STREQ(L"Hello World", engine()->GetText().c_str()); + + engine()->Insert(5, L" A"); + EXPECT_FALSE(engine()->HasSelection()); + EXPECT_STREQ(L"", engine()->GetSelectedText().c_str()); + + // Selection over the gap. + engine()->SelectAll(); + EXPECT_TRUE(engine()->HasSelection()); + EXPECT_STREQ(L"Hello A World", engine()->GetSelectedText().c_str()); + engine()->Clear(); + + engine()->Insert(0, L"Hello World"); + engine()->SelectAll(); + + EXPECT_STREQ(L"Hello World", engine()->DeleteSelectedText().c_str()); + EXPECT_FALSE(engine()->HasSelection()); + EXPECT_STREQ(L"", engine()->GetText().c_str()); + + engine()->Insert(0, L"Hello World"); + engine()->SetSelection(5, 9); + EXPECT_STREQ(L" Worl", engine()->DeleteSelectedText().c_str()); + EXPECT_FALSE(engine()->HasSelection()); + EXPECT_STREQ(L"Hellod", engine()->GetText().c_str()); + + engine()->Clear(); + engine()->Insert(0, L"Hello World"); + engine()->SelectAll(); + engine()->ReplaceSelectedText(L"Goodbye Everybody"); + EXPECT_FALSE(engine()->HasSelection()); + EXPECT_STREQ(L"Goodbye Everybody", engine()->GetText().c_str()); + + engine()->Clear(); + engine()->Insert(0, L"Hello World"); + engine()->SetSelection(1, 4); + engine()->ReplaceSelectedText(L"i,"); + EXPECT_FALSE(engine()->HasSelection()); + EXPECT_STREQ(L"Hi, World", engine()->GetText().c_str()); + + // Selection fully after gap. + engine()->Clear(); + engine()->Insert(0, L"Hello"); + engine()->Insert(0, L"A "); + engine()->SetSelection(3, 6); + EXPECT_STREQ(L"ello", engine()->GetSelectedText().c_str()); + + engine()->Clear(); + engine()->Insert(0, L"Hello World"); + engine()->ClearSelection(); + engine()->DeleteSelectedText(); + EXPECT_STREQ(L"Hello World", engine()->GetText().c_str()); +} + +TEST_F(CFDE_TextEditEngineTest, UndoRedo) { + EXPECT_FALSE(engine()->CanUndo()); + EXPECT_FALSE(engine()->CanRedo()); + EXPECT_FALSE(engine()->Undo()); + EXPECT_FALSE(engine()->Redo()); + + engine()->Insert(0, L"Hello"); + EXPECT_TRUE(engine()->CanUndo()); + EXPECT_FALSE(engine()->CanRedo()); + EXPECT_TRUE(engine()->Undo()); + EXPECT_STREQ(L"", engine()->GetText().c_str()); + EXPECT_FALSE(engine()->CanUndo()); + EXPECT_TRUE(engine()->CanRedo()); + EXPECT_TRUE(engine()->Redo()); + EXPECT_STREQ(L"Hello", engine()->GetText().c_str()); + EXPECT_TRUE(engine()->CanUndo()); + EXPECT_FALSE(engine()->CanRedo()); + + engine()->Clear(); + EXPECT_FALSE(engine()->CanUndo()); + EXPECT_FALSE(engine()->CanRedo()); + + engine()->Insert(0, L"Hello World"); + engine()->SelectAll(); + engine()->DeleteSelectedText(); + EXPECT_STREQ(L"", engine()->GetText().c_str()); + EXPECT_TRUE(engine()->CanUndo()); + EXPECT_TRUE(engine()->Undo()); + EXPECT_STREQ(L"Hello World", engine()->GetText().c_str()); + EXPECT_TRUE(engine()->CanRedo()); + EXPECT_TRUE(engine()->Redo()); + EXPECT_STREQ(L"", engine()->GetText().c_str()); + EXPECT_TRUE(engine()->CanUndo()); + EXPECT_FALSE(engine()->CanRedo()); + + engine()->Insert(0, L"Hello World"); + engine()->SelectAll(); + engine()->ReplaceSelectedText(L"Goodbye Friend"); + EXPECT_STREQ(L"Goodbye Friend", engine()->GetText().c_str()); + EXPECT_TRUE(engine()->CanUndo()); + EXPECT_TRUE(engine()->Undo()); + EXPECT_STREQ(L"Hello World", engine()->GetText().c_str()); + EXPECT_TRUE(engine()->CanRedo()); + EXPECT_TRUE(engine()->Redo()); + EXPECT_STREQ(L"Goodbye Friend", engine()->GetText().c_str()); + + engine()->Clear(); + engine()->SetMaxEditOperationsForTesting(3); + engine()->Insert(0, L"First "); + engine()->Insert(engine()->GetLength(), L"Second "); + engine()->Insert(engine()->GetLength(), L"Third"); + + EXPECT_TRUE(engine()->CanUndo()); + EXPECT_TRUE(engine()->Undo()); + EXPECT_STREQ(L"First Second ", engine()->GetText().c_str()); + EXPECT_TRUE(engine()->CanUndo()); + EXPECT_TRUE(engine()->Undo()); + EXPECT_FALSE( + engine()->CanUndo()); // Can't undo First; undo buffer too small. + EXPECT_STREQ(L"First ", engine()->GetText().c_str()); + + EXPECT_TRUE(engine()->CanRedo()); + EXPECT_TRUE(engine()->Redo()); + EXPECT_TRUE(engine()->CanRedo()); + EXPECT_TRUE(engine()->Redo()); + EXPECT_FALSE(engine()->CanRedo()); + EXPECT_STREQ(L"First Second Third", engine()->GetText().c_str()); + + engine()->Clear(); + + engine()->SetMaxEditOperationsForTesting(4); + + // Go beyond the max operations limit. + engine()->Insert(0, L"H"); + engine()->Insert(1, L"e"); + engine()->Insert(2, L"l"); + engine()->Insert(3, L"l"); + engine()->Insert(4, L"o"); + engine()->Insert(5, L" World"); + EXPECT_STREQ(L"Hello World", engine()->GetText().c_str()); + + // Do A, undo. Do B, undo. Redo should cause B. + engine()->Delete(4, 3); + EXPECT_STREQ(L"Hellorld", engine()->GetText().c_str()); + EXPECT_TRUE(engine()->Undo()); + EXPECT_STREQ(L"Hello World", engine()->GetText().c_str()); + engine()->Delete(5, 6); + EXPECT_STREQ(L"Hello", engine()->GetText().c_str()); + EXPECT_TRUE(engine()->Undo()); + EXPECT_STREQ(L"Hello World", engine()->GetText().c_str()); + EXPECT_TRUE(engine()->Redo()); + EXPECT_STREQ(L"Hello", engine()->GetText().c_str()); + + // Undo down to the limit. + EXPECT_TRUE(engine()->Undo()); + EXPECT_STREQ(L"Hello World", engine()->GetText().c_str()); + EXPECT_TRUE(engine()->Undo()); + EXPECT_STREQ(L"Hello", engine()->GetText().c_str()); + EXPECT_TRUE(engine()->Undo()); + EXPECT_STREQ(L"Hell", engine()->GetText().c_str()); + EXPECT_FALSE(engine()->Undo()); + EXPECT_STREQ(L"Hell", engine()->GetText().c_str()); +} + +TEST_F(CFDE_TextEditEngineTest, GetIndexForPoint) { + engine()->SetFontSize(10.0f); + engine()->Insert(0, L"Hello World"); + EXPECT_EQ(0U, engine()->GetIndexForPoint({0.0f, 0.0f})); + EXPECT_EQ(11U, engine()->GetIndexForPoint({999999.0f, 9999999.0f})); + EXPECT_EQ(1U, engine()->GetIndexForPoint({10.0f, 5.0f})); +} |