#
# Copyright (c) 2013-2015 Dorian Pula <dorian.pula@amber-penguin-software.ca>
#
# Rookeries 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.
#
# Rookeries 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 Rookeries.  If not, see <http://www.gnu.org/licenses/>.
#
# Please share and enjoy!
#

import mock
import pytest

from rookeries.__future__ import file_importer as data_stores
from rookeries.journal import views


@mock.patch('os.path.exists', autospec=True)
@mock.patch('io.open', autospec=True)
def test_file_system_data_store_reads_content_when_path_relative_to_app_and_root_folder(
        mock_io_open, mock_path_exists):

    test_data = '**Test_Content**\nHello world'
    expected_domain_path = 'test_app_path/rookeries/test.md'

    setup_mock_io_open_with_data(mock_io_open, test_data)
    mock_path_exists.return_value = True

    test_data_store = data_stores.FileSystemDataStore('test_app_path', 'rookeries')
    actual_domain = test_data_store['test']
    mock_path_exists.assert_called_with(expected_domain_path)
    assert actual_domain.page == 'test'
    assert actual_domain.page_content == test_data


@mock.patch('os.path.exists', autospec=True)
@mock.patch('io.open', autospec=True)
def test_file_system_data_store_reads_content_when_path_relative_to_app_inside_pages_folder_found(
        mock_io_open, mock_path_exists):

    test_data = '**Test_Content**\nHello world'
    expected_domain_path = 'test_app_path/pages/test.md'

    setup_mock_io_open_with_data(mock_io_open, test_data)
    mock_path_exists.return_value = True

    test_data_store = data_stores.FileSystemDataStore('test_app_path', views.ROOT_PAGE_PATH)
    actual_domain = test_data_store['test']
    mock_path_exists.assert_called_with(expected_domain_path)
    assert actual_domain.page == 'test'
    assert actual_domain.page_content == test_data


@mock.patch('os.path.exists', autospec=True)
@mock.patch('io.open', autospec=True)
def test_file_system_data_store_reads_content_when_file_extension_specified(
        mock_io_open, mock_path_exists):
    test_data = '**Test_Content**\nHello world'
    expected_domain_path = 'test_app_path/pages/test.rst'

    setup_mock_io_open_with_data(mock_io_open, test_data)
    mock_path_exists.return_value = True

    test_data_store = data_stores.FileSystemDataStore('test_app_path', views.ROOT_PAGE_PATH, extension='rst')
    actual_domain = test_data_store['test']
    mock_path_exists.assert_called_with(expected_domain_path)
    assert actual_domain.page == 'test'
    assert actual_domain.page_content == test_data


@mock.patch('os.path.exists', autospec=True)
def test_file_system_data_store_raises_key_error_when_the_path_not_found(mock_path_exists):

    expected_domain_path = 'test_app_path/rookeries/non_existent_file.md'
    mock_path_exists.return_value = False

    test_data_store = data_stores.FileSystemDataStore('test_app_path', 'rookeries')

    with pytest.raises(KeyError) as expected_error:
        test_data_store['non_existent_file']

    assert 'non_existent_file' in expected_error.exconly()
    mock_path_exists.assert_called_with(expected_domain_path)


def setup_mock_io_open_with_data(mock_io_open, test_data):
    """Setup mocked out io.open to work as a context manager. Refer to
    http://www.voidspace.org.uk/python/weblog/arch_d7_2010_10_02.shtml#e1188 for details.
    :param mock_io_open: The mock to setup.
    :param test_data: The test data to setup.
    """
    mock_file_handle = mock.MagicMock(spec=file)
    mock_file_handle.read.return_value = test_data
    mock_io_open.return_value.__enter__.return_value = mock_file_handle
