Skip to content

Commit

Permalink
Improve test
Browse files Browse the repository at this point in the history
  • Loading branch information
faucomte97 committed Feb 14, 2024
1 parent 9aed69f commit 7f08ee3
Showing 1 changed file with 168 additions and 50 deletions.
218 changes: 168 additions & 50 deletions game/tests/test_scoreboard.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,10 @@
from common.models import Class, Teacher, Student
from common.tests.utils.classes import create_class_directly
from common.tests.utils.organisation import create_organisation_directly
from common.tests.utils.student import create_school_student_directly, create_independent_student_directly
from common.tests.utils.student import (
create_school_student_directly,
create_independent_student_directly,
)
from common.tests.utils.teacher import signup_teacher_directly
from django.test import Client, TestCase
from django.urls import reverse
Expand All @@ -22,7 +25,11 @@
shared_levels_data,
SharedHeaders,
)
from game.views.scoreboard_csv import scoreboard_csv, Headers as CSVHeaders, SharedHeaders as CSVSharedHeaders
from game.views.scoreboard_csv import (
scoreboard_csv,
Headers as CSVHeaders,
SharedHeaders as CSVSharedHeaders,
)


class ScoreboardTestCase(TestCase):
Expand All @@ -31,7 +38,10 @@ def test_teacher_multiple_students_multiple_levels(self):
episode_ids = [1, 2]
episode1 = Episode.objects.get(id=1)
episode2 = Episode.objects.get(id=2)
level_ids = [f"{x}" for x in range(1, len(episode1.levels) + len(episode2.levels) + 1)]
level_ids = [
f"{x}"
for x in range(1, len(episode1.levels) + len(episode2.levels) + 1)
]
level1 = Level.objects.get(name="1")
level13 = Level.objects.get(name="13")

Expand All @@ -42,31 +52,41 @@ def test_teacher_multiple_students_multiple_levels(self):
create_attempt(student2, level13, 16)

# Setup custom levels data
shared_level = create_save_level(student, "custom_level1", shared_with=[student2.new_user])
shared_level = create_save_level(
student, "custom_level1", shared_with=[student2.new_user]
)

create_attempt(student2, shared_level, 10)

all_levels = [level1, level13]
all_shared_levels = [shared_level]

attempts_per_student = {
student: Attempt.objects.filter(level__in=all_levels, student=student, is_best_attempt=True).select_related(
"level"
),
student: Attempt.objects.filter(
level__in=all_levels, student=student, is_best_attempt=True
).select_related("level"),
student2: Attempt.objects.filter(
level__in=all_levels, student=student2, is_best_attempt=True
).select_related("level"),
}

shared_attempts_per_student = {
student2: Attempt.objects.filter(
level__in=all_shared_levels, student=student2, is_best_attempt=True
level__in=all_shared_levels,
student=student2,
is_best_attempt=True,
).select_related("level"),
}

