Merge branch 'main' into search-refactor

This commit is contained in:
Mouse Reeve
2021-09-30 10:40:57 -07:00
218 changed files with 8892 additions and 6942 deletions

View File

@ -1,5 +1,6 @@
""" testing models """
from unittest.mock import patch
from django.http import Http404
from django.test import TestCase
from bookwyrm import models
@ -39,14 +40,14 @@ class BaseModel(TestCase):
"""these should be generated"""
self.test_model.id = 1
expected = self.test_model.get_remote_id()
self.assertEqual(expected, "https://%s/bookwyrmtestmodel/1" % DOMAIN)
self.assertEqual(expected, f"https://{DOMAIN}/bookwyrmtestmodel/1")
def test_remote_id_with_user(self):
"""format of remote id when there's a user object"""
self.test_model.user = self.local_user
self.test_model.id = 1
expected = self.test_model.get_remote_id()
self.assertEqual(expected, "https://%s/user/mouse/bookwyrmtestmodel/1" % DOMAIN)
self.assertEqual(expected, f"https://{DOMAIN}/user/mouse/bookwyrmtestmodel/1")
def test_set_remote_id(self):
"""this function sets remote ids after creation"""
@ -55,9 +56,7 @@ class BaseModel(TestCase):
instance = models.Work.objects.create(title="work title")
instance.remote_id = None
base_model.set_remote_id(None, instance, True)
self.assertEqual(
instance.remote_id, "https://%s/book/%d" % (DOMAIN, instance.id)
)
self.assertEqual(instance.remote_id, f"https://{DOMAIN}/book/{instance.id}")
# shouldn't set remote_id if it's not created
instance.remote_id = None
@ -70,28 +69,30 @@ class BaseModel(TestCase):
obj = models.Status.objects.create(
content="hi", user=self.remote_user, privacy="public"
)
self.assertTrue(obj.visible_to_user(self.local_user))
self.assertIsNone(obj.raise_visible_to_user(self.local_user))
obj = models.Shelf.objects.create(
name="test", user=self.remote_user, privacy="unlisted"
)
self.assertTrue(obj.visible_to_user(self.local_user))
self.assertIsNone(obj.raise_visible_to_user(self.local_user))
obj = models.Status.objects.create(
content="hi", user=self.remote_user, privacy="followers"
)
self.assertFalse(obj.visible_to_user(self.local_user))
with self.assertRaises(Http404):
obj.raise_visible_to_user(self.local_user)
obj = models.Status.objects.create(
content="hi", user=self.remote_user, privacy="direct"
)
self.assertFalse(obj.visible_to_user(self.local_user))
with self.assertRaises(Http404):
obj.raise_visible_to_user(self.local_user)
obj = models.Status.objects.create(
content="hi", user=self.remote_user, privacy="direct"
)
obj.mention_users.add(self.local_user)
self.assertTrue(obj.visible_to_user(self.local_user))
self.assertIsNone(obj.raise_visible_to_user(self.local_user))
@patch("bookwyrm.activitystreams.add_status_task.delay")
def test_object_visible_to_user_follower(self, _):
@ -100,18 +101,19 @@ class BaseModel(TestCase):
obj = models.Status.objects.create(
content="hi", user=self.remote_user, privacy="followers"
)
self.assertTrue(obj.visible_to_user(self.local_user))
self.assertIsNone(obj.raise_visible_to_user(self.local_user))
obj = models.Status.objects.create(
content="hi", user=self.remote_user, privacy="direct"
)
self.assertFalse(obj.visible_to_user(self.local_user))
with self.assertRaises(Http404):
obj.raise_visible_to_user(self.local_user)
obj = models.Status.objects.create(
content="hi", user=self.remote_user, privacy="direct"
)
obj.mention_users.add(self.local_user)
self.assertTrue(obj.visible_to_user(self.local_user))
self.assertIsNone(obj.raise_visible_to_user(self.local_user))
@patch("bookwyrm.activitystreams.add_status_task.delay")
def test_object_visible_to_user_blocked(self, _):
@ -120,9 +122,11 @@ class BaseModel(TestCase):
obj = models.Status.objects.create(
content="hi", user=self.remote_user, privacy="public"
)
self.assertFalse(obj.visible_to_user(self.local_user))
with self.assertRaises(Http404):
obj.raise_visible_to_user(self.local_user)
obj = models.Shelf.objects.create(
name="test", user=self.remote_user, privacy="unlisted"
)
self.assertFalse(obj.visible_to_user(self.local_user))
with self.assertRaises(Http404):
obj.raise_visible_to_user(self.local_user)

View File

@ -0,0 +1,95 @@
""" testing models """
from datetime import timedelta
from unittest.mock import patch
from django.db import IntegrityError
from django.test import TestCase
from django.utils import timezone
from bookwyrm import models, settings
class SiteModels(TestCase):
"""tests for site models"""
def setUp(self):
"""we need basic test data and mocks"""
with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch(
"bookwyrm.activitystreams.populate_stream_task.delay"
):
self.local_user = models.User.objects.create_user(
"mouse@local.com",
"mouse@mouse.com",
"mouseword",
local=True,
localname="mouse",
remote_id="https://example.com/users/mouse",
)
def test_site_settings_absent(self):
"""create and load site settings"""
self.assertFalse(models.SiteSettings.objects.exists())
result = models.SiteSettings.get()
self.assertTrue(models.SiteSettings.objects.exists())
self.assertEqual(result.id, 1)
self.assertEqual(result.name, "BookWyrm")
def test_site_settings_present(self):
"""load site settings"""
models.SiteSettings.objects.create(id=1, name="Fish Town")
result = models.SiteSettings.get()
self.assertEqual(result.id, 1)
self.assertEqual(result.name, "Fish Town")
self.assertEqual(models.SiteSettings.objects.all().count(), 1)
def test_site_invite(self):
"""default invite"""
invite = models.SiteInvite.objects.create(
user=self.local_user,
)
self.assertTrue(invite.valid())
def test_site_invite_with_limit(self):
"""with use limit"""
# valid
invite = models.SiteInvite.objects.create(user=self.local_user, use_limit=1)
self.assertTrue(invite.valid())
# invalid
invite = models.SiteInvite.objects.create(user=self.local_user, use_limit=0)
self.assertFalse(invite.valid())
invite = models.SiteInvite.objects.create(
user=self.local_user, use_limit=1, times_used=1
)
self.assertFalse(invite.valid())
def test_site_invite_with_expiry(self):
"""with expiration date"""
date = timezone.now() + timedelta(days=1)
invite = models.SiteInvite.objects.create(user=self.local_user, expiry=date)
self.assertTrue(invite.valid())
date = timezone.now() - timedelta(days=1)
invite = models.SiteInvite.objects.create(user=self.local_user, expiry=date)
self.assertFalse(invite.valid())
def test_site_invite_link(self):
"""invite link generator"""
invite = models.SiteInvite.objects.create(user=self.local_user, code="hello")
self.assertEqual(invite.link, f"https://{settings.DOMAIN}/invite/hello")
def test_invite_request(self):
"""someone wants an invite"""
# normal and good
request = models.InviteRequest.objects.create(email="mouse.reeve@gmail.com")
self.assertIsNone(request.invite)
# already in use
with self.assertRaises(IntegrityError):
request = models.InviteRequest.objects.create(email="mouse@mouse.com")
def test_password_reset(self):
"""password reset token"""
token = models.PasswordReset.objects.create(user=self.local_user, code="hello")
self.assertTrue(token.valid())
self.assertEqual(token.link, f"https://{settings.DOMAIN}/password-reset/hello")

