mirror of https://gitlab.crans.org/bde/nk20
173 lines
6.8 KiB
Python
173 lines
6.8 KiB
Python
|
# Copyright (C) 2018-2024 by BDE ENS Paris-Saclay
|
||
|
# SPDX-License-Identifier: GPL-3.0-or-later
|
||
|
|
||
|
import random
|
||
|
from datetime import date, timedelta
|
||
|
|
||
|
from django.contrib.auth.models import User
|
||
|
from django.test import TestCase
|
||
|
from django.urls import reverse
|
||
|
from note.models import NoteUser
|
||
|
|
||
|
from ..forms.surveys.wei2024 import WEIBusInformation2024, WEISurvey2024, WORDS, WEISurveyInformation2024
|
||
|
from ..models import Bus, WEIClub, WEIRegistration
|
||
|
|
||
|
|
||
|
class TestWEIAlgorithm(TestCase):
|
||
|
"""
|
||
|
Run some tests to ensure that the WEI algorithm is working well.
|
||
|
"""
|
||
|
fixtures = ('initial',)
|
||
|
|
||
|
def setUp(self):
|
||
|
"""
|
||
|
Create some test data, with one WEI and 10 buses with random score attributions.
|
||
|
"""
|
||
|
self.user = User.objects.create_superuser(
|
||
|
username="weiadmin",
|
||
|
password="admin",
|
||
|
email="admin@example.com",
|
||
|
)
|
||
|
self.user.save()
|
||
|
self.client.force_login(self.user)
|
||
|
sess = self.client.session
|
||
|
sess["permission_mask"] = 42
|
||
|
sess.save()
|
||
|
|
||
|
self.wei = WEIClub.objects.create(
|
||
|
name="WEI 2024",
|
||
|
email="wei2024@example.com",
|
||
|
parent_club_id=2,
|
||
|
membership_fee_paid=12500,
|
||
|
membership_fee_unpaid=5500,
|
||
|
membership_start='2024-01-01',
|
||
|
membership_end='2024-12-31',
|
||
|
date_start=date.today() + timedelta(days=2),
|
||
|
date_end='2024-12-31',
|
||
|
year=2024,
|
||
|
)
|
||
|
|
||
|
self.buses = []
|
||
|
for i in range(10):
|
||
|
bus = Bus.objects.create(wei=self.wei, name=f"Bus {i}", size=10)
|
||
|
self.buses.append(bus)
|
||
|
information = WEIBusInformation2024(bus)
|
||
|
for question in WORDS:
|
||
|
information.scores[question] = {answer: random.randint(1, 5) for answer in WORDS[question][1]}
|
||
|
information.save()
|
||
|
bus.save()
|
||
|
|
||
|
def test_survey_algorithm_small(self):
|
||
|
"""
|
||
|
There are only a few people in each bus, ensure that each person has its best bus
|
||
|
"""
|
||
|
# Add a few users
|
||
|
for i in range(10):
|
||
|
user = User.objects.create(username=f"user{i}")
|
||
|
registration = WEIRegistration.objects.create(
|
||
|
user=user,
|
||
|
wei=self.wei,
|
||
|
first_year=True,
|
||
|
birth_date='2000-01-01',
|
||
|
)
|
||
|
information = WEISurveyInformation2024(registration)
|
||
|
for question in WORDS:
|
||
|
options = list(WORDS[question][1].keys())
|
||
|
setattr(information, question, random.choice(options))
|
||
|
information.step = 20
|
||
|
information.save(registration)
|
||
|
registration.save()
|
||
|
|
||
|
# Run algorithm
|
||
|
WEISurvey2024.get_algorithm_class()().run_algorithm()
|
||
|
|
||
|
# Ensure that everyone has its first choice
|
||
|
for r in WEIRegistration.objects.filter(wei=self.wei).all():
|
||
|
survey = WEISurvey2024(r)
|
||
|
preferred_bus = survey.ordered_buses()[0][0]
|
||
|
chosen_bus = survey.information.get_selected_bus()
|
||
|
self.assertEqual(preferred_bus, chosen_bus)
|
||
|
|
||
|
def test_survey_algorithm_full(self):
|
||
|
"""
|
||
|
Buses are full of first year people, ensure that they are happy
|
||
|
"""
|
||
|
# Add a lot of users
|
||
|
for i in range(95):
|
||
|
user = User.objects.create(username=f"user{i}")
|
||
|
registration = WEIRegistration.objects.create(
|
||
|
user=user,
|
||
|
wei=self.wei,
|
||
|
first_year=True,
|
||
|
birth_date='2000-01-01',
|
||
|
)
|
||
|
information = WEISurveyInformation2024(registration)
|
||
|
for question in WORDS:
|
||
|
options = list(WORDS[question][1].keys())
|
||
|
setattr(information, question, random.choice(options))
|
||
|
information.step = 20
|
||
|
information.save(registration)
|
||
|
registration.save()
|
||
|
|
||
|
# Run algorithm
|
||
|
WEISurvey2024.get_algorithm_class()().run_algorithm()
|
||
|
|
||
|
penalty = 0
|
||
|
# Ensure that everyone seems to be happy
|
||
|
# We attribute a penalty for each user that didn't have its first choice
|
||
|
# The penalty is the square of the distance between the score of the preferred bus
|
||
|
# and the score of the attributed bus
|
||
|
# We consider it acceptable if the mean of this distance is lower than 5 %
|
||
|
for r in WEIRegistration.objects.filter(wei=self.wei).all():
|
||
|
survey = WEISurvey2024(r)
|
||
|
chosen_bus = survey.information.get_selected_bus()
|
||
|
buses = survey.ordered_buses()
|
||
|
score = min(v for bus, v in buses if bus == chosen_bus)
|
||
|
max_score = buses[0][1]
|
||
|
penalty += (max_score - score) ** 2
|
||
|
|
||
|
self.assertLessEqual(max_score - score, 25) # Always less than 25 % of tolerance
|
||
|
|
||
|
self.assertLessEqual(penalty / 100, 25) # Tolerance of 5 %
|
||
|
|
||
|
def test_register_1a(self):
|
||
|
"""
|
||
|
Test register a first year member to the WEI and complete the survey
|
||
|
"""
|
||
|
response = self.client.get(reverse("wei:wei_register_1A", kwargs=dict(wei_pk=self.wei.pk)))
|
||
|
self.assertEqual(response.status_code, 200)
|
||
|
|
||
|
user = User.objects.create(username="toto", email="toto@example.com")
|
||
|
NoteUser.objects.create(user=user)
|
||
|
response = self.client.post(reverse("wei:wei_register_1A", kwargs=dict(wei_pk=self.wei.pk)), dict(
|
||
|
user=user.id,
|
||
|
soge_credit=True,
|
||
|
birth_date=date(2000, 1, 1),
|
||
|
gender='nonbinary',
|
||
|
clothing_cut='female',
|
||
|
clothing_size='XS',
|
||
|
health_issues='I am a bot',
|
||
|
emergency_contact_name='NoteKfet2020',
|
||
|
emergency_contact_phone='+33123456789',
|
||
|
))
|
||
|
qs = WEIRegistration.objects.filter(user_id=user.id)
|
||
|
self.assertTrue(qs.exists())
|
||
|
registration = qs.get()
|
||
|
self.assertRedirects(response, reverse("wei:wei_survey", kwargs=dict(pk=registration.pk)), 302, 200)
|
||
|
for question in WORDS:
|
||
|
# Fill 1A Survey, 20 pages
|
||
|
# be careful if questionnary form change (number of page, type of answer...)
|
||
|
response = self.client.post(reverse("wei:wei_survey", kwargs=dict(pk=registration.pk)), {
|
||
|
question: "1"
|
||
|
})
|
||
|
registration.refresh_from_db()
|
||
|
survey = WEISurvey2024(registration)
|
||
|
self.assertRedirects(response, reverse("wei:wei_survey", kwargs=dict(pk=registration.pk)), 302,
|
||
|
302 if survey.is_complete() else 200)
|
||
|
self.assertIsNotNone(getattr(survey.information, question), "Survey page " + question + " failed")
|
||
|
survey = WEISurvey2024(registration)
|
||
|
self.assertTrue(survey.is_complete())
|
||
|
survey.select_bus(self.buses[0])
|
||
|
survey.save()
|
||
|
self.assertIsNotNone(survey.information.get_selected_bus())
|