testDms.py 131 KB
Newer Older
1
# -*- coding: utf-8 -*-
Bartek Górny's avatar
Bartek Górny committed
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
##############################################################################
#
# Copyright (c) 2004 Nexedi SARL and Contributors. All Rights Reserved.
#          Sebastien Robin <seb@nexedi.com>
#
# WARNING: This program as such is intended to be used by professional
# programmers who take the whole responsability of assessing all potential
# consequences resulting from its eventual inadequacies and bugs
# End users who are looking for a ready-to-use solution with commercial
# garantees and support are strongly adviced to contract a Free Software
# Service Company
#
# This program is Free Software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
##############################################################################

30 31 32
"""
  A test suite for Document Management System functionality.
  This will test:
Bartek Górny's avatar
Bartek Górny committed
33
  - creating Text Document objects
34 35 36 37 38 39 40 41 42 43 44 45 46
  - setting properties of a document, assigning local roles
  - setting relations between documents (explicit and implicity)
  - searching in basic and advanced modes
  - document publication workflow settings
  - sourcing external content
  - (...)
  This will NOT test:
  - contributing files of various types
  - convertion between many formats
  - metadata extraction and editing
  - email ingestion
  These are subject to another suite "testIngestion".
"""
Bartek Górny's avatar
Bartek Górny committed
47

48
import unittest
49
import time
50
import StringIO
51
from subprocess import Popen, PIPE
52
from cgi import FieldStorage
53
from unittest import expectedFailure
Bartek Górny's avatar
Bartek Górny committed
54

55
import ZPublisher.HTTPRequest
Bartek Górny's avatar
Bartek Górny committed
56 57
from Testing import ZopeTestCase
from Products.ERP5Type.tests.ERP5TypeTestCase import ERP5TypeTestCase
Jérome Perrin's avatar
Jérome Perrin committed
58
from Products.ERP5Type.tests.ERP5TypeTestCase import  _getConversionServerDict
59
from Products.ERP5Type.tests.utils import FileUpload
60
from Products.ERP5Type.tests.utils import DummyLocalizer
61
from Products.ERP5OOo.OOoUtils import OOoBuilder
62
from Products.CMFCore.utils import getToolByName
Jérome Perrin's avatar
Jérome Perrin committed
63
from AccessControl.SecurityManagement import newSecurityManager
64
from AccessControl import getSecurityManager
Bartek Górny's avatar
Bartek Górny committed
65
from zLOG import LOG
66
from Products.ERP5.Document.Document import NotConvertedError
67
from Products.ERP5Form.PreferenceTool import Priority
68
from Products.ERP5Type.tests.utils import createZODBPythonScript
69
from Products.ERP5Type.Globals import get_request
Bartek Górny's avatar
Bartek Górny committed
70
import os
71 72
from threading import Thread
import httplib
73
import urllib
74
import difflib
75
import re
76
from AccessControl import Unauthorized
77
from Products.ERP5Type import Permissions
78
from DateTime import DateTime
Bartek Górny's avatar
Bartek Górny committed
79

Bartek Górny's avatar
Bartek Górny committed
80 81
QUIET = 0

82
TEST_FILES_HOME = os.path.join(os.path.dirname(__file__), 'test_document')
Nicolas Delaby's avatar
Nicolas Delaby committed
83
FILENAME_REGULAR_EXPRESSION = "(?P<reference>[A-Z]{3,10})-(?P<language>[a-z]{2})-(?P<version>[0-9]{3})"
84
REFERENCE_REGULAR_EXPRESSION = "(?P<reference>[A-Z]{3,10})(-(?P<language>[a-z]{2}))?(-(?P<version>[0-9]{3}))?"
85

Bartek Górny's avatar
Bartek Górny committed
86
def makeFilePath(name):
87
  return os.path.join(os.path.dirname(__file__), 'test_document', name)
Bartek Górny's avatar
Bartek Górny committed
88

89 90 91 92 93
def makeFileUpload(name, as_name=None):
  if as_name is None:
    as_name = name
  path = makeFilePath(name)
  return FileUpload(path, as_name)
Bartek Górny's avatar
Bartek Górny committed
94

Ivan Tyagov's avatar
Ivan Tyagov committed
95 96 97 98 99 100 101
def getFileSize(name):
  path = makeFilePath(name)
  f = open(path, "r")
  file_size = len(f.read())
  f.close()
  return file_size

102
class TestDocumentMixin(ERP5TypeTestCase):
103

Arnaud Fontaine's avatar
Arnaud Fontaine committed
104 105
  business_template_list = ['erp5_core_proxy_field_legacy',
                            'erp5_jquery',
106
                            'erp5_full_text_mroonga_catalog',
Arnaud Fontaine's avatar
Arnaud Fontaine committed
107
                            'erp5_base',
108
                            'erp5_ingestion_mysql_innodb_catalog',
Arnaud Fontaine's avatar
Arnaud Fontaine committed
109
                            'erp5_ingestion',
110
                            'erp5_web',
Arnaud Fontaine's avatar
Arnaud Fontaine committed
111
                            'erp5_dms']
Ivan Tyagov's avatar
Ivan Tyagov committed
112

113
  def setUpOnce(self):
114 115
    # set a dummy localizer (because normally it is cookie based)
    self.portal.Localizer = DummyLocalizer()
Bartek Górny's avatar
Bartek Górny committed
116

117
  def afterSetUp(self):
118
    TestDocumentMixin.login(self)
119 120 121
    self.setDefaultSitePreference()
    self.setSystemPreference()
    self.tic()
122
    self.login()
123

124 125
  def setDefaultSitePreference(self):
    default_pref = self.portal.portal_preferences.default_site_preference
Jérome Perrin's avatar
Jérome Perrin committed
126 127 128
    conversion_dict = _getConversionServerDict()
    default_pref.setPreferredOoodocServerAddress(conversion_dict['hostname'])
    default_pref.setPreferredOoodocServerPortNumber(conversion_dict['port'])
Nicolas Delaby's avatar
Nicolas Delaby committed
129
    default_pref.setPreferredDocumentFilenameRegularExpression(FILENAME_REGULAR_EXPRESSION)
130
    default_pref.setPreferredDocumentReferenceRegularExpression(REFERENCE_REGULAR_EXPRESSION)
131
    if self.portal.portal_workflow.isTransitionPossible(default_pref, 'enable'):
132
      default_pref.enable()
133
    return default_pref
134

135 136 137 138 139
  def setSystemPreference(self):
    portal_type = 'System Preference'
    preference_list = self.portal.portal_preferences.contentValues(
                                                       portal_type=portal_type)
    if not preference_list:
140 141 142 143
      # create a Cache Factory for tests
      cache_factory = self.portal.portal_caches.newContent(portal_type = 'Cache Factory')
      cache_factory.cache_duration = 36000
      cache_plugin = cache_factory.newContent(portal_type='Ram Cache')
144
      cache_plugin.cache_expire_check_interval = 54000
145
      preference = self.portal.portal_preferences.newContent(title="Default System Preference",
146
                                                             # use local RAM based cache as some tests need it
147
                                                             preferred_conversion_cache_factory = cache_factory.getId(),
148
                                                             portal_type=portal_type)
149 150
    else:
      preference = preference_list[0]
151
    if self.portal.portal_workflow.isTransitionPossible(preference, 'enable'):
152 153 154
      preference.enable()
    return preference

Bartek Górny's avatar
Bartek Górny committed
155 156 157 158
  def getDocumentModule(self):
    return getattr(self.getPortal(),'document_module')

  def getBusinessTemplateList(self):
Arnaud Fontaine's avatar
Arnaud Fontaine committed
159
    return self.business_template_list
Bartek Górny's avatar
Bartek Górny committed
160 161

  def getNeededCategoryList(self):
162
    return ()
Bartek Górny's avatar
Bartek Górny committed
163

164
  def beforeTearDown(self):
165 166 167 168
    """
      Do some stuff after each test:
      - clear document module
    """
169
    self.abort()
170
    self.clearRestrictedSecurityHelperScript()
171
    activity_tool = self.portal.portal_activities
172 173
    activity_status = {m.processing_node < -1
                       for m in activity_tool.getMessageList()}
174 175 176 177
    if True in activity_status:
      activity_tool.manageClearActivities()
    else:
      assert not activity_status
178
    self.clearDocumentModule()
179

180 181
  conversion_format_permission_script_id_list = [
      'Document_checkConversionFormatPermission',
182
      'Image_checkConversionFormatPermission',
183
      'PDF_checkConversionFormatPermission']
184
  def clearRestrictedSecurityHelperScript(self):
185 186 187 188
    for script_id in self.conversion_format_permission_script_id_list:
      custom = self.getPortal().portal_skins.custom
      if script_id in custom.objectIds():
        custom.manage_delObjects(ids=[script_id])
189
        self.commit()
190

191
  def clearDocumentModule(self):
Bartek Górny's avatar
Bartek Górny committed
192
    """
193
      Remove everything after each run
Bartek Górny's avatar
Bartek Górny committed
194
    """
195
    self.abort()
196
    doc_module = self.getDocumentModule()
197
    doc_module.manage_delObjects(list(doc_module.objectIds()))
198 199
    self.tic()

200 201 202 203 204 205 206 207 208 209
class TestDocument(TestDocumentMixin):
  """
    Test basic document - related operations
  """

  def getTitle(self):
    return "DMS"

  ## setup

210

211
  ## helper methods
Bartek Górny's avatar
Bartek Górny committed
212

Nicolas Delaby's avatar
Nicolas Delaby committed
213
  def createTestDocument(self, filename=None, portal_type='Text', reference='TEST', version='002', language='en'):
Bartek Górny's avatar
Bartek Górny committed
214 215 216
    """
      Creates a text document
    """
217
    dm=self.getPortal().document_module
218
    doctext=dm.newContent(portal_type=portal_type)
Nicolas Delaby's avatar
Nicolas Delaby committed
219 220
    if filename is not None:
      f = open(makeFilePath(filename), 'rb')
Bartek Górny's avatar
Bartek Górny committed
221 222 223 224 225
      doctext.setTextContent(f.read())
      f.close()
    doctext.setReference(reference)
    doctext.setVersion(version)
    doctext.setLanguage(language)
226
    return doctext
Bartek Górny's avatar
Bartek Górny committed
227

Bartek Górny's avatar
Bartek Górny committed
228 229 230 231 232 233 234 235
  def getDocument(self, id):
    """
      Returns a document with given ID in the
      document module.
    """
    document_module = self.portal.document_module
    return getattr(document_module, id)

236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268
  def getPreferences(self, image_display):
    preference_tool = self.portal.getPortalObject().portal_preferences
    height_preference = 'preferred_%s_image_height' % (image_display,)
    width_preference = 'preferred_%s_image_width' % (image_display,)
    height = int(preference_tool.getPreference(height_preference))
    width = int(preference_tool.getPreference(width_preference))
    return (width, height)

  def getURLSizeList(self, uri, **kw):
    # __ac=RVJQNVR5cGVUZXN0Q2FzZTo%3D is encoded ERP5TypeTestCase with empty password
    url = '%s?%s&__ac=%s' %(uri, urllib.urlencode(kw), 'RVJQNVR5cGVUZXN0Q2FzZTo%3D')
    format=kw.get('format', 'jpeg')
    infile = urllib.urlopen(url)
    # save as file with proper incl. format filename (for some reasons PIL uses this info)
    filename = "%s%stest-image-format-resize.%s" %(os.getcwd(), os.sep, format)
    f = open(filename, "w")
    image_data = infile.read()
    f.write(image_data)
    f.close()
    infile.close()
    file_size = len(image_data)
    try:
      from PIL import Image
      image = Image.open(filename)
      image_size = image.size
    except ImportError:
      identify_output = Popen(['identify', filename],
                              stdout=PIPE).communicate()[0]
      image_size = tuple(map(lambda x:int(x),
                             identify_output.split()[2].split('x')))
    os.remove(filename)
    return image_size, file_size

269 270
  ## tests

271
  def test_01_HasEverything(self):
Bartek Górny's avatar
Bartek Górny committed
272 273 274
    """
      Standard test to make sure we have everything we need - all the tools etc
    """
275 276 277 278 279 280
    self.assertNotEqual(self.getCategoryTool(), None)
    self.assertNotEqual(self.getSimulationTool(), None)
    self.assertNotEqual(self.getTypeTool(), None)
    self.assertNotEqual(self.getSQLConnection(), None)
    self.assertNotEqual(self.getCatalogTool(), None)
    self.assertNotEqual(self.getWorkflowTool(), None)
281

282
  def test_02_RevisionSystem(self):
Bartek Górny's avatar
Bartek Górny committed
283 284 285 286
    """
      Test revision mechanism
    """
    # create a test document
287
    # revision should be 1
Bartek Górny's avatar
Bartek Górny committed
288
    # upload file (can be the same) into it
289
    # revision should now be 2
290 291
    # edit the document with any value or no values
    # revision should now be 3
Bartek Górny's avatar
Bartek Górny committed
292
    # contribute the same file through portal_contributions
293 294
    # the same document should now have revision 4 (because it should have done mergeRevision)
    # getRevisionList should return (1, 2, 3, 4)
295 296 297 298 299 300 301
    filename = 'TEST-en-002.doc'
    file = makeFileUpload(filename)
    document = self.portal.portal_contributions.newContent(file=file)
    self.tic()
    document_url = document.getRelativeUrl()
    def getTestDocument():
      return self.portal.restrictedTraverse(document_url)
302
    self.assertEqual(getTestDocument().getRevision(), '1')
303 304
    getTestDocument().edit(file=file)
    self.tic()
305
    self.assertEqual(getTestDocument().getRevision(), '2')
306 307
    getTestDocument().edit(title='Hey Joe')
    self.tic()
308
    self.assertEqual(getTestDocument().getRevision(), '3')
309 310
    another_document = self.portal.portal_contributions.newContent(file=file)
    self.tic()
311 312
    self.assertEqual(getTestDocument().getRevision(), '4')
    self.assertEqual(getTestDocument().getRevisionList(), ['1', '2', '3', '4'])
Bartek Górny's avatar
Bartek Górny committed
313

314
  def test_03_Versioning(self):
Bartek Górny's avatar
Bartek Górny committed
315 316 317
    """
      Test versioning
    """
318 319 320 321 322 323 324 325 326 327 328 329 330 331 332
    # create a document 1, set coordinates (reference=TEST, version=002, language=en)
    # create a document 2, set coordinates (reference=TEST, version=002, language=en)
    # create a document 3, set coordinates (reference=TEST, version=004, language=en)
    # run isVersionUnique on 1, 2, 3 (should return False, False, True)
    # change version of 2 to 003
    # run isVersionUnique on 1, 2, 3  (should return True)
    # run getLatestVersionValue on all (should return 3)
    # run getVersionValueList on 2 (should return [3, 2, 1])
    document_module = self.getDocumentModule()
    docs = {}
    docs[1] = self.createTestDocument(reference='TEST', version='002', language='en')
    docs[2] = self.createTestDocument(reference='TEST', version='002', language='en')
    docs[3] = self.createTestDocument(reference='TEST', version='004', language='en')
    docs[4] = self.createTestDocument(reference='ANOTHER', version='002', language='en')
    self.tic()
333 334 335
    self.assertFalse(docs[1].isVersionUnique())
    self.assertFalse(docs[2].isVersionUnique())
    self.assertTrue(docs[3].isVersionUnique())
336 337
    docs[2].setVersion('003')
    self.tic()
338 339 340 341 342 343
    self.assertTrue(docs[1].isVersionUnique())
    self.assertTrue(docs[2].isVersionUnique())
    self.assertTrue(docs[3].isVersionUnique())
    self.assertTrue(docs[1].getLatestVersionValue() == docs[3])
    self.assertTrue(docs[2].getLatestVersionValue() == docs[3])
    self.assertTrue(docs[3].getLatestVersionValue() == docs[3])
344
    version_list = [br.getRelativeUrl() for br in docs[2].getVersionValueList()]
345
    self.assertTrue(version_list == [docs[3].getRelativeUrl(), docs[2].getRelativeUrl(), docs[1].getRelativeUrl()])
Bartek Górny's avatar
Bartek Górny committed
346

347
  def test_04_VersioningWithLanguage(self):
Bartek Górny's avatar
Bartek Górny committed
348 349 350 351 352 353 354 355 356
    """
      Test versioning with multi-language support
    """
    # create empty test documents, set their coordinates as follows:
    # (1) TEST, 002, en
    # (2) TEST, 002, fr
    # (3) TEST, 002, pl
    # (4) TEST, 003, en
    # (5) TEST, 003, sp
357
    # the following calls (on any doc) should produce the following output:
Bartek Górny's avatar
Bartek Górny committed
358 359 360 361 362 363 364
    # getOriginalLanguage() = 'en'
    # getLanguageList = ('en', 'fr', 'pl', 'sp')
    # getLatestVersionValue() = 4
    # getLatestVersionValue('en') = 4
    # getLatestVersionValue('fr') = 2
    # getLatestVersionValue('pl') = 3
    # getLatestVersionValue('ru') = None
365
    # change user language into 'sp'
Bartek Górny's avatar
Bartek Górny committed
366
    # getLatestVersionValue() = 5
367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385
    # add documents:
    # (6) TEST, 004, pl
    # (7) TEST, 004, en
    # getLatestVersionValue() = 7
    localizer = self.portal.Localizer
    document_module = self.getDocumentModule()
    docs = {}
    docs[1] = self.createTestDocument(reference='TEST', version='002', language='en')
    time.sleep(1) # time span here because catalog records only full seconds
    docs[2] = self.createTestDocument(reference='TEST', version='002', language='fr')
    time.sleep(1)
    docs[3] = self.createTestDocument(reference='TEST', version='002', language='pl')
    time.sleep(1)
    docs[4] = self.createTestDocument(reference='TEST', version='003', language='en')
    time.sleep(1)
    docs[5] = self.createTestDocument(reference='TEST', version='003', language='sp')
    time.sleep(1)
    self.tic()
    doc = docs[2] # can be any
386 387 388 389 390 391 392
    self.assertTrue(doc.getOriginalLanguage() == 'en')
    self.assertTrue(doc.getLanguageList() == ['en', 'fr', 'pl', 'sp'])
    self.assertTrue(doc.getLatestVersionValue() == docs[4]) # there are two latest - it chooses the one in user language
    self.assertTrue(doc.getLatestVersionValue('en') == docs[4])
    self.assertTrue(doc.getLatestVersionValue('fr') == docs[2])
    self.assertTrue(doc.getLatestVersionValue('pl') == docs[3])
    self.assertTrue(doc.getLatestVersionValue('ru') == None)
393
    localizer.changeLanguage('sp') # change user language
394
    self.assertTrue(doc.getLatestVersionValue() == docs[5]) # there are two latest - it chooses the one in user language
