from __future__ import unicode_literals

from django.conf import settings
from django.db.models import Q
from django.test import TestCase
from console_base.utils import QTestMixin, get_query_params


# -----------------------------------------------------------------------
class TestQueryParams(TestCase, QTestMixin):
    """
    Test query_param dicts in format supporting django-filters
    Convert those query_param dicts to normal Django Q objects
    to apply the same queryset via Django Models
    """

    @classmethod
    def tearDownClass(cls):
        pass

    def test_query_params_csv(self):
        data = {'levels': 'A,B'}

        self.assertQEqual(
            get_query_params(data),
            Q(levels__in=['A', 'B']),
        )

    def test_bools_ints(self):
        data = {
            'app__isnull': True,
            'level': 1,
        }

        self.assertQEqual(
            get_query_params(data),
            Q(app__isnull=True, level=1),
        )

    def test_negated_values(self):
        data = {f'levels{settings.DRF_EXCLUDE_SUFFIX}': 'A'}

        self.assertQEqual(
            get_query_params(data),
            ~Q(('levels', 'A')),
        )

    def test_multiple_values(self):
        data = {
            f'levels{settings.DRF_EXCLUDE_SUFFIX}': 'A',
            'app__isnull': True,
        }

        self.assertQEqual(
            get_query_params(data),
            ~Q(('levels', 'A')) & Q(app__isnull=True),
        )


# -----------------------------------------------------------------------
class TestHelpers(TestCase, QTestMixin):
    """
    Taken from https://gist.github.com/jamescooke/b9bd5afba3a7253d53bd
    """

    # Matches

    def test_eq_self(self):
        """
        assertQEqual is reflexive, matches self
        """
        q_a = Q(location='London')

        self.assertQEqual(q_a, q_a)

    def test_eq(self):
        """
        assertQEqual matches logic
        """
        q_a = Q(location='北京市')
        q_b = Q(location='北京市')

        self.assertQEqual(q_a, q_b)

    def test_eq_multi_and(self):
        """
        assertQEqual matches multi Qs
        """
        q_a = Q(direction='north') & Q(speed=12)
        q_b = Q(direction='north') & Q(speed=12)

        self.assertQEqual(q_a, q_b)

    def test_eq_multi_or(self):
        """
        assertQEqual matches multi Qs
        """
        q_a = Q(direction='north') | Q(speed=12)
        q_b = Q(direction='north') | Q(speed=12)

        self.assertQEqual(q_a, q_b)

    # Non-matches

    def test_neq_simple(self):
        """
        assertQEqual spots that Q filters do not match
        """
        q_a = Q(location='北京市')
        q_b = Q(location='北京')

        with self.assertRaises(AssertionError):
            self.assertQEqual(q_a, q_b)

    def test_neq_multi_and(self):
        """
        assertQEqual matches multi Qs
        """
        q_a = Q(direction='north') & Q(speed=13)
        q_b = Q(direction='north') & Q(speed=12)

        with self.assertRaises(AssertionError):
            self.assertQEqual(q_a, q_b)

    def test_neq_multi_not_commutative(self):
        """
        assertQEqual does not match commutative: A & B != B & A
        """
        q_a = Q(speed=12) & Q(direction='north')
        q_b = Q(direction='north') & Q(speed=12)

        with self.assertRaises(AssertionError):
            self.assertQEqual(q_a, q_b)

    def test_neq_type_a(self):
        """
        assertQEqual raises if either q is not of type Q, left side
        """
        q_a = "(AND: ('location', u'New York'))"
        q_b = Q(location='New York')

        with self.assertRaises(AssertionError):
            self.assertQEqual(q_a, q_b)

    def test_neq_type_b(self):
        """
        assertQEqual raises if either q is not of type Q, right side
        """
        q_a = Q(location='New York')
        q_b = "(AND: ('location', u'New York'))"

        with self.assertRaises(AssertionError):
            self.assertQEqual(q_a, q_b)
