testOOoStyle.py 21.3 KB
Newer Older
1
# -*- coding: utf-8 -*-
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 30
# Copyright (c) 2007 Nexedi SA and Contributors. All Rights Reserved.
#          Jerome Perrin <jerome@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.
#
##############################################################################

import unittest
31
from Products.ERP5Type.tests.ERP5TypeTestCase import ERP5TypeTestCase
32
from Products.ERP5Type.tests.utils import DummyLocalizer
33
from Products.ERP5Form.Selection import Selection
34 35
from Testing import ZopeTestCase
from Products.ERP5OOo.tests.utils import Validator
36
import httplib
37

38
HTTP_OK = httplib.OK
39

40 41
# setting this to True allows the .publish() calls to provide tracebacks
debug = False
42 43 44 45 46 47 48

class TestOOoStyle(ERP5TypeTestCase, ZopeTestCase.Functional):
  """Tests ODF styles for ERP5."""
  skin = None
  content_type = None

  def getBusinessTemplateList(self):
49 50
    return ('erp5_core_proxy_field_legacy', 'erp5_ui_test', 'erp5_base',
            'erp5_ods_style', 'erp5_odt_style',)
51 52 53 54

  def afterSetUp(self):
    if not self.skin:
      raise NotImplementedError('Subclasses must define skin')
55

56 57 58 59 60
    gender = self.portal.portal_categories.gender
    if 'male' not in gender.objectIds():
      gender.newContent(id='male')
      self.portal.portal_caches.clearAllCache()

61 62
    self.auth = 'ERP5TypeTestCase:'
    person_module = self.portal.person_module
63
    if person_module._getOb('pers', None) is None:
64
      person_module.newContent(id='pers', portal_type='Person')
65
      self.tic()
66
    person_module.pers.setFirstName('Bob')
67 68 69
    person_module.pers.setGender(None)
    person_module.pers.setCareerRole(None)

70
    if person_module.pers._getOb('img', None) is None:
71
      person_module.pers.newContent(portal_type='Embedded File', id='img')
72 73 74 75 76 77

    if person_module._getOb('pers_without_image', None) is None:
      person = person_module.newContent(
                              portal_type='Person',
                              id = 'pers_without_image',
                              first_name = 'Test')
78
      self.tic()
79

80 81
    self.portal.changeSkin(self.skin)
    self.validator = Validator()
82
    # make sure selections are empty
83 84
    name = 'person_module_selection'
    self.portal.portal_selections.setSelectionFor(name, Selection(name))
85

86 87
  def publish(self, *args, **kw):
    kw['handle_errors'] = not debug
88
    return super(TestOOoStyle, self).publish(*args, **kw)
89 90 91 92 93

  def _validate(self, odf_file_data):
    error_list = self.validator.validate(odf_file_data)
    if error_list:
      self.fail(''.join(error_list))
94

95
  def _assertFieldInGroup(self, field_type, form_id, group):
96
    for f in getattr(self.portal, form_id).get_fields_in_group(group):
97 98 99 100 101 102 103
      if f.meta_type == 'ProxyField':
        if f.getRecursiveTemplateField().meta_type == field_type:
          break
      if f.meta_type == field_type:
        break
    else:
      self.fail('No %s found in %s (%s group)' % (field_type, form_id, group))
104 105 106 107 108

  def test_skin_selection(self):
    self.assertTrue(self.skin in
              self.portal.portal_skins.getSkinSelections())

109 110 111 112
  def test_form_list(self):
    response = self.publish(
                   '/%s/person_module/PersonModule_viewPersonList'
                    % self.portal.getId(), self.auth)
113
    self.assertEqual(HTTP_OK, response.getStatus())
114 115 116
    content_type = response.getHeader('content-type')
    self.assertTrue(content_type.startswith(self.content_type), content_type)
    content_disposition = response.getHeader('content-disposition')
117
    self.assertEqual('attachment', content_disposition.split(';')[0])
118 119
    self._validate(response.getBody())

120
  def test_form_list_domain_tree(self):
121 122 123
    self.portal.portal_selections.setListboxDisplayMode(
                  self.portal.REQUEST, 'DomainTreeMode',
                  'person_module_selection')
124 125 126 127 128 129
    # XXX no proper API on selection / selection tool for this ?
    self.portal.portal_selections.setSelectionParamsFor(
                  selection_name='person_module_selection',
                  params=dict(domain_path='portal_categories',
                              domain_url='group',
                              domain_list=()))