395 396 397
    docs[6] = document_module.newContent(reference='TEST', version='004', language='pl')
    docs[7] = document_module.newContent(reference='TEST', version='004', language='en')
    self.tic()
398
    self.assertTrue(doc.getLatestVersionValue() == docs[7]) # there are two latest, neither in user language - it chooses the one in original language
Bartek Górny's avatar
Bartek Górny committed
399

400
  def test_06_testExplicitRelations(self):
Bartek Górny's avatar
Bartek Górny committed
401 402 403 404 405 406 407 408 409 410 411 412
    """
      Test explicit relations.
      Explicit relations are just like any other relation, so no need to test them here
      except for similarity cloud which we test.
    """
    # create test documents:
    # (1) TEST, 002, en
    # (2) TEST, 003, en
    # (3) ONE, 001, en
    # (4) TWO, 001, en
    # (5) THREE, 001, en
    # set 3 similar to 1, 4 to 3, 5 to 4
Romain Courteaud's avatar
Romain Courteaud committed
413
    # getSimilarCloudValueList on 4 should return 1, 3 and 5
Bartek Górny's avatar
Bartek Górny committed
414
    # getSimilarCloudValueList(depth=1) on 4 should return 3 and 5
Fabien Morin's avatar
Fabien Morin committed
415

416 417 418 419 420 421 422 423
    # create documents for test version and language
    # reference, version, language
    kw = {'portal_type': 'Drawing'}
    document1 = self.portal.document_module.newContent(**kw)
    document2 = self.portal.document_module.newContent(**kw)
    document3 = self.portal.document_module.newContent(**kw)
    document4 = self.portal.document_module.newContent(**kw)
    document5 = self.portal.document_module.newContent(**kw)
Fabien Morin's avatar
Fabien Morin committed
424 425

    document6 = self.portal.document_module.newContent(reference='SIX', version='001',
426
                                                                                    language='en',  **kw)
Fabien Morin's avatar
Fabien Morin committed
427
    document7 = self.portal.document_module.newContent(reference='SEVEN', version='001',
428
                                                                                    language='en',  **kw)
Fabien Morin's avatar
Fabien Morin committed
429
    document8 = self.portal.document_module.newContent(reference='SEVEN', version='001',
430
                                                                                    language='fr',  **kw)
Fabien Morin's avatar
Fabien Morin committed
431
    document9 = self.portal.document_module.newContent(reference='EIGHT', version='001',
432
                                                                                    language='en',  **kw)
Fabien Morin's avatar
Fabien Morin committed
433
    document10 = self.portal.document_module.newContent(reference='EIGHT', version='002',
434
                                                                                      language='en',  **kw)
Fabien Morin's avatar
Fabien Morin committed
435
    document11 = self.portal.document_module.newContent(reference='TEN', version='001',
436
                                                                                      language='en',  **kw)
Fabien Morin's avatar
Fabien Morin committed
437
    document12 = self.portal.document_module.newContent(reference='TEN', version='001',
438
                                                                                      language='fr',  **kw)
Fabien Morin's avatar
Fabien Morin committed
439
    document13 = self.portal.document_module.newContent(reference='TEN', version='002',
440
                                                                                      language='en',  **kw)
Romain Courteaud's avatar
Romain Courteaud committed
441 442 443 444

    document3.setSimilarValue(document1)
    document4.setSimilarValue(document3)
    document5.setSimilarValue(document4)
Fabien Morin's avatar
Fabien Morin committed
445

446 447 448
    document6.setSimilarValueList([document8,  document13])
    document7.setSimilarValue([document9])
    document11.setSimilarValue(document7)
Romain Courteaud's avatar
Romain Courteaud committed
449 450

    self.tic()
Fabien Morin's avatar
Fabien Morin committed
451

452 453
    #if user language is 'en'
    self.portal.Localizer.changeLanguage('en')
Romain Courteaud's avatar
Romain Courteaud committed
454

455
    # 4 is similar to 3 and 5, 3 similar to 1, last version are the same
Romain Courteaud's avatar
Romain Courteaud committed
456 457 458 459
    self.assertSameSet([document1, document3, document5],
                       document4.getSimilarCloudValueList())
    self.assertSameSet([document3, document5],
                       document4.getSimilarCloudValueList(depth=1))
Bartek Górny's avatar
Bartek Górny committed
460

Fabien Morin's avatar
Fabien Morin committed
461
    self.assertSameSet([document7, document13],
462
                       document6.getSimilarCloudValueList())
Fabien Morin's avatar
Fabien Morin committed
463
    self.assertSameSet([document10, document13],
464
                       document7.getSimilarCloudValueList())
Fabien Morin's avatar
Fabien Morin committed
465
    self.assertSameSet([document7, document13],
466
                       document9.getSimilarCloudValueList())
Fabien Morin's avatar
Fabien Morin committed
467
    self.assertSameSet([],
468 469
                       document10.getSimilarCloudValueList())
    # 11 similar to 7, last version of 7 (en) is 7, similar of 7 is 9, last version of 9 (en) is 10
Fabien Morin's avatar
Fabien Morin committed
470
    self.assertSameSet([document7, document10],
471
                       document11.getSimilarCloudValueList())
Fabien Morin's avatar
Fabien Morin committed
472
    self.assertSameSet([document6, document7],
473 474
                       document13.getSimilarCloudValueList())

475
    self.commit()
Fabien Morin's avatar
Fabien Morin committed
476

477 478
    # if user language is 'fr', test that latest documents are prefferable returned in user_language (if available)
    self.portal.Localizer.changeLanguage('fr')
Fabien Morin's avatar
Fabien Morin committed
479 480

    self.assertSameSet([document8, document13],
481
                       document6.getSimilarCloudValueList())
Fabien Morin's avatar
Fabien Morin committed
482
    self.assertSameSet([document6, document13],
483
                       document8.getSimilarCloudValueList())
Fabien Morin's avatar
Fabien Morin committed
484
    self.assertSameSet([document8, document10],
485
                       document11.getSimilarCloudValueList())
Fabien Morin's avatar
Fabien Morin committed
486
    self.assertSameSet([],
487
                       document12.getSimilarCloudValueList())
Fabien Morin's avatar
Fabien Morin committed
488
    self.assertSameSet([document6, document8],
489
                       document13.getSimilarCloudValueList())
Fabien Morin's avatar
Fabien Morin committed
490

491
    self.commit()
Fabien Morin's avatar
Fabien Morin committed
492

493 494
    # if user language is "bg"
    self.portal.Localizer.changeLanguage('bg')
Fabien Morin's avatar
Fabien Morin committed
495
    self.assertSameSet([document8, document13],
496 497
                       document6.getSimilarCloudValueList())

498
  def test_07_testImplicitRelations(self):
Bartek Górny's avatar
Bartek Górny committed
499 500 501 502
    """
      Test implicit (wiki-like) relations.
    """
    # XXX this test should be extended to check more elaborate language selection
503 504 505 506

    def sqlresult_to_document_list(result):
      return [i.getObject() for i in result]

Bartek Górny's avatar
Bartek Górny committed
507 508
    # create docs to be referenced:
    # (1) TEST, 002, en
509 510 511 512
    filename = 'TEST-en-002.odt'
    file = makeFileUpload(filename)
    document1 = self.portal.portal_contributions.newContent(file=file)

Bartek Górny's avatar
Bartek Górny committed
513
    # (2) TEST, 002, fr
514 515
    as_name = 'TEST-fr-002.odt'
    file = makeFileUpload(filename, as_name)
516 517
    document2 = self.portal.portal_contributions.newContent(file=file)

Bartek Górny's avatar
Bartek Górny committed
518
    # (3) TEST, 003, en
519 520
    as_name = 'TEST-en-003.odt'
    file = makeFileUpload(filename, as_name)
521 522
    document3 = self.portal.portal_contributions.newContent(file=file)

Bartek Górny's avatar
Bartek Górny committed
523 524
    # create docs to contain references in text_content:
    # REF, 001, en; "I use reference to look up TEST"
525 526 527 528
    filename = 'REF-en-001.odt'
    file = makeFileUpload(filename)
    document4 = self.portal.portal_contributions.newContent(file=file)

Bartek Górny's avatar
Bartek Górny committed
529
    # REF, 002, en; "I use reference to look up TEST"
530 531 532 533
    filename = 'REF-en-002.odt'
    file = makeFileUpload(filename)
    document5 = self.portal.portal_contributions.newContent(file=file)

Bartek Górny's avatar
Bartek Górny committed
534
    # REFLANG, 001, en: "I use reference and language to look up TEST-fr"
535 536 537 538
    filename = 'REFLANG-en-001.odt'
    file = makeFileUpload(filename)
    document6 = self.portal.portal_contributions.newContent(file=file)

Bartek Górny's avatar
Bartek Górny committed
539
    # REFVER, 001, en: "I use reference and version to look up TEST-002"
540 541 542 543
    filename = 'REFVER-en-001.odt'
    file = makeFileUpload(filename)
    document7 = self.portal.portal_contributions.newContent(file=file)

Bartek Górny's avatar
Bartek Górny committed
544
    # REFVERLANG, 001, en: "I use reference, version and language to look up TEST-002-en"
545 546 547 548 549
    filename = 'REFVERLANG-en-001.odt'
    file = makeFileUpload(filename)
    document8 = self.portal.portal_contributions.newContent(file=file)

    self.tic()
550 551
    # the implicit predecessor will find documents by reference.
    # version and language are not used.
Bartek Górny's avatar
Bartek Górny committed
552
    # the implicit predecessors should be:
553 554 555 556 557 558 559 560 561

    # for (1): REF-002, REFLANG, REFVER, REFVERLANG
    # document1's reference is TEST. getImplicitPredecessorValueList will
    # return latest version of documents which contains string "TEST".
    self.assertSameSet(
      [document5, document6, document7, document8],
      sqlresult_to_document_list(document1.getImplicitPredecessorValueList()))

    # clear transactional variable cache
562
    self.commit()
563 564 565 566 567 568 569 570 571 572 573 574

    # the implicit successors should be return document with appropriate
    # language.

    # if user language is 'en'.
    self.portal.Localizer.changeLanguage('en')

    self.assertSameSet(
      [document3],
      sqlresult_to_document_list(document5.getImplicitSuccessorValueList()))

    # clear transactional variable cache
575
    self.commit()
576 577 578 579 580 581 582 583

    # if user language is 'fr'.
    self.portal.Localizer.changeLanguage('fr')
    self.assertSameSet(
      [document2],
      sqlresult_to_document_list(document5.getImplicitSuccessorValueList()))

    # clear transactional variable cache
584
    self.commit()
585 586 587 588 589 590

    # if user language is 'ja'.
    self.portal.Localizer.changeLanguage('ja')
    self.assertSameSet(
      [document3],
      sqlresult_to_document_list(document5.getImplicitSuccessorValueList()))
Bartek Górny's avatar
Bartek Górny committed
591

592 593 594 595 596 597 598
    # with empty reference no implicit relation should exists even though some documents
    # used to reference us with previous reference
    document1.setReference(None)
    self.tic()
    self.assertSameSet([],
      sqlresult_to_document_list(document1.getImplicitPredecessorValueList()))

599 600 601 602
  def testOOoDocument_get_size(self):
    # test get_size on OOoDocument
    doc = self.portal.document_module.newContent(portal_type='Spreadsheet')
    doc.edit(file=makeFileUpload('import_data_list.ods'))
603
    self.assertEqual(len(makeFileUpload('import_data_list.ods').read()),
604 605 606 607 608 609
                      doc.get_size())

  def testTempOOoDocument_get_size(self):
    # test get_size on temporary OOoDocument
    from Products.ERP5Type.Document import newTempOOoDocument
    doc = newTempOOoDocument(self.portal, 'tmp')
610
    doc.edit(data='OOo')
611
    self.assertEqual(len('OOo'), doc.get_size())
612

613 614 615
  def testOOoDocument_hasData(self):
    # test hasData on OOoDocument
    doc = self.portal.document_module.newContent(portal_type='Spreadsheet')
616
    self.assertFalse(doc.hasData())
617
    doc.edit(file=makeFileUpload('import_data_list.ods'))
618
    self.assertTrue(doc.hasData())
619 620 621 622 623

  def testTempOOoDocument_hasData(self):
    # test hasData on TempOOoDocument
    from Products.ERP5Type.Document import newTempOOoDocument
    doc = newTempOOoDocument(self.portal, 'tmp')
624
    self.assertFalse(doc.hasData())
625
    doc.edit(file=makeFileUpload('import_data_list.ods'))
626
    self.assertTrue(doc.hasData())
627

628
  def test_Owner_Base_download(self):
629 630 631
    # tests that owners can download original documents and OOo
    # documents, and all headers (including filenames) are set
    # correctly
632
    doc = self.portal.document_module.newContent(
Nicolas Delaby's avatar
Nicolas Delaby committed
633
                                  filename='test.ods',
634
                                  portal_type='Spreadsheet')
635 636
    doc.edit(file=makeFileUpload('TEST-en-002.doc'))
    self.tic()
637 638 639 640 641 642 643 644

    uf = self.portal.acl_users
    uf._doAddUser('member_user1', 'secret', ['Member', 'Owner'], [])
    user = uf.getUserById('member_user1').__of__(uf)
    newSecurityManager(None, user)

    response = self.publish('%s/Base_download' % doc.getPath(),
                            basic='member_user1:secret')
645
    self.assertEqual(makeFileUpload('TEST-en-002.doc').read(),
Nicolas Delaby's avatar
Nicolas Delaby committed
646
                      response.getBody())
647
    self.assertEqual('application/msword',
648
                      response.headers['content-type'])
649 650 651 652 653 654 655
    self.assertEqual('attachment; filename="TEST-en-002.doc"',
                      response.headers['content-disposition'])
    response = self.publish('%s/OOoDocument_getOOoFile' % doc.getPath(),
                            basic='member_user1:secret')
    self.assertEqual('application/vnd.oasis.opendocument.text',
                      response.headers['content-type'])
    self.assertEqual('attachment; filename="TEST-en-002.odt"',
656 657 658 659 660 661
                      response.headers['content-disposition'])

  def test_Member_download_pdf_format(self):
    # tests that members can download OOo documents in pdf format (at least in
    # published state), and all headers (including filenames) are set correctly
    doc = self.portal.document_module.newContent(
Nicolas Delaby's avatar
Nicolas Delaby committed
662
                                  filename='test.ods',
663
                                  portal_type='Spreadsheet')
664
    doc.edit(file=makeFileUpload('import.file.with.dot.in.filename.ods'))
665
    doc.publish()
666
    self.tic()
667 668 669 670 671 672

    uf = self.portal.acl_users
    uf._doAddUser('member_user2', 'secret', ['Member'], [])
    user = uf.getUserById('member_user2').__of__(uf)
    newSecurityManager(None, user)

673
    response = self.publish('%s?format=pdf' % doc.getPath(),
674
                            basic='member_user2:secret')
675 676
    self.assertEqual('application/pdf', response.getHeader('content-type'))
    self.assertEqual('attachment; filename="import.file.with.dot.in.filename.pdf"',
Nicolas Delaby's avatar
Nicolas Delaby committed
677
                      response.getHeader('content-disposition'))
678 679 680 681 682 683
    response_body = response.getBody()
    conversion = str(doc.convert('pdf')[1])
    diff = '\n'+'\n'.join(difflib.unified_diff(response_body.splitlines(),
                                          conversion.splitlines(),
                                          fromfile='first_call.pdf',
                                          tofile='second_call.pdf'))
684
    self.assertEqual(response_body, conversion, diff)
685

686 687
    # test Print icon works on OOoDocument
    response = self.publish('%s/OOoDocument_print' % doc.getPath())
688
    self.assertEqual('application/pdf',
689
                      response.headers['content-type'])
690
    self.assertEqual('attachment; filename="import.file.with.dot.in.filename.pdf"',
691 692
                      response.headers['content-disposition'])

693
  def test_05_getCreationDate(self):
694
    """
Ivan Tyagov's avatar
Ivan Tyagov committed
695
    Check getCreationDate on all document types.
696 697 698 699 700 701 702 703 704 705
    """
    portal = self.getPortalObject()
    for document_type in portal.getPortalDocumentTypeList():
      module = portal.getDefaultModule(document_type)
      obj = module.newContent(portal_type=document_type)
      self.assertNotEquals(obj.getCreationDate(),
                           module.getCreationDate())
      self.assertNotEquals(obj.getCreationDate(),
                           portal.CreationDate())

706
  def test_06_ProcessingStateOfAClonedDocument(self):
707 708 709 710 711 712 713 714
    """
    Check that the processing state of a cloned document
    is not draft
    """
    filename = 'TEST-en-002.doc'
    file = makeFileUpload(filename)
    document = self.portal.portal_contributions.newContent(file=file)

715
    self.assertEqual('converting', document.getExternalProcessingState())
716
    self.commit()
717
    self.assertEqual('converting', document.getExternalProcessingState())
718 719 720 721 722 723 724

    # Clone a uploaded document
    container = document.getParentValue()
    clipboard = container.manage_copyObjects(ids=[document.getId()])
    paste_result = container.manage_pasteObjects(cb_copy_data=clipboard)
    new_document = container[paste_result[0]['new_id']]

725
    self.assertEqual('converting', new_document.getExternalProcessingState())
726
    self.commit()
727
    self.assertEqual('converting', new_document.getExternalProcessingState())
728 729

    # Change workflow state to converted
730
    self.tic()
731 732
    self.assertEqual('converted', document.getExternalProcessingState())
    self.assertEqual('converted', new_document.getExternalProcessingState())
733

734
    # Clone a converted document
735 736 737 738 739
    container = document.getParentValue()
    clipboard = container.manage_copyObjects(ids=[document.getId()])
    paste_result = container.manage_pasteObjects(cb_copy_data=clipboard)
    new_document = container[paste_result[0]['new_id']]

740
    self.assertEqual('converted', new_document.getExternalProcessingState())
741
    self.commit()
742
    self.assertEqual('converted', new_document.getExternalProcessingState())
743
    self.tic()
744
    self.assertEqual('converted', new_document.getExternalProcessingState())
745

746
  def test_07_EmbeddedDocumentOfAClonedDocument(self):
747 748 749 750
    """
    Check the validation state of embedded document when its container is
    cloned
    """
751
    document = self.portal.person_module.newContent(portal_type='Person')
752

753
    sub_document = document.newContent(portal_type='Embedded File')
754
    self.assertEqual('embedded', sub_document.getValidationState())
755
    self.tic()
756
    self.assertEqual('embedded', sub_document.getValidationState())
