# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*-
# Copyright 2012-2014 Canonical, Ltd.
# Author: Thomi Richards
#
# 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.

from testscenarios import TestWithScenarios
from testtools import TestCase
from testtools.matchers import Contains, Equals, raises

try:
    from unittest.mock import patch
except ImportError:
    from mock import patch

from windowmocker.plugins import (
    base,
    get_plugin_by_name,
    register_plugin,
    register_named_plugin,
    unregister_plugin_by_name
    )

class DummyAppPlugin(base.ApplicationTypePluginBase):

    Name = "Dummy"

    def create_application(self):
        pass

    def create_window(self, window_spec):
        pass


class PluginRegistryTests(TestCase):

    def register_plugin(self, plugin_class):
        register_plugin(plugin_class)
        self.addCleanup(unregister_plugin_by_name, plugin_class.Name)

    def register_named_plugin(self, plugin_name, plugin_class):
        register_named_plugin(plugin_name, plugin_class)
        self.addCleanup(unregister_plugin_by_name, plugin_name)

    def test_returns_None_on_unknown_plugin_name(self):
        plugin = get_plugin_by_name("unknown")
        self.assertThat(plugin, Equals(None))

    def test_can_register_plugin(self):
        self.register_plugin(DummyAppPlugin)
        plugin = get_plugin_by_name("Dummy")

        self.assertThat(plugin, Equals(DummyAppPlugin))

    def test_can_register_named_plugin(self):
        self.register_named_plugin("Dummy", DummyAppPlugin)
        plugin = get_plugin_by_name("Dummy")

        self.assertThat(plugin, Equals(DummyAppPlugin))

    def test_can_create_empty_plugin(self):
        # must not raise NotImplementedError:
        DummyAppPlugin({})

    def test_base_raises_NotImplemented(self):
        fn = lambda: base.ApplicationTypePluginBase({"Windows": {}})

        self.assertThat(fn, raises(NotImplementedError))

    @patch.object(DummyAppPlugin, "create_application")
    def test_calls_create_application(self, mock_create_app):
        DummyAppPlugin({})

        mock_create_app.assert_called_once_with()

    @patch.object(DummyAppPlugin, "create_window")
    def test_window_created_by_default(self, mock_create_window):
        DummyAppPlugin({})

        self.assertThat(mock_create_window.call_count, Equals(1))
        self.assertThat(mock_create_window.call_args[0][0],
                        Equals(DummyAppPlugin._window_default))

    @patch.object(DummyAppPlugin, "create_window")
    def test_calls_create_window_with_defaults_added(self, mock_create_window):
        DummyAppPlugin({})

        self.assertThat(mock_create_window.call_count, Equals(1))
        self.assertThat(mock_create_window.call_args[0][0],
                        Equals(DummyAppPlugin._window_default))

    @patch.object(DummyAppPlugin, "create_window")
    def test_passes_params_to_create_window(self, mock_create_window):
        DummyAppPlugin({"Title": "Hello World"})

        self.assertThat(mock_create_window.call_count, Equals(1))
        passed_spec = mock_create_window.call_args[0][0]

        self.assertThat(passed_spec, Contains("Title"))
        self.assertThat(passed_spec["Title"], Equals("Hello World"))

    @patch.object(DummyAppPlugin, "create_window")
    def test_can_create_many_windows(self, mock_create_window):
        DummyAppPlugin([
                {"Title": "Window 1"},
                {"Title": "Window 2"},
                ])

        self.assertThat(mock_create_window.call_count, Equals(2))
        self.assertThat(mock_create_window.call_args_list[0][0][0]["Title"],
                        Equals("Window 1"))
        self.assertThat(mock_create_window.call_args_list[1][0][0]["Title"],
                        Equals("Window 2"))


class PluginWindowDefaultParameterTests(TestWithScenarios, TestCase):

    """Tests for various default values for required parameters."""

    scenarios = [
        ("Window Title",
            {'name': 'Title', 'expected': 'Default Window Title'}),
        ("Maximised", {'name': 'Maximized', 'expected': False}),
        ("Minimized", {'name': 'Minimized', 'expected': False}),
        ("MinimizeImmediatelyAfterShow",
            {'name': 'MinimizeImmediatelyAfterShow', 'expected': False}),
        ("Menus", {'name': 'Menu', 'expected': []}),
        ]

    @patch.object(DummyAppPlugin, "create_window")
    def test_default_parameter(self, mock_create_window):
        DummyAppPlugin({"Windows": {}})
        window_spec = mock_create_window.call_args[0][0]

        self.assertThat(window_spec, Contains(self.name))
        self.assertThat(window_spec[self.name], Equals(self.expected))