130 131 132
    response = self.publish(
                   '/%s/person_module/PersonModule_viewPersonList'
                    % self.portal.getId(), self.auth)
133
    self.assertEqual(HTTP_OK, response.getStatus())
134 135 136
    content_type = response.getHeader('content-type')
    self.assertTrue(content_type.startswith(self.content_type), content_type)
    content_disposition = response.getHeader('content-disposition')
137
    self.assertEqual('attachment', content_disposition.split(';')[0])
138 139 140
    self._validate(response.getBody())

  def test_form_view(self):
141 142 143 144 145
    # form_view on a form without listbox
    self.portal.person_module.pers.setDefaultAddressZipCode(59000)
    response = self.publish(
        '/%s/person_module/pers/default_address/GeographicAddress_view'
        % self.portal.getId(), self.auth)
146
    self.assertEqual(HTTP_OK, response.getStatus())
147 148 149
    content_type = response.getHeader('content-type')
    self.assertTrue(content_type.startswith(self.content_type), content_type)
    content_disposition = response.getHeader('content-disposition')
150
    self.assertEqual('attachment', content_disposition.split(';')[0])
151 152 153 154 155 156 157 158 159
    self._validate(response.getBody())

  def test_form_view_empty_listbox(self):
    # form_view on a form with an empty listbox
    if hasattr(self.portal.person_module.pers, 'default_address'):
      self.portal.person_module.pers._delObject('default_address')
    response = self.publish(
                   '/%s/person_module/pers/Person_view'
                   % self.portal.getId(), self.auth)
160
    self.assertEqual(HTTP_OK, response.getStatus())
161 162 163
    content_type = response.getHeader('content-type')
    self.assertTrue(content_type.startswith(self.content_type), content_type)
    content_disposition = response.getHeader('content-disposition')
164
    self.assertEqual('attachment', content_disposition.split(';')[0])
165 166 167 168
    self._validate(response.getBody())

  def test_form_view_non_empty_listbox(self):
    self.portal.person_module.pers.setDefaultAddressZipCode(59000)
169 170 171
    response = self.publish(
                   '/%s/person_module/pers/Person_view'
                   % self.portal.getId(), self.auth)
172
    self.assertEqual(HTTP_OK, response.getStatus())
173 174 175
    content_type = response.getHeader('content-type')
    self.assertTrue(content_type.startswith(self.content_type), content_type)
    content_disposition = response.getHeader('content-disposition')
176
    self.assertEqual('attachment', content_disposition.split(';')[0])
177 178
    self._validate(response.getBody())

179
  def test_form_view_empty_format(self):
180
    # empty format= does not use oood for conversion
181 182 183
    response = self.publish(
                   '/%s/person_module/pers/Person_view?format='
                   % self.portal.getId(), self.auth)
184
    self.assertEqual(HTTP_OK, response.getStatus())
185 186 187
    content_type = response.getHeader('content-type')
    self.assertTrue(content_type.startswith(self.content_type), content_type)
    content_disposition = response.getHeader('content-disposition')
188
    self.assertEqual('attachment', content_disposition.split(';')[0])
189
    self._validate(response.getBody())
190 191

  def test_form_view_pdf_format(self):
192 193 194 195
    # format=pdf uses oood for conversion
    response = self.publish(
                   '/%s/person_module/pers/Person_view?format=pdf'
                   % self.portal.getId(), self.auth)
196
    self.assertEqual(HTTP_OK, response.getStatus())
197
    content_type = response.getHeader('content-type')
198
    self.assertEqual(content_type, 'application/pdf')
199
    content_disposition = response.getHeader('content-disposition')
200
    self.assertEqual('attachment', content_disposition.split(';')[0])
201

202 203 204 205 206 207 208 209 210 211 212
  def test_form_view_html_format(self):
    # format=html is rendered inline
    response = self.publish(
                   '/%s/person_module/pers/Person_view?format=html'
                   % self.portal.getId(), self.auth)
    self.assertEqual(HTTP_OK, response.getStatus())
    content_type = response.getHeader('content-type')
    self.assertEqual(content_type, 'text/html; charset=utf-8')
    content_disposition = response.getHeader('content-disposition')
    self.assertEqual('inline', content_disposition.split(';')[0])

