from unittest import TestCase as UnitTestCase import django from django.conf import settings from django.core.exceptions import ValidationError from django.db import connection from django.test import TestCase, TransactionTestCase from taggit.managers import TaggableManager from taggit.models import Tag, TaggedItem from taggit.tests.forms import (FoodForm, DirectFoodForm, CustomPKFoodForm, OfficialFoodForm) from taggit.tests.models import (Food, Pet, HousePet, DirectFood, DirectPet, DirectHousePet, TaggedPet, CustomPKFood, CustomPKPet, CustomPKHousePet, TaggedCustomPKPet, OfficialFood, OfficialPet, OfficialHousePet, OfficialThroughModel, OfficialTag, Photo, Movie, Article) from taggit.utils import parse_tags, edit_string_for_tags class BaseTaggingTest(object): def assert_tags_equal(self, qs, tags, sort=True, attr="name"): got = map(lambda tag: getattr(tag, attr), qs) if sort: got.sort() tags.sort() self.assertEqual(got, tags) def assert_num_queries(self, n, f, *args, **kwargs): original_DEBUG = settings.DEBUG settings.DEBUG = True current = len(connection.queries) try: f(*args, **kwargs) self.assertEqual( len(connection.queries) - current, n, ) finally: settings.DEBUG = original_DEBUG def _get_form_str(self, form_str): if django.VERSION >= (1, 3): form_str %= { "help_start": '', "help_stop": "" } else: form_str %= { "help_start": "", "help_stop": "" } return form_str def assert_form_renders(self, form, html): self.assertEqual(str(form), self._get_form_str(html)) class BaseTaggingTestCase(TestCase, BaseTaggingTest): pass class BaseTaggingTransactionTestCase(TransactionTestCase, BaseTaggingTest): pass class TagModelTestCase(BaseTaggingTransactionTestCase): food_model = Food tag_model = Tag def test_unique_slug(self): apple = self.food_model.objects.create(name="apple") apple.tags.add("Red", "red") def test_update(self): special = self.tag_model.objects.create(name="special") special.save() def test_add(self): apple = self.food_model.objects.create(name="apple") yummy = self.tag_model.objects.create(name="yummy") apple.tags.add(yummy) def test_slugify(self): a = Article.objects.create(title="django-taggit 1.0 Released") a.tags.add("awesome", "release", "AWESOME") self.assert_tags_equal(a.tags.all(), [ "category-awesome", "category-release", "category-awesome-1" ], attr="slug") class TagModelDirectTestCase(TagModelTestCase): food_model = DirectFood tag_model = Tag class TagModelCustomPKTestCase(TagModelTestCase): food_model = CustomPKFood tag_model = Tag class TagModelOfficialTestCase(TagModelTestCase): food_model = OfficialFood tag_model = OfficialTag class TaggableManagerTestCase(BaseTaggingTestCase): food_model = Food pet_model = Pet housepet_model = HousePet taggeditem_model = TaggedItem tag_model = Tag def test_add_tag(self): apple = self.food_model.objects.create(name="apple") self.assertEqual(list(apple.tags.all()), []) self.assertEqual(list(self.food_model.tags.all()), []) apple.tags.add('green') self.assert_tags_equal(apple.tags.all(), ['green']) self.assert_tags_equal(self.food_model.tags.all(), ['green']) pear = self.food_model.objects.create(name="pear") pear.tags.add('green') self.assert_tags_equal(pear.tags.all(), ['green']) self.assert_tags_equal(self.food_model.tags.all(), ['green']) apple.tags.add('red') self.assert_tags_equal(apple.tags.all(), ['green', 'red']) self.assert_tags_equal(self.food_model.tags.all(), ['green', 'red']) self.assert_tags_equal( self.food_model.tags.most_common(), ['green', 'red'], sort=False ) apple.tags.remove('green') self.assert_tags_equal(apple.tags.all(), ['red']) self.assert_tags_equal(self.food_model.tags.all(), ['green', 'red']) tag = self.tag_model.objects.create(name="delicious") apple.tags.add(tag) self.assert_tags_equal(apple.tags.all(), ["red", "delicious"]) apple.delete() self.assert_tags_equal(self.food_model.tags.all(), ["green"]) def test_add_queries(self): apple = self.food_model.objects.create(name="apple") # 1 query to see which tags exist # + 3 queries to create the tags. # + 6 queries to create the intermediary things (including SELECTs, to # make sure we don't double create. self.assert_num_queries(10, apple.tags.add, "red", "delicious", "green") pear = self.food_model.objects.create(name="pear") # 1 query to see which tags exist # + 4 queries to create the intermeidary things (including SELECTs, to # make sure we dont't double create. self.assert_num_queries(5, pear.tags.add, "green", "delicious") self.assert_num_queries(0, pear.tags.add) def test_require_pk(self): food_instance = self.food_model() self.assertRaises(ValueError, lambda: food_instance.tags.all()) def test_delete_obj(self): apple = self.food_model.objects.create(name="apple") apple.tags.add("red") self.assert_tags_equal(apple.tags.all(), ["red"]) strawberry = self.food_model.objects.create(name="strawberry") strawberry.tags.add("red") apple.delete() self.assert_tags_equal(strawberry.tags.all(), ["red"]) def test_delete_bulk(self): apple = self.food_model.objects.create(name="apple") kitty = self.pet_model.objects.create(pk=apple.pk, name="kitty") apple.tags.add("red", "delicious", "fruit") kitty.tags.add("feline") self.food_model.objects.all().delete() self.assert_tags_equal(kitty.tags.all(), ["feline"]) def test_lookup_by_tag(self): apple = self.food_model.objects.create(name="apple") apple.tags.add("red", "green") pear = self.food_model.objects.create(name="pear") pear.tags.add("green") self.assertEqual( list(self.food_model.objects.filter(tags__name__in=["red"])), [apple] ) self.assertEqual( list(self.food_model.objects.filter(tags__name__in=["green"])), [apple, pear] ) kitty = self.pet_model.objects.create(name="kitty") kitty.tags.add("fuzzy", "red") dog = self.pet_model.objects.create(name="dog") dog.tags.add("woof", "red") self.assertEqual( list(self.food_model.objects.filter(tags__name__in=["red"]).distinct()), [apple] ) tag = self.tag_model.objects.get(name="woof") self.assertEqual(list(self.pet_model.objects.filter(tags__in=[tag])), [dog]) cat = self.housepet_model.objects.create(name="cat", trained=True) cat.tags.add("fuzzy") self.assertEqual( map(lambda o: o.pk, self.pet_model.objects.filter(tags__name__in=["fuzzy"])), [kitty.pk, cat.pk] ) def test_exclude(self): apple = self.food_model.objects.create(name="apple") apple.tags.add("red", "green", "delicious") pear = self.food_model.objects.create(name="pear") pear.tags.add("green", "delicious") guava = self.food_model.objects.create(name="guava") self.assertEqual( map(lambda o: o.pk, self.food_model.objects.exclude(tags__name__in=["red"])), [pear.pk, guava.pk], ) def test_similarity_by_tag(self): """Test that pears are more similar to apples than watermelons""" apple = self.food_model.objects.create(name="apple") apple.tags.add("green", "juicy", "small", "sour") pear = self.food_model.objects.create(name="pear") pear.tags.add("green", "juicy", "small", "sweet") watermelon = self.food_model.objects.create(name="watermelon") watermelon.tags.add("green", "juicy", "large", "sweet") similar_objs = apple.tags.similar_objects() self.assertEqual(similar_objs, [pear, watermelon]) self.assertEqual(map(lambda x: x.similar_tags, similar_objs), [3, 2]) def test_tag_reuse(self): apple = self.food_model.objects.create(name="apple") apple.tags.add("juicy", "juicy") self.assert_tags_equal(apple.tags.all(), ['juicy']) def test_query_traverse(self): spot = self.pet_model.objects.create(name='Spot') spike = self.pet_model.objects.create(name='Spike') spot.tags.add('scary') spike.tags.add('fluffy') lookup_kwargs = { '%s__name' % self.pet_model._meta.module_name: 'Spot' } self.assert_tags_equal( self.tag_model.objects.filter(**lookup_kwargs), ['scary'] ) def test_taggeditem_unicode(self): ross = self.pet_model.objects.create(name="ross") # I keep Ross Perot for a pet, what's it to you? ross.tags.add("president") self.assertEqual( unicode(self.taggeditem_model.objects.all()[0]), "ross tagged with president" ) def test_abstract_subclasses(self): p = Photo.objects.create() p.tags.add("outdoors", "pretty") self.assert_tags_equal( p.tags.all(), ["outdoors", "pretty"] ) m = Movie.objects.create() m.tags.add("hd") self.assert_tags_equal( m.tags.all(), ["hd"], ) class TaggableManagerDirectTestCase(TaggableManagerTestCase): food_model = DirectFood pet_model = DirectPet housepet_model = DirectHousePet taggeditem_model = TaggedPet class TaggableManagerCustomPKTestCase(TaggableManagerTestCase): food_model = CustomPKFood pet_model = CustomPKPet housepet_model = CustomPKHousePet taggeditem_model = TaggedCustomPKPet def test_require_pk(self): # TODO with a charfield pk, pk is never None, so taggit has no way to # tell if the instance is saved or not pass class TaggableManagerOfficialTestCase(TaggableManagerTestCase): food_model = OfficialFood pet_model = OfficialPet housepet_model = OfficialHousePet taggeditem_model = OfficialThroughModel tag_model = OfficialTag def test_extra_fields(self): self.tag_model.objects.create(name="red") self.tag_model.objects.create(name="delicious", official=True) apple = self.food_model.objects.create(name="apple") apple.tags.add("delicious", "red") pear = self.food_model.objects.create(name="Pear") pear.tags.add("delicious") self.assertEqual( map(lambda o: o.pk, self.food_model.objects.filter(tags__official=False)), [apple.pk], ) class TaggableFormTestCase(BaseTaggingTestCase): form_class = FoodForm food_model = Food def test_form(self): self.assertEqual(self.form_class.base_fields.keys(), ['name', 'tags']) f = self.form_class({'name': 'apple', 'tags': 'green, red, yummy'}) self.assert_form_renders(f, """