757 758 759 760 761 762 763 764

    # Clone document
    container = document.getParentValue()
    clipboard = container.manage_copyObjects(ids=[document.getId()])

    paste_result = container.manage_pasteObjects(cb_copy_data=clipboard)
    new_document = container[paste_result[0]['new_id']]

765
    new_sub_document_list = new_document.contentValues(portal_type='Embedded File')
766
    self.assertEqual(1, len(new_sub_document_list))
767
    new_sub_document = new_sub_document_list[0]
768
    self.assertEqual('embedded', new_sub_document.getValidationState())
769
    self.tic()
770
    self.assertEqual('embedded', new_sub_document.getValidationState())
771

772 773 774
  def test_08_NoImagesCreatedDuringHTMLConversion(self):
    """Converting an ODT to html no longer creates Images embedded in the
    document.
775 776 777 778 779 780 781
    """
    filename = 'EmbeddedImage-en-002.odt'
    file = makeFileUpload(filename)
    document = self.portal.portal_contributions.newContent(file=file)

    self.tic()

782
    self.assertEqual(0, len(document.contentValues(portal_type='Image')))
783 784
    document.convert(format='html')
    image_list = document.contentValues(portal_type='Image')
785
    self.assertEqual(0, len(image_list))
786

787
  def test_09_SearchableText(self):
788
    """
789
    Check DMS SearchableText capabilities.
790
    """
Ivan Tyagov's avatar
Ivan Tyagov committed
791
    portal = self.portal
792

793
    # Create a document.
Ivan Tyagov's avatar
Ivan Tyagov committed
794 795 796 797 798 799 800 801 802 803
    document_1 = self.portal.document_module.newContent(
                        portal_type = 'File',
                        description = 'Hello. ScriptableKey is very useful if you want to make your own search syntax.',
                        language = 'en',
                        version = '001')
    document_2 = self.portal.document_module.newContent(
                        portal_type='File',
                        description = 'This test make sure that scriptable key feature on ZSQLCatalog works.',
                        language='fr',
                        version = '002')
Ivan Tyagov's avatar
Ivan Tyagov committed
804 805 806 807 808 809
    document_3 = portal.document_module.newContent(
                   portal_type = 'Presentation',
                   title = "Complete set of tested reports with a long title.",
                   version = '003',
                   language = 'bg',
                   reference = 'tio-test-doc-3')
Ivan Tyagov's avatar
Ivan Tyagov committed
810 811 812 813 814
    person = portal.person_module.newContent(portal_type = 'Person', \
                                             reference= "john",
                                             title='John Doe Great')
    web_page = portal.web_page_module.newContent(portal_type = 'Web Page',
                                                 reference = "page_great_site",
Ivan Tyagov's avatar
Ivan Tyagov committed
815 816 817
                                                 text_content = 'Great website',
                                                 language='en',
                                                 version = '003')
Ivan Tyagov's avatar
Ivan Tyagov committed
818 819 820 821
    organisation = portal.organisation_module.newContent( \
                            portal_type = 'Organisation', \
                            reference = 'organisation-1',
                            title='Super nova organisation')
822
    self.tic()
Nicolas Delaby's avatar
Nicolas Delaby committed
823

824
    def getAdvancedSearchTextResultList(searchable_text, portal_type=None,src__=0):
825
      kw = {'full_text': searchable_text}
826 827
      if portal_type is not None:
        kw['portal_type'] = portal_type
828 829
      if src__==1:
        print portal.portal_catalog(src__=src__,**kw)
Ivan Tyagov's avatar
Ivan Tyagov committed
830
      return [x.getObject() for x in portal.portal_catalog(**kw)]
Nicolas Delaby's avatar
Nicolas Delaby committed
831

Ivan Tyagov's avatar
Ivan Tyagov committed
832 833 834 835 836
    # full text search
    self.assertSameSet([document_1], \
      getAdvancedSearchTextResultList('ScriptableKey'))
    self.assertEqual(len(getAdvancedSearchTextResultList('RelatedKey')), 0)
    self.assertSameSet([document_1, document_2], \
Ivan Tyagov's avatar
Ivan Tyagov committed
837
      getAdvancedSearchTextResultList('make', ('File',)))
Ivan Tyagov's avatar
Ivan Tyagov committed
838
    self.assertSameSet([web_page, person], \
839
      getAdvancedSearchTextResultList("Great", ('Person', 'Web Page')))
Ivan Tyagov's avatar
Ivan Tyagov committed
840 841
    # full text search with whole title of a document
    self.assertSameSet([document_3], \
842
      getAdvancedSearchTextResultList(document_3.getTitle(), ('Presentation',)))
843
    # full text search with reference part of searchable_text
Ivan Tyagov's avatar
Ivan Tyagov committed
844 845
    # (i.e. not specified with 'reference:' - simply part of search text)
    self.assertSameSet([document_3], \
846
      getAdvancedSearchTextResultList(document_3.getReference(), ('Presentation',)))
Ivan Tyagov's avatar
Ivan Tyagov committed
847 848 849 850 851 852 853 854 855

   # full text search with reference
    self.assertSameSet([web_page], \
      getAdvancedSearchTextResultList("reference:%s Great" %web_page.getReference()))
    self.assertSameSet([person],
          getAdvancedSearchTextResultList('reference:%s' %person.getReference()))

    # full text search with portal_type
    self.assertSameSet([person], \
Ivan Tyagov's avatar
Ivan Tyagov committed
856 857
      getAdvancedSearchTextResultList('%s portal_type:%s' %(person.getTitle(), person.getPortalType())))

Ivan Tyagov's avatar
Ivan Tyagov committed
858
    self.assertSameSet([organisation], \
Ivan Tyagov's avatar
Ivan Tyagov committed
859 860 861
      getAdvancedSearchTextResultList('%s portal_type:%s' \
                                       %(organisation.getTitle(),
                                         organisation.getPortalType())))
862 863 864

    # full text search with portal_type passed outside searchable_text
    self.assertSameSet([web_page, person],
865 866
                       getAdvancedSearchTextResultList('Great',
                          ('Person', 'Web Page')))
867 868 869 870
    self.assertSameSet([web_page], \
                       getAdvancedSearchTextResultList('Great', web_page.getPortalType()))
    self.assertSameSet([person], \
                       getAdvancedSearchTextResultList('Great', person.getPortalType()))
871

Ivan Tyagov's avatar
Ivan Tyagov committed
872 873
    # full text search with portal_type & reference
    self.assertSameSet([person], \
Ivan Tyagov's avatar
Ivan Tyagov committed
874 875 876 877 878 879
      getAdvancedSearchTextResultList('reference:%s portal_type:%s' \
                                        %(person.getReference(), person.getPortalType())))
    # full text search with language
    self.assertSameSet([document_1, web_page], \
      getAdvancedSearchTextResultList('language:en'))
    self.assertSameSet([document_1], \
880
      getAdvancedSearchTextResultList('ScriptableKey language:en'))
Ivan Tyagov's avatar
Ivan Tyagov committed
881 882 883 884 885 886 887 888 889 890 891 892 893 894
    self.assertSameSet([document_2], \
      getAdvancedSearchTextResultList('language:fr'))
    self.assertSameSet([web_page], \
      getAdvancedSearchTextResultList('%s reference:%s language:%s' \
                                       %(web_page.getTextContent(),
                                         web_page.getReference(),
                                         web_page.getLanguage())))
    # full text search with version
    self.assertSameSet([web_page], \
      getAdvancedSearchTextResultList('%s reference:%s language:%s version:%s' \
                                       %(web_page.getTextContent(),
                                         web_page.getReference(),
                                         web_page.getLanguage(),
                                         web_page.getVersion())))
895 896 897 898

    document = portal.document_module.newContent(
                   portal_type = 'Presentation',)
    # searchable text is empty by default
899
    self.assertEqual('', document.SearchableText())
900 901
    # it contains title
    document.setTitle('foo')
902
    self.assertEqual('foo', document.SearchableText())
903 904 905 906 907
    # and description
    document.setDescription('bar')
    self.assertTrue('bar' in document.SearchableText(),
      document.SearchableText())

908
  def test_10_SearchString(self):
909 910 911 912 913 914 915
    """
    Test search string search generation and parsing.
    """

    portal = self.portal
    assemble = portal.Base_assembleSearchString
    parse = portal.Base_parseSearchString
916

917
    # directly pasing searchable string
918
    self.assertEqual('searchable text',
919 920 921 922 923
                      assemble(**{'searchabletext': 'searchable text'}))
    kw = {'searchabletext_any': 'searchabletext_any',
          'searchabletext_phrase': 'searchabletext_phrase1 searchabletext_phrase1'}
    # exact phrase
    search_string = assemble(**kw)
924
    self.assertEqual('%s "%s"' %(kw['searchabletext_any'], kw['searchabletext_phrase']), \
925 926
                      search_string)
    parsed_string = parse(search_string)
927
    self.assertEqual(['searchabletext'], parsed_string.keys())
928

929

930 931 932
    # search "with all of the words"
    kw["searchabletext_all"] = "searchabletext_all1 searchabletext_all2"
    search_string = assemble(**kw)
933
    self.assertEqual('searchabletext_any "searchabletext_phrase1 searchabletext_phrase1"  +searchabletext_all1 +searchabletext_all2', \
934 935
                      search_string)
    parsed_string = parse(search_string)
936
    self.assertEqual(['searchabletext'], parsed_string.keys())
937 938

    # search without these words
939 940
    kw["searchabletext_without"] = "searchabletext_without1 searchabletext_without2"
    search_string = assemble(**kw)
941
    self.assertEqual('searchabletext_any "searchabletext_phrase1 searchabletext_phrase1"  +searchabletext_all1 +searchabletext_all2 -searchabletext_without1 -searchabletext_without2', \
942 943
                      search_string)
    parsed_string = parse(search_string)
944
    self.assertEqual(['searchabletext'], parsed_string.keys())
945

946 947 948
    # search limited to a certain date range
    kw['created_within'] = '1w'
    search_string = assemble(**kw)
949
    self.assertEqual('searchabletext_any "searchabletext_phrase1 searchabletext_phrase1"  +searchabletext_all1 +searchabletext_all2 -searchabletext_without1 -searchabletext_without2 created:1w', \
950 951 952
                      search_string)
    parsed_string = parse(search_string)
    self.assertSameSet(['searchabletext', 'creation_from'], parsed_string.keys())
953

954 955 956 957
    # search with portal_type
    kw['search_portal_type'] = 'Document'
    search_string = assemble(**kw)
    parsed_string = parse(search_string)
958
    self.assertEqual('searchabletext_any "searchabletext_phrase1 searchabletext_phrase1"  +searchabletext_all1 +searchabletext_all2 -searchabletext_without1 -searchabletext_without2 created:1w AND (portal_type:Document)', \
959 960 961
                      search_string)
    self.assertSameSet(['searchabletext', 'creation_from', 'portal_type'], \
                        parsed_string.keys())
962
    self.assertEqual(kw['search_portal_type'], parsed_string['portal_type'])
963

964 965 966 967
    # search by reference
    kw['reference'] = 'Nxd-test'
    search_string = assemble(**kw)
    parsed_string = parse(search_string)
968
    self.assertEqual('searchabletext_any "searchabletext_phrase1 searchabletext_phrase1"  +searchabletext_all1 +searchabletext_all2 -searchabletext_without1 -searchabletext_without2 created:1w AND (portal_type:Document) reference:Nxd-test', \
969 970 971
                      search_string)
    self.assertSameSet(['searchabletext', 'creation_from', 'portal_type', 'reference'], \
                        parsed_string.keys())
972 973
    self.assertEqual(kw['search_portal_type'], parsed_string['portal_type'])
    self.assertEqual(kw['reference'], parsed_string['reference'])
974

975 976 977 978
    # search by version
    kw['version'] = '001'
    search_string = assemble(**kw)
    parsed_string = parse(search_string)
979
    self.assertEqual('searchabletext_any "searchabletext_phrase1 searchabletext_phrase1"  +searchabletext_all1 +searchabletext_all2 -searchabletext_without1 -searchabletext_without2 created:1w AND (portal_type:Document) reference:Nxd-test version:001', \
980 981 982
                      search_string)
    self.assertSameSet(['searchabletext', 'creation_from', 'portal_type', 'reference', 'version'], \
                        parsed_string.keys())
983 984 985
    self.assertEqual(kw['search_portal_type'], parsed_string['portal_type'])
    self.assertEqual(kw['reference'], parsed_string['reference'])
    self.assertEqual(kw['version'], parsed_string['version'])
986

987 988 989 990
    # search by language
    kw['language'] = 'en'
    search_string = assemble(**kw)
    parsed_string = parse(search_string)
991
    self.assertEqual('searchabletext_any "searchabletext_phrase1 searchabletext_phrase1"  +searchabletext_all1 +searchabletext_all2 -searchabletext_without1 -searchabletext_without2 created:1w AND (portal_type:Document) reference:Nxd-test version:001 language:en', \
992 993 994 995
                      search_string)
    self.assertSameSet(['searchabletext', 'creation_from', 'portal_type', 'reference', \
                        'version', 'language'], \
                        parsed_string.keys())
996 997 998 999
    self.assertEqual(kw['search_portal_type'], parsed_string['portal_type'])
    self.assertEqual(kw['reference'], parsed_string['reference'])
    self.assertEqual(kw['version'], parsed_string['version'])
    self.assertEqual(kw['language'], parsed_string['language'])
1000

1001 1002 1003 1004
    # contributor title search
    kw['contributor_title'] = 'John'
    search_string = assemble(**kw)
    parsed_string = parse(search_string)
1005
    self.assertEqual('searchabletext_any "searchabletext_phrase1 searchabletext_phrase1"  +searchabletext_all1 +searchabletext_all2 -searchabletext_without1 -searchabletext_without2 created:1w AND (portal_type:Document) reference:Nxd-test version:001 language:en contributor_title:John', \
1006 1007 1008 1009
                      search_string)
    self.assertSameSet(['searchabletext', 'creation_from', 'portal_type', 'reference', \
                        'version', 'language', 'contributor_title'], \
                        parsed_string.keys())
1010 1011 1012 1013
    self.assertEqual(kw['search_portal_type'], parsed_string['portal_type'])
    self.assertEqual(kw['reference'], parsed_string['reference'])
    self.assertEqual(kw['version'], parsed_string['version'])
    self.assertEqual(kw['language'], parsed_string['language'])
1014

1015 1016 1017 1018
    # only my docs
    kw['mine'] = 'yes'
    search_string = assemble(**kw)
    parsed_string = parse(search_string)
1019
    self.assertEqual('searchabletext_any "searchabletext_phrase1 searchabletext_phrase1"  +searchabletext_all1 +searchabletext_all2 -searchabletext_without1 -searchabletext_without2 created:1w AND (portal_type:Document) reference:Nxd-test version:001 language:en contributor_title:John mine:yes', \
1020 1021 1022 1023
                      search_string)
    self.assertSameSet(['searchabletext', 'creation_from', 'portal_type', 'reference', \
                        'version', 'language', 'contributor_title', 'mine'], \
                        parsed_string.keys())
1024 1025 1026 1027 1028
    self.assertEqual(kw['search_portal_type'], parsed_string['portal_type'])
    self.assertEqual(kw['reference'], parsed_string['reference'])
    self.assertEqual(kw['version'], parsed_string['version'])
    self.assertEqual(kw['language'], parsed_string['language'])
    self.assertEqual(kw['mine'], parsed_string['mine'])
1029 1030

    # only newest versions
1031 1032 1033
    kw['newest'] = 'yes'
    search_string = assemble(**kw)
    parsed_string = parse(search_string)
1034
    self.assertEqual('searchabletext_any "searchabletext_phrase1 searchabletext_phrase1"  +searchabletext_all1 +searchabletext_all2 -searchabletext_without1 -searchabletext_without2 created:1w AND (portal_type:Document) reference:Nxd-test version:001 language:en contributor_title:John mine:yes newest:yes', \
1035 1036 1037 1038
                      search_string)
    self.assertSameSet(['searchabletext', 'creation_from', 'portal_type', 'reference', \
                        'version', 'language', 'contributor_title', 'mine', 'newest'], \
                        parsed_string.keys())
1039 1040 1041 1042 1043 1044
    self.assertEqual(kw['search_portal_type'], parsed_string['portal_type'])
    self.assertEqual(kw['reference'], parsed_string['reference'])
    self.assertEqual(kw['version'], parsed_string['version'])
    self.assertEqual(kw['language'], parsed_string['language'])
    self.assertEqual(kw['mine'], parsed_string['mine'])
    self.assertEqual(kw['newest'], parsed_string['newest'])
1045 1046

    # search mode
1047 1048 1049
    kw['search_mode'] = 'in_boolean_mode'
    search_string = assemble(**kw)
    parsed_string = parse(search_string)
1050
    self.assertEqual('searchabletext_any "searchabletext_phrase1 searchabletext_phrase1"  +searchabletext_all1 +searchabletext_all2 -searchabletext_without1 -searchabletext_without2 created:1w AND (portal_type:Document) reference:Nxd-test version:001 language:en contributor_title:John mine:yes newest:yes mode:boolean', \
1051 1052 1053 1054
                      search_string)
    self.assertSameSet(['searchabletext', 'creation_from', 'portal_type', 'reference', \
                        'version', 'language', 'contributor_title', 'mine', 'newest', 'mode'], \
                        parsed_string.keys())
1055 1056 1057 1058 1059 1060 1061
    self.assertEqual(kw['search_portal_type'], parsed_string['portal_type'])
    self.assertEqual(kw['reference'], parsed_string['reference'])
    self.assertEqual(kw['version'], parsed_string['version'])
    self.assertEqual(kw['language'], parsed_string['language'])
    self.assertEqual(kw['mine'], parsed_string['mine'])
    self.assertEqual(kw['newest'], parsed_string['newest'])
    self.assertEqual('boolean', parsed_string['mode'])
1062

1063
    # search with multiple portal_type
1064
    kw = {'search_portal_type': ['Document','Presentation','Web Page'],
1065 1066 1067
           'searchabletext_any': 'erp5'}
    search_string = assemble(**kw)
    parsed_string = parse(search_string)
1068
    self.assertEqual('erp5 AND (portal_type:Document OR portal_type:Presentation OR portal_type:"Web Page")', \
1069 1070 1071
                      search_string)
    self.assertSameSet(['searchabletext', 'portal_type'], \
                        parsed_string.keys())
1072
    #self.assertEqual(kw['search_portal_type'], parsed_string['portal_type'])
1073

1074
    # parse with multiple portal_type containing spaces in one portal_type
1075
    search_string = 'erp5 AND (portal_type:Document OR portal_type:Presentation OR portal_type:"Web Page")'
1076
    parsed_string = parse(search_string)
1077
    self.assertEqual(parsed_string['portal_type'], ['Document','Presentation','"Web Page"'])
1078

