#!/usr/bin/env python
# -*- coding: utf-8 -*-
#   Copyright 2008 Agile42 GmbH - Andrea Tomasini 
#
#   Licensed under the Apache License, Version 2.0 (the "License");
#   you may not use this file except in compliance with the License.
#   You may obtain a copy of the License at
#
#       http://www.apache.org/licenses/LICENSE-2.0
#
#   Unless required by applicable law or agreed to in writing, software
#   distributed under the License is distributed on an "AS IS" BASIS,
#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
#   See the License for the specific language governing permissions and
#   limitations under the License.
# 
# Authors:
#     - Andrea Tomasini

import unittest
import datetime

from agilo.utils import Key, Type
from agilo.test import TestEnvHelper
from agilo.utils.config import AgiloConfig
from agilo.utils.web_ui import CoreTemplateProvider


class TestCoreTemplateProvider(unittest.TestCase):
    """
    This testcase aims to test as much as possible of the IRequestFilter
    implementation, given the fact that it is very complex and may introduce
    may issues. The IRequestFilter process the request before (PRE) and after
    (POST) having called the process_request() of a Trac Component.
    
    With Trac 0.11 there has been a change in the interface of the API, with it
    the use of Genshi complicate the things a bit, now in the data dictionary
    there may be any valid Python object.
    
    A sample data dictionary look the following:
    
    {'action': 'leave',
     'action_controls': [('leave', 'leave', <Fragment>, ['']),
                         ('resolve',
                          'resolve',
                          <Fragment>,
                          [u"The resolution will be set. Next status will be 'closed'"]),
                         ('reassign',
                          'reassign',
                          <Fragment>,
                          [u"The owner will change. Next status will be 'assigned'"]),
                         ('accept',
                          'accept',
                          <Fragment>,
                          [u"The owner will change to admin. Next status will be 'accepted'"])],
     'attachments': {'attach_href': '/test0.11/attachment/ticket/4/',
                     'attachments': [],
                     'can_create': True,
                     'parent': <Resource u'ticket:4'>},
     'author_id': u'admin',
     'change_preview': None,
     'changes': [{'author': u'admin',
                  'cnum': 1,
                  'comment': '',
                  'date': datetime.datetime(2008, 6, 12, 18, 26, 18, tzinfo=<FixedOffset "UTC" 0:00:00>),
                  'fields': {u'description': {'new': u'Test story changed',
                                              'old': u'Test story',
                                              'rendered': <Fragment>},
                             u'type': {'new': u'task', 'old': u'story'}},
                  'permanent': 1},
                 {'author': u'admin',
                  'cnum': 2,
                  'comment': '',
                  'date': datetime.datetime(2008, 6, 12, 18, 26, 44, tzinfo=<FixedOffset "UTC" 0:00:00>),
                  'fields': {u'type': {'new': u'story', 'old': u'task'}},
                  'permanent': 1},
                 {'author': u'admin',
                  'cnum': 3,
                  'comment': '',
                  'date': datetime.datetime(2008, 6, 13, 8, 54, 51, tzinfo=<FixedOffset "UTC" 0:00:00>),
                  'fields': {u'description': {'new': u'Test story changed...',
                                              'old': u'Test story changed',
                                              'rendered': <Fragment>}},
                  'permanent': 1},
                 {'author': u'admin',
                  'cnum': 4,
                  'comment': '',
                  'date': datetime.datetime(2008, 6, 13, 15, 27, 34, tzinfo=<FixedOffset "UTC" 0:00:00>),
                  'fields': {u'type': {'new': u'requirement', 'old': u'story'}},
                  'permanent': 1},
                 {'author': u'admin',
                  'cnum': 5,
                  'comment': '',
                  'date': datetime.datetime(2008, 6, 13, 15, 27, 50, tzinfo=<FixedOffset "UTC" 0:00:00>),
                  'fields': {u'type': {'new': u'story', 'old': u'requirement'}},
                  'permanent': 1}],
     'cnum': 6,
     'comment': None,
     'context': <Context <Resource u'ticket:4'>>,
     'description_change': {'author': u'admin',
                            'cnum': 3,
                            'comment': '',
                            'date': datetime.datetime(2008, 6, 13, 8, 54, 51, tzinfo=<FixedOffset "UTC" 0:00:00>),
                            'fields': {u'description': {'new': u'Test story changed...',
                                                        'old': u'Test story changed',
                                                        'rendered': <Fragment>}},
                            'permanent': 1},
     'fields': [{'label': 'Summary',
                 'name': 'summary',
                 'optional': False,
                 'options': [],
                 'skip': True,
                 'type': 'text'},
                {'label': 'Reporter',
                 'name': 'reporter',
                 'optional': False,
                 'options': [],
                 'skip': True,
                 'type': 'text'},
                {'label': 'Owner',
                 'name': 'owner',
                 'optional': False,
                 'options': [],
                 'skip': True,
                 'type': 'text'},
                {'label': 'Description',
                 'name': 'description',
                 'optional': False,
                 'options': [],
                 'skip': True,
                 'type': 'textarea'},
                {'label': 'Type',
                 'name': 'type',
                 'optional': False,
                 'options': [u'task', u'requirement', u'story', u'bug'],
                 'skip': False,
                 'type': 'select',
                 'value': u'defect'},
                {'label': 'Status',
                 'name': 'status',
                 'optional': True,
                 'options': [u'accepted',
                             u'assigned',
                             u'closed',
                             u'new',
                             u'reopened'],
                 'skip': True,
                 'type': 'radio',
                 'value': u''},
                {'label': 'Priority',
                 'name': 'priority',
                 'optional': False,
                 'options': [u'blocker',
                             u'critical',
                             u'major',
                             u'minor',
                             u'trivial'],
                 'skip': True,
                 'type': 'select',
                 'value': u'major'},
                {'label': 'Milestone',
                 'name': 'milestone',
                 'optgroups': [{'label': 'Open',
                                'options': [u'milestone1',
                                            u'milestone2',
                                            u'milestone3',
                                            u'milestone4']},
                               {'label': 'Closed', 'options': []}],
                 'optional': True,
                 'options': [],
                 'rendered': <Element "a">,
                 'skip': False,
                 'type': 'select',
                 'value': u''},
                {'label': 'Component',
                 'name': 'component',
                 'optional': False,
                 'options': [u'component1', u'component2'],
                 'skip': True,
                 'type': 'select',
                 'value': u''},
                {'label': 'Version',
                 'name': 'version',
                 'optional': True,
                 'options': [u'2.0', u'1.0'],
                 'skip': True,
                 'type': 'select',
                 'value': u''},
                {'label': 'Resolution',
                 'name': 'resolution',
                 'optional': True,
                 'options': [u'fixed',
                             u'invalid',
                             u'wontfix',
                             u'duplicate',
                             u'worksforme'],
                 'skip': True,
                 'type': 'radio',
                 'value': u'fixed'},
                {'label': 'Keywords',
                 'name': 'keywords',
                 'optional': False,
                 'options': [],
                 'skip': True,
                 'type': 'text'},
                {'label': 'Cc',
                 'name': 'cc',
                 'optional': False,
                 'options': [],
                 'rendered': '',
                 'skip': True,
                 'type': 'text'},
                {'custom': True,
                 'label': u'Remaining Time',
                 'name': 'remaining_time',
                 'optional': False,
                 'options': [],
                 'order': 0,
                 'skip': True,
                 'type': u'text',
                 'value': u''},
                {'custom': True,
                 'label': u'User Story Points',
                 'name': 'rd_points',
                 'optional': True,
                 'options': [u'0',
                             u'1',
                             u'2',
                             u'3',
                             u'5',
                             u'8',
                             u'13',
                             u'20',
                             u'40',
                             u'100'],
                 'order': 0,
                 'skip': False,
                 'type': u'select',
                 'value': u''},
                {'custom': True,
                 'label': u'References',
                 'name': 'o_links',
                 'optional': False,
                 'options': [],
                 'order': 0,
                 'skip': True,
                 'type': u'text',
                 'value': u''},
                {'custom': True,
                 'label': u'User Story Priority',
                 'name': 'story_priority',
                 'optional': False,
                 'options': [u'Mandatory', u'Linear', u'Exciter'],
                 'order': 0,
                 'skip': False,
                 'type': u'select',
                 'value': u'Mandatory'},
                {'custom': True,
                 'label': u'Business Value Points',
                 'name': 'businessvalue',
                 'optional': True,
                 'options': [u'100',
                             u'200',
                             u'300',
                             u'500',
                             u'800',
                             u'1200',
                             u'2000',
                             u'3000'],
                 'order': 0,
                 'skip': True,
                 'type': u'select',
                 'value': u''},
                {'custom': True,
                 'label': u'Referenced By',
                 'name': 'i_links',
                 'optional': False,
                 'options': [],
                 'order': 0,
                 'skip': True,
                 'type': u'text',
                 'value': u''}],
     'may_comment_ticket': True,
     'can_access_ticket_edit_page': True,
     'preserve_newlines': True,
     'reassign_owner': u'admin',
     'replies': {},
     'replyto': None,
     'resolve_resolution': None,
     'ticket': <AgiloTicket #4 (story)>,
     'timestamp': '2008-06-13 15:27:50+00:00',
     'version': None}
    
    This example is used also for testing and is based on a pprint of a regular Trac
    ticket.
    """
    
    def setUp(self):
        """Creates the environment stub"""
        self.teh = TestEnvHelper()
        self.env = self.teh.get_env()
        t1 = self.teh.create_ticket(Type.TASK, props={'remaining_time': '12'})
        self.DATA = {
         'action': 'leave',
         'action_controls': [('leave', 'leave', '<Fragment>', ['']),
                             ('resolve',
                              'resolve',
                              '<Fragment>',
                              [u"The resolution will be set. Next status will be 'closed'"]),
                             ('reassign',
                              'reassign',
                              '<Fragment>',
                              [u"The owner will change. Next status will be 'assigned'"]),
                             ('accept',
                              'accept',
                              '<Fragment>',
                              [u"The owner will change to admin. Next status will be 'accepted'"])],
         'attachments': {'attach_href': '/test0.11/attachment/ticket/4/',
                         'attachments': [],
                         'can_create': True,
                         'parent': None},
         'author_id': u'admin',
         'change_preview': None,
         # Command: changes@fields(item.has_key(Key.FIELDS)):Key.TYPE:'new'|'old'
         'changes': [{'author': u'admin',
                      'cnum': 1,
                      'comment': '',
                      'date': datetime.datetime(2008, 6, 12, 18, 26, 18),
                      'fields': {u'description': {'new': u'Test story changed',
                                                  'old': u'Test story',
                                                  'rendered': None},
                                 u'type': {'new': u'task', 'old': u'story'}}, # Replace
                      'permanent': 1},
                     {'author': u'admin',
                      'cnum': 2,
                      'comment': '',
                      'date': datetime.datetime(2008, 6, 12, 18, 26, 44),
                      'fields': {u'type': {'new': u'story', 'old': u'task'}}, # Replace
                      'permanent': 1},
                     {'author': u'admin',
                      'cnum': 3,
                      'comment': '',
                      'date': datetime.datetime(2008, 6, 13, 8, 54, 51),
                      'fields': {u'description': {'new': u'Test story changed...',
                                                  'old': u'Test story changed',
                                                  'rendered': None}},
                      'permanent': 1},
                     {'author': u'admin',
                      'cnum': 4,
                      'comment': '',
                      'date': datetime.datetime(2008, 6, 13, 15, 27, 34),
                      'fields': {u'type': {'new': u'requirement', 'old': u'story'}}, # Replace
                      'permanent': 1},
                     {'author': u'admin',
                      'cnum': 5,
                      'comment': '',
                      'date': datetime.datetime(2008, 6, 13, 15, 27, 50),
                      'fields': {u'type': {'new': u'story', 'old': u'requirement'}}, # Replace
                      'permanent': 1}],
         'cnum': 6,
         'comment': None,
         'context': None,
         'allowed_links': {u'bug-story': [u'bug', u'story'],
                           u'bug-task': [u'bug', u'task'],
                           u'requirement-story': [u'requirement', u'story'],
                           u'story-task': [u'story', u'task']}, # Replace
         'available_types': [u'task', u'requirement', u'story', u'bug'], # Replace
         'description_change': {'author': u'admin',
                                'cnum': 3,
                                'comment': '',
                                'date': datetime.datetime(2008, 6, 13, 8, 54, 51),
                                'fields': {u'description': {'new': u'Test story changed...',
                                                            'old': u'Test story changed',
                                                            'rendered': None}},
                                'permanent': 1},
         'fields': [{'label': 'Summary',
                     'name': 'summary',
                     'optional': False,
                     'options': [],
                     'skip': True,
                     'type': 'text'},
                    {'label': 'Reporter',
                     'name': 'reporter',
                     'optional': False,
                     'options': [],
                     'skip': True,
                     'type': 'text'},
                    {'label': 'Owner',
                     'name': 'owner',
                     'optional': False,
                     'options': [],
                     'skip': True,
                     'type': 'text'},
                    {'label': 'Description',
                     'name': 'description',
                     'optional': False,
                     'options': [],
                     'skip': True,
                     'type': 'textarea'},
                    {'label': 'Type',
                     'name': 'type',
                     'optional': False,
                     'options': [u'task', u'requirement', u'story', u'bug'], # Replace
                     'skip': False,
                     'type': 'select',
                     'value': u'defect'},
                    {'label': 'Status',
                     'name': 'status',
                     'optional': True,
                     'options': [u'accepted',
                                 u'assigned',
                                 u'closed',
                                 u'new',
                                 u'reopened'],
                     'skip': True,
                     'type': 'radio',
                     'value': u''},
                    {'label': 'Priority',
                     'name': 'priority',
                     'optional': False,
                     'options': [u'blocker',
                                 u'critical',
                                 u'major',
                                 u'minor',
                                 u'trivial'],
                     'skip': True,
                     'type': 'select',
                     'value': u'major'},
                    {'label': 'Milestone',
                     'name': 'milestone',
                     'optgroups': [{'label': 'Open',
                                    'options': [u'milestone1',
                                                u'milestone2',
                                                u'milestone3',
                                                u'milestone4']},
                                   {'label': 'Closed', 'options': []}],
                     'optional': True,
                     'options': [],
                     'rendered': '<Element "a">',
                     'skip': False,
                     'type': 'select',
                     'value': u''},
                    {'label': 'Component',
                     'name': 'component',
                     'optional': False,
                     'options': [u'component1', u'component2'],
                     'skip': True,
                     'type': 'select',
                     'value': u''},
                    {'label': 'Version',
                     'name': 'version',
                     'optional': True,
                     'options': [u'2.0', u'1.0'],
                     'skip': True,
                     'type': 'select',
                     'value': u''},
                    {'label': 'Resolution',
                     'name': 'resolution',
                     'optional': True,
                     'options': [u'fixed',
                                 u'invalid',
                                 u'wontfix',
                                 u'duplicate',
                                 u'worksforme'],
                     'skip': True,
                     'type': 'radio',
                     'value': u'fixed'},
                    {'label': 'Keywords',
                     'name': 'keywords',
                     'optional': False,
                     'options': [],
                     'skip': True,
                     'type': 'text'},
                    {'label': 'Cc',
                     'name': 'cc',
                     'optional': False,
                     'options': [],
                     'rendered': '',
                     'skip': True,
                     'type': 'text'},
                    {'custom': True,
                     'label': 'Linking_src',
                     'name': 'linking_src',
                     'optional': False,
                     'options': [],
                     'order': 0,
                     'skip': True,
                     'type': u'text',
                     'value': u''},
                    {'custom': True,
                     'label': u'Remaining Time',
                     'name': 'remaining_time',
                     'optional': False,
                     'options': [],
                     'order': 0,
                     'skip': True,
                     'type': u'text',
                     'value': u''},
                    {'custom': True,
                     'label': u'User Story Points',
                     'name': 'rd_points',
                     'optional': True,
                     'options': [u'0',
                                 u'1',
                                 u'2',
                                 u'3',
                                 u'5',
                                 u'8',
                                 u'13',
                                 u'20',
                                 u'40',
                                 u'100'],
                     'order': 0,
                     'skip': False,
                     'type': u'select',
                     'value': u''},
                    {'custom': True,
                     'label': u'References',
                     'name': 'o_links',
                     'optional': False,
                     'options': [],
                     'order': 0,
                     'skip': True,
                     'type': u'text',
                     'value': u''},
                    {'custom': True,
                     'label': u'User Story Priority',
                     'name': 'story_priority',
                     'optional': False,
                     'options': [u'Mandatory', u'Linear', u'Exciter'],
                     'order': 0,
                     'skip': False,
                     'type': u'select',
                     'value': u'Mandatory'},
                    {'custom': True,
                     'label': u'Business Value Points',
                     'name': 'businessvalue',
                     'optional': True,
                     'options': [u'100',
                                 u'200',
                                 u'300',
                                 u'500',
                                 u'800',
                                 u'1200',
                                 u'2000',
                                 u'3000'],
                     'order': 0,
                     'skip': True,
                     'type': u'select',
                     'value': u''},
                    {'custom': True,
                     'label': u'Referenced By',
                     'name': 'i_links',
                     'optional': False,
                     'options': [],
                     'order': 0,
                     'skip': True,
                     'type': u'text',
                     'value': u''}],
         'may_comment_ticket': True,
         'can_access_ticket_edit_page': True,
         'preserve_newlines': True,
         'reassign_owner': u'admin',
         'replies': {},
         'replyto': None,
         'resolve_resolution': None,
         'ticket': t1,
         'timestamp': '2008-06-13 15:27:50+00:00',
         'version': None,
         'row_groups': [(None,
                          [{u'__color__': u'3',
                            '__idx__': 0,
                            'cell_groups': [[{'header': {'asc': False,
                                                         'col': u'__color__',
                                                         'hidden': True,
                                                         'title': u'Color'},
                                              'index': 0,
                                              'value': u'3'},
                                             {'header': {'asc': False,
                                                         'col': u'ticket',
                                                         'hidden': False,
                                                         'title': u'Ticket'},
                                              'index': 1,
                                              'value': u'4'},
                                             {'header': {'asc': False,
                                                         'col': u'summary',
                                                         'hidden': False,
                                                         'title': u'Summary'},
                                              'index': 2,
                                              'value': u'New User Story'},
                                             {'header': {'asc': False,
                                                         'col': u'component',
                                                         'hidden': False,
                                                         'title': u'Component'},
                                              'index': 3,
                                              'value': u'component1'},
                                             {'header': {'asc': False,
                                                         'col': u'version',
                                                         'hidden': False,
                                                         'title': u'Version'},
                                              'index': 4,
                                              'value': u''},
                                             {'header': {'asc': False,
                                                         'col': u'milestone',
                                                         'hidden': False,
                                                         'title': u'Milestone'},
                                              'index': 5,
                                              'value': u''},
                                             {'header': {'asc': False,
                                                         'col': u'type',
                                                         'hidden': False,
                                                         'title': u'Type'},
                                              'index': 6,
                                              'value': u'story'}]], # Replace in View Ticket
                            'id': u'4',
                            'resource': "Resource u'ticket:4'"}]
                        )],
        }
        self.ctp = CoreTemplateProvider(self.env)
        
    def tearDown(self):
        self.teh.delete_created_tickets()
    
    def alias_values(self):
        return AgiloConfig(self.env).ALIASES.values()
    
    def testReplaceInFields(self):
        """Tests the replace of the type alias into the fields"""
        ALIAS_KEYS = ["'fields'@'options'(item[Key.NAME]==Key.TYPE)"]
        self.ctp._substitute_ticket_types_with_aliases_in_genshi_data(self.DATA, ALIAS_KEYS)
        for f in self.DATA['fields']:
            if f.has_key('name') and f['name'] == 'type':
                self.assertEqual(sorted(f['options']), sorted(self.alias_values()))
    
    def testReplaceInChanges(self):
        """Tests the replace of the type alias into the changes"""
        ALIAS_KEYS = ["'changes'@'fields'(item.has_key(Key.FIELDS)):Key.TYPE:'new'|'old'"]
        self.ctp._substitute_ticket_types_with_aliases_in_genshi_data(self.DATA, ALIAS_KEYS)
        for change in self.DATA['changes']:
            if change.has_key(Key.TYPE):
                self.assertTrue(change[Key.TYPE]['new'] in self.alias_values())
                self.assertTrue(change[Key.TYPE]['old'] in self.alias_values())
                
    def testReplaceInAdminInterface(self):
        """Tests the replace in the Admin interface"""
        ALIAS_KEYS = ["'available_types'", "'allowed_links':'*'"]
        self.ctp._substitute_ticket_types_with_aliases_in_genshi_data(self.DATA, ALIAS_KEYS)
        for ltype in self.DATA['available_types']:
            self.assertTrue(ltype in self.alias_values())
        for alinks in self.DATA['allowed_links'].values():
            for al in alinks:
                self.assertTrue(al in self.alias_values())
                
    def testReplaceInViewTicketReport(self):
        """Tests the replace in the Report from View Ticket"""
        ALIAS_KEYS = ["'row_groups',0,1@'cell_groups',0@'value'(item['header']['title']=='Type')"]
        self.ctp._substitute_ticket_types_with_aliases_in_genshi_data(self.DATA, ALIAS_KEYS)
        for key, rows in self.DATA['row_groups']:
            for r in rows:
                for v in r['cell_groups']:
                    for l in v:
                        if l['header']['title'] == 'Type':
                            self.assertTrue(l['value'] in self.alias_values())


if __name__ == '__main__':
    suite = unittest.TestLoader().loadTestsFromTestCase(TestCoreTemplateProvider)
    #suite = unittest.TestSuite()
    #suite.addTest(TestCoreTemplateProvider('testCommandParser'))
    unittest.TextTestRunner(verbosity=0).run(suite)
