# Copyright (C) 2019, 2020 The Meme Factory, Inc.  http://www.karlpinc.com/

# This file is part of PGWUI_Copy.
#
# This program is free software: you can redistribute it and/or
# modify it under the terms of the GNU Affero General Public License
# as published by the Free Software Foundation, either version 3 of
# the License, or (at your option) any later version.
#
# 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
# Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public
# License along with this program.  If not, see
# <http://www.gnu.org/licenses/>.
#

# Karl O. Pinc <kop@karlpinc.com>

import pytest
import pyramid.testing

import pgwui_copy.pgwui_copy as pgwui_copy

from pgwui_develop import testing

# Activiate the PGWUI pytest plugin
pytest_plugins = ("pgwui",)


# Module packaging test

def test_pgwui_copy_is_pgwui_component(pgwui_component_entry_point):
    '''Ensure that pgwui_copy is a pgwui.component entry point
    '''
    assert pgwui_component_entry_point('pgwui_copy') is True


# build_sensitive_dbs()

@pytest.mark.parametrize(
    ('copy_settings', 'expected'), [
        ({}, ['default_db_value']),
        ({'sensitive_dbs': 'single db'}, ['single db']),
        ({'sensitive_dbs': ['list of', 'dbs']}, ['list of', 'dbs'])])
@pytest.mark.unittest
def test_build_sensitive_dbs(copy_settings, expected):
    '''The expected result is returned
    '''
    result = pgwui_copy.build_sensitive_dbs({'default_db': 'default_db_value'},
                                            copy_settings)
    assert result == expected


mock_build_sensitive_dbs = testing.make_mock_fixture(
    pgwui_copy, 'build_sensitive_dbs')


# establish_settings()

@pytest.mark.unittest
def test_establish_settings_default(mock_build_sensitive_dbs):
    '''The settings get the module's default value when no settings exist
    '''
    mock_build_sensitive_dbs.return_value = []
    with pyramid.testing.testConfig() as config:

        pgwui_copy.establish_settings(config)

        new_settings = config.get_settings()
    assert (new_settings['pgwui']['pgwui_copy']['menu_label']
            == pgwui_copy.DEFAULT_COPY_MENU_LABEL)


@pytest.mark.unittest
def test_establish_settings_no_default(mock_build_sensitive_dbs):
    '''The settings keep their value when they exist
    '''
    test_menu_label = 'test label'

    mock_build_sensitive_dbs.return_value = []
    with pyramid.testing.testConfig() as config:
        sample_settings = config.get_settings()

        sample_settings['pgwui'] = dict()
        sample_settings['pgwui']['pgwui_copy'] = dict()
        sample_settings['pgwui']['pgwui_copy']['menu_label'] = test_menu_label

        pgwui_copy.establish_settings(config)

        new_settings = config.get_settings()
    assert new_settings['pgwui']['pgwui_copy']['menu_label'] == test_menu_label


mock_establish_settings = testing.make_mock_fixture(
    pgwui_copy, 'establish_settings')


# includeme()

mock_add_route = testing.instance_method_mock_fixture('add_route')
mock_scan = testing.instance_method_mock_fixture('scan')


@pytest.mark.unittest
def test_includeme(mock_establish_settings, mock_add_route, mock_scan):
    '''establish_settings, add_route, and scan are all called
    '''
    with pyramid.testing.testConfig() as config:
        mocked_add_route = mock_add_route(config)
        mocked_scan = mock_scan(config)

        pgwui_copy.includeme(config)

    mock_establish_settings.assert_called_once()
    mocked_add_route.assert_called_once()
    mocked_scan.assert_called_once()


# Integration tests

@pytest.mark.integrationtest
def test_integration(mock_add_route, mock_scan):
    '''The mocks are called
    '''
    with pyramid.testing.testConfig() as config:
        mocked_add_route = mock_add_route(config)
        mocked_scan = mock_scan(config)

        pgwui_copy.includeme(config)

    mocked_add_route.assert_called_once()
    mocked_scan.assert_called_once()
