from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
from __future__ import unicode_literals

from hashlib import sha1

from mock import Mock
import unittest2

from github_reviewboard_sync.exceptions import MissingRemoteException, MissingBranchExcpetion
from github_reviewboard_sync.repo import _get_relevant_commit_shas, _get_relevant_commits, \
    _construct_summary, _get_messages, _get_remote, _get_branch


class TestGetRelevantCommitShas(unittest2.TestCase):
    def test__when_no_matches__returns_empty_list(self):
        expected = []

        repo = Mock(git=Mock(log=Mock(return_value='a'*1000)))
        resp = _get_relevant_commit_shas(repo, 'doesnt', 'matter')
        self.assertListEqual(expected, resp)

    def test__when_merge__returns_empty_list(self):
        expected = []

        log_output = 'commit {0}\nMerge'.format(sha1(b'a').hexdigest())
        repo = Mock(git=Mock(log=Mock(return_value=log_output)))
        resp = _get_relevant_commit_shas(repo, 'doesnt', 'matter')
        self.assertListEqual(expected, resp)

    def test__when_multiple__returns_all(self):
        first = sha1(b'a').hexdigest()
        second = sha1(b'b').hexdigest()
        expected = [first, second]

        log_output = 'commit {0}\n\ncommit {1}\n'.format(first, second)
        repo = Mock(git=Mock(log=Mock(return_value=log_output)))
        resp = _get_relevant_commit_shas(repo, 'doesnt', 'matter')
        self.assertListEqual(expected, resp)


class TestGetRelevantCommits(unittest2.TestCase):
    def setUp(self):
        self.commit1 = Mock(hexsha=sha1(b'a').hexdigest())
        self.commit2 = Mock(hexsha=sha1(b'b').hexdigest())
        self.commit3 = Mock(hexsha=sha1(b'c').hexdigest())
        self.repo = Mock(iter_commits=Mock(return_value=[self.commit1, self.commit2, self.commit3]))

    def test__when_no_shas_match__returns_empty_list(self):
        shas = [sha1(b'd').hexdigest()]
        resp = _get_relevant_commits(self.repo, shas, 'notrelevant')
        self.assertListEqual([], resp)

    def test__when_multiple__returns_all_matching(self):
        expected = [self.commit1, self.commit3]
        shas = [commit.hexsha for commit in expected]
        resp = _get_relevant_commits(self.repo, shas, 'notrelevant')
        self.assertEqual(expected, resp)


class TestConstructSummary(unittest2.TestCase):
    def test__when_empty__returns_generic(self):
        expected = 'Autogenerated pull request'
        resp = _construct_summary([])
        self.assertEqual(expected, resp)

    def test__when_not_empty__returns_first_summary(self):
        expected = 'blah'
        resp = _construct_summary([Mock(summary=expected), Mock(summary='bad')])
        self.assertEqual(expected, resp)


class TestGetMessage(unittest2.TestCase):
    def test__when_empty__returns_empty_string(self):
        resp = _get_messages(None)
        self.assertEqual('', resp)
        resp = _get_messages([])
        self.assertEqual('', resp)

    def test__when_not_empty__joins_messages(self):
        first = Mock(message='blah')
        second = Mock(message='another')
        expected = 'blah\n\nanother'
        resp = _get_messages([first, second])
        self.assertEqual(expected, resp)


class TestGetRemote(unittest2.TestCase):
    def test__when_missing_name__raises_missing_remote(self):
        # This is strange because the dictionary like object `remotes`
        # raises a IndexError instead of a KeyError
        repo = Mock(remotes=[])
        self.assertRaises(MissingRemoteException, _get_remote, repo, 1)

    def test__when_valid_name__returns_remote(self):
        repo = Mock(remotes=dict(remote='blah'))
        self.assertEquals('blah', _get_remote(repo, 'remote'))


class TestGetBranch(unittest2.TestCase):
    def test__when_missing_branch__raises_missing_branch(self):
        # This is strange because the dictionary like object `branches`
        # raises a IndexError instead of a KeyError
        repo = Mock(branches=[])
        self.assertRaises(MissingBranchExcpetion, _get_branch, repo, 1)

    def test__when_valid_name__returns_remote(self):
        repo = Mock(branches=dict(branch='blah'))
        self.assertEquals('blah', _get_branch(repo, 'branch'))
