# Copyright (C) 2018-2025 by BDE ENS Paris-Saclay # SPDX-License-Identifier: GPL-3.0-or-later import os from api.tests import TestAPI from django.contrib.auth.models import User from django.core.files.uploadedfile import SimpleUploadedFile from django.test import TestCase from rest_framework.test import APITestCase from django.urls import reverse from django.utils import timezone from ..api.views import FamilyViewSet, FamilyMembershipViewSet, ChallengeViewSet, AchievementViewSet from ..models import Family, FamilyMembership, Challenge, Achievement class TestFamily(TestCase): """ Test family """ def setUp(self): self.user = User.objects.create_superuser( username='admintoto', password='toto1234', email='toto@example.com', ) self.client.force_login(self.user) sess = self.client.session sess['permission_mask'] = 42 sess.save() self.family = Family.objects.create( name='Test family', description='', ) self.challenge = Challenge.objects.create( name='Test challenge', description='', points=100, ) self.achievement = Achievement.objects.create( family=self.family, challenge=self.challenge, valid=False, ) def test_family_list(self): """ Test display family list """ response = self.client.get(reverse("family:family_list")) self.assertEqual(response.status_code, 200) def test_family_create(self): """ Test create a family """ response = self.client.get(reverse("family:family_create")) self.assertEqual(response.status_code, 200) response = self.client.post(reverse("family:family_create"), data={ "name": "Family toto", "description": "A test family", }) self.assertTrue(Family.objects.filter(name="Family toto").exists()) self.assertRedirects(response, reverse("family:manage"), 302, 200) def test_family_detail(self): """ Test display the detail of a family """ response = self.client.get(reverse("family:family_detail", args=(self.family.pk,))) self.assertEqual(response.status_code, 200) def test_family_update(self): """ Test update a family """ response = self.client.get(reverse("family:family_update", args=(self.family.pk,))) self.assertEqual(response.status_code, 200) response = self.client.post(reverse("family:family_update", args=(self.family.pk,)), data=dict( name="Toto family updated", description="A larger description for the test family" )) self.assertRedirects(response, self.family.get_absolute_url(), 302, 200) self.assertTrue(Family.objects.filter(name="Toto family updated").exists()) def test_family_update_picture(self): """ Test update the picture of a family """ response = self.client.get(reverse("family:update_pic", args=(self.family.pk,))) self.assertEqual(response.status_code, 200) old_pic = self.family.display_image with open("apps/family/static/family/img/default_picture.png", "rb") as f: image = SimpleUploadedFile("image.png", f.read(), "image/png") response = self.client.post(reverse("family:update_pic", args=(self.family.pk,)), dict( image=image, x=0, y=0, width=200, height=200, )) self.assertRedirects(response, self.family.get_absolute_url(), 302, 200) self.family.refresh_from_db() self.assertTrue(os.path.exists(self.family.display_image.path)) os.remove(self.family.display_image.path) self.family.display_image = old_pic self.family.save() def test_family_add_member(self): """ Test add memberships to a family """ response = self.client.get(reverse("family:family_add_member", args=(self.family.pk,))) self.assertEqual(response.status_code, 200) user = User.objects.create(username="totototo") user.profile.registration_valid = True user.profile.email_confirmed = True user.profile.save() user.save() response = self.client.post(reverse("family:family_add_member", args=(self.family.pk,)), data=dict( user=user.pk, )) self.assertRedirects(response, self.family.get_absolute_url(), 302, 200) self.assertTrue(FamilyMembership.objects.filter(user=user, family=self.family, year=timezone.now().year).exists()) def test_challenge_list(self): """ Test display challenge list """ response = self.client.get(reverse('family:challenge_list')) self.assertEqual(response.status_code, 200) def test_challenge_create(self): """ Test create a challenge """ response = self.client.get(reverse("family:challenge_create")) self.assertEqual(response.status_code, 200) response = self.client.post(reverse("family:challenge_create"), data={ "name": "Challenge for toto", "description": "A test challenge", "points": 50, }) self.assertTrue(Challenge.objects.filter(name="Challenge for toto").exists()) self.assertRedirects(response, reverse("family:manage"), 302, 200) def test_challenge_detail(self): """ Test display the detail of a challenge """ response = self.client.get(reverse("family:challenge_detail", args=(self.challenge.pk,))) self.assertEqual(response.status_code, 200) def test_challenge_update(self): """ Test update a challenge """ response = self.client.get(reverse("family:challenge_update", args=(self.challenge.pk,))) self.assertEqual(response.status_code, 200) response = self.client.post(reverse("family:challenge_update", args=(self.challenge.pk,)), data=dict( name="Challenge updated", description="Another description", points=10, )) self.assertRedirects(response, self.challenge.get_absolute_url(), 302, 200) self.assertTrue(Challenge.objects.filter(name="Challenge updated").exists()) def test_render_manage_page(self): """ Test render manage page """ response = self.client.get(reverse("family:manage")) self.assertEqual(response.status_code, 200) def test_validate_achievement(self): """ Test validate an achievement """ old_family_score = self.family.score response = self.client.get(reverse("family:achievement_validate", args=(self.achievement.pk,))) self.assertEqual(response.status_code, 200) response = self.client.post(reverse("family:achievement_validate", args=(self.achievement.pk,))) self.assertRedirects(response, reverse("family:achievement_list"), 302, 200) self.achievement.refresh_from_db() self.assertIs(self.achievement.valid, True) self.family.refresh_from_db() self.assertEqual(self.family.score, old_family_score + self.achievement.challenge.points) def test_delete_achievement(self): """ Test delete an achievement """ response = self.client.get(reverse("family:achievement_delete", args=(self.achievement.pk,))) self.assertEqual(response.status_code, 200) response = self.client.delete(reverse("family:achievement_delete", args=(self.achievement.pk,))) self.assertRedirects(response, reverse("family:achievement_list"), 302, 200) self.assertFalse(Achievement.objects.filter(pk=self.achievement.pk).exists()) class TestBatchAchievements(APITestCase): def setUp(self): self.user = User.objects.create_superuser( username='admintoto', password='toto1234', email='toto@example.com', ) self.client.force_login(self.user) sess = self.client.session sess['permission_mask'] = 42 sess.save() self.families = [ Family.objects.create(name=f'Famille {i}', description='') for i in range(2) ] self.challenges = [ Challenge.objects.create(name=f'Challenge {i}', description='', points=50) for i in range(3) ] self.url = reverse("family:api:batch_achievements") def test_batch_achievement_creation(self): family_ids = [f.id for f in self.families] challenge_ids = [c.id for c in self.challenges] response = self.client.post( self.url, data={ 'families': family_ids, 'challenges': challenge_ids }, format='json' ) self.assertEqual(response.status_code, 201) self.assertEqual(response.data['status'], 'ok') expected_count = len(family_ids) * len(challenge_ids) self.assertEqual(Achievement.objects.count(), expected_count) # Check that correct couples family/challenge exist for f in self.families: for c in self.challenges: self.assertTrue( Achievement.objects.filter(family=f, challenge=c).exists() ) class TestFamilyAPI(TestAPI): def setUp(self): super().setUp() self.family = Family.objects.create( name='Test family', description='', ) self.familymembership = FamilyMembership.objects.create( user=self.user, family=self.family, ) self.challenge = Challenge.objects.create( name='Test challenge', description='', points=100, ) self.achievement = Achievement.objects.create( family=self.family, challenge=self.challenge, valid=False, ) def test_family_api(self): """ Load Family API page and test all filters and permissions """ self.check_viewset(FamilyViewSet, '/api/family/family/') def test_familymembership_api(self): """ Load FamilyMembership API page and test all filters and permissions """ self.check_viewset(FamilyMembershipViewSet, '/api/family/familymembership/') def test_challenge_api(self): """ Load Challenge API page and test all filters and permissions """ self.check_viewset(ChallengeViewSet, '/api/family/challenge/') def test_achievement_api(self): """ Load Achievement API page and test all filters and permissions """ self.check_viewset(AchievementViewSet, '/api/family/achievement/')