Traversal Behavior
==================

BaseObject overrides ``__bobo_traverse__`` to expose subobjects
created by ``PortalTransforms`` during the transformation of
content. However, overriding traversal can be tricky, and very hard to
get right.

These tests pretend to make sure that this functionality behaves
correctly across the many use cases that must co-exist.

First, we are going to setup an environment so we can test that stuff
is acquired or not acquired at the right times.

  >>> from Products.ATContentTypes.tests.atcttestcase import default_user
  >>> from Products.ATContentTypes.tests.atcttestcase import default_password
  >>> from Products.ATContentTypes.tests.atcttestcase import portal_name
  >>> from Products.CMFCore.utils import getToolByName
  >>> self.setRoles(['Manager'])

  >>> self.portal.setTitle('Portal Title')
  
  >>> self.portal.invokeFactory('Document', 'test_document',
  ...             title='Root Document')
  'test_document'

  >>> self.portal.invokeFactory('Document', 'index_html', title='Root Index')
  'index_html'

  >>> self.portal.invokeFactory('Folder', 'simple_folder')
  'simple_folder'

  >>> self.portal.invokeFactory('Large Plone Folder', 'simple_btree_folder')
  'simple_btree_folder'


XML-RPC
-------

XML-RPC is basically a ``POST`` with content-type text/xml. It should
be allowed to acquire content from higher-level hierarchies:

  >>> print http(r"""
  ... POST /%s HTTP/1.0
  ... Authorization: Basic %s:%s
  ... Content-Type: text/xml
  ...
  ... <?xml version='1.0'?>
  ... <methodCall>
  ... <methodName>title_or_id</methodName>
  ... <params>
  ... </params>
  ...
  ... </methodCall>
  ... """ % (portal_name, default_user, default_password))
  HTTP/1.0 200 OK
  ...Portal Title...

  >>> print self.portal.test_document.getPortalTypeName()
  Document

  >>> print self.portal.test_document.title_or_id()
  Root Document

  >>> print http(r"""
  ... POST /%s HTTP/1.0
  ... Authorization: Basic %s:%s
  ... Content-Type: text/xml
  ...
  ... <?xml version='1.0'?>
  ... <methodCall>
  ... <methodName>test_document.title_or_id</methodName>
  ... <params>
  ... </params>
  ...
  ... </methodCall>
  ... """ % (portal_name, default_user, default_password))
  HTTP/1.0 200 OK
  ...Root Document...

  >>> 'test_document' in self.portal.simple_folder
  False

  >>> print http(r"""
  ... POST /%s HTTP/1.0
  ... Authorization: Basic %s:%s
  ... Content-Type: text/xml
  ...
  ... <?xml version='1.0'?>
  ... <methodCall>
  ... <methodName>simple_folder.test_document.title_or_id</methodName>
  ... <params>
  ... </params>
  ...
  ... </methodCall>
  ... """ % (portal_name, default_user, default_password))
  HTTP/1.0 200 OK
  ...Root Document...

  >>> 'test_document' in self.portal.simple_btree_folder
  False

  >>> print http(r"""
  ... POST /%s HTTP/1.0
  ... Authorization: Basic %s:%s
  ... Content-Type: text/xml
  ...
  ... <?xml version='1.0'?>
  ... <methodCall>
  ... <methodName>simple_btree_folder.test_document.title_or_id</methodName>
  ... <params>
  ... </params>
  ...
  ... </methodCall>
  ... """ % (portal_name, default_user, default_password))
  HTTP/1.0 200 OK
  ...Root Document...

Browser
-------

For testing Browser access, we are going to just try using the ``GET``
method instead.

  >>> print self.portal.title_or_id()
  Portal Title

  >>> print http(r"""
  ... GET /%s/title_or_id HTTP/1.0
  ... Authorization: Basic %s:%s
  ... """ % (portal_name, default_user, default_password))
  HTTP/1.0 200 OK
  ...Portal Title...

  >>> print self.portal.test_document.getPortalTypeName()
  Document

  >>> print self.portal.test_document.title_or_id()
  Root Document

  >>> print http(r"""
  ... GET /%s/test_document/title_or_id HTTP/1.0
  ... Authorization: Basic %s:%s
  ... """ % (portal_name, default_user, default_password))
  HTTP/1.0 200 OK
  ...Root Document...

  >>> 'test_document' in self.portal.simple_folder
  False

  >>> print http(r"""
  ... GET /%s/simple_folder/test_document/title_or_id HTTP/1.0
  ... Authorization: Basic %s:%s
  ... """ % (portal_name, default_user, default_password))
  HTTP/1.0 200 OK
  ...Root Document...

  >>> 'test_document' in self.portal.simple_btree_folder
  False

  >>> print http(r"""
  ... GET /%s/simple_btree_folder/test_document/title_or_id HTTP/1.0
  ... Authorization: Basic %s:%s
  ... """ % (portal_name, default_user, default_password))
  HTTP/1.0 200 OK
  ...Root Document...

Lets make sure view lookup takes precedence over acquired views.

We need to do some site magic, or our we end up with the SimpleView class
being persisted in the local component registry. We really shouldn't do
ZCML registrations in function tests.

  >>> from zope.site.hooks import getSite, setSite
  >>> site = getSite()

  >>> setSite(None)
  >>> try:
  ...     from Zope2.App import zcml
  ... except ImportError:
  ...     from Products.Five import zcml

  >>> zcml.load_string('''<configure xmlns="http://namespaces.zope.org/browser">
  ... <page
  ...     name="document_view"
  ...     for="*"
  ...     permission="zope.Public"
  ...     class="Products.Archetypes.tests.utils.SimpleView"
  ...     />
  ... </configure>''')
  >>> setSite(site)

  >>> print http(r"""
  ... GET /%s/simple_btree_folder/test_document/document_view HTTP/1.0
  ... Authorization: Basic %s:%s
  ... """ % (portal_name, default_user, default_password))
  HTTP/1.0 200 OK
  ...SimpleView simple output...

