Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve test coverage #1195

Merged
merged 9 commits into from
Nov 11, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 21 additions & 14 deletions project/accounts/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -286,26 +286,27 @@ def edit_user(request):
@login_required
def upload_profile_image(request):
"""This function is used to allow users to upload profile photos"""

if request.method == "POST":
form = UpdateProfileImage(request.POST, request.FILES)
if form.is_valid():
try:
account = Profile.objects.get(user=request.user)
profile = Profile.objects.get(user=request.user)

# Clean up previous image
account.profile_image.delete()
profile.profile_image.delete()

# Upload new image and set as profile picture
account.profile_image = form.clean_profile_image()
profile.profile_image = form.clean_profile_image()
try:
account.save()
profile.save()
except Exception as e:
response = {"message": str(e), "error": "MODEL_SAVE_ERROR"}
return JsonResponse(response, status=400)

request.session["login_user_image"] = account.profile_image_thumb_url
request.session["login_user_image"] = profile.profile_image_thumb_url

response = {"profile_image": account.profile_image_url}
response = {"profile_image": profile.profile_image_url}
return JsonResponse(response, status=200)

except get_user_model().DoesNotExist:
Expand All @@ -328,6 +329,7 @@ def upload_profile_image(request):
@login_required
def clear_profile_image(request):
"""This function is used to delete a profile image"""

if request.method == "POST":
try:
account = Profile.objects.get(user=request.user)
Expand Down Expand Up @@ -363,12 +365,15 @@ def request_follow(request):

