Skip to content

Commit

Permalink
Get all written tests to pass
Browse files Browse the repository at this point in the history
  • Loading branch information
AaDalal committed Feb 5, 2024
1 parent 672ee03 commit e1c74e2
Show file tree
Hide file tree
Showing 3 changed files with 50 additions and 80 deletions.
31 changes: 19 additions & 12 deletions backend/degree/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@

from courses.models import Course
from degree.utils.model_utils import q_object_parser
from django.db.models.signals import m2m_changed


program_choices = [
Expand Down Expand Up @@ -334,7 +335,7 @@ class Fulfillment(models.Model):

rules = models.ManyToManyField(
Rule,
related_name="fulfillments",
related_name="+",
blank=True,
help_text=dedent(
"""
Expand Down Expand Up @@ -365,17 +366,26 @@ def save(self, *args, **kwargs):

self.historical_course = course

fulfillment = super().save(*args, **kwargs)

# Update rule statuses
for rule in self.rules.all():
super().save(*args, **kwargs)

def update_satisfaction_statuses(sender, instance, action, pk_set, **kwargs):
"""
This function updates the SatisfactionStatuses associated with a DegreePlan when the rules
associated with a Fulfillment change.
"""
if action == "pre_clear" or action == "pre_remove":
instance.degree_plan.satisfactions.filter(rule__in=pk_set).delete()
return

if action == "post_add" or action == "post_remove" or action == "post_clear":
degree_plan = instance.degree_plan
for rule in degree_plan.degree.rules.all():
status, _ = SatisfactionStatus.objects.get_or_create(
degree_plan=self.degree_plan, rule=rule
degree_plan=degree_plan, rule=rule
)
status.satisfied = rule.evaluate([self.full_code])
status.satisfied = rule.evaluate([fulfillment.full_code for fulfillment in degree_plan.fulfillments.all()])
status.save()

return fulfillment
m2m_changed.connect(update_satisfaction_statuses, sender=Fulfillment.rules.through)


class SatisfactionStatus(models.Model):
Expand All @@ -386,17 +396,14 @@ class SatisfactionStatus(models.Model):
related_name="satisfactions",
help_text="The degree plan that leads to the satisfaction of the rule",
)

rule = models.ForeignKey(
Rule,
on_delete=models.CASCADE,
db_index=True,
related_name="+",
help_text="The rule that is satisfied",
)

satisfied = models.BooleanField(default=False, help_text="Whether the rule is satisfied")

last_updated = models.DateTimeField(auto_now=True)
last_checked = models.DateTimeField(default=timezone.now)

Expand Down
18 changes: 1 addition & 17 deletions backend/degree/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,21 +39,6 @@ class Meta:
fields = "__all__"
read_only_fields = "__all__"


class PathParamPrimaryKeyDefault:
requires_context = True

def __call__(self, serializer_field):
print("CALLED")
return DegreePlan.objects.get(
person=serializer_field.context['request'].user,
pk=serializer_field.context['view'].get_degree_plan_id()
)

def __repr__(self):
return '%s()' % self.__class__.__name__


class FulfillmentSerializer(serializers.ModelSerializer):
course = CourseListSerializer(
read_only=True,
Expand All @@ -75,14 +60,13 @@ def to_internal_value(self, data):

class Meta:
model = Fulfillment
fields = ["degree_plan", "full_code", "course", "semester", "rules"]
fields = ["id", "degree_plan", "full_code", "course", "semester", "rules"]

def validate(self, data):
data = super().validate(data)
rules = data.get("rules") # for patch requests without a rules field
full_code = data.get("full_code")
degree_plan = data.get("degree_plan")
print(data)

if rules is None and full_code is None:
return data # Nothing to validate
Expand Down
81 changes: 30 additions & 51 deletions backend/tests/degree/test_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,15 @@ def test_delete_user_degree_plan_with_fulfillments(self):
pass

class FulfillmentViewsetTest(TestCase):
def assertSerializedFulfillmentEquals(self, fulfillment: dict, expected: Fulfillment):
self.assertEqual(len(fulfillment), 6)
self.assertEqual(fulfillment["id"], expected.id)
self.assertEqual(fulfillment["course"], CourseListSerializer(expected.historical_course).data)
self.assertEqual(fulfillment["rules"], [rule.id for rule in expected.rules.all()])
self.assertEqual(fulfillment["semester"], expected.semester)
self.assertEqual(fulfillment["degree_plan"], expected.degree_plan.id)
self.assertEqual(fulfillment["full_code"], expected.full_code)

def setUp(self):
self.user = User.objects.create_user(
username="test", password="top_secret", email="[email protected]"
Expand Down Expand Up @@ -109,6 +118,8 @@ def test_create_fulfillment(self):
{"full_code": "CIS-1200", "semester": TEST_SEMESTER, "rules": [self.rule1.id]}
)
self.assertEqual(response.status_code, 201, response.json())
self.assertSerializedFulfillmentEquals(response.data, Fulfillment.objects.get(full_code="CIS-1200"))

fulfillment = Fulfillment.objects.get(full_code="CIS-1200")
self.assertEqual(fulfillment.degree_plan, self.degree_plan)
self.assertEqual(fulfillment.historical_course, self.cis_1200)
Expand Down Expand Up @@ -137,24 +148,10 @@ def test_list_fulfillment(self):

response = self.client.get(reverse("degreeplan-fulfillment-list", kwargs={"degreeplan_pk": self.degree_plan.id}))
self.assertEqual(response.status_code, 200, response.json())
fulfillments = sorted((dict(d) for d in response.data), key=lambda d: d["full_code"])
fulfillments == [
{
"degree_plan": self.degree_plan.id,
"full_code": "CIS-1200",
"course": CourseListSerializer(self.cis_1200).data,
"semester": TEST_SEMESTER,
"rules": [self.rule2.id]
},
{

"degree_plan": self.degree_plan.id,
"full_code": "CIS-1910",
"course": dict(CourseListSerializer(self.cis_1910).data),
"semester": None,
"rules": [self.rule1.id]
}
]
response_a, response_b = sorted((dict(d) for d in response.data), key=lambda d: d["full_code"])

self.assertSerializedFulfillmentEquals(response_a, a)
self.assertSerializedFulfillmentEquals(response_b, b)

def test_retrieve_fulfillment(self):
a = Fulfillment(
Expand All @@ -167,15 +164,7 @@ def test_retrieve_fulfillment(self):

response = self.client.get(reverse("degreeplan-fulfillment-detail", kwargs={"degreeplan_pk": self.degree_plan.id, "pk": a.id}))
self.assertEqual(response.status_code, 200, response.json())
fulfillment = response.data
print(fulfillment)
assert fulfillment == {
"full_code": "CIS-1200",
"degree_plan": self.degree_plan.id,
"course": CourseListSerializer(self.cis_1200).data,
"semester": TEST_SEMESTER,
"rules": [self.rule1]
}
self.assertSerializedFulfillmentEquals(response.data, a)


def test_update_fulfillment_replace_rule(self):
Expand All @@ -192,11 +181,10 @@ def test_update_fulfillment_replace_rule(self):
{"rules": [self.rule3.id]}
)
self.assertEqual(response.status_code, 200, response.json())
fulfillment = response.data
self.assertEquals(fulfillment["course"], CourseListSerializer(self.cis_1200).data)
self.assertEquals(fulfillment["rules"], [self.rule3.id])
self.assertEquals(fulfillment["semester"], TEST_SEMESTER)
self.assertEquals(fulfillment["degree_plan"], self.degree_plan.id)
self.assertSerializedFulfillmentEquals(response.data, a)
a.refresh_from_db()
self.assertEqual(a.rules.count(), 1)
self.assertEqual(a.rules.first(), self.rule3)

def test_update_semester(self):
a = Fulfillment(
Expand All @@ -212,13 +200,9 @@ def test_update_semester(self):
{"semester": "2022B"}
)
self.assertEqual(response.status_code, 200, response.json())
fulfillment = response.data
self.assertEquals(fulfillment["course"], CourseListSerializer(self.cis_1200).data)
self.assertEquals(fulfillment["rules"], [self.rule1.id])
self.assertEquals(fulfillment["semester"], "2022B")
self.assertEquals(fulfillment["degree_plan"], self.degree_plan.id)
a.refresh_from_db()
self.assertEquals(a.semester, "2022B")
self.assertSerializedFulfillmentEquals(response.data, a)
self.assertEqual(a.semester, "2022B")

def test_update_fulfillment_full_code(self):
a = Fulfillment(
Expand All @@ -234,13 +218,9 @@ def test_update_fulfillment_full_code(self):
{"full_code": "CIS-1910"}
)
self.assertEqual(response.status_code, 200, response.json())
fulfillment = response.data
self.assertEquals(fulfillment["course"], CourseListSerializer(self.cis_1910).data)
self.assertEquals(fulfillment["rules"], [self.rule3.id])
self.assertEquals(fulfillment["semester"], TEST_SEMESTER)
self.assertEquals(fulfillment["degree_plan"], self.degree_plan.id)
a.refresh_from_db()
self.assertEquals(a.full_code, "CIS-1910")
self.assertSerializedFulfillmentEquals(response.data, a)
self.assertEqual(a.full_code, "CIS-1910")

def test_update_fulfillment_rule(self):
a = Fulfillment(
Expand All @@ -256,11 +236,10 @@ def test_update_fulfillment_rule(self):
{"rules": [self.rule3.id, self.rule1.id]}
)
self.assertEqual(response.status_code, 200, response.json())
fulfillment = response.data
self.assertEquals(fulfillment["course"], CourseListSerializer(self.cis_1200).data)
self.assertEquals(fulfillment["rules"], [self.rule3.id])
self.assertEquals(fulfillment["semester"], TEST_SEMESTER)
self.assertEquals(fulfillment["degree_plan"], self.degree_plan.id)
a.refresh_from_db()
self.assertSerializedFulfillmentEquals(response.data, a)
self.assertEqual(a.rules.count(), 2)
self.assertEqual(set(a.rules.all()), {self.rule1, self.rule3})

def test_update_fulfillment_add_violated_rule(self):
a = Fulfillment(
Expand All @@ -276,7 +255,7 @@ def test_update_fulfillment_add_violated_rule(self):
{"rules": [self.rule2.id, self.rule1.id]}
)
self.assertEqual(response.status_code, 400, response.json())
self.assertEquals(
self.assertEqual(
response.data["non_field_errors"][0],
f"Course CIS-1200 does not satisfy rule {self.rule2.id}"
)
Expand All @@ -295,7 +274,7 @@ def test_update_fulfillment_full_code_violates_rule(self):
{"full_code": "CIS-1910"}
)
self.assertEqual(response.status_code, 400, response.json())
self.assertEquals(
self.assertEqual(
response.data["non_field_errors"][0],
f"Course CIS-1910 does not satisfy rule {self.rule1.id}"
)
Expand Down

0 comments on commit e1c74e2

Please sign in to comment.