#! /usr/bin/env python # -*- tab-width: 4; indent-tabs-mode: nil; py-indent-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/. # This file incorporates work covered by the following license notice: # Licensed to the Apache Software Foundation (ASF) under one or more # contributor license agreements. See the NOTICE file distributed # with this work for additional information regarding copyright # ownership. The ASF licenses this file to you under the Apache # License, Version 2.0 (the "License"); you may not use this file # except in compliance with the License. You may obtain a copy of # the License at http://www.apache.org/licenses/LICENSE-2.0. import unittest import random import os.path from hashlib import sha1 from tempfile import TemporaryDirectory from org.libreoffice.unotest import UnoInProcess, mkPropertyValues, systemPathToFileUrl from com.sun.star.text.ControlCharacter import PARAGRAPH_BREAK class CheckBookmarks(unittest.TestCase): expectedHashes = { 'nSetupHash': 0x8f88ee1a13a55d6024f58f470723b5174dfa21bb, 'nInsertRandomHash': 0x5f27e87e16d2cb3ff0bcb24237aa30da3b84cf24, 'nDeleteRandomHash': 0x1bdaa7773cbfc73a4dc0bb3e0f801b98f648e8e7, 'nLinebreakHash': 0x3f30a35f195efcfe0373a3e439de05087a2ad37c, 'nOdfReloadHash': 0x3f30a35f195efcfe0373a3e439de05087a2ad37c, 'nMsWordReloadHash': 0x3f30a35f195efcfe0373a3e439de05087a2ad37c, } @classmethod def setUpClass(cls): cls._uno = UnoInProcess() cls._uno.setUp() cls._xDoc = cls._uno.openEmptyWriterDoc() smgr = cls._uno.xContext.ServiceManager cls._desktop = smgr.createInstanceWithContext("com.sun.star.frame.Desktop", cls._uno.xContext) @classmethod def tearDownClass(cls): cls._uno.tearDown() # HACK in case cls._xDoc holds a UNO proxy to an SwXTextDocument (whose dtor calls # Application::GetSolarMutex via sw::UnoImplPtrDeleter), which would potentially only be # garbage-collected after VCL has already been deinitialized: cls._xDoc = None def test_bookmarks(self): self.xDoc = self.__class__._xDoc self.xText = self.xDoc.getText() ## setting and testing bookmarks self.setupBookmarks() self.assertEqual(self.expectedHashes['nSetupHash'], self.getBookmarksHash(self.xDoc)) ## modifying bookmarks and testing again self.insertRandomParts(200177) self.assertEqual(self.expectedHashes['nInsertRandomHash'], self.getBookmarksHash(self.xDoc)) ## modifying bookmarks and testing again self.deleteRandomParts(4711) self.assertEqual(self.expectedHashes['nDeleteRandomHash'], self.getBookmarksHash(self.xDoc)) ## adding line breaks and testing again self.insertLinebreaks(7) self.assertEqual(self.expectedHashes['nLinebreakHash'], self.getBookmarksHash(self.xDoc)) ## reloading document and testing again with TemporaryDirectory() as tempdir: xOdfReloadedDoc = self.reloadFrom(tempdir, "writer8", "odt") self.assertEqual(self.expectedHashes['nOdfReloadHash'], self.getBookmarksHash(xOdfReloadedDoc)) xOdfReloadedDoc.close(True) ## reloading document as MS Word 97 doc and testing again ## MsWord Hash is unstable over different systems # xMsWordReloadedDoc = self.reloadFrom(tempdir, "MS Word 97", "doc") # self.assertEqual(self.expectedHashes['nMsWordReloadHash'], # self.getBookmarksHash(xMsWordReloadedDoc)) # xMsWordReloadedDoc.close(True) print('tests ok') def setupBookmarks(self): xCursor = self.xText.createTextCursor() for nPara in range(10): for nBookmark in range(100): s = "P{}word{}".format(nPara, nBookmark) xCursor.gotoEnd(False) xCursor.setString(s) xBookmark = self.xDoc.createInstance("com.sun.star.text.Bookmark") xBookmark.setName(s) self.xText.insertTextContent(xCursor, xBookmark, True) xCursor.End.setString(" ") self.xText.insertControlCharacter(xCursor.End, PARAGRAPH_BREAK, False) def getBookmarksHash(self, doc): _hash = sha1() xBookmarks = doc.getBookmarks() for xBookmark in xBookmarks: s = '{}:{};'.format(xBookmark.Name, xBookmark.getAnchor().getString().replace("\r\n", "\n")) _hash.update(str.encode(s)) return int(_hash.hexdigest(), 16) def insertRandomParts(self, seed): random.seed(seed) xCursor = self.xText.createTextCursor() for i in range(600): xCursor.goRight(random.randrange(100), False) xCursor.setString(str(random.getrandbits(64))) def deleteRandomParts(self, seed): random.seed(seed) xCursor = self.xText.createTextCursor() for i in range(600): xCursor.goRight(random.randrange(100), False) xCursor.goRight(random.randrange(20), True) xCursor.setString("") def insertLinebreaks(self, seed): random.seed(seed) xCursor = self.xText.createTextCursor() for i in range(30): xCursor.goRight(random.randrange(300), False) self.xText.insertControlCharacter(xCursor, PARAGRAPH_BREAK, False) def reloadFrom(self, tempdir, sFilter, sExtension): sFileUrl = os.path.join(tempdir, "Bookmarktest.{}".format(sExtension)) sFileUrl = systemPathToFileUrl(sFileUrl) store_props = mkPropertyValues(Override=True, FilterName=sFilter) self.xDoc.storeToURL(sFileUrl, store_props) desktop = self.__class__._desktop load_props = mkPropertyValues(Hidden=True, ReadOnly=False) return desktop.loadComponentFromURL(sFileUrl, "_default", 0, load_props) if __name__ == '__main__': unittest.main()