# -*- coding: utf-8 -*-
#
# Copyright 2012 Canonical Ltd.
#
# This program is free software: you can redistribute it and/or modify it
# under the terms of the GNU General Public License version 3, as published
# by the Free Software Foundation.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranties of
# MERCHANTABILITY, SATISFACTORY QUALITY, 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, see <http://www.gnu.org/licenses/>.
#
# In addition, as a special exception, the copyright holders give
# permission to link the code of portions of this program with the
# OpenSSL library under certain conditions as described in each
# individual source file, and distribute linked combinations
# including the two.
# You must obey the GNU General Public License in all respects
# for all of the code used other than OpenSSL.  If you modify
# file(s) with this exception, you may extend this exception to your
# version of the file(s), but you are not obligated to do so.  If you
# do not wish to do so, delete this exception statement from your
# version.  If you delete this exception statement from all source
# files in the program, then also delete it here.
"""Test the ssl dialog."""

from PyQt4.QtGui import QStyle
from twisted.internet import defer
from twisted.trial.unittest import TestCase

from ubuntu_kylin_sso import USER_CANCELLATION, USER_SUCCESS
from ubuntu_kylin_sso.qt import ssl_dialog
from ubuntu_kylin_sso.utils import compat
from ubuntu_kylin_sso.utils.ui import (
    CANCEL_BUTTON,
    SSL_APPNAME_HELP,
    SSL_DETAILS_HELP,
    SSL_DESCRIPTION,
    SSL_DOMAIN_HELP,
    SSL_HEADER,
    SSL_EXPLANATION,
    SSL_FIRST_REASON,
    SSL_SECOND_REASON,
    SSL_THIRD_REASON,
    SSL_CERT_DETAILS,
    SSL_NOT_SURE,
    SSL_REMEMBER_DECISION,
    SSL_HELP_BUTTON,
    SSL_CONNECT_BUTTON,
)

# pylint: disable=W0212, C0103,