Ivan Tyagov's avatar
Ivan Tyagov committed
1079
  def test_11_Base_getAdvancedSearchResultList(self):
1080
    """
Ivan Tyagov's avatar
Ivan Tyagov committed
1081
    Test search string search capabilities using Base_getAdvancedSearchResultList script.
1082 1083 1084 1085 1086 1087 1088 1089
    """
    portal = self.portal
    assemble = portal.Base_assembleSearchString
    search = portal.Base_getAdvancedSearchResultList

    def getAdvancedSearchStringResultList(**kw):
      search_string = assemble(**kw)
      return [x.getObject() for x in search(search_string)]
1090

1091 1092 1093 1094 1095 1096 1097 1098 1099
    # create some objects
    document_1 = portal.document_module.newContent(
                   portal_type = 'File',
                   description = 'standalone software linux python free',
                   version = '001',
                   language = 'en',
                   reference = 'nxd-test-doc-1')
    document_2 = portal.document_module.newContent(
                   portal_type = 'Presentation',
1100
                   description = 'standalone free python linux knowledge system management different',
1101 1102 1103 1104 1105 1106 1107 1108 1109
                   version = '002',
                   language = 'fr',
                   reference = 'nxd-test-doc-2')
    document_3 = portal.document_module.newContent(
                   portal_type = 'Presentation',
                   description = 'just a copy',
                   version = '003',
                   language = 'en',
                   reference = 'nxd-test-doc-2')
1110
    # multiple revisions of a Web Page
1111 1112
    web_page_1 = portal.web_page_module.newContent(
                   portal_type = 'Web Page',
1113
                   text_content = 'software based solutions document management product standalone owner different',
1114 1115 1116
                   version = '003',
                   language = 'jp',
                   reference = 'nxd-test-web-page-3')
1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135
    web_page_2 = portal.web_page_module.newContent(
                   portal_type = 'Web Page',
                   text_content = 'new revision (004) of nxd-test-web-page-3',
                   version = '004',
                   language = 'jp',
                   reference = 'nxd-test-web-page-3')
    web_page_3 = portal.web_page_module.newContent(
                   portal_type = 'Web Page',
                   text_content = 'new revision (005) of nxd-test-web-page-3',
                   version = '005',
                   language = 'jp',
                   reference = 'nxd-test-web-page-3')
    # publish documents so we can test searching within owned documents for an user
    for document in (document_1, document_2, document_3, web_page_1, web_page_2, web_page_3):
      document.publish()
    # create test Person objects and add pseudo local security
    person1 =  self.createUser(reference='user1')
    person1.setTitle('Another Contributor')
    portal.document_module.manage_setLocalRoles('user1', ['Assignor',])
1136
    self.tic()
1137 1138

    # login as another user
1139
    super(TestDocument, self).login('user1')
1140 1141 1142 1143 1144 1145
    document_4 = portal.document_module.newContent(
                   portal_type = 'Presentation',
                   description = 'owner different user contributing document',
                   version = '003',
                   language = 'bg',
                   reference = 'tlv-test-doc-1')
1146
    self.login()
1147 1148 1149 1150
    contributor_list = document_4.getContributorValueList()
    contributor_list.append(person1)
    document_4.setContributorValueList(contributor_list)
    document_4.publish()
1151
    self.tic()
1152 1153 1154 1155

    # search arbitrary word
    kw = {'searchabletext_any': 'software'}
    self.assertSameSet([document_1,web_page_1], getAdvancedSearchStringResultList(**kw))
1156

1157
    # exact word search
1158
    kw = {'searchabletext_any': '',
1159
          'searchabletext_phrase': 'linux python'}
1160
    self.assertSameSet([document_1], getAdvancedSearchStringResultList(**kw))
1161
    kw = {'searchabletext_any': '',
1162
          'searchabletext_phrase': 'python linux'}
1163
    self.assertSameSet([document_2], getAdvancedSearchStringResultList(**kw))
1164
    kw = {'searchabletext_any': '',
1165 1166
          'searchabletext_phrase': 'python linux knowledge system'}
    self.assertSameSet([document_2], getAdvancedSearchStringResultList(**kw))
1167

1168 1169 1170 1171
    # search "with all of the words" - each word prefixed by "+"
    kw = {'searchabletext_any': 'standalone',
          'searchabletext_all': 'python'}
    self.assertSameSet([document_1, document_2], getAdvancedSearchStringResultList(**kw))
1172

1173 1174 1175 1176
    # search without these words - every word prefixed by "-"
    kw = {'searchabletext_any': 'standalone',
          'searchabletext_without': 'python'}
    self.assertSameSet([web_page_1], getAdvancedSearchStringResultList(**kw))
1177

1178 1179 1180 1181
    # only given portal_types - add "type:Type" or type:(Type1,Type2...)
    kw = {'searchabletext_any': 'python',
          'search_portal_type': 'Presentation'}
    self.assertSameSet([document_2], getAdvancedSearchStringResultList(**kw))
1182 1183 1184 1185 1186 1187
    kw = {'searchabletext_any': 'python',
          'search_portal_type': 'File'}
    self.assertSameSet([document_1], getAdvancedSearchStringResultList(**kw))
    kw = {'searchabletext_any': 'management',
          'search_portal_type': 'File'}
    self.assertSameSet([], getAdvancedSearchStringResultList(**kw))
1188

1189
    # search by reference
1190
    kw = {'reference': document_2.getReference()}
1191 1192 1193 1194
    self.assertSameSet([document_2, document_3], getAdvancedSearchStringResultList(**kw))
    kw = {'searchabletext_any': 'copy',
          'reference': document_2.getReference()}
    self.assertSameSet([document_3], getAdvancedSearchStringResultList(**kw))
1195 1196
    kw = {'searchabletext_any': 'copy',
          'reference': document_2.getReference(),
1197
          'search_portal_type': 'File'}
1198
    self.assertSameSet([], getAdvancedSearchStringResultList(**kw))
1199

1200
    # search by version
1201
    kw = {'reference': document_2.getReference(),
1202
          'version': document_2.getVersion()}
1203
    self.assertSameSet([document_2], getAdvancedSearchStringResultList(**kw))
1204
    kw = {'reference': document_2.getReference(),
1205 1206 1207
          'version': document_2.getVersion(),
          'search_portal_type': 'File'}
    self.assertSameSet([], getAdvancedSearchStringResultList(**kw))
1208

1209
    # search by language
1210
    kw = {'reference': document_2.getReference(),
1211 1212
          'language': document_2.getLanguage()}
    self.assertSameSet([document_2], getAdvancedSearchStringResultList(**kw))
1213
    kw = {'reference': document_2.getReference(),
1214 1215
          'language': document_3.getLanguage()}
    self.assertSameSet([document_3], getAdvancedSearchStringResultList(**kw))
1216
    kw = {'reference': document_2.getReference(),
1217
          'language': document_3.getLanguage(),
1218
          'search_portal_type': 'File'}
1219
    self.assertSameSet([], getAdvancedSearchStringResultList(**kw))
1220

1221
    # only my docs
1222
    super(TestDocument, self).login('user1')
1223 1224 1225 1226 1227 1228 1229 1230
    kw = {'searchabletext_any': 'owner'}
    # should return all documents matching a word no matter if we're owner or not
    self.assertSameSet([web_page_1, document_4], getAdvancedSearchStringResultList(**kw))
    kw = {'searchabletext_any': 'owner',
          'mine': 'yes'}
    # should return ONLY our own documents matching a word
    self.assertSameSet([document_4], getAdvancedSearchStringResultList(**kw))
    self.login()
1231

1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245
    # only newest versions
    # should return ALL documents for a reference
    kw = {'reference': web_page_1.getReference()}
    self.assertSameSet([web_page_1, web_page_2, web_page_3], getAdvancedSearchStringResultList(**kw))
    # should return ONLY newest document for a reference
    kw = {'reference': web_page_1.getReference(),
          'newest': 'yes'}
    self.assertSameSet([web_page_3], getAdvancedSearchStringResultList(**kw))

    # contributor title search
    kw = {'searchabletext_any': 'owner'}
    # should return all documents matching a word no matter of contributor
    self.assertSameSet([web_page_1, document_4], getAdvancedSearchStringResultList(**kw))
    kw = {'searchabletext_any': 'owner',
1246
          'contributor_title': 'Contributor'}
1247
    self.assertSameSet([document_4], getAdvancedSearchStringResultList(**kw))
1248 1249 1250 1251 1252

    # multiple portal_type specified
    kw = {'search_portal_type': 'File,Presentation'}
    self.assertSameSet([document_1, document_2, document_3, document_4], getAdvancedSearchStringResultList(**kw))

1253
    # XXX: search limited to a certain date range
1254 1255
    # XXX: search mode

1256 1257 1258 1259
  # &nbsp; and &#160; are equivalent, and "pdftohtml" can generate
  # either depending on the version of the "poppler" package used.
  re_html_nbsp = re.compile('&(nbsp|#160);')

1260 1261 1262
  def test_PDFTextContent(self):
    upload_file = makeFileUpload('REF-en-001.pdf')
    document = self.portal.portal_contributions.newContent(file=upload_file)
1263 1264
    self.assertEqual('PDF', document.getPortalType())
    self.assertEqual('I use reference to look up TEST\n',
1265
                      document._convertToText())
1266 1267
    html_data = re.sub(self.re_html_nbsp, ' ', document._convertToHTML())
    self.assert_('I use reference to look up TEST' in html_data)
1268 1269 1270
    self.assert_('I use reference to look up TEST' in
                 document.SearchableText())

1271 1272 1273
  def test_PDFToImage(self):
    upload_file = makeFileUpload('REF-en-001.pdf')
    document = self.portal.portal_contributions.newContent(file=upload_file)
1274
    self.assertEqual('PDF', document.getPortalType())
Nicolas Delaby's avatar
Nicolas Delaby committed
1275

1276
    content_type, image_data = document.convert(format='png',
Nicolas Delaby's avatar
Nicolas Delaby committed
1277 1278
                                                frame=0,
                                                display='thumbnail')
1279
    # it's a valid PNG
1280
    self.assertEqual('PNG', image_data[1:4])
Fabien Morin's avatar
Fabien Morin committed
1281

1282 1283 1284
  def test_PDF_content_information(self):
    upload_file = makeFileUpload('REF-en-001.pdf')
    document = self.portal.portal_contributions.newContent(file=upload_file)
1285
    self.assertEqual('PDF', document.getPortalType())
1286
    content_information = document.getContentInformation()
1287 1288 1289 1290
    self.assertEqual('1', content_information['Pages'])
    self.assertEqual('subject', content_information['Subject'])
    self.assertEqual('title', content_information['Title'])
    self.assertEqual('application/pdf', document.getContentType())
1291

1292 1293 1294
  def test_PDF_content_information_extra_metadata(self):
    # Extra metadata, such as those stored by pdftk update_info are also
    # available in document.getContentInformation()
1295
    upload_file = makeFileUpload('metadata.pdf', as_name='REF-en-001.pdf')
1296
    document = self.portal.portal_contributions.newContent(file=upload_file)
1297
    self.tic()
1298
    self.assertEqual('PDF', document.getPortalType())
1299
    content_information = document.getContentInformation()
1300 1301 1302
    self.assertEqual('the value', content_information['NonStandardMetadata'])
    self.assertEqual('1', content_information['Pages'])
    self.assertEqual('REF', document.getReference())
1303 1304

    # contribute file which will be merged to current document in synchronous mode
1305
    # and check content_type recalculated
1306 1307 1308
    upload_file = makeFileUpload('Forty-Two.Pages-en-001.pdf', as_name='REF-en-001.pdf')
    contributed_document = self.portal.Base_contribute(file=upload_file, \
                                                       synchronous_metadata_discovery=True)
1309
    self.tic()
1310
    content_information = contributed_document.getContentInformation()
1311

1312 1313 1314 1315 1316 1317 1318 1319 1320 1321
    # we should have same data, respectively same PDF pages
    self.assertEqual(contributed_document.getSize(), document.getSize())
    self.assertEqual(contributed_document.getContentInformation()['Pages'], \
                     document.getContentInformation()['Pages'])
    self.assertEqual('42', \
                     document.getContentInformation()['Pages'])

    # upload with another file and check content_type recalculated
    upload_file = makeFileUpload('REF-en-001.pdf')
    document.setFile(upload_file)
1322
    self.tic()
1323
    content_information = document.getContentInformation()
1324
    self.assertEqual('1', content_information['Pages'])
1325

1326 1327 1328 1329
  def test_empty_PDF_content_information(self):
    document = self.portal.document_module.newContent(portal_type='PDF')
    content_information = document.getContentInformation()
    # empty PDF have no content information
1330
    self.assertEqual({}, content_information)
1331

1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346
  def test_apple_PDF_metadata(self):
    # PDF created with Apple software have a special 'AAPL:Keywords' info tag
    # and when pypdf extracts pdf information, it is returned as an
    # IndirectObject instance which is not picklable
    document = self.portal.document_module.newContent(
      portal_type='PDF',
      file=makeFileUpload('apple_metadata.pdf'))
    # content_information is picklable
    content_information = document.getContentInformation()
    from pickle import dumps
    dumps(content_information)
    # so document can be saved in ZODB
    self.commit()
    self.tic()

Aurel's avatar
Aurel committed
1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358
  def test_upload_bad_pdf_file(self):
    """ Test that pypdf2 handle wrong formatted PDF """
    path = os.path.join(os.path.dirname(__file__), 'test_document',
      'FEUILLE BLANCHE.pdf')
    file_upload = FileUpload(path, 'FEUILLE BLANCHE.pdf')
    pdf = self.portal.document_module.newContent(
      portal_type='PDF',
      file=file_upload,
      title='Bad PDF')
    self.tic()
    pdf.share()
    self.tic()
1359
    self.assertEqual(pdf.getValidationState(), "shared")
Aurel's avatar
Aurel committed
1360 1361 1362
    result = pdf.getContentInformation()
    self.assertNotEquals(result, None)

1363 1364
  def test_PDF_content_content_type(self):
    upload_file = makeFileUpload('REF-en-001.pdf')
1365 1366
    document = self.portal.document_module.newContent(portal_type='PDF')
    # Here we use edit instead of setFile,
Nicolas Delaby's avatar
Nicolas Delaby committed
1367
    # because only edit method set filename as filename.
1368
    document.edit(file=upload_file)
1369
    self.assertEqual('application/pdf', document.getContentType())
1370

1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429
  def test_PDF_watermark(self):
    original_document = self.portal.portal_contributions.newContent(
      file=makeFileUpload('REF-en-001.pdf'))
    # This watermark.pdf document is a pdf with a transparent background. Such
    # document can be created using GIMP
    watermark_document = self.portal.portal_contributions.newContent(
      file=makeFileUpload('watermark.pdf'))
    watermarked_data = original_document.getWatermarkedData(
      watermark_data=watermark_document.getData(),
      repeat_watermark=False)

    # this looks like a pdf
    self.assertTrue(watermarked_data.startswith('%PDF-1.3'))

    # and ERP5 can make a PDF Document out of it
    watermarked_document = self.portal.document_module.newContent(
      portal_type='PDF',
      data=watermarked_data)
    self.assertEqual('1', watermarked_document.getContentInformation()['Pages'])
    self.assertNotEqual(original_document.getData(),
      watermarked_document.getData())

  def test_PDF_watermark_repeat(self):
    # watermark a pdf, repeating the watermark
    original_document = self.portal.portal_contributions.newContent(
      file=makeFileUpload('Forty-Two.Pages-en-001.pdf'))
    watermark_document = self.portal.portal_contributions.newContent(
      file=makeFileUpload('watermark.pdf'))
    watermarked_data = original_document.getWatermarkedData(
      watermark_data=watermark_document.getData(),
      repeat_watermark=True)

    self.assertTrue(watermarked_data.startswith('%PDF-1.3'))
    watermarked_document = self.portal.document_module.newContent(
      portal_type='PDF',
      data=watermarked_data)
    self.assertEqual('42', watermarked_document.getContentInformation()['Pages'])
    self.assertNotEqual(original_document.getData(),
      watermarked_document.getData())

  def test_PDF_watermark_start_page(self):
    # watermark a pdf, starting on the second page
    original_document = self.portal.portal_contributions.newContent(
      file=makeFileUpload('Forty-Two.Pages-en-001.pdf'))
    watermark_document = self.portal.portal_contributions.newContent(
      file=makeFileUpload('watermark.pdf'))
    watermarked_data = original_document.getWatermarkedData(
      watermark_data=watermark_document.getData(),
      repeat_watermark=False,
      watermark_start_page=1) # This is 0 based.

    self.assertTrue(watermarked_data.startswith('%PDF-1.3'))
    watermarked_document = self.portal.document_module.newContent(
      portal_type='PDF',
      data=watermarked_data)
    self.assertEqual('42', watermarked_document.getContentInformation()['Pages'])
    self.assertNotEqual(original_document.getData(),
      watermarked_document.getData())

Nicolas Delaby's avatar
Nicolas Delaby committed
1430
  def test_Document_getStandardFilename(self):
1431 1432 1433
    upload_file = makeFileUpload('metadata.pdf')
    document = self.portal.document_module.newContent(portal_type='PDF')
    document.edit(file=upload_file)
1434 1435
    self.assertEqual(document.getStandardFilename(), 'metadata.pdf')
    self.assertEqual(document.getStandardFilename(format='png'),
1436 1437 1438
                      'metadata.png')
    document.setVersion('001')
    document.setLanguage('en')
1439 1440
    self.assertEqual(document.getStandardFilename(), 'metadata-001-en.pdf')
    self.assertEqual(document.getStandardFilename(format='png'),
1441
                      'metadata-001-en.png')
1442 1443 1444 1445
    # check when format contains multiple '.'
    upload_file = makeFileUpload('TEST-en-003.odp')
    document = self.portal.document_module.newContent(portal_type='Presentation')
    document.edit(file=upload_file)
1446 1447
    self.assertEqual(document.getStandardFilename(), 'TEST-en-003.odp')
    self.assertEqual('TEST-en-003.odg', document.getStandardFilename(format='odp.odg'))
1448

1449

1450 1451 1452
  def test_CMYKImageTextContent(self):
    upload_file = makeFileUpload('cmyk_sample.jpg')
    document = self.portal.portal_contributions.newContent(file=upload_file)
1453 1454
    self.assertEqual('Image', document.getPortalType())
    self.assertEqual('ERP5 is a free software\n\n', document.asText())
1455 1456 1457 1458

  def test_MonochromeImageResize(self):
    upload_file = makeFileUpload('monochrome_sample.tiff')
    document = self.portal.portal_contributions.newContent(file=upload_file)
1459
    self.assertEqual('Image', document.getPortalType())
