def test_url_showings_detail_positive_patch_admin(self):
        """
        Positive test checks response for admin's PATCH request to /showings/<int:pk>/
        """
        showing = Showing(hall=self.hall, movie=self.movie,
                          date_time=datetime.datetime(2019, 11, 25, 9, 0, 0, 1,
                                                      tzinfo=datetime.timezone.utc),
                          price='9.99')
        showing.save()

        input_data = {
            'price': '4.99'
        }
        response = self.client.patch(path=reverse('showing-detail', args=[showing.pk]),
                                     data=input_data,
                                     content_type='application/json',
                                     HTTP_AUTHORIZATION=f'Bearer {self.admin_token}')
        expected_response = {
            'id': showing.pk,
            'hall': self.hall.pk,
            'movie': self.movie.pk,
            'price': input_data['price'],
            'date_time': showing.date_time.isoformat()[:-3] + showing.date_time.isoformat()[-2:],
        }
        self.assertEqual(response.status_code, status.HTTP_200_OK)
        self.assertDictEqual(response.data, expected_response)
 def setUp(self) -> None:
     super(ShowingsDetailNegativeTestCase, self).setUp()
     self.showing = Showing(hall=self.hall, movie=self.movie,
                            date_time=datetime.datetime(2019, 12, 14, 10, 0,
                                                        tzinfo=datetime.timezone.utc),
                            price=9.99)
     self.showing.save()
class TicketsBaseTestCase(LoggedInTestCase):
    """
    Base test case prepares movie and hall instances for test tickets
    """
    def setUp(self) -> None:
        super(TicketsBaseTestCase, self).setUp()
        self.movie = Movie(name='Movie', duration=120, premiere_year=1999)
        self.movie.save()
        self.hall = Hall(name='Hall', rows_count=16, rows_size=20)
        self.hall.save()
        show_time = \
            datetime.datetime(2019, 12, 24, 10, 0, 0, 1, tzinfo=datetime.timezone.utc) + \
            datetime.timedelta(10)
        self.showing = Showing(hall=self.hall,
                               movie=self.movie,
                               date_time=show_time,
                               price='19.99')
        self.showing.save()
        ticket_time = show_time - datetime.timedelta(10)
        self.ticket = Ticket(showing=self.showing,
                             user=self.user,
                             date_time=ticket_time,
                             row_number=1,
                             seat_number=1)
        self.ticket.save()
    def test_url_tickets_detail_negative_modify_paid_ticket(self):
        """
        Negative test checks that it's impossible to modify paid ticket
        """
        showtime = datetime.datetime.now(
            tz=datetime.timezone.utc) - datetime.timedelta(days=2)
        showing = Showing(movie=self.movie,
                          date_time=showtime,
                          hall=self.hall,
                          price='9.99')
        showing.save()
        changes = {
            'showing': showing.pk,
            'row_number': 1,
            'seat_number': 1,
            'user': self.admin.pk,
        }

        self.ticket.receipt = 'receipt: ticket paid'
        self.ticket.save()
        ticket_date_time = self.ticket.date_time
        expected_data = {
            'id':
            self.ticket.pk,
            'showing':
            self.ticket.showing.pk,
            'row_number':
            self.ticket.row_number,
            'seat_number':
            self.ticket.seat_number,
            'user':
            self.ticket.user.pk,
            'paid':
            bool(self.ticket.receipt),
            'receipt':
            self.ticket.receipt,
            'date_time':
            ticket_date_time.isoformat()[:-3] +
            ticket_date_time.isoformat()[-2:],
            'price':
            Decimal(self.ticket.showing.price)
        }
        response = self.client.put(
            path=reverse('ticket-detail', args=[self.ticket.pk]),
            data=changes,
            content_type='application/json',
            HTTP_AUTHORIZATION=f'Bearer {self.user_token}')
        self.assertEqual(response.status_code, status.HTTP_200_OK)
        self.assertDictEqual(response.data, expected_data)

        for field, new_value in changes.items():
            response = self.client.patch(
                path=reverse('ticket-detail', args=[self.ticket.pk]),
                data={field: new_value},
                content_type='application/json',
                HTTP_AUTHORIZATION=f'Bearer {self.user_token}')
            self.assertEqual(response.status_code, status.HTTP_200_OK)
            self.assertDictEqual(response.data, expected_data)
 def test_url_showings_detail_positive_delete_admin(self):
     """
     Positive test checks response for admin's DELETE request to /showings/<int:pk>/
     """
     showing = Showing(hall=self.hall, movie=self.movie,
                       date_time=datetime.datetime(2019, 11, 25, 9, 0,
                                                   tzinfo=datetime.timezone.utc),
                       price='9.99')
     showing.save()
     response = self.client.delete(path=reverse('showing-detail', args=[showing.pk]),
                                   content_type='application/json',
                                   HTTP_AUTHORIZATION=f'Bearer {self.admin_token}')
     self.assertEqual(response.status_code, status.HTTP_204_NO_CONTENT)
 def setUp(self) -> None:
     super(ShowingsListNegativeTestCase, self).setUp()
     self.url_list = reverse('showing-list')
     showings = [Showing(hall_id=hall_id, movie=self.movie,
                         date_time=datetime.datetime(2019, 12, 14, 10, 0,
                                                     tzinfo=datetime.timezone.utc).isoformat(),
                         price=9.99) for hall_id in [1, 2, 3]]
     Showing.objects.bulk_create(showings)
     self.showings = list(Showing.objects.all())
    def test_url_showings_detail_positive_get(self):
        """
        Positive test checks response for GET request to /showings/<int:pk>/
        """
        showing = Showing(hall=self.hall, movie=self.movie,
                          date_time=datetime.datetime(2019, 11, 25, 9, 0, 0, 1,
                                                      tzinfo=datetime.timezone.utc),
                          price='9.99')
        showing.save()

        expected_response = {
            'id': showing.pk,
            'hall': self.hall.pk,
            'movie': self.movie.pk,
            'price': showing.price,
            'date_time': showing.date_time.isoformat()[:-3] + showing.date_time.isoformat()[-2:],
        }
        response = self.client.get(path=reverse('showing-detail', args=[showing.pk]))
        self.assertEqual(response.status_code, status.HTTP_200_OK)
        self.assertDictEqual(response.data, expected_response)