class SSLDialogTestCase(TestCase):
    """Test the ssl dialog."""

    @defer.inlineCallbacks
    def setUp(self):
        """Set the tests."""
        yield super(SSLDialogTestCase, self).setUp()
        self.domain = 'test-domain'
        self.details = 'SSL details'
        self.appname = 'test'

        self.dialog = ssl_dialog.SSLDialog(self.appname,
                                           domain=self.domain,
                                           details=self.details)
        self.return_code = None

        def fake_done(code):
            """Fake done for the dialog."""
            self.return_code = code

        self.patch(self.dialog, 'done', fake_done)

    def test_init_none_domain(self):
        """Test the init method when the domain is none."""
        dialog = ssl_dialog.SSLDialog(self.appname, domain=None,
                                      details=self.details)
        self.assertEqual(self.details, dialog.details)
        self.assertEqual('', dialog.domain)

    def test_init_none_details(self):
        """Test the init method when the details are none."""
        dialog = ssl_dialog.SSLDialog(self.appname, domain=self.domain,
                                      details=None)
        self.assertEqual('', dialog.details)
        self.assertEqual(self.domain, dialog.domain)

    def test_set_labels(self):
        """Test that the labels contain the correct info."""
        self.assertEqual(SSL_HEADER,
                         compat.text_type(self.dialog.ui.title_label.text()))
        explanation = SSL_EXPLANATION % dict(domain=self.domain)
        intro = ssl_dialog.REASONS_TEMPLATE % dict(explanation=explanation,
                                              first_reason=SSL_FIRST_REASON,
                                              second_reason=SSL_SECOND_REASON,
                                              third_reason=SSL_THIRD_REASON)
        self.assertEqual(intro,
                         compat.text_type(self.dialog.ui.intro_label.text()))
        self.assertEqual(SSL_NOT_SURE % dict(app_name=self.appname),
                compat.text_type(self.dialog.ui.not_sure_label.text()))
        self.assertEqual(SSL_REMEMBER_DECISION,
                compat.text_type(self.dialog.ui.remember_checkbox.text()))

    def test_on_cancel_clicked(self):
        """Test the cancelation action."""
        self.dialog._on_cancel_clicked()
        self.assertEqual(USER_CANCELLATION, self.return_code)

    def test_on_connect_clicked(self):
        """Test the connect action."""
        self.dialog._on_connect_clicked()
        self.assertEqual(USER_SUCCESS, self.return_code)

    def test_set_buttons(self):
        """Test that the buttons are correctly set up."""

        # assert that the buttons have been correctly connected
        called = []

        def fake_on_connect_clicked(event):
            """Fake the on connect clicked method."""
            called.append('_on_connect_clicked')

        self.patch(ssl_dialog.SSLDialog, '_on_connect_clicked',
                                          fake_on_connect_clicked)

        def fake_on_cancel_clicked(event):
            """Fake the on cancle clicked."""
            called.append('_on_cancel_clicked')

        self.patch(ssl_dialog.SSLDialog, '_on_cancel_clicked',
                                          fake_on_cancel_clicked)

        dialog = ssl_dialog.SSLDialog(self.appname, domain=None,
                                      details=self.details)

        dialog.ui.connect_button.clicked.emit(True)
        self.assertIn('_on_connect_clicked', called)

        dialog.ui.cancel_button.clicked.emit(True)
        self.assertIn('_on_cancel_clicked', called)

        self.assertEqual(CANCEL_BUTTON,
                compat.text_type(dialog.ui.cancel_button.text()))
        self.assertEqual(SSL_CONNECT_BUTTON,
                compat.text_type(dialog.ui.connect_button.text()))
        self.assertEqual(SSL_HELP_BUTTON,
                compat.text_type(dialog.ui.help_button.text()))

    def test_set_expander(self):
        """Test that the expander is correctly set."""
        self.assertEqual(SSL_CERT_DETAILS,
            compat.text_type(self.dialog.expander.text()))
        self.assertNotEqual(None, self.dialog.expander.content)
        self.assertEqual(2, self.dialog.ui.expander_layout.indexOf(
                                                        self.dialog.expander))

    def test_set_icon(self):
        """Test that the icon is correctly set."""
        self.assertNotEqual(None, self.dialog.ui.logo_label.pixmap())
        icon = self.dialog.style().standardIcon(QStyle.SP_MessageBoxWarning)
        self.assertEqual(icon.pixmap(48, 48).toImage(),
                         self.dialog.ui.logo_label.pixmap().toImage())
        self.assertEqual('', self.dialog.ui.logo_label.text())


class FakeArgumentParser(object):
    """Fake args parse."""

    def __init__(self):
        """Create an instance."""
        self.called = []

    def __call__(self, description=''):
        """Instance callable."""
        self.called.append(('__init__', description))
        return self

    # pylint: disable=W0622
    def add_argument(self, name, required=False, help=''):
        """Add an argument."""
        self.called.append(('add_argument', name, required, help))
    # pylint: enable=W0622

    def parse_args(self):
        """Parse the args."""
        self.called.append(('parse_args',))
        return self


class ParseArgTestCase(TestCase):
    """Test the parse of the args."""

    def test_parse_args(self):
        """Set tests."""
        argparse = FakeArgumentParser()
        self.patch(ssl_dialog.argparse, 'ArgumentParser', argparse)
        args = ssl_dialog.parse_args()
        self.assertEqual(argparse, args)
        self.assertIn(('__init__', SSL_DESCRIPTION), argparse.called)
        self.assertIn(('add_argument', '--domain', True, SSL_DOMAIN_HELP),
                                                         argparse.called)
        self.assertIn(('add_argument', '--details', True, SSL_DETAILS_HELP),
                                                          argparse.called)
        self.assertIn(('add_argument', '--appname', True, SSL_APPNAME_HELP),
                                                          argparse.called)
        self.assertIn(('parse_args',), argparse.called)