1460 1461 1462
    resized_image = document.convert(format='png', display='small')[1]
    identify_output = Popen(['identify', '-verbose', '-'], stdin=PIPE, stdout=PIPE).communicate(resized_image)[0]
    self.assertFalse('1-bit' in identify_output)
1463
    self.assertEqual('ERP5 is a free software\n\n', document.asText())
1464

1465 1466 1467
  def test_Base_showFoundText(self):
    # Create document with good content
    document = self.portal.document_module.newContent(portal_type='Drawing')
1468
    self.assertEqual('empty', document.getExternalProcessingState())
1469

1470
    upload_file = makeFileUpload('TEST-en-002.odt')
1471
    document.edit(file=upload_file)
1472
    self.tic()
1473
    self.assertEqual('converted', document.getExternalProcessingState())
1474

Nicolas Delaby's avatar
Nicolas Delaby committed
1475 1476
    # Delete base_data
    document.edit(base_data=None)
1477

Nicolas Delaby's avatar
Nicolas Delaby committed
1478
    # As document is not converted, text conversion is impossible
1479 1480
    self.assertRaises(NotConvertedError, document.asText)
    self.assertRaises(NotConvertedError, document.getSearchableText)
1481
    self.assertEqual('This document is not converted yet.',
1482
                      document.Base_showFoundText())
1483

1484 1485 1486
    # upload again good content
    upload_file = makeFileUpload('TEST-en-002.odt')
    document.edit(file=upload_file)
1487
    self.tic()
1488
    self.assertEqual('converted', document.getExternalProcessingState())
1489

1490
  def test_Base_contribute(self):
1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504
    """
      Test contributing a file and attaching it to context.
    """
    person = self.portal.person_module.newContent(portal_type='Person')
    contributed_document = person.Base_contribute(
                                     portal_type=None,
                                     title=None,
                                     reference=None,
                                     short_title=None,
                                     language=None,
                                     version=None,
                                     description=None,
                                     attach_document_to_context=True,
                                     file=makeFileUpload('TEST-en-002.odt'))
1505
    self.assertEqual('Text', contributed_document.getPortalType())
1506
    self.tic()
1507
    document_list = person.getFollowUpRelatedValueList()
1508
    self.assertEqual(1, len(document_list))
1509
    document = document_list[0]
1510 1511 1512 1513
    self.assertEqual('converted', document.getExternalProcessingState())
    self.assertEqual('Text', document.getPortalType())
    self.assertEqual('title', document.getTitle())
    self.assertEqual(contributed_document, document)
1514

1515
  def test_Base_contribute_empty(self):
Ivan Tyagov's avatar
Typo.  
Ivan Tyagov committed
1516
    """
1517 1518 1519
      Test contributing an empty file and attaching it to context.
    """
    person = self.portal.person_module.newContent(portal_type='Person')
1520 1521 1522 1523 1524 1525
    empty_file_upload = ZPublisher.HTTPRequest.FileUpload(FieldStorage(
                            fp=StringIO.StringIO(),
                            environ=dict(REQUEST_METHOD='PUT'),
                            headers={"content-disposition":
                              "attachment; filename=empty;"}))

1526 1527 1528 1529 1530 1531 1532 1533 1534 1535
    contributed_document = person.Base_contribute(
                                    portal_type=None,
                                    title=None,
                                    reference=None,
                                    short_title=None,
                                    language=None,
                                    version=None,
                                    description=None,
                                    attach_document_to_context=True,
                                    file=empty_file_upload)
1536
    self.tic()
1537
    document_list = person.getFollowUpRelatedValueList()
1538
    self.assertEqual(1, len(document_list))
1539
    document = document_list[0]
1540 1541
    self.assertEqual('File', document.getPortalType())
    self.assertEqual(contributed_document, document)
1542

1543
  def test_Base_contribute_forced_type(self):
1544 1545 1546 1547 1548 1549
    """Test contributing while forcing the portal type.
    """
    person = self.portal.person_module.newContent(portal_type='Person')
    contributed_document = person.Base_contribute(
                                     portal_type='PDF',
                                     file=makeFileUpload('TEST-en-002.odt'))
1550
    self.assertEqual('PDF', contributed_document.getPortalType())
1551

1552 1553 1554 1555 1556 1557 1558 1559
  def test_Base_contribute_input_parameter_dict(self):
    """Test contributing while entering input parameters.
    """
    person = self.portal.person_module.newContent(portal_type='Person')
    contributed_document = person.Base_contribute(
                                     title='user supplied title',
                                     file=makeFileUpload('TEST-en-002.pdf'))
    self.tic()
1560
    self.assertEqual('user supplied title', contributed_document.getTitle())
1561

1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579
  def test_HTML_to_ODT_conversion_keep_enconding(self):
    """This test perform an PDF conversion of HTML content
    then to plain text.
    Check that encoding remains.
    """
    web_page_portal_type = 'Web Page'
    string_to_test = 'éààéôù'
    web_page = self.portal.getDefaultModule(web_page_portal_type)\
          .newContent(portal_type=web_page_portal_type)
    html_content = '<p>%s</p>' % string_to_test
    web_page.edit(text_content=html_content)
    mime_type, pdf_data = web_page.convert('pdf')
    text_content = self.portal.portal_transforms.\
                                      convertToData('text/plain',
                                          str(pdf_data),
                                          object=web_page, context=web_page,
                                          filename='test.pdf')
    self.assertTrue(string_to_test in text_content)
1580

1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599
  def test_HTML_to_ODT_conversion_keep_related_image_list(self):
    """This test create a Web Page and an Image.
    HTML content of Web Page referred to that Image with it's reference.
    Check that ODT conversion of Web Page embed image data.
    """
    # create web page
    web_page_portal_type = 'Web Page'
    web_page = self.portal.getDefaultModule(web_page_portal_type)\
          .newContent(portal_type=web_page_portal_type)
    image_reference = 'MY-TESTED-IMAGE'
    # Target image with it reference only
    html_content = '<p><img src="%s"/></p>' % image_reference
    web_page.edit(text_content=html_content)

    # Create image
    image_portal_type = 'Image'
    image = self.portal.getDefaultModule(image_portal_type)\
          .newContent(portal_type=image_portal_type)

1600
    # edit content and publish it
1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613
    upload_file = makeFileUpload('cmyk_sample.jpg')
    image.edit(reference=image_reference,
               version='001',
               language='en',
               file=upload_file)
    image.publish()

    self.tic()

    # convert web_page into odt
    mime_type, odt_archive = web_page.convert('odt')
    builder = OOoBuilder(odt_archive)
    image_count = builder._image_count
1614 1615
    failure_message = 'Expected image not found in ODF zipped archive'
    # fetch image from zipped archive content then compare with ERP5 Image
1616
    self.assertEqual(builder.extract('Pictures/%s.jpeg' % image_count),
1617
                      image.getData(), failure_message)
1618

1619 1620 1621
    # Continue the test with image resizing support
    image_display = 'large'
    # Add url parameters
1622
    html_content = '<p><img src="%s?format=jpeg&amp;display=%s&amp;quality=75"/></p>' % \
1623 1624 1625 1626 1627 1628 1629 1630 1631
                                              (image_reference, image_display)
    web_page.edit(text_content=html_content)
    mime_type, odt_archive = web_page.convert('odt')
    builder = OOoBuilder(odt_archive)
    image_count = builder._image_count
    # compute resized image for comparison
    mime, converted_image = image.convert(format='jpeg', display=image_display)
    # fetch image from zipped archive content
    # then compare with resized ERP5 Image
1632
    self.assertEqual(builder.extract('Pictures/%s.jpeg' % image_count),
1633 1634
                      converted_image, failure_message)

1635 1636 1637 1638 1639 1640 1641 1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653
    # Let's continue with Presentation Document as embbeded image
    document = self.portal.document_module.newContent(portal_type='Presentation')
    upload_file = makeFileUpload('TEST-en-003.odp')
    image_reference = 'IMAGE-odp'
    document.edit(file=upload_file, reference=image_reference)
    document.publish()
    self.tic()
    html_content = '<p><img src="%s?format=png&amp;display=%s&amp;quality=75"/></p>' % \
                                              (image_reference, image_display)
    web_page.edit(text_content=html_content)
    mime_type, odt_archive = web_page.convert('odt')
    builder = OOoBuilder(odt_archive)
    image_count = builder._image_count
    # compute resized image for comparison
    mime, converted_image = document.convert(format='png',
                                             display=image_display,
                                             quality=75)
    # fetch image from zipped archive content
    # then compare with resized ERP5 Image
1654
    self.assertEqual(builder.extract('Pictures/%s.png' % image_count),
1655 1656 1657
                      converted_image, failure_message)


1658 1659 1660 1661 1662 1663 1664 1665
  def test_addContributorToDocument(self):
    """
      Test if current authenticated user is added to contributor list of document
      (only if authenticated user is an ERP5 Person object)
    """
    portal = self.portal
    document_module = portal.document_module

1666
    # create Person objects and add pseudo local security
1667 1668 1669 1670
    person1 =  self.createUser(reference='contributor1')
    document_module.manage_setLocalRoles('contributor1', ['Assignor',])
    person2 =  self.createUser(reference='contributor2')
    document_module.manage_setLocalRoles('contributor2', ['Assignor',])
1671
    self.tic()
1672 1673

    # login as first one
1674
    super(TestDocument, self).login('contributor1')
1675
    doc = document_module.newContent(portal_type='File',
1676
                                     title='Test1')
1677
    self.tic()
1678
    self.login()
1679
    self.assertSameSet([person1],
1680 1681 1682
                       doc.getContributorValueList())

    # login as second one
1683
    super(TestDocument, self).login('contributor2')
1684
    doc.edit(title='Test2')
1685
    self.tic()
1686
    self.login()
1687
    self.assertSameSet([person1, person2],
1688 1689 1690 1691 1692
                       doc.getContributorValueList())

    # editing with non ERP5 Person object, nothing added to contributor
    self.login()
    doc.edit(title='Test3')
1693
    self.tic()
1694
    self.assertSameSet([person1, person2],
1695
                       doc.getContributorValueList())
1696

1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708
  def test_safeHTML_conversion(self):
    """This test create a Web Page and test asSafeHTML conversion.
    Test also with a very non well-formed html document
    to stress conversion engine.
    """
    # create web page
    web_page_portal_type = 'Web Page'
    module = self.portal.getDefaultModule(web_page_portal_type)
    web_page = module.newContent(portal_type=web_page_portal_type)

    html_content = """<html>
      <head>
1709 1710
        <meta http-equiv="refresh" content="5;url=http://example.com/"/>
        <meta http-equiv="Set-Cookie" content=""/>
1711
        <title>My dirty title</title>
1712 1713 1714
        <style type="text/css">
          a {color: #FFAA44;}
        </style>
Kazuhiko Shiozaki's avatar
Kazuhiko Shiozaki committed
1715
        <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"/>
1716 1717 1718 1719 1720 1721
      </head>
      <body>
        <div>
          <h1>My splendid title</h1>
        </div>
        <script type="text/javascript" src="http://example.com/something.js"/>
1722 1723 1724 1725
        <script type="text/javascript">
          alert("da");
        </script>
        <a href="javascript:DosomethingNasty()">Link</a>
1726
        <a onclick="javascript:DosomethingNasty()">Another Link</a>
1727
        <p>éàèù</p>
1728
        <p class="Th&#232;mes Thèmes">Th&#232;mes Thèmes</p>
1729 1730
      </body>
    </html>
1731
    """.decode('utf-8').encode('iso-8859-1')
1732 1733
    # content encoded into another codec
    # than utf-8 comes from necessarily an external file
1734
    # (Ingestion, or FileField), not from user interface
1735 1736 1737 1738 1739 1740 1741 1742 1743 1744 1745
    # which is always utf-8.
    # Edit web_page with a file to force conversion to base_format
    # as it is done in reality

    # Mimic the behaviour of a FileUpload from WebPage_view
    file_like = StringIO.StringIO()
    file_like.write(html_content)
    setattr(file_like, 'filename', 'something.htm')
    web_page.edit(file=file_like)
    # run conversion to base format
    self.tic()
1746

1747
    # Check that outputted stripped html is safe
1748
    safe_html = web_page.asStrippedHTML()
1749 1750 1751
    self.assertTrue('My splendid title' in safe_html)
    self.assertTrue('script' not in safe_html, safe_html)
    self.assertTrue('something.js' not in safe_html, safe_html)
1752 1753 1754 1755
    self.assertTrue('<body>' not in safe_html)
    self.assertTrue('<head>' not in safe_html)
    self.assertTrue('<style' not in safe_html)
    self.assertTrue('#FFAA44' not in safe_html)
1756 1757
    self.assertTrue('5;url=http://example.com/' not in safe_html)
    self.assertTrue('Set-Cookie' not in safe_html)
1758 1759 1760
    self.assertTrue('javascript' not in safe_html)
    self.assertTrue('alert("da");' not in safe_html)
    self.assertTrue('javascript:DosomethingNasty()' not in safe_html)
1761
    self.assertTrue('onclick' not in safe_html)
1762 1763 1764 1765 1766 1767 1768 1769 1770 1771 1772

    # Check that outputed entire html is safe
    entire_html = web_page.asEntireHTML()
    self.assertTrue('My splendid title' in entire_html)
    self.assertTrue('script' not in entire_html, entire_html)
    self.assertTrue('something.js' not in entire_html, entire_html)
    self.assertTrue('<title>' in entire_html)
    self.assertTrue('<body>' in entire_html)
    self.assertTrue('<head>' in entire_html)
    self.assertTrue('<style' in entire_html)
    self.assertTrue('#FFAA44' in entire_html)
1773
    self.assertTrue('charset=utf-8' in entire_html)
1774 1775 1776
    self.assertTrue('javascript' not in entire_html)
    self.assertTrue('alert("da");' not in entire_html)
    self.assertTrue('javascript:DosomethingNasty()' not in entire_html)
1777
    self.assertTrue('onclick' not in entire_html)
1778 1779

    # now check converted value is stored in cache
1780
    format = 'html'
1781 1782 1783 1784 1785
    self.assertTrue(web_page.hasConversion(format=format))
    web_page.edit(text_content=None)
    self.assertFalse(web_page.hasConversion(format=format))

    # test with not well-formed html document
1786
    html_content = r"""
1787 1788 1789 1790 1791 1792 1793 1794 1795 1796 1797 1798
    <HTML dir=3Dltr><HEAD>=0A=
<META http-equiv=3DContent-Type content=3D"text/html; charset=3Dunicode">=0A=
<META content=3D"DIRTYHTML 6.00.2900.2722" name=3DGENERATOR></HEAD>=0A=

<BODY>=0A=
<DIV><FONT face=3D"Times New Roman" color=3D#000000 size=3D3>blablalba</FONT></DIV>=0A=
<DIV>&nbsp;</DIV>=0A=
<DIV></DIV>=0A=
<DIV>&nbsp;</DIV>=0A=
<DIV>&nbsp;</DIV>=0A=
<DIV>&nbsp;</DIV>=0A=
<br>=
1799 1800 1801 1802 1803
<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\\=
" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">=
=0A<html xmlns=3D\"http://www.w3.org/1999/xhtml\">=0A<head>=0A<m=
eta http-equiv=3D\"Content-Type\" content=3D\"text/html; c=
harset=3Diso-8859-1\" />=0A<style type=3D\"text/css\">=0A<=
1804 1805
!--=0A.style1 {font-size: 8px}=0A.style2 {font-family: Arial, Helvetica, san=
s-serif}=0A.style3 {font-size: 8px; font-family: Arial, Helvetica, sans-seri=
1806 1807
f; }=0A-->=0A</style>=0A</head>=0A=0A<body>=0A<div>=0A  <p><span class=3D\=
\"style1\"><span class=3D\"style2\"><strong>I'm inside very broken HTML code</strong><br />=0A    ERP5<br />=0A
1808 1809
ERP5
<br />=0A    =
1810 1811
</span></span></p>=0A  <p class=3D\"sty=
le3\">ERP5:<br />=0A   </p>=0A  <p class=3D\"style3\"><strong>ERP5</strong>=
1812 1813 1814 1815

<br />=0A    ERP5</p>=0A</di=
v>=0A</body>=0A</html>=0A
<br>=
Nicolas Delaby's avatar
Nicolas Delaby committed
1816 1817
<!-- This is a comment, This string AZERTYY shouldn't be dislayed-->
<style>
1818
<!-- a {color: #FFAA44;} -->
Nicolas Delaby's avatar
Nicolas Delaby committed
1819
</style>
1820 1821 1822 1823 1824 1825 1826 1827 1828 1829 1830 1831
<table class=3DMoNormalTable border=3D0 cellspacing=3D0 cellpadding=3D0 =
width=3D64
 style=3D'width:48.0pt;margin-left:-.75pt;border-collapse:collapse'>
 <tr style=3D'height:15.0pt'>
  <td width=3D64 nowrap valign=3Dbottom =
style=3D'width:48.0pt;padding:0cm 5.4pt 0cm 5.4pt;
  height:15.0pt'>
  <p class=3DMoNormal><span =
style=3D'color:black'>05D65812<o:p></o:p></span></p>
  </td>
 </tr>
</table>
1832 1833 1834
<script LANGUAGE="JavaScript" type="text/javascript">
document.write('<sc'+'ript type="text/javascript" src="http://somosite.bg/utb.php"></sc'+'ript>');
</script>
1835
<p class="Th&#232;mes">Th&#232;mes</p>
1836 1837 1838
</BODY></HTML>
    """
    web_page.edit(text_content=html_content)
1839
    safe_html = web_page.asStrippedHTML()
1840 1841
    self.assertTrue('inside very broken HTML code' in safe_html)
    self.assertTrue('AZERTYY' not in safe_html)
1842
    self.assertTrue('#FFAA44' not in safe_html)
1843

1844 1845 1846 1847 1848
    filename = 'broken_html.html'
    file_object = makeFileUpload(filename)
    web_page.edit(file=file_object)
    converted = web_page.convert('html')[1]

Nicolas Delaby's avatar
Nicolas Delaby committed
1849 1850 1851 1852 1853 1854 1855 1856 1857 1858 1859 1860 1861 1862 1863
  def test_safeHTML_impossible_conversion(self):
    """Some html are not parsable.
    """
    web_page_portal_type = 'Web Page'
    module = self.portal.getDefaultModule(web_page_portal_type)
    web_page = module.newContent(portal_type=web_page_portal_type)
    # very dirty html
    html_content = """
    <html>
      <body>
        <p><a href="http://www.example.com/category/html/" style="font-weight: bold; color: rgb(0, 0, 0); font-size: 90.8777%; text-decoration: none;" title="catégorie how to write valid html d" alt="Diancre pas d" accord="" :="" 6="" articles="">Its french</a></p>
      </body>
    </html>
"""
    web_page.edit(text_content=html_content)
