#!/usr/bin/env python
"""
camcops_server/tasks/tests/apeq_cpft_perinatal_tests.py
===============================================================================
Copyright (C) 2012, University of Cambridge, Department of Psychiatry.
Created by Rudolf Cardinal (rnc1001@cam.ac.uk).
This file is part of CamCOPS.
CamCOPS is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
CamCOPS is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with CamCOPS. If not, see <https://www.gnu.org/licenses/>.
===============================================================================
"""
from typing import Generator, Optional
import pendulum
from camcops_server.cc_modules.cc_unittest import BasicDatabaseTestCase
from camcops_server.tasks.apeq_cpft_perinatal import (
APEQCPFTPerinatal,
APEQCPFTPerinatalReport,
)
# =============================================================================
# Unit tests
# =============================================================================
[docs]class APEQCPFTPerinatalReportTestCase(BasicDatabaseTestCase):
COL_Q = 0
COL_TOTAL = 1
COL_RESPONSE_START = 2
COL_FF_WHY = 1
[docs] def __init__(self, *args, **kwargs) -> None:
super().__init__(*args, **kwargs)
self.id_sequence = self.get_id()
[docs] def setUp(self) -> None:
super().setUp()
self.report = APEQCPFTPerinatalReport()
# Really only needed for tests
self.report.start_datetime = None
self.report.end_datetime = None
@staticmethod
def get_id() -> Generator[int, None, None]:
i = 1
while True:
yield i
i += 1
def create_task(
self,
q1: Optional[int],
q2: Optional[int],
q3: Optional[int],
q4: Optional[int],
q5: Optional[int],
q6: Optional[int],
ff_rating: int,
ff_why: str = None,
comments: str = None,
era: str = None,
) -> None:
task = APEQCPFTPerinatal()
self.apply_standard_task_fields(task)
task.id = next(self.id_sequence)
task.q1 = q1
task.q2 = q2
task.q3 = q3
task.q4 = q4
task.q5 = q5
task.q6 = q6
task.ff_rating = ff_rating
task.ff_why = ff_why
task.comments = comments
if era is not None:
task.when_created = pendulum.parse(era)
self.dbsession.add(task)
[docs]class APEQCPFTPerinatalReportTests(APEQCPFTPerinatalReportTestCase):
[docs] def create_tasks(self) -> None:
"""
Creates 20 tasks.
Should give us:
.. code-block:: none
q1: 0 - 50%,
1 - 25%
2 - 25%
q2: 1 - 100%
q3: 0 - 5%
1 - 20%
2 - 75%
q4: 0 - 10%
1 - 40%
2 - 50%
q5: 0 - 15%
1 - 55%
2 - 30%
q6: 1 - 50%
2 - 50%
ff: 0 - 25%
1 - 10%
2 - 15%
3 - 10%
4 - 5%
5 - 35%
"""
# q1 q2 q3 q4 q5 q6 ff
self.create_task(0, 1, 0, 0, 2, 2, 5, ff_why="ff_5_1")
self.create_task(
0, 1, 1, 0, 2, 2, 5, ff_why="ff_5_2", comments="comments_2"
)
self.create_task(0, 1, 1, 1, 2, 2, 5)
self.create_task(0, 1, 1, 1, 2, 2, 5)
self.create_task(0, 1, 1, 1, 2, 2, 5, comments="comments_5")
self.create_task(0, 1, 2, 1, 2, 2, 5)
self.create_task(0, 1, 2, 1, 1, 2, 5)
self.create_task(0, 1, 2, 1, 1, 2, 4, ff_why="ff_4_1")
self.create_task(0, 1, 2, 1, 1, 2, 3)
self.create_task(0, 1, 2, 1, 1, 1, 3, ff_why="ff_3_1")
self.create_task(1, 1, 2, 2, 1, 1, 2, ff_why="ff_2_1")
self.create_task(1, 1, 2, 2, 1, 1, 2)
self.create_task(1, 1, 2, 2, 1, 1, 2, ff_why="ff_2_2")
self.create_task(1, 1, 2, 2, 1, 1, 1, ff_why="ff_1_1")
self.create_task(1, 1, 2, 2, 1, 1, 1, ff_why="ff_1_2")
self.create_task(2, 1, 2, 2, 1, 1, 0)
self.create_task(2, 1, 2, 2, 1, 1, 0)
self.create_task(2, 1, 2, 2, 0, None, 0)
self.create_task(2, 1, 2, 2, 0, None, 0)
self.create_task(2, 1, 2, 2, 0, 1, 0, comments="comments_20")
self.dbsession.commit()
def test_main_rows_contain_percentages(self) -> None:
expected_percentages = [
[20, 50, 25, 25], # q1
[20, "", 100, ""], # q2
[20, 5, 20, 75], # q3
[20, 10, 40, 50], # q4
[20, 15, 55, 30], # q5
[18, "", 50, 50], # q6
]
main_rows = self.report._get_main_rows(self.req)
# MySQL does floating point division
for row, expected in zip(main_rows, expected_percentages):
percentages = []
for p in row[1:]:
if p != "":
p = int(float(p))
percentages.append(p)
self.assertEqual(percentages, expected)
def test_main_rows_formatted(self) -> None:
expected_q1 = [20, "50.0%", "25.0%", "25.0%"]
main_rows = self.report._get_main_rows(
self.req, cell_format="{0:.1f}%"
)
self.assertEqual(main_rows[0][1:], expected_q1)
def test_ff_rows_contain_percentages(self) -> None:
expected_ff = [20, 25, 10, 15, 10, 5, 35]
ff_rows = self.report._get_ff_rows(self.req)
# MySQL does floating point division
percentages = [int(float(p)) for p in ff_rows[0][1:]]
self.assertEqual(percentages, expected_ff)
def test_ff_rows_formatted(self) -> None:
expected_ff = [20, "25.0%", "10.0%", "15.0%", "10.0%", "5.0%", "35.0%"]
ff_rows = self.report._get_ff_rows(self.req, cell_format="{0:.1f}%")
self.assertEqual(ff_rows[0][1:], expected_ff)
def test_ff_why_rows_contain_reasons(self) -> None:
expected_reasons = [
["Extremely unlikely", "ff_1_1"],
["Extremely unlikely", "ff_1_2"],
["Unlikely", "ff_2_1"],
["Unlikely", "ff_2_2"],
["Neither likely nor unlikely", "ff_3_1"],
["Likely", "ff_4_1"],
["Extremely likely", "ff_5_1"],
["Extremely likely", "ff_5_2"],
]
ff_why_rows = self.report._get_ff_why_rows(self.req)
self.assertEqual(ff_why_rows, expected_reasons)
def test_comments(self) -> None:
expected_comments = ["comments_2", "comments_5", "comments_20"]
comments = self.report._get_comments(self.req)
self.assertEqual(comments, expected_comments)
[docs]class APEQCPFTPerinatalReportDateRangeTests(APEQCPFTPerinatalReportTestCase):
def create_tasks(self) -> None:
self.create_task(
1,
0,
0,
0,
0,
0,
0,
ff_why="ff why 1",
comments="comments 1",
era="2018-10-01T00:00:00.000000+00:00",
)
self.create_task(
0,
0,
0,
0,
0,
0,
2,
ff_why="ff why 2",
comments="comments 2",
era="2018-10-02T00:00:00.000000+00:00",
)
self.create_task(
0,
0,
0,
0,
0,
0,
2,
ff_why="ff why 3",
comments="comments 3",
era="2018-10-03T00:00:00.000000+00:00",
)
self.create_task(
0,
0,
0,
0,
0,
0,
2,
ff_why="ff why 4",
comments="comments 4",
era="2018-10-04T00:00:00.000000+00:00",
)
self.create_task(
1,
0,
0,
0,
0,
0,
0,
ff_why="ff why 5",
comments="comments 5",
era="2018-10-05T00:00:00.000000+00:00",
)
self.dbsession.commit()
def test_main_rows_filtered_by_date(self) -> None:
self.report.start_datetime = "2018-10-02T00:00:00.000000+00:00"
self.report.end_datetime = "2018-10-05T00:00:00.000000+00:00"
rows = self.report._get_main_rows(self.req, cell_format="{0:.1f}%")
q1_row = rows[0]
# There should be three tasks included in the calculation.
self.assertEqual(q1_row[self.COL_TOTAL], 3)
# For question 1 all of them answered 0 so we would expect
# 100%. If the results aren't being filtered we will get
# 60%
self.assertEqual(q1_row[self.COL_RESPONSE_START + 0], "100.0%")
def test_ff_rows_filtered_by_date(self) -> None:
self.report.start_datetime = "2018-10-02T00:00:00.000000+00:00"
self.report.end_datetime = "2018-10-05T00:00:00.000000+00:00"
rows = self.report._get_ff_rows(self.req, cell_format="{0:.1f}%")
ff_row = rows[0]
# There should be three tasks included in the calculation.
self.assertEqual(ff_row[self.COL_TOTAL], 3)
# For the ff question all of them answered 2 so we would expect
# 100%. If the results aren't being filtered we will get
# 60%
self.assertEqual(ff_row[self.COL_RESPONSE_START + 2], "100.0%")
def test_ff_why_row_filtered_by_date(self) -> None:
self.report.start_datetime = "2018-10-02T00:00:00.000000+00:00"
self.report.end_datetime = "2018-10-05T00:00:00.000000+00:00"
rows = self.report._get_ff_why_rows(self.req)
self.assertEqual(len(rows), 3)
self.assertEqual(rows[0][self.COL_FF_WHY], "ff why 2")
self.assertEqual(rows[1][self.COL_FF_WHY], "ff why 3")
self.assertEqual(rows[2][self.COL_FF_WHY], "ff why 4")
def test_comments_filtered_by_date(self) -> None:
self.report.start_datetime = "2018-10-02T00:00:00.000000+00:00"
self.report.end_datetime = "2018-10-05T00:00:00.000000+00:00"
comments = self.report._get_comments(self.req)
self.assertEqual(len(comments), 3)
self.assertEqual(comments[0], "comments 2")
self.assertEqual(comments[1], "comments 3")
self.assertEqual(comments[2], "comments 4")