213 214
  def test_report_view_form_view(self):
    # Test report view rendering forms using form_view
215
    self.assertEqual('form_view', self.portal.Base_viewWorkflowHistory.pt)
216 217 218
    response = self.publish(
                   '/%s/person_module/pers/Base_viewHistory'
                    % self.portal.getId(), self.auth)
219
    self.assertEqual(HTTP_OK, response.getStatus())
220 221 222
    content_type = response.getHeader('content-type')
    self.assertTrue(content_type.startswith(self.content_type), content_type)
    content_disposition = response.getHeader('content-disposition')
223
    self.assertEqual('attachment', content_disposition.split(';')[0])
224 225
    self._validate(response.getBody())

226 227 228 229 230 231 232 233 234 235 236
  def test_report_view_form_list(self):
    # Test report view rendering forms using form_list
    self.portal.Base_viewWorkflowHistory.pt = 'form_list'
    try:
      # publish commits a transaction, so we have to restore the original page
      # template on the form
      response = self.publish(
                   '/%s/person_module/pers/Base_viewHistory'
                    % self.portal.getId(), self.auth)
    finally:
      self.portal.Base_viewWorkflowHistory.pt = 'form_view'
237
      self.commit()
238
    self.assertEqual(HTTP_OK, response.getStatus())
239 240 241
    content_type = response.getHeader('content-type')
    self.assertTrue(content_type.startswith(self.content_type), content_type)
    content_disposition = response.getHeader('content-disposition')
242
    self.assertEqual('attachment', content_disposition.split(';')[0])
243 244 245
    self._validate(response.getBody())


246 247 248 249
  def test_report_view_landscape(self):
    response = self.publish(
       '/%s/person_module/pers/Base_viewHistory?landscape=1'
        % self.portal.getId(), self.auth)
250
    self.assertEqual(HTTP_OK, response.getStatus())
251 252 253
    content_type = response.getHeader('content-type')
    self.assertTrue(content_type.startswith(self.content_type), content_type)
    content_disposition = response.getHeader('content-disposition')
254
    self.assertEqual('attachment', content_disposition.split(';')[0])
255 256 257 258 259 260
    self._validate(response.getBody())

  def test_report_view_sheet_per_report_section(self):
    response = self.publish(
       '/%s/person_module/pers/Base_viewHistory?sheet_per_report_section=1'
        % self.portal.getId(), self.auth)
261
    self.assertEqual(HTTP_OK, response.getStatus())
262 263 264
    content_type = response.getHeader('content-type')
    self.assertTrue(content_type.startswith(self.content_type), content_type)
    content_disposition = response.getHeader('content-disposition')
265
    self.assertEqual('attachment', content_disposition.split(';')[0])
266 267
    self._validate(response.getBody())

268 269 270 271
  def test_form_view_encoding(self):
    self.portal.person_module.pers.setFirstName('Jérome')
    response = self.publish('/%s/person_module/pers/Person_view'
                          % self.portal.getId(), basic=self.auth)
272
    self.assertEqual(HTTP_OK, response.getStatus())
273 274 275
    content_type = response.getHeader('content-type')
    self.assertTrue(content_type.startswith(self.content_type), content_type)
    content_disposition = response.getHeader('content-disposition')
276
    self.assertEqual('attachment', content_disposition.split(';')[0])
277 278 279 280 281 282
    self._validate(response.getBody())

  def test_form_view_category(self):
    self.portal.person_module.pers.setGender('male')
    response = self.publish('/%s/person_module/pers/Person_view'
                          % self.portal.getId(), basic=self.auth)
283
    self.assertEqual(HTTP_OK, response.getStatus())
284 285 286
    content_type = response.getHeader('content-type')
    self.assertTrue(content_type.startswith(self.content_type), content_type)
    content_disposition = response.getHeader('content-disposition')
287
    self.assertEqual('attachment', content_disposition.split(';')[0])
288 289 290 291 292 293 294
    self._validate(response.getBody())

  def test_form_view_broken_category(self):
    self.portal.person_module.pers.setGender('not exist')
    self.portal.person_module.pers.setCareerRole('not exist')
    response = self.publish('/%s/person_module/pers/Person_view'
                          % self.portal.getId(), basic=self.auth)
295
    self.assertEqual(HTTP_OK, response.getStatus())