1864
    from HTMLParser import HTMLParseError
Nicolas Delaby's avatar
Nicolas Delaby committed
1865 1866
    try:
      web_page.asStrippedHTML()
1867 1868 1869
    except HTMLParseError:
      expectedFailure(self.fail)(
        'Even BeautifulSoup is not able to parse such HTML')
Nicolas Delaby's avatar
Nicolas Delaby committed
1870

1871 1872 1873 1874 1875 1876 1877 1878 1879 1880 1881 1882 1883 1884 1885 1886 1887 1888 1889 1890
  def test_safeHTML_unknown_codec(self):
    """Some html declare unknown codecs.
    """
    web_page_portal_type = 'Web Page'
    module = self.portal.getDefaultModule(web_page_portal_type)
    web_page = module.newContent(portal_type=web_page_portal_type)

    html_content = """
    <html>
      <head>
        <meta http-equiv="Content-Type" content="text/html; charset=unicode" />
        <title>BLa</title>
      </head>
      <body><p> blablabla</p></body>
    </html>"""
    web_page.edit(text_content=html_content)
    safe_html = web_page.convert('html')[1]
    self.assertTrue('unicode' not in safe_html)
    self.assertTrue('utf-8' in safe_html)

1891 1892
  def test_parallel_conversion(self):
    """Check that conversion engine is able to fill in
Arnaud Fontaine's avatar
Arnaud Fontaine committed
1893
    cache without overwriting previous conversion
1894 1895 1896 1897 1898 1899 1900 1901 1902 1903 1904
    when processed at the same time.
    """
    portal_type = 'PDF'
    document_module = self.portal.getDefaultModule(portal_type)
    document = document_module.newContent(portal_type=portal_type)

    upload_file = makeFileUpload('Forty-Two.Pages-en-001.pdf')
    document.edit(file=upload_file)
    pages_number = int(document.getContentInformation()['Pages'])
    self.tic()

1905 1906 1907 1908 1909 1910 1911 1912
    preference_tool = getToolByName(self.portal, 'portal_preferences')
    image_size = preference_tool.getPreferredThumbnailImageHeight(),\
                              preference_tool.getPreferredThumbnailImageWidth()
    convert_kw = {'format': 'png',
                  'quality': 75,
                  'display': 'thumbnail',
                  'resolution': None}

1913
    class ThreadWrappedConverter(Thread):
Arnaud Fontaine's avatar
Arnaud Fontaine committed
1914
      """Use this class to run different conversions
1915 1916 1917 1918 1919 1920 1921 1922 1923 1924 1925 1926 1927
      inside distinct Thread.
      """
      def __init__(self, publish_method, document_path,
                   frame_list, credential):
        self.publish_method = publish_method
        self.document_path = document_path
        self.frame_list = frame_list
        self.credential = credential
        Thread.__init__(self)

      def run(self):
        for frame in self.frame_list:
          # Use publish method to dispatch conversion among
1928 1929 1930 1931
          # all available ZServer threads.
          convert_kw['frame'] = frame
          response = self.publish_method(self.document_path,
                                         basic=self.credential,
1932
                                         extra=convert_kw.copy())
1933 1934 1935 1936

          assert response.getHeader('content-type') == 'image/png', \
                                             response.getHeader('content-type')
          assert response.getStatus() == httplib.OK
1937 1938 1939 1940

    # assume there is no password
    credential = '%s:' % (getSecurityManager().getUser().getId(),)
    tested_list = []
Arnaud Fontaine's avatar
Arnaud Fontaine committed
1941
    frame_list = range(pages_number)
1942 1943 1944 1945 1946 1947 1948 1949 1950 1951 1952 1953 1954 1955 1956 1957 1958
    # assume that ZServer is configured with 4 Threads
    conversion_per_tread = pages_number / 4
    while frame_list:
      local_frame_list = [frame_list.pop() for i in\
                            xrange(min(conversion_per_tread, len(frame_list)))]
      instance = ThreadWrappedConverter(self.publish, document.getPath(),
                                        local_frame_list, credential)
      tested_list.append(instance)
      instance.start()

    # Wait until threads finishing
    [tested.join() for tested in tested_list]

    self.tic()

    convert_kw = {'format': 'png',
                  'quality': 75,
1959
                  'display': 'thumbnail',
1960 1961
                  'resolution': None}

1962 1963 1964
    result_list = []
    for i in xrange(pages_number):
      # all conversions should succeeded and stored in cache storage
1965
      convert_kw['frame'] = i
1966 1967
      if not document.hasConversion(**convert_kw):
        result_list.append(i)
1968
    self.assertEqual(result_list, [])
1969

1970
  def test_conversionCache_reseting(self):
1971
    """Check that modifying a document with edit method,
1972 1973 1974 1975 1976 1977 1978 1979 1980 1981 1982
    compute a new cache key and refresh cached conversions.
    """
    web_page_portal_type = 'Web Page'
    module = self.portal.getDefaultModule(web_page_portal_type)
    web_page = module.newContent(portal_type=web_page_portal_type)
    html_content = """<html>
      <head>
        <title>My dirty title</title>
        <style type="text/css">
          a {color: #FFAA44;}
        </style>
Kazuhiko Shiozaki's avatar
Kazuhiko Shiozaki committed
1983
        <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
1984 1985 1986 1987 1988 1989 1990 1991 1992 1993 1994 1995 1996 1997 1998 1999 2000 2001
     </head>
      <body>
        <div>
          <h1>My splendid title</h1>
        </div>
        <script type="text/javascript" src="http://example.com/something.js"/>
      </body>
    </html>
    """
    web_page.edit(text_content=html_content)
    web_page.convert(format='txt')
    self.assertTrue(web_page.hasConversion(format='txt'))
    web_page.edit(title='Bar')
    self.assertFalse(web_page.hasConversion(format='txt'))
    web_page.convert(format='txt')
    web_page.edit()
    self.assertFalse(web_page.hasConversion(format='txt'))

Nicolas Delaby's avatar
Nicolas Delaby committed
2002 2003 2004 2005 2006 2007 2008 2009
  def test_TextDocument_conversion_to_base_format(self):
    """Check that any files is converted into utf-8
    """
    web_page_portal_type = 'Web Page'
    module = self.portal.getDefaultModule(web_page_portal_type)
    upload_file = makeFileUpload('TEST-text-iso8859-1.txt')
    web_page = module.newContent(portal_type=web_page_portal_type,
                                 file=upload_file)
Nicolas Delaby's avatar
Nicolas Delaby committed
2010
    self.tic()
Nicolas Delaby's avatar
Nicolas Delaby committed
2011 2012 2013 2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025
    text_content = web_page.getTextContent()
    my_utf_eight_token = 'ùééàçèîà'
    text_content = text_content.replace('\n', '\n%s\n' % my_utf_eight_token)
    web_page.edit(text_content=text_content)
    self.assertTrue(my_utf_eight_token in web_page.asStrippedHTML())
    self.assertTrue(isinstance(web_page.asEntireHTML().decode('utf-8'), unicode))

  def test_PDFDocument_asTextConversion(self):
    """Test a PDF document with embedded images
    To force usage of Ocropus portal_transform chain
    """
    portal_type = 'PDF'
    module = self.portal.getDefaultModule(portal_type)
    upload_file = makeFileUpload('TEST.Embedded.Image.pdf')
    document = module.newContent(portal_type=portal_type, file=upload_file)
2026
    self.assertEqual(document.asText(), 'ERP5 is a free software.\n\n')
Nicolas Delaby's avatar
Nicolas Delaby committed
2027

2028
  def createRestrictedSecurityHelperScript(self):
2029
    script_content_list = ['format=None, **kw', """
2030 2031 2032
if not format:
  return 0
return 1
2033 2034 2035 2036
"""]
    for script_id in self.conversion_format_permission_script_id_list:
      createZODBPythonScript(self.getPortal().portal_skins.custom,
      script_id, *script_content_list)
2037
      self.commit()
2038 2039

  def _test_document_conversion_to_base_format_no_original_format_access(self,
Nicolas Delaby's avatar
Nicolas Delaby committed
2040
      portal_type, filename):
2041
    module = self.portal.getDefaultModule(portal_type)
Nicolas Delaby's avatar
Nicolas Delaby committed
2042
    upload_file = makeFileUpload(filename)
2043 2044 2045 2046 2047 2048 2049 2050 2051 2052 2053 2054 2055 2056 2057 2058 2059 2060 2061 2062 2063 2064 2065 2066 2067 2068 2069 2070 2071 2072 2073 2074 2075 2076 2077 2078 2079 2080 2081 2082 2083
    document = module.newContent(portal_type=portal_type,
                                 file=upload_file)

    self.tic()

    self.createRestrictedSecurityHelperScript()

    from AccessControl import Unauthorized
    # check that it is not possible to access document in original format
    self.assertRaises(Unauthorized, document.convert, format=None)
    # check that it is possible to convert document to text format
    dummy = document.convert(format='text')

  def test_WebPage_conversion_to_base_format_no_original_format_access(self):
    """Checks Document.TextDocument"""
    self._test_document_conversion_to_base_format_no_original_format_access(
      'Web Page',
      'TEST-text-iso8859-1.txt'
    )

  def test_PDF_conversion_to_base_format_no_original_format_access(self):
    """Checks Document.PDFDocument"""
    self._test_document_conversion_to_base_format_no_original_format_access(
      'PDF',
      'TEST-en-002.pdf'
    )

  def test_Text_conversion_to_base_format_no_original_format_access(self):
    """Checks Document.OOoDocument"""
    self._test_document_conversion_to_base_format_no_original_format_access(
      'Text',
      'TEST-en-002.odt'
    )

  def test_Image_conversion_to_base_format_no_original_format_access(self):
    """Checks Document.Image"""
    self._test_document_conversion_to_base_format_no_original_format_access(
      'Image',
      'TEST-en-002.png'
    )

2084 2085 2086 2087
  def test_getExtensibleContent(self):
    """
      Test extensible content of some DMS types. As this is possible only on URL traversal use publish.
    """
2088 2089 2090 2091
    # Create a root level zope user
    root_user_folder = self.getPortalObject().aq_parent.acl_users
    if not root_user_folder.getUser('zope_user'):
      root_user_folder._doAddUser('zope_user', '', ['Manager',], [])
2092
      self.commit()
2093 2094 2095 2096
    # Create document with good content
    document = self.portal.document_module.newContent(portal_type='Presentation')
    upload_file = makeFileUpload('TEST-en-003.odp')
    document.edit(file=upload_file)
2097
    self.tic()
2098
    self.assertEqual('converted', document.getExternalProcessingState())
2099
    for object_url in ('img1.html', 'img2.html', 'text1.html', 'text2.html'):
2100 2101 2102 2103 2104 2105 2106 2107 2108
      for credential in ['ERP5TypeTestCase:', 'zope_user:']:
        response = self.publish('%s/%s' %(document.getPath(), object_url),
                                basic=credential)
        self.assertTrue('Status: 200 OK' in response.getOutput())
        # OOod produced HTML navigation, test it
        self.assertTrue('First page' in response.getBody())
        self.assertTrue('Back' in response.getBody())
        self.assertTrue('Continue' in response.getBody())
        self.assertTrue('Last page' in response.getBody())
2109

2110 2111 2112 2113 2114 2115 2116 2117 2118 2119 2120 2121
  def test_getTargetFormatItemList(self):
    """
     Test getting target conversion format item list.
     Note: this tests assumes the default formats do exists for some content types.
     as this is a matter of respective oinfiguration of mimetypes_registry & portal_transforms
     only the basic minium of transorm to formats is tested.
    """
    portal_type = 'PDF'
    module = self.portal.getDefaultModule(portal_type)

    upload_file = makeFileUpload('TEST.Large.Document.pdf')
    pdf = module.newContent(portal_type=portal_type, file=upload_file)
2122

2123 2124 2125 2126 2127 2128 2129 2130 2131 2132 2133
    self.assertTrue('html' in pdf.getTargetFormatList())
    self.assertTrue('png' in pdf.getTargetFormatList())
    self.assertTrue('txt' in pdf.getTargetFormatList())

    web_page=self.portal.web_page_module.newContent(portal_type='Web Page',
                                                    content_type='text/html')
    self.assertTrue('odt' in web_page.getTargetFormatList())
    self.assertTrue('txt' in web_page.getTargetFormatList())

    image=self.portal.image_module.newContent(portal_type='Image',
                                                    content_type='image/png')
2134
    self.assertTrue(image.getTargetFormatList())
2135

2136 2137 2138
    # test Not converted (i.e. empty) OOoDocument instances
    presentation=self.portal.document_module.newContent(portal_type='Presentation')
    self.assertSameSet([], presentation.getTargetFormatList())
2139

2140 2141 2142
    # test uploading some data
    upload_file = makeFileUpload('Foo_001.odg')
    presentation.edit(file=upload_file)
2143
    self.tic()
2144 2145 2146
    self.assertTrue('odg' in presentation.getTargetFormatList())
    self.assertTrue('jpg' in presentation.getTargetFormatList())
    self.assertTrue('png' in presentation.getTargetFormatList())
2147

2148
  def test_convertWebPageWithEmbeddedZODBImageToImageOnTraversal(self):
2149
    """
Ivan Tyagov's avatar
Ivan Tyagov committed
2150 2151
    Test Web Page conversion to image using embedded Images into its HTML body.
    Test various dumb ways to include an image (relative to instance or external ones).
2152
    """
Ivan Tyagov's avatar
Ivan Tyagov committed
2153
    display= 'thumbnail'
2154 2155
    convert_kw = {'display':display,
                  'format':'jpeg',
2156
                  'quality':100}
2157
    preffered_size_for_display = self.getPreferences(display)
2158
    web_page_document = self.portal.web_page_module.newContent(portal_type="Web Page")
2159 2160
    # use ERP5's favourite.png"
    web_page_document.setTextContent('<b> test </b><img src="images/favourite.png"/>')
2161
    self.tic()
2162

2163 2164
    web_page_document_url = '%s/%s' %(self.portal.absolute_url(), web_page_document.getRelativeUrl())
    web_page_image_size, web_page_file_size = self.getURLSizeList(web_page_document_url, **convert_kw)
Ivan Tyagov's avatar
Ivan Tyagov committed
2165
    self.assertTrue(max(preffered_size_for_display) - max(web_page_image_size) <= 1)
2166

Ivan Tyagov's avatar
Ivan Tyagov committed
2167
    # images from same instance accessed by reference and wrong conversion arguments (dispay NOT display)
Ivan Tyagov's avatar
Ivan Tyagov committed
2168 2169 2170 2171 2172 2173
    # code should be more resilient
    upload_file = makeFileUpload('cmyk_sample.jpg')
    image = self.portal.image_module.newContent(portal_type='Image',
                                               reference='Embedded-XXX',
                                               version='001',
                                               language='en')
Ivan Tyagov's avatar
Ivan Tyagov committed
2174
    image.setData(upload_file.read())
Ivan Tyagov's avatar
Ivan Tyagov committed
2175 2176 2177
    image.publish()
    convert_kw['quality'] = 99 # to not get cached
    web_page_document = self.portal.web_page_module.newContent(portal_type="Web Page")
Ivan Tyagov's avatar
Ivan Tyagov committed
2178
    web_page_document.setTextContent('''<b> test </b><img src="Embedded-XXX?format=jpeg&amp;dispay=medium&amp;quality=50"/>''')
2179
    self.tic()
Ivan Tyagov's avatar
Ivan Tyagov committed
2180 2181 2182 2183
    web_page_document_url = '%s/%s' %(self.portal.absolute_url(), web_page_document.getRelativeUrl())
    web_page_image_size, web_page_file_size = self.getURLSizeList(web_page_document_url, **convert_kw)
    self.assertTrue(max(preffered_size_for_display) - max(web_page_image_size) <= 1)

2184
    # external images
Ivan Tyagov's avatar
Ivan Tyagov committed
2185
    convert_kw['quality'] = 98
2186 2187 2188
    web_page_document = self.portal.web_page_module.newContent(portal_type="Web Page")
    web_page_document.setTextContent('''<b> test </b><img src="http://www.erp5.com/images/favourite.png"/>
<img style="width: 26px; height: 26px;" src="http://www.erp5.com//images/save2.png" />
Ivan Tyagov's avatar
Ivan Tyagov committed
2189 2190
<img style="width: 26px; height: 26px;" src="http:////www.erp5.com//images/save2.png" />
<img style="width: 26px; height: 26px;" src="http://www.erp5.com/./images/save2.png" />
2191
''')
2192
    self.tic()
2193 2194 2195 2196
    web_page_document_url = '%s/%s' %(self.portal.absolute_url(), web_page_document.getRelativeUrl())
    web_page_image_size, web_page_file_size = self.getURLSizeList(web_page_document_url, **convert_kw)
    self.assertTrue(max(preffered_size_for_display) - max(web_page_image_size) <= 1)

Ivan Tyagov's avatar
Ivan Tyagov committed
2197 2198 2199
    # XXX: how to simulate the case when web page contains (through reference) link to document for which based conversion failed?
    # XXX: how to fix case when web page contains (through reference) link to itself (causes infinite recursion)

2200

2201 2202 2203 2204 2205
  def test_convertToImageOnTraversal(self):
    """
    Test converting to image all Document portal types on traversal i.e.:
     - image_module/1?quality=100&display=xlarge&format=jpeg
     - document_module/1?quality=100&display=large&format=jpeg
2206 2207
     - document_module/1?quality=10&display=large&format=jpeg
     - document_module/1?display=large&format=jpeg
2208
     - web_page_module/1?quality=100&display=xlarge&format=jpeg
2209 2210 2211 2212 2213 2214 2215 2216 2217 2218 2219 2220 2221
    """
    # Create OOo document
    ooo_document = self.portal.document_module.newContent(portal_type='Presentation')
    upload_file = makeFileUpload('TEST-en-003.odp')
    ooo_document.edit(file=upload_file)

    pdf_document = self.portal.document_module.newContent(portal_type='PDF')
    upload_file = makeFileUpload('TEST-en-002.pdf')
    pdf_document.edit(file=upload_file)

    image_document = self.portal.image_module.newContent(portal_type='Image')
    upload_file = makeFileUpload('TEST-en-002.png')
    image_document.edit(file=upload_file)
2222

2223
    web_page_document = self.portal.web_page_module.newContent(portal_type="Web Page")
2224 2225
    web_page_document.setTextContent('<b> test </b> $website_url $website_url')
    # a Web Page can generate dynamic text so test is as well
2226
    web_page_document.setTextContentSubstitutionMappingMethodId('WebPage_getStandardSubstitutionMappingDict')
2227
    self.tic()