View File

@ -20,6 +20,7 @@ from bookwyrm.preview_images import (
# pylint: disable=unused-argument
# pylint: disable=missing-function-docstring
# pylint: disable=consider-using-with
class PreviewImages(TestCase):
"""every response to a get request, html or json"""
@ -120,3 +121,11 @@ class PreviewImages(TestCase):
self.assertEqual(
self.local_user.preview_image.height, settings.PREVIEW_IMG_HEIGHT
)
def test_generate_user_preview_images_task(self, *args, **kwargs):
"""test task's external calls"""
with patch("bookwyrm.preview_images.generate_preview_image") as generate_mock:
generate_user_preview_image_task(self.local_user.id)
args = generate_mock.call_args.kwargs
self.assertEqual(args["texts"]["text_one"], "possum")
self.assertEqual(args["texts"]["text_three"], f"@possum@{settings.DOMAIN}")

View File

@ -0,0 +1 @@
from . import *

View File

@ -1,5 +1,6 @@
""" test for app action functionality """
from unittest.mock import patch
from tidylib import tidy_document
from django.template.response import TemplateResponse
from django.test import TestCase
from django.test.client import RequestFactory
@ -34,5 +35,8 @@ class DashboardViews(TestCase):
request.user.is_superuser = True
result = view(request)
self.assertIsInstance(result, TemplateResponse)
result.render()
html = result.render()
_, errors = tidy_document(html.content)
if errors:
raise Exception(errors)
self.assertEqual(result.status_code, 200)

View File

@ -1,5 +1,7 @@
""" test for app action functionality """
from unittest.mock import patch
from tidylib import tidy_document
from django.template.response import TemplateResponse
from django.test import TestCase
from django.test.client import RequestFactory
@ -36,7 +38,10 @@ class EmailBlocklistViews(TestCase):
result = view(request)
self.assertIsInstance(result, TemplateResponse)
result.render()
html = result.render()
_, errors = tidy_document(html.content, options={"drop-empty-elements": False})
if errors:
raise Exception(errors)
self.assertEqual(result.status_code, 200)
def test_blocklist_page_post(self):
@ -49,7 +54,10 @@ class EmailBlocklistViews(TestCase):
result = view(request)
self.assertIsInstance(result, TemplateResponse)
result.render()
html = result.render()
_, errors = tidy_document(html.content, options={"drop-empty-elements": False})
if errors:
raise Exception(errors)
self.assertEqual(result.status_code, 200)
self.assertTrue(

View File

@ -1,6 +1,8 @@
""" test for app action functionality """
import json
from unittest.mock import patch
from tidylib import tidy_document
from django.core.files.uploadedfile import SimpleUploadedFile
from django.template.response import TemplateResponse
from django.test import TestCase
@ -46,10 +48,19 @@ class FederationViews(TestCase):
request.user.is_superuser = True
result = view(request)
self.assertIsInstance(result, TemplateResponse)
result.render()
html = result.render()
_, errors = tidy_document(
html.content,
options={
"drop-empty-elements": False,
"warn-proprietary-attributes": False,
},
)
if errors:
raise Exception(errors)
self.assertEqual(result.status_code, 200)
def test_server_page(self):
def test_instance_page(self):
"""there are so many views, this just makes sure it LOADS"""
server = models.FederatedServer.objects.create(server_name="hi.there.com")
view = views.FederatedServer.as_view()
@ -59,7 +70,10 @@ class FederationViews(TestCase):
result = view(request, server.id)
self.assertIsInstance(result, TemplateResponse)
result.render()
html = result.render()
_, errors = tidy_document(html.content, options={"drop-empty-elements": False})
if errors:
raise Exception(errors)
self.assertEqual(result.status_code, 200)
def test_server_page_block(self):
@ -148,7 +162,10 @@ class FederationViews(TestCase):
result = view(request)
self.assertIsInstance(result, TemplateResponse)
result.render()
html = result.render()
_, errors = tidy_document(html.content)
if errors:
raise Exception(errors)
self.assertEqual(result.status_code, 200)
def test_add_view_post_create(self):
@ -169,6 +186,7 @@ class FederationViews(TestCase):
self.assertEqual(server.application_type, "coolsoft")
self.assertEqual(server.status, "blocked")
# pylint: disable=consider-using-with
def test_import_blocklist(self):
"""load a json file with a list of servers to block"""
server = models.FederatedServer.objects.create(server_name="hi.there.com")
@ -180,7 +198,7 @@ class FederationViews(TestCase):
{"instance": "hi.there.com", "url": "https://explanation.url"}, # existing
{"a": "b"}, # invalid
]
json.dump(data, open("file.json", "w"))
json.dump(data, open("file.json", "w")) # pylint: disable=unspecified-encoding
view = views.ImportServerBlocklist.as_view()
request = self.factory.post(

View File

@ -0,0 +1,44 @@
""" test for app action functionality """
from unittest.mock import patch
from tidylib import tidy_document
from django.template.response import TemplateResponse
from django.test import TestCase
from django.test.client import RequestFactory
from bookwyrm import models, views
class IPBlocklistViews(TestCase):
"""every response to a get request, html or json"""
def setUp(self):
"""we need basic test data and mocks"""
self.factory = RequestFactory()
with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch(
"bookwyrm.activitystreams.populate_stream_task.delay"
):
self.local_user = models.User.objects.create_user(
"mouse@local.com",
"mouse@mouse.mouse",
"password",
local=True,
localname="mouse",
)
models.SiteSettings.objects.create()
def test_blocklist_page_get(self):
"""there are so many views, this just makes sure it LOADS"""
view = views.IPBlocklist.as_view()
request = self.factory.get("")
request.user = self.local_user
request.user.is_superuser = True
result = view(request)
self.assertIsInstance(result, TemplateResponse)
html = result.render()
_, errors = tidy_document(html.content, options={"drop-empty-elements": False})
if errors:
raise Exception(errors)
self.assertEqual(result.status_code, 200)

View File

@ -1,6 +1,8 @@
""" test for app action functionality """
import json
from unittest.mock import patch
from tidylib import tidy_document
from django.template.response import TemplateResponse
from django.test import TestCase
from django.test.client import RequestFactory
@ -42,7 +44,16 @@ class ReportViews(TestCase):
result = view(request)
self.assertIsInstance(result, TemplateResponse)
result.render()
html = result.render()
_, errors = tidy_document(
html.content,
options={
"drop-empty-elements": False,
"warn-proprietary-attributes": False,
},
)
if errors:
raise Exception(errors)
self.assertEqual(result.status_code, 200)
def test_reports_page_with_data(self):
@ -55,7 +66,16 @@ class ReportViews(TestCase):
result = view(request)
self.assertIsInstance(result, TemplateResponse)
result.render()
html = result.render()
_, errors = tidy_document(
html.content,
options={
"drop-empty-elements": False,
"warn-proprietary-attributes": False,
},
)
if errors:
raise Exception(errors)
self.assertEqual(result.status_code, 200)
def test_report_page(self):
@ -69,7 +89,10 @@ class ReportViews(TestCase):
result = view(request, report.id)
self.assertIsInstance(result, TemplateResponse)
result.render()
html = result.render()
_, errors = tidy_document(html.content, options={"drop-empty-elements": False})
if errors:
raise Exception(errors)
self.assertEqual(result.status_code, 200)
def test_report_comment(self):

View File

@ -1,5 +1,7 @@
""" test for app action functionality """
from unittest.mock import patch
from tidylib import tidy_document
from django.contrib.auth.models import Group
from django.template.response import TemplateResponse
from django.test import TestCase
@ -34,7 +36,10 @@ class UserAdminViews(TestCase):
request.user.is_superuser = True
result = view(request)
self.assertIsInstance(result, TemplateResponse)
result.render()
html = result.render()
_, errors = tidy_document(html.content, options={"drop-empty-elements": False})
if errors:
raise Exception(errors)
self.assertEqual(result.status_code, 200)
def test_user_admin_page(self):
@ -47,7 +52,10 @@ class UserAdminViews(TestCase):
result = view(request, self.local_user.id)
self.assertIsInstance(result, TemplateResponse)
result.render()
html = result.render()
_, errors = tidy_document(html.content, options={"drop-empty-elements": False})
if errors:
raise Exception(errors)
self.assertEqual(result.status_code, 200)
@patch("bookwyrm.suggested_users.rerank_suggestions_task.delay")
@ -69,7 +77,10 @@ class UserAdminViews(TestCase):
result = view(request, self.local_user.id)
self.assertIsInstance(result, TemplateResponse)
result.render()
html = result.render()
_, errors = tidy_document(html.content, options={"drop-empty-elements": False})
if errors:
raise Exception(errors)
self.assertEqual(
list(self.local_user.groups.values_list("name", flat=True)), ["editor"]

View File

@ -3,6 +3,7 @@ import json
import pathlib
from unittest.mock import patch
from django.core.exceptions import PermissionDenied
from django.http import HttpResponseNotAllowed, HttpResponseNotFound
from django.test import TestCase, Client
from django.test.client import RequestFactory
@ -130,22 +131,24 @@ class Inbox(TestCase):
"",
HTTP_USER_AGENT="http.rb/4.4.1 (Mastodon/3.3.0; +https://mastodon.social/)",
)
self.assertFalse(views.inbox.is_blocked_user_agent(request))
self.assertIsNone(views.inbox.raise_is_blocked_user_agent(request))
models.FederatedServer.objects.create(
server_name="mastodon.social", status="blocked"
)
self.assertTrue(views.inbox.is_blocked_user_agent(request))
with self.assertRaises(PermissionDenied):
views.inbox.raise_is_blocked_user_agent(request)
def test_is_blocked_activity(self):
"""check for blocked servers"""
activity = {"actor": "https://mastodon.social/user/whaatever/else"}
self.assertFalse(views.inbox.is_blocked_activity(activity))
self.assertIsNone(views.inbox.raise_is_blocked_activity(activity))
models.FederatedServer.objects.create(
server_name="mastodon.social", status="blocked"
)
self.assertTrue(views.inbox.is_blocked_activity(activity))
with self.assertRaises(PermissionDenied):
views.inbox.raise_is_blocked_activity(activity)
@patch("bookwyrm.suggested_users.remove_user_task.delay")
def test_create_by_deactivated_user(self, _):
@ -157,11 +160,11 @@ class Inbox(TestCase):
activity = self.create_json
activity["actor"] = self.remote_user.remote_id
activity["object"] = status_data
activity["type"] = "Create"
with patch("bookwyrm.views.inbox.has_valid_signature") as mock_valid:
mock_valid.return_value = True
result = self.client.post(
"/inbox", json.dumps(activity), content_type="application/json"
)
self.assertEqual(result.status_code, 403)
response = self.client.post(
"/inbox",
json.dumps(activity),
content_type="application/json",
)
self.assertEqual(response.status_code, 403)

View File

@ -0,0 +1 @@
from . import *

View File

@ -1,5 +1,7 @@
""" test for app action functionality """
from unittest.mock import patch
from tidylib import tidy_document
from django.template.response import TemplateResponse
from django.test import TestCase
from django.test.client import RequestFactory
@ -44,7 +46,10 @@ class BlockViews(TestCase):
request.user = self.local_user
result = view(request)
self.assertIsInstance(result, TemplateResponse)
result.render()
html = result.render()
_, errors = tidy_document(html.content)
if errors:
raise Exception(errors)
self.assertEqual(result.status_code, 200)
def test_block_post(self, _):
@ -75,6 +80,6 @@ class BlockViews(TestCase):
request.user = self.local_user
with patch("bookwyrm.activitystreams.add_user_statuses_task.delay"):
views.block.unblock(request, self.remote_user.id)
views.unblock(request, self.remote_user.id)
self.assertFalse(models.UserBlocks.objects.exists())

View File

@ -0,0 +1,61 @@
""" test for app action functionality """
from unittest.mock import patch
from tidylib import tidy_document
from django.template.response import TemplateResponse
from django.test import TestCase
from django.test.client import RequestFactory
from bookwyrm import models, views
class ChangePasswordViews(TestCase):
"""view user and edit profile"""
def setUp(self):
"""we need basic test data and mocks"""
self.factory = RequestFactory()
with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch(
"bookwyrm.activitystreams.populate_stream_task.delay"
):
self.local_user = models.User.objects.create_user(
"mouse@local.com",
"mouse@mouse.com",
"password",
local=True,
localname="mouse",
)
models.SiteSettings.objects.create(id=1)
def test_password_change_get(self):
"""there are so many views, this just makes sure it LOADS"""
view = views.ChangePassword.as_view()
request = self.factory.get("")
request.user = self.local_user
result = view(request)
self.assertIsInstance(result, TemplateResponse)
html = result.render()
_, errors = tidy_document(html.content)
if errors:
raise Exception(errors)
self.assertEqual(result.status_code, 200)
def test_password_change(self):
"""change password"""
view = views.ChangePassword.as_view()
password_hash = self.local_user.password
request = self.factory.post("", {"password": "hi", "confirm-password": "hi"})
request.user = self.local_user
with patch("bookwyrm.views.preferences.change_password.login"):
view(request)
self.assertNotEqual(self.local_user.password, password_hash)
def test_password_change_mismatch(self):
"""change password"""
view = views.ChangePassword.as_view()
password_hash = self.local_user.password
request = self.factory.post("", {"password": "hi", "confirm-password": "hihi"})
request.user = self.local_user
view(request)
self.assertEqual(self.local_user.password, password_hash)

View File

@ -0,0 +1,89 @@
""" test for app action functionality """
import json
from unittest.mock import patch
from tidylib import tidy_document
from django.contrib.sessions.middleware import SessionMiddleware
from django.template.response import TemplateResponse
from django.test import TestCase
from django.test.client import RequestFactory
from bookwyrm import forms, models, views
@patch("bookwyrm.suggested_users.remove_user_task.delay")
class DeleteUserViews(TestCase):
"""view user and edit profile"""
def setUp(self):
"""we need basic test data and mocks"""
self.factory = RequestFactory()
with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch(
"bookwyrm.activitystreams.populate_stream_task.delay"
):
self.local_user = models.User.objects.create_user(
"mouse@local.com",
"mouse@mouse.mouse",
"password",
local=True,
localname="mouse",
)
self.rat = models.User.objects.create_user(
"rat@local.com", "rat@rat.rat", "password", local=True, localname="rat"
)
self.book = models.Edition.objects.create(
title="test", parent_work=models.Work.objects.create(title="test work")
)
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"), patch(
"bookwyrm.activitystreams.add_book_statuses_task.delay"
):
models.ShelfBook.objects.create(
book=self.book,
user=self.local_user,
shelf=self.local_user.shelf_set.first(),
)
models.SiteSettings.objects.create()
def test_delete_user_page(self, _):
"""there are so many views, this just makes sure it LOADS"""
view = views.DeleteUser.as_view()
request = self.factory.get("")
request.user = self.local_user
result = view(request)
self.assertIsInstance(result, TemplateResponse)
html = result.render()
_, errors = tidy_document(html.content)
if errors:
raise Exception(errors)
self.assertEqual(result.status_code, 200)
@patch("bookwyrm.suggested_users.rerank_suggestions_task")
def test_delete_user(self, *_):
"""use a form to update a user"""
view = views.DeleteUser.as_view()
form = forms.DeleteUserForm()
form.data["password"] = "password"
request = self.factory.post("", form.data)
request.user = self.local_user
middleware = SessionMiddleware()
middleware.process_request(request)
request.session.save()
self.assertIsNone(self.local_user.name)
with patch(
"bookwyrm.models.activitypub_mixin.broadcast_task.delay"
) as delay_mock:
view(request)
self.assertEqual(delay_mock.call_count, 1)
activity = json.loads(delay_mock.call_args[0][1])
self.assertEqual(activity["type"], "Delete")
self.assertEqual(activity["actor"], self.local_user.remote_id)
self.assertEqual(
activity["cc"][0], "https://www.w3.org/ns/activitystreams#Public"
)
self.local_user.refresh_from_db()
self.assertFalse(self.local_user.is_active)
self.assertEqual(self.local_user.deactivation_reason, "self_deletion")

View File

@ -1,11 +1,10 @@
""" test for app action functionality """
import json
import pathlib
from unittest.mock import patch
from PIL import Image
from tidylib import tidy_document
from django.contrib.auth.models import AnonymousUser
from django.contrib.sessions.middleware import SessionMiddleware
from django.core.files.base import ContentFile
from django.core.files.uploadedfile import SimpleUploadedFile
from django.template.response import TemplateResponse
@ -59,7 +58,10 @@ class EditUserViews(TestCase):
request.user = self.local_user
result = view(request)
self.assertIsInstance(result, TemplateResponse)
result.render()
html = result.render()
_, errors = tidy_document(html.content)
if errors:
raise Exception(errors)
self.assertEqual(result.status_code, 200)
def test_edit_user(self, _):
@ -91,8 +93,9 @@ class EditUserViews(TestCase):
form.data["default_post_privacy"] = "public"
form.data["preferred_timezone"] = "UTC"
image_file = pathlib.Path(__file__).parent.joinpath(
"../../static/images/no_cover.jpg"
"../../../static/images/no_cover.jpg"
)
# pylint: disable=consider-using-with
form.data["avatar"] = SimpleUploadedFile(
image_file, open(image_file, "rb").read(), content_type="image/jpeg"
)
@ -113,50 +116,11 @@ class EditUserViews(TestCase):
def test_crop_avatar(self, _):
"""reduce that image size"""
image_file = pathlib.Path(__file__).parent.joinpath(
"../../static/images/no_cover.jpg"
"../../../static/images/no_cover.jpg"
)
image = Image.open(image_file)
result = views.edit_user.crop_avatar(image)
result = views.preferences.edit_user.crop_avatar(image)
self.assertIsInstance(result, ContentFile)
image_result = Image.open(result)
self.assertEqual(image_result.size, (120, 120))
def test_delete_user_page(self, _):
"""there are so many views, this just makes sure it LOADS"""
view = views.DeleteUser.as_view()
request = self.factory.get("")
request.user = self.local_user
result = view(request)
self.assertIsInstance(result, TemplateResponse)
result.render()
self.assertEqual(result.status_code, 200)
@patch("bookwyrm.suggested_users.rerank_suggestions_task")
def test_delete_user(self, *_):
"""use a form to update a user"""
view = views.DeleteUser.as_view()
form = forms.DeleteUserForm()
form.data["password"] = "password"
request = self.factory.post("", form.data)
request.user = self.local_user
middleware = SessionMiddleware()
middleware.process_request(request)
request.session.save()
self.assertIsNone(self.local_user.name)
with patch(
"bookwyrm.models.activitypub_mixin.broadcast_task.delay"
) as delay_mock:
view(request)
self.assertEqual(delay_mock.call_count, 1)
activity = json.loads(delay_mock.call_args[0][1])
self.assertEqual(activity["type"], "Delete")
self.assertEqual(activity["actor"], self.local_user.remote_id)
self.assertEqual(
activity["cc"][0], "https://www.w3.org/ns/activitystreams#Public"
)
self.local_user.refresh_from_db()
self.assertFalse(self.local_user.is_active)
self.assertEqual(self.local_user.deactivation_reason, "self_deletion")

View File

@ -9,6 +9,7 @@ import responses
from django.contrib.auth.models import Group, Permission
from django.contrib.contenttypes.models import ContentType
from django.core.files.uploadedfile import SimpleUploadedFile
from django.http import Http404
from django.template.response import TemplateResponse
from django.test import TestCase
from django.test.client import RequestFactory
@ -133,8 +134,8 @@ class BookViews(TestCase):
request.user = self.local_user
with patch("bookwyrm.views.books.is_api_request") as is_api:
is_api.return_value = False
result = view(request, 0)
self.assertEqual(result.status_code, 404)
with self.assertRaises(Http404):
view(request, 0)
def test_book_page_work_id(self):
"""there are so many views, this just makes sure it LOADS"""
@ -282,6 +283,46 @@ class BookViews(TestCase):
self.assertEqual(book.authors.first().name, "Sappho")
self.assertEqual(book.authors.first(), book.parent_work.authors.first())
def _setup_cover_url(self):
cover_url = "http://example.com"
image_file = pathlib.Path(__file__).parent.joinpath(
"../../static/images/default_avi.jpg"
)
image = Image.open(image_file)
output = BytesIO()
image.save(output, format=image.format)
responses.add(
responses.GET,
cover_url,
body=output.getvalue(),
status=200,
)
return cover_url
@responses.activate
def test_create_book_upload_cover_url(self):
"""create an entirely new book and work with cover url"""
self.assertFalse(self.book.cover)
view = views.ConfirmEditBook.as_view()
self.local_user.groups.add(self.group)
cover_url = self._setup_cover_url()
form = forms.EditionForm()
form.data["title"] = "New Title"
form.data["last_edited_by"] = self.local_user.id
form.data["cover-url"] = cover_url
request = self.factory.post("", form.data)
request.user = self.local_user
with patch(
"bookwyrm.models.activitypub_mixin.broadcast_task.delay"
) as delay_mock:
views.upload_cover(request, self.book.id)
self.assertEqual(delay_mock.call_count, 1)
self.book.refresh_from_db()
self.assertTrue(self.book.cover)
def test_upload_cover_file(self):
"""add a cover via file upload"""
self.assertFalse(self.book.cover)
@ -310,21 +351,8 @@ class BookViews(TestCase):
def test_upload_cover_url(self):
"""add a cover via url"""
self.assertFalse(self.book.cover)
image_file = pathlib.Path(__file__).parent.joinpath(
"../../static/images/default_avi.jpg"
)
image = Image.open(image_file)
output = BytesIO()
image.save(output, format=image.format)
responses.add(
responses.GET,
"http://example.com",
body=output.getvalue(),
status=200,
)
form = forms.CoverForm(instance=self.book)
form.data["cover-url"] = "http://example.com"
form.data["cover-url"] = self._setup_cover_url()
request = self.factory.post("", form.data)
request.user = self.local_user

View File

@ -1,5 +1,6 @@
""" test for app action functionality """
from unittest.mock import patch
from tidylib import tidy_document
from django.contrib.auth.models import AnonymousUser
from django.template.response import TemplateResponse
@ -51,7 +52,16 @@ class DirectoryViews(TestCase):
result = view(request)
self.assertIsInstance(result, TemplateResponse)
result.render()
html = result.render()
_, errors = tidy_document(
html.content,
options={
"drop-empty-elements": False,
"warn-proprietary-attributes": False,
},
)
if errors:
raise Exception(errors)
self.assertEqual(result.status_code, 200)
def test_directory_page_empty(self):
@ -62,7 +72,10 @@ class DirectoryViews(TestCase):
result = view(request)
self.assertIsInstance(result, TemplateResponse)
result.render()
html = result.render()
_, errors = tidy_document(html.content, options={"drop-empty-elements": False})
if errors:
raise Exception(errors)
self.assertEqual(result.status_code, 200)
def test_directory_page_logged_out(self):

View File

@ -5,6 +5,7 @@ import pathlib
from PIL import Image
from django.core.files.base import ContentFile
from django.http import Http404
from django.template.response import TemplateResponse
from django.test import TestCase
from django.test.client import RequestFactory
@ -81,9 +82,8 @@ class FeedViews(TestCase):
request.user = self.local_user
with patch("bookwyrm.views.feed.is_api_request") as is_api:
is_api.return_value = False
result = view(request, "mouse", 12345)
self.assertEqual(result.status_code, 404)
with self.assertRaises(Http404):
view(request, "mouse", 12345)
def test_status_page_not_found_wrong_user(self, *_):
"""there are so many views, this just makes sure it LOADS"""
@ -102,9 +102,8 @@ class FeedViews(TestCase):
request.user = self.local_user
with patch("bookwyrm.views.feed.is_api_request") as is_api:
is_api.return_value = False
result = view(request, "mouse", status.id)
self.assertEqual(result.status_code, 404)
with self.assertRaises(Http404):
view(request, "mouse", status.id)
def test_status_page_with_image(self, *_):
"""there are so many views, this just makes sure it LOADS"""

View File

@ -1,11 +1,13 @@
""" test for app action functionality """
from unittest.mock import patch
from django.utils import timezone
from tidylib import tidy_document
from django.contrib.auth.models import AnonymousUser
from django.http import Http404
from django.template.response import TemplateResponse
from django.test import TestCase
from django.test.client import RequestFactory
from django.utils import timezone
from bookwyrm import models, views
@ -60,7 +62,16 @@ class GoalViews(TestCase):
request.user = self.local_user
result = view(request, self.local_user.localname, self.year)
result.render()
html = result.render()
_, errors = tidy_document(
html.content,
options={
"drop-empty-elements": False,
"warn-proprietary-attributes": False,
},
)
if errors:
raise Exception(errors)
self.assertIsInstance(result, TemplateResponse)
def test_goal_page_anonymous(self):
@ -91,7 +102,16 @@ class GoalViews(TestCase):
request.user = self.rat
result = view(request, self.local_user.localname, timezone.now().year)
result.render()
html = result.render()
_, errors = tidy_document(
html.content,
options={
"drop-empty-elements": False,
"warn-proprietary-attributes": False,
},
)
if errors:
raise Exception(errors)
self.assertIsInstance(result, TemplateResponse)
def test_goal_page_private(self):
@ -103,8 +123,8 @@ class GoalViews(TestCase):
request = self.factory.get("")
request.user = self.rat
result = view(request, self.local_user.localname, self.year)
self.assertEqual(result.status_code, 404)
with self.assertRaises(Http404):
view(request, self.local_user.localname, self.year)
@patch("bookwyrm.activitystreams.add_status_task.delay")
def test_create_goal(self, _):

View File

@ -568,5 +568,6 @@ class ListActionViews(TestCase):
)
request.user = self.rat
views.list.remove_book(request, self.list.id)
with self.assertRaises(PermissionDenied):
views.list.remove_book(request, self.list.id)
self.assertTrue(self.list.listitem_set.exists())