class ShowingsDetailNegativeTestCase(ShowingsBaseTestCase):
    """
    Negative test case for showing detail: /showings/<int:pk>/
    """

    def setUp(self) -> None:
        super(ShowingsDetailNegativeTestCase, self).setUp()
        self.showing = Showing(hall=self.hall, movie=self.movie,
                               date_time=datetime.datetime(2019, 12, 14, 10, 0,
                                                           tzinfo=datetime.timezone.utc),
                               price=9.99)
        self.showing.save()

    def test_url_showings_detail_negative_get_unknown(self):
        """
        Negative test checks 404 status code on /showings/<not existing hall>
        """
        response = self.client.get(path=reverse('showing-detail', args=[100]))
        self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND)

    def test_url_showings_detail_negative_put_user(self):
        """
        Negative test checks that users cannot modify showings via PUT requests
        """
        input_data = {
            'price': 2.0,
        }
        response = self.client.put(path=reverse('showing-detail', args=[self.showing.pk]),
                                   data=input_data,
                                   content_type='application/json',
                                   HTTP_AUTHORIZATION=f'Bearer {self.user_token}')
        self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN)

    def test_url_showings_detail_negative_put_unauthorized(self):
        """
        Negative test checks that anonymous users cannot modify showings via PUT requests
        """
        input_data = {
            'date_time': datetime.datetime.now(tz=datetime.timezone.utc),
            'hall': self.hall.pk + 1,
            'movie': self.movie.pk + 1,
            'price': 2.0
        }
        response = self.client.put(path=reverse('movie-detail', args=[self.showing.pk]),
                                   data=input_data,
                                   content_type='application/json')
        self.assertEqual(response.status_code, status.HTTP_401_UNAUTHORIZED)

    def test_url_showing_detail_negative_patch_user(self):
        """
        Negative test checks that users cannot modify showing via PATCH requests
        """
        input_data = {
            'date_time': datetime.datetime.now(tz=datetime.timezone.utc),
            'hall': self.hall.pk + 1,
            'movie': self.movie.pk + 1,
            'price': 2.0
        }
        response = self.client.patch(path=reverse('showing-detail', args=[self.showing.pk]),
                                     data=input_data,
                                     content_type='application/json',
                                     HTTP_AUTHORIZATION=f'Bearer {self.user_token}')
        self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN)

    def test_url_showings_detail_negative_patch_unauthorized(self):
        """
        Negative test checks that anonymous users cannot modify showings via PATCH requests
        """
        input_data = {
            'date_time': datetime.datetime.now(tz=datetime.timezone.utc),
            'hall': self.hall.pk + 1,
            'movie': self.movie.pk + 1,
            'price': 2.0
        }
        response = self.client.patch(path=reverse('showing-detail', args=[self.showing.pk]),
                                     data=input_data,
                                     content_type='application/json')
        self.assertEqual(response.status_code, status.HTTP_401_UNAUTHORIZED)

    def test_url_showing_detail_negative_patch_incorrect_input(self):
        """
        Negative test checks incorrect input while modifying showings
        """
        incorrect_date =\
            datetime.datetime(self.showing.movie.premiere_year, 1, 1, 10, 0,
                              tzinfo=datetime.timezone.utc) - datetime.timedelta(20)
        input_data = {
            'date_time': incorrect_date.isoformat()
        }
        response = self.client.patch(path=reverse('showing-detail', args=[self.showing.pk]),
                                     data=input_data,
                                     content_type='application/json',
                                     HTTP_AUTHORIZATION=f'Bearer {self.admin_token}')
        self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)

    def test_url_showings_detail_negative_delete_user(self):
        """
        Negative test checks that users cannot delete showings
        """
        response = self.client.delete(path=reverse('showing-detail', args=[self.showing.pk]),
                                      HTTP_AUTHORIZATION=f'Bearer {self.user_token}')

        self.showing.refresh_from_db()
        self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN)
        self.assertEqual(Showing.objects.all().count(), 1)

    def test_url_showings_detail_negative_delete_unauthorized(self):
        """
        Negative test checks that anonymous users cannot delete showings
        """
        response = self.client.delete(path=reverse('movie-detail', args=[self.showing.pk]))

        self.assertEqual(response.status_code, status.HTTP_401_UNAUTHORIZED)
        self.assertEqual(Showing.objects.all().count(), 1)