import shutil import tempfile from datetime import datetime, time, timedelta from unittest.mock import patch from django.contrib.auth import get_user_model from django.core.files.uploadedfile import SimpleUploadedFile from django.test import TestCase, override_settings from django.urls import reverse from django.utils import timezone from .models import ApiKey, Attachment, Collection, CollectionSection, Item, Tag, Team, TeamMembership, UserPreference from .templatetags.markdown_extras import markdown, markdown_title from .views import parse_due_command, parse_quick_content class ItemMetadataTests(TestCase): def setUp(self): self.user = get_user_model().objects.create_user(username='tester', password='secret') def test_code_sections_are_ignored_when_extracting_tags(self): item = Item.objects.create( owner=self.user, content='Outside #real\n```python\n# fenced\n```\nInline `#inline` text', ) item.sync_metadata() self.assertEqual(list(item.tags.values_list('name', flat=True)), ['real']) self.assertFalse(Tag.objects.filter(name__in=['fenced', 'inline']).exists()) def test_unused_tags_are_removed_after_sync_and_delete(self): item = Item.objects.create(owner=self.user, content='#old') item.sync_metadata() item.content = '#new' item.save() item.sync_metadata() self.assertFalse(Tag.objects.filter(name='old').exists()) self.assertTrue(Tag.objects.filter(name='new').exists()) item.delete() self.assertFalse(Tag.objects.filter(name='new').exists()) class DefaultItemKindTests(TestCase): def setUp(self): self.user = get_user_model().objects.create_user(username='tester', password='secret') self.client.force_login(self.user) self.preferences = UserPreference.objects.create(user=self.user, default_item_kind=Item.Kind.TODO) def test_quick_create_uses_user_default(self): response = self.client.post(reverse('index'), {'content': 'Default task'}) self.assertRedirects(response, reverse('index')) self.assertEqual(Item.objects.get().kind, Item.Kind.TODO) def test_quick_create_can_override_and_persist_default_from_composer(self): response = self.client.post(reverse('index'), {'content': 'Composer note', 'default_item_kind': Item.Kind.NOTE}) self.assertRedirects(response, reverse('index')) self.assertEqual(Item.objects.get().kind, Item.Kind.NOTE) self.preferences.refresh_from_db() self.assertEqual(self.preferences.default_item_kind, Item.Kind.NOTE) def test_default_item_kind_select_persists_immediately(self): response = self.client.post(reverse('set_default_item_kind'), {'default_item_kind': Item.Kind.LINK}) self.assertEqual(response.status_code, 204) self.preferences.refresh_from_db() self.assertEqual(self.preferences.default_item_kind, Item.Kind.LINK) response = self.client.get(reverse('index')) self.assertContains(response, '