# -*- coding: utf-8 -*-
#
# Copyright 2011-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 Setup Account page Qt UI."""

from PyQt4 import QtGui, QtCore

from ubuntu_kylin_sso.utils import compat
from ubuntu_kylin_sso.tests import CAPTCHA_PATH

from ubuntu_kylin_sso.qt import common, setup_account_page as gui
from ubuntu_kylin_sso.qt.tests import PageBaseTestCase


class SetupAccountTestCase(PageBaseTestCase):
    """Test the SetupAccountPage code."""

    ui_class = gui.SetupAccountPage
    ui_signals = ('userRegistered', 'signIn')
    ui_backend_signals = ('CaptchaGenerated', 'CaptchaGenerationError',
                          'UserRegistered', 'UserRegistrationError')

    def test_password_receiver(self):
        """Check the initial state of SetupAccount."""
        self.assertEqual(self.ui.ui.password_edit.receivers(
            QtCore.SIGNAL('textEdited(QString)')), 2)

    def test_empty_name(self):
        """Status when the name field is empty.

        * Name Assistance label visible.
        * Correct error message in it.
        """
        self.ui.ui.name_edit.setText("")
        self.ui.name_assistance()
        self.assertTrue(self.ui.ui.name_assistance.isVisible())
        self.assert_error_correct(self.ui.ui.name_assistance, gui.EMPTY_NAME,
                                  max_width=self.ui.header.max_title_width)

    def test_hide_error_on_refresh_clicked(self):
        """Hide form errors when the user click to refresh the captcha."""
        self.ui.show_error('error')
        self.assert_error_correct(self.ui.form_errors_label, 'error',
            max_width=self.ui.header.max_title_width)

        self.ui.ui.refresh_label.linkActivated.emit('error')

        message = compat.text_type(self.ui.form_errors_label.text())
        self.assertEqual(message, ' ')

    def test_enable_setup_button_with_visible_check(self):
        """Test _enable_setup_button method with terms check visible."""
        self.patch(self.ui, "set_up_button", QtGui.QPushButton())

        self.ui.ui.name_edit.setText('name')
        email = 'email@example.com'
        self.ui.ui.email_edit.setText(email)
        self.ui.ui.confirm_email_edit.setText(email)
        password = 'T3st3rqwe'
        self.ui.ui.password_edit.setText(password)
        self.ui.ui.confirm_password_edit.setText(password)
        self.ui.ui.captcha_solution_edit.setText('captcha solution')
        self.ui.terms_checkbox.setChecked(True)

        self.ui.terms_checkbox.setVisible(True)
        self.ui.ui.captcha_solution_edit.textEdited.emit('')
        self.assertTrue(self.ui.set_up_button.isEnabled())

    def test_enable_setup_button_without_visible_check(self):
        """Test _enable_setup_button method with terms check not visible."""
        self.patch(self.ui, "set_up_button", QtGui.QPushButton())

        self.ui.ui.name_edit.setText('name')
        email = 'email@example.com'
        self.ui.ui.email_edit.setText(email)
        self.ui.ui.confirm_email_edit.setText(email)
        password = 'T3st3rqwe'
        self.ui.ui.password_edit.setText(password)
        self.ui.ui.confirm_password_edit.setText(password)
        self.ui.ui.captcha_solution_edit.setText('captcha solution')

        self.ui.terms_checkbox.setVisible(False)
        self.ui.ui.captcha_solution_edit.textEdited.emit('')
        self.assertTrue(self.ui.set_up_button.isEnabled())

    def test_password_default_assistance(self):
        """Status when the password line edit receive focus and shows popup.

        * Password assistance contains the right message.
        """
        self.ui.ui.password_edit.setText("")
        self.ui.ui.confirm_password_edit.setText("")
        common.password_default_assistance(self.ui.ui.password_assistance)
        self.ui.focus_changed(None, self.ui.ui.password_edit)
        self.assertIn(
            common.NORMAL % common.PASSWORD_LENGTH,
            compat.text_type(self.ui.ui.password_assistance.text()),
        )
        self.assertIn(
            common.NORMAL % common.PASSWORD_UPPER,
            compat.text_type(self.ui.ui.password_assistance.text()),
        )
        self.assertIn(
            common.NORMAL % common.PASSWORD_DIGIT,
            compat.text_type(self.ui.ui.password_assistance.text()),
        )

    def test_password_focus_gain(self):
        """Check functions execution when focus_changed() is executed."""
        self.ui.ui.password_assistance.setVisible(False)
        self.assertFalse(self.ui.ui.password_assistance.isVisible())
        self.patch(self.ui, 'name_assistance', self._set_called)
        self.ui.focus_changed(None, self.ui.ui.password_edit)
        self.assertTrue(self.ui.ui.password_assistance.isVisible())

    def test_name_focus_lost(self):
        """Check functions execution when focus_changed() is executed."""
        self.patch(self.ui, 'name_assistance', self._set_called)
        self.ui.focus_changed(self.ui.ui.name_edit, None)
        self.assertTrue(self._called)

    def test_email_focus_lost(self):
        """Check functions execution when focus_changed() is executed."""
        self.patch(self.ui, 'email_assistance', self._set_called)
        self.ui.focus_changed(self.ui.ui.email_edit, None)
        self.assertTrue(self._called)

    def test_confirm_email_focus_lost(self):
        """Check functions execution when focus_changed() is executed."""
        self.patch(self.ui, 'confirm_email_assistance', self._set_called)
        self.ui.focus_changed(self.ui.ui.confirm_email_edit, None)
        self.assertTrue(self._called)

    def test_confirm_password_focus_lost(self):
        """Check functions execution when focus_changed() is executed."""
        self.patch(common, 'password_check_match', self._set_called)
        self.ui.focus_changed(self.ui.ui.confirm_password_edit, None)
        self.assertTrue(self._called)

    def test_on_user_registered(self):
        """Test on_user_registered method."""
        self.patch(self.ui, "validate_form", lambda: True)
        self.patch(self.ui, "hide_error", self._set_called)

        email = 'email@example'
        password = 'password'
        name = 'name'
        captcha_id = 1
        captcha_solution = 'solution'
        self.ui.ui.email_edit.setText(email)
        self.ui.ui.password_edit.setText(password)
        self.ui.ui.name_edit.setText(name)
        self.ui.captcha_id = captcha_id
        self.ui.ui.captcha_solution_edit.setText(captcha_solution)

        self.ui.set_next_validation()

        self.assert_backend_called('register_user',
            self.app_name, email, password, name, captcha_id,
            captcha_solution)
        expected = ((), {})
        self.assertEqual(expected, self._called)

    def test_set_next_validation(self):
        """Test on_user_registered method."""
        email = 'email@example'
        self.ui.ui.email_edit.setText(email)
        self.assert_signal_emitted(self.ui.userRegistered, (email,),
            self.ui.on_user_registered, self.app_name, email)

    def test_captcha_image_is_requested_as_startup(self):
        """The captcha image is requested at startup."""
        # assert generate_captcha was called
        self.assert_backend_called('generate_captcha',
            self.app_name, self.ui.captcha_file)

    def test_set_translated_strings(self):
        """Test the translated string method."""
        expected = gui.REGISTER_TITLE.format(app_name=self.app_name)
        self.assert_title_correct(expected)
        self.assert_subtitle_correct(self.ui.help_text)

    def test_initialize_page(self):
        """Widgets are properly initialized."""
        self.ui.initializePage()

        # set up account button
        expected = [QtGui.QWizard.Stretch, QtGui.QWizard.CustomButton3]
        self.assertIn(('setButtonLayout', ((expected,), {})),
                       self.ui.wizard().called)
        self.assertEqual(gui.SET_UP_ACCOUNT_BUTTON,
                         self.ui.buttonText(QtGui.QWizard.CustomButton3))
        self.assertTrue(self.ui.wizard().button(QtGui.QWizard.CustomButton3) is
                        self.ui.set_up_button)
        self.assertFalse(self.ui.set_up_button.isEnabled())

        self.assertFalse(self.ui.captcha_received)

        # labels
        self.assertEqual(compat.text_type(self.ui.ui.name_label.text()),
            gui.NAME_ENTRY)
        self.assertEqual(compat.text_type(self.ui.ui.email_label.text()),
            gui.EMAIL)
        self.assertEqual(
                compat.text_type(self.ui.ui.confirm_email_label.text()),
                gui.RETYPE_EMAIL)
        self.assertEqual(compat.text_type(self.ui.ui.password_label.text()),
            gui.PASSWORD)
        self.assertEqual(
                compat.text_type(self.ui.ui.confirm_password_label.text()),
                gui.RETYPE_PASSWORD)
        expected = gui.LINK_STYLE.format(link_url='#',
            link_text=gui.SIGN_IN_LABEL)
        self.assertEqual(
                compat.text_type(self.ui.ui.sign_in_label.text()),
                expected)

        # connections
        self.assertEqual(self.ui.set_up_button.receivers(
            QtCore.SIGNAL("clicked(const bool)")), 1)

        # assistants
        self.assertFalse(self.ui.ui.name_assistance.isVisible())
        self.assertFalse(self.ui.ui.email_assistance.isVisible())
        self.assertFalse(self.ui.ui.confirm_email_assistance.isVisible())
        self.assertFalse(self.ui.ui.password_assistance.isVisible())
        self.assertTrue(self.ui.ui.refresh_label.isVisible())

    def test_connect_ui(self):
        """Test the connect ui method."""
        self.assertEqual(self.ui.ui.password_edit.receivers(
            QtCore.SIGNAL("textEdited(const QString&)")), 2)
        self.assertEqual(self.ui.ui.refresh_label.receivers(
            QtCore.SIGNAL("linkActivated(const QString&)")), 2)
        self.assertEqual(self.ui.ui.name_edit.receivers(
            QtCore.SIGNAL("textEdited(const QString&)")), 1)
        self.assertEqual(self.ui.ui.email_edit.receivers(
            QtCore.SIGNAL("textEdited(const QString&)")), 1)
        self.assertEqual(self.ui.ui.confirm_email_edit.receivers(
            QtCore.SIGNAL("textEdited(const QString&)")), 1)
        self.assertEqual(self.ui.ui.password_edit.receivers(
            QtCore.SIGNAL("textEdited(const QString&)")), 2)
        self.assertEqual(self.ui.ui.confirm_password_edit.receivers(
            QtCore.SIGNAL("textEdited(const QString&)")), 1)
        self.assertEqual(self.ui.ui.sign_in_label.receivers(
            QtCore.SIGNAL("linkActivated(const QString&)")), 1)

    def test_connect_ui_2(self):
        """Test more connections from connect_ui"""
        self.assertEqual(self.ui.ui.captcha_solution_edit.receivers(
            QtCore.SIGNAL("textEdited(const QString&)")), 1)
        self.assertEqual(self.ui.terms_checkbox.receivers(
            QtCore.SIGNAL("stateChanged(bool)")), 1)

    test_connect_ui_2.skip = "These oscilate 0/1 (LP:1046885)"

    def test_set_up_button_clicked(self):
        """Validation and overlay is shown when the setupbutton is clicked."""
        self.patch(self.ui, 'set_next_validation', self._set_called)
        self.ui.initializePage()
        self.ui.captcha_received = True

        self.ui.set_up_button.clicked.emit(False)
        self.assertEqual(self._called, ((False,), {}))

    def test_set_error_message(self):
        """Check the state of the label after calling: set_error_message."""
        self.ui.email_assistance()
        self.ui.set_error_message(self.ui.ui.email_assistance, "message")
        self.assertTrue(self.ui.ui.email_assistance.isVisible())
        self.assert_error_correct(self.ui.ui.email_assistance, "message",
                                  max_width=self.ui.header.max_title_width)

    def test_blank_name(self):
        """Status when the name field is blank (spaces).

        * Name Assistance label visible.
        * Correct error message in it.
        """
        self.ui.ui.name_edit.setText("  ")
        self.ui.name_assistance()
        self.assertTrue(self.ui.ui.name_assistance.isVisible())
        self.assert_error_correct(self.ui.ui.name_assistance, gui.EMPTY_NAME,
                                  max_width=self.ui.header.max_title_width)

    def test_valid_name(self):
        """Status when the name field is valid.

        * Name Assistance label invisible.
        """
        self.ui.ui.name_edit.setText("John Doe")
        self.ui.name_assistance()
        self.assertFalse(self.ui.ui.name_assistance.isVisible())

    def test_invalid_email(self):
        """Status when the email field has no @.

        * Email Assistance label visible.
        * Correct error message in it.
        """
        self.ui.ui.email_edit.setText("foobar")
        self.ui.email_assistance()
        self.assertTrue(self.ui.ui.email_assistance.isVisible())
        self.assert_error_correct(self.ui.ui.email_assistance,
                                  gui.INVALID_EMAIL,
                                  max_width=self.ui.header.max_title_width)

    def test_valid_email(self):
        """Status when the email field has a @.

        * Email Assistance label invisible.
        """
        self.ui.ui.email_edit.setText("foo@bar")
        self.ui.email_assistance()
        self.assertFalse(self.ui.ui.email_assistance.isVisible())

    def test_matching_emails(self):
        """Status when the email fields match.

        * Email Assistance label invisible.
        """
        self.ui.ui.email_edit.setText("foo@bar")
        self.ui.ui.confirm_email_edit.setText("foo@bar")
        self.ui.confirm_email_assistance()
        self.assertFalse(self.ui.ui.confirm_email_assistance.isVisible())

    def test_not_matching_emails(self):
        """Status when the email fields don't match.

        * Email Assistance label visible.
        * Correct error message.
        """
        self.ui.ui.email_edit.setText("foo@bar")
        self.ui.ui.confirm_email_edit.setText("foo@baz")
        self.ui.confirm_email_assistance()
        self.assertTrue(self.ui.ui.confirm_email_assistance.isVisible())
        self.assert_error_correct(self.ui.ui.confirm_email_assistance,
                                  gui.EMAIL_MATCH,
                                  max_width=self.ui.header.max_title_width)

    def test_focus_changed_password_visibility(self):
        """Check visibility changes when focus_changed() is executed."""
        self.ui.focus_changed(None, self.ui.ui.password_edit)
        self.assertTrue(self.ui.ui.password_assistance.isVisible())

    def test_hide_event(self):
        """Check that hide_event works when set_up_button is none."""
        self.assertEqual(self.ui.set_up_button, None)
        self.ui.hideEvent(QtGui.QHideEvent())

    def test_show_event(self):
        """Check that show_event works when set_up_button is none."""
        self.assertEqual(self.ui.set_up_button, None)
        self.ui.show()
        self.addCleanup(self.ui.hide)

    def test_on_captcha_generated(self):
        """Check that the captcha image is handled correctly."""

        self.ui.captcha_file = CAPTCHA_PATH
        self.ui.on_captcha_generated(u"fake app name",
                                     "fake id")
        pixmap_empty = self.ui.captcha_image.size().isEmpty()
        self.assertEqual(pixmap_empty, False)

    def test_on_captcha_refreshing_visible(self):
        """Check the state of the overlay on captcha refreshing."""
        self.ui.hide_overlay()

        self.assertEqual(self._overlay_show_counter, 0)
        self.assertTrue(self.ui.isEnabled())

        self.ui.on_captcha_refreshing()

        self.assertFalse(self.ui.isEnabled())
        self.assertEqual(self._overlay_show_counter, 1)

    def test_on_captcha_refreshing_not_visible(self):
        """Check the state of the overlay on captcha refreshing."""
        self.ui.hide_overlay()

        self.assertEqual(self._overlay_show_counter, 0)
        self.assertTrue(self.ui.isEnabled())

        self.ui.hide()
        self.ui.on_captcha_refreshing()

        self.assertEqual(self._overlay_show_counter, 0)
        self.assertTrue(self.ui.isEnabled())

    def test_on_captcha_refresh_complete(self):
        """Check the state of the overlay on captcha refreshing complete."""
        self.assertEqual(self._overlay_hide_counter, 0)

        self.ui.on_captcha_refresh_complete()

        self.assertEqual(self._overlay_hide_counter, 1)

    def test_hide_error_on_refresh_captcha(self):
        """Test that the errors are hidden on refresh captcha."""
        self.ui.show_error('error-message')
        self.ui.ui.refresh_label.linkActivated.emit('link')
        self.assertEqual(self.ui.form_errors_label.text(), ' ')
