##############################################################################
#
# Copyright (c) 2004, 2005 Zope Corporation and Contributors.
# All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE.
#
##############################################################################
"""Test Five-traversable classes

$Id: test_traversable.py 23586 2006-02-22 04:37:33Z whit $
"""
import os, sys
if __name__ == '__main__':
    execfile(os.path.join(sys.path[0], 'framework.py'))


class SimpleClass(object):
    """Class with no __bobo_traverse__."""


def test_traversable():
    """
    Test the behaviour of Five-traversable classes.

      >>> import Products.Five
      >>> from Products.Five import zcml
      >>> zcml.load_config("configure.zcml", Products.Five)

    ``SimpleContent`` is a traversable class by default.  Its fallback
    traverser should raise NotFound when traversal fails.  (Note: If
    we return None in __fallback_traverse__, this test passes but for
    the wrong reason: None doesn't have a docstring so BaseRequest
    raises NotFoundError.)

      >>> from Products.Five.tests.testing.simplecontent import manage_addSimpleContent
      >>> manage_addSimpleContent(self.folder, 'testoid', 'Testoid')
      >>> print http(r'''
      ... GET /test_folder_1_/testoid/doesntexist HTTP/1.1
      ... ''')
      HTTP/1.1 404 Not Found
      ...

    Now let's take class which already has a __bobo_traverse__ method.
    Five should correctly use that as a fallback.

      >>> configure_zcml = '''
      ... <configure xmlns="http://namespaces.zope.org/zope"
      ...            xmlns:meta="http://namespaces.zope.org/meta"
      ...            xmlns:browser="http://namespaces.zope.org/browser"
      ...            xmlns:five="http://namespaces.zope.org/five">
      ... 
      ... <!-- make the zope2.Public permission work -->
      ... <meta:redefinePermission from="zope2.Public" to="zope.Public" />
      ... 
      ... <five:traversable
      ...     class="Products.Five.tests.testing.fancycontent.FancyContent"
      ...     />
      ... <five:traversable
      ...     class="Products.Five.browser.tests.test_traversable.SimpleClass"
      ...     />
      ... <five:traversable
      ...     class="Products.Five.tests.testing.FiveTraversableFolder"
      ...     />
      ... 
      ... <browser:page
      ...     for="Products.Five.tests.testing.fancycontent.IFancyContent"
      ...     class="Products.Five.browser.tests.pages.FancyView"
      ...     attribute="view"
      ...     name="fancy"
      ...     permission="zope2.Public"
      ...     />
      ... 
      ... </configure>'''
      >>> zcml.load_string(configure_zcml)

      >>> from Products.Five.tests.testing.fancycontent import manage_addFancyContent
      >>> info = manage_addFancyContent(self.folder, 'fancy', '')

    In the following test we let the original __bobo_traverse__ method
    kick in:

      >>> print http(r'''
      ... GET /test_folder_1_/fancy/something-else HTTP/1.1
      ... ''')
      HTTP/1.1 200 OK
      ...
      something-else

    Of course we also need to make sure that Zope 3 style view lookup
    actually works:

      >>> print http(r'''
      ... GET /test_folder_1_/fancy/fancy HTTP/1.1
      ... ''')
      HTTP/1.1 200 OK
      ...
      Fancy, fancy

    Without five traversable, if there had been an attrubute something-else,
    the __bobo_traverse__ method would have still been used instead of the
    atribute, let's make sure we preserve that behavior.

      >>> self.folder.fancy.an_attribute = 'This is an attribute'
      >>> print http(r'''
      ... GET /test_folder_1_/fancy/an_attribute HTTP/1.1
      ... ''')
      HTTP/1.1 200 OK
      ...
      an_attribute

    If we use WebDAV to get an object no acquisition should be performed,
    otherwise content creation will break:

      >>> from Products.Five.tests.testing import manage_addFiveTraversableFolder
      >>> manage_addFiveTraversableFolder(self.folder, 'traversable_folder', 'Traversable')

    Let's verify that we can get our object properties via WebDAV:
      >>> print http(r'''
      ... PROPFIND /test_folder_1_/fancy HTTP/1.1
      ... 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>
      ... ''')
      HTTP/1.1 200 OK
      ...
      PROPFIND

    And that a normal http request will acquire the object:
      >>> print http(r'''
      ... GET /test_folder_1_/traversable_folder/fancy HTTP/1.1
      ... ''')
      HTTP/1.1 200 OK
      ...
      <FancyContent at >

    But that a WebDAV request will not:
      >>> print http(r'''
      ... PROPFIND /test_folder_1_/traversable_folder/fancy HTTP/1.1
      ... 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>
      ... ''')
      HTTP/1.1 404 Not Found
      ...

    If we use WebDAV to get an object no acquisition should be performed,
    otherwise content creation will break:
 
      >>> from Products.Five.tests.testing import manage_addFiveTraversableFolder
      >>> manage_addFiveTraversableFolder(self.folder, 'traversable_folder', 'Traversable')

    Let's verify that we can get our object properties via WebDAV:
      >>> print http(r'''
      ... PROPFIND /test_folder_1_/fancy HTTP/1.1
      ... 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>
      ... ''')
      HTTP/1.1 200 OK
      ...
      PROPFIND

    And that a normal http request will acquire the object:
      >>> print http(r'''
      ... GET /test_folder_1_/traversable_folder/fancy HTTP/1.1
      ... ''')
      HTTP/1.1 200 OK
      ...
      <FancyContent at >

    But that a WebDAV request will not:
      >>> print http(r'''
      ... PROPFIND /test_folder_1_/traversable_folder/fancy HTTP/1.1
      ... 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>
      ... ''')
      HTTP/1.1 404 Not Found
      ...


    Clean up:

      >>> from zope.app.tests.placelesssetup import tearDown
      >>> tearDown()

    Verify that after cleanup, there's no cruft left from five:traversable::

      >>> from Products.Five.browser.tests.test_traversable import SimpleClass
      >>> hasattr(SimpleClass, '__bobo_traverse__')
      False
      >>> hasattr(SimpleClass, '__fallback_traverse__')
      False

      >>> from Products.Five.tests.testing.fancycontent import FancyContent
      >>> hasattr(FancyContent, '__bobo_traverse__')
      True
      >>> hasattr(FancyContent.__bobo_traverse__, '__five_method__')
      False
      >>> hasattr(FancyContent, '__fallback_traverse__')
      False
    """

def test_suite():
    from Testing.ZopeTestCase import FunctionalDocTestSuite
    return FunctionalDocTestSuite()

if __name__ == '__main__':
    framework()
