class TestsFirstFunctionality(unittest.TestCase):
    def setUp(self):
        unittest.TestCase.setUp(self)

    def test_init_movie_getProperties(self):
        movie = Movie(1, 'Frozen', 'Ice queen with magical powers',
                      'Animation')
        self.__valid_movie = movie
        self.assertEqual(movie.get_id(), 1)
        self.assertEqual(movie.get_title(), 'Frozen')
        self.assertEqual(movie.get_description(),
                         'Ice queen with magical powers')
        self.assertEqual(movie.get_genre(), 'Animation')

    def test_setters_movie_changedProperties(self):
        movie = Movie(1, 'Frozen', 'Ice queen with magical powers',
                      'Animation')
        movie.set_title('Frozen 2')
        self.assertEqual(movie.get_title(), 'Frozen 2')
        movie.set_movieId(2)
        self.assertEqual(2, movie.get_id())

    def test_str_validMovie_string(self):
        movie = Movie(1, 'a', 'b', 'c')
        self.assertEqual(
            str(movie), "Movie ID: 1" + "\n" + "Title: a" + "\n" +
            "Description: b" + "\n" + "Genre: c")

    def test_eq_moviesSameID_True(self):
        movie = Movie(1, 'Frozen', 'Ice queen with magical powers',
                      'Animation')
        self.__movie_sameID = Movie(1, 'Frozen 2',
                                    'Ice queen with magical powers', 'Kids')
        self.assertEqual(movie, self.__movie_sameID)

    def test_specialReplace_elUpdateNonemptyFields_allFieldsReplaced(self):
        movie = Movie(1, 'Frozen', 'Ice queen with magical powers',
                      'Animation')
        self.__movieUpdate = Movie(1, 'Frozen 2', 'Story about sisters',
                                   'Family')
        movie.special_replace(self.__movieUpdate)
        self.assertTrue(self.__movieUpdate.identical(movie))

    def test_specialReplace_elUpdate1EmptyField_1remainsUnchanged(self):
        movie = Movie(1, 'Frozen', 'Ice queen with magical powers',
                      'Animation')
        self.__movieUpdate_emptyField = Movie(1, 'Frozen 3', '', 'Family')
        movie.special_replace(self.__movieUpdate_emptyField)
        self.assertEqual(movie.get_title(), 'Frozen 3')
        self.assertEqual(movie.get_description(),
                         'Ice queen with magical powers')
        self.assertEqual(movie.get_genre(), 'Family')

    def test_identical_identicalMovies_True(self):
        movie = Movie(1, 'Frozen 2', 'Ice queen with magical powers',
                      'Animation')
        self.__valid_movie = movie
        self.assertTrue(self.__valid_movie.identical(movie))

    def test_identical_differentMovies_False(self):
        movie = Movie(1, 'Frozen', '-', 'Family')
        self.__valid_movie = Movie(1, 'Frozen 2',
                                   'Ice queen with magical powers',
                                   'Animation')
        self.assertFalse(self.__valid_movie.identical(movie))

    def test_validate_validMovie_None(self):
        self.__valid_movie = Movie(1, 'a', 'a', 'a')
        validator = ValidMovie()
        validator.validate_movie(self.__valid_movie)

    def test_validate_invalidID_throwsException(self):
        validator = ValidMovie()
        self.__movie_invalidID = Movie(-2, 'Lion King', 'Hamlet for kids',
                                       'Animation')
        with self.assertRaises(ValidationError):
            validator.validate_movie(self.__movie_invalidID)

    def test_validate_invalidTitle_throwsException(self):
        validator = ValidMovie()
        self.__movie_invalidTitle = Movie(1, '', 'No description', 'Horror')
        with self.assertRaises(ValidationError):
            validator.validate_movie(self.__movie_invalidTitle)

    def test_validate_invalidMovie_throwsException(self):
        validator = ValidMovie()
        self.__invalid_movie = Movie(-2, '', '-', 'Drama')
        with self.assertRaises(ValidationError):
            validator.validate_movie(self.__invalid_movie)

    def test_add_newMovie_movieIsAdded(self):
        movie = Movie(1, 'a', 'a', 'a')
        repo = Repository()
        repo.add(movie)
        self.assertEqual(repo.size(), 1)
        self.assertEqual(repo.get_all()[repo.size() - 1], movie)

    def test_add_movieSameID_throwsException(self):
        movie = Movie(1, 'a', '', '')
        movie_sameID = Movie(1, 'b', '', '')
        repository = Repository()
        repository.add(movie)
        with self.assertRaises(RepositoryError):
            repository.add(movie_sameID)

    def test_ServiceAdd_validMovie_isAdded(self):
        undo_stack = Stack()
        redo_stack = Stack()
        self.__movie_validator = ValidMovie()
        self.__movie_repository = Repository()
        self.__rental_repository = Repository
        self.__movie_service = ServiceMovies(self.__movie_repository,
                                             self.__movie_validator,
                                             undo_stack, redo_stack,
                                             self.__rental_repository)
        self.__valid_movie = Movie(1, 'Frozen',
                                   'Ice queen with magical powers',
                                   'Animation')
        self.__movie_service.add_movie(1, 'Frozen',
                                       'Ice queen with magical powers',
                                       'Animation')
        self.assertEqual(
            self.__movie_service.get_movies()[
                self.__movie_service.get_number() - 1], self.__valid_movie)

    def test_ServiceAdd_invalidId_throwsException(self):
        undo_stack = Stack()
        redo_stack = Stack()
        self.__movie_validator = ValidMovie()
        self.__movie_repository = Repository()
        self.__rental_repository = Repository
        self.__movie_service = ServiceMovies(self.__movie_repository,
                                             self.__movie_validator,
                                             undo_stack, redo_stack,
                                             self.__rental_repository)
        with self.assertRaises(ValidationError):
            self.__movie_service.add_movie(-1, '-', '-', '-')

    def test_ServiceAdd_invalidTitle_throwsException(self):
        undo_stack = Stack()
        redo_stack = Stack()
        self.__movie_validator = ValidMovie()
        self.__movie_repository = Repository()
        self.__rental_repository = Repository
        self.__movie_service = ServiceMovies(self.__movie_repository,
                                             self.__movie_validator,
                                             undo_stack, redo_stack,
                                             self.__rental_repository)
        with self.assertRaises(ValidationError):
            self.__movie_service.add_movie(2, '', '-', '-')

    def test_ServiceAdd_invalidMovie_throwsException(self):
        undo_stack = Stack()
        redo_stack = Stack()
        self.__movie_validator = ValidMovie()
        self.__movie_repository = Repository()
        self.__rental_repository = Repository
        self.__movie_service = ServiceMovies(self.__movie_repository,
                                             self.__movie_validator,
                                             undo_stack, redo_stack,
                                             self.__rental_repository)
        with self.assertRaises(ValidationError):
            self.__movie_service.add_movie(-1, '', '-', '-')

    def test_ServiceAdd_existingId_throwsException(self):
        undo_stack = Stack()
        redo_stack = Stack()
        self.__movie_validator = ValidMovie()
        self.__movie_repository = Repository()
        self.__rental_repository = Repository
        self.__movie_service = ServiceMovies(self.__movie_repository,
                                             self.__movie_validator,
                                             undo_stack, redo_stack,
                                             self.__rental_repository)
        self.__movie_service.add_movie(1, 'a', '', '')
        with self.assertRaises(RepositoryError):
            self.__movie_service.add_movie(1, '-', '-', '-')

    def test_remove_movie_isRemoved(self):
        repository = Repository()
        movie = Movie(1, '-', '-', '-')
        repository.add(movie)
        repository.remove(movie)
        self.assertEqual(repository.size(), 0)

    def test_ServiceRemove_existingMovie_isRemoved(self):
        undo_stack = Stack()
        redo_stack = Stack()
        self.__rental_repository = Repository()
        self.__movie_validator = ValidMovie()
        self.__movie_repository = Repository()
        self.__movie_service = ServiceMovies(self.__movie_repository,
                                             self.__movie_validator,
                                             undo_stack, redo_stack,
                                             self.__rental_repository)
        self.__movie_service.add_movie(1, '-', '-', '-')
        self.__movie_service.remove_movie(1)
        self.assertEqual(self.__movie_service.get_number(), 0)

    def test_ServiceRemove_inexistentMovie_throwsException(self):
        undo_stack = Stack()
        redo_stack = Stack()
        self.__movie_validator = ValidMovie()
        self.__movie_repository = Repository()
        rental_repository = Repository()
        self.__movie_service = ServiceMovies(self.__movie_repository,
                                             self.__movie_validator,
                                             undo_stack, redo_stack,
                                             rental_repository)
        self.__movie_service.add_movie(1, '-', '-', '-')
        with self.assertRaises(RepositoryError):
            self.__movie_service.remove_movie(2)

    def test_updateElement_withAllFields_elementUpdated(self):
        repository = Repository()
        movie = Movie(1, 'Frozen', 'Ice queen with magical powers',
                      'Animation')
        repository.add(movie)
        movieUpdate = Movie(1, '-', '-', '-')
        repository.update(movie, movieUpdate)
        self.assertTrue(repository.get_all()[0].identical(movieUpdate))

    def test_updateElement_with1emptyField_elementUpdated1fieldUnchanged(self):
        repository = Repository()
        movie = Movie(1, 'Frozen', 'Ice queen with magical powers',
                      'Animation')
        repository.add(movie)
        repository.update(movie, Movie(1, '', 'a', 'b'))
        expected_result = Movie(1, 'Frozen', 'a', 'b')
        self.assertTrue(repository.get_all()[0].identical(expected_result))

    def test_ServiceUpdate_movieWithAllFields_allFieldsUpdated(self):
        undo_stack = Stack()
        redo_stack = Stack()
        self.__movie_validator = ValidMovie()
        self.__movie_repository = Repository()
        self.__rental_repository = Repository
        self.__movie_service = ServiceMovies(self.__movie_repository,
                                             self.__movie_validator,
                                             undo_stack, redo_stack,
                                             self.__rental_repository)
        self.__movie_service.add_movie(1, 'Harry Potter', 'Witchcraft',
                                       'Adventure')
        self.__movie_service.update_movie(1, 'Harry Potter 2', 'Wizardry',
                                          'Action')
        expected = Movie(1, 'Harry Potter 2', 'Wizardry', 'Action')
        self.assertTrue(
            self.__movie_service.get_movies()[0].identical(expected))

    def test_ServiceUpdate_movieWith1emptyField_thatFieldIsUnchanged(self):
        undo_stack = Stack()
        redo_stack = Stack()
        self.__movie_validator = ValidMovie()
        self.__movie_repository = Repository()
        self.__rental_repository = Repository
        self.__movie_service = ServiceMovies(self.__movie_repository,
                                             self.__movie_validator,
                                             undo_stack, redo_stack,
                                             self.__rental_repository)
        self.__movie_service.add_movie(1, 'Harry Potter', 'Witchcraft',
                                       'Adventure')
        self.__movie_service.update_movie(1, '', '-', '-')
        expected = Movie(1, 'Harry Potter', '-', '-')
        self.assertTrue(
            self.__movie_service.get_movies()[0].identical(expected))

    def test_ServiceUpdate_inexistentId_throwsException(self):
        undo_stack = Stack()
        redo_stack = Stack()
        self.__movie_validator = ValidMovie()
        self.__movie_repository = Repository()
        self.__rental_repository = Repository
        self.__movie_service = ServiceMovies(self.__movie_repository,
                                             self.__movie_validator,
                                             undo_stack, redo_stack,
                                             self.__rental_repository)
        self.__movie_service.add_movie(1, 'Harry Potter', 'Witchcraft',
                                       'Adventure')
        with self.assertRaises(RepositoryError):
            self.__movie_service.update_movie(2, '', '', '')

    def test_init_client_getProperties(self):
        client = Client(1, 'Jonn Doe')
        self.assertEqual(client.get_id(), 1)
        self.assertEqual(client.get_name(), 'Jonn Doe')

    def test_setters_client_changedProperties(self):
        self.__valid_client = Client(1, '-')
        self.__valid_client.set_name('John Doe')
        self.assertEqual(self.__valid_client.get_name(), 'John Doe')
        self.__valid_client.set_clientId(2)
        self.assertEqual(self.__valid_client.get_id(), 2)

    def test_str_validClient_string(self):
        client = Client(1, 'o')
        self.assertEqual(str(client), "Client ID: 1" + '\n' + 'Name: o')

    def test_eq_clientsSameID_True(self):
        self.__valid_client = Client(1, '-')
        self.__client_sameID = Client(1, 'Jane Doe')
        self.assertEqual(self.__valid_client, self.__client_sameID)

    def test_identical_identicalClients_True(self):
        client = Client(1, 'John Doe')
        self.__valid_client = Client(1, 'John Doe')
        self.assertTrue(self.__valid_client.identical(client))

    def test_identical_differentClients_False(self):
        self.__valid_client = Client(1, '-')
        client = Client(1, 'Billy')
        self.assertFalse(self.__valid_client.identical(client))

    def test_validate_validClient_None(self):
        validator = ValidClient()
        self.__valid_client = Client(1, 'a')
        validator.validate_client(self.__valid_client)

    def test_validate_invalidClientID_throwsException(self):
        validator = ValidClient()
        self.__client_invalidID = Client(-2, 'Elsa')
        with self.assertRaises(ValidationError):
            validator.validate_client(self.__client_invalidID)

    def test_validate_invalidName_throwsException(self):
        validator = ValidClient()
        self.__client_invalidName = Client(1, '')
        with self.assertRaises(ValidationError):
            validator.validate_client(self.__client_invalidName)

    def test_validate_invalidClient_throwsException(self):
        validator = ValidClient()
        self.__invalid_client = Client(-2, '')
        with self.assertRaises(ValidationError):
            validator.validate_client(self.__invalid_client)

    def test_ServiceAdd_validClient_isAdded(self):
        undo_stack = Stack()
        redo_stack = Stack()
        self.__rental_repository = Repository()
        self.__client_validator = ValidClient()
        self.__client_repository = Repository()
        self.__client_service = ServiceClients(self.__client_repository,
                                               self.__client_validator,
                                               undo_stack, redo_stack,
                                               self.__rental_repository)
        self.__client_service.add_client(1, 'John Doe')
        self.assertEqual(
            self.__client_service.get_clients()[
                self.__client_service.get_number() - 1], Client(1, 'John Doe'))

    def test_ServiceAdd_invalidClientId_throwsException(self):
        undo_stack = Stack()
        redo_stack = Stack()
        self.__rental_repository = Repository()
        self.__client_validator = ValidClient()
        self.__client_repository = Repository()
        self.__client_service = ServiceClients(self.__client_repository,
                                               self.__client_validator,
                                               undo_stack, redo_stack,
                                               self.__rental_repository)
        with self.assertRaises(ValidationError):
            self.__client_service.add_client(-1, '-')

    def test_ServiceAdd_invalidName_throwsException(self):
        undo_stack = Stack()
        redo_stack = Stack()
        self.__rental_repository = Repository()
        self.__client_validator = ValidClient()
        self.__client_repository = Repository()
        self.__client_service = ServiceClients(self.__client_repository,
                                               self.__client_validator,
                                               undo_stack, redo_stack,
                                               self.__rental_repository)
        with self.assertRaises(ValidationError):
            self.__client_service.add_client(2, '')

    def test_ServiceAdd_invalidClient_throwsException(self):
        undo_stack = Stack()
        redo_stack = Stack()
        self.__rental_repository = Repository()
        self.__client_validator = ValidClient()
        self.__client_repository = Repository()
        self.__client_service = ServiceClients(self.__client_repository,
                                               self.__client_validator,
                                               undo_stack, redo_stack,
                                               self.__rental_repository)
        with self.assertRaises(ValidationError):
            self.__client_service.add_client(-1, '')

    def test_ServiceAdd_existingClientId_throwsException(self):
        undo_stack = Stack()
        redo_stack = Stack()
        self.__rental_repository = Repository()
        self.__client_validator = ValidClient()
        self.__client_repository = Repository()
        self.__client_service = ServiceClients(self.__client_repository,
                                               self.__client_validator,
                                               undo_stack, redo_stack,
                                               self.__rental_repository)
        self.__client_service.add_client(1, 'o')
        with self.assertRaises(RepositoryError):
            self.__client_service.add_client(1, '-')

    def test_ServiceRemove_existingClient_isRemoved(self):
        undo_stack = Stack()
        redo_stack = Stack()
        self.__rental_repository = Repository()
        self.__client_validator = ValidClient()
        self.__client_repository = Repository()
        self.__client_service = ServiceClients(self.__client_repository,
                                               self.__client_validator,
                                               undo_stack, redo_stack,
                                               self.__rental_repository)
        self.__client_service.add_client(1, '-')

        self.__client_service.remove_client(1)
        self.assertEqual(self.__client_service.get_number(), 0)

    def test_ServiceRemove_inexistentClient_throwsException(self):
        undo_stack = Stack()
        redo_stack = Stack()
        self.__rental_repository = Repository()
        self.__client_validator = ValidClient()
        self.__client_repository = Repository()
        self.__client_service = ServiceClients(self.__client_repository,
                                               self.__client_validator,
                                               undo_stack, redo_stack,
                                               self.__rental_repository)
        self.__client_service.add_client(1, '-')
        with self.assertRaises(RepositoryError):
            self.__client_service.remove_client(2)

    def test_ServiceUpdate_client_isUpdated(self):
        undo_stack = Stack()
        redo_stack = Stack()
        self.__rental_repository = Repository()
        self.__client_validator = ValidClient()
        self.__client_repository = Repository()
        self.__client_service = ServiceClients(self.__client_repository,
                                               self.__client_validator,
                                               undo_stack, redo_stack,
                                               self.__rental_repository)
        self.__client_service.add_client(1, 'Bob')

        self.__client_service.update_client(1, 'Billy')
        self.assertEqual(self.__client_service.get_clients()[0].get_name(),
                         'Billy')

    def test_ServiceUpdate_inexistentClientId_throwsException(self):
        undo_stack = Stack()
        redo_stack = Stack()
        self.__rental_repository = Repository()
        self.__client_validator = ValidClient()
        self.__client_repository = Repository()
        self.__client_service = ServiceClients(self.__client_repository,
                                               self.__client_validator,
                                               undo_stack, redo_stack,
                                               self.__rental_repository)
        self.__client_service.add_client(1, 'Bob')
        with self.assertRaises(RepositoryError):
            self.__client_service.update_client(2, '-')
 def test_init_client_getProperties(self):
     client = Client(1, 'Jonn Doe')
     self.assertEqual(client.get_id(), 1)
     self.assertEqual(client.get_name(), 'Jonn Doe')