# -*- 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.
"""Tests for the main module."""

from copy import copy
import os
import sys

from PyQt4 import QtCore
from twisted.internet import defer
from twisted.trial.unittest import TestCase

from ubuntu_kylin_sso.qt import main
from ubuntu_kylin_sso.utils import compat
from ubuntu_kylin_sso import tests


# pylint: disable=C0103
class FakeUi(object):

    """A fake UI."""

    def size(self):
        """Fake size."""
        return QtCore.QSize(100, 100)

    def setGeometry(self, *args):
        """Fake setGeometry."""

    show = setGeometry
    raise_ = lambda self: None


class FakeDesktop(object):

    """Fake Desktop Widget."""

    def availableGeometry(self):
        """Fake availableGeometry for desktop.-"""
        return QtCore.QRect(100, 100, 100, 100)


class FakeApplication(object):

    """Fake QApplication."""

    called = {}
    __instance = None

    def __init__(self, args):
        self.called['args'] = args
        FakeApplication.__instance = self

    def setStyleSheet(self, style):
        """Fake setStyleSheet."""
        self.called["setStyleSheet"] = style

    def styleSheet(self):
        """Fake get style sheet."""
        return self.called.get("setStyleSheet", '')

    def desktop(self):
        """Fake Desktop."""
        return FakeDesktop()

    def exec_(self):
        """Fake exec_."""

    def exit(self):
        """Fake exit."""

    def setWindowIcon(self, icon_path):
        """Fake setWindowIcon."""

    @classmethod
    def instance(cls):
        """Fake instance."""
        return FakeApplication.__instance
# pylint: enable=C0103


class BasicTestCase(TestCase):
    """Test case with a helper tracker."""

    @defer.inlineCallbacks
    def setUp(self):
        yield super(BasicTestCase, self).setUp()
        self.called = []
        self._close_callback = None
        self._app = None

        def called_ui(method, *args, **kw):
            """record ui call."""
            if 'close_callback' in kw:
                self._close_callback = kw.pop('close_callback')
            self.called.append((method, args, kw))
            return FakeUi()

        self.patch(main, 'UbuntuSSOClientGUI',
            lambda *arg, **kw: called_ui('GUI', *arg, **kw))
        self.patch(main.source, 'main',
            lambda *arg, **kw: called_ui('main', *arg, **kw))
        self.patch(main.source, 'main_start',
            lambda *arg, **kw: called_ui('main_start', *arg, **kw))
        self.patch(main.QtGui, 'QApplication', FakeApplication)
        FakeApplication.called['args'] = []

    def test_main(self):
        """Calling main.main() a UI instance is created."""
        kwargs = dict(app_name='APP_NAME', foo='foo', bar='bar',
            baz='yadda', yadda=0)
        main.main(**kwargs)

        expected = [('main', (FakeApplication.instance(),), {}),
            ('GUI', (), kwargs),
            ('main_start', (FakeApplication.instance(),), {})]
        self.assertEqual(self.called, expected)

    def test_testability(self):
        """Calling main.main() with TESTABILITY=1, adds -testability."""
        environ = copy(os.environ)
        environ['TESTABILITY'] = '1'
        self.patch(os, 'environ', environ)
        self.patch(sys, 'argv', [])
        kwargs = dict(app_name='APP_NAME', foo='foo', bar='bar',
            baz='yadda', yadda=0)
        main.main(**kwargs)
        self.assertIn('-testability', FakeApplication.called['args'])

    def test_no_testability(self):
        """Calling main.main() with TESTABILITY unset."""
        environ = copy(os.environ)
        if 'TESTABILITY' in environ:
            environ['TESTABILITY'] = ''
        self.patch(os, 'environ', environ)
        self.patch(sys, 'argv', [])
        kwargs = dict(app_name='APP_NAME', foo='foo', bar='bar',
            baz='yadda', yadda=0)
        main.main(**kwargs)
        self.assertNotIn('-testability', FakeApplication.called['args'])

    def test_check_close_callback(self):
        """Check that the close callback is main_quit."""

        def called_quit(app):
            """Record the call to quit."""
            self._app = app

        self.patch(main.source, 'main_quit', called_quit)

        kwargs = dict(app_name='APP_NAME', foo='foo', bar='bar',
            baz='yadda', yadda=0)
        main.main(**kwargs)

        expected = [('main', (FakeApplication.instance(),), {}),
            ('GUI', (), kwargs),
            ('main_start', (FakeApplication.instance(),), {})]
        self._close_callback()
        self.assertEqual(self.called, expected)
        self.assertEqual(self._app, FakeApplication.instance())

    def test_main_args(self):
        """Calling main.main() a UI instance is created."""
        arg_list = (tests.APP_NAME, tests.NAME, tests.PASSWORD,
            tests.EMAIL_TOKEN)
        kwargs = dict(app_name=arg_list[0].encode('utf-8'),
            foo=arg_list[1].encode('utf-8'),
            bar=arg_list[2].encode('utf-8'),
            baz=arg_list[3].encode('utf-8'))
        main.main(**kwargs)

        args_unicode = dict(app_name=arg_list[0], foo=arg_list[1],
            bar=arg_list[2], baz=arg_list[3])
        expected = [('main', (FakeApplication.instance(),), {}),
            ('GUI', (), args_unicode),
            ('main_start', (FakeApplication.instance(),), {})]
        self.assertEqual(self.called, expected)

    def test_styles_load(self):
        """Test that all stylesheets load."""
        kwargs = dict(foo='foo', bar='bar', baz='yadda', yadda=0)
        main.main(**kwargs)
        data = []
        for qss_name in (main.PLATFORM_QSS, ":/stylesheet.qss"):
            qss = QtCore.QResource(qss_name)
            data.append(compat.text_type(qss.data()))
        self.assertEqual(
            compat.text_type(main.QtGui.QApplication.instance().styleSheet()),
            '\n'.join(data))