WebDAV
------

Now for the tricky part. WebDAV requests are *not* allowed to acquire
content, because that would completely break creation of content
through WebDAV.

  >>> print http(r"""
  ... PROPFIND /%s/test_document HTTP/1.1
  ... Authorization: Basic %s:%s
  ... Content-Type: text/xml; charset="utf-8"
  ... Depth: 0
  ...
  ... <?xml version="1.0" encoding="utf-8"?>
  ...   <DAV:propfind xmlns:DAV="DAV:"
  ...      xmlns:zope="http://www.zope.org/propsets/default">
  ...      <DAV:prop><zope:title/></DAV:prop>
  ...   </DAV:propfind>
  ... """ % (portal_name, default_user, default_password))
  HTTP/1.1 207 Multi-Status
  ...Root Document...

  >>> print http(r"""
  ... PROPFIND /%s/simple_folder/test_document HTTP/1.1
  ... Authorization: Basic %s:%s
  ... Content-Type: text/xml; charset="utf-8"
  ... Depth: 0
  ...
  ... <?xml version="1.0" encoding="utf-8"?>
  ...   <DAV:propfind xmlns:DAV="DAV:"
  ...      xmlns:zope="http://www.zope.org/propsets/default">
  ...      <DAV:prop><zope:title/></DAV:prop>
  ...   </DAV:propfind>
  ... """ % (portal_name, default_user, default_password))
  HTTP/1.1 404 Not Found
  ...

  >>> print http(r"""
  ... PROPFIND /%s/simple_btree_folder/test_document HTTP/1.1
  ... Authorization: Basic %s:%s
  ... Content-Type: text/xml; charset="utf-8"
  ... Depth: 0
  ...
  ... <?xml version="1.0" encoding="utf-8"?>
  ...   <DAV:propfind xmlns:DAV="DAV:"
  ...      xmlns:zope="http://www.zope.org/propsets/default">
  ...      <DAV:prop><zope:title/></DAV:prop>
  ...   </DAV:propfind>
  ... """ % (portal_name, default_user, default_password))
  HTTP/1.1 404 Not Found
  ...

Should be possible to create objects via PUT that would otherwise be
acquired.

Create a CTR predicate to map any content to ``Document``:

  >>> ctr = getToolByName(self.portal, 'content_type_registry')
  >>> p_id = 'at_dav_test'
  >>> p_type = 'name_regex'
  >>> ctr.addPredicate(p_id, p_type)
  >>> class foo: pass
  >>> p_dict = foo()
  >>> p_dict.pattern = '.*'
  >>> ctr.updatePredicate(p_id, p_dict, 'Document')
  >>> ctr.reorderPredicate(p_id, 0)

  >>> print http(r"""
  ... PUT /%s/simple_folder/test_document HTTP/1.1
  ... Authorization: Basic %s:%s
  ... Content-Type: text/plain; charset="utf-8"
  ... Depth: 0
  ...
  ... Simple Folder Document Content
  ... """ % (portal_name, default_user, default_password))
  HTTP/1.1 201 Created
  ...

  >>> folder = self.portal.simple_folder
  >>> print folder.test_document.getPortalTypeName()
  Document

  >>> print folder.test_document.title_or_id()
  test_document

  >>> print folder.test_document.getText()
  <p>Simple Folder Document Content</p>
  <BLANKLINE>

  >>> print http(r"""
  ... PUT /%s/simple_btree_folder/test_document HTTP/1.1
  ... Authorization: Basic %s:%s
  ... Content-Type: text/plain; charset="utf-8"
  ... Depth: 0
  ...
  ... BTree Folder Document Content
  ... """ % (portal_name, default_user, default_password))
  HTTP/1.1 201 Created
  ...

  >>> folder = self.portal.simple_btree_folder
  >>> print folder.test_document.getPortalTypeName()
  Document

  >>> print folder.test_document.title_or_id()
  test_document

  >>> print folder.test_document.getText()
  <p>BTree Folder Document Content</p>

Make sure it's possible to create an item named ``index_html`` into a
AT-based folder.

  >>> folder = self.portal.simple_folder
  >>> 'index_html' in folder
  False

  >>> print folder.index_html
  <ATDocument at index_html>

  >>> print http(r"""
  ... PUT /%s/simple_folder/index_html HTTP/1.1
  ... Authorization: Basic %s:%s
  ... Content-Type: text/plain; charset="utf-8"
  ... Depth: 0
  ...
  ... Simple Folder Index
  ... """ % (portal_name, default_user, default_password))
  HTTP/1.1 201 Created
  ...

  >>> print folder.index_html.title_or_id()
  index_html

  >>> print folder.index_html.getText()
  <p>Simple Folder Index</p>


Finally, cleanup the CTR predicate to not affect other tests:

  >>> ctr.removePredicate(p_id)

Creating folders should work the same way. And the newly created folder
should be of the same kind as the parent:

  >>> print http(r"""
  ... MKCOL /%s/simple_folder/simple_folder HTTP/1.1
  ... Authorization: Basic %s:%s
  ... """ % (portal_name, default_user, default_password))
  HTTP/1.1 201 Created
  ...

  >>> folder = self.portal.simple_folder.simple_folder
  >>> print folder.getPortalTypeName()
  Folder