# Generate results
student_data, headers, level_headers, levels_sorted = scoreboard_data(episode_ids, attempts_per_student)
shared_headers, shared_level_headers, shared_student_data = shared_levels_data(
student_data, headers, level_headers, levels_sorted = scoreboard_data(
episode_ids, attempts_per_student
)
(
shared_headers,
shared_level_headers,
shared_student_data,
) = shared_levels_data(
student.new_user, all_shared_levels, shared_attempts_per_student
)

Expand Down Expand Up @@ -99,7 +119,9 @@ def test_teacher_multiple_students_multiple_levels(self):

# Check data for custom levels matches
assert shared_headers == SharedHeaders
assert shared_level_headers == [f"{shared_level.name} ({shared_level.owner})"]
assert shared_level_headers == [
f"{shared_level.name} ({shared_level.owner})"
]

assert len(shared_student_data) == 1

Expand Down Expand Up @@ -130,14 +152,23 @@ def test_scoreboard_loads(self):
data = {"classes": [klass.id], "view": [""]}

response = c.post(url, data)

active_levels = Level.objects.filter(episode__in_development=False)

assert response.status_code == 200
assert len(response.context["level_headers"]) == 109
assert len(response.context["level_headers"]) == active_levels.count()

def test_student_can_see_classes(self):
"""A student should be able to see the classes they are in"""
mr_teacher = Teacher.objects.factory("Normal", "Teacher", "[email protected]", "secretpa$sword")
klass, name1, _ = create_class_directly(mr_teacher.user.user.email, class_name="Class 1")
_, name2, _ = create_class_directly(mr_teacher.user.user.email, class_name="Class 2")
mr_teacher = Teacher.objects.factory(
"Normal", "Teacher", "[email protected]", "secretpa$sword"
)
klass, name1, _ = create_class_directly(
mr_teacher.user.user.email, class_name="Class 1"
)
_, name2, _ = create_class_directly(
mr_teacher.user.user.email, class_name="Class 2"
)
student = Student.objects.schoolFactory(klass, "some student", "secret")

c = Client()
Expand All @@ -146,43 +177,69 @@ def test_student_can_see_classes(self):
url = reverse("scoreboard")
response = c.get(url)

choices_in_form = [v for (k, v) in response.context["form"]["classes"].field.choices]
choices_in_form = [
v for (k, v) in response.context["form"]["classes"].field.choices
]
assert name1 in choices_in_form
assert name2 not in choices_in_form
assert len(choices_in_form) == 1

def test_admin_teacher_can_see_all_classes(self):
"""An admin should be able to see all classes, not just the ones they teach"""
normal_teacher = Teacher.objects.factory("Normal", "Teacher", "[email protected]", "secretpa$sword")
admin_teacher = Teacher.objects.factory("Admin", "Admin", "[email protected]", "secretpa$sword2")
normal_teacher = Teacher.objects.factory(
"Normal", "Teacher", "[email protected]", "secretpa$sword"
)
admin_teacher = Teacher.objects.factory(
"Admin", "Admin", "[email protected]", "secretpa$sword2"
)

admin_teacher.is_admin = True
admin_teacher.save()

_, name1, _ = create_class_directly(admin_teacher.user.user.email, class_name="Class 1")
_, name2, _ = create_class_directly(admin_teacher.user.user.email, class_name="Class 2")
_, name3, _ = create_class_directly(normal_teacher.user.user.email, class_name="Class 3")
_, name1, _ = create_class_directly(
admin_teacher.user.user.email, class_name="Class 1"
)
_, name2, _ = create_class_directly(
admin_teacher.user.user.email, class_name="Class 2"
)
_, name3, _ = create_class_directly(
normal_teacher.user.user.email, class_name="Class 3"
)

c = Client()
c.login(username=admin_teacher.user.user.email, password="secretpa$sword2")
c.login(
username=admin_teacher.user.user.email, password="secretpa$sword2"
)

url = reverse("scoreboard")
response = c.get(url)

choices_in_form = [v for (k, v) in response.context["form"]["classes"].field.choices]
choices_in_form = [
v for (k, v) in response.context["form"]["classes"].field.choices
]

assert name1 in choices_in_form
assert name2 in choices_in_form
assert name3 in choices_in_form

def test_non_admin_teacher_can_only_see_their_own_classes(self):
"""A teacher who is not an admin should only be able to see their classes, not ones taught by others"""
teacher1 = Teacher.objects.factory("First", "Teacher", "[email protected]", "secretpa$sword")
teacher2 = Teacher.objects.factory("Second", "Teacher", "[email protected]", "secretpa$sword2")
teacher1 = Teacher.objects.factory(
"First", "Teacher", "[email protected]", "secretpa$sword"
)
teacher2 = Teacher.objects.factory(
"Second", "Teacher", "[email protected]", "secretpa$sword2"
)

_, name1, _ = create_class_directly(teacher2.user.user.email, class_name="Class 1")
_, name2, _ = create_class_directly(teacher2.user.user.email, class_name="Class 2")
_, name3, _ = create_class_directly(teacher1.user.user.email, class_name="Class 3")
_, name1, _ = create_class_directly(
teacher2.user.user.email, class_name="Class 1"
)
_, name2, _ = create_class_directly(
teacher2.user.user.email, class_name="Class 2"
)
_, name3, _ = create_class_directly(
teacher1.user.user.email, class_name="Class 3"
)

c = Client()
# First teacher logs in. Should see only Class 3
Expand All @@ -191,7 +248,9 @@ def test_non_admin_teacher_can_only_see_their_own_classes(self):
url = reverse("scoreboard")
response = c.get(url)

choices_in_form = [v for (k, v) in response.context["form"]["classes"].field.choices]
choices_in_form = [
v for (k, v) in response.context["form"]["classes"].field.choices
]

assert name3 in choices_in_form
assert name1 not in choices_in_form
Expand All @@ -202,7 +261,9 @@ def test_non_admin_teacher_can_only_see_their_own_classes(self):
c.login(username="[email protected]", password="secretpa$sword2")

response = c.get(url)
choices_in_form = [v for (k, v) in response.context["form"]["classes"].field.choices]
choices_in_form = [
v for (k, v) in response.context["form"]["classes"].field.choices
]

assert name3 not in choices_in_form
assert name1 in choices_in_form
Expand All @@ -218,7 +279,10 @@ def test_independent_student_cannot_see_scoreboard(self):
url = reverse("scoreboard")
response = c.get(url)

assert "Scoreboard is only visible to school students and teachers" in str(response.content)
assert (
"Scoreboard is only visible to school students and teachers"
in str(response.content)
)


class ScoreboardCsvTestCase(TestCase):
Expand All @@ -234,14 +298,25 @@ def test_scoreboard_csv(self):

# Create 2 custom levels and create the associated student data
shared_level_rows = [None, None]
shared_level1 = create_save_level(students[0], "level1", shared_with=[students[1].new_user])
shared_level1 = create_save_level(
students[0], "level1", shared_with=[students[1].new_user]
)
shared_level2 = create_save_level(students[1], "level2")
shared_levels = [shared_level1, shared_level2]

shared_levels_headers = list([shared_level_to_name(level, level.owner) for level in shared_levels])
shared_levels_headers = list(
[
shared_level_to_name(level, level.owner)
for level in shared_levels
]
)

shared_level_rows[0] = self.shared_student_row(students[0], shared_levels)
shared_level_rows[1] = self.shared_student_row(students[1], shared_levels)
shared_level_rows[0] = self.shared_student_row(
students[0], shared_levels
)
shared_level_rows[1] = self.shared_student_row(
students[1], shared_levels
)

# Create students' improvement table data
improvement_data = []
Expand All @@ -250,7 +325,13 @@ def test_scoreboard_csv(self):
improvement_data.append(stud)

# Generate the CSV
response = scoreboard_csv(student_rows, levels, improvement_data, shared_levels_headers, shared_level_rows)
response = scoreboard_csv(
student_rows,
levels,
improvement_data,
shared_levels_headers,
shared_level_rows,
)

# Gather the data from the CSV
(
Expand All @@ -261,15 +342,27 @@ def test_scoreboard_csv(self):
) = self.actual_data(response.content.decode("utf-8"), len(students))

# Check the headers and the number or rows match expectations
assert actual_scoreboard_header == self.expected_scoreboard_header(levels)
assert actual_scoreboard_header == self.expected_scoreboard_header(
levels
)
assert len(actual_scoreboard_rows) == len(student_rows)
assert actual_shared_levels_header == self.expected_shared_levels_header(shared_levels)
assert (
actual_shared_levels_header
== self.expected_shared_levels_header(shared_levels)
)
assert len(actual_shared_levels_rows) == len(shared_level_rows)

# check first scoreboard row
(class_name, name, completed_levels, total_time, total_scores, l1, l2, improvement) = actual_scoreboard_rows[
0
].split(",")
(
class_name,
name,
completed_levels,
total_time,
total_scores,
l1,
l2,
improvement,
) = actual_scoreboard_rows[0].split(",")
assert student_rows[0].class_field.name == class_name
assert student_rows[0].name == name
assert student_rows[0].level_scores[0]["score"] == int(l1)
Expand All @@ -278,9 +371,16 @@ def test_scoreboard_csv(self):

# check last scoreboard row
last = len(actual_scoreboard_rows) - 1
(class_name, name, completed_levels, total_time, total_scores, l1, l2, improvement) = actual_scoreboard_rows[
last
].split(",")
(
class_name,
name,
completed_levels,
total_time,
total_scores,
l1,
l2,
improvement,
) = actual_scoreboard_rows[last].split(",")
assert student_rows[last].class_field.name == class_name
assert student_rows[last].name == name
assert str(student_rows[last].total_time) == total_time
Expand Down Expand Up @@ -364,12 +464,19 @@ def shared_student_row(self, student, shared_levels):

def expected_scoreboard_header(self, levels):
level_strings = list(map(str, levels))
all_header_strings = CSVHeaders + level_strings + ["Areas for improvement"]
all_header_strings = (
CSVHeaders + level_strings + ["Areas for improvement"]
)
joined = ",".join(all_header_strings)
return joined

def expected_shared_levels_header(self, shared_levels):
level_strings = list([shared_level_to_name(level, level.owner) for level in shared_levels])
level_strings = list(
[
shared_level_to_name(level, level.owner)
for level in shared_levels
]
)
all_header_strings = CSVSharedHeaders + level_strings
joined = ",".join(all_header_strings)
return joined
Expand All @@ -390,14 +497,25 @@ def actual_data(self, content, number_of_students):
scoreboard_header = split[scoreboard_header_row]
scoreboard_rows = split[scoreboard_rows_start:scoreboard_rows_end]
shared_levels_header = split[shared_levels_header_row]
shared_levels_rows = split[shared_levels_rows_start:shared_levels_rows_end]

return scoreboard_header, scoreboard_rows, shared_levels_header, shared_levels_rows
shared_levels_rows = split[
shared_levels_rows_start:shared_levels_rows_end
]

return (
scoreboard_header,
scoreboard_rows,
shared_levels_header,
shared_levels_rows,
)


def create_attempt(student, level, score):
attempt = Attempt.objects.create(
finish_time=datetime.fromtimestamp(1435305072), level=level, student=student, score=score, is_best_attempt=True
finish_time=datetime.fromtimestamp(1435305072),
level=level,
student=student,
score=score,
is_best_attempt=True,
)
attempt.start_time = datetime.fromtimestamp(1435305072)
attempt.save()
Expand Down

0 comments on commit 7f08ee3

Please sign in to comment.