660 lines
26 KiB
Python
660 lines
26 KiB
Python
from __future__ import absolute_import, unicode_literals
|
|
|
|
from unittest import TestCase as UnitTestCase
|
|
|
|
import django
|
|
from django.contrib.contenttypes.models import ContentType
|
|
from django.core import serializers
|
|
from django.core.exceptions import ImproperlyConfigured, ValidationError
|
|
from django.db import connection, models
|
|
from django.test import TestCase, TransactionTestCase
|
|
from django.test.utils import override_settings
|
|
from django.utils.encoding import force_text
|
|
|
|
from .forms import (CustomPKFoodForm, DirectCustomPKFoodForm, DirectFoodForm,
|
|
FoodForm, OfficialFoodForm)
|
|
from .models import (Article, Child, CustomManager, CustomPKFood,
|
|
CustomPKHousePet, CustomPKPet, DirectCustomPKFood,
|
|
DirectCustomPKHousePet, DirectCustomPKPet, DirectFood,
|
|
DirectHousePet, DirectPet, Food, HousePet, Movie,
|
|
OfficialFood, OfficialHousePet, OfficialPet,
|
|
OfficialTag, OfficialThroughModel, Pet, Photo,
|
|
TaggedCustomPK, TaggedCustomPKFood, TaggedCustomPKPet,
|
|
TaggedFood, TaggedPet)
|
|
|
|
from taggit.managers import _model_name, _TaggableManager, TaggableManager
|
|
from taggit.models import Tag, TaggedItem
|
|
|
|
from taggit.utils import edit_string_for_tags, parse_tags
|
|
|
|
try:
|
|
from unittest import skipIf, skipUnless
|
|
except ImportError:
|
|
from django.utils.unittest import skipIf, skipUnless
|
|
|
|
|
|
class BaseTaggingTest(object):
|
|
def assert_tags_equal(self, qs, tags, sort=True, attr="name"):
|
|
got = [getattr(obj, attr) for obj in qs]
|
|
if sort:
|
|
got.sort()
|
|
tags.sort()
|
|
self.assertEqual(got, tags)
|
|
|
|
def _get_form_str(self, form_str):
|
|
if django.VERSION >= (1, 3):
|
|
form_str %= {
|
|
"help_start": '<span class="helptext">',
|
|
"help_stop": "</span>"
|
|
}
|
|
else:
|
|
form_str %= {
|
|
"help_start": "",
|
|
"help_stop": ""
|
|
}
|
|
return form_str
|
|
|
|
def assert_form_renders(self, form, html):
|
|
self.assertHTMLEqual(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")
|
|
|
|
def test_integers(self):
|
|
"""Adding an integer as a tag should raise a ValueError (#237)."""
|
|
apple = self.food_model.objects.create(name="apple")
|
|
with self.assertRaisesRegexp(ValueError, (
|
|
r"Cannot add 1 \(<(type|class) 'int'>\). "
|
|
r"Expected <class 'django.db.models.base.ModelBase'> or str.")):
|
|
apple.tags.add(1)
|
|
|
|
class TagModelDirectTestCase(TagModelTestCase):
|
|
food_model = DirectFood
|
|
tag_model = Tag
|
|
|
|
class TagModelDirectCustomPKTestCase(TagModelTestCase):
|
|
food_model = DirectCustomPKFood
|
|
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):
|
|
# Prefill content type cache:
|
|
ContentType.objects.get_for_model(self.food_model)
|
|
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.
|
|
# + 12 on Django 1.6 for save points.
|
|
queries = 22
|
|
if django.VERSION < (1, 6):
|
|
queries -= 12
|
|
self.assertNumQueries(queries, 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.
|
|
# + 4 on Django 1.6 for save points.
|
|
queries = 9
|
|
if django.VERSION < (1, 6):
|
|
queries -= 4
|
|
self.assertNumQueries(queries, pear.tags.add, "green", "delicious")
|
|
|
|
self.assertNumQueries(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")
|
|
|
|
pks = self.pet_model.objects.filter(tags__name__in=["fuzzy"])
|
|
model_name = self.pet_model.__name__
|
|
self.assertQuerysetEqual(pks,
|
|
['<{0}: kitty>'.format(model_name),
|
|
'<{0}: cat>'.format(model_name)],
|
|
ordered=False)
|
|
|
|
def test_lookup_bulk(self):
|
|
apple = self.food_model.objects.create(name="apple")
|
|
pear = self.food_model.objects.create(name="pear")
|
|
apple.tags.add('fruit', 'green')
|
|
pear.tags.add('fruit', 'yummie')
|
|
|
|
def lookup_qs():
|
|
# New fix: directly allow WHERE object_id IN (SELECT id FROM ..)
|
|
objects = self.food_model.objects.all()
|
|
lookup = self.taggeditem_model.bulk_lookup_kwargs(objects)
|
|
list(self.taggeditem_model.objects.filter(**lookup))
|
|
|
|
def lookup_list():
|
|
# Simulate old situation: iterate over a list.
|
|
objects = list(self.food_model.objects.all())
|
|
lookup = self.taggeditem_model.bulk_lookup_kwargs(objects)
|
|
list(self.taggeditem_model.objects.filter(**lookup))
|
|
|
|
self.assertNumQueries(1, lookup_qs)
|
|
self.assertNumQueries(2, lookup_list)
|
|
|
|
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")
|
|
|
|
self.food_model.objects.create(name="guava")
|
|
|
|
pks = self.food_model.objects.exclude(tags__name__in=["red"])
|
|
model_name = self.food_model.__name__
|
|
self.assertQuerysetEqual(pks,
|
|
['<{0}: pear>'.format(model_name),
|
|
'<{0}: guava>'.format(model_name)],
|
|
ordered=False)
|
|
|
|
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([obj.similar_tags for obj in 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' % _model_name(self.pet_model): 'Spot'
|
|
}
|
|
self.assert_tags_equal(
|
|
self.tag_model.objects.filter(**lookup_kwargs),
|
|
['scary']
|
|
)
|
|
|
|
def test_taggeditem_unicode(self):
|
|
apple = self.food_model.objects.create(name="apple")
|
|
apple.tags.add("juicy")
|
|
|
|
self.assertEqual(
|
|
force_text(self.taggeditem_model.objects.all()[0]),
|
|
"apple tagged with juicy"
|
|
)
|
|
|
|
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"],
|
|
)
|
|
|
|
def test_field_api(self):
|
|
# Check if tag field, which simulates m2m, has django-like api.
|
|
field = self.food_model._meta.get_field('tags')
|
|
self.assertTrue(hasattr(field, 'rel'))
|
|
self.assertTrue(hasattr(field.rel, 'to'))
|
|
self.assertTrue(hasattr(field, 'related'))
|
|
|
|
# This API has changed in Django 1.8
|
|
# https://code.djangoproject.com/ticket/21414
|
|
if django.VERSION >= (1, 8):
|
|
self.assertEqual(self.food_model, field.model)
|
|
self.assertEqual(self.tag_model, field.related.model)
|
|
else:
|
|
self.assertEqual(self.food_model, field.related.model)
|
|
|
|
def test_names_method(self):
|
|
apple = self.food_model.objects.create(name="apple")
|
|
apple.tags.add('green')
|
|
apple.tags.add('red')
|
|
self.assertEqual(list(apple.tags.names()), ['green', 'red'])
|
|
|
|
def test_slugs_method(self):
|
|
apple = self.food_model.objects.create(name="apple")
|
|
apple.tags.add('green and juicy')
|
|
apple.tags.add('red')
|
|
self.assertEqual(list(apple.tags.slugs()), ['green-and-juicy', 'red'])
|
|
|
|
def test_serializes(self):
|
|
apple = self.food_model.objects.create(name="apple")
|
|
serializers.serialize("json", (apple,))
|
|
|
|
def test_prefetch_related(self):
|
|
apple = self.food_model.objects.create(name="apple")
|
|
apple.tags.add('1', '2')
|
|
orange = self.food_model.objects.create(name="orange")
|
|
orange.tags.add('2', '4')
|
|
with self.assertNumQueries(2):
|
|
l = list(self.food_model.objects.prefetch_related('tags').all())
|
|
with self.assertNumQueries(0):
|
|
foods = dict((f.name, set(t.name for t in f.tags.all())) for f in l)
|
|
self.assertEqual(foods, {
|
|
'orange': set(['2', '4']),
|
|
'apple': set(['1', '2'])
|
|
})
|
|
|
|
def test_internal_type_is_manytomany(self):
|
|
self.assertEqual(
|
|
TaggableManager().get_internal_type(), 'ManyToManyField'
|
|
)
|
|
|
|
def test_prefetch_no_extra_join(self):
|
|
apple = self.food_model.objects.create(name="apple")
|
|
apple.tags.add('1', '2')
|
|
with self.assertNumQueries(2):
|
|
l = list(self.food_model.objects.prefetch_related('tags').all())
|
|
join_clause = 'INNER JOIN "%s"' % self.taggeditem_model._meta.db_table
|
|
self.assertEqual(connection.queries[-1]['sql'].count(join_clause), 1, connection.queries[-2:])
|
|
|
|
@override_settings(TAGGIT_CASE_INSENSITIVE=True)
|
|
def test_with_case_insensitive_option(self):
|
|
spain = self.tag_model.objects.create(name="Spain", slug="spain")
|
|
orange = self.food_model.objects.create(name="orange")
|
|
orange.tags.add('spain')
|
|
self.assertEqual(list(orange.tags.all()), [spain])
|
|
|
|
|
|
class TaggableManagerDirectTestCase(TaggableManagerTestCase):
|
|
food_model = DirectFood
|
|
pet_model = DirectPet
|
|
housepet_model = DirectHousePet
|
|
taggeditem_model = TaggedFood
|
|
|
|
class TaggableManagerDirectCustomPKTestCase(TaggableManagerTestCase):
|
|
food_model = DirectCustomPKFood
|
|
pet_model = DirectCustomPKPet
|
|
housepet_model = DirectCustomPKHousePet
|
|
taggeditem_model = TaggedCustomPKFood
|
|
|
|
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 TaggableManagerCustomPKTestCase(TaggableManagerTestCase):
|
|
food_model = CustomPKFood
|
|
pet_model = CustomPKPet
|
|
housepet_model = CustomPKHousePet
|
|
taggeditem_model = TaggedCustomPK
|
|
|
|
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(apple, self.food_model.objects.get(tags__official=False))
|
|
|
|
def test_get_tags_with_count(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")
|
|
|
|
tag_info = self.tag_model.objects.filter(officialfood__in=[apple.id, pear.id],name='green').annotate(models.Count('name'))
|
|
self.assertEqual(tag_info[0].name__count, 2)
|
|
|
|
class TaggableManagerInitializationTestCase(TaggableManagerTestCase):
|
|
"""Make sure manager override defaults and sets correctly."""
|
|
food_model = Food
|
|
custom_manager_model = CustomManager
|
|
|
|
def test_default_manager(self):
|
|
self.assertEqual(self.food_model.tags.__class__, _TaggableManager)
|
|
|
|
def test_custom_manager(self):
|
|
self.assertEqual(self.custom_manager_model.tags.__class__, CustomManager.Foo)
|
|
|
|
class TaggableFormTestCase(BaseTaggingTestCase):
|
|
form_class = FoodForm
|
|
food_model = Food
|
|
|
|
def test_form(self):
|
|
self.assertEqual(list(self.form_class.base_fields), ['name', 'tags'])
|
|
|
|
f = self.form_class({'name': 'apple', 'tags': 'green, red, yummy'})
|
|
self.assert_form_renders(f, """<tr><th><label for="id_name">Name:</label></th><td><input id="id_name" type="text" name="name" value="apple" maxlength="50" /></td></tr>
|
|
<tr><th><label for="id_tags">Tags:</label></th><td><input type="text" name="tags" value="green, red, yummy" id="id_tags" /><br />%(help_start)sA comma-separated list of tags.%(help_stop)s</td></tr>""")
|
|
f.save()
|
|
apple = self.food_model.objects.get(name='apple')
|
|
self.assert_tags_equal(apple.tags.all(), ['green', 'red', 'yummy'])
|
|
|
|
f = self.form_class({'name': 'apple', 'tags': 'green, red, yummy, delicious'}, instance=apple)
|
|
f.save()
|
|
apple = self.food_model.objects.get(name='apple')
|
|
self.assert_tags_equal(apple.tags.all(), ['green', 'red', 'yummy', 'delicious'])
|
|
self.assertEqual(self.food_model.objects.count(), 1)
|
|
|
|
f = self.form_class({"name": "raspberry"})
|
|
self.assertFalse(f.is_valid())
|
|
|
|
f = self.form_class(instance=apple)
|
|
self.assert_form_renders(f, """<tr><th><label for="id_name">Name:</label></th><td><input id="id_name" type="text" name="name" value="apple" maxlength="50" /></td></tr>
|
|
<tr><th><label for="id_tags">Tags:</label></th><td><input type="text" name="tags" value="delicious, green, red, yummy" id="id_tags" /><br />%(help_start)sA comma-separated list of tags.%(help_stop)s</td></tr>""")
|
|
|
|
apple.tags.add('has,comma')
|
|
f = self.form_class(instance=apple)
|
|
self.assert_form_renders(f, """<tr><th><label for="id_name">Name:</label></th><td><input id="id_name" type="text" name="name" value="apple" maxlength="50" /></td></tr>
|
|
<tr><th><label for="id_tags">Tags:</label></th><td><input type="text" name="tags" value=""has,comma", delicious, green, red, yummy" id="id_tags" /><br />%(help_start)sA comma-separated list of tags.%(help_stop)s</td></tr>""")
|
|
|
|
apple.tags.add('has space')
|
|
f = self.form_class(instance=apple)
|
|
self.assert_form_renders(f, """<tr><th><label for="id_name">Name:</label></th><td><input id="id_name" type="text" name="name" value="apple" maxlength="50" /></td></tr>
|
|
<tr><th><label for="id_tags">Tags:</label></th><td><input type="text" name="tags" value=""has space", "has,comma", delicious, green, red, yummy" id="id_tags" /><br />%(help_start)sA comma-separated list of tags.%(help_stop)s</td></tr>""")
|
|
|
|
def test_formfield(self):
|
|
tm = TaggableManager(verbose_name='categories', help_text='Add some categories', blank=True)
|
|
ff = tm.formfield()
|
|
self.assertEqual(ff.label, 'Categories')
|
|
self.assertEqual(ff.help_text, 'Add some categories')
|
|
self.assertEqual(ff.required, False)
|
|
|
|
self.assertEqual(ff.clean(""), [])
|
|
|
|
tm = TaggableManager()
|
|
ff = tm.formfield()
|
|
self.assertRaises(ValidationError, ff.clean, "")
|
|
|
|
class TaggableFormDirectTestCase(TaggableFormTestCase):
|
|
form_class = DirectFoodForm
|
|
food_model = DirectFood
|
|
|
|
class TaggableFormDirectCustomPKTestCase(TaggableFormTestCase):
|
|
form_class = DirectCustomPKFoodForm
|
|
food_model = DirectCustomPKFood
|
|
|
|
class TaggableFormCustomPKTestCase(TaggableFormTestCase):
|
|
form_class = CustomPKFoodForm
|
|
food_model = CustomPKFood
|
|
|
|
class TaggableFormOfficialTestCase(TaggableFormTestCase):
|
|
form_class = OfficialFoodForm
|
|
food_model = OfficialFood
|
|
|
|
|
|
class TagStringParseTestCase(UnitTestCase):
|
|
"""
|
|
Ported from Jonathan Buchanan's `django-tagging
|
|
<http://django-tagging.googlecode.com/>`_
|
|
"""
|
|
|
|
def test_with_simple_space_delimited_tags(self):
|
|
"""
|
|
Test with simple space-delimited tags.
|
|
"""
|
|
self.assertEqual(parse_tags('one'), ['one'])
|
|
self.assertEqual(parse_tags('one two'), ['one', 'two'])
|
|
self.assertEqual(parse_tags('one two three'), ['one', 'three', 'two'])
|
|
self.assertEqual(parse_tags('one one two two'), ['one', 'two'])
|
|
|
|
def test_with_comma_delimited_multiple_words(self):
|
|
"""
|
|
Test with comma-delimited multiple words.
|
|
An unquoted comma in the input will trigger this.
|
|
"""
|
|
self.assertEqual(parse_tags(',one'), ['one'])
|
|
self.assertEqual(parse_tags(',one two'), ['one two'])
|
|
self.assertEqual(parse_tags(',one two three'), ['one two three'])
|
|
self.assertEqual(parse_tags('a-one, a-two and a-three'),
|
|
['a-one', 'a-two and a-three'])
|
|
|
|
def test_with_double_quoted_multiple_words(self):
|
|
"""
|
|
Test with double-quoted multiple words.
|
|
A completed quote will trigger this. Unclosed quotes are ignored.
|
|
"""
|
|
self.assertEqual(parse_tags('"one'), ['one'])
|
|
self.assertEqual(parse_tags('"one two'), ['one', 'two'])
|
|
self.assertEqual(parse_tags('"one two three'), ['one', 'three', 'two'])
|
|
self.assertEqual(parse_tags('"one two"'), ['one two'])
|
|
self.assertEqual(parse_tags('a-one "a-two and a-three"'),
|
|
['a-one', 'a-two and a-three'])
|
|
|
|
def test_with_no_loose_commas(self):
|
|
"""
|
|
Test with no loose commas -- split on spaces.
|
|
"""
|
|
self.assertEqual(parse_tags('one two "thr,ee"'), ['one', 'thr,ee', 'two'])
|
|
|
|
def test_with_loose_commas(self):
|
|
"""
|
|
Loose commas - split on commas
|
|
"""
|
|
self.assertEqual(parse_tags('"one", two three'), ['one', 'two three'])
|
|
|
|
def test_tags_with_double_quotes_can_contain_commas(self):
|
|
"""
|
|
Double quotes can contain commas
|
|
"""
|
|
self.assertEqual(parse_tags('a-one "a-two, and a-three"'),
|
|
['a-one', 'a-two, and a-three'])
|
|
self.assertEqual(parse_tags('"two", one, one, two, "one"'),
|
|
['one', 'two'])
|
|
|
|
def test_with_naughty_input(self):
|
|
"""
|
|
Test with naughty input.
|
|
"""
|
|
# Bad users! Naughty users!
|
|
self.assertEqual(parse_tags(None), [])
|
|
self.assertEqual(parse_tags(''), [])
|
|
self.assertEqual(parse_tags('"'), [])
|
|
self.assertEqual(parse_tags('""'), [])
|
|
self.assertEqual(parse_tags('"' * 7), [])
|
|
self.assertEqual(parse_tags(',,,,,,'), [])
|
|
self.assertEqual(parse_tags('",",",",",",","'), [','])
|
|
self.assertEqual(parse_tags('a-one "a-two" and "a-three'),
|
|
['a-one', 'a-three', 'a-two', 'and'])
|
|
|
|
def test_recreation_of_tag_list_string_representations(self):
|
|
plain = Tag.objects.create(name='plain')
|
|
spaces = Tag.objects.create(name='spa ces')
|
|
comma = Tag.objects.create(name='com,ma')
|
|
self.assertEqual(edit_string_for_tags([plain]), 'plain')
|
|
self.assertEqual(edit_string_for_tags([plain, spaces]), '"spa ces", plain')
|
|
self.assertEqual(edit_string_for_tags([plain, spaces, comma]), '"com,ma", "spa ces", plain')
|
|
self.assertEqual(edit_string_for_tags([plain, comma]), '"com,ma", plain')
|
|
self.assertEqual(edit_string_for_tags([comma, spaces]), '"com,ma", "spa ces"')
|
|
|
|
|
|
@skipIf(django.VERSION < (1, 7), "not relevant for Django < 1.7")
|
|
class DeconstructTestCase(UnitTestCase):
|
|
def test_deconstruct_kwargs_kept(self):
|
|
instance = TaggableManager(through=OfficialThroughModel, to='dummy.To')
|
|
name, path, args, kwargs = instance.deconstruct()
|
|
new_instance = TaggableManager(*args, **kwargs)
|
|
self.assertEqual('tests.OfficialThroughModel', new_instance.rel.through)
|
|
self.assertEqual('dummy.To', new_instance.rel.to)
|
|
|
|
|
|
@skipUnless(django.VERSION < (1, 7), "test only applies to 1.6 and below")
|
|
class SouthSupportTests(TestCase):
|
|
def test_import_migrations_module(self):
|
|
try:
|
|
from taggit.migrations import __doc__ # noqa
|
|
except ImproperlyConfigured as e:
|
|
exception = e
|
|
self.assertIn("SOUTH_MIGRATION_MODULES", exception.args[0])
|
|
|
|
|
|
class InheritedPrefetchTests(TestCase):
|
|
|
|
def test_inherited_tags_with_prefetch(self):
|
|
child = Child()
|
|
child.save()
|
|
child.tags.add('tag 1', 'tag 2', 'tag 3', 'tag 4')
|
|
|
|
child = Child.objects.get()
|
|
no_prefetch_tags = child.tags.all()
|
|
self.assertEquals(4, no_prefetch_tags.count())
|
|
child = Child.objects.prefetch_related('tags').get()
|
|
prefetch_tags = child.tags.all()
|
|
self.assertEquals(4, prefetch_tags.count())
|
|
self.assertEquals(set([t.name for t in no_prefetch_tags]),
|
|
set([t.name for t in prefetch_tags]))
|