def test_search_Document_multiple_tag(): doc_foo = DocumentFactory(tags=["foo"]) doc_bar = DocumentFactory(tags=["bar"]) doc_foo_bar = DocumentFactory(tags=["foo", "bar"]) doc_bar_foo = DocumentFactory(tags=["bar", "foo"]) doc = DocumentFactory() for d in (doc_foo, doc_foo_bar, doc_bar_foo): assert d in Search.search(tags__match=["foo"]) for d in (doc, doc_bar): assert d not in Search.search(tags__match=["foo"]) for d in (doc_bar, doc_foo_bar, doc_bar_foo): assert d in Search.search(tags__match=["bar"]) for d in (doc, doc_foo): assert d not in Search.search(tags__match=["bar"]) for d in (doc_foo_bar, doc_bar_foo): assert d in Search.search(tags__match=["bar", "foo"]) for d in (doc, doc_foo, doc_bar): assert d not in Search.search(tags__match=["bar", "foo"]) for d in (doc_foo_bar, doc_bar_foo): assert d in Search.search(tags__match=["foo", "bar"]) for d in (doc, doc_foo, doc_bar): assert d not in Search.search(tags__match=["foo", "bar"])
def test_search_Document_on_no_tag(): assert Document.objects.count() == 0 document = DocumentFactory(tags=["foo"]) document_no_tag = DocumentFactory() assert Document.objects.count() == 2 assert document not in Search.search(tags__match=[]) assert document_no_tag in Search.search(tags__match=[])
def test_search_Document_on_tag_name_and_slug(): doc1 = DocumentFactory(tags=["aé"]) doc2 = DocumentFactory(tags=["ae"]) assert doc1 in Search.search(tags__match=["ae"]) assert doc2 in Search.search(tags__match=["ae"]) assert doc1 in Search.search(tags__match=["aé"]) assert doc2 not in Search.search(tags__match=["aé"])
def test_search_Document_is_case_insensitive(): # The custom function to parse tag string (and so sanitize tag's names) # is used is form only, not if we use `tag.set()` or `tag.add()`. # DocumentFactory use `tag.add()` to set the tags of the document and so # the tag's names are not sanitized. doc1 = DocumentFactory(tags=[sanitize_tag_name("aé")]) doc2 = DocumentFactory(tags=[sanitize_tag_name("AÉ")]) doc3 = DocumentFactory(tags=[sanitize_tag_name("Bar")]) assert sorted(Search.search(tags__match=["aé"]), key=attrgetter('id')) \ == [doc1, doc2] assert sorted(Search.search(tags__match=["AÉ"]), key=attrgetter('id')) \ == [doc1, doc2] assert doc3 in Search.search(tags__match=["baR"])
def test_rename_should_exit_if_new_name_already_exists(): DocumentFactory(tags=['tag1']) Tag.objects.create(name='tag2') with pytest.raises(SystemExit): call_command('tags', 'rename', 'tag1', 'tag2') assert Tag.objects.filter(name='tag1') assert Tag.objects.filter(name='tag2')
def test_replace_should_create_if_needed(): doc = DocumentFactory(tags=['tag1']) call_command('tags', 'replace', 'tag1', 'tag2') tag2 = Tag.objects.get(name='tag2') assert not Tag.objects.filter(name='tag1') assert 'tag1' not in doc.tags.names() assert tag2 in doc.tags.all()
def test_rename_should_rename_tag(): doc = DocumentFactory(tags=['tag1']) tag1 = Tag.objects.get(name='tag1') call_command('tags', 'rename', 'tag1', 'tag2') assert not Tag.objects.filter(name='tag1') assert 'tag2' in doc.tags.names() assert 'tag1' not in doc.tags.names() assert tag1.id == Tag.objects.get(name='tag2').id
def test_replace_should_replace_and_delete_tag(): tag1 = Tag.objects.create(name='tag1') tag2 = Tag.objects.create(name='tag2') doc = DocumentFactory(tags=[tag1]) call_command('tags', 'replace', 'tag1', 'tag2') assert not Tag.objects.filter(name='tag1') assert tag1 not in doc.tags.all() assert tag2 in doc.tags.all() assert tag1.id != tag2.id
def test_sanitize_tags(): foo = Tag.objects.create(name='foo') Foo = Tag.objects.create(name='Foo') Bar = Tag.objects.create(name='Bar') # Create a tag with upper case first. bar = Tag.objects.create(name='bar') bar_ = Tag.objects.create(name='bar;') Bar_ = Tag.objects.create(name='Bar;') tag_to_delete = Tag.objects.create(name=':') clean = Tag.objects.create(name="Other:") half_clean1 = Tag.objects.create(name="Other:Foo,") half_clean2 = Tag.objects.create(name="Other:foo") doc1 = DocumentFactory(tags=[foo, bar, clean]) doc2 = DocumentFactory(tags=[foo, Bar, clean, half_clean2]) doc3 = DocumentFactory(tags=[Foo, bar]) doc4 = DocumentFactory(tags=[Foo, Bar_, half_clean1, half_clean2]) doc5 = DocumentFactory(tags=[Foo, foo, bar_, Bar]) doc6 = DocumentFactory(tags=[Foo, foo, Bar_, tag_to_delete]) call_command('tags', 'sanitize') all_tag_names = list(Tag.objects.all().order_by('name').values_list( 'name', flat=True)) assert all_tag_names == ['bar', 'foo', 'other', 'other:foo'] assert sorted(doc1.tags.names()) == ['bar', 'foo', 'other'] assert sorted(doc2.tags.names()) == ['bar', 'foo', 'other', 'other:foo'] assert sorted(doc3.tags.names()) == ['bar', 'foo'] assert sorted(doc4.tags.names()) == ['bar', 'foo', 'other:foo'] assert sorted(doc5.tags.names()) == ['bar', 'foo'] assert sorted(doc6.tags.names()) == ['bar', 'foo']
def test_search_Document_on_kind(): assert Document.objects.count() == 0 document = DocumentFactory(kind="video") assert Document.objects.count() == 1 assert document in Search.search(kind="video") assert document not in Search.search(kind="pdf")
def test_search_Document_on_lang(): assert Document.objects.count() == 0 document = DocumentFactory(lang="FR") assert Document.objects.count() == 1 assert document in Search.search(lang="FR") assert document not in Search.search(lang="EN")
def test_rename_should_exit_on_non_existing_tag(): DocumentFactory(tags=['tag1']) with pytest.raises(SystemExit): call_command('tags', 'rename', 'tag3', 'tag2') assert Tag.objects.filter(name='tag1')
def test_count_should_count_usage(capsys): DocumentFactory.create_batch(size=4, tags=['tag1']) call_command('tags', 'count', 'tag1') out, err = capsys.readouterr() assert '4 object(s)' in out
def test_theme_slug_for_document(): book = DocumentFactory(kind=Document.IMAGE) assert theme_slug(book) == '<span class="theme discover">image</span>'
def handle(self, *args, **options): if not settings.DEBUG: msg = ('This does not seem to be a dev project. Aborting. You need' ' to be in DEBUG=True') raise CommandError(msg) # Create some users. staff = UserFactory(short_name='Amelia', serial='123456', password='******', is_staff=True) UserFactory(short_name='Amy', password='******') UserFactory(short_name='Touria', password='******') # Create some blog content. text = ('The last voice transmission received on Howland Island from ' 'Earhart indicated she and Noonan were flying along a line of ' 'position (taken from a "sun line" running on 157-337 degrees)' ' which Noonan would have calculated and drawn on a chart as ' 'passing through Howland. After all contact was lost with ' 'Howland Island, attempts were made to reach the flyers with ' 'both voice and Morse code transmissions. Operators across the' ' Pacific and the United States may have heard signals from ' 'the downed Electra but these were unintelligible or weak') ContentFactory( title='1937 world flight', text=text, summary=text, status=Content.PUBLISHED, author=staff, tags=['plane', 'aviation'], image__from_path='ideascube/tests/data/amelia-earhart.jpg') # noqa ContentFactory(title='This is another article with a longer title', text=text, summary=text, status=Content.PUBLISHED, author=staff, image=None) title = ('The Untold Story of Thirteen American Women and the Dream ' 'of Space Flight') ContentFactory(title=title, text=text, summary=text, status=Content.PUBLISHED, author=staff, tags=['plane', 'aviation', 'record'], image__from_path='ideascube/tests/data/plane.jpg') ContentFactory(title='This is a draft content', text=text, status=Content.DRAFT, author=staff, image=None) ContentFactory(title='This is a deleted content', text=text, status=Content.DELETED, author=staff, image=None) # Create some books. summary = ("If one chanced to examine the catalogues of Kingsbridge " "College for the past hundred years it would be found that " "in most of them is recorded the name of some dead and " "gone Deering-a name famous in the annals of the South-who " "came up from Louisiana, 'marched through the four long " "happy years of college,' as the old song has it, with an " "arts degree to his credit; or, perchance, marched out at " "the end of one or two of them with nothing to his credit " "at all. Kingsbridge was a tradition in the Deering " "family, southern though it was-a tradition that was " "hardly broken, even when in 1861 Victor Deering and a " "hundred other chivalrous youths threw their text-books " "out of the windows and enlisted in the armies of the " "Confederacy. Victor's father, Basil, too, was in the " "war, and laid down his arms at Appomattox as a " "brigadier-general-brevetted for gallantry on the field of " "action. For a while it seemed that no Deerings would go " "to Kingsbridge, but time at length healed the old " "antagonisms, and when it became a question where young " "Anthony, Victor's boy, should go to[2] college, there was " "no longer any question that Kingsbridge should be the " "place.") path = 'ideascube/tests/data/deering-of-deal.jpg' book = BookFactory(title='Deering of Deal', summary=summary, subtitle='The Spirit of the School', authors=u'Latta Griswold', lang='en', cover__from_path=path, tags=['plane', 'aviation']) BookSpecimenFactory(book=book, serial="1234567") summary = (u"Le roman raconte les aventures d'un Gascon impécunieux " u"de 18 ans, d'Artagnan, venu à Paris pour faire carrière " u"dans le corps des mousquetaires. Il se lie d'amitié avec " u"Athos, Porthos et Aramis, mousquetaires du roi Louis " u"XIII. Ces quatre hommes vont s'opposer au premier " u"ministre, le cardinal de Richelieu et à ses agents, dont " u"le comte de Rochefort et la belle et mystérieuse Milady " u"de Winter, pour sauver l'honneur de la reine de France " u"Anne d'Autriche.") path = 'ideascube/tests/data/les-trois-mousquetaires.jpg' book = BookFactory(title='Les Trois Mousquetaires', summary=summary, authors=u'Alexandre Dumas', lang='fr', cover__from_path=path, tags=['roman', 'aventure']) BookSpecimenFactory(book=book, serial="98765479") summary = ("With the title of Sense and Sensibility is connected one " "of those minor problems which delight the cummin-splitters" " of criticism. In the Cecilia of Madame D'Arblay-the " "forerunner, if not the model, of Miss Austen-is a " "sentence which at first sight suggests some relationship " "to the name of the book which, in the present series, " "inaugurated Miss Austen's novels. 'The whole of this " "unfortunate business'-says a certain didactic Dr. Lyster, " "talking in capitals, towards the end of volume three of " "Cecilia-'has been the result of Pride and Prejudice,' and " "looking to the admitted familiarity of Miss Austen with " "Madame D'Arblay's work, it has been concluded that Miss " "Austen borrowed from Cecilia, the title of her second " "novel.") path = 'ideascube/tests/data/sense-and-sensibility.jpg' book = BookFactory(title='Sense and Sensibility', summary=summary, authors=u'Jane Austen', lang='en', cover__from_path=path, tags=['19th-century']) BookSpecimenFactory(book=book, serial="32657324") summary = (u"النبي (1923) أشهر كتب جبران كتبه بالإنجليزية وترجم إلى " u"أكثر من خمسين لغة، وهو يعتبر بحق رائعة جبران العالمية، " u"مضمونه اجتماعي، مثالي وتأملي فلسفي، وهو يحوي خلاصة " u"الاراء الجبرانية في الحب والزواج والأولاد والبيوت " u"والثياب والبيع والشراء والحرية والثانون والرحمة والعقاب " u"والدين والأخلاق والحياة والموت واللذة والجمال والكرم " u"والشرائع وغيرها، وقد وردت على لسان نبي سمي المصطفى " u"ورسالة النبي رسالة المتصوف المؤمن بوحدة الوجود، وبأن " u"الروح تتعطش للعودة إلى مصدرها، وبأن الحب جوهر الحياة. " u"وفي كتاب النبي يعبر جبران عن آرائه في الحياة عن طريق " u"معالجته للعلاقات الإنسانية التي تربط الإنسان بالإنسان.") path = 'ideascube/tests/data/the-prophet.jpg' book = BookFactory(title=u'النبي (كتاب)', summary=summary, authors=u'جبران خليل جبران', lang='ar', cover__from_path=path) BookSpecimenFactory(book=book, serial="3213542") title = (u"Déclaration des droits de l'homme et du citoyen " u"du 26 août 1789") summary = (u"Les Représentants du Peuple Français, constitués en " u"Assemblée Nationale, considérant que l'ignorance, " u"l'oubli ou le mépris des droits de l'Homme sont les " u"seules causes des malheurs publics et de la corruption " u"des Gouvernements, ont résolu d'exposer, dans une " u"Déclaration solennelle, les droits naturels, " u"inaliénables et sacrés de l'Homme, afin que cette " u"Déclaration, constamment présente à tous les Membres du " u"corps social, leur rappelle sans cesse leurs droits et " u"leurs devoirs ; afin que leurs actes du pouvoir " u"législatif, et ceux du pouvoir exécutif, pouvant être à " u"chaque instant comparés avec le but de toute institution " u"politique, en soient plus respectés ; afin que les " u"réclamations des citoyens, fondées désormais sur des " u"principes simples et incontestables, tournent toujours " u"au maintien de la Constitution et au bonheur de tous.") path = 'ideascube/tests/data/declaration-1789.pdf' DocumentFactory(title=title, original__from_path=path, summary=summary, tags=['history', 'France']) path = 'ideascube/tests/data/amelia-earhart.jpg' DocumentFactory(title="Picture of Amelia Earhart", original__from_path=path, tags=['plane', 'aviation']) self.stdout.write('Done.')