296 297 298
    content_type = response.getHeader('content-type')
    self.assertTrue(content_type.startswith(self.content_type), content_type)
    content_disposition = response.getHeader('content-disposition')
299
    self.assertEqual('attachment', content_disposition.split(';')[0])
300 301 302 303 304 305
    self._validate(response.getBody())

  def test_form_view_embedded_image(self):
    # with image
    response = self.publish('/%s/person_module/pers/Person_viewDetails'
                          % self.portal.getId(), basic=self.auth)
306
    self.assertEqual(HTTP_OK, response.getStatus())
307 308 309
    content_type = response.getHeader('content-type')
    self.assertTrue(content_type.startswith(self.content_type), content_type)
    content_disposition = response.getHeader('content-disposition')
310
    self.assertEqual('attachment', content_disposition.split(';')[0])
311 312 313 314
    self._validate(response.getBody())
    # without image
    response = self.publish('/%s/person_module/pers_without_image/Person_viewDetails'
                          % self.portal.getId(), basic=self.auth)
315
    self.assertEqual(HTTP_OK, response.getStatus())
316 317 318
    content_type = response.getHeader('content-type')
    self.assertTrue(content_type.startswith(self.content_type), content_type)
    content_disposition = response.getHeader('content-disposition')
319
    self.assertEqual('attachment', content_disposition.split(';')[0])
320 321 322 323 324 325
    self._validate(response.getBody())

  def test_report_view_encoding(self):
    self.portal.person_module.pers.setFirstName('Jérome')
    response = self.publish('/%s/person_module/pers/Base_viewHistory'
                          % self.portal.getId(), basic=self.auth)
326
    self.assertEqual(HTTP_OK, response.getStatus())
327 328 329
    content_type = response.getHeader('content-type')
    self.assertTrue(content_type.startswith(self.content_type), content_type)
    content_disposition = response.getHeader('content-disposition')
330
    self.assertEqual('attachment', content_disposition.split(';')[0])
331 332 333 334 335 336 337
    self._validate(response.getBody())

  def test_form_list_encoding(self):
    self.portal.person_module.pers.setFirstName('Jérome')
    response = self.publish(
       '/%s/person_module/PersonModule_viewPersonList'
        % self.portal.getId(), basic=self.auth)
338
    self.assertEqual(HTTP_OK, response.getStatus())
339 340 341
    content_type = response.getHeader('content-type')
    self.assertTrue(content_type.startswith(self.content_type), content_type)
    content_disposition = response.getHeader('content-disposition')
342
    self.assertEqual('attachment', content_disposition.split(';')[0])
343 344
    self._validate(response.getBody())

345
  def test_image_field_form_view(self):
346
    self._assertFieldInGroup('ImageField', 'Image_view', 'right')
347 348 349
    response = self.publish(
       '/%s/person_module/pers/img/Image_view'
        % self.portal.getId(), basic=self.auth)
350
    self.assertEqual(HTTP_OK, response.getStatus())
351 352 353
    content_type = response.getHeader('content-type')
    self.assertTrue(content_type.startswith(self.content_type), content_type)
    content_disposition = response.getHeader('content-disposition')
354
    self.assertEqual('attachment', content_disposition.split(';')[0])
355 356 357
    self._validate(response.getBody())

  def test_image_field_form_view_bottom_group(self):
358 359
    self._assertFieldInGroup(
        'ImageField', 'Image_viewFullSizedImage', 'bottom')
360 361 362
    response = self.publish(
       '/%s/person_module/pers/img/Image_viewFullSizedImage'
        % self.portal.getId(), basic=self.auth)
363
    self.assertEqual(HTTP_OK, response.getStatus())
364 365 366
    content_type = response.getHeader('content-type')
    self.assertTrue(content_type.startswith(self.content_type), content_type)
    content_disposition = response.getHeader('content-disposition')
367
    self.assertEqual('attachment', content_disposition.split(';')[0])
368 369
    self._validate(response.getBody())

370 371 372 373 374 375 376 377
  def test_textarea_center_group(self):
    self._assertFieldInGroup('TextAreaField', 'Person_view', 'center')
    self.assert_('my_description' in [f.getId() for f in
        self.portal.Person_view.get_fields_in_group('center')])
    self.portal.person_module.pers.setDescription('<Escape>&\nnewline')
    response = self.publish(
                   '/%s/person_module/pers/Person_view'
                   % self.portal.getId(), self.auth)
