"""This module holds the test cases for the api-related decorators"""

from mock import patch

from django.core.cache import cache

from rest_framework import viewsets
from rest_framework.test import APIRequestFactory, APITestCase

from ..decorators import conditional_cache_response

from .api_testapp.factories import SyncableModelFactory
from .api_testapp.models import SyncableModel
from .api_testapp.serializers import SyncableModelSerializer


class ConditionalCacheResponseDecoratorTestCase(APITestCase):
    """Test case for the ``conditional_cache_response`` decorator"""

    def setUp(self):
        """Clear the cache before each test"""

        super().setUp()

        cache.clear()

    class ConditionallyCachedModelViewSet(viewsets.ModelViewSet):
        """A ViewSet that should maybe be cached"""

        queryset = SyncableModel.objects.non_deleted()
        serializer_class = SyncableModelSerializer

        def should_be_cached(self):
            """This view should NOT be cached"""

            return False

        @conditional_cache_response()
        def list(self, request, *args, **kwargs):
            """Override the list method to apply the cache decorator

            For the parameters, see ``ModelViewSet``

            """

            return super().list(request, *args, **kwargs)

    @classmethod
    def setUpTestData(cls):
        """Create a request factory and instances to test."""

        super().setUpTestData()

        cls.factory = APIRequestFactory()
        cls.syncable_instance = SyncableModelFactory()

    def test_view_should_not_be_cached_if_condition_is_not_met(self):
        """Test that the view response should not be cached if the condition is not met"""

        request = self.factory.get('/users/')
        view = self.ConditionallyCachedModelViewSet.as_view({'get': 'list'})

        # One BDD request the first time
        with self.assertNumQueries(1):
            response = view(request)

        self.assertEqual(response.status_code, 200)

        # One BDD request the second time (the view was not cached)
        with self.assertNumQueries(1):
            response = view(request)

        self.assertEqual(response.status_code, 200)

    def test_view_should_be_cached_if_condition_is_met(self):
        """Test that the view response should be cached if the condition is met"""

        request = self.factory.get('/users/')

        view = self.ConditionallyCachedModelViewSet.as_view({'get': 'list'})

        with patch.object(self.ConditionallyCachedModelViewSet,
                          'should_be_cached',
                          return_value=True):

            # One BDD request the first time
            with self.assertNumQueries(1):
                response = view(request)

            self.assertEqual(response.status_code, 200)

            # 0 BDD request the second time (the view was cached)
            with self.assertNumQueries(0):
                response = view(request)

            self.assertEqual(response.status_code, 200)
