#!/usr/bin/env python
# -*- coding: utf-8 -*-

import unittest
import re

from libs.mock import *

from runner.sensei import Sensei
from runner.writeln_decorator import WritelnDecorator
from runner.mockable_test_result import MockableTestResult

class AboutParrots:
    pass
class AboutLumberjacks:
    pass
class AboutTennis:
    pass
class AboutTheKnightsWhoSayNi:
    pass
class AboutMrGumby:
    pass
class AboutMessiahs:
    pass
class AboutGiantFeet:
    pass
class AboutTrebuchets:
    pass
class AboutFreemasons:
    pass

error_assertion_with_message = """Traceback (most recent call last):
  File "/Users/Greg/hg/python_koans/koans/about_exploding_trousers.py", line 43, in test_durability
    self.assertEqual("Steel","Lard", "Another fine mess you've got me into Stanley...")
AssertionError: Another fine mess you've got me into Stanley..."""

error_assertion_equals = """

Traceback (most recent call last):
  File "/Users/Greg/hg/python_koans/koans/about_exploding_trousers.py", line 49, in test_math
    self.assertEqual(4,99)
AssertionError: 4 != 99
"""

error_assertion_true = """Traceback (most recent call last):
  File "/Users/Greg/hg/python_koans/koans/about_armories.py", line 25, in test_weoponary
    self.assertTrue("Pen" > "Sword")
AssertionError

"""

error_mess = """
Traceback (most recent call last):
  File "contemplate_koans.py", line 5, in <module>
    from runner.mountain import Mountain
  File "/Users/Greg/hg/python_koans/runner/mountain.py", line 7, in <module>
    import path_to_enlightenment
  File "/Users/Greg/hg/python_koans/runner/path_to_enlightenment.py", line 8, in <module>
    from koans import *
  File "/Users/Greg/hg/python_koans/koans/about_asserts.py", line 20
    self.assertTrue(eoe"Pen" > "Sword", "nhnth")
                           ^
SyntaxError: invalid syntax"""

error_with_list = """Traceback (most recent call last):
  File "/Users/Greg/hg/python_koans/koans/about_armories.py", line 84, in test_weoponary
    self.assertEqual([1, 9], [1, 2])
AssertionError: Lists differ: [1, 9] != [1, 2]

First differing element 1:
9
2

- [1, 9]
?     ^

+ [1, 2]
?     ^

"""


class TestSensei(unittest.TestCase):

    def setUp(self):
        self.sensei = Sensei(WritelnDecorator(Mock()))

    def test_that_failures_are_handled_in_the_base_class(self):
        with patch('runner.mockable_test_result.MockableTestResult.addFailure', Mock()):
            self.sensei.addFailure(Mock(), Mock())
            self.assertTrue(MockableTestResult.addFailure.called)

    def test_that_it_successes_only_count_if_passes_are_currently_allowed(self):
        with patch('runner.mockable_test_result.MockableTestResult.addSuccess', Mock()):
            self.sensei.passesCount = Mock()
            self.sensei.addSuccess(Mock())
            self.assertTrue(self.sensei.passesCount.called)

    def test_that_it_passes_on_add_successes_message(self):
        with patch('runner.mockable_test_result.MockableTestResult.addSuccess', Mock()):
            self.sensei.addSuccess(Mock())
            self.assertTrue(MockableTestResult.addSuccess.called)

    def test_that_it_increases_the_passes_on_every_success(self):
        with patch('runner.mockable_test_result.MockableTestResult.addSuccess', Mock()):
            pass_count = self.sensei.pass_count
            self.sensei.addSuccess(Mock())
            self.assertEqual(pass_count + 1, self.sensei.pass_count)

    def test_that_nothing_is_returned_as_a_first_result_if_there_are_no_failures(self):
        self.sensei.failures = []
        self.assertEqual(None, self.sensei.firstFailure())

    def test_that_nothing_is_returned_as_sorted_result_if_there_are_no_failures(self):
        self.sensei.failures = []
        self.assertEqual(None, self.sensei.sortFailures("AboutLife"))

    def test_that_nothing_is_returned_as_sorted_result_if_there_are_no_relevent_failures(self):
        self.sensei.failures = [
            (AboutTheKnightsWhoSayNi(),"File 'about_the_knights_whn_say_ni.py', line 24"),
            (AboutMessiahs(),"File 'about_messiahs.py', line 43"),
            (AboutMessiahs(),"File 'about_messiahs.py', line 844")
        ]
        self.assertEqual(None, self.sensei.sortFailures("AboutLife"))

    def test_that_nothing_is_returned_as_sorted_result_if_there_are_3_shuffled_results(self):
        self.sensei.failures = [
            (AboutTennis(),"File 'about_tennis.py', line 299"),
            (AboutTheKnightsWhoSayNi(),"File 'about_the_knights_whn_say_ni.py', line 24"),
            (AboutTennis(),"File 'about_tennis.py', line 30"),
            (AboutMessiahs(),"File 'about_messiahs.py', line 43"),
            (AboutTennis(),"File 'about_tennis.py', line 2"),
            (AboutMrGumby(),"File 'about_mr_gumby.py', line odd"),
            (AboutMessiahs(),"File 'about_messiahs.py', line 844")
        ]

        expected = [
            (AboutTennis(),"File 'about_tennis.py', line 2"),
            (AboutTennis(),"File 'about_tennis.py', line 30"),
            (AboutTennis(),"File 'about_tennis.py', line 299")
        ]

        results = self.sensei.sortFailures("AboutTennis")
        self.assertEqual(3, len(results))
        self.assertEqual(2, results[0][0])
        self.assertEqual(30, results[1][0])
        self.assertEqual(299, results[2][0])

    def test_that_it_will_choose_not_find_anything_with_non_standard_error_trace_string(self):
        self.sensei.failures = [
            (AboutMrGumby(),"File 'about_mr_gumby.py', line MISSING"),
        ]
        self.assertEqual(None, self.sensei.sortFailures("AboutMrGumby"))


    def test_that_it_will_choose_correct_first_result_with_lines_9_and_27(self):
        self.sensei.failures = [
            (AboutTrebuchets(),"File 'about_trebuchets.py', line 27"),
            (AboutTrebuchets(),"File 'about_trebuchets.py', line 9"),
            (AboutTrebuchets(),"File 'about_trebuchets.py', line 73v")
        ]
        self.assertEqual("File 'about_trebuchets.py', line 9", self.sensei.firstFailure()[1])