# -*- encoding: utf-8 -*-
#   Copyright 2008 Agile42 GmbH, Berlin (Germany)
#
#   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.
#   
#   Author: 
#       - Felix Schwarz <felix.schwarz_at_agile42.com>

import unittest

from agilo.scrum.sprint import SprintController
from agilo.utils import Type, Key
from agilo.test import TestEnvHelper


class TestRtUspCalculation(unittest.TestCase):
    """Tests for the Remaining Time/User Story Points ratio calculation"""

    def _create_story_with_tasks(self, story_points, list_remaining_times, 
                                sprint):
        props = {Key.STORY_POINTS: story_points, Key.SPRINT: sprint.name}
        story = self.teh.create_ticket(Type.USER_STORY, props=props)
        
        for rt in list_remaining_times:
            props = {Key.REMAINING_TIME: rt, Key.SPRINT: sprint.name}
            task = self.teh.create_ticket(Type.TASK, props=props)
            task.link_from(story)
        return story
    
    def setUp(self):
        self.teh = TestEnvHelper()
        self.env = self.teh.get_env()
        sprint = self.teh.create_sprint(name='Sprint 1', milestone='Milestone 1')
        self.story1 = self._create_story_with_tasks('4', ('2', None), sprint)
        self.story2 = self._create_story_with_tasks('10', ('2', '6'), sprint)
        self.story3 = self._create_story_with_tasks(None, ('7'), sprint)
        self.sprint = sprint
    
    def tearDown(self):
        self.teh.cleanup()
    
    def _calculate_remaining_time_usp_ratio(self, stories):
        cmd_class = SprintController.CalculateRemainingTimeUSPRatioCommand
        cmd = cmd_class(self.env, sprint=self.sprint, stories=stories)
        return SprintController(self.env).process_command(cmd)
    
    def test_calculate_ratio(self):
        self.assertEqual(4, int(self.story1[Key.STORY_POINTS]))
        self.assertEqual(2, self.story1[Key.TOTAL_REMAINING_TIME])
        
        ratio = self._calculate_remaining_time_usp_ratio([self.story1])
        self.assertEqual(float(2) / float(4), ratio)
    
    def test_calculate_ratio_skip_stories_without_remaining_time(self):
        stories = [self.story1, self.story2, self.story3]
        ratio = self._calculate_remaining_time_usp_ratio(stories)
        self.assertEqual(float(2 + 2 + 6) / float(4 + 10), ratio)
    
    def test_no_ratio_without_stories(self):
        ratio = self._calculate_remaining_time_usp_ratio([])
        self.assertEqual(None, ratio)
    
    def test_skip_stories_with_invalid_story_point_value(self):
        self.story1[Key.STORY_POINTS] = 'foo'
        ratio = self._calculate_remaining_time_usp_ratio([self.story1])
        self.assertEqual(None, ratio)
    
    def test_ratio_calculation_works_with_float_numbers(self):
        self.story3.get_outgoing()[0][Key.REMAINING_TIME] = '5.2'
        self.story3[Key.STORY_POINTS] = '13'
        ratio = self._calculate_remaining_time_usp_ratio([self.story3])
        self.assertEqual(float('0.4'), ratio)


if __name__ == '__main__':
    unittest.main()
