import random import logging import datetime from typing import List from bs4 import BeautifulSoup from django.contrib.auth.models import User from django.utils import timezone from django.utils.crypto import get_random_string from rest_framework import status from rest_framework.test import APITestCase from bookmarks.models import Bookmark, Tag class BookmarkFactoryMixin: user = None def get_or_create_test_user(self): if self.user is None: self.user = User.objects.create_user('testuser', 'test@example.com', 'password123') return self.user def setup_bookmark(self, is_archived: bool = False, unread: bool = False, shared: bool = False, tags=None, user: User = None, url: str = '', title: str = None, description: str = '', notes: str = '', website_title: str = '', website_description: str = '', web_archive_snapshot_url: str = '', favicon_file: str = '', added: datetime = None, ): if title is None: title = get_random_string(length=32) if tags is None: tags = [] if user is None: user = self.get_or_create_test_user() if not url: unique_id = get_random_string(length=32) url = 'https://example.com/' + unique_id if added is None: added = timezone.now() bookmark = Bookmark( url=url, title=title, description=description, notes=notes, website_title=website_title, website_description=website_description, date_added=added, date_modified=timezone.now(), owner=user, is_archived=is_archived, unread=unread, shared=shared, web_archive_snapshot_url=web_archive_snapshot_url, favicon_file=favicon_file, ) bookmark.save() for tag in tags: bookmark.tags.add(tag) bookmark.save() return bookmark def setup_numbered_bookmarks(self, count: int, prefix: str = '', suffix: str = '', tag_prefix: str = '', archived: bool = False, unread: bool = False, shared: bool = False, with_tags: bool = False, user: User = None): user = user or self.get_or_create_test_user() bookmarks = [] if not prefix: if archived: prefix = 'Archived Bookmark' elif shared: prefix = 'Shared Bookmark' else: prefix = 'Bookmark' if not tag_prefix: if archived: tag_prefix = 'Archived Tag' elif shared: tag_prefix = 'Shared Tag' else: tag_prefix = 'Tag' for i in range(1, count + 1): title = f'{prefix} {i}{suffix}' url = f'https://example.com/{prefix}/{i}' tags = [] if with_tags: tag_name = f'{tag_prefix} {i}{suffix}' tags = [self.setup_tag(name=tag_name)] bookmark = self.setup_bookmark(url=url, title=title, is_archived=archived, unread=unread, shared=shared, tags=tags, user=user) bookmarks.append(bookmark) return bookmarks def get_numbered_bookmark(self, title: str): return Bookmark.objects.get(title=title) def setup_tag(self, user: User = None, name: str = ''): if user is None: user = self.get_or_create_test_user() if not name: name = get_random_string(length=32) tag = Tag(name=name, date_added=timezone.now(), owner=user) tag.save() return tag def setup_user(self, name: str = None, enable_sharing: bool = False, enable_public_sharing: bool = False): if not name: name = get_random_string(length=32) user = User.objects.create_user(name, 'user@example.com', 'password123') user.profile.enable_sharing = enable_sharing user.profile.enable_public_sharing = enable_public_sharing user.profile.save() return user def get_random_string(self, length: int = 32): return get_random_string(length=length) class HtmlTestMixin: def make_soup(self, html: str): return BeautifulSoup(html, features="html.parser") class LinkdingApiTestCase(APITestCase): def get(self, url, expected_status_code=status.HTTP_200_OK): response = self.client.get(url) self.assertEqual(response.status_code, expected_status_code) return response def post(self, url, data=None, expected_status_code=status.HTTP_200_OK): response = self.client.post(url, data, format='json') self.assertEqual(response.status_code, expected_status_code) return response def put(self, url, data=None, expected_status_code=status.HTTP_200_OK): response = self.client.put(url, data, format='json') self.assertEqual(response.status_code, expected_status_code) return response def patch(self, url, data=None, expected_status_code=status.HTTP_200_OK): response = self.client.patch(url, data, format='json') self.assertEqual(response.status_code, expected_status_code) return response def delete(self, url, expected_status_code=status.HTTP_200_OK): response = self.client.delete(url) self.assertEqual(response.status_code, expected_status_code) return response class BookmarkHtmlTag: def __init__(self, href: str = '', title: str = '', description: str = '', add_date: str = '', tags: str = '', to_read: bool = False, private: bool = True): self.href = href self.title = title self.description = description self.add_date = add_date self.tags = tags self.to_read = to_read self.private = private class ImportTestMixin: def render_tag(self, tag: BookmarkHtmlTag): return f'''
{tag.title if tag.title else ''} {f'
{tag.description}' if tag.description else ''} ''' def render_html(self, tags: List[BookmarkHtmlTag] = None, tags_html: str = ''): if tags: rendered_tags = [self.render_tag(tag) for tag in tags] tags_html = '\n'.join(rendered_tags) return f''' Bookmarks

Bookmarks

{tags_html}

''' _words = [ 'quasi', 'consequatur', 'necessitatibus', 'debitis', 'quod', 'vero', 'qui', 'commodi', 'quod', 'odio', 'aliquam', 'veniam', 'architecto', 'consequatur', 'autem', 'qui', 'iste', 'asperiores', 'soluta', 'et', ] def random_sentence(num_words: int = None, including_word: str = ''): if num_words is None: num_words = random.randint(5, 10) selected_words = random.choices(_words, k=num_words) if including_word: selected_words.append(including_word) random.shuffle(selected_words) return ' '.join(selected_words) def disable_logging(f): def wrapper(*args): logging.disable(logging.CRITICAL) result = f(*args) logging.disable(logging.NOTSET) return result return wrapper def collapse_whitespace(text: str): text = text.replace('\n', '').replace('\r', '') return ' '.join(text.split())