from rest_framework.test import APITestCase
from apps.user.models import UserRole, User


class TestUserRegistration(APITestCase):
    ENDPOINT = '/api/users/register'

    def test_user_registration_should_success(self):
        """
        this function tests the user registration with following processes:
        1. define client as self.APIClient
        2. send post request to '/api/users/register' using the client, with following parameters:
            phone_number = 01012341234
            name = 홍길동
            password = <PASSWORD>
        """

        response = self.client.post(
            self.ENDPOINT,
            {
                'phone_number': '01012341234',
                'name': '홍길동',
                'password': '<PASSWORD>',
            },
        )
        self.assertEqual(response.status_code, 201)

    def test_user_regstration_with_duplicated_phone_number_should_fail(self):
        """
        this function tests the user registration, whether it successfully returns 400 if the phone_number (which is unique) duplicates
        the other conditions are the same as the upper function, but trying it for twice and check whether if the last request's response.status_code is 400
        """

        response = self.client.post(
            self.ENDPOINT,
            {
                'phone_number': '01012341234',
                'name': '홍길동',
                'password': '<PASSWORD>',
            },
        )
        self.assertEqual(response.status_code, 201)
        response = self.client.post(
            self.ENDPOINT,
            {
                'phone_number': '01012341234',
                'name': '홍길동',
                'password': '<PASSWORD>',
            },
        )
        self.assertEqual(response.status_code, 400)

    def test_user_registration_with_easy_password_should_fail(self):
        """
        all of the conditions are the same as the function 'test_user_registration_should_success',
        but the password should be <PASSWORD>
        """

        response = self.client.post(
            self.ENDPOINT,
            {
                'phone_number': '01012341234',
                'name': '홍길동',
                'password': '<PASSWORD>',
            },
        )
        self.assertEqual(response.status_code, 400)


class TestAuthorization(APITestCase):
    TOKEN_ENDPOINT = '/api/token'
    """
    this class is about the jwt authorization
    actually, the proccess of issuing token is all offered by the django-simplejwt module.
    Therefore this test only tests the authorization itself works alright (the process of checking phone_number and password is working correctly)
    """
    def setUp(self):
        """
        create a sample user
        """
        User.objects.create_user(phone_number='021231234',
                                 name='홍길동',
                                 password='<PASSWORD>',
                                 role=UserRole.CLIENT)
        self.client = self.APIClient()

    def test_issuing_token_should_success(self):
        """
        1. get token by sending post request to self.TOKEN_ENDPOINT with phone_number and password
        2. it should return 200 status code with jwt token
        """
        response = self.client.post(
            self.TOKEN_ENDPOINT,
            {
                'phone_number': '01012341234',
                'password': '<PASSWORD>',
            },
        )
        self.assertEqual(response.status_code, 200)
        self.assertIn('access', response.data)
        self.assertIn('refresh', response.data)

    def test_issuing_token_with_wrong_password_should_fail(self):
        """
        1. get token by sending post request to self.TOKEN_ENDPOINT with phone_number and wrong password
        2. it should return 400 status code
        """

        response = self.client.post(
            self.TOKEN_ENDPOINT,
            {
                'phone_number': '01012341234',
                'password': '<PASSWORD>',
            },
        )
        self.assertEqual(response.status_code, 400)

    def test_issuing_token_without_info_should_fail(self):
        """
        1. get token by sending post request to self.TOKEN_ENDPOINT without phone_number and password
        2. it should return 400 status code
        """
        response = self.client.post(
            self.TOKEN_ENDPOINT,
            {},
        )
        self.assertEqual(response.status_code, 400)

    def test_refreshing_token_should_success(self):
        """
        1. get token by sending post request to self.TOKEN_ENDPOINT with phone_number and password
        2. it should return 200 status code with jwt token
        3. send post request to '/api/token/refresh' with jwt token
        4. it should return 200 status code
        """
        response = self.client.post(
            self.TOKEN_ENDPOINT,
            {
                'phone_number': '01012341234',
                'password': '<PASSWORD>',
            },
        )
        self.assertEqual(response.status_code, 200)
        response = self.client.post(
            '/api/token/refresh',
            {
                'refresh': response.data['refresh'],
            },
        )
        self.assertEqual(response.status_code, 200)

    def test_verifying_token_should_success(self):
        """
        1. get token by sending post request to self.TOKEN_ENDPOINT with phone_number and password
        2. it should return 200 status code with jwt token
        3. send post request to '/api/token/verify' with jwt token
        4. it should return 200 status code
        """
        response = self.client.post(
            self.TOKEN_ENDPOINT,
            {
                'phone_number': '01012341234',
                'password': '<PASSWORD>',
            },
        )
        self.assertEqual(response.status_code, 200)
        response = self.client.post(
            '/api/token/verify',
            {
                'token': response.data['access'],
            },
        )
        self.assertEqual(response.status_code, 200)

    def test_verifying_token_with_wrong_token_should_fail(self):
        """
        1. get token by sending post request to self.TOKEN_ENDPOINT with phone_number and password
        2. it should return 200 status code with jwt token
        3. send post request to '/api/token/verify' with wrong jwt token
        4. it should return 400 status code
        """
        response = self.client.post(
            self.TOKEN_ENDPOINT,
            {
                'phone_number': '01012341234',
                'password': '<PASSWORD>',
            },
        )
        self.assertEqual(response.status_code, 200)
        response = self.client.post(
            '/api/token/verify',
            {
                'token': 'wrong',
            },
        )
        self.assertEqual(response.status_code, 400)