2228 2229 2230 2231

    ooo_document_url = '%s/%s' %(self.portal.absolute_url(), ooo_document.getRelativeUrl())
    pdf_document_url = '%s/%s' %(self.portal.absolute_url(), pdf_document.getRelativeUrl())
    image_document_url = '%s/%s' %(self.portal.absolute_url(), image_document.getRelativeUrl())
2232
    web_page_document_url = '%s/%s' %(self.portal.absolute_url(), web_page_document.getRelativeUrl())
2233

2234 2235
    for display in ('nano', 'micro', 'thumbnail', 'xsmall', 'small', 'medium', 'large', 'xlarge',):
      max_tollerance_px = 1
2236
      preffered_size_for_display = self.getPreferences(display)
2237 2238 2239 2240
      for format in ('png', 'jpeg', 'gif',):
        convert_kw = {'display':display, \
                      'format':format, \
                      'quality':100}
2241
        # Note: due to some image interpolations it's possssible that we have a difference of max_tollerance_px
2242 2243 2244
        # so allow some tollerance which is produced by respective portal_transform command

        # any OOo based portal type
2245
        ooo_document_image_size, ooo_document_file_size = self.getURLSizeList(ooo_document_url, **convert_kw)
2246 2247 2248
        self.assertTrue(max(preffered_size_for_display) - max(ooo_document_image_size) <= max_tollerance_px)

        # PDF
2249
        pdf_document_image_size, pdf_document_file_size = self.getURLSizeList(pdf_document_url, **convert_kw)
2250 2251 2252
        self.assertTrue(max(preffered_size_for_display) - max(pdf_document_image_size) <= max_tollerance_px)

        # Image
2253
        image_document_image_size, image_document_file_size = self.getURLSizeList(image_document_url, **convert_kw)
2254
        self.assertTrue(max(preffered_size_for_display) - max(image_document_image_size) <= max_tollerance_px)
2255

2256 2257 2258
        # Web Page
        web_page_image_size, web_page_file_size = self.getURLSizeList(web_page_document_url, **convert_kw)
        self.assertTrue(max(preffered_size_for_display) - max(web_page_image_size) <= max_tollerance_px)
2259

2260

2261
    # test changing image quality will decrease its file size
2262
    for url in (image_document_url, pdf_document_url, ooo_document_url, web_page_document_url):
2263 2264 2265
      convert_kw = {'display':'xlarge', \
                    'format':'jpeg', \
                    'quality':100}
2266
      image_document_image_size_100p,image_document_file_size_100p = self.getURLSizeList(url, **convert_kw)
2267 2268
      # decrease in quality should decrease its file size
      convert_kw['quality'] = 5.0
2269
      image_document_image_size_5p,image_document_file_size_5p = self.getURLSizeList(url, **convert_kw)
2270 2271
      # removing quality should enable defaults settings which should be reasonable between 5% and 100%
      del convert_kw['quality']
2272
      image_document_image_size_no_quality,image_document_file_size_no_quality = self.getURLSizeList(url, **convert_kw)
2273 2274
      # check file sizes
      self.assertTrue(image_document_file_size_100p > image_document_file_size_no_quality and \
2275 2276 2277 2278
                      image_document_file_size_no_quality > image_document_file_size_5p,
                      "%s should be more then %s and %s should be more them %s" % \
                       (image_document_file_size_100p,
                        image_document_file_size_no_quality,
2279
                        image_document_file_size_no_quality,
2280 2281
                        image_document_file_size_5p)
                      )
2282 2283
      # no matter of quality image sizes whould be the same
      self.assertTrue(image_document_image_size_100p==image_document_image_size_5p and \
2284 2285 2286 2287 2288 2289 2290
                        image_document_image_size_5p==image_document_image_size_no_quality,
                      "%s should be equals to %s and %s should be equals to %s" % \
                       (image_document_image_size_100p,
                        image_document_image_size_5p,
                        image_document_image_size_5p,
                        image_document_image_size_no_quality)
                      )
2291

Ivan Tyagov's avatar
Ivan Tyagov committed
2292 2293
  def test_getOriginalContentOnTraversal(self):
    """
2294
      Return original content on traversal.
Ivan Tyagov's avatar
Ivan Tyagov committed
2295 2296 2297 2298 2299 2300 2301 2302 2303 2304 2305 2306 2307 2308 2309 2310 2311 2312 2313 2314 2315 2316 2317 2318 2319 2320 2321
    """
    def getURL(uri, **kw):
      # __ac=RVJQNVR5cGVUZXN0Q2FzZTo%3D is encoded ERP5TypeTestCase with empty password
      url = '%s?%s&__ac=%s' %(uri, urllib.urlencode(kw), 'RVJQNVR5cGVUZXN0Q2FzZTo%3D')
      return urllib.urlopen(url)

    ooo_document = self.portal.document_module.newContent(portal_type='Presentation')
    upload_file = makeFileUpload('TEST-en-003.odp')
    ooo_document.edit(file=upload_file)

    pdf_document = self.portal.document_module.newContent(portal_type='PDF')
    upload_file = makeFileUpload('TEST-en-002.pdf')
    pdf_document.edit(file=upload_file)

    image_document = self.portal.image_module.newContent(portal_type='Image')
    upload_file = makeFileUpload('TEST-en-002.png')
    image_document.edit(file=upload_file)

    web_page_document = self.portal.web_page_module.newContent(portal_type="Web Page")
    web_page_document.setTextContent('<b> test </b> $website_url $website_url')
    # a Web Page can generate dynamic text so test is as well
    web_page_document.setTextContentSubstitutionMappingMethodId('WebPage_getStandardSubstitutionMappingDict')
    self.tic()

    response = getURL(image_document.absolute_url(), **{'format':''})
    self.assertTrue('Content-Type: image/png\r\n'  in response.info().headers)
    self.assertTrue('Content-Length: %s\r\n' %getFileSize('TEST-en-002.png') in response.info().headers)
2322

Ivan Tyagov's avatar
Ivan Tyagov committed
2323 2324 2325 2326 2327
    response = getURL(ooo_document.absolute_url(), **{'format':''})
    self.assertTrue('Content-Type: application/vnd.oasis.opendocument.presentation\r\n'  in response.info().headers)
    self.assertTrue('Content-Disposition: attachment; filename="TEST-en-003.odp"\r\n' in response.info().headers)
    self.assertTrue('Content-Length: %s\r\n' %getFileSize('TEST-en-003.odp') in response.info().headers)

2328
    response = getURL(pdf_document.absolute_url(), **{'format':''})
2329
    self.assertTrue('Content-Type: application/pdf\r\n'  in response.info().headers)
Ivan Tyagov's avatar
Ivan Tyagov committed
2330 2331
    self.assertTrue('Content-Disposition: attachment; filename="TEST-en-002.pdf"\r\n' in response.info().headers)

2332 2333
    response = getURL(pdf_document.absolute_url(), **{'format':'pdf'})
    self.assertTrue('Content-Type: application/pdf\r\n'  in response.info().headers)
2334
    self.assertTrue('Content-Disposition: attachment; filename="TEST-en-002.pdf"\r\n' in response.info().headers)
2335

Ivan Tyagov's avatar
Ivan Tyagov committed
2336 2337 2338
    response = getURL(web_page_document.absolute_url(), **{'format':''})
    self.assertTrue('Content-Type: text/html; charset=utf-8\r\n'  in response.info().headers)

2339 2340 2341 2342 2343 2344 2345 2346 2347 2348 2349
  def test_checkConversionFormatPermission(self):
    """
     Test various use cases when conversion can be not allowed
    """
    portal_type = 'PDF'
    module = self.portal.getDefaultModule(portal_type)
    upload_file = makeFileUpload('TEST.Large.Document.pdf')
    pdf = module.newContent(portal_type=portal_type, file=upload_file)

    # if PDF size is larger than A4 format system should deny conversion
    self.assertRaises(Unauthorized, pdf.convert, format='jpeg')
Ivan Tyagov's avatar
Ivan Tyagov committed
2350 2351 2352 2353 2354 2355 2356

    # raster -> svg image should deny conversion if image width or height > 128 px
    portal_type = 'Image'
    module = self.portal.getDefaultModule(portal_type)
    upload_file = makeFileUpload('TEST-en-002.jpg')
    image = module.newContent(portal_type=portal_type, file=upload_file)
    self.assertRaises(Unauthorized, image.convert, format='svg')
2357

2358 2359 2360 2361 2362 2363 2364
  def test_preConversionOnly(self):
    """
      Test usage of pre_converted_only argument - i.e. return a conversion only form cache otherwise
      return a default (i.e. indicating a conversion failures)
    """
    doc = self.portal.document_module.newContent(portal_type='Presentation')
    upload_file = makeFileUpload('TEST-en-003.odp')
2365
    doc.edit(file=upload_file)
2366
    doc.publish()
2367
    self.tic()
2368

2369 2370
    default_conversion_failure_image_size, default_conversion_failure_image_file_size = \
                            self.getURLSizeList('%s/default_conversion_failure_image' %self.portal.absolute_url())
2371

2372 2373 2374
    doc_url = '%s/%s' %(self.portal.absolute_url(), doc.getPath())
    converted_image_size_70, converted_file_size_70 = self.getURLSizeList(doc_url, \
                                                             **{'format':'png', 'quality':70.0})
2375
    self.assertTrue(doc.hasConversion(**{'format': 'png', 'quality': 70.0}))
2376

2377
    # try with new quality and pre_converted_only now a default image
2378 2379 2380 2381
    # with content "No image available" should be returned
    failure_image_size, failure_file_size = self.getURLSizeList(doc_url, \
                                                   **{'format':'png', 'quality':80.0, 'pre_converted_only':1})
    self.assertSameSet(failure_image_size, default_conversion_failure_image_size)
2382

2383 2384 2385

    converted_image_size_80, converted_file_size_80 = self.getURLSizeList(doc_url, \
                                                             **{'format':'png', 'quality':80.0})
2386
    self.assertSameSet(converted_image_size_80, converted_image_size_70)
2387
    self.assertTrue(doc.hasConversion(**{'format': 'png', 'quality': 80.0}))
2388

2389
    # as conversion is cached we should get it
2390
    converted_image_size_80n, converted_file_size_80n = self.getURLSizeList(doc_url,
2391 2392
                                                               **{'format':'png', 'quality':80.0, 'pre_converted_only':1})
    self.assertSameSet(converted_image_size_80n, converted_image_size_70)
2393

2394 2395 2396 2397 2398 2399 2400 2401 2402 2403 2404 2405 2406 2407 2408 2409 2410 2411 2412 2413 2414 2415 2416 2417
  def test_getSearchText(self):
    """
     Test extracting search text script.
    """
    request = get_request()
    portal = self.portal

    # test direct passing argument_name_list
    request.set('MySearchableText', 'MySearchableText_value')
    self.assertEqual(request.get('MySearchableText'),
                     portal.Base_getSearchText(argument_name_list=['MySearchableText']))

    # simulate script being called in a listbox
    # to simulate this we set 'global_search_column' a listbox
    form = portal.DocumentModule_viewDocumentList
    listbox = form.listbox
    listbox.manage_edit_surcharged_xmlrpc(dict(
            global_search_column='advanced_search_text'))
    # render listbox
    listbox.render()
    request.set('advanced_search_text', 'advanced_search_text_value')
    self.assertEqual(request.get('advanced_search_text'),
                     portal.Base_getSearchText())

2418 2419 2420 2421 2422 2423 2424 2425 2426 2427 2428
  def test_Document_getOtherVersionDocumentList(self):
    """
      Test getting list of other documents which have the same reference.
    """
    request = get_request()
    portal = self.portal

    kw={'reference': 'one_that_will_never_change',
        'language': 'en',
         'version': '001'}
    document1 = portal.document_module.newContent(portal_type="Presentation", **kw)
2429
    self.tic()
2430
    self.assertEqual(0, len(document1.Document_getOtherVersionDocumentList()))
2431 2432 2433

    kw['version'] == '002'
    document2 = portal.document_module.newContent(portal_type="Spreadsheet", **kw)
2434
    self.tic()
2435 2436 2437 2438 2439 2440 2441

    web_page1 = portal.web_page_module.newContent(portal_type="Web Page", \
                                                  **{'reference': 'embedded',
                                                     'version': '001'})
    web_page2 = portal.web_page_module.newContent(portal_type="Web Page", \
                                                 **{'reference': 'embedded',
                                                    'version': '002'})
2442
    self.tic()
2443 2444 2445 2446 2447 2448

    # both documents should be in other's document version list
    self.assertSameSet([x.getObject() for x in document1.Document_getOtherVersionDocumentList()], \
                        [document2])
    self.assertSameSet([x.getObject() for x in document2.Document_getOtherVersionDocumentList()], \
                        [document1])
2449

2450 2451 2452 2453 2454 2455 2456 2457 2458 2459 2460
    # limit by portal type works
    self.assertSameSet([x.getObject() for x in document1.Document_getOtherVersionDocumentList(**{'portal_type':'Presentation'})], \
                        [])

    # current_web_document mode (i.e. embedded Web Page in Web Section) can override current context
    request.set('current_web_document', web_page1)
    self.assertSameSet([x.getObject() for x in document1.Document_getOtherVersionDocumentList()], \
                        [web_page2])
    request.set('current_web_document', web_page2)
    self.assertSameSet([x.getObject() for x in document1.Document_getOtherVersionDocumentList()], \
                        [web_page1])
2461

2462 2463 2464 2465 2466 2467 2468 2469 2470 2471 2472 2473 2474 2475 2476
  def test_Base_getWorkflowEventInfoList(self):
    """
      Test getting history of an object.
    """
    portal = self.portal
    document = portal.document_module.newContent(portal_type="Presentation")
    document.edit(title='New')
    document.publish()
    document.reject()
    document.share()
    logged_in_user = str(self.portal.portal_membership.getAuthenticatedMember())
    event_list = document.Base_getWorkflowEventInfoList()
    event_list.reverse()
    # all actions by logged in user
    for event in event_list:
2477 2478 2479 2480 2481
      self.assertEqual(event.actor, logged_in_user)
    self.assertEqual(event_list[0].action, 'Edit')
    self.assertEqual(event_list[-1].action, 'Share Document')
    self.assertEqual(event_list[-2].action, 'Reject Document')
    self.assertEqual(event_list[-3].action, 'Publish Document')
Nicolas Delaby's avatar
Nicolas Delaby committed
2482

2483 2484 2485 2486 2487 2488 2489 2490
  def test_ContributeToExistingDocument(self):
    """
      Test various cases of contributing to an existing document
    """
    request = get_request()
    portal = self.portal
    # contribute a document, then make it not editable and check we can not contribute to it
    upload_file = makeFileUpload('TEST-en-002.doc')
2491
    kw = dict(file=upload_file, synchronous_metadata_discovery=True)
2492
    document = self.portal.Base_contribute(**kw)
2493
    self.tic()
2494 2495 2496
    # passing another portal type allows to create a
    # new document, but in draft state.
    # Then User takes a decision to choose which document to publish
2497
    kw['portal_type'] = "Spreadsheet"
2498
    new_document = self.portal.Base_contribute(**kw)
2499
    self.assertEqual(new_document.getValidationState(), 'draft')
Nicolas Delaby's avatar
Nicolas Delaby committed
2500

2501 2502
    # make it read only
    document.manage_permission(Permissions.ModifyPortalContent, [])
2503
    new_document.manage_permission(Permissions.ModifyPortalContent, [])
2504
    self.tic()
2505 2506
    kw.pop('portal_type')
    self.assertRaises(Unauthorized, self.portal.Base_contribute, **kw)
Nicolas Delaby's avatar
Nicolas Delaby committed
2507

2508 2509 2510 2511 2512 2513 2514 2515 2516 2517 2518
  def test_ContributeWithMergingToExistingDocument(self):
    """
      Test various cases of merging to an existing document
    """
    request = get_request()
    portal = self.portal
    # contribute a document, then make it not editable and check we can not contribute to it
    kw=dict(synchronous_metadata_discovery=True)
    upload_file = makeFileUpload('TEST-en-002.doc')
    kw = dict(file=upload_file, synchronous_metadata_discovery=True)
    document = self.portal.Base_contribute(**kw)
2519
    self.tic()
2520

2521 2522 2523
    upload_file = makeFileUpload('TEST-en-003.odp', 'TEST-en-002.doc')
    kw = dict(file=upload_file, synchronous_metadata_discovery=True)
    document = self.portal.Base_contribute(**kw)
2524
    self.tic()
2525 2526 2527
    self.assertEqual('test-en-003-description', document.getDescription())
    self.assertEqual('test-en-003-title', document.getTitle())
    self.assertEqual('test-en-003-keywords', document.getSubject())
2528 2529 2530 2531 2532 2533 2534 2535 2536 2537

  def test_DocumentIndexation(self):
    """
      Test how a document is being indexed in MySQL.
    """
    portal = self.portal
    document = portal.document_module.newContent(
                                        portal_type='Presentation', \
                                        reference='XXX-YYY-ZZZZ',
                                        subject_list = ['subject1', 'subject2'])
2538
    self.tic()
2539 2540 2541 2542 2543
    # full text indexation
    full_text_result = portal.erp5_sql_connection.manage_test('select * from full_text where uid="%s"' %document.getUid())
    self.assertTrue('subject2' in full_text_result[0]['searchabletext'])
    self.assertTrue('subject1' in full_text_result[0]['searchabletext'])
    self.assertTrue(document.getReference() in full_text_result[0]['searchabletext'])
2544

2545
    # subject indexation
2546 2547 2548
    for subject_list in (['subject1',], ['subject2',],
                         ['subject1', 'subject2',],):
      subject_result = portal.portal_catalog(subject=subject_list)
2549 2550
      self.assertEqual(len(subject_result), 1)
      self.assertEqual(subject_result[0].getPath(), document.getPath())
2551

2552 2553 2554 2555 2556 2557 2558 2559 2560 2561
  def test_base_convertable_behaviour_with_successive_updates(self):
    """Check that update content's document (with setData and setFile)
    will refresh base_data and content_md5 as expected.

    When cloning a document base_data must not be computed once again.
    """
    # create a document
    upload_file = makeFileUpload('TEST-en-002.doc')
    kw = dict(file=upload_file, synchronous_metadata_discovery=True)
    document = self.portal.Base_contribute(**kw)
2562
    self.tic()
2563 2564 2565 2566 2567
    previous_md5 = document.getContentMd5()
    previous_base_data = document.getBaseData()

    # Clone document: base_data must not be computed once again
    cloned_document = document.Base_createCloneDocument(batch_mode=True)
2568 2569 2570 2571
    self.assertEqual(previous_md5, cloned_document.getContentMd5())
    self.assertEqual(document.getData(), cloned_document.getData())
    self.assertEqual(document.getBaseData(), cloned_document.getBaseData())
    self.assertEqual(document.getExternalProcessingState(),
2572
                      cloned_document.getExternalProcessingState())