View File

@ -43,12 +43,14 @@ class PasswordViews(TestCase):
def test_password_reset_request_post(self):
"""send 'em an email"""
request = self.factory.post("", {"email": "aa@bb.ccc"})
request.user = self.anonymous_user
view = views.PasswordResetRequest.as_view()
resp = view(request)
self.assertEqual(resp.status_code, 200)
resp.render()
request = self.factory.post("", {"email": "mouse@mouse.com"})
request.user = self.anonymous_user
with patch("bookwyrm.emailing.send_email.delay"):
resp = view(request)
resp.render()
@ -93,33 +95,3 @@ class PasswordViews(TestCase):
resp = view(request, code.code)
resp.render()
self.assertTrue(models.PasswordReset.objects.exists())
def test_password_change_get(self):
"""there are so many views, this just makes sure it LOADS"""
view = views.ChangePassword.as_view()
request = self.factory.get("")
request.user = self.local_user
result = view(request)
self.assertIsInstance(result, TemplateResponse)
result.render()
self.assertEqual(result.status_code, 200)
def test_password_change(self):
"""change password"""
view = views.ChangePassword.as_view()
password_hash = self.local_user.password
request = self.factory.post("", {"password": "hi", "confirm-password": "hi"})
request.user = self.local_user
with patch("bookwyrm.views.password.login"):
view(request)
self.assertNotEqual(self.local_user.password, password_hash)
def test_password_change_mismatch(self):
"""change password"""
view = views.ChangePassword.as_view()
password_hash = self.local_user.password
request = self.factory.post("", {"password": "hi", "confirm-password": "hihi"})
request.user = self.local_user
view(request)
self.assertEqual(self.local_user.password, password_hash)

