123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322 |
- from rest_framework.exceptions import ValidationError
- from django.contrib.auth import get_user_model
- from django.test import TestCase
- from misago.categories.models import Category
- from misago.threads import testutils
- from misago.threads.mergeconflict import MergeConflict
- UserModel = get_user_model()
- class MergeConflictTests(TestCase):
- def setUp(self):
- self.category = Category.objects.get(slug='first-category')
- self.user = UserModel.objects.create_user('bob', 'bob@test.com', 'Pass.123')
- def create_plain_thread(self):
- return testutils.post_thread(self.category)
- def create_poll_thread(self):
- thread = testutils.post_thread(self.category)
- testutils.post_poll(thread, self.user)
- return thread
- def create_best_answer_thread(self):
- thread = testutils.post_thread(self.category)
- best_answer = testutils.reply_thread(thread)
- thread.set_best_answer(self.user, best_answer)
- thread.synchronize()
- thread.save()
- return thread
- def test_plain_threads_no_conflicts(self):
- """threads without items of interest don't conflict"""
- threads = [self.create_plain_thread() for i in range(10)]
- merge_conflict = MergeConflict(threads=threads)
- self.assertFalse(merge_conflict.is_merge_conflict())
- self.assertEqual(merge_conflict.get_conflicting_fields(), [])
- merge_conflict.is_valid(raise_exception=True)
- self.assertEqual(merge_conflict.get_resolution(), {})
- def test_one_best_answer_one_plain(self):
- """thread with best answer and plain thread don't conflict"""
- threads = [
- self.create_best_answer_thread(),
- self.create_plain_thread(),
- ]
- merge_conflict = MergeConflict(threads=threads)
- self.assertFalse(merge_conflict.is_merge_conflict())
- self.assertEqual(merge_conflict.get_conflicting_fields(), [])
- merge_conflict.is_valid(raise_exception=True)
- self.assertEqual(merge_conflict.get_resolution(), {
- 'best_answer': threads[0],
- })
- def test_one_poll_one_plain(self):
- """thread with poll and plain thread don't conflict"""
- threads = [
- self.create_poll_thread(),
- self.create_plain_thread(),
- ]
- merge_conflict = MergeConflict(threads=threads)
- self.assertFalse(merge_conflict.is_merge_conflict())
- self.assertEqual(merge_conflict.get_conflicting_fields(), [])
- merge_conflict.is_valid(raise_exception=True)
- self.assertEqual(merge_conflict.get_resolution(), {
- 'poll': threads[0].poll,
- })
- def test_one_best_answer_one_poll(self):
- """thread with best answer and thread with poll don't conflict"""
- threads = [
- self.create_poll_thread(),
- self.create_best_answer_thread(),
- ]
- merge_conflict = MergeConflict(threads=threads)
- self.assertFalse(merge_conflict.is_merge_conflict())
- def test_one_best_answer_one_poll_one_plain(self):
- """thread with best answer, thread with poll and plain thread don't conflict"""
- threads = [
- self.create_plain_thread(),
- self.create_poll_thread(),
- self.create_best_answer_thread(),
- ]
- merge_conflict = MergeConflict(threads=threads)
- self.assertFalse(merge_conflict.is_merge_conflict())
- def test_three_best_answers_one_poll_two_plain_conflict(self):
- """three threads with best answer, thread with poll and two plain threads conflict"""
- best_answers = [self.create_best_answer_thread() for i in range(3)]
- polls = [self.create_poll_thread()]
- threads = [
- self.create_plain_thread(),
- self.create_plain_thread(),
- ] + best_answers + polls
- merge_conflict = MergeConflict(threads=threads)
- self.assertTrue(merge_conflict.is_merge_conflict())
- self.assertEqual(merge_conflict.get_conflicting_fields(), ['best_answer'])
- # without choice, conflict lists resolutions
- try:
- merge_conflict.is_valid(raise_exception=True)
- self.fail("merge_conflict.is_valid() should raise ValidationError")
- except ValidationError as e:
- self.assertTrue(merge_conflict.is_merge_conflict())
- self.assertEqual(merge_conflict.get_conflicting_fields(), ['best_answer'])
- self.assertEqual(e.detail, {
- 'best_answers': [['0', 'Unmark all best answers']] + [
- [
- str(thread.id),
- thread.title,
- ] for thread in best_answers
- ]
- })
- # conflict validates choice
- try:
- merge_conflict = MergeConflict({'best_answer': threads[0].id}, threads)
- merge_conflict.is_valid(raise_exception=True)
- self.fail("merge_conflict.is_valid() should raise ValidationError")
- except ValidationError as e:
- self.assertTrue(merge_conflict.is_merge_conflict())
- self.assertEqual(e.detail, {'best_answer': ['Invalid choice.']})
- # conflict returns selected resolution
- merge_conflict = MergeConflict({'best_answer': best_answers[0].id}, threads)
- self.assertTrue(merge_conflict.is_merge_conflict())
- self.assertEqual(merge_conflict.get_conflicting_fields(), ['best_answer'])
- merge_conflict.is_valid(raise_exception=True)
- self.assertEqual(merge_conflict.get_resolution(), {
- 'best_answer': best_answers[0],
- 'poll': polls[0].poll,
- })
- # conflict returns no-choice resolution
- merge_conflict = MergeConflict({'best_answer': 0}, threads)
- self.assertTrue(merge_conflict.is_merge_conflict())
- self.assertEqual(merge_conflict.get_conflicting_fields(), ['best_answer'])
- merge_conflict.is_valid(raise_exception=True)
- self.assertEqual(merge_conflict.get_resolution(), {
- 'best_answer': None,
- 'poll': polls[0].poll,
- })
- def test_one_best_answer_three_polls_two_plain_conflict(self):
- """one thread with best answer, three threads with poll and two plain threads conflict"""
- best_answers = [self.create_best_answer_thread()]
- polls = [self.create_poll_thread() for i in range(3)]
- threads = [
- self.create_plain_thread(),
- self.create_plain_thread(),
- ] + best_answers + polls
- merge_conflict = MergeConflict(threads=threads)
- self.assertTrue(merge_conflict.is_merge_conflict())
- self.assertEqual(merge_conflict.get_conflicting_fields(), ['poll'])
- # without choice, conflict lists resolutions
- try:
- merge_conflict.is_valid(raise_exception=True)
- self.fail("merge_conflict.is_valid() should raise ValidationError")
- except ValidationError as e:
- self.assertTrue(merge_conflict.is_merge_conflict())
- self.assertEqual(merge_conflict.get_conflicting_fields(), ['poll'])
- self.assertEqual(e.detail, {
- 'polls': [['0', 'Delete all polls']] + [
- [
- str(thread.poll.id),
- '{} ({})'.format(thread.poll.question, thread.title),
- ] for thread in polls
- ]
- })
- # conflict validates choice
- try:
- merge_conflict = MergeConflict({'poll': threads[0].id}, threads)
- merge_conflict.is_valid(raise_exception=True)
- self.fail("merge_conflict.is_valid() should raise ValidationError")
- except ValidationError as e:
- self.assertTrue(merge_conflict.is_merge_conflict())
- self.assertEqual(e.detail, {'poll': ['Invalid choice.']})
- # conflict returns selected resolution
- merge_conflict = MergeConflict({'poll': polls[0].poll.id}, threads)
- self.assertTrue(merge_conflict.is_merge_conflict())
- self.assertEqual(merge_conflict.get_conflicting_fields(), ['poll'])
- merge_conflict.is_valid(raise_exception=True)
- self.assertEqual(merge_conflict.get_resolution(), {
- 'best_answer': best_answers[0],
- 'poll': polls[0].poll,
- })
- # conflict returns no-choice resolution
- merge_conflict = MergeConflict({'poll': 0}, threads)
- self.assertTrue(merge_conflict.is_merge_conflict())
- self.assertEqual(merge_conflict.get_conflicting_fields(), ['poll'])
- merge_conflict.is_valid(raise_exception=True)
- self.assertEqual(merge_conflict.get_resolution(), {
- 'best_answer': best_answers[0],
- 'poll': None,
- })
- def test_three_best_answers_three_polls_two_plain_conflict(self):
- """multiple conflict is handled"""
- best_answers = [self.create_best_answer_thread() for i in range(3)]
- polls = [self.create_poll_thread() for i in range(3)]
- threads = [
- self.create_plain_thread(),
- self.create_plain_thread(),
- ] + best_answers + polls
- merge_conflict = MergeConflict(threads=threads)
- self.assertTrue(merge_conflict.is_merge_conflict())
- self.assertEqual(merge_conflict.get_conflicting_fields(), ['best_answer', 'poll'])
- # without choice, conflict lists all resolutions
- try:
- merge_conflict.is_valid(raise_exception=True)
- self.fail("merge_conflict.is_valid() should raise ValidationError")
- except ValidationError as e:
- self.assertTrue(merge_conflict.is_merge_conflict())
- self.assertEqual(merge_conflict.get_conflicting_fields(), ['best_answer', 'poll'])
- self.assertEqual(e.detail, {
- 'best_answers': [['0', 'Unmark all best answers']] + [
- [
- str(thread.id),
- thread.title,
- ] for thread in best_answers
- ],
- 'polls': [['0', 'Delete all polls']] + [
- [
- str(thread.poll.id),
- '{} ({})'.format(thread.poll.question, thread.title),
- ] for thread in polls
- ]
- })
- # conflict validates all choices if single choice was given
- try:
- merge_conflict = MergeConflict({'best_answer': threads[0].id}, threads)
- merge_conflict.is_valid(raise_exception=True)
- self.fail("merge_conflict.is_valid() should raise ValidationError")
- except ValidationError as e:
- self.assertTrue(merge_conflict.is_merge_conflict())
- self.assertEqual(e.detail, {
- 'best_answer': ['Invalid choice.'],
- 'poll': ['Invalid choice.'],
- })
- try:
- merge_conflict = MergeConflict({'poll': threads[0].id}, threads)
- merge_conflict.is_valid(raise_exception=True)
- self.fail("merge_conflict.is_valid() should raise ValidationError")
- except ValidationError as e:
- self.assertTrue(merge_conflict.is_merge_conflict())
- self.assertEqual(e.detail, {
- 'best_answer': ['Invalid choice.'],
- 'poll': ['Invalid choice.'],
- })
- # conflict validates all choices if all choices were given
- try:
- merge_conflict = MergeConflict({
- 'best_answer': threads[0].id,
- 'poll': threads[0].id,
- }, threads)
- merge_conflict.is_valid(raise_exception=True)
- self.fail("merge_conflict.is_valid() should raise ValidationError")
- except ValidationError as e:
- self.assertTrue(merge_conflict.is_merge_conflict())
- self.assertEqual(e.detail, {
- 'best_answer': ['Invalid choice.'],
- 'poll': ['Invalid choice.'],
- })
- # conflict returns selected resolutions
- valid_choices = {'best_answer': best_answers[0].id, 'poll': polls[0].poll.id}
- merge_conflict = MergeConflict(valid_choices, threads)
- self.assertTrue(merge_conflict.is_merge_conflict())
- self.assertEqual(merge_conflict.get_conflicting_fields(), ['best_answer', 'poll'])
- merge_conflict.is_valid(raise_exception=True)
- self.assertEqual(merge_conflict.get_resolution(), {
- 'best_answer': best_answers[0],
- 'poll': polls[0].poll,
- })
- # conflict returns no-choice resolution
- merge_conflict = MergeConflict({'best_answer': 0, 'poll': 0}, threads)
- self.assertTrue(merge_conflict.is_merge_conflict())
- self.assertEqual(merge_conflict.get_conflicting_fields(), ['best_answer', 'poll'])
- merge_conflict.is_valid(raise_exception=True)
- self.assertEqual(merge_conflict.get_resolution(), {
- 'best_answer': None,
- 'poll': None,
- })
- # conflict allows mixing no-choice with choice
- merge_conflict = MergeConflict({'best_answer': best_answers[0].id, 'poll': 0}, threads)
- self.assertTrue(merge_conflict.is_merge_conflict())
- self.assertEqual(merge_conflict.get_conflicting_fields(), ['best_answer', 'poll'])
- merge_conflict.is_valid(raise_exception=True)
- self.assertEqual(merge_conflict.get_resolution(), {
- 'best_answer': best_answers[0],
- 'poll': None,
- })
- merge_conflict = MergeConflict({'best_answer': 0, 'poll': polls[0].poll.id}, threads)
- self.assertTrue(merge_conflict.is_merge_conflict())
- self.assertEqual(merge_conflict.get_conflicting_fields(), ['best_answer', 'poll'])
- merge_conflict.is_valid(raise_exception=True)
- self.assertEqual(merge_conflict.get_resolution(), {
- 'best_answer': None,
- 'poll': polls[0].poll,
- })
|