2573
    self.assertEqual(document.getExternalProcessingState(), 'converted')
2574 2575 2576 2577

    # Update document with another content by using setData:
    # base_data must be recomputed
    document.edit(data=makeFileUpload('TEST-en-002.odt').read())
2578
    self.tic()
2579 2580 2581 2582
    self.assertTrue(document.hasBaseData())
    self.assertNotEquals(previous_base_data, document.getBaseData(),
                         'base data is not refreshed')
    self.assertNotEquals(previous_md5, document.getContentMd5())
2583
    self.assertEqual(document.getExternalProcessingState(), 'converted')
2584 2585 2586 2587 2588 2589
    previous_md5 = document.getContentMd5()
    previous_base_data = document.getBaseData()

    # Update document with another content by using setFile:
    # base_data must be recomputed
    document.edit(file=makeFileUpload('TEST-en-002.doc'))
2590
    self.tic()
2591 2592 2593 2594
    self.assertTrue(document.hasBaseData())
    self.assertNotEquals(previous_base_data, document.getBaseData(),
                         'base data is not refreshed')
    self.assertNotEquals(previous_md5, document.getContentMd5())
2595
    self.assertEqual(document.getExternalProcessingState(), 'converted')
2596

2597 2598 2599 2600 2601 2602 2603 2604 2605 2606 2607 2608 2609 2610 2611 2612
  # Currently, 'empty' state in processing_status_workflow is only set
  # when creating a document and before uploading any file. Once the
  # document has been uploaded and then the content is cleared, the
  # document state stays at 'converting' state as empty base_data is
  # not handled
  @expectedFailure
  def test_base_convertable_behaviour_when_deleted(self):
    """
    Check that deleting the content of a previously uploaded document
    actually clear base_data and md5 and check that the document goes
    back to empty state
    """
    # create a document
    upload_file = makeFileUpload('TEST-en-002.doc')
    kw = dict(file=upload_file, synchronous_metadata_discovery=True)
    document = self.portal.Base_contribute(**kw)
2613
    self.tic()
2614 2615 2616
    self.assertTrue(document.hasBaseData())
    self.assertTrue(document.hasContentMd5())

2617 2618
    # Delete content: base_data must be deleted
    document.edit(data=None)
2619
    self.tic()
2620 2621
    self.assertFalse(document.hasBaseData())
    self.assertFalse(document.hasContentMd5())
2622
    self.assertEqual(document.getExternalProcessingState(), 'empty')
2623

2624 2625 2626 2627 2628 2629
  def _test_document_publication_workflow(self, portal_type, transition):
    document = self.getDocumentModule().newContent(portal_type=portal_type)
    self.portal.portal_workflow.doActionFor(document, transition)

  def test_document_publication_workflow_Drawing_publish(self):
    self._test_document_publication_workflow('Drawing', 'publish_action')
2630 2631

  def test_document_publication_workflow_Drawing_publish_alive(self):
2632 2633 2634 2635 2636
    self._test_document_publication_workflow('Drawing',
        'publish_alive_action')

  def test_document_publication_workflow_Drawing_release(self):
    self._test_document_publication_workflow('Drawing', 'release_action')
2637 2638

  def test_document_publication_workflow_Drawing_release_alive(self):
2639 2640 2641 2642 2643
    self._test_document_publication_workflow('Drawing',
        'release_alive_action')

  def test_document_publication_workflow_Drawing_share(self):
    self._test_document_publication_workflow('Drawing', 'share_action')
2644 2645

  def test_document_publication_workflow_Drawing_share_alive(self):
2646 2647 2648 2649 2650
    self._test_document_publication_workflow('Drawing',
        'share_alive_action')

  def test_document_publication_workflow_File_publish(self):
    self._test_document_publication_workflow('File', 'publish_action')
2651 2652

  def test_document_publication_workflow_File_publish_alive(self):
2653 2654 2655 2656 2657
    self._test_document_publication_workflow('File',
        'publish_alive_action')

  def test_document_publication_workflow_File_release(self):
    self._test_document_publication_workflow('File', 'release_action')
2658 2659

  def test_document_publication_workflow_File_release_alive(self):
2660 2661 2662 2663 2664
    self._test_document_publication_workflow('File',
        'release_alive_action')

  def test_document_publication_workflow_File_share(self):
    self._test_document_publication_workflow('File', 'share_action')
2665 2666

  def test_document_publication_workflow_File_share_alive(self):
2667 2668 2669 2670 2671
    self._test_document_publication_workflow('File',
        'share_alive_action')

  def test_document_publication_workflow_PDF_publish(self):
    self._test_document_publication_workflow('PDF', 'publish_action')
2672 2673

  def test_document_publication_workflow_PDF_publish_alive(self):
2674 2675 2676 2677 2678
    self._test_document_publication_workflow('PDF',
        'publish_alive_action')

  def test_document_publication_workflow_PDF_release(self):
    self._test_document_publication_workflow('PDF', 'release_action')
2679 2680

  def test_document_publication_workflow_PDF_release_alive(self):
2681 2682 2683 2684 2685
    self._test_document_publication_workflow('PDF',
        'release_alive_action')

  def test_document_publication_workflow_PDF_share(self):
    self._test_document_publication_workflow('PDF', 'share_action')
2686 2687

  def test_document_publication_workflow_PDF_share_alive(self):
2688 2689 2690 2691 2692
    self._test_document_publication_workflow('PDF',
        'share_alive_action')

  def test_document_publication_workflow_Presentation_publish(self):
    self._test_document_publication_workflow('Presentation', 'publish_action')
2693 2694

  def test_document_publication_workflow_Presentation_publish_alive(self):
2695 2696 2697 2698 2699
    self._test_document_publication_workflow('Presentation',
        'publish_alive_action')

  def test_document_publication_workflow_Presentation_release(self):
    self._test_document_publication_workflow('Presentation', 'release_action')
2700 2701

  def test_document_publication_workflow_Presentation_release_alive(self):
2702 2703 2704 2705 2706
    self._test_document_publication_workflow('Presentation',
        'release_alive_action')

  def test_document_publication_workflow_Presentation_share(self):
    self._test_document_publication_workflow('Presentation', 'share_action')
2707 2708

  def test_document_publication_workflow_Presentation_share_alive(self):
2709 2710 2711 2712 2713
    self._test_document_publication_workflow('Presentation',
        'share_alive_action')

  def test_document_publication_workflow_Spreadsheet_publish(self):
    self._test_document_publication_workflow('Spreadsheet', 'publish_action')
2714 2715

  def test_document_publication_workflow_Spreadsheet_publish_alive(self):
2716 2717 2718 2719 2720
    self._test_document_publication_workflow('Spreadsheet',
        'publish_alive_action')

  def test_document_publication_workflow_Spreadsheet_release(self):
    self._test_document_publication_workflow('Spreadsheet', 'release_action')
2721 2722

  def test_document_publication_workflow_Spreadsheet_release_alive(self):
2723 2724 2725 2726 2727
    self._test_document_publication_workflow('Spreadsheet',
        'release_alive_action')

  def test_document_publication_workflow_Spreadsheet_share(self):
    self._test_document_publication_workflow('Spreadsheet', 'share_action')
2728 2729

  def test_document_publication_workflow_Spreadsheet_share_alive(self):
2730 2731 2732 2733 2734
    self._test_document_publication_workflow('Spreadsheet',
        'share_alive_action')

  def test_document_publication_workflow_Text_publish(self):
    self._test_document_publication_workflow('Text', 'publish_action')
2735 2736

  def test_document_publication_workflow_Text_publish_alive(self):
2737 2738 2739 2740 2741
    self._test_document_publication_workflow('Text',
        'publish_alive_action')

  def test_document_publication_workflow_Text_release(self):
    self._test_document_publication_workflow('Text', 'release_action')
2742 2743

  def test_document_publication_workflow_Text_release_alive(self):
2744 2745 2746 2747 2748
    self._test_document_publication_workflow('Text',
        'release_alive_action')

  def test_document_publication_workflow_Text_share(self):
    self._test_document_publication_workflow('Text', 'share_action')
2749 2750

  def test_document_publication_workflow_Text_share_alive(self):
2751 2752 2753
    self._test_document_publication_workflow('Text',
        'share_alive_action')

2754
  def test_document_publication_workflow_archiveVersion(self):
2755
    """ Test "visible" instances of a doc are auto archived when a new
2756 2757
    instance is made "visible" except when they have a future effective date.
    """
2758
    portal = self.portal
2759

2760 2761 2762 2763
    upload_file = makeFileUpload('TEST-en-002.doc')
    kw = dict(file=upload_file, synchronous_metadata_discovery=True)
    document_002 = self.portal.Base_contribute(**kw)
    document_002.publish()
2764
    self.tic()
2765

2766
    document_003 = document_002.Base_createCloneDocument(batch_mode=1)
2767
    document_003.setEffectiveDate(DateTime() - 1)
2768
    document_003.publish()
2769 2770 2771
    document_future_003 = document_002.Base_createCloneDocument(batch_mode=1)
    document_future_003.setEffectiveDate(DateTime() + 10)
    document_future_003.publish()
2772
    self.tic()
2773 2774
    self.assertEqual('published', document_003.getValidationState())
    self.assertEqual('archived', document_002.getValidationState())
2775
    self.assertEqual('published', document_future_003.getValidationState())
2776

2777
    # check if in any case document doesn't archive itself
2778
    # (i.e. shared_alive -> published or any other similar chain)
2779
    document_004 = document_002.Base_createCloneDocument(batch_mode=1)
2780
    document_004.shareAlive()
2781
    self.tic()
2782 2783

    document_004.publish()
2784
    self.tic()
2785
    self.assertEqual('published', document_004.getValidationState())
2786 2787 2788 2789 2790 2791 2792 2793 2794 2795 2796
    # document_future_003 must not have been archived, as its effective date is
    # in the future.
    self.assertEqual('published', document_future_003.getValidationState())

    document_005 = document_004.Base_createCloneDocument(batch_mode=1)
    document_005.setEffectiveDate(DateTime() + 5)
    document_005.publish()
    self.tic()
    # Also, document_004 must not have been archived, as document_005's
    # effective_date is in the future.
    self.assertEqual('published', document_004.getValidationState())
2797 2798 2799 2800 2801

    # check case when no language is used
    document_nolang_005 = document_004.Base_createCloneDocument(batch_mode=1)
    document_nolang_005.setLanguage(None)
    document_nolang_005.publish()
2802
    self.tic()
2803 2804 2805 2806
    self.assertEqual('published', document_nolang_005.getValidationState())

    document_nolang_006 = document_nolang_005.Base_createCloneDocument(batch_mode=1)
    document_nolang_006.shareAlive()
2807
    self.tic()
2808

2809 2810 2811
    self.assertEqual('archived', document_nolang_005.getValidationState())
    self.assertEqual('shared_alive', document_nolang_006.getValidationState())

2812 2813 2814 2815 2816 2817 2818 2819
  def testFileWithNotDefinedMimeType(self):
    upload_file = makeFileUpload('TEST-001-en.dummy')
    kw = dict(file=upload_file, synchronous_metadata_discovery=True,
              portal_type='File')
    document = self.portal.Base_contribute(**kw)
    document.setReference('TEST')
    request = self.app.REQUEST
    download_file = document.index_html(REQUEST=request, format=None)
2820
    self.assertEqual(download_file, 'foo\n')
2821
    document_format = None
2822
    self.assertEqual('TEST-001-en.dummy', document.getStandardFilename(
2823 2824
                      document_format))

2825
class TestDocumentWithSecurity(TestDocumentMixin):
2826 2827 2828 2829 2830 2831 2832 2833 2834 2835 2836 2837

  username = 'yusei'

  def getTitle(self):
    return "DMS with security"

  def login(self):
    uf = self.getPortal().acl_users
    uf._doAddUser(self.username, '', ['Auditor', 'Author'], [])
    user = uf.getUserById(self.username).__of__(uf)
    newSecurityManager(None, user)

2838
  def test_ShowPreviewAfterSubmitted(self):
2839 2840 2841 2842 2843 2844
    """
    Make sure that uploader can preview document after submitted.
    """
    filename = 'REF-en-001.odt'
    upload_file = makeFileUpload(filename)
    document = self.portal.portal_contributions.newContent(file=upload_file)
2845
    self.tic()
2846 2847 2848 2849 2850

    document.submit()

    preview_html = document.Document_getPreviewAsHTML().replace('\n', ' ')

2851
    self.tic()
2852 2853 2854

    self.assert_('I use reference to look up TEST' in preview_html)

2855 2856 2857 2858
  def test_DownloadableDocumentSize(self):
    '''Check that once the document is converted and cached, its size is
    correctly set'''
    portal = self.getPortalObject()
2859 2860
    portal_type = 'Text'
    document_module = portal.getDefaultModule(portal_type)
2861 2862

    # create a text document in document module
2863
    text_document = document_module.newContent(portal_type=portal_type,
2864 2865 2866 2867 2868
                                               reference='Foo_001',
                                               title='Foo_OO1')
    f = makeFileUpload('Foo_001.odt')
    text_document.edit(file=f.read())
    f.close()
2869
    self.tic()
2870 2871

    # the document should be automatically converted to html
2872
    self.assertEqual(text_document.getExternalProcessingState(), 'converted')
2873 2874 2875 2876 2877

    # check there is nothing in the cache for pdf conversion
    self.assertFalse(text_document.hasConversion(format='pdf'))

    # call pdf conversion, in this way, the result should be cached
2878 2879
    mime_type, pdf_data = text_document.convert(format='pdf')
    pdf_size = len(pdf_data)
2880 2881 2882 2883 2884 2885


    # check there is a cache entry for pdf conversion of this document
    self.assertTrue(text_document.hasConversion(format='pdf'))

    # check the size of the pdf conversion
2886
    self.assertEqual(text_document.getConversionSize(format='pdf'), pdf_size)
2887

2888 2889 2890 2891 2892 2893
  def test_ImageSizePreference(self):
    """
    Tests that when user defines image sizes are already defined in preferences
    those properties are taken into account when the user
    views an image
    """
2894
    super(TestDocumentWithSecurity, self).login('yusei')
2895 2896 2897 2898 2899 2900 2901
    preference_tool = self.portal.portal_preferences
    #get the thumbnail sizes defined by default on default site preference
    default_thumbnail_image_height = \
       preference_tool.default_site_preference.getPreferredThumbnailImageHeight()
    default_thumbnail_image_width = \
       preference_tool.default_site_preference.getPreferredThumbnailImageWidth()
    self.assertTrue(default_thumbnail_image_height > 0)
2902
    self.assertTrue(default_thumbnail_image_width > 0)
2903 2904 2905 2906
    self.assertEqual(default_thumbnail_image_height,
                     preference_tool.getPreferredThumbnailImageHeight())
    self.assertEqual(default_thumbnail_image_width,
                     preference_tool.getPreferredThumbnailImageWidth())
2907
    #create new user preference and set new sizes for image thumbnail display
2908 2909 2910 2911 2912
    user_pref = preference_tool.newContent(
                          portal_type='Preference',
                          priority=Priority.USER)
    self.portal.portal_workflow.doActionFor(user_pref, 'enable_action')
    self.assertEqual(user_pref.getPreferenceState(), 'enabled')
2913
    self.tic()
2914 2915 2916 2917 2918 2919 2920 2921 2922 2923 2924
    user_pref.setPreferredThumbnailImageHeight(default_thumbnail_image_height + 10)
    user_pref.setPreferredThumbnailImageWidth(default_thumbnail_image_width + 10)
    #Verify that the new values defined are the ones used by default
    self.assertEqual(default_thumbnail_image_height + 10,
                     preference_tool.getPreferredThumbnailImageHeight())
    self.assertEqual(default_thumbnail_image_height + 10,
                     preference_tool.getPreferredThumbnailImageHeight(0))
    self.assertEqual(default_thumbnail_image_width + 10,
                     preference_tool.getPreferredThumbnailImageWidth())
    self.assertEqual(default_thumbnail_image_width + 10,
                     preference_tool.getPreferredThumbnailImageWidth(0))
2925
    #Now lets check that when we try to view an image as thumbnail,
2926 2927
    #the sizes of that image are the ones defined in user preference
    image_portal_type = 'Image'
2928 2929
    image_module = self.portal.getDefaultModule(image_portal_type)
    image = image_module.newContent(portal_type=image_portal_type)
2930
    self.assertEqual('thumbnail',
2931
       image.Image_view._getOb('my_thumbnail', None).get_value('image_display'))
2932 2933 2934
    self.assertEqual((user_pref.getPreferredThumbnailImageWidth(),
                    user_pref.getPreferredThumbnailImageHeight()),
                     image.getSizeFromImageDisplay('thumbnail'))
2935 2936 2937 2938 2939 2940 2941 2942 2943 2944

class TestDocumentPerformance(TestDocumentMixin):

  def test_01_LargeOOoDocumentToImageConversion(self):
    """
      Test large OOoDocument to image conversion
    """
    ooo_document = self.portal.document_module.newContent(portal_type='Spreadsheet')
    upload_file = makeFileUpload('import_big_spreadsheet.ods')
    ooo_document.edit(file=upload_file)
2945
    self.tic()
2946 2947 2948
    before = time.time()
    # converting any OOoDocument -> PDF -> Image
    # make sure that this can happen in less tan XXX seconds i.e. code doing convert
2949
    # uses only first PDF frame (not entire PDF) to make an image - i.e.optimized enough to not kill
2950 2951 2952 2953
    # entire system performance by doing extensive calculations over entire PDF (see r37102-37103)
    ooo_document.convert(format='png')
    after = time.time()
    req_time = (after - before)
2954 2955 2956
    # we should have image converted in less than Xs
    # the 100s value is estimated one, it's equal to time for cloudood conversion (around 52s) +
    # time for gs conversion. As normally test are executed in parallel some tollerance is needed.
2957
    self.assertTrue(req_time < 100.0,
2958
      "Conversion took %s seconds and it is not less them 100.0 seconds" % \
2959
        req_time)
Ivan Tyagov's avatar
Ivan Tyagov committed
2960

2961 2962 2963
def test_suite():
  suite = unittest.TestSuite()
  suite.addTest(unittest.makeSuite(TestDocument))
Ivan Tyagov's avatar
Ivan Tyagov committed
2964 2965
  suite.addTest(unittest.makeSuite(TestDocumentWithSecurity))
  suite.addTest(unittest.makeSuite(TestDocumentPerformance))
2966
  return suite
Bartek Górny's avatar
Bartek Górny committed
2967 2968


Fabien Morin's avatar
Fabien Morin committed
2969
# vim: syntax=python shiftwidth=2