# ElasticQuery
# File: tests/test_dsl.py
# Desc: tests for ElasticQuery DSL objects (Filter, Query, Aggregate)

from os import path
from unittest import TestCase

from jsontest import JsonTest

from elasticquery import Query, Aggregate, Suggester
from elasticquery.exceptions import (
    NoQueryError, NoAggregateError, NoSuggesterError,
    MissingArgError
)
from .util import assert_equal

CLASS_NAMES = {
    '_query': Query
}


def _test_query(self, query, test_name, test_data):
    method = getattr(query, test_name)

    def parse_arg(arg):
        if isinstance(arg, list):
            return [parse_arg(a) for a in arg]
        else:
            return (
                CLASS_NAMES[arg](arg, {})
                if (isinstance(arg, basestring) and arg.startswith('_'))
                else arg
            )

    args = test_data.get('args', [])
    args = parse_arg(args)

    kwargs = test_data.get('kwargs', {})
    kwargs = {
        k: parse_arg(v) if isinstance(v, list) else parse_arg(v)
        for k, v in kwargs.iteritems()
    }

    output = method(*args, **kwargs).dict()
    assert_equal(self, output, test_data['output'])


class TestQueries(TestCase):
    __metaclass__ = JsonTest

    jsontest_files = path.join('tests', 'queries')
    jsontest_function = lambda self, test_name, test_data: (
        _test_query(self, Query, test_name, test_data)
    )


class TestAggregates(TestCase):
    __metaclass__ = JsonTest

    jsontest_files = path.join('tests', 'aggregates')
    jsontest_function = lambda self, test_name, test_data: (
        _test_query(self, Aggregate, test_name, test_data)
    )


class TestSuggesters(TestCase):
    __metaclass__ = JsonTest

    jsontest_files = path.join('tests', 'suggesters')
    jsontest_function = lambda self, test_name, test_data: (
        _test_query(self, Suggester, test_name, test_data)
    )


class TestFails(TestCase):
    def test_no_query(self):
        with self.assertRaises(NoQueryError):
            Query.doesnotexist()

    def test_no_aggregate(self):
        with self.assertRaises(NoAggregateError):
            Aggregate.doesnotexist()

    def test_no_suggester(self):
        with self.assertRaises(NoSuggesterError):
            Suggester.doesnotexist()

    def test_missing_arg(self):
        with self.assertRaises(MissingArgError):
            Query.term(None)

    def test_invalid_arg(self):
        # Test passing not a list
        with self.assertRaises(ValueError):
            Query.bool(must=set())

        # And now an invalid list
        with self.assertRaises(ValueError):
            Query.bool(must=[None])

        # And now an invalid list
        with self.assertRaises(ValueError):
            Query.bool(must=[Aggregate.terms('test', 'test')])

        # And now an invalid list
        with self.assertRaises(ValueError):
            Query.range('field', gte=['error'])

        # Empty list should be OK/ignored
        Query.bool(must=[])

[((51, 21, 51, 50), 'os.path.join', 'path.join', ({(51, 31, 51, 38): '"""tests"""', (51, 40, 51, 49): '"""queries"""'}, {}), "('tests', 'queries')", False, 'from os import path\n'), ((60, 21, 60, 53), 'os.path.join', 'path.join', ({(60, 31, 60, 38): '"""tests"""', (60, 40, 60, 52): '"""aggregates"""'}, {}), "('tests', 'aggregates')", False, 'from os import path\n'), ((69, 21, 69, 53), 'os.path.join', 'path.join', ({(69, 31, 69, 38): '"""tests"""', (69, 40, 69, 52): '"""suggesters"""'}, {}), "('tests', 'suggesters')", False, 'from os import path\n'), ((110, 8, 110, 27), 'elasticquery.Query.bool', 'Query.bool', (), '', False, 'from elasticquery import Query, Aggregate, Suggester\n'), ((78, 12, 78, 32), 'elasticquery.Query.doesnotexist', 'Query.doesnotexist', ({}, {}), '()', False, 'from elasticquery import Query, Aggregate, Suggester\n'), ((82, 12, 82, 36), 'elasticquery.Aggregate.doesnotexist', 'Aggregate.doesnotexist', ({}, {}), '()', False, 'from elasticquery import Query, Aggregate, Suggester\n'), ((86, 12, 86, 36), 'elasticquery.Suggester.doesnotexist', 'Suggester.doesnotexist', ({}, {}), '()', False, 'from elasticquery import Query, Aggregate, Suggester\n'), ((90, 12, 90, 28), 'elasticquery.Query.term', 'Query.term', ({(90, 23, 90, 27): 'None'}, {}), '(None)', False, 'from elasticquery import Query, Aggregate, Suggester\n'), ((99, 12, 99, 35), 'elasticquery.Query.bool', 'Query.bool', (), '', False, 'from elasticquery import Query, Aggregate, Suggester\n'), ((107, 12, 107, 47), 'elasticquery.Query.range', 'Query.range', (), '', False, 'from elasticquery import Query, Aggregate, Suggester\n'), ((103, 29, 103, 60), 'elasticquery.Aggregate.terms', 'Aggregate.terms', ({(103, 45, 103, 51): '"""test"""', (103, 53, 103, 59): '"""test"""'}, {}), "('test', 'test')", False, 'from elasticquery import Query, Aggregate, Suggester\n')]