class TestRetrieveUserProfile(APITestCase):
    """
    Test the API endpoint to retrieve the user's profile

    the profile should work like:
    1. it should contain phone_number, name, role, is_verified and date_joined fields
    2. the password shouldn't be returned
    3. it shouldn't be returned when the user is not authenticated
    """
    def setUp(self):
        """
        create a sample user
        """
        User.objects.create_user(phone_number='021231234',
                                 name='홍길동',
                                 password='<PASSWORD>',
                                 role=UserRole.CLIENT)
        self.client = self.APIClient()

    def test_retrieve_profile_should_success(self):
        """
        1. get jwt token
        2. using jwt token, send get request to '/api/users'
        3. check status code
        4. check every required fields are there
        """
        response = self.client.post(
            self.TOKEN_ENDPOINT,
            {
                'phone_number': '01012341234',
                'password': '<PASSWORD>',
            },
        )
        self.assertEqual(response.status_code, 200)
        self.assertIn('token', response.data)
        response = self.client.get(
            '/api/users',
            HTTP_AUTHORIZATION='Bearer ' + response.data['access'],
        )
        self.assertEqual(response.status_code, 200)
        self.assertIn('phone_number', response.data)
        self.assertIn('name', response.data)
        self.assertIn('role', response.data)
        self.assertIn('is_verified', response.data)
        self.assertIn('date_joined', response.data)
        self.assertNotIn('password', response.data)

    def test_retrieve_profile_should_fail_when_not_authenticated(self):
        """
        1. send get request to '/api/users'
        2. check status code
        """
        response = self.client.get('/api/users', )
        self.assertEqual(response.status_code, 401)

from rest_framework.test import APITestCase
from apps.user.models import UserRole, User


class TestUserRegistration(APITestCase):
    ENDPOINT = '/api/users/register'

    def test_user_registration_should_success(self):
        """
        this function tests the user registration with following processes:
        1. define client as self.APIClient
        2. send post request to '/api/users/register' using the client, with following parameters:
            phone_number = 01012341234
            name = 홍길동
            password = <PASSWORD>
        """

        response = self.client.post(
            self.ENDPOINT,
            {
                'phone_number': '01012341234',
                'name': '홍길동',
                'password': '<PASSWORD>',
            },
        )
        self.assertEqual(response.status_code, 201)

    def test_user_regstration_with_duplicated_phone_number_should_fail(self):
        """
        this function tests the user registration, whether it successfully returns 400 if the phone_number (which is unique) duplicates
        the other conditions are the same as the upper function, but trying it for twice and check whether if the last request's response.status_code is 400
        """

        response = self.client.post(
            self.ENDPOINT,
            {
                'phone_number': '01012341234',
                'name': '홍길동',
                'password': '<PASSWORD>',
            },
        )
        self.assertEqual(response.status_code, 201)
        response = self.client.post(
            self.ENDPOINT,
            {
                'phone_number': '01012341234',
                'name': '홍길동',
                'password': '<PASSWORD>',
            },
        )
        self.assertEqual(response.status_code, 400)

    def test_user_registration_with_easy_password_should_fail(self):
        """
        all of the conditions are the same as the function 'test_user_registration_should_success',
        but the password should be <PASSWORD>
        """

        response = self.client.post(
            self.ENDPOINT,
            {
                'phone_number': '01012341234',
                'name': '홍길동',
                'password': '<PASSWORD>',
            },
        )
        self.assertEqual(response.status_code, 400)