:return: (200, okay, list of friend information) (400, bad lookup) (500, error)
"""
if request.user.username == request.POST.get("target", -1):
return HttpResponseBadRequest(reason="You cannot follow yourself, silly!")

target_username = request.POST.get("target", -1)
if request.user.username == target_username:
response = {"error": "You cannot follow yourself, silly!"}
return JsonResponse(response, status=400)

try:
account = Profile.objects.get(user=request.user)
target = get_user_model().objects.get(username=request.POST.get("target", -1))
target = get_user_model().objects.get(username=target_username)
target_account = Profile.objects.get(user=target)

account.following.add(target_account)
Expand All @@ -387,8 +392,10 @@ def request_follow(request):
)

return JsonResponse({"result": data})
except get_user_model().DoesNotExist as e:
return HttpResponseBadRequest(reason=str(e))
except get_user_model().DoesNotExist:
return JsonResponse(
{"error": f"User with username {target_username} not found"}, status=400
)
except Exception as e:
return HttpResponseServerError(reason=str(e))

Expand Down Expand Up @@ -421,11 +428,11 @@ def request_unfollow(request):
target_account.followers.remove(account)
target_account.save()
return JsonResponse({"result": "Success"})
return HttpResponseBadRequest(reason="username cannot be empty")
return JsonResponse({"error": "username cannot be empty"}, status=400)

except get_user_model().DoesNotExist:
return HttpResponseBadRequest(
reason=f"User with username {username} does not exist"
return JsonResponse(
{"error": f"User with username {username} not found"}, status=400
)
except Exception as e:
return HttpResponseServerError(reason=str(e))
Expand Down
142 changes: 136 additions & 6 deletions project/accounts/tests/test_api.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import json
from PIL import Image
from django.core.files.temp import NamedTemporaryFile
from django.contrib.auth import get_user_model
from django.test import TestCase
from rest_framework.test import APIClient
Expand Down Expand Up @@ -155,8 +157,8 @@ def test_existing_user_account_data(self):
self.assertEqual(response.status_code, 200)
self.assertEqual(content["username"], self.user.username)

def test_nonexisting_user_account_data(self):
"""Whether retrieving a nonexisting user raises 404"""
def test_nonexistent_user_account_data(self):
"""Whether retrieving a nonexistent user raises 404"""

self.client.login(username="newuser", password="password123")
response = self.client.get(reverse("get_user", args=["newuser" + "not_exist"]))
Expand All @@ -177,8 +179,8 @@ def test_existing_user_profile_data(self):
self.assertEqual(response.status_code, 200)
self.assertEqual(content["username"], self.user.username)

def test_nonexisting_user_profile_data(self):
"""Whether retrieving a nonexisting user profile raises 404"""
def test_nonexistent_user_profile_data(self):
"""Whether retrieving a nonexistent user profile raises 404"""

self.client.login(username="newuser", password="password123")
response = self.client.get(
Expand Down Expand Up @@ -207,8 +209,8 @@ def test_existing_user_profile_data(self):
self.assertEqual(content["username"], self.superuser.username)
self.assertTrue(content["follow_state"])

def test_nonexisting_user_profile_data(self):
"""Whether retrieving a nonexisting user card raises 404"""
def test_nonexistent_user_profile_data(self):
"""Whether retrieving a nonexistent user card raises 404"""

self.client.login(username="newuser", password="password123")
response = self.client.get(reverse("get_card", args=["newuser" + "not_exist"]))
Expand All @@ -231,3 +233,131 @@ def test_first_name_last_name_about_fields_can_be_editable(self):
self.assertEqual(self.user.profile.first_name, "First")
self.assertEqual(self.user.profile.last_name, "Last")
self.assertEqual(self.user.profile.about_me, "About me")


class UploadProfileImage(BaseTestCase):
"""A class to test upload_profile_image function"""

def setUp(self) -> None:
super(UploadProfileImage, self).setUp()
self.client.login(username="newuser", password="password123")
self.url = reverse("upload_profile")
self.image = Image.new("RGB", size=(5, 5), color=(0, 0, 0))
self.file = NamedTemporaryFile(suffix=".jpg")
self.image.save(self.file)

def tearDown(self) -> None:
for profile in Profile.objects.all():
profile.profile_image.delete()
profile.profile_image_thumb.delete()

def test_upload_profile_image(self):
"""Whether upload_profile_image function works as expected"""

with open(self.file.name, "rb") as image_file:
data = {"profile_image": image_file}
response = self.client.post(self.url, data=data)
content = json.loads(response.content)
self.user.profile.refresh_from_db()
self.assertEqual(
content.get("profile_image"), self.user.profile.profile_image_url
)
self.assertNotEqual(
self.user.profile.profile_image_url, "/static/img/no_image_md.png"
)
self.assertNotEqual(
self.user.profile.profile_image_thumb_url, "/static/img/no_image_md.png"
)

def test_upload_profile_image_with_invalid_extension(self):
"""Whether upload_profile_image raises an error when non-image file is past"""

image = Image.new("RGB", size=(5, 5), color=(0, 0, 0))
file = NamedTemporaryFile(suffix=".pdf")
image.save(file)

with open(file.name, "rb") as image_file:
data = {"profile_image": image_file}
response = self.client.post(self.url, data=data)
content = json.loads(response.content)
self.assertEqual(content["error"], "FORM_ERROR")
self.user.profile.refresh_from_db()
self.assertEqual(
self.user.profile.profile_image_url, "/static/img/no_image_md.png"
)
self.assertEqual(
self.user.profile.profile_image_thumb_url, "/static/img/no_image_md.png"
)


class RequestFollowTests(BaseTestCase):
"""A class to test request_follow function"""

def test_request_follow(self):
"""Whether request_follow function works as expected"""

self.client.login(username="newuser", password="password123")
number_of_followings = self.user.profile.following.count()
data = {"target": self.user2.username}
response = self.client.post(reverse("follow_user"), data=data)
content = json.loads(response.content)
self.assertEqual(response.status_code, 200)
self.assertEqual(content.get("result").get("username"), self.user2.username)
self.assertTrue(content.get("result").get("follow_status"))
self.assertEqual(self.user.profile.following.count(), number_of_followings + 1)

def test_user_cannot_follow_itself(self):
"""Whether a user trying to follow itself raises an error"""

self.client.login(username="newuser", password="password123")
data = {"target": self.user.username}
response = self.client.post(reverse("follow_user"), data=data)
content = json.loads(response.content)
self.assertEqual(response.status_code, 400)
self.assertIn("You cannot follow yourself", content.get("error"))

def test_following_nonexistent_user_gives_error(self):
"""Whether following a nonexistent user raises an error"""

self.client.login(username="newuser", password="password123")
data = {"target": "nonexistent"}
response = self.client.post(reverse("follow_user"), data=data)
content = json.loads(response.content)
self.assertEqual(response.status_code, 400)
self.assertIn("not found", content.get("error"))


class RequestUnfollowTests(BaseTestCase):
"""A class to test request_unfollow function"""

def test_request_unfollow(self):
"""Whether request_unfollow function works as expected"""

self.client.login(username="newuser", password="password123")
number_of_followings = self.user.profile.following.count()
data = {"target": self.superuser.username}
response = self.client.post(reverse("unfollow_user"), data=data)
content = json.loads(response.content)
self.assertEqual(response.status_code, 200)
self.assertEqual(content.get("result"), "Success")
self.assertEqual(self.user.profile.following.count(), number_of_followings - 1)

def test_username_for_unfollowing_cannot_be_empty(self):
"""Whether unfollowing an empty username raises an error"""

self.client.login(username="newuser", password="password123")
data = {"target": ""}
response = self.client.post(reverse("unfollow_user"), data=data)
content = json.loads(response.content)
self.assertEqual(response.status_code, 400)
self.assertEqual(content.get("error"), "username cannot be empty")

def test_unfollowing_nonexistent_user_gives_error(self):
"""Whether unfollowing an nonexistent user raises an error"""

self.client.login(username="newuser", password="password123")
data = {"target": "nonexistent"}
response = self.client.post(reverse("unfollow_user"), data=data)
content = json.loads(response.content)
self.assertEqual(response.status_code, 400)
self.assertIn("not found", content.get("error"))
28 changes: 24 additions & 4 deletions project/accounts/tests/test_views.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ def setUp(self) -> None:
self.user = get_user_model().objects.create_user(
username="newuser", email="[email protected]", password="password123"
)
self.profile, created = Profile.objects.update_or_create(user=self.user)


class LoginViewTests(BaseTestCase):
Expand Down Expand Up @@ -118,9 +117,9 @@ class SettingsViewTests(BaseTestCase):

def setUp(self) -> None:
super(SettingsViewTests, self).setUp()
self.profile.first_name = "Gorkem"
self.profile.last_name = "Arslan"
self.profile.save()
self.user.profile.first_name = "Gorkem"
self.user.profile.last_name = "Arslan"
self.user.profile.save()
self.client.login(username=self.user.username, password="password123")
self.url = reverse("accounts_settings")
self.response = self.client.get(self.url)
Expand Down Expand Up @@ -196,3 +195,24 @@ def test_invalid_action_link(self):
self.assertFalse(self.profile.is_verified)
self.assertTemplateUsed(response, "general_message.html")
self.assertContains(response, "Email Verification Error")


class UserProfileView(BaseTestCase):
"""A class to test user profile view"""

def setUp(self) -> None:
super(UserProfileView, self).setUp()
self.user.profile.first_name = "First"
self.user.profile.last_name = "Last"
self.user.profile.about_me = "About"
self.user.profile.save()

def test_get_user_profile(self):
"""Whether user_profile function works as expected"""

self.client.login(username="newuser", password="password123")
response = self.client.get(reverse("profile", args=["newuser"]))
self.assertEqual(response.status_code, 200)
self.assertContains(response, self.user.username)
self.assertContains(response, self.user.email)
self.assertTemplateUsed(response, "account.html")
27 changes: 16 additions & 11 deletions project/threads/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@
from django.contrib.auth import get_user_model
from django.http import (
JsonResponse,
HttpResponse,
HttpResponseServerError,
HttpResponseForbidden,
HttpResponseBadRequest,
Expand Down Expand Up @@ -311,11 +310,11 @@ def edit_civi(request):
body = request.POST.get("body", "")
civi_type = request.POST.get("type", "")

c = Civi.objects.get(id=civi_id)
if request.user.username != c.author.username:
return HttpResponseBadRequest(reason="No Edit Rights")

try:
c = Civi.objects.get(id=civi_id)
if request.user.username != c.author.username:
return HttpResponseBadRequest(reason="No Edit Rights")

c.title = title
c.body = body
c.c_type = civi_type
Expand All @@ -335,6 +334,12 @@ def edit_civi(request):
civi_image.delete()

return JsonResponse(c.dict_with_score(request.user.id))

except Civi.DoesNotExist:
return JsonResponse(
{"error": f"Civi with id:{civi_id} does not exist"},
status=400,
)
except Exception as e:
return HttpResponseServerError(reason=str(e))

Expand All @@ -346,12 +351,11 @@ def delete_civi(request):

c = Civi.objects.get(id=civi_id)
if request.user.username != c.author.username:
return HttpResponseBadRequest(reason="No Edit Rights")
return JsonResponse({"error": "No Edit Rights"}, status=400)

try:
c.delete()

return HttpResponse("Success")
return JsonResponse({"result": "Success"})
except Exception as e:
return HttpResponseServerError(reason=str(e))

Expand All @@ -368,7 +372,7 @@ def edit_thread(request):
is_draft = request.POST.get("is_draft", True)

if not thread_id:
return HttpResponseBadRequest(reason="Invalid Thread Reference")
return JsonResponse({"error": "Invalid Thread Reference"}, status=400)

# for some reason this is not cast to boolean in the request
if is_draft == "false":
Expand All @@ -391,8 +395,9 @@ def edit_thread(request):

req_edit_thread.save()
except Thread.DoesNotExist:
return HttpResponseServerError(
reason=f"Thread with id:{thread_id} does not exist"
return JsonResponse(
{"error": f"Thread with id:{thread_id} does not exist"},
status=400,
)
except Exception as e:
return HttpResponseServerError(reason=str(e))
Expand Down
2 changes: 1 addition & 1 deletion project/threads/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ def get_score(self, obj):
else:
return 0

if user.is_anonymous():
if not user.is_authenticated:
return 0
else:
return obj.score(user.id)
Expand Down
Loading