View File

@ -113,6 +113,7 @@ class ReadingViews(TestCase):
{
"post-status": True,
"privacy": "followers",
"start_date": readthrough.start_date,
"finish_date": timezone.now().isoformat(),
"id": readthrough.id,
},

View File

@ -1,11 +1,14 @@
""" test for app action functionality """
import json
from unittest.mock import patch
from tidylib import tidy_document
from django.core.exceptions import PermissionDenied
from django.template.response import TemplateResponse
from django.test import TestCase
from django.test.client import RequestFactory
from bookwyrm import models, views
from bookwyrm import forms, models, views
from bookwyrm.activitypub import ActivitypubResponse
@ -53,7 +56,16 @@ class ShelfViews(TestCase):
is_api.return_value = False
result = view(request, self.local_user.username, shelf.identifier)
self.assertIsInstance(result, TemplateResponse)
result.render()
html = result.render()
_, errors = tidy_document(
html.content,
options={
"drop-empty-elements": False,
"warn-proprietary-attributes": False,
},
)
if errors:
raise Exception(errors)
self.assertEqual(result.status_code, 200)
with patch("bookwyrm.views.shelf.is_api_request") as is_api:
@ -105,7 +117,7 @@ class ShelfViews(TestCase):
shelf.refresh_from_db()
self.assertEqual(shelf.name, "cool name")
self.assertEqual(shelf.identifier, "testshelf-%d" % shelf.id)
self.assertEqual(shelf.identifier, f"testshelf-{shelf.id}")
def test_edit_shelf_name_not_editable(self, *_):
"""can't change the name of an non-editable shelf"""
@ -122,7 +134,7 @@ class ShelfViews(TestCase):
self.assertEqual(shelf.name, "To Read")
def test_handle_shelve(self, *_):
def test_shelve(self, *_):
"""shelve a book"""
request = self.factory.post(
"", {"book": self.book.id, "shelf": self.shelf.identifier}
@ -140,7 +152,7 @@ class ShelfViews(TestCase):
# make sure the book is on the shelf
self.assertEqual(self.shelf.books.get(), self.book)
def test_handle_shelve_to_read(self, *_):
def test_shelve_to_read(self, *_):
"""special behavior for the to-read shelf"""
shelf = models.Shelf.objects.get(identifier="to-read")
request = self.factory.post(
@ -153,7 +165,7 @@ class ShelfViews(TestCase):
# make sure the book is on the shelf
self.assertEqual(shelf.books.get(), self.book)
def test_handle_shelve_reading(self, *_):
def test_shelve_reading(self, *_):
"""special behavior for the reading shelf"""
shelf = models.Shelf.objects.get(identifier="reading")
request = self.factory.post(
@ -166,7 +178,7 @@ class ShelfViews(TestCase):
# make sure the book is on the shelf
self.assertEqual(shelf.books.get(), self.book)
def test_handle_shelve_read(self, *_):
def test_shelve_read(self, *_):
"""special behavior for the read shelf"""
shelf = models.Shelf.objects.get(identifier="read")
request = self.factory.post(
@ -179,7 +191,7 @@ class ShelfViews(TestCase):
# make sure the book is on the shelf
self.assertEqual(shelf.books.get(), self.book)
def test_handle_unshelve(self, *_):
def test_unshelve(self, *_):
"""remove a book from a shelf"""
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"):
models.ShelfBook.objects.create(
@ -197,3 +209,76 @@ class ShelfViews(TestCase):
self.assertEqual(activity["type"], "Remove")
self.assertEqual(activity["object"]["id"], item.remote_id)
self.assertEqual(self.shelf.books.count(), 0)
def test_create_shelf(self, *_):
"""a brand new custom shelf"""
form = forms.ShelfForm()
form.data["user"] = self.local_user.id
form.data["name"] = "new shelf name"
form.data["description"] = "desc"
form.data["privacy"] = "unlisted"
request = self.factory.post("", form.data)
request.user = self.local_user
views.create_shelf(request)
shelf = models.Shelf.objects.get(name="new shelf name")
self.assertEqual(shelf.privacy, "unlisted")
self.assertEqual(shelf.description, "desc")
self.assertEqual(shelf.user, self.local_user)
def test_delete_shelf(self, *_):
"""delete a brand new custom shelf"""
request = self.factory.post("")
request.user = self.local_user
shelf_id = self.shelf.id
views.delete_shelf(request, shelf_id)
self.assertFalse(models.Shelf.objects.filter(id=shelf_id).exists())
def test_delete_shelf_unauthorized(self, *_):
"""delete a brand new custom shelf"""
with patch("bookwyrm.suggested_users.rerank_suggestions_task.delay"), patch(
"bookwyrm.activitystreams.populate_stream_task.delay"
):
rat = models.User.objects.create_user(
"rat@local.com",
"rat@mouse.mouse",
"password",
local=True,
localname="rat",
)
request = self.factory.post("")
request.user = rat
with self.assertRaises(PermissionDenied):
views.delete_shelf(request, self.shelf.id)
self.assertTrue(models.Shelf.objects.filter(id=self.shelf.id).exists())
def test_delete_shelf_has_book(self, *_):
"""delete a brand new custom shelf"""
with patch("bookwyrm.models.activitypub_mixin.broadcast_task.delay"):
models.ShelfBook.objects.create(
book=self.book, user=self.local_user, shelf=self.shelf
)
request = self.factory.post("")
request.user = self.local_user
with self.assertRaises(PermissionDenied):
views.delete_shelf(request, self.shelf.id)
self.assertTrue(models.Shelf.objects.filter(id=self.shelf.id).exists())
def test_delete_shelf_not_editable(self, *_):
"""delete a brand new custom shelf"""
shelf = self.local_user.shelf_set.first()
self.assertFalse(shelf.editable)
request = self.factory.post("")
request.user = self.local_user
with self.assertRaises(PermissionDenied):
views.delete_shelf(request, shelf.id)
self.assertTrue(models.Shelf.objects.filter(id=shelf.id).exists())

View File

@ -1,6 +1,7 @@
""" test for app action functionality """
import json
from unittest.mock import patch
from django.core.exceptions import PermissionDenied
from django.test import TestCase
from django.test.client import RequestFactory
@ -101,7 +102,7 @@ class StatusViews(TestCase):
"""@mention a user in a post"""
view = views.CreateStatus.as_view()
user = models.User.objects.create_user(
"rat@%s" % DOMAIN,
f"rat@{DOMAIN}",
"rat@rat.com",
"password",
local=True,
@ -124,7 +125,7 @@ class StatusViews(TestCase):
self.assertEqual(list(status.mention_users.all()), [user])
self.assertEqual(models.Notification.objects.get().user, user)
self.assertEqual(
status.content, '<p>hi <a href="%s">@rat</a></p>' % user.remote_id
status.content, f'<p>hi <a href="{user.remote_id}">@rat</a></p>'
)
def test_handle_status_reply_with_mentions(self, *_):
@ -196,9 +197,9 @@ class StatusViews(TestCase):
)
with patch("bookwyrm.activitystreams.remove_status_task.delay") as mock:
result = view(request, status.id)
with self.assertRaises(PermissionDenied):
view(request, status.id)
self.assertFalse(mock.called)
self.assertEqual(result.status_code, 400)
status.refresh_from_db()
self.assertFalse(status.deleted)
@ -214,9 +215,9 @@ class StatusViews(TestCase):
)
with patch("bookwyrm.activitystreams.remove_status_task.delay") as mock:
result = view(request, status.id)
with self.assertRaises(PermissionDenied):
view(request, status.id)
self.assertFalse(mock.called)
self.assertEqual(result.status_code, 400)
status.refresh_from_db()
self.assertFalse(status.deleted)
@ -224,13 +225,13 @@ class StatusViews(TestCase):
def test_find_mentions(self, *_):
"""detect and look up @ mentions of users"""
user = models.User.objects.create_user(
"nutria@%s" % DOMAIN,
f"nutria@{DOMAIN}",
"nutria@nutria.com",
"password",
local=True,
localname="nutria",
)
self.assertEqual(user.username, "nutria@%s" % DOMAIN)
self.assertEqual(user.username, f"nutria@{DOMAIN}")
self.assertEqual(
list(views.status.find_mentions("@nutria"))[0], ("@nutria", user)
@ -263,19 +264,19 @@ class StatusViews(TestCase):
self.assertEqual(list(views.status.find_mentions("@beep@beep.com")), [])
self.assertEqual(
list(views.status.find_mentions("@nutria@%s" % DOMAIN))[0],
("@nutria@%s" % DOMAIN, user),
list(views.status.find_mentions(f"@nutria@{DOMAIN}"))[0],
(f"@nutria@{DOMAIN}", user),
)
def test_format_links_simple_url(self, *_):
"""find and format urls into a tags"""
url = "http://www.fish.com/"
self.assertEqual(
views.status.format_links(url), '<a href="%s">www.fish.com/</a>' % url
views.status.format_links(url), f'<a href="{url}">www.fish.com/</a>'
)
self.assertEqual(
views.status.format_links("(%s)" % url),
'(<a href="%s">www.fish.com/</a>)' % url,
views.status.format_links(f"({url})"),
f'(<a href="{url}">www.fish.com/</a>)',
)
def test_format_links_paragraph_break(self, *_):
@ -292,8 +293,8 @@ http://www.fish.com/"""
"""find and format urls into a tags"""
url = "http://www.fish.com/"
self.assertEqual(
views.status.format_links("(%s)" % url),
'(<a href="%s">www.fish.com/</a>)' % url,
views.status.format_links(f"({url})"),
f'(<a href="{url}">www.fish.com/</a>)',
)
def test_format_links_special_chars(self, *_):
@ -301,27 +302,27 @@ http://www.fish.com/"""
url = "https://archive.org/details/dli.granth.72113/page/n25/mode/2up"
self.assertEqual(
views.status.format_links(url),
'<a href="%s">'
"archive.org/details/dli.granth.72113/page/n25/mode/2up</a>" % url,
f'<a href="{url}">'
"archive.org/details/dli.granth.72113/page/n25/mode/2up</a>",
)
url = "https://openlibrary.org/search?q=arkady+strugatsky&mode=everything"
self.assertEqual(
views.status.format_links(url),
'<a href="%s">openlibrary.org/search'
"?q=arkady+strugatsky&mode=everything</a>" % url,
f'<a href="{url}">openlibrary.org/search'
"?q=arkady+strugatsky&mode=everything</a>",
)
url = "https://tech.lgbt/@bookwyrm"
self.assertEqual(
views.status.format_links(url), '<a href="%s">tech.lgbt/@bookwyrm</a>' % url
views.status.format_links(url), f'<a href="{url}">tech.lgbt/@bookwyrm</a>'
)
url = "https://users.speakeasy.net/~lion/nb/book.pdf"
self.assertEqual(
views.status.format_links(url),
'<a href="%s">users.speakeasy.net/~lion/nb/book.pdf</a>' % url,
f'<a href="{url}">users.speakeasy.net/~lion/nb/book.pdf</a>',
)
url = "https://pkm.one/#/page/The%20Book%20which%20launched%20a%201000%20Note%20taking%20apps"
url = "https://pkm.one/#/page/The%20Book%20launched%20a%201000%20Note%20apps"
self.assertEqual(
views.status.format_links(url), '<a href="%s">%s</a>' % (url, url[8:])
views.status.format_links(url), f'<a href="{url}">{url[8:]}</a>'
)
def test_to_markdown(self, *_):
@ -375,7 +376,8 @@ http://www.fish.com/"""
request = self.factory.post("")
request.user = self.remote_user
view(request, status.id)
with self.assertRaises(PermissionDenied):
view(request, status.id)
status.refresh_from_db()
self.assertFalse(status.deleted)

View File

@ -1,5 +1,6 @@
""" test for app action functionality """
from unittest.mock import patch
from tidylib import tidy_document
from django.contrib.auth.models import AnonymousUser
from django.http.response import Http404
@ -55,7 +56,16 @@ class UserViews(TestCase):
is_api.return_value = False
result = view(request, "mouse")
self.assertIsInstance(result, TemplateResponse)
result.render()
html = result.render()
_, errors = tidy_document(
html.content,
options={
"drop-empty-elements": False,
"warn-proprietary-attributes": False,
},
)
if errors:
raise Exception(errors)
self.assertEqual(result.status_code, 200)
request.user = self.anonymous_user
@ -63,7 +73,16 @@ class UserViews(TestCase):
is_api.return_value = False
result = view(request, "mouse")
self.assertIsInstance(result, TemplateResponse)
result.render()
html = result.render()
_, errors = tidy_document(
html.content,
options={
"drop-empty-elements": False,
"warn-proprietary-attributes": False,
},
)
if errors:
raise Exception(errors)
self.assertEqual(result.status_code, 200)
with patch("bookwyrm.views.user.is_api_request") as is_api:
@ -92,7 +111,16 @@ class UserViews(TestCase):
is_api.return_value = False
result = view(request, "mouse")
self.assertIsInstance(result, TemplateResponse)
result.render()
html = result.render()
_, errors = tidy_document(
html.content,
options={
"drop-empty-elements": False,
"warn-proprietary-attributes": False,
},
)
if errors:
raise Exception(errors)
self.assertEqual(result.status_code, 200)
with patch("bookwyrm.views.user.is_api_request") as is_api:
@ -123,7 +151,16 @@ class UserViews(TestCase):
is_api.return_value = False
result = view(request, "mouse")
self.assertIsInstance(result, TemplateResponse)
result.render()
html = result.render()
_, errors = tidy_document(
html.content,
options={
"drop-empty-elements": False,
"warn-proprietary-attributes": False,
},
)
if errors:
raise Exception(errors)
self.assertEqual(result.status_code, 200)
with patch("bookwyrm.views.user.is_api_request") as is_api: