# This file is part of Buildbot.  Buildbot is free software: you can
# redistribute it and/or modify it under the terms of the GNU General Public
# License as published by the Free Software Foundation, version 2.
#
# This program is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
# FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
# details.
#
# You should have received a copy of the GNU General Public License along with
# this program; if not, write to the Free Software Foundation, Inc., 51
# Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
#
# Copyright Buildbot Team Members

from twisted.internet import defer
from twisted.internet import reactor
from twisted.trial import unittest

from buildbot.clients import sendchange as sendchange_client
from buildbot.scripts import sendchange
from buildbot.test.util import misc


class TestSendChange(misc.StdoutAssertionsMixin, unittest.TestCase):
    class FakeSender:
        def __init__(self, testcase, master, auth, encoding=None):
            self.master = master
            self.auth = auth
            self.encoding = encoding
            self.testcase = testcase

        def send(self, branch, revision, comments, files, **kwargs):
            kwargs['branch'] = branch
            kwargs['revision'] = revision
            kwargs['comments'] = comments
            kwargs['files'] = files
            self.send_kwargs = kwargs
            d = defer.Deferred()
            if self.testcase.fail:
                reactor.callLater(0, d.errback, RuntimeError("oh noes"))
            else:
                reactor.callLater(0, d.callback, None)
            return d

    def setUp(self):
        self.fail = False  # set to true to get Sender.send to fail

        def Sender_constr(*args, **kwargs):
            self.sender = self.FakeSender(self, *args, **kwargs)
            return self.sender

        self.patch(sendchange_client, 'Sender', Sender_constr)

        # undo the effects of @in_reactor
        self.patch(sendchange, 'sendchange', sendchange.sendchange._orig)

        self.setUpStdoutAssertions()

    @defer.inlineCallbacks
    def test_sendchange_config(self):
        rc = yield sendchange.sendchange({
            "encoding": 'utf16',
            "who": 'me',
            "auth": ['a', 'b'],
            "master": 'm',
            "branch": 'br',
            "category": 'cat',
            "revision": 'rr',
            "properties": {'a': 'b'},
            "repository": 'rep',
            "project": 'prj',
            "vc": 'git',
            "revlink": 'rl',
            "when": 1234.0,
            "comments": 'comm',
            "files": ('a', 'b'),
            "codebase": 'cb',
        })

        self.assertEqual(
            (
                self.sender.master,
                self.sender.auth,
                self.sender.encoding,
                self.sender.send_kwargs,
                self.getStdout(),
                rc,
            ),
            (
                'm',
                ['a', 'b'],
                'utf16',
                {
                    'branch': 'br',
                    'category': 'cat',
                    'codebase': 'cb',
                    'comments': 'comm',
                    'files': ('a', 'b'),
                    'project': 'prj',
                    'properties': {'a': 'b'},
                    'repository': 'rep',
                    'revision': 'rr',
                    'revlink': 'rl',
                    'when': 1234.0,
                    'who': 'me',
                    'vc': 'git',
                },
                'change sent successfully',
                0,
            ),
        )

    @defer.inlineCallbacks
    def test_sendchange_config_no_codebase(self):
        rc = yield sendchange.sendchange({
            "encoding": 'utf16',
            "who": 'me',
            "auth": ['a', 'b'],
            "master": 'm',
            "branch": 'br',
            "category": 'cat',
            "revision": 'rr',
            "properties": {'a': 'b'},
            "repository": 'rep',
            "project": 'prj',
            "vc": 'git',
            "revlink": 'rl',
            "when": 1234.0,
            "comments": 'comm',
            "files": ('a', 'b'),
        })

        self.assertEqual(
            (
                self.sender.master,
                self.sender.auth,
                self.sender.encoding,
                self.sender.send_kwargs,
                self.getStdout(),
                rc,
            ),
            (
                'm',
                ['a', 'b'],
                'utf16',
                {
                    'branch': 'br',
                    'category': 'cat',
                    'codebase': None,
                    'comments': 'comm',
                    'files': ('a', 'b'),
                    'project': 'prj',
                    'properties': {'a': 'b'},
                    'repository': 'rep',
                    'revision': 'rr',
                    'revlink': 'rl',
                    'when': 1234.0,
                    'who': 'me',
                    'vc': 'git',
                },
                'change sent successfully',
                0,
            ),
        )

    @defer.inlineCallbacks
    def test_sendchange_fail(self):
        self.fail = True
        rc = yield sendchange.sendchange({})

        self.assertEqual((self.getStdout().split('\n')[0], rc), ('change not sent:', 1))
