text: # -*- coding: utf-8 -*-
  #
  # Copyright (C) 2012-2013 Edgewall Software
  # All rights reserved.
  #
  # This software is licensed as described in the file COPYING, which
  # you should have received as part of this distribution. The terms
  # are also available at http://trac.edgewall.org/wiki/TracLicense.
  #
  # This software consists of voluntary contributions made by many
  # individuals. For the exact contribution history, see the revision
  # history and logs, available at http://trac.edgewall.org/log/.
  
  import os
  import tempfile
  import unittest
  try:
      from configobj import ConfigObj
  except ImportError:
      ConfigObj = None
  
  import trac.tests.compat
  from trac.config import ConfigurationError
  from trac.perm import PermissionCache
  from trac.resource import Resource
  from trac.test import EnvironmentStub, Mock
  from trac.util import create_file
  from trac.versioncontrol.api import Repository
  from tracopt.perm.authz_policy import AuthzPolicy
  
  
  class AuthzPolicyTestCase(unittest.TestCase):
  
      def setUp(self):
          tmpdir = os.path.realpath(tempfile.gettempdir())
          self.authz_file = os.path.join(tmpdir, 'trac-authz-policy')
          create_file(self.authz_file, """\
  # Unicode user names
  [groups]
  administrators = éat
  
  [wiki:WikiStart]
  änon = WIKI_VIEW
  @administrators = WIKI_VIEW
  * =
  
  # Unicode page names
  [wiki:résumé]
  änon =
  @administrators = WIKI_VIEW
  * =
  
  # Tickets
  [ticket:43]
  änon = TICKET_VIEW
  @administrators =
  * =
  
  [ticket:*]
  änon =
  @administrators = TICKET_VIEW
  * =
  
  # Default repository
  [repository:@*]
  änon =
  @administrators = BROWSER_VIEW, FILE_VIEW
  * =
  
  # Non-default repository
  [repository:bláh@*]
  änon = BROWSER_VIEW, FILE_VIEW
  @administrators = BROWSER_VIEW, FILE_VIEW
  * =
  """)
          self.env = EnvironmentStub(enable=['trac.*', AuthzPolicy], path=tmpdir)
          self.env.config.set('trac', 'permission_policies',
                              'AuthzPolicy, DefaultPermissionPolicy')
          self.env.config.set('authz_policy', 'authz_file', self.authz_file)
          self.authz_policy = AuthzPolicy(self.env)
  
      def tearDown(self):
          self.env.reset_db()
          os.remove(self.authz_file)
  
      def check_permission(self, action, user, resource, perm):
          return self.authz_policy.check_permission(action, user, resource, perm)
  
      def get_repository(self, reponame):
          params = {'id': 1, 'name': reponame}
          return Mock(Repository, 'mock', params, self.env.log)
  
      def get_perm(self, username, *args):
          perm = PermissionCache(self.env, username)
          if args:
              return perm(*args)
          return perm
  
      def test_unicode_username(self):
          resource = Resource('wiki', 'WikiStart')
  
          perm = self.get_perm('anonymous')
          self.assertFalse(
              self.check_permission('WIKI_VIEW', 'anonymous', resource, perm))
          self.assertNotIn('WIKI_VIEW', perm)
          self.assertNotIn('WIKI_VIEW', perm(resource))
  
          perm = self.get_perm(u'änon')
          self.assertTrue(
              self.check_permission('WIKI_VIEW', u'änon', resource, perm))
          self.assertNotIn('WIKI_VIEW', perm)
          self.assertIn('WIKI_VIEW', perm(resource))
  
      def test_unicode_resource_name(self):
          resource = Resource('wiki', u'résumé')
  
          perm = self.get_perm('anonymous')
          self.assertFalse(
              self.check_permission('WIKI_VIEW', 'anonymous', resource, perm))
          self.assertNotIn('WIKI_VIEW', perm)
          self.assertNotIn('WIKI_VIEW', perm(resource))
  
          perm = self.get_perm(u'änon')
          self.assertFalse(
              self.check_permission('WIKI_VIEW', u'änon', resource, perm))
          self.assertNotIn('WIKI_VIEW', perm)
          self.assertNotIn('WIKI_VIEW', perm(resource))
  
          perm = self.get_perm(u'éat')
          self.assertTrue(
              self.check_permission('WIKI_VIEW', u'éat', resource, perm))
          self.assertNotIn('WIKI_VIEW', perm)
          self.assertIn('WIKI_VIEW', perm(resource))
  
      def test_resource_without_id(self):
          perm = self.get_perm('anonymous')
          self.assertNotIn('TICKET_VIEW', perm)
          self.assertNotIn('TICKET_VIEW', perm('ticket'))
          self.assertNotIn('TICKET_VIEW', perm('ticket', 42))
          self.assertNotIn('TICKET_VIEW', perm('ticket', 43))
  
          perm = self.get_perm(u'änon')
          self.assertNotIn('TICKET_VIEW', perm)
          self.assertNotIn('TICKET_VIEW', perm('ticket'))
          self.assertNotIn('TICKET_VIEW', perm('ticket', 42))
          self.assertIn('TICKET_VIEW', perm('ticket', 43))
  
          perm = self.get_perm(u'éat')
          self.assertNotIn('TICKET_VIEW', perm)
          self.assertIn('TICKET_VIEW', perm('ticket'))
          self.assertIn('TICKET_VIEW', perm('ticket', 42))
          self.assertNotIn('TICKET_VIEW', perm('ticket', 43))
  
      def test_default_repository(self):
          repos = self.get_repository('')
          self.assertFalse(repos.is_viewable(self.get_perm('anonymous')))
          self.assertFalse(repos.is_viewable(self.get_perm(u'änon')))
          self.assertTrue(repos.is_viewable(self.get_perm(u'éat')))
  
      def test_non_default_repository(self):
          repos = self.get_repository(u'bláh')
          self.assertFalse(repos.is_viewable(self.get_perm('anonymous')))
          self.assertTrue(repos.is_viewable(self.get_perm(u'änon')))
          self.assertTrue(repos.is_viewable(self.get_perm(u'éat')))
  
      def test_case_sensitive_resource(self):
          resource = Resource('WIKI', 'wikistart')
          self.assertIsNone(
              self.check_permission('WIKI_VIEW', 'anonymous', resource, None))
          self.assertIsNone(
              self.check_permission('WIKI_VIEW', u'änon', resource, None))
  
      def test_get_authz_file(self):
          """get_authz_file should resolve a relative path and lazily compute.
          """
          authz_file = self.authz_policy.get_authz_file
          self.assertEqual(os.path.join(self.env.path, 'trac-authz-policy'),
                           authz_file)
          self.assertIs(authz_file, self.authz_policy.get_authz_file)
  
      def test_get_authz_file_notfound_raises(self):
          """ConfigurationError exception should be raised if file not found."""
          authz_file = os.path.join(self.env.path, 'some-nonexistent-file')
          self.env.config.set('authz_policy', 'authz_file', authz_file)
          self.assertRaises(ConfigurationError, getattr, self.authz_policy,
                            'get_authz_file')
  
      def test_get_authz_file_notdefined_raises(self):
          """ConfigurationError exception should be raised if the option
          `[authz_policy] authz_file` is not specified in trac.ini."""
          self.env.config.remove('authz_policy', 'authz_file')
          self.assertRaises(ConfigurationError, getattr, self.authz_policy,
                            'get_authz_file')
  
      def test_get_authz_file_empty_raises(self):
          """ConfigurationError exception should be raised if the option
          `[authz_policy] authz_file` is empty."""
          self.env.config.set('authz_policy', 'authz_file', '')
          self.assertRaises(ConfigurationError, getattr, self.authz_policy,
                            'get_authz_file')
  
      def test_parse_authz_empty(self):
          """Allow the file to be empty."""
          create_file(self.authz_file, '')
          self.authz_policy.parse_authz()
          self.assertFalse(self.authz_policy.authz)
  
      def test_parse_authz_no_settings(self):
          """Allow the file to have no settings."""
          create_file(self.authz_file, """\
  # [wiki:WikiStart]
  # änon = WIKI_VIEW
  # * =
  """)
          self.authz_policy.parse_authz()
          self.assertFalse(self.authz_policy.authz)
  
      def test_parse_authz_malformed_raises(self):
          """ConfigurationError should be raised if the file is malformed."""
          create_file(self.authz_file, """\
  wiki:WikiStart]
  änon = WIKI_VIEW
  * =
  """)
          self.assertRaises(ConfigurationError, self.authz_policy.parse_authz)
  
      def test_parse_authz_duplicated_sections_raises(self):
          """ConfigurationError should be raised if the file has duplicate
          sections."""
          create_file(self.authz_file, """\
  [wiki:WikiStart]
  änon = WIKI_VIEW
  
  [wiki:WikiStart]
  änon = WIKI_VIEW
  """)
          self.assertRaises(ConfigurationError, self.authz_policy.parse_authz)
  
  
  def suite():
      suite = unittest.TestSuite()
      if ConfigObj:
          suite.addTest(unittest.makeSuite(AuthzPolicyTestCase))
      else:
          print "SKIP: tracopt/perm/tests/authz_policy.py (no configobj " + \
                "installed)"
      return suite
  
  
  if __name__ == '__main__':
      unittest.main(defaultTest='suite')
  