378
    self.assertEqual(HTTP_OK, response.getStatus())
379 380 381
    content_type = response.getHeader('content-type')
    self.assertTrue(content_type.startswith(self.content_type), content_type)
    content_disposition = response.getHeader('content-disposition')
382
    self.assertEqual('attachment', content_disposition.split(';')[0])
383 384
    body = response.getBody()
    self._validate(body)
385

386 387 388 389 390 391 392
    if self.skin == 'ODT':
      # Is it good to do this only for ODT ?
      from Products.ERP5OOo.OOoUtils import OOoParser
      parser = OOoParser()
      parser.openFromString(body)
      content_xml = parser.oo_files['content.xml']
      self.assert_('&lt;Escape&gt;&amp;<text:line-break/>newline' in content_xml)
393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409

  def test_untranslatable_columns(self):
    self.portal.ListBoxZuite_reset()
    self.portal.Localizer = DummyLocalizer()
    message_catalog = self.portal.Localizer.erp5_ui
    # XXX odt style does not seem to display a listbox if it is empty ???
    self.portal.foo_module.newContent(portal_type='Foo')
    message = self.id()
    self.portal.FooModule_viewFooList.listbox.ListBox_setPropertyList(
      field_columns = ['do_not_translate | %s' % message,],
      field_untranslatablecolumns = ['do_not_translate | %s' % message,],
    )
    self.tic()
    self.portal.changeSkin(self.skin)
    response = self.publish(
                   '/%s/foo_module/FooModule_viewFooList?portal_skin='
                   % self.portal.getId(), self.auth)
410
    self.assertEqual(HTTP_OK, response.getStatus())
411 412 413
    content_type = response.getHeader('content-type')
    self.assertTrue(content_type.startswith(self.content_type), content_type)
    content_disposition = response.getHeader('content-disposition')
414
    self.assertEqual('attachment', content_disposition.split(';')[0])
415 416 417 418 419 420 421 422 423 424 425 426
    body = response.getBody()
    self._validate(body)

    from Products.ERP5OOo.OOoUtils import OOoParser
    parser = OOoParser()
    parser.openFromString(body)
    content_xml = parser.oo_files['content.xml']
    self.assertTrue(message in content_xml)

    # This untranslatable column have not been translated
    self.assertTrue(message not in message_catalog._translated)

427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456
  def test_form_view_ZMI(self):
    """We can edit form_view in the ZMI."""
    response = self.publish('/%s/form_view/manage_main'
       % self.portal.getId(), self.auth)
    self.assertEqual(HTTP_OK, response.getStatus())
    content_type = response.getHeader('content-type')
    self.assertEquals('text/html;charset=UTF-8', content_type)
    self.assertFalse(response.getHeader('content-disposition'))
    # Simplistic assertion that we are viewing the ODF XML source
    self.assertTrue('office:document-content' in response.getBody())

  def test_form_list_ZMI(self):
    """We can edit form_list in the ZMI."""
    response = self.publish('/%s/form_list/manage_main'
       % self.portal.getId(), self.auth)
    self.assertEqual(HTTP_OK, response.getStatus())
    content_type = response.getHeader('content-type')
    self.assertEquals('text/html;charset=UTF-8', content_type)
    self.assertFalse(response.getHeader('content-disposition'))
    self.assertTrue('office:document-content' in response.getBody())

  def test_report_view_ZMI(self):
    """We can edit report_view in the ZMI."""
    response = self.publish('/%s/report_view/manage_main'
       % self.portal.getId(), self.auth)
    self.assertEqual(HTTP_OK, response.getStatus())
    content_type = response.getHeader('content-type')
    self.assertEquals('text/html;charset=UTF-8', content_type)
    self.assertFalse(response.getHeader('content-disposition'))
    self.assertTrue('office:document-content' in response.getBody())
457 458 459 460 461 462 463 464 465 466 467 468 469 470

class TestODTStyle(TestOOoStyle):
  skin = 'ODT'
  content_type = 'application/vnd.oasis.opendocument.text'


class TestODSStyle(TestOOoStyle):
  skin = 'ODS'
  content_type = 'application/vnd.oasis.opendocument.spreadsheet'


def test_suite():
  suite = unittest.TestSuite()
  suite.addTest(unittest.makeSuite(TestODTStyle))
471
  suite.addTest(unittest.makeSuite(TestODSStyle))
472 473
  return suite