class TestAuthorization(APITestCase):
    TOKEN_ENDPOINT = '/api/token'
    """
    this class is about the jwt authorization
    actually, the proccess of issuing token is all offered by the django-simplejwt module.
    Therefore this test only tests the authorization itself works alright (the process of checking phone_number and password is working correctly)
    """
    def setUp(self):
        """
        create a sample user
        """
        User.objects.create_user(phone_number='021231234',
                                 name='홍길동',
                                 password='<PASSWORD>',
                                 role=UserRole.CLIENT)
        self.client = self.APIClient()

    def test_issuing_token_should_success(self):
        """
        1. get token by sending post request to self.TOKEN_ENDPOINT with phone_number and password
        2. it should return 200 status code with jwt token
        """
        response = self.client.post(
            self.TOKEN_ENDPOINT,
            {
                'phone_number': '01012341234',
                'password': '<PASSWORD>',
            },
        )
        self.assertEqual(response.status_code, 200)
        self.assertIn('access', response.data)
        self.assertIn('refresh', response.data)

    def test_issuing_token_with_wrong_password_should_fail(self):
        """
        1. get token by sending post request to self.TOKEN_ENDPOINT with phone_number and wrong password
        2. it should return 400 status code
        """

        response = self.client.post(
            self.TOKEN_ENDPOINT,
            {
                'phone_number': '01012341234',
                'password': '<PASSWORD>',
            },
        )
        self.assertEqual(response.status_code, 400)

    def test_issuing_token_without_info_should_fail(self):
        """
        1. get token by sending post request to self.TOKEN_ENDPOINT without phone_number and password
        2. it should return 400 status code
        """
        response = self.client.post(
            self.TOKEN_ENDPOINT,
            {},
        )
        self.assertEqual(response.status_code, 400)

    def test_refreshing_token_should_success(self):
        """
        1. get token by sending post request to self.TOKEN_ENDPOINT with phone_number and password
        2. it should return 200 status code with jwt token
        3. send post request to '/api/token/refresh' with jwt token
        4. it should return 200 status code
        """
        response = self.client.post(
            self.TOKEN_ENDPOINT,
            {
                'phone_number': '01012341234',
                'password': '<PASSWORD>',
            },
        )
        self.assertEqual(response.status_code, 200)
        response = self.client.post(
            '/api/token/refresh',
            {
                'refresh': response.data['refresh'],
            },
        )
        self.assertEqual(response.status_code, 200)

    def test_verifying_token_should_success(self):
        """
        1. get token by sending post request to self.TOKEN_ENDPOINT with phone_number and password
        2. it should return 200 status code with jwt token
        3. send post request to '/api/token/verify' with jwt token
        4. it should return 200 status code
        """
        response = self.client.post(
            self.TOKEN_ENDPOINT,
            {
                'phone_number': '01012341234',
                'password': '<PASSWORD>',
            },
        )
        self.assertEqual(response.status_code, 200)
        response = self.client.post(
            '/api/token/verify',
            {
                'token': response.data['access'],
            },
        )
        self.assertEqual(response.status_code, 200)

    def test_verifying_token_with_wrong_token_should_fail(self):
        """
        1. get token by sending post request to self.TOKEN_ENDPOINT with phone_number and password
        2. it should return 200 status code with jwt token
        3. send post request to '/api/token/verify' with wrong jwt token
        4. it should return 400 status code
        """
        response = self.client.post(
            self.TOKEN_ENDPOINT,
            {
                'phone_number': '01012341234',
                'password': '<PASSWORD>',
            },
        )
        self.assertEqual(response.status_code, 200)
        response = self.client.post(
            '/api/token/verify',
            {
                'token': 'wrong',
            },
        )
        self.assertEqual(response.status_code, 400)


