import unittest.mock
import pytest
from szurubooru import search
from szurubooru.func import cache


def test_retrieving_from_cache():
    config = unittest.mock.MagicMock()
    with unittest.mock.patch('szurubooru.func.cache.has'), \
            unittest.mock.patch('szurubooru.func.cache.get'):
        cache.has.side_effect = lambda *args: True
        executor = search.Executor(config)
        executor.execute('test:whatever', 1, 10)
        assert cache.get.called


def test_putting_equivalent_queries_into_cache():
    config = search.configs.PostSearchConfig()
    with unittest.mock.patch('szurubooru.func.cache.has'), \
            unittest.mock.patch('szurubooru.func.cache.put'):
        hashes = []

        def appender(key, _value):
            hashes.append(key)

        cache.has.side_effect = lambda *args: False
        cache.put.side_effect = appender
        executor = search.Executor(config)
        executor.execute('safety:safe test', 1, 10)
        executor.execute('safety:safe  test', 1, 10)
        executor.execute('safety:safe test ', 1, 10)
        executor.execute(' safety:safe test', 1, 10)
        executor.execute(' SAFETY:safe test', 1, 10)
        executor.execute('test safety:safe', 1, 10)
        assert len(hashes) == 6
        assert len(set(hashes)) == 1


def test_putting_non_equivalent_queries_into_cache():
    config = search.configs.PostSearchConfig()
    with unittest.mock.patch('szurubooru.func.cache.has'), \
            unittest.mock.patch('szurubooru.func.cache.put'):
        hashes = []

        def appender(key, _value):
            hashes.append(key)

        cache.has.side_effect = lambda *args: False
        cache.put.side_effect = appender
        executor = search.Executor(config)
        args = [
            ('', 1, 10),
            ('creation-time:2016', 1, 10),
            ('creation-time:2015', 1, 10),
            ('creation-time:2016-01', 1, 10),
            ('creation-time:2016-02', 1, 10),
            ('creation-time:2016-01-01', 1, 10),
            ('creation-time:2016-01-02', 1, 10),
            ('tag-count:1,3', 1, 10),
            ('tag-count:1,2', 1, 10),
            ('tag-count:1', 1, 10),
            ('tag-count:1..3', 1, 10),
            ('tag-count:1..4', 1, 10),
            ('tag-count:2..3', 1, 10),
            ('tag-count:1..', 1, 10),
            ('tag-count:2..', 1, 10),
            ('tag-count:..3', 1, 10),
            ('tag-count:..4', 1, 10),
            ('-tag-count:1..3', 1, 10),
            ('-tag-count:1..4', 1, 10),
            ('-tag-count:2..3', 1, 10),
            ('-tag-count:1..', 1, 10),
            ('-tag-count:2..', 1, 10),
            ('-tag-count:..3', 1, 10),
            ('-tag-count:..4', 1, 10),
            ('safety:safe', 1, 10),
            ('safety:safe', 1, 20),
            ('safety:safe', 2, 10),
            ('safety:sketchy', 1, 10),
            ('safety:safe test', 1, 10),
            ('-safety:safe', 1, 10),
            ('-safety:safe', 1, 20),
            ('-safety:safe', 2, 10),
            ('-safety:sketchy', 1, 10),
            ('-safety:safe test', 1, 10),
            ('safety:safe -test', 1, 10),
            ('-test', 1, 10),
        ]
        for arg in args:
            executor.execute(*arg)
        assert len(hashes) == len(args)
        assert len(set(hashes)) == len(args)


@pytest.mark.parametrize('input', [
    'special:fav',
    'special:liked',
    'special:disliked',
    '-special:fav',
    '-special:liked',
    '-special:disliked',
])
def test_putting_auth_dependent_queries_into_cache(user_factory, input):
    config = search.configs.PostSearchConfig()
    with unittest.mock.patch('szurubooru.func.cache.has'), \
            unittest.mock.patch('szurubooru.func.cache.put'):
        hashes = []

        def appender(key, _value):
            hashes.append(key)

        cache.has.side_effect = lambda *args: False
        cache.put.side_effect = appender
        executor = search.Executor(config)

        executor.config.user = user_factory()
        executor.execute(input, 1, 1)
        assert len(set(hashes)) == 1

        executor.config.user = user_factory()
        executor.execute(input, 1, 1)
        assert len(set(hashes)) == 2

        executor.execute(input, 1, 1)
        assert len(set(hashes)) == 2
