Initial commit - Zhangmenu Django project
A menu management application built with Django, featuring: - Dish management with cover images - Order system with party dates and participants - REST API with Django REST Framework - Bootstrap-styled frontend Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,96 @@
|
||||
import json
|
||||
from pathlib import Path
|
||||
|
||||
from django.conf import settings
|
||||
from django.core.files.uploadedfile import SimpleUploadedFile
|
||||
from django.test import TestCase, override_settings
|
||||
from django.urls import reverse
|
||||
|
||||
from menu.models import Dish, DishCategory, Order
|
||||
|
||||
|
||||
TEST_MEDIA_ROOT = Path(settings.BASE_DIR) / 'test_media'
|
||||
|
||||
|
||||
@override_settings(MEDIA_ROOT=TEST_MEDIA_ROOT)
|
||||
class UploadImageTests(TestCase):
|
||||
def tearDown(self):
|
||||
if TEST_MEDIA_ROOT.exists():
|
||||
for path in sorted(TEST_MEDIA_ROOT.rglob('*'), reverse=True):
|
||||
if path.is_file():
|
||||
path.unlink()
|
||||
elif path.is_dir():
|
||||
path.rmdir()
|
||||
|
||||
def test_upload_rejects_invalid_extension(self):
|
||||
image = SimpleUploadedFile('bad.txt', b'file-content', content_type='image/png')
|
||||
|
||||
response = self.client.post(reverse('upload'), {'image': image})
|
||||
|
||||
self.assertEqual(response.status_code, 400)
|
||||
self.assertEqual(response.json()['error'], 'Unsupported image extension')
|
||||
|
||||
def test_upload_rejects_invalid_content_type(self):
|
||||
image = SimpleUploadedFile('dish.png', b'file-content', content_type='text/plain')
|
||||
|
||||
response = self.client.post(reverse('upload'), {'image': image})
|
||||
|
||||
self.assertEqual(response.status_code, 400)
|
||||
self.assertEqual(response.json()['error'], 'Unsupported image content type')
|
||||
|
||||
@override_settings(MAX_UPLOAD_IMAGE_SIZE=4)
|
||||
def test_upload_rejects_oversized_file(self):
|
||||
image = SimpleUploadedFile('dish.png', b'12345', content_type='image/png')
|
||||
|
||||
response = self.client.post(reverse('upload'), {'image': image})
|
||||
|
||||
self.assertEqual(response.status_code, 400)
|
||||
self.assertEqual(response.json()['error'], 'Image file too large')
|
||||
|
||||
def test_upload_returns_absolute_media_url(self):
|
||||
image = SimpleUploadedFile('dish.png', b'png-bytes', content_type='image/png')
|
||||
|
||||
response = self.client.post(reverse('upload'), {'image': image}, secure=True)
|
||||
|
||||
self.assertEqual(response.status_code, 200)
|
||||
data = response.json()
|
||||
self.assertTrue(data['url'].startswith('https://testserver/media/dishes/'))
|
||||
|
||||
|
||||
class ParseUrlTests(TestCase):
|
||||
def test_parse_url_rejects_non_allowlisted_host(self):
|
||||
response = self.client.post(
|
||||
'/api/parse-url/',
|
||||
data=json.dumps({'url': 'http://127.0.0.1/internal'}),
|
||||
content_type='application/json',
|
||||
)
|
||||
|
||||
self.assertEqual(response.status_code, 400)
|
||||
self.assertEqual(response.json()['error'], '该站点不在允许的解析范围内')
|
||||
|
||||
|
||||
class OrderApiTests(TestCase):
|
||||
def setUp(self):
|
||||
category = DishCategory.objects.create(name='热菜')
|
||||
self.dish1 = Dish.objects.create(name='宫保鸡丁', category=category, ingredients=[{'name': '鸡肉', 'amount': '300g'}])
|
||||
self.dish2 = Dish.objects.create(name='鱼香肉丝', category=category, ingredients=[{'name': '猪肉', 'amount': '200g'}])
|
||||
|
||||
def test_create_order_binds_dish_ids_and_returns_saved_object(self):
|
||||
payload = {
|
||||
'name': '周末聚会',
|
||||
'dish_ids': [self.dish1.id, self.dish2.id],
|
||||
'participants': ['张三', '李四'],
|
||||
'party_date': '2026-03-10T12:30:00Z',
|
||||
}
|
||||
|
||||
response = self.client.post('/api/orders/', payload, content_type='application/json')
|
||||
|
||||
self.assertEqual(response.status_code, 201)
|
||||
data = response.json()
|
||||
self.assertEqual(data['name'], '周末聚会')
|
||||
self.assertEqual(sorted(d['id'] for d in data['dishes_detail']), sorted([self.dish1.id, self.dish2.id]))
|
||||
self.assertEqual(data['participants'], ['张三', '李四'])
|
||||
|
||||
order = Order.objects.get(pk=data['id'])
|
||||
self.assertEqual(order.dishes.count(), 2)
|
||||
self.assertEqual(sorted(order.dishes.values_list('id', flat=True)), sorted([self.dish1.id, self.dish2.id]))
|
||||
Reference in New Issue
Block a user