from django.test import TestCase

from queryset_sequence import QuerySetSequence

from .models import Article


class MetaTestGenerator(type):
    """Generate identical test method off of a list of data."""

    NOT_IMPLEMENTED = [
        # Methods that return QuerySets.
        'annotate',
        'reverse',
        'distinct',
        'values',
        'values_list',
        'dates',
        'datetimes',
        'none',
        'select_related',
        'prefetch_related',
        'extra',
        'defer',
        'only',
        'using',
        'select_for_update',
        'raw',

        # Methods that don't return QuerySets.
        'create',
        'get_or_create',
        'update_or_create',
        'bulk_create',
        'in_bulk',
        'latest',
        'earliest',
        'first',
        'last',
        'aggregate',
        'exists',
        'update',
        'delete',
    ]

    def __new__(meta, name, bases, dct):
        # Give the test function a separate namespace.
        def gen_test_func(attr):
            def test(self):
                self.assertRaises(NotImplementedError, getattr(self.qss, attr))
            test.__doc__ = ("Ensure that NotImplementedError is raised when "
                            "accessing '%s'" % attr)
            return test

        for attr in meta.NOT_IMPLEMENTED:
            dct['test_' + attr] = gen_test_func(attr)

        return type.__new__(meta, name, bases, dct)


class TestNotImplemented(TestCase):
    """Test methods that are not implemented and should raise NotImplemented."""
    __metaclass__ = MetaTestGenerator

    @classmethod
    def setUpClass(cls):
        """Set-up some data to be tested against."""
        cls.qss = QuerySetSequence(Article.objects.all())

    @classmethod
    def tearDownClass(cls):
        del cls.qss

@@ -205,31 +205,700 @@
 %22%22%0A%0A    
-NOT_IMPLEMENTED
+ATTRIBUTES = %5B%5D%0A    EXPECTED_EXCEPTION = RuntimeError%0A%0A    def __new__(meta, name, bases, dct):%0A        # Give the test function a separate namespace.%0A        def gen_test_func(attr):%0A            def test(self):%0A                with self.assertRaises(meta.EXPECTED_EXCEPTION):%0A                    getattr(self.qss, attr)()%0A            test.__doc__ = (%22Ensure that NotImplementedError is raised when %22%0A                            %22accessing '%25s'%22 %25 attr)%0A            return test%0A%0A        for attr in meta.ATTRIBUTES:%0A            dct%5B'test_' + attr%5D = gen_test_func(attr)%0A%0A        return type.__new__(meta, name, bases, dct)%0A%0A%0Aclass NotImplementedMeta(MetaTestGenerator):%0A    ATTRIBUTES
  = %5B%0A   
@@ -1571,182 +1571,419 @@
   %5D%0A
-%0A
     
-def __new__(meta, name, bases, dct):%0A        # Give the test function a separate namespace.%0A        def gen_test_func(attr):%0A            def test(self):%0A        
+EXPECTED_EXCEPTION = NotImplementedError%0A%0A%0Aclass TestNotImplemented(TestCase):%0A    %22%22%22Test methods that are not implemented and should raise NotImplemented.%22%22%22%0A    __metaclass__ = NotImplementedMeta%0A%0A    @classmethod%0A    def setUpClass(cls):%0A        %22%22%22Set-up some data to be tested against.%22%22%22%0A        cls.qss = QuerySetSequence(Article.objects.all())%0A%0A    @classmethod%0A    def tearDownClass(cls):%0A
         
 self
@@ -1982,403 +1982,712 @@
     
-self.assertRaises(NotImplemen
+del cls.qss%0A%0A%0Aclass Attribu
 te
-d
 Error
-, getattr(self.qss, attr))
+Meta(MetaTestGenerator):
 %0A    
-        test.__doc__ = (%22Ensure that NotImplementedError is raised when %22%0A                            %22accessing '%25s'%22 %25 attr)%0A            return test%0A%0A        for attr in meta.NOT_IMPLEMENTED:%0A            dct%5B'test_' + attr%5D = gen_test_func(attr)%0A%0A        return type.__new__(meta, name, bases, dct)%0A%0A%0Aclass TestNotImplemented
+ATTRIBUTES = %5B%0A        # Private methods used by not implemented methods.%0A        '_populate_pk_values',%0A        '_create_object_from_params',%0A        '_extract_model_params',%0A        '_earliest_or_latest',%0A        '_raw_delete',%0A        '_update',%0A        '_prefetch_related_objects',%0A%0A        # Private methods.%0A        '_insert',%0A        '_batched_insert',%0A        '_next_is_sticky',%0A        '_merge_known_related_objects',%0A        '_setup_aggregate_query',%0A        '_as_sql',%0A        '_add_hints',%0A        '_has_filters',%0A        'is_compatible_query_object_type',%0A    %5D%0A    EXPECTED_EXCEPTION = AttributeError%0A%0A%0Aclass TestAttributeError
 (Tes
@@ -2795,33 +2795,34 @@
 ass__ = 
-MetaTestGenerator
+AttributeErrorMeta
 %0A%0A    @c

Add tests for AttributeErrors.