backup for Phase 2.5

This commit is contained in:
2026-08-04 00:34:02 -05:00
parent b1ae1d0023
commit 529f3e5c3d
9 changed files with 745 additions and 11 deletions
+178
View File
@@ -1142,3 +1142,181 @@ class UGCCategoryTests(UGCMediaTestCase, UGCGatedTestCase):
version = self.project.versions.first()
self.assertIsNone(version.pack_format)
self.assertEqual(version.mods_manifest, {})
def _animation_pack_zip(with_id=True, entity_x_player=False, problem=True):
actor_a = {
'label': 'actor1', 'entity_types': ['minecraft:player'],
'actor_tags': ['gender.male'], 'activity': 'active', 'injector': 'V',
}
actor_b = {
'label': 'actor2',
'entity_types': ['minecraft:zombie'] if entity_x_player else ['minecraft:player'],
'actor_tags': [] if entity_x_player else ['gender.female'],
'activity': 'passive', 'receiver': True,
}
content_tags = ['missionary'] + (['bugged'] if problem else [])
af = {
'id': 'jakebreath:testpack', 'name': 'Test Pack', 'author': 'Alice, Bob',
'version': '1.0.0', 'description': 'A test pack.',
} if with_id else {'name': 'Test Pack', 'author': 'Alice'}
return _zip_bytes({
'pack.mcmeta': json.dumps({'pack': {'pack_format': 64}, 'animationframework': af}),
'data/jakebreath/afw_animdefs/ground.json': json.dumps({
'display_name': 'Ground', 'content_tags': content_tags,
'actors': [actor_a, actor_b],
'stages': [{'stage': 1, 'loop': True, 'cycle_seconds': 1.0},
{'stage': 2, 'loop': False, 'non_peak': True}],
}),
})
def _bom_pack_zip():
mcmeta = b'\xef\xbb\xbf' + json.dumps({
'pack': {'pack_format': 64},
'animationframework': {'id': 'needsofnature:default', 'name': 'Default', 'author': 'NoN Team'},
}).encode()
return _zip_bytes({
'pack.mcmeta': mcmeta,
'data/needsofnature/afw_animdefs/solo.json': json.dumps({
'actors': [{'label': 'actor1', 'entity_types': ['minecraft:player'], 'activity': 'passive'}],
'content_tags': ['solo'],
'stages': [{'stage': 1, 'loop': True}],
}),
})
class UGCAnimationTests(UGCMediaTestCase, UGCGatedTestCase):
def setUp(self):
User = get_user_model()
self.alice = User.objects.create_user(username='Alice', password='pw')
UserProfile.objects.get_or_create(user=self.alice)
def _write_zip(self, data):
with tempfile.NamedTemporaryFile(suffix='.zip', delete=False) as f:
f.write(data)
return f.name
def _upload_version(self, slug, name, content):
self.gate()
self.client.login(username='Alice', password='pw')
resp = self.client.post(
reverse('library:api_upload_temp'),
{'kind': 'version', 'file': SimpleUploadedFile(name, content, content_type='application/zip')},
HTTP_X_REQUESTED_WITH='XMLHttpRequest',
)
self.assertEqual(resp.status_code, 200)
return self.client.post(
reverse('library:version_upload', args=[slug]), {'version_name': '1.0.0'},
)
def test_read_animation_manifest_player_x_player(self):
from library.zips import read_animation_manifest
path = self._write_zip(_animation_pack_zip())
try:
manifest = read_animation_manifest(path)
finally:
os.unlink(path)
self.assertEqual(manifest['animation_id'], 'jakebreath:testpack')
self.assertEqual(manifest['authors'], ['Alice', 'Bob'])
anim = manifest['animations'][0]
self.assertEqual(anim['name'], 'Ground')
self.assertEqual(anim['type'], 'Pair')
self.assertEqual(anim['content_tags'], ['missionary', 'bugged'])
self.assertEqual(anim['problem_tags'], ['bugged'])
self.assertEqual(anim['actors'][0]['injector'], 'V')
self.assertEqual(anim['actors'][0]['injector_name'], 'Vaginal')
self.assertEqual(anim['actors'][1]['gender'], 'female')
self.assertEqual(anim['stages'][1]['climax'], True)
def test_read_animation_manifest_entity_x_player(self):
from library.zips import read_animation_manifest
path = self._write_zip(_animation_pack_zip(entity_x_player=True))
try:
manifest = read_animation_manifest(path)
finally:
os.unlink(path)
anim = manifest['animations'][0]
self.assertEqual(anim['type'], 'Entity x Player')
self.assertEqual(anim['actors'][1]['entity'], 'Zombie')
self.assertEqual(anim['entity_names'], ['Zombie'])
def test_read_animation_manifest_bom_mcmeta(self):
from library.zips import read_animation_manifest, read_pack_mcmeta
path = self._write_zip(_bom_pack_zip())
try:
fmt, desc = read_pack_mcmeta(path)
manifest = read_animation_manifest(path)
finally:
os.unlink(path)
self.assertEqual(fmt, 64)
self.assertEqual(manifest['animation_id'], 'needsofnature:default')
self.assertEqual(manifest['animations'][0]['type'], 'Solo')
def test_read_animation_manifest_not_animation(self):
from library.zips import read_animation_manifest
path = self._write_zip(_zip_bytes({'data/x.txt': 'x'}))
try:
manifest = read_animation_manifest(path)
finally:
os.unlink(path)
self.assertIsNone(manifest)
def test_version_upload_captures_manifest_and_tags(self):
self.project = Project.objects.create(
slug='anim-pack', title='Anim Pack', category='non_pack', owner=self.alice,
)
resp = self._upload_version('anim-pack', 'pack.zip', _animation_pack_zip())
self.assertRedirects(resp, reverse('library:project_detail', args=['anim-pack']))
version = self.project.versions.first()
self.assertEqual(version.animation_id, 'jakebreath:testpack')
self.assertEqual(version.animation_manifest['animations'][0]['name'], 'Ground')
# Auto-created content tags (including the problem tag).
names = set(TagList.objects.filter(project=self.project).values_list('tag__name', flat=True))
self.assertIn('missionary', names)
self.assertIn('bugged', names)
def test_version_upload_warns_without_animation_id(self):
self.project = Project.objects.create(
slug='anim-pack', title='Anim Pack', category='non_pack', owner=self.alice,
)
resp = self._upload_version('anim-pack', 'pack.zip', _animation_pack_zip(with_id=False))
self.assertRedirects(resp, reverse('library:project_detail', args=['anim-pack']),
fetch_redirect_response=False)
version = self.project.versions.first()
self.assertEqual(version.animation_id, '')
self.assertTrue(version.animation_manifest)
# The warning banner renders on the redirect target (before it's consumed).
resp = self.client.get(reverse('library:project_detail', args=['anim-pack']))
self.assertContains(resp, 'incompatible with the update-check API')
def test_latest_api_returns_version_and_url(self):
self.project = Project.objects.create(
slug='anim-pack', title='Anim Pack', category='non_pack', owner=self.alice,
)
self._upload_version('anim-pack', 'pack.zip', _animation_pack_zip())
self.gate()
self.client.login(username='Alice', password='pw')
resp = self.client.get(reverse('library:api_packs_latest', args=['jakebreath', 'testpack']))
self.assertEqual(resp.status_code, 200)
data = resp.json()
self.assertEqual(data['version'], '1.0.0')
self.assertEqual(data['pack_format'], 64)
self.assertIn('/api/files/', data['download_url'])
self.assertIn('?download=1', data['download_url'])
def test_latest_api_404_unknown_pack(self):
self.gate()
self.client.login(username='Alice', password='pw')
resp = self.client.get(reverse('library:api_packs_latest', args=['nope', 'missing']))
self.assertEqual(resp.status_code, 404)
def test_latest_api_404_without_animation_id(self):
self.project = Project.objects.create(
slug='anim-pack', title='Anim Pack', category='non_pack', owner=self.alice,
)
self._upload_version('anim-pack', 'pack.zip', _animation_pack_zip(with_id=False))
self.gate()
self.client.login(username='Alice', password='pw')
resp = self.client.get(reverse('library:api_packs_latest', args=['jakebreath', 'testpack']))
self.assertEqual(resp.status_code, 404)