sw/CppunitTest_sw_tox.mk | 1 sw/Library_sw.mk | 1 sw/inc/ToxLinkProcessor.hxx | 86 ++++++++++++++++++ sw/inc/ToxTextGenerator.hxx | 12 +- sw/qa/cppunit/tox/test_ToxLinkProcessor.cxx | 133 ++++++++++++++++++++++++++++ sw/source/core/tox/ToxLinkProcessor.cxx | 70 ++++++++++++++ sw/source/core/tox/ToxTextGenerator.cxx | 66 ++----------- 7 files changed, 312 insertions(+), 57 deletions(-)
New commits: commit 94b296d5416dd71d721ad16216b50bce79e3dc04 Author: Tobias Lippert <d...@fastmail.fm> Date: Sun Jun 1 14:18:39 2014 +0200 Unittest link generation for table of contents. The logic was moved to a separate class and unittested. Conflicts: sw/inc/ToxTextGenerator.hxx Change-Id: I0e4475f5e2950cdfdfb07b89128c4ce1d6af3f22 Reviewed-on: https://gerrit.libreoffice.org/9609 Reviewed-by: Caolán McNamara <caol...@redhat.com> Tested-by: Caolán McNamara <caol...@redhat.com> diff --git a/sw/CppunitTest_sw_tox.mk b/sw/CppunitTest_sw_tox.mk index f372442..7911de3 100644 --- a/sw/CppunitTest_sw_tox.mk +++ b/sw/CppunitTest_sw_tox.mk @@ -14,6 +14,7 @@ $(eval $(call gb_CppunitTest_CppunitTest,sw_tox_test)) $(eval $(call gb_CppunitTest_add_exception_objects,sw_tox_test, \ sw/qa/cppunit/tox/test_ToxWhitespaceStripper \ + sw/qa/cppunit/tox/test_ToxLinkProcessor \ )) $(eval $(call gb_CppunitTest_use_libraries,sw_tox_test, \ diff --git a/sw/Library_sw.mk b/sw/Library_sw.mk index a7500ad..c073564 100644 --- a/sw/Library_sw.mk +++ b/sw/Library_sw.mk @@ -388,6 +388,7 @@ $(eval $(call gb_Library_add_exception_objects,sw,\ sw/source/core/tox/tox \ sw/source/core/tox/toxhlp \ sw/source/core/tox/txmsrt \ + sw/source/core/tox/ToxLinkProcessor \ sw/source/core/tox/ToxTextGenerator \ sw/source/core/tox/ToxWhitespaceStripper \ sw/source/core/txtnode/SwGrammarContact \ diff --git a/sw/inc/ToxLinkProcessor.hxx b/sw/inc/ToxLinkProcessor.hxx new file mode 100644 index 0000000..5a45465 --- /dev/null +++ b/sw/inc/ToxLinkProcessor.hxx @@ -0,0 +1,86 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#ifndef SW_TOXLINKPROCESSOR_HXX_ +#define SW_TOXLINKPROCESSOR_HXX_ + +#include "fmtinfmt.hxx" +#include "rtl/ustring.hxx" + +#include <vector> + +class SwTxtNode; + +class ToxLinkProcessorTest; + +namespace sw { + +/** A helper class for ToxTextGenerator. + * It collects information about encountered link tokens and allows access in a processed form. + */ +class SW_DLLPUBLIC ToxLinkProcessor { +public: + ToxLinkProcessor() {;} + virtual ~ToxLinkProcessor() {;} + + void + StartNewLink(sal_Int32 startPosition, const OUString& characterStyle); + + /** Close a link which has been found during processing. + * + * @throw std::runtime_error If there are no open links. + */ + void + CloseLink(sal_Int32 endPosition, const OUString& url); + + /** Insert the found links as attributes to a text node */ + void + InsertLinkAttributes(SwTxtNode& node); + +private: + /** Obtain the pool id which belongs to a character style. + * + * @internal + * This method is overridden in the unittests. You should not override it yourself. + */ + virtual sal_uInt16 + ObtainPoolId(const OUString& characterStyle) const; + + /** Information about a started link */ + struct StartedLink { + StartedLink(sal_Int32 startPosition, OUString characterStyle) : + mStartPosition(startPosition), mCharacterStyle(characterStyle) { + ; + } + sal_Int32 mStartPosition; + OUString mCharacterStyle; + }; + + /** A link that has been encountered while parsing a tox. + * A link is closed if it has both a start and an end token. + */ + struct ClosedLink { + ClosedLink(const OUString& url, sal_Int32 startPosition, sal_Int32 endPosition) : + mINetFmt(url, OUString()), mStartTextPos(endPosition), mEndTextPos(startPosition) { + } + SwFmtINetFmt mINetFmt; + sal_Int32 mStartTextPos; + sal_Int32 mEndTextPos; + }; + + std::vector<ClosedLink> mClosedLinks; + + std::vector<StartedLink> mStartedLinks; + + friend class ::ToxLinkProcessorTest; +}; + +} + +#endif /* SW_TOXLINKPROCESSOR_HXX_ */ diff --git a/sw/inc/ToxTextGenerator.hxx b/sw/inc/ToxTextGenerator.hxx index e64c8b6..d83736b 100644 --- a/sw/inc/ToxTextGenerator.hxx +++ b/sw/inc/ToxTextGenerator.hxx @@ -22,6 +22,7 @@ #include "sal/types.h" #include "swdllapi.h" +#include <boost/shared_ptr.hpp> #include <vector> class SwDoc; @@ -31,12 +32,15 @@ struct SwTOXSortTabBase; namespace sw { +class ToxLinkProcessor; + class SW_DLLPUBLIC ToxTextGenerator { public: - ToxTextGenerator(const SwForm& toxForm) - : mToxForm(toxForm) - {} + ToxTextGenerator(const SwForm& toxForm); + + ~ToxTextGenerator(); + /** Generate the text for an entry of a table of X (X is, e.g., content). * * This method will process the entries in @p entries, starting at @p indexOfEntryToProcess and @@ -47,9 +51,9 @@ public: sal_uInt16 indexOfEntryToProcess, sal_uInt16 numberOfEntriesToProcess, sal_uInt32 _nTOXSectNdIdx, const SwPageDesc* _pDefaultPageDesc); - private: const SwForm& mToxForm; + boost::shared_ptr<ToxLinkProcessor> mLinkProcessor; }; } diff --git a/sw/qa/cppunit/tox/test_ToxLinkProcessor.cxx b/sw/qa/cppunit/tox/test_ToxLinkProcessor.cxx new file mode 100644 index 0000000..9dc621f --- /dev/null +++ b/sw/qa/cppunit/tox/test_ToxLinkProcessor.cxx @@ -0,0 +1,133 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#include <stdexcept> + +#include <sal/types.h> + +#include <rtl/ustring.hxx> + +#include <ToxLinkProcessor.hxx> + +#include <cppunit/TestAssert.h> +#include <cppunit/TestFixture.h> +#include <cppunit/extensions/HelperMacros.h> +#include <cppunit/plugin/TestPlugIn.h> + +using namespace sw; + +class ToxLinkProcessorTest : public CppUnit::TestFixture +{ + void ExceptionIsThrownIfTooManyLinksAreClosed(); + void AddingAndClosingTwoLinksResultsInTwoClosedLinks(); + void LinkIsCreatedCorrectly(); + void LinkSequenceIsPreserved(); + + CPPUNIT_TEST_SUITE(ToxLinkProcessorTest); + CPPUNIT_TEST(ExceptionIsThrownIfTooManyLinksAreClosed); + CPPUNIT_TEST(AddingAndClosingTwoLinksResultsInTwoClosedLinks); + CPPUNIT_TEST(LinkIsCreatedCorrectly); + CPPUNIT_TEST(LinkSequenceIsPreserved); + CPPUNIT_TEST_SUITE_END(); +public: + static const OUString STYLE_NAME_1; + static const OUString STYLE_NAME_2; + static const sal_uInt16 POOL_ID_1; + static const sal_uInt16 POOL_ID_2; + static const OUString URL_1; + static const OUString URL_2; +}; + +const OUString ToxLinkProcessorTest::STYLE_NAME_1 = "anyStyle1"; +const OUString ToxLinkProcessorTest::STYLE_NAME_2 = "anyStyle2"; +const OUString ToxLinkProcessorTest::URL_1 = "anyUrl1"; +const OUString ToxLinkProcessorTest::URL_2 = "anyUrl2"; +const sal_uInt16 ToxLinkProcessorTest::POOL_ID_1 = 42; +const sal_uInt16 ToxLinkProcessorTest::POOL_ID_2 = 43; + +void +ToxLinkProcessorTest::ExceptionIsThrownIfTooManyLinksAreClosed() +{ + ToxLinkProcessor sut; + sut.StartNewLink(0, STYLE_NAME_1); + sut.CloseLink(1, URL_1); + CPPUNIT_ASSERT_THROW(sut.CloseLink(1, URL_1), std::runtime_error); +} + +void +ToxLinkProcessorTest::AddingAndClosingTwoLinksResultsInTwoClosedLinks() +{ + ToxLinkProcessor sut; + sut.StartNewLink(0, STYLE_NAME_1); + sut.StartNewLink(0, STYLE_NAME_2); + sut.CloseLink(1, URL_1); + sut.CloseLink(1, URL_2); + CPPUNIT_ASSERT_EQUAL(2u, static_cast<unsigned>(sut.mClosedLinks.size())); + CPPUNIT_ASSERT_MESSAGE("no links are open", sut.mStartedLinks.empty()); +} + +class ToxLinkProcessorWithOverriddenObtainPoolId : public ToxLinkProcessor { +public: + /*virtual*/ sal_uInt16 + ObtainPoolId(const OUString& characterStyle) const { + if (characterStyle == ToxLinkProcessorTest::STYLE_NAME_1) { + return ToxLinkProcessorTest::POOL_ID_1; + } + if (characterStyle == ToxLinkProcessorTest::STYLE_NAME_2) { + return ToxLinkProcessorTest::POOL_ID_2; + } + return 0; + } +}; + +void +ToxLinkProcessorTest::LinkIsCreatedCorrectly() +{ + // obtainpoolid needs to be overridden to check what we are + ToxLinkProcessorWithOverriddenObtainPoolId sut; + + sut.StartNewLink(0, STYLE_NAME_1); + sut.CloseLink(1, URL_1); + + CPPUNIT_ASSERT_EQUAL_MESSAGE("Style is stored correctly in link", STYLE_NAME_1, sut.mClosedLinks.at(0).mINetFmt.GetVisitedFmt()); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Url is stored correctly in link", URL_1, sut.mClosedLinks.at(0).mINetFmt.GetValue()); +} + +void +ToxLinkProcessorTest::LinkSequenceIsPreserved() +{ + + // obtainpoolid needs to be overridden to check what we are + ToxLinkProcessorWithOverriddenObtainPoolId sut; + + sut.StartNewLink(0, STYLE_NAME_1); + sut.StartNewLink(0, STYLE_NAME_2); + sut.CloseLink(1, URL_2); + sut.CloseLink(1, URL_1); + + // check first closed element + CPPUNIT_ASSERT_EQUAL_MESSAGE("Style is stored correctly in link", + STYLE_NAME_2, sut.mClosedLinks.at(0).mINetFmt.GetVisitedFmt()); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Pool id is stored correctly in link", + POOL_ID_2, sut.mClosedLinks.at(0).mINetFmt.GetINetFmtId()); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Url is stored correctly in link", + URL_2, sut.mClosedLinks.at(0).mINetFmt.GetValue()); + // check second closed element + CPPUNIT_ASSERT_EQUAL_MESSAGE("Style is stored correctly in link", + STYLE_NAME_1, sut.mClosedLinks.at(1).mINetFmt.GetVisitedFmt()); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Pool id is stored correctly in link", + POOL_ID_1, sut.mClosedLinks.at(1).mINetFmt.GetINetFmtId()); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Url is stored correctly in link", + URL_1, sut.mClosedLinks.at(1).mINetFmt.GetValue()); +} + +// Put the test suite in the registry +CPPUNIT_TEST_SUITE_REGISTRATION(ToxLinkProcessorTest); + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/core/tox/ToxLinkProcessor.cxx b/sw/source/core/tox/ToxLinkProcessor.cxx new file mode 100644 index 0000000..e236f00 --- /dev/null +++ b/sw/source/core/tox/ToxLinkProcessor.cxx @@ -0,0 +1,70 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#include "ToxLinkProcessor.hxx" + +#include "SwStyleNameMapper.hxx" +#include "ndtxt.hxx" + +#include <boost/foreach.hpp> +#include <stdexcept> + +namespace sw { + +void +ToxLinkProcessor::StartNewLink(sal_Int32 startPosition, const OUString& characterStyle) +{ + mStartedLinks.push_back(StartedLink(startPosition, characterStyle)); +} + +void +ToxLinkProcessor::CloseLink(sal_Int32 endPosition, const OUString& url) +{ + if (mStartedLinks.empty()) { + throw std::runtime_error("ToxLinkProcessor: More calls for CloseLink() than open links exist."); + } + StartedLink startedLink = mStartedLinks.back(); + mStartedLinks.pop_back(); + + if (url.isEmpty()) { + return; + } + + ClosedLink closedLink(url, startedLink.mStartPosition, endPosition); + + const OUString& characterStyle = startedLink.mCharacterStyle; + sal_uInt16 poolId = ObtainPoolId(characterStyle); + closedLink.mINetFmt.SetVisitedFmtAndId(characterStyle, poolId); + closedLink.mINetFmt.SetINetFmtAndId(characterStyle, poolId); + + mClosedLinks.push_back(closedLink); +} + +sal_uInt16 +ToxLinkProcessor::ObtainPoolId(const OUString& characterStyle) const +{ + if (characterStyle.isEmpty()) { + return USHRT_MAX; + } + else { + return SwStyleNameMapper::GetPoolIdFromUIName(characterStyle, nsSwGetPoolIdFromName::GET_POOLID_CHRFMT); + } +} + + +void +ToxLinkProcessor::InsertLinkAttributes(SwTxtNode& node) +{ + BOOST_FOREACH(ClosedLink& clink, mClosedLinks) { + node.InsertItem(clink.mINetFmt, clink.mStartTextPos, clink.mEndTextPos); + } +} + +} + diff --git a/sw/source/core/tox/ToxTextGenerator.cxx b/sw/source/core/tox/ToxTextGenerator.cxx index 8554c88..86e8777 100644 --- a/sw/source/core/tox/ToxTextGenerator.cxx +++ b/sw/source/core/tox/ToxTextGenerator.cxx @@ -34,22 +34,12 @@ #include "DocumentSettingManager.hxx" #include "SwStyleNameMapper.hxx" #include "ToxWhitespaceStripper.hxx" +#include "ToxLinkProcessor.hxx" #include "editeng/tstpitem.hxx" #include "editeng/lrspitem.hxx" #include "rtl/ustring.hxx" -struct LinkStruct -{ - SwFmtINetFmt aINetFmt; - sal_Int32 nStartTextPos, nEndTextPos; - - LinkStruct( const OUString& rURL, sal_Int32 nStart, sal_Int32 nEnd ) - : aINetFmt( rURL, OUString()), - nStartTextPos( nStart), - nEndTextPos(nEnd) {} -}; - /// Generate String according to the Form and remove the /// special characters 0-31 and 255. static OUString lcl_GetNumString( const SwTOXSortTabBase& rBase, bool bUsePrefix, sal_uInt8 nLevel ) @@ -70,18 +60,22 @@ static OUString lcl_GetNumString( const SwTOXSortTabBase& rBase, bool bUsePrefix return sRet; } -typedef std::vector<LinkStruct*> LinkStructArr; - namespace sw { +ToxTextGenerator::ToxTextGenerator(const SwForm& toxForm) +:mToxForm(toxForm), + mLinkProcessor(new ToxLinkProcessor()) +{;} + +ToxTextGenerator::~ToxTextGenerator() +{;} + // Add parameter <_TOXSectNdIdx> and <_pDefaultPageDesc> in order to control, // which page description is used, no appropriate one is found. void ToxTextGenerator::GenerateText(SwDoc* pDoc, const std::vector<SwTOXSortTabBase*> &entries, sal_uInt16 indexOfEntryToProcess, sal_uInt16 numberOfEntriesToProcess, sal_uInt32 _nTOXSectNdIdx, const SwPageDesc* _pDefaultPageDesc) { - LinkStructArr aLinkArr; - // pTOXNd is only set at the first mark SwTxtNode* pTOXNd = (SwTxtNode*)entries.at(indexOfEntryToProcess)->pTOXNd; // FIXME this operates directly on the node text @@ -97,9 +91,6 @@ void ToxTextGenerator::GenerateText(SwDoc* pDoc, const std::vector<SwTOXSortTabB OSL_ENSURE( nLvl < mToxForm.GetFormMax(), "invalid FORM_LEVEL"); SvxTabStopItem aTStops( 0, 0, SVX_TAB_ADJUST_DEFAULT, RES_PARATR_TABSTOP ); - sal_Int32 nLinkStartPosition = -1; - OUString sLinkCharacterStyle; // default to "Default" character style - which is none - OUString sURL; // create an enumerator // #i21237# SwFormTokens aPattern = mToxForm.GetPattern(nLvl); @@ -276,36 +267,11 @@ void ToxTextGenerator::GenerateText(SwDoc* pDoc, const std::vector<SwTOXSortTabB break; case TOKEN_LINK_START: - nLinkStartPosition = rTxt.getLength(); - sLinkCharacterStyle = aToken.sCharStyleName; - break; + mLinkProcessor->StartNewLink(rTxt.getLength(), aToken.sCharStyleName); + break; case TOKEN_LINK_END: - //TODO: only paired start/end tokens are valid - if (nLinkStartPosition != -1) - { - SwIndex aIdx( pTOXNd, nLinkStartPosition ); - // pTOXNd->Erase( aIdx, SwForm::nFormLinkSttLen ); - sal_Int32 nEnd = rTxt.getLength(); - - if( sURL.isEmpty() ) - { - sURL = rBase.GetURL(); - if( sURL.isEmpty() ) - break; - } - LinkStruct* pNewLink = new LinkStruct(sURL, nLinkStartPosition, - nEnd); - const sal_uInt16 nPoolId = - sLinkCharacterStyle.isEmpty() - ? USHRT_MAX - : SwStyleNameMapper::GetPoolIdFromUIName( sLinkCharacterStyle, nsSwGetPoolIdFromName::GET_POOLID_CHRFMT ); - pNewLink->aINetFmt.SetVisitedFmtAndId( sLinkCharacterStyle, nPoolId ); - pNewLink->aINetFmt.SetINetFmtAndId( sLinkCharacterStyle, nPoolId ); - aLinkArr.push_back(pNewLink); - nLinkStartPosition = -1; - sLinkCharacterStyle = ""; - } + mLinkProcessor->CloseLink(rTxt.getLength(), rBase.GetURL()); break; case TOKEN_AUTHORITY: @@ -339,13 +305,7 @@ void ToxTextGenerator::GenerateText(SwDoc* pDoc, const std::vector<SwTOXSortTabB pTOXNd->SetAttr( aTStops ); } - - for(LinkStructArr::const_iterator i = aLinkArr.begin(); i != aLinkArr.end(); ++i) - { - pTOXNd->InsertItem((*i)->aINetFmt, (*i)->nStartTextPos, - (*i)->nEndTextPos); - delete (*i); - } + mLinkProcessor->InsertLinkAttributes(*pTOXNd); } } // end namespace sw
_______________________________________________ Libreoffice-commits mailing list libreoffice-comm...@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/libreoffice-commits