class TestRetrieveUserProfile(APITestCase):
    """
    Test the API endpoint to retrieve the user's profile

    the profile should work like:
    1. it should contain phone_number, name, role, is_verified and date_joined fields
    2. the password shouldn't be returned
    3. it shouldn't be returned when the user is not authenticated
    """
    def setUp(self):
        """
        create a sample user
        """
        User.objects.create_user(phone_number='021231234',
                                 name='홍길동',
                                 password='<PASSWORD>',
                                 role=UserRole.CLIENT)
        self.client = self.APIClient()

    def test_retrieve_profile_should_success(self):
        """
        1. get jwt token
        2. using jwt token, send get request to '/api/users'
        3. check status code
        4. check every required fields are there
        """
        response = self.client.post(
            self.TOKEN_ENDPOINT,
            {
                'phone_number': '01012341234',
                'password': '<PASSWORD>',
            },
        )
        self.assertEqual(response.status_code, 200)
        self.assertIn('token', response.data)
        response = self.client.get(
            '/api/users',
            HTTP_AUTHORIZATION='Bearer ' + response.data['access'],
        )
        self.assertEqual(response.status_code, 200)
        self.assertIn('phone_number', response.data)
        self.assertIn('name', response.data)
        self.assertIn('role', response.data)
        self.assertIn('is_verified', response.data)
        self.assertIn('date_joined', response.data)
        self.assertNotIn('password', response.data)

    def test_retrieve_profile_should_fail_when_not_authenticated(self):
        """
        1. send get request to '/api/users'
        2. check status code
        """
        response = self.client.get('/api/users', )
        self.assertEqual(response.status_code, 401)

this function tests the user registration with following processes:         1. define client as self.APIClient         2. send post request to '/api/users/register' using the client, with following parameters:             phone_number = 01012341234             name = 홍길동             password = <PASSWORD> this function tests the user registration, whether it successfully returns 400 if the phone_number (which is unique) duplicates         the other conditions are the same as the upper function, but trying it for twice and check whether if the last request's response.status_code is 400 all of the conditions are the same as the function 'test_user_registration_should_success',         but the password should be <PASSWORD> this class is about the jwt authorization     actually, the proccess of issuing token is all offered by the django-simplejwt module.     Therefore this test only tests the authorization itself works alright (the process of checking phone_number and password is working correctly) create a sample user 1. get token by sending post request to self.TOKEN_ENDPOINT with phone_number and password         2. it should return 200 status code with jwt token 1. get token by sending post request to self.TOKEN_ENDPOINT with phone_number and wrong password         2. it should return 400 status code 1. get token by sending post request to self.TOKEN_ENDPOINT without phone_number and password         2. it should return 400 status code 1. get token by sending post request to self.TOKEN_ENDPOINT with phone_number and password         2. it should return 200 status code with jwt token         3. send post request to '/api/token/refresh' with jwt token         4. it should return 200 status code 1. get token by sending post request to self.TOKEN_ENDPOINT with phone_number and password         2. it should return 200 status code with jwt token         3. send post request to '/api/token/verify' with jwt token         4. it should return 200 status code 1. get token by sending post request to self.TOKEN_ENDPOINT with phone_number and password         2. it should return 200 status code with jwt token         3. send post request to '/api/token/verify' with wrong jwt token         4. it should return 400 status code Test the API endpoint to retrieve the user's profile      the profile should work like:     1. it should contain phone_number, name, role, is_verified and date_joined fields     2. the password shouldn't be returned     3. it shouldn't be returned when the user is not authenticated create a sample user 1. get jwt token         2. using jwt token, send get request to '/api/users'         3. check status code         4. check every required fields are there 1. send get request to '/api/users'         2. check status code