1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690 |
- from functools import partial
- from django.test import TestCase
- from django.utils.safestring import SafeString
- from wagtail.admin import compare
- from wagtail.blocks import StreamValue
- from wagtail.images import get_image_model
- from wagtail.images.tests.utils import get_test_image_file
- from wagtail.test.testapp.models import (
- AdvertWithCustomPrimaryKey,
- EventCategory,
- EventPage,
- EventPageSpeaker,
- HeadCountRelatedModelUsingPK,
- SimplePage,
- SnippetChooserModelWithCustomPrimaryKey,
- StreamPage,
- TaggedPage,
- )
- class TestFieldComparison(TestCase):
- comparison_class = compare.FieldComparison
- def test_hasnt_changed(self):
- comparison = self.comparison_class(
- SimplePage._meta.get_field("content"),
- SimplePage(content="Content"),
- SimplePage(content="Content"),
- )
- self.assertTrue(comparison.is_field)
- self.assertFalse(comparison.is_child_relation)
- self.assertEqual(comparison.field_label(), "Content")
- self.assertEqual(comparison.htmldiff(), "Content")
- self.assertIsInstance(comparison.htmldiff(), SafeString)
- self.assertFalse(comparison.has_changed())
- def test_has_changed(self):
- comparison = self.comparison_class(
- SimplePage._meta.get_field("content"),
- SimplePage(content="Original content"),
- SimplePage(content="Modified content"),
- )
- self.assertEqual(
- comparison.htmldiff(),
- '<span class="deletion">Original content</span><span class="addition">Modified content</span>',
- )
- self.assertIsInstance(comparison.htmldiff(), SafeString)
- self.assertTrue(comparison.has_changed())
- def test_htmldiff_escapes_value(self):
- comparison = self.comparison_class(
- SimplePage._meta.get_field("content"),
- SimplePage(content="Original content"),
- SimplePage(
- content='<script type="text/javascript">doSomethingBad();</script>'
- ),
- )
- self.assertEqual(
- comparison.htmldiff(),
- '<span class="deletion">Original content</span><span class="addition"><script type="text/javascript">doSomethingBad();</script></span>',
- )
- self.assertIsInstance(comparison.htmldiff(), SafeString)
- class TestTextFieldComparison(TestFieldComparison):
- comparison_class = compare.TextFieldComparison
- # Only change from FieldComparison is the HTML diff is performed on words
- # instead of the whole field value.
- def test_has_changed(self):
- comparison = self.comparison_class(
- SimplePage._meta.get_field("content"),
- SimplePage(content="Original content"),
- SimplePage(content="Modified content"),
- )
- self.assertEqual(
- comparison.htmldiff(),
- '<span class="deletion">Original</span><span class="addition">Modified</span> content',
- )
- self.assertIsInstance(comparison.htmldiff(), SafeString)
- self.assertTrue(comparison.has_changed())
- def test_from_none_to_value_only_shows_addition(self):
- comparison = self.comparison_class(
- SimplePage._meta.get_field("content"),
- SimplePage(content=None),
- SimplePage(content="Added content"),
- )
- self.assertEqual(
- comparison.htmldiff(), '<span class="addition">Added content</span>'
- )
- self.assertIsInstance(comparison.htmldiff(), SafeString)
- self.assertTrue(comparison.has_changed())
- def test_from_value_to_none_only_shows_deletion(self):
- comparison = self.comparison_class(
- SimplePage._meta.get_field("content"),
- SimplePage(content="Removed content"),
- SimplePage(content=None),
- )
- self.assertEqual(
- comparison.htmldiff(), '<span class="deletion">Removed content</span>'
- )
- self.assertIsInstance(comparison.htmldiff(), SafeString)
- self.assertTrue(comparison.has_changed())
- class TestRichTextFieldComparison(TestFieldComparison):
- comparison_class = compare.RichTextFieldComparison
- # Only change from FieldComparison is the HTML diff is performed on words
- # instead of the whole field value.
- def test_has_changed(self):
- comparison = self.comparison_class(
- SimplePage._meta.get_field("content"),
- SimplePage(content="Original content"),
- SimplePage(content="Modified content"),
- )
- self.assertEqual(
- comparison.htmldiff(),
- '<span class="deletion">Original</span><span class="addition">Modified</span> content',
- )
- self.assertIsInstance(comparison.htmldiff(), SafeString)
- self.assertTrue(comparison.has_changed())
- # Only change from FieldComparison is that this comparison disregards HTML tags
- def test_has_changed_html(self):
- comparison = self.comparison_class(
- SimplePage._meta.get_field("content"),
- SimplePage(content="<b>Original</b> content"),
- SimplePage(content="Modified <i>content</i>"),
- )
- self.assertEqual(
- comparison.htmldiff(),
- '<span class="deletion">Original</span><span class="addition">Modified</span> content',
- )
- self.assertIsInstance(comparison.htmldiff(), SafeString)
- self.assertTrue(comparison.has_changed())
- def test_htmldiff_escapes_value(self):
- # Need to override this one as the HTML tags are stripped by RichTextFieldComparison
- comparison = self.comparison_class(
- SimplePage._meta.get_field("content"),
- SimplePage(content="Original content"),
- SimplePage(
- content='Do something good. <script type="text/javascript">doSomethingBad();</script>'
- ),
- )
- self.assertEqual(
- comparison.htmldiff(),
- '<span class="deletion">Original content</span><span class="addition">Do something good.</span>',
- )
- self.assertIsInstance(comparison.htmldiff(), SafeString)
- class TestStreamFieldComparison(TestCase):
- comparison_class = compare.StreamFieldComparison
- def test_hasnt_changed(self):
- field = StreamPage._meta.get_field("body")
- comparison = self.comparison_class(
- field,
- StreamPage(
- body=StreamValue(
- field.stream_block,
- [
- ("text", "Content", "1"),
- ],
- )
- ),
- StreamPage(
- body=StreamValue(
- field.stream_block,
- [
- ("text", "Content", "1"),
- ],
- )
- ),
- )
- self.assertTrue(comparison.is_field)
- self.assertFalse(comparison.is_child_relation)
- self.assertEqual(comparison.field_label(), "Body")
- self.assertEqual(
- comparison.htmldiff(), '<div class="comparison__child-object">Content</div>'
- )
- self.assertIsInstance(comparison.htmldiff(), SafeString)
- self.assertFalse(comparison.has_changed())
- def test_has_changed(self):
- field = StreamPage._meta.get_field("body")
- comparison = self.comparison_class(
- field,
- StreamPage(
- body=StreamValue(
- field.stream_block,
- [
- ("text", "Original content", "1"),
- ],
- )
- ),
- StreamPage(
- body=StreamValue(
- field.stream_block,
- [
- ("text", "Modified content", "1"),
- ],
- )
- ),
- )
- self.assertEqual(
- comparison.htmldiff(),
- '<div class="comparison__child-object"><span class="deletion">Original</span><span class="addition">Modified</span> content</div>',
- )
- self.assertIsInstance(comparison.htmldiff(), SafeString)
- self.assertTrue(comparison.has_changed())
- def test_add_block(self):
- field = StreamPage._meta.get_field("body")
- comparison = self.comparison_class(
- field,
- StreamPage(
- body=StreamValue(
- field.stream_block,
- [
- ("text", "Content", "1"),
- ],
- )
- ),
- StreamPage(
- body=StreamValue(
- field.stream_block,
- [
- ("text", "Content", "1"),
- ("text", "New Content", "2"),
- ],
- )
- ),
- )
- self.assertEqual(
- comparison.htmldiff(),
- '<div class="comparison__child-object">Content</div>\n<div class="comparison__child-object addition">New Content</div>',
- )
- self.assertIsInstance(comparison.htmldiff(), SafeString)
- self.assertTrue(comparison.has_changed())
- def test_delete_block(self):
- field = StreamPage._meta.get_field("body")
- comparison = self.comparison_class(
- field,
- StreamPage(
- body=StreamValue(
- field.stream_block,
- [
- ("text", "Content", "1"),
- ("text", "Content Foo", "2"),
- ("text", "Content Bar", "3"),
- ],
- )
- ),
- StreamPage(
- body=StreamValue(
- field.stream_block,
- [
- ("text", "Content", "1"),
- ("text", "Content Bar", "3"),
- ],
- )
- ),
- )
- self.assertEqual(
- comparison.htmldiff(),
- '<div class="comparison__child-object">Content</div>\n<div class="comparison__child-object deletion">Content Foo</div>\n<div class="comparison__child-object">Content Bar</div>',
- )
- self.assertIsInstance(comparison.htmldiff(), SafeString)
- self.assertTrue(comparison.has_changed())
- def test_edit_block(self):
- field = StreamPage._meta.get_field("body")
- comparison = self.comparison_class(
- field,
- StreamPage(
- body=StreamValue(
- field.stream_block,
- [
- ("text", "Content", "1"),
- ("text", "Content Foo", "2"),
- ("text", "Content Bar", "3"),
- ],
- )
- ),
- StreamPage(
- body=StreamValue(
- field.stream_block,
- [
- ("text", "Content", "1"),
- ("text", "Content Baz", "2"),
- ("text", "Content Bar", "3"),
- ],
- )
- ),
- )
- self.assertEqual(
- comparison.htmldiff(),
- '<div class="comparison__child-object">Content</div>\n<div class="comparison__child-object">Content <span class="deletion">Foo</span><span class="addition">Baz</span></div>\n<div class="comparison__child-object">Content Bar</div>',
- )
- self.assertIsInstance(comparison.htmldiff(), SafeString)
- self.assertTrue(comparison.has_changed())
- def test_has_changed_richtext(self):
- field = StreamPage._meta.get_field("body")
- comparison = self.comparison_class(
- field,
- StreamPage(
- body=StreamValue(
- field.stream_block,
- [
- ("rich_text", "<b>Original</b> content", "1"),
- ],
- )
- ),
- StreamPage(
- body=StreamValue(
- field.stream_block,
- [
- ("rich_text", "Modified <i>content</i>", "1"),
- ],
- )
- ),
- )
- self.assertEqual(
- comparison.htmldiff(),
- '<div class="comparison__child-object"><span class="deletion">Original</span><span class="addition">Modified</span> content</div>',
- )
- self.assertIsInstance(comparison.htmldiff(), SafeString)
- self.assertTrue(comparison.has_changed())
- def test_htmldiff_escapes_value_on_change(self):
- field = StreamPage._meta.get_field("body")
- comparison = self.comparison_class(
- field,
- StreamPage(
- body=StreamValue(
- field.stream_block,
- [
- (
- "text",
- "I <b>really</b> like original<i>ish</i> content",
- "1",
- ),
- ],
- )
- ),
- StreamPage(
- body=StreamValue(
- field.stream_block,
- [
- (
- "text",
- 'I <b>really</b> like evil code <script type="text/javascript">doSomethingBad();</script>',
- "1",
- ),
- ],
- )
- ),
- )
- self.assertEqual(
- comparison.htmldiff(),
- '<div class="comparison__child-object">I <b>really</b> like <span class="deletion">original<i>ish</i> content</span><span class="addition">evil code <script type="text/javascript">doSomethingBad();</script></span></div>',
- )
- self.assertIsInstance(comparison.htmldiff(), SafeString)
- def test_htmldiff_escapes_value_on_addition(self):
- field = StreamPage._meta.get_field("body")
- comparison = self.comparison_class(
- field,
- StreamPage(
- body=StreamValue(
- field.stream_block,
- [
- ("text", "Original <em>and unchanged</em> content", "1"),
- ],
- )
- ),
- StreamPage(
- body=StreamValue(
- field.stream_block,
- [
- ("text", "Original <em>and unchanged</em> content", "1"),
- (
- "text",
- '<script type="text/javascript">doSomethingBad();</script>',
- "2",
- ),
- ],
- )
- ),
- )
- self.assertEqual(
- comparison.htmldiff(),
- '<div class="comparison__child-object">Original <em>and unchanged</em> content</div>\n<div class="comparison__child-object addition"><script type="text/javascript">doSomethingBad();</script></div>',
- )
- self.assertIsInstance(comparison.htmldiff(), SafeString)
- def test_htmldiff_escapes_value_on_deletion(self):
- field = StreamPage._meta.get_field("body")
- comparison = self.comparison_class(
- field,
- StreamPage(
- body=StreamValue(
- field.stream_block,
- [
- ("text", "Original <em>and unchanged</em> content", "1"),
- (
- "text",
- '<script type="text/javascript">doSomethingBad();</script>',
- "2",
- ),
- ],
- )
- ),
- StreamPage(
- body=StreamValue(
- field.stream_block,
- [
- ("text", "Original <em>and unchanged</em> content", "1"),
- ],
- )
- ),
- )
- self.assertEqual(
- comparison.htmldiff(),
- '<div class="comparison__child-object">Original <em>and unchanged</em> content</div>\n<div class="comparison__child-object deletion"><script type="text/javascript">doSomethingBad();</script></div>',
- )
- self.assertIsInstance(comparison.htmldiff(), SafeString)
- def test_htmldiff_richtext_strips_tags_on_change(self):
- field = StreamPage._meta.get_field("body")
- comparison = self.comparison_class(
- field,
- StreamPage(
- body=StreamValue(
- field.stream_block,
- [
- ("rich_text", "I <b>really</b> like Wagtail <3", "1"),
- ],
- )
- ),
- StreamPage(
- body=StreamValue(
- field.stream_block,
- [
- (
- "rich_text",
- 'I <b>really</b> like evil code >_< <script type="text/javascript">doSomethingBad();</script>',
- "1",
- ),
- ],
- )
- ),
- )
- self.assertEqual(
- comparison.htmldiff(),
- '<div class="comparison__child-object">I really like <span class="deletion">Wagtail <3</span><span class="addition">evil code >_<</span></div>',
- )
- self.assertIsInstance(comparison.htmldiff(), SafeString)
- def test_htmldiff_richtext_strips_tags_on_addition(self):
- field = StreamPage._meta.get_field("body")
- comparison = self.comparison_class(
- field,
- StreamPage(
- body=StreamValue(
- field.stream_block,
- [
- ("rich_text", "Original <em>and unchanged</em> content", "1"),
- ],
- )
- ),
- StreamPage(
- body=StreamValue(
- field.stream_block,
- [
- ("rich_text", "Original <em>and unchanged</em> content", "1"),
- (
- "rich_text",
- 'I <b>really</b> like evil code >_< <script type="text/javascript">doSomethingBad();</script>',
- "2",
- ),
- ],
- )
- ),
- )
- self.assertEqual(
- comparison.htmldiff(),
- '<div class="comparison__child-object">Original and unchanged content</div>\n<div class="comparison__child-object addition">I really like evil code >_<</div>',
- )
- self.assertIsInstance(comparison.htmldiff(), SafeString)
- def test_htmldiff_richtext_strips_tags_on_deletion(self):
- field = StreamPage._meta.get_field("body")
- comparison = self.comparison_class(
- field,
- StreamPage(
- body=StreamValue(
- field.stream_block,
- [
- ("rich_text", "Original <em>and unchanged</em> content", "1"),
- (
- "rich_text",
- 'I <b>really</b> like evil code >_< <script type="text/javascript">doSomethingBad();</script>',
- "2",
- ),
- ],
- )
- ),
- StreamPage(
- body=StreamValue(
- field.stream_block,
- [
- ("rich_text", "Original <em>and unchanged</em> content", "1"),
- ],
- )
- ),
- )
- self.assertEqual(
- comparison.htmldiff(),
- '<div class="comparison__child-object">Original and unchanged content</div>\n<div class="comparison__child-object deletion">I really like evil code >_<</div>',
- )
- self.assertIsInstance(comparison.htmldiff(), SafeString)
- def test_htmldiff_raw_html_escapes_value_on_change(self):
- field = StreamPage._meta.get_field("body")
- comparison = self.comparison_class(
- field,
- StreamPage(
- body=StreamValue(
- field.stream_block,
- [
- ("raw_html", "Original<i>ish</i> content", "1"),
- ],
- )
- ),
- StreamPage(
- body=StreamValue(
- field.stream_block,
- [
- (
- "raw_html",
- '<script type="text/javascript">doSomethingBad();</script>',
- "1",
- ),
- ],
- )
- ),
- )
- self.assertEqual(
- comparison.htmldiff(),
- '<div class="comparison__child-object"><span class="deletion">Original<i>ish</i> content</span><span class="addition"><script type="text/javascript">doSomethingBad();</script></span></div>',
- )
- self.assertIsInstance(comparison.htmldiff(), SafeString)
- def test_htmldiff_raw_html_escapes_value_on_addition(self):
- field = StreamPage._meta.get_field("body")
- comparison = self.comparison_class(
- field,
- StreamPage(
- body=StreamValue(
- field.stream_block,
- [
- ("raw_html", "Original <em>and unchanged</em> content", "1"),
- ],
- )
- ),
- StreamPage(
- body=StreamValue(
- field.stream_block,
- [
- ("raw_html", "Original <em>and unchanged</em> content", "1"),
- (
- "raw_html",
- '<script type="text/javascript">doSomethingBad();</script>',
- "2",
- ),
- ],
- )
- ),
- )
- self.assertEqual(
- comparison.htmldiff(),
- '<div class="comparison__child-object">Original <em>and unchanged</em> content</div>\n<div class="comparison__child-object addition"><script type="text/javascript">doSomethingBad();</script></div>',
- )
- self.assertIsInstance(comparison.htmldiff(), SafeString)
- def test_htmldiff_raw_html_escapes_value_on_deletion(self):
- field = StreamPage._meta.get_field("body")
- comparison = self.comparison_class(
- field,
- StreamPage(
- body=StreamValue(
- field.stream_block,
- [
- ("raw_html", "Original <em>and unchanged</em> content", "1"),
- (
- "raw_html",
- '<script type="text/javascript">doSomethingBad();</script>',
- "2",
- ),
- ],
- )
- ),
- StreamPage(
- body=StreamValue(
- field.stream_block,
- [
- ("raw_html", "Original <em>and unchanged</em> content", "1"),
- ],
- )
- ),
- )
- self.assertEqual(
- comparison.htmldiff(),
- '<div class="comparison__child-object">Original <em>and unchanged</em> content</div>\n<div class="comparison__child-object deletion"><script type="text/javascript">doSomethingBad();</script></div>',
- )
- self.assertIsInstance(comparison.htmldiff(), SafeString)
- def test_compare_structblock(self):
- field = StreamPage._meta.get_field("body")
- comparison = self.comparison_class(
- field,
- StreamPage(
- body=StreamValue(
- field.stream_block,
- [
- ("product", {"name": "a packet of rolos", "price": "75p"}, "1"),
- ],
- )
- ),
- StreamPage(
- body=StreamValue(
- field.stream_block,
- [
- ("product", {"name": "a packet of rolos", "price": "85p"}, "1"),
- ],
- )
- ),
- )
- expected = """
- <div class="comparison__child-object"><dl>
- <dt>Name</dt>
- <dd>a packet of rolos</dd>
- <dt>Price</dt>
- <dd><span class="deletion">75p</span><span class="addition">85p</span></dd>
- </dl></div>
- """
- self.assertHTMLEqual(comparison.htmldiff(), expected)
- self.assertIsInstance(comparison.htmldiff(), SafeString)
- self.assertTrue(comparison.has_changed())
- def test_compare_listblock(self):
- field = StreamPage._meta.get_field("body")
- block = field.stream_block.child_blocks["title_list"]
- block_val = block.to_python(
- [
- {
- "type": "item",
- "value": "foo",
- "id": "11111111-1111-1111-1111-111111111111",
- },
- {
- "type": "item",
- "value": "bar",
- "id": "22222222-2222-2222-2222-222222222222",
- },
- ]
- )
- block_val_2 = block.to_python(
- [
- {
- "type": "item",
- "value": "bard",
- "id": "22222222-2222-2222-2222-222222222222",
- },
- {
- "type": "item",
- "value": "food",
- "id": "11111111-1111-1111-1111-111111111111",
- },
- ]
- )
- comparison = self.comparison_class(
- field,
- StreamPage(
- body=StreamValue(
- field.stream_block,
- [
- ("title_list", block_val, "1"),
- ],
- )
- ),
- StreamPage(
- body=StreamValue(
- field.stream_block,
- [
- ("title_list", block_val_2, "1"),
- ],
- )
- ),
- )
- htmldiff = comparison.htmldiff()
- expected = """
- <div class="comparison__child-object">
- <div class="comparison__child-object">
- <span class="deletion">bar</span>
- <span class="addition">bard</span>
- </div>\n
- <div class="comparison__child-object">
- <span class="deletion">foo</span>
- <span class="addition">food</span>
- </div>
- </div>
- """
- self.assertHTMLEqual(htmldiff, expected)
- self.assertIsInstance(htmldiff, SafeString)
- self.assertTrue(comparison.has_changed())
- def test_compare_listblock_old_format(self):
- field = StreamPage._meta.get_field("body")
- block = field.stream_block.child_blocks["title_list"]
- no_diff = """
- <div class="comparison__child-object">
- <div class="comparison__child-object">foo</div>\n
- <div class="comparison__child-object">bar</div>
- </div>
- """
- edit_and_add_diff = """
- <div class="comparison__child-object">
- <div class="comparison__child-object">
- foo
- </div>\n
- <div class="comparison__child-object">
- <span class="deletion">bar</span>
- <span class="addition">bap</span>
- </div>\n
- <div class="comparison__child-object addition">baz</div>
- </div>
- """
- edit_and_add_diff_reversed = """
- <div class="comparison__child-object">
- <div class="comparison__child-object">
- <span class="deletion">foo</span>
- <span class="addition">fo</span>
- </div>\n
- <div class="comparison__child-object">bar</div>\n
- <div class="comparison__child-object deletion">baz</div>
- </div>
- """
- old_format_listblock_fixtures = [
- (["foo", "bar"], ["foo", "bar"], no_diff),
- (["foo", "bar"], ["foo", "bap", "baz"], edit_and_add_diff),
- (["foo", "bar", "baz"], ["fo", "bar"], edit_and_add_diff_reversed),
- ]
- for list_1, list_2, expected_diff in old_format_listblock_fixtures:
- with self.subTest(list_1=list_1, list_2=list_2):
- block_val = block.to_python(list_1)
- block_val_2 = block.to_python(list_2)
- comparison = self.comparison_class(
- field,
- StreamPage(
- body=StreamValue(
- field.stream_block,
- [
- ("title_list", block_val, "1"),
- ],
- )
- ),
- StreamPage(
- body=StreamValue(
- field.stream_block,
- [
- ("title_list", block_val_2, "1"),
- ],
- )
- ),
- )
- htmldiff = comparison.htmldiff()
- self.assertHTMLEqual(htmldiff, expected_diff)
- self.assertIsInstance(htmldiff, SafeString)
- self.assertTrue(comparison.has_changed())
- def test_compare_nested_streamblock_uses_comparison_class(self):
- field = StreamPage._meta.get_field("body")
- stream_block = field.stream_block.child_blocks["books"]
- comparison = self.comparison_class(
- field,
- StreamPage(
- body=StreamValue(
- field.stream_block,
- [
- (
- "books",
- StreamValue(
- stream_block,
- [("title", "The Old Man and the Sea", "10")],
- ),
- "1",
- ),
- ],
- )
- ),
- StreamPage(
- body=StreamValue(
- field.stream_block,
- [
- (
- "books",
- StreamValue(
- stream_block, [("author", "Oscar Wilde", "11")]
- ),
- "1",
- ),
- ],
- )
- ),
- )
- expected = """
- <div class="comparison__child-object">
- <div class="comparison__child-object addition">Oscar Wilde</div>\n
- <div class="comparison__child-object deletion">The Old Man and the Sea</div>
- </div>
- """
- self.assertHTMLEqual(comparison.htmldiff(), expected)
- self.assertIsInstance(comparison.htmldiff(), SafeString)
- self.assertTrue(comparison.has_changed())
- def test_compare_imagechooserblock(self):
- image_model = get_image_model()
- test_image_1 = image_model.objects.create(
- title="Test image 1",
- file=get_test_image_file(),
- )
- test_image_2 = image_model.objects.create(
- title="Test image 2",
- file=get_test_image_file(),
- )
- field = StreamPage._meta.get_field("body")
- comparison = self.comparison_class(
- field,
- StreamPage(
- body=StreamValue(
- field.stream_block,
- [
- ("image", test_image_1, "1"),
- ],
- )
- ),
- StreamPage(
- body=StreamValue(
- field.stream_block,
- [
- ("image", test_image_2, "1"),
- ],
- )
- ),
- )
- result = comparison.htmldiff()
- self.assertIn('<div class="preview-image deletion">', result)
- self.assertIn('alt="Test image 1"', result)
- self.assertIn('<div class="preview-image addition">', result)
- self.assertIn('alt="Test image 2"', result)
- self.assertIsInstance(result, SafeString)
- self.assertTrue(comparison.has_changed())
- class TestChoiceFieldComparison(TestCase):
- comparison_class = compare.ChoiceFieldComparison
- def test_hasnt_changed(self):
- comparison = self.comparison_class(
- EventPage._meta.get_field("audience"),
- EventPage(audience="public"),
- EventPage(audience="public"),
- )
- self.assertTrue(comparison.is_field)
- self.assertFalse(comparison.is_child_relation)
- self.assertEqual(comparison.field_label(), "Audience")
- self.assertEqual(comparison.htmldiff(), "Public")
- self.assertIsInstance(comparison.htmldiff(), SafeString)
- self.assertFalse(comparison.has_changed())
- def test_has_changed(self):
- comparison = self.comparison_class(
- EventPage._meta.get_field("audience"),
- EventPage(audience="public"),
- EventPage(audience="private"),
- )
- self.assertEqual(
- comparison.htmldiff(),
- '<span class="deletion">Public</span><span class="addition">Private</span>',
- )
- self.assertIsInstance(comparison.htmldiff(), SafeString)
- self.assertTrue(comparison.has_changed())
- def test_from_none_to_value_only_shows_addition(self):
- comparison = self.comparison_class(
- EventPage._meta.get_field("audience"),
- EventPage(audience=None),
- EventPage(audience="private"),
- )
- self.assertEqual(comparison.htmldiff(), '<span class="addition">Private</span>')
- self.assertIsInstance(comparison.htmldiff(), SafeString)
- self.assertTrue(comparison.has_changed())
- def test_from_value_to_none_only_shows_deletion(self):
- comparison = self.comparison_class(
- EventPage._meta.get_field("audience"),
- EventPage(audience="public"),
- EventPage(audience=None),
- )
- self.assertEqual(comparison.htmldiff(), '<span class="deletion">Public</span>')
- self.assertIsInstance(comparison.htmldiff(), SafeString)
- self.assertTrue(comparison.has_changed())
- class TestTagsFieldComparison(TestCase):
- comparison_class = compare.TagsFieldComparison
- def test_hasnt_changed(self):
- a = TaggedPage()
- a.tags.add("wagtail")
- a.tags.add("bird")
- b = TaggedPage()
- b.tags.add("wagtail")
- b.tags.add("bird")
- comparison = self.comparison_class(TaggedPage._meta.get_field("tags"), a, b)
- self.assertTrue(comparison.is_field)
- self.assertFalse(comparison.is_child_relation)
- self.assertEqual(comparison.field_label(), "Tags")
- self.assertEqual(comparison.htmldiff(), "wagtail, bird")
- self.assertIsInstance(comparison.htmldiff(), SafeString)
- self.assertFalse(comparison.has_changed())
- def test_has_changed(self):
- a = TaggedPage()
- a.tags.add("wagtail")
- a.tags.add("bird")
- b = TaggedPage()
- b.tags.add("wagtail")
- b.tags.add("motacilla")
- comparison = self.comparison_class(TaggedPage._meta.get_field("tags"), a, b)
- self.assertEqual(
- comparison.htmldiff(),
- 'wagtail, <span class="deletion">bird</span>, <span class="addition">motacilla</span>',
- )
- self.assertIsInstance(comparison.htmldiff(), SafeString)
- self.assertTrue(comparison.has_changed())
- class TestM2MFieldComparison(TestCase):
- fixtures = ["test.json"]
- comparison_class = compare.M2MFieldComparison
- def setUp(self):
- self.meetings_category = EventCategory.objects.create(name="Meetings")
- self.parties_category = EventCategory.objects.create(name="Parties")
- self.holidays_category = EventCategory.objects.create(name="Holidays")
- def test_hasnt_changed(self):
- christmas_event = EventPage.objects.get(url_path="/home/events/christmas/")
- saint_patrick_event = EventPage.objects.get(
- url_path="/home/events/saint-patrick/"
- )
- christmas_event.categories = [self.meetings_category, self.parties_category]
- saint_patrick_event.categories = [self.meetings_category, self.parties_category]
- comparison = self.comparison_class(
- EventPage._meta.get_field("categories"),
- christmas_event,
- saint_patrick_event,
- )
- self.assertTrue(comparison.is_field)
- self.assertFalse(comparison.is_child_relation)
- self.assertEqual(comparison.field_label(), "Categories")
- self.assertFalse(comparison.has_changed())
- self.assertEqual(comparison.htmldiff(), "Meetings, Parties")
- self.assertIsInstance(comparison.htmldiff(), SafeString)
- def test_has_changed(self):
- christmas_event = EventPage.objects.get(url_path="/home/events/christmas/")
- saint_patrick_event = EventPage.objects.get(
- url_path="/home/events/saint-patrick/"
- )
- christmas_event.categories = [self.meetings_category, self.parties_category]
- saint_patrick_event.categories = [
- self.meetings_category,
- self.holidays_category,
- ]
- comparison = self.comparison_class(
- EventPage._meta.get_field("categories"),
- christmas_event,
- saint_patrick_event,
- )
- self.assertTrue(comparison.has_changed())
- self.assertEqual(
- comparison.htmldiff(),
- 'Meetings, <span class="deletion">Parties</span>, <span class="addition">Holidays</span>',
- )
- self.assertIsInstance(comparison.htmldiff(), SafeString)
- class TestForeignObjectComparison(TestCase):
- comparison_class = compare.ForeignObjectComparison
- @classmethod
- def setUpTestData(cls):
- image_model = get_image_model()
- cls.test_image_1 = image_model.objects.create(
- title="Test image 1",
- file=get_test_image_file(),
- )
- cls.test_image_2 = image_model.objects.create(
- title="Test image 2",
- file=get_test_image_file(),
- )
- def test_hasnt_changed(self):
- comparison = self.comparison_class(
- EventPage._meta.get_field("feed_image"),
- EventPage(feed_image=self.test_image_1),
- EventPage(feed_image=self.test_image_1),
- )
- self.assertTrue(comparison.is_field)
- self.assertFalse(comparison.is_child_relation)
- self.assertEqual(comparison.field_label(), "Feed image")
- self.assertEqual(comparison.htmldiff(), "Test image 1")
- self.assertIsInstance(comparison.htmldiff(), SafeString)
- self.assertFalse(comparison.has_changed())
- def test_has_changed(self):
- comparison = self.comparison_class(
- EventPage._meta.get_field("feed_image"),
- EventPage(feed_image=self.test_image_1),
- EventPage(feed_image=self.test_image_2),
- )
- self.assertEqual(
- comparison.htmldiff(),
- '<span class="deletion">Test image 1</span><span class="addition">Test image 2</span>',
- )
- self.assertIsInstance(comparison.htmldiff(), SafeString)
- self.assertTrue(comparison.has_changed())
- class TestForeignObjectComparisonWithCustomPK(TestCase):
- """ForeignObjectComparison works with models declaring a custom primary key field"""
- comparison_class = compare.ForeignObjectComparison
- @classmethod
- def setUpTestData(cls):
- ad1 = AdvertWithCustomPrimaryKey.objects.create(
- advert_id="ad1", text="Advert 1"
- )
- ad2 = AdvertWithCustomPrimaryKey.objects.create(
- advert_id="ad2", text="Advert 2"
- )
- cls.test_obj_1 = SnippetChooserModelWithCustomPrimaryKey.objects.create(
- advertwithcustomprimarykey=ad1
- )
- cls.test_obj_2 = SnippetChooserModelWithCustomPrimaryKey.objects.create(
- advertwithcustomprimarykey=ad2
- )
- def test_hasnt_changed(self):
- comparison = self.comparison_class(
- SnippetChooserModelWithCustomPrimaryKey._meta.get_field(
- "advertwithcustomprimarykey"
- ),
- self.test_obj_1,
- self.test_obj_1,
- )
- self.assertTrue(comparison.is_field)
- self.assertFalse(comparison.is_child_relation)
- self.assertEqual(comparison.field_label(), "Advertwithcustomprimarykey")
- self.assertEqual(comparison.htmldiff(), "Advert 1")
- self.assertIsInstance(comparison.htmldiff(), SafeString)
- self.assertFalse(comparison.has_changed())
- def test_has_changed(self):
- comparison = self.comparison_class(
- SnippetChooserModelWithCustomPrimaryKey._meta.get_field(
- "advertwithcustomprimarykey"
- ),
- self.test_obj_1,
- self.test_obj_2,
- )
- self.assertEqual(
- comparison.htmldiff(),
- '<span class="deletion">Advert 1</span><span class="addition">Advert 2</span>',
- )
- self.assertIsInstance(comparison.htmldiff(), SafeString)
- self.assertTrue(comparison.has_changed())
- class TestChildRelationComparison(TestCase):
- field_comparison_class = compare.FieldComparison
- comparison_class = compare.ChildRelationComparison
- def test_hasnt_changed(self):
- # Two event pages with speaker called "Father Christmas". Neither of
- # the speaker objects have an ID so this tests that the code can match
- # the two together by field content.
- event_page = EventPage(title="Event page", slug="event")
- event_page.speakers.add(
- EventPageSpeaker(
- first_name="Father",
- last_name="Christmas",
- )
- )
- modified_event_page = EventPage(title="Event page", slug="event")
- modified_event_page.speakers.add(
- EventPageSpeaker(
- first_name="Father",
- last_name="Christmas",
- )
- )
- comparison = self.comparison_class(
- EventPage._meta.get_field("speaker"),
- [
- partial(
- self.field_comparison_class,
- EventPageSpeaker._meta.get_field("first_name"),
- ),
- partial(
- self.field_comparison_class,
- EventPageSpeaker._meta.get_field("last_name"),
- ),
- ],
- event_page,
- modified_event_page,
- )
- self.assertFalse(comparison.is_field)
- self.assertTrue(comparison.is_child_relation)
- self.assertEqual(comparison.field_label(), "Speaker")
- self.assertFalse(comparison.has_changed())
- # Check mapping
- objs_a = list(comparison.val_a.all())
- objs_b = list(comparison.val_b.all())
- map_forwards, map_backwards, added, deleted = comparison.get_mapping(
- objs_a, objs_b
- )
- self.assertEqual(map_forwards, {0: 0})
- self.assertEqual(map_backwards, {0: 0})
- self.assertEqual(added, [])
- self.assertEqual(deleted, [])
- def test_has_changed(self):
- # Father Christmas renamed to Santa Claus. And Father Ted added.
- # Father Christmas should be mapped to Father Ted because they
- # are most alike. Santa Claus should be displayed as "new"
- event_page = EventPage(title="Event page", slug="event")
- event_page.speakers.add(
- EventPageSpeaker(
- first_name="Father",
- last_name="Christmas",
- sort_order=0,
- )
- )
- modified_event_page = EventPage(title="Event page", slug="event")
- modified_event_page.speakers.add(
- EventPageSpeaker(
- first_name="Santa",
- last_name="Claus",
- sort_order=0,
- )
- )
- modified_event_page.speakers.add(
- EventPageSpeaker(
- first_name="Father",
- last_name="Ted",
- sort_order=1,
- )
- )
- comparison = self.comparison_class(
- EventPage._meta.get_field("speaker"),
- [
- partial(
- self.field_comparison_class,
- EventPageSpeaker._meta.get_field("first_name"),
- ),
- partial(
- self.field_comparison_class,
- EventPageSpeaker._meta.get_field("last_name"),
- ),
- ],
- event_page,
- modified_event_page,
- )
- self.assertFalse(comparison.is_field)
- self.assertTrue(comparison.is_child_relation)
- self.assertEqual(comparison.field_label(), "Speaker")
- self.assertTrue(comparison.has_changed())
- # Check mapping
- objs_a = list(comparison.val_a.all())
- objs_b = list(comparison.val_b.all())
- map_forwards, map_backwards, added, deleted = comparison.get_mapping(
- objs_a, objs_b
- )
- self.assertEqual(map_forwards, {0: 1}) # Map Father Christmas to Father Ted
- self.assertEqual(map_backwards, {1: 0}) # Map Father Ted to Father Christmas
- self.assertEqual(added, [0]) # Add Santa Claus
- self.assertEqual(deleted, [])
- def test_has_changed_with_same_id(self):
- # Father Christmas renamed to Santa Claus, but this time the ID of the
- # child object remained the same. It should now be detected as the same
- # object
- event_page = EventPage(title="Event page", slug="event")
- event_page.speakers.add(
- EventPageSpeaker(
- id=1,
- first_name="Father",
- last_name="Christmas",
- sort_order=0,
- )
- )
- modified_event_page = EventPage(title="Event page", slug="event")
- modified_event_page.speakers.add(
- EventPageSpeaker(
- id=1,
- first_name="Santa",
- last_name="Claus",
- sort_order=0,
- )
- )
- modified_event_page.speakers.add(
- EventPageSpeaker(
- first_name="Father",
- last_name="Ted",
- sort_order=1,
- )
- )
- comparison = self.comparison_class(
- EventPage._meta.get_field("speaker"),
- [
- partial(
- self.field_comparison_class,
- EventPageSpeaker._meta.get_field("first_name"),
- ),
- partial(
- self.field_comparison_class,
- EventPageSpeaker._meta.get_field("last_name"),
- ),
- ],
- event_page,
- modified_event_page,
- )
- self.assertFalse(comparison.is_field)
- self.assertTrue(comparison.is_child_relation)
- self.assertEqual(comparison.field_label(), "Speaker")
- self.assertTrue(comparison.has_changed())
- # Check mapping
- objs_a = list(comparison.val_a.all())
- objs_b = list(comparison.val_b.all())
- map_forwards, map_backwards, added, deleted = comparison.get_mapping(
- objs_a, objs_b
- )
- self.assertEqual(map_forwards, {0: 0}) # Map Father Christmas to Santa Claus
- self.assertEqual(map_backwards, {0: 0}) # Map Santa Claus to Father Christmas
- self.assertEqual(added, [1]) # Add Father Ted
- self.assertEqual(deleted, [])
- def test_hasnt_changed_with_different_id(self):
- # Both of the child objects have the same field content but have a
- # different ID so they should be detected as separate objects
- event_page = EventPage(title="Event page", slug="event")
- event_page.speakers.add(
- EventPageSpeaker(
- id=1,
- first_name="Father",
- last_name="Christmas",
- )
- )
- modified_event_page = EventPage(title="Event page", slug="event")
- modified_event_page.speakers.add(
- EventPageSpeaker(
- id=2,
- first_name="Father",
- last_name="Christmas",
- )
- )
- comparison = self.comparison_class(
- EventPage._meta.get_field("speaker"),
- [
- partial(
- self.field_comparison_class,
- EventPageSpeaker._meta.get_field("first_name"),
- ),
- partial(
- self.field_comparison_class,
- EventPageSpeaker._meta.get_field("last_name"),
- ),
- ],
- event_page,
- modified_event_page,
- )
- self.assertFalse(comparison.is_field)
- self.assertTrue(comparison.is_child_relation)
- self.assertEqual(comparison.field_label(), "Speaker")
- self.assertTrue(comparison.has_changed())
- # Check mapping
- objs_a = list(comparison.val_a.all())
- objs_b = list(comparison.val_b.all())
- map_forwards, map_backwards, added, deleted = comparison.get_mapping(
- objs_a, objs_b
- )
- self.assertEqual(map_forwards, {})
- self.assertEqual(map_backwards, {})
- self.assertEqual(added, [0]) # Add new Father Christmas
- self.assertEqual(deleted, [0]) # Delete old Father Christmas
- def test_panel_label_as_field_label(self):
- # Just to check whether passing `label` changes field_label
- event_page = EventPage(title="Event page", slug="event")
- event_page.speakers.add(
- EventPageSpeaker(
- first_name="Father",
- )
- )
- comparison = self.comparison_class(
- EventPage._meta.get_field("speaker"),
- [
- partial(
- self.field_comparison_class,
- EventPageSpeaker._meta.get_field("first_name"),
- )
- ],
- event_page,
- event_page,
- label="Speakers",
- )
- self.assertEqual(comparison.field_label(), "Speakers")
- class TestChildObjectComparison(TestCase):
- field_comparison_class = compare.FieldComparison
- comparison_class = compare.ChildObjectComparison
- def test_same_object(self):
- obj_a = EventPageSpeaker(
- first_name="Father",
- last_name="Christmas",
- )
- obj_b = EventPageSpeaker(
- first_name="Father",
- last_name="Christmas",
- )
- comparison = self.comparison_class(
- EventPageSpeaker,
- [
- partial(
- self.field_comparison_class,
- EventPageSpeaker._meta.get_field("first_name"),
- ),
- partial(
- self.field_comparison_class,
- EventPageSpeaker._meta.get_field("last_name"),
- ),
- ],
- obj_a,
- obj_b,
- )
- self.assertFalse(comparison.is_addition())
- self.assertFalse(comparison.is_deletion())
- self.assertFalse(comparison.has_changed())
- self.assertEqual(comparison.get_position_change(), 0)
- self.assertEqual(comparison.get_num_differences(), 0)
- def test_different_object(self):
- obj_a = EventPageSpeaker(
- first_name="Father",
- last_name="Christmas",
- )
- obj_b = EventPageSpeaker(
- first_name="Santa",
- last_name="Claus",
- )
- comparison = self.comparison_class(
- EventPageSpeaker,
- [
- partial(
- self.field_comparison_class,
- EventPageSpeaker._meta.get_field("first_name"),
- ),
- partial(
- self.field_comparison_class,
- EventPageSpeaker._meta.get_field("last_name"),
- ),
- ],
- obj_a,
- obj_b,
- )
- self.assertFalse(comparison.is_addition())
- self.assertFalse(comparison.is_deletion())
- self.assertTrue(comparison.has_changed())
- self.assertEqual(comparison.get_position_change(), 0)
- self.assertEqual(comparison.get_num_differences(), 2)
- def test_moved_object(self):
- obj_a = EventPageSpeaker(
- first_name="Father",
- last_name="Christmas",
- sort_order=1,
- )
- obj_b = EventPageSpeaker(
- first_name="Father",
- last_name="Christmas",
- sort_order=5,
- )
- comparison = self.comparison_class(
- EventPageSpeaker,
- [
- partial(
- self.field_comparison_class,
- EventPageSpeaker._meta.get_field("first_name"),
- ),
- partial(
- self.field_comparison_class,
- EventPageSpeaker._meta.get_field("last_name"),
- ),
- ],
- obj_a,
- obj_b,
- )
- self.assertFalse(comparison.is_addition())
- self.assertFalse(comparison.is_deletion())
- self.assertFalse(comparison.has_changed())
- self.assertEqual(comparison.get_position_change(), 4)
- self.assertEqual(comparison.get_num_differences(), 0)
- def test_addition(self):
- obj = EventPageSpeaker(
- first_name="Father",
- last_name="Christmas",
- )
- comparison = self.comparison_class(
- EventPageSpeaker,
- [
- partial(
- self.field_comparison_class,
- EventPageSpeaker._meta.get_field("first_name"),
- ),
- partial(
- self.field_comparison_class,
- EventPageSpeaker._meta.get_field("last_name"),
- ),
- ],
- None,
- obj,
- )
- self.assertTrue(comparison.is_addition())
- self.assertFalse(comparison.is_deletion())
- self.assertFalse(comparison.has_changed())
- self.assertIsNone(comparison.get_position_change(), 0)
- self.assertEqual(comparison.get_num_differences(), 0)
- def test_deletion(self):
- obj = EventPageSpeaker(
- first_name="Father",
- last_name="Christmas",
- )
- comparison = self.comparison_class(
- EventPageSpeaker,
- [
- partial(
- self.field_comparison_class,
- EventPageSpeaker._meta.get_field("first_name"),
- ),
- partial(
- self.field_comparison_class,
- EventPageSpeaker._meta.get_field("last_name"),
- ),
- ],
- obj,
- None,
- )
- self.assertFalse(comparison.is_addition())
- self.assertTrue(comparison.is_deletion())
- self.assertFalse(comparison.has_changed())
- self.assertIsNone(comparison.get_position_change())
- self.assertEqual(comparison.get_num_differences(), 0)
- class TestChildRelationComparisonUsingPK(TestCase):
- """Test related objects can be compred if they do not use id for primary key"""
- field_comparison_class = compare.FieldComparison
- comparison_class = compare.ChildRelationComparison
- def test_has_changed_with_same_id(self):
- # Head Count was changed but the PK of the child object remained the same.
- # It should be detected as the same object
- event_page = EventPage(title="Semi Finals", slug="semi-finals-2018")
- event_page.head_counts.add(
- HeadCountRelatedModelUsingPK(
- custom_id=1,
- head_count=22,
- )
- )
- modified_event_page = EventPage(title="Semi Finals", slug="semi-finals-2018")
- modified_event_page.head_counts.add(
- HeadCountRelatedModelUsingPK(
- custom_id=1,
- head_count=23,
- )
- )
- modified_event_page.head_counts.add(
- HeadCountRelatedModelUsingPK(
- head_count=25,
- )
- )
- comparison = self.comparison_class(
- EventPage._meta.get_field("head_counts"),
- [
- partial(
- self.field_comparison_class,
- HeadCountRelatedModelUsingPK._meta.get_field("head_count"),
- )
- ],
- event_page,
- modified_event_page,
- )
- self.assertFalse(comparison.is_field)
- self.assertTrue(comparison.is_child_relation)
- self.assertEqual(comparison.field_label(), "Head counts")
- self.assertTrue(comparison.has_changed())
- # Check mapping
- objs_a = list(comparison.val_a.all())
- objs_b = list(comparison.val_b.all())
- map_forwards, map_backwards, added, deleted = comparison.get_mapping(
- objs_a, objs_b
- )
- self.assertEqual(map_forwards, {0: 0}) # map head count 22 to 23
- self.assertEqual(map_backwards, {0: 0}) # map head count 23 to 22
- self.assertEqual(added, [1]) # add second head count
- self.assertEqual(deleted, [])
- def test_hasnt_changed_with_different_id(self):
- # Both of the child objects have the same field content but have a
- # different PK (ID) so they should be detected as separate objects
- event_page = EventPage(title="Finals", slug="finals-event-abc")
- event_page.head_counts.add(
- HeadCountRelatedModelUsingPK(custom_id=1, head_count=220)
- )
- modified_event_page = EventPage(title="Finals", slug="finals-event-abc")
- modified_event_page.head_counts.add(
- HeadCountRelatedModelUsingPK(custom_id=2, head_count=220)
- )
- comparison = self.comparison_class(
- EventPage._meta.get_field("head_counts"),
- [
- partial(
- self.field_comparison_class,
- HeadCountRelatedModelUsingPK._meta.get_field("head_count"),
- )
- ],
- event_page,
- modified_event_page,
- )
- self.assertFalse(comparison.is_field)
- self.assertTrue(comparison.is_child_relation)
- self.assertEqual(comparison.field_label(), "Head counts")
- self.assertTrue(comparison.has_changed())
- # Check mapping
- objs_a = list(comparison.val_a.all())
- objs_b = list(comparison.val_b.all())
- map_forwards, map_backwards, added, deleted = comparison.get_mapping(
- objs_a, objs_b
- )
- self.assertEqual(map_forwards, {})
- self.assertEqual(map_backwards, {})
- self.assertEqual(added, [0]) # Add new head count
- self.assertEqual(deleted, [0]) # Delete old head count
|