From 5e9066cbfa252b84d49f8b4adba445ba7761e81f Mon Sep 17 00:00:00 2001 From: dsinclair Date: Mon, 9 Jan 2017 13:43:07 -0800 Subject: Add CFDE_TxtEdtBuf tests This CL adds a set of unit tests for the text edit buffer. It fixes up a few bugs found adding the tests and removes the unused ::Optimize method. Review-Url: https://codereview.chromium.org/2614383003 --- BUILD.gn | 1 + xfa/fde/cfde_txtedtbuf.cpp | 60 +++-------- xfa/fde/cfde_txtedtbuf.h | 13 +-- xfa/fde/cfde_txtedtbuf_unittest.cpp | 199 ++++++++++++++++++++++++++++++++++++ xfa/fde/cfde_txtedtengine.cpp | 4 - xfa/fde/cfde_txtedtengine.h | 1 - 6 files changed, 221 insertions(+), 57 deletions(-) create mode 100644 xfa/fde/cfde_txtedtbuf_unittest.cpp diff --git a/BUILD.gn b/BUILD.gn index 53236f50f2..73d0494cf6 100644 --- a/BUILD.gn +++ b/BUILD.gn @@ -1728,6 +1728,7 @@ test("pdfium_unittests") { include_dirs = [] if (pdf_enable_xfa) { sources += [ + "xfa/fde/cfde_txtedtbuf_unittest.cpp", "xfa/fde/css/fde_cssdatatable_unittest.cpp", "xfa/fde/xml/fde_xml_imp_unittest.cpp", "xfa/fxbarcode/pdf417/BC_PDF417HighLevelEncoder_unittest.cpp", diff --git a/xfa/fde/cfde_txtedtbuf.cpp b/xfa/fde/cfde_txtedtbuf.cpp index 94383c261c..36fc47e492 100644 --- a/xfa/fde/cfde_txtedtbuf.cpp +++ b/xfa/fde/cfde_txtedtbuf.cpp @@ -37,6 +37,7 @@ int32_t CFDE_TxtEdtBuf::GetTextLength() const { void CFDE_TxtEdtBuf::SetText(const CFX_WideString& wsText) { ASSERT(!wsText.IsEmpty()); + Clear(false); int32_t nTextLength = wsText.GetLength(); int32_t nNeedCount = @@ -89,6 +90,12 @@ FX_WCHAR CFDE_TxtEdtBuf::GetCharByIndex(int32_t nIndex) const { } CFX_WideString CFDE_TxtEdtBuf::GetRange(int32_t nBegin, int32_t nLength) const { + if (nLength == 0 || GetTextLength() == 0) + return CFX_WideString(); + + ASSERT(nBegin >= 0 && nLength > 0 && nBegin < GetTextLength() && + nBegin + nLength <= GetTextLength()); + FDE_CHUNKPLACE cp; Index2CP(nBegin, cp); int32_t nLeave = nLength; @@ -124,6 +131,8 @@ void CFDE_TxtEdtBuf::Insert(int32_t nPos, const FX_WCHAR* lpText, int32_t nLength) { ASSERT(nPos >= 0 && nPos <= m_nTotal); + ASSERT(nLength > 0); + FDE_CHUNKPLACE cp; Index2CP(nPos, cp); int32_t nLengthTemp = nLength; @@ -220,52 +229,6 @@ void CFDE_TxtEdtBuf::Clear(bool bRelease) { m_bChanged = true; } -bool CFDE_TxtEdtBuf::Optimize(IFX_Pause* pPause) { - if (m_bChanged == false) { - return true; - } - if (m_nTotal == 0) { - return true; - } - int32_t nCount = m_Chunks.GetSize(); - if (nCount == 0) { - return true; - } - int32_t i = 0; - for (; i < nCount; i++) { - FDE_CHUNKHEADER* lpChunk = m_Chunks[i]; - if (lpChunk->nUsed == 0) { - m_pAllocator->Free(lpChunk); - m_Chunks.RemoveAt(i); - --i; - --nCount; - } - } - if (pPause && pPause->NeedToPauseNow()) - return false; - - FDE_CHUNKHEADER* lpPreChunk = m_Chunks[0]; - FDE_CHUNKHEADER* lpCurChunk = nullptr; - for (i = 1; i < nCount; i++) { - lpCurChunk = m_Chunks[i]; - if (lpPreChunk->nUsed + lpCurChunk->nUsed <= m_nChunkSize) { - FXSYS_memcpy(lpPreChunk->wChars + lpPreChunk->nUsed, lpCurChunk->wChars, - lpCurChunk->nUsed * sizeof(FX_WCHAR)); - lpPreChunk->nUsed += lpCurChunk->nUsed; - m_pAllocator->Free(lpCurChunk); - m_Chunks.RemoveAt(i); - --i; - --nCount; - } else { - lpPreChunk = lpCurChunk; - } - if (pPause && pPause->NeedToPauseNow()) - return false; - } - m_bChanged = false; - return true; -} - void CFDE_TxtEdtBuf::ResetChunkBuffer(int32_t nDefChunkCount, int32_t nChunkSize) { ASSERT(nChunkSize); @@ -284,6 +247,11 @@ void CFDE_TxtEdtBuf::ResetChunkBuffer(int32_t nDefChunkCount, m_nTotal = 0; } +void CFDE_TxtEdtBuf::SetChunkSizeForTesting(size_t size) { + Clear(true); + ResetChunkBuffer(kDefaultChunkCount, size); +} + int32_t CFDE_TxtEdtBuf::CP2Index(const FDE_CHUNKPLACE& cp) const { int32_t nTotal = cp.nCharIndex; int32_t i = 0; diff --git a/xfa/fde/cfde_txtedtbuf.h b/xfa/fde/cfde_txtedtbuf.h index ac25a080e5..63edbf6167 100644 --- a/xfa/fde/cfde_txtedtbuf.h +++ b/xfa/fde/cfde_txtedtbuf.h @@ -25,16 +25,15 @@ class CFDE_TxtEdtBuf { void SetText(const CFX_WideString& wsText); CFX_WideString GetText() const; FX_WCHAR GetCharByIndex(int32_t nIndex) const; - CFX_WideString GetRange(int32_t nBegin, int32_t nCount = -1) const; + CFX_WideString GetRange(int32_t nBegin, int32_t nCount) const; - void Insert(int32_t nPos, const FX_WCHAR* lpText, int32_t nLength = 1); - void Delete(int32_t nIndex, int32_t nLength = 1); - void Clear(bool bRelease = true); - - bool Optimize(IFX_Pause* pPause = nullptr); + void Insert(int32_t nPos, const FX_WCHAR* lpText, int32_t nLength); + void Delete(int32_t nIndex, int32_t nLength); + void Clear(bool bRelease); private: friend class CFDE_TxtEdtBufIter; + friend class CFDE_TxtEdtBufTest; struct FDE_CHUNKHEADER { int32_t nUsed; @@ -50,6 +49,8 @@ class CFDE_TxtEdtBuf { int32_t CP2Index(const FDE_CHUNKPLACE& cp) const; void Index2CP(int32_t nIndex, FDE_CHUNKPLACE& cp) const; + void SetChunkSizeForTesting(size_t size); + int32_t m_nChunkSize; int32_t m_nTotal; diff --git a/xfa/fde/cfde_txtedtbuf_unittest.cpp b/xfa/fde/cfde_txtedtbuf_unittest.cpp new file mode 100644 index 0000000000..7228b2ad03 --- /dev/null +++ b/xfa/fde/cfde_txtedtbuf_unittest.cpp @@ -0,0 +1,199 @@ +// 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_txtedtbuf.h" + +#include "testing/gtest/include/gtest/gtest.h" +#include "testing/test_support.h" +#include "third_party/base/ptr_util.h" + +class CFDE_TxtEdtBufTest : public testing::Test { + public: + void SetUp() override { + buf_ = pdfium::MakeUnique(); + buf_->SetChunkSizeForTesting(5); + } + size_t ChunkCount() const { return buf_->m_Chunks.GetSize(); } + + std::unique_ptr buf_; +}; + +TEST_F(CFDE_TxtEdtBufTest, SetTextLessThenChunkSize) { + buf_->SetText(L"Hi"); + EXPECT_EQ(1UL, ChunkCount()); + EXPECT_EQ(2, buf_->GetTextLength()); + + CFX_WideString res = buf_->GetText(); + EXPECT_EQ(2, res.GetLength()); + EXPECT_EQ(L"Hi", res); +} + +TEST_F(CFDE_TxtEdtBufTest, InsertAppendChunk) { + buf_->SetText(L"Hi"); + + CFX_WideString end = L" World"; + buf_->Insert(2, end.c_str(), end.GetLength()); + EXPECT_EQ(3UL, ChunkCount()); + EXPECT_EQ(8, buf_->GetTextLength()); + + CFX_WideString res = buf_->GetText(); + EXPECT_EQ(8, res.GetLength()); + EXPECT_EQ(L"Hi World", res); +} + +TEST_F(CFDE_TxtEdtBufTest, InsertPrependChunk) { + buf_->SetText(L"Hi"); + + CFX_WideString end = L"World "; + buf_->Insert(0, end.c_str(), end.GetLength()); + EXPECT_EQ(3UL, ChunkCount()); + EXPECT_EQ(8, buf_->GetTextLength()); + + CFX_WideString res = buf_->GetText(); + EXPECT_EQ(L"World Hi", res); + EXPECT_EQ(8, res.GetLength()); +} + +TEST_F(CFDE_TxtEdtBufTest, InsertBetweenChunks) { + buf_->SetText(L"Hello World"); + EXPECT_EQ(3UL, ChunkCount()); + + CFX_WideString inst = L"there "; + buf_->Insert(6, inst.c_str(), inst.GetLength()); + EXPECT_EQ(5UL, ChunkCount()); + EXPECT_EQ(17, buf_->GetTextLength()); + + CFX_WideString res = buf_->GetText(); + EXPECT_EQ(L"Hello there World", res); + EXPECT_EQ(17, res.GetLength()); +} + +TEST_F(CFDE_TxtEdtBufTest, SetText) { + buf_->SetText(L"Hello World"); + EXPECT_EQ(11, buf_->GetTextLength()); + + buf_->SetText(L"Hi"); + // Don't remove chunks on setting shorter text. + EXPECT_EQ(3UL, ChunkCount()); + EXPECT_EQ(2, buf_->GetTextLength()); + + CFX_WideString res = buf_->GetText(); + EXPECT_EQ(L"Hi", res); + EXPECT_EQ(2, res.GetLength()); +} + +TEST_F(CFDE_TxtEdtBufTest, DeleteMiddleText) { + buf_->SetText(L"Hello there World"); + buf_->Delete(6, 6); + EXPECT_EQ(4UL, ChunkCount()); + EXPECT_EQ(11, buf_->GetTextLength()); + + CFX_WideString res = buf_->GetText(); + EXPECT_EQ(L"Hello World", res); + EXPECT_EQ(11, res.GetLength()); +} + +TEST_F(CFDE_TxtEdtBufTest, DeleteEndText) { + buf_->SetText(L"Hello World"); + buf_->Delete(5, 6); + EXPECT_EQ(1UL, ChunkCount()); + EXPECT_EQ(5, buf_->GetTextLength()); + + CFX_WideString res = buf_->GetText(); + EXPECT_EQ(L"Hello", res); + EXPECT_EQ(5, res.GetLength()); +} + +TEST_F(CFDE_TxtEdtBufTest, DeleteStartText) { + buf_->SetText(L"Hello World"); + buf_->Delete(0, 6); + EXPECT_EQ(2UL, ChunkCount()); + EXPECT_EQ(5, buf_->GetTextLength()); + + CFX_WideString res = buf_->GetText(); + EXPECT_EQ(L"World", res); + EXPECT_EQ(5, res.GetLength()); +} + +TEST_F(CFDE_TxtEdtBufTest, DeleteAllText) { + buf_->SetText(L"Hello World"); + buf_->Delete(0, 11); + EXPECT_EQ(0UL, ChunkCount()); + EXPECT_EQ(0, buf_->GetTextLength()); + + CFX_WideString res = buf_->GetText(); + EXPECT_EQ(L"", res); + EXPECT_EQ(0, res.GetLength()); +} + +TEST_F(CFDE_TxtEdtBufTest, ClearWithRelease) { + buf_->SetText(L"Hello World"); + buf_->Clear(true); + EXPECT_EQ(0UL, ChunkCount()); + EXPECT_EQ(0, buf_->GetTextLength()); + + CFX_WideString res = buf_->GetText(); + EXPECT_EQ(L"", res); + EXPECT_EQ(0, res.GetLength()); +} + +TEST_F(CFDE_TxtEdtBufTest, ClearWithoutRelease) { + buf_->SetText(L"Hello World"); + buf_->Clear(false); + EXPECT_EQ(3UL, ChunkCount()); + EXPECT_EQ(0, buf_->GetTextLength()); + + CFX_WideString res = buf_->GetText(); + EXPECT_EQ(L"", res); + EXPECT_EQ(0, res.GetLength()); +} + +TEST_F(CFDE_TxtEdtBufTest, GetCharByIndex) { + buf_->SetText(L"Hello world"); + EXPECT_EQ(L"e", CFX_WideString(buf_->GetCharByIndex(1))); + EXPECT_EQ(L"o", CFX_WideString(buf_->GetCharByIndex(7))); +} + +TEST_F(CFDE_TxtEdtBufTest, GetRange) { + buf_->SetText(L"Hello World"); + EXPECT_EQ(L"", buf_->GetRange(1, 0)); + EXPECT_EQ(L"ello", buf_->GetRange(1, 4)); + EXPECT_EQ(L"lo Wo", buf_->GetRange(3, 5)); +} + +#ifndef NDEBUG +using CFDE_TxtEdtBufTestDeathTest = CFDE_TxtEdtBufTest; + +TEST_F(CFDE_TxtEdtBufTestDeathTest, InsertBadIndexes) { + CFX_WideString inst = L"there "; + + buf_->SetText(L"Hi"); + EXPECT_DEATH(buf_->Insert(-4, inst.c_str(), inst.GetLength()), "Assertion"); + EXPECT_DEATH(buf_->Insert(9999, inst.c_str(), inst.GetLength()), "Assertion"); + EXPECT_DEATH(buf_->Insert(1, inst.c_str(), -6), "Assertion"); +} + +TEST_F(CFDE_TxtEdtBufTestDeathTest, DeleteWithBadIdx) { + buf_->SetText(L"Hi"); + EXPECT_DEATH(buf_->Delete(-10, 4), "Assertion"); + EXPECT_DEATH(buf_->Delete(1, -5), "Assertion"); + EXPECT_DEATH(buf_->Delete(5, 1), "Assertion"); + EXPECT_DEATH(buf_->Delete(0, 10000), "Assertion"); +} + +TEST_F(CFDE_TxtEdtBufTestDeathTest, GetCharByIndex) { + buf_->SetText(L"Hi"); + EXPECT_DEATH(buf_->GetCharByIndex(-1), "Assertion"); + EXPECT_DEATH(buf_->GetCharByIndex(100), "Assertion"); +} + +TEST_F(CFDE_TxtEdtBufTestDeathTest, GetRange) { + buf_->SetText(L"Hi"); + EXPECT_DEATH(buf_->GetRange(1, -1), "Assertion"); + EXPECT_DEATH(buf_->GetRange(-1, 1), "Assertion"); + EXPECT_DEATH(buf_->GetRange(10, 1), "Assertion"); + EXPECT_DEATH(buf_->GetRange(1, 100), "Assertion"); +} + +#endif // NDEBUG diff --git a/xfa/fde/cfde_txtedtengine.cpp b/xfa/fde/cfde_txtedtengine.cpp index 342913d820..555df20b99 100644 --- a/xfa/fde/cfde_txtedtengine.cpp +++ b/xfa/fde/cfde_txtedtengine.cpp @@ -675,10 +675,6 @@ void CFDE_TxtEdtEngine::EndLayout() { Unlock(); } -bool CFDE_TxtEdtEngine::Optimize(IFX_Pause* pPause) { - return m_pTxtBuf->Optimize(pPause); -} - CFDE_TxtEdtBuf* CFDE_TxtEdtEngine::GetTextBuf() const { return m_pTxtBuf.get(); } diff --git a/xfa/fde/cfde_txtedtengine.h b/xfa/fde/cfde_txtedtengine.h index 755a820fd2..6918d6305f 100644 --- a/xfa/fde/cfde_txtedtengine.h +++ b/xfa/fde/cfde_txtedtengine.h @@ -69,7 +69,6 @@ class CFDE_TxtEdtEngine { int32_t DoLayout(IFX_Pause* pPause); void EndLayout(); - bool Optimize(IFX_Pause* pPause = nullptr); int32_t CountParags() const; CFDE_TxtEdtParag* GetParag(int32_t nParagIndex) const; IFX_CharIter* CreateCharIter(); -- cgit v1.2.3