-
Notifications
You must be signed in to change notification settings - Fork 12
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
dba8445
commit d9a5b4a
Showing
3 changed files
with
252 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
{"birth_data":{"birth_date":"2020-04-12","gestation_weeks":40,"gestation_days":0,"estimated_date_delivery":"2020-04-12","estimated_date_delivery_string":"Sun 12 April, 2020","sex":"female"},"measurement_dates":{"observation_date":"2028-06-12","chronological_decimal_age":8.167008898015059,"corrected_decimal_age":8.167008898015059,"chronological_calendar_age":"8 years and 2 months","corrected_calendar_age":"8 years and 2 months","corrected_gestational_age":{"corrected_gestation_weeks":null,"corrected_gestation_days":null},"comments":{"clinician_corrected_decimal_age_comment":"Born at term. No correction for gestation has been made.","lay_corrected_decimal_age_comment":"Your child was born at term. No correction for gestation has been made.","clinician_chronological_decimal_age_comment":"Born at term. No correction for gestation has been made.","lay_chronological_decimal_age_comment":"Your child was born at term. No correction for gestation has been made."},"corrected_decimal_age_error":null,"chronological_decimal_age_error":null},"child_observation_value":{"measurement_method":"height","observation_value":115.0,"observation_value_error":null},"measurement_calculated_values":{"corrected_sds":-2.139034562567385,"corrected_centile":1.6216,"corrected_centile_band":"This height measurement is on or near the 2nd centile.","chronological_sds":-2.139034562567385,"chronological_centile":1.6216,"chronological_centile_band":"This height measurement is on or near the 2nd centile.","corrected_measurement_error":null,"chronological_measurement_error":null,"corrected_percentage_median_bmi":null,"chronological_percentage_median_bmi":null},"plottable_data":{"centile_data":{"chronological_decimal_age_data":{"x":8.167008898015059,"y":115.0,"b":10.0,"centile":1.6216,"sds":-2.139034562567385,"bone_age_label":"This bone age is advanced","events_text":["Growth hormone start","Growth Hormone Deficiency diagnosis"],"bone_age_type":"greulich-pyle","bone_age_sds":2.0,"bone_age_centile":98.0,"observation_error":null,"age_type":"chronological_age","calendar_age":"8 years and 2 months","lay_comment":"Your child was born at term. No correction for gestation has been made.","clinician_comment":"Born at term. No correction for gestation has been made.","age_error":null,"centile_band":"This height measurement is on or near the 2nd centile.","observation_value_error":null},"corrected_decimal_age_data":{"x":8.167008898015059,"y":115.0,"b":10.0,"centile":1.6216,"sds":-2.139034562567385,"bone_age_label":"This bone age is advanced","events_text":["Growth hormone start","Growth Hormone Deficiency diagnosis"],"bone_age_type":"greulich-pyle","bone_age_sds":2.0,"bone_age_centile":98.0,"observation_error":null,"age_type":"corrected_age","calendar_age":"8 years and 2 months","corrected_gestational_age":"","lay_comment":"Your child was born at term. No correction for gestation has been made.","clinician_comment":"Born at term. No correction for gestation has been made.","age_error":null,"centile_band":"This height measurement is on or near the 2nd centile.","observation_value_error":null}},"sds_data":{"chronological_decimal_age_data":{"x":8.167008898015059,"y":-2.139034562567385,"b":10.0,"centile":1.6216,"sds":null,"bone_age_label":"This bone age is advanced","events_text":["Growth hormone start","Growth Hormone Deficiency diagnosis"],"bone_age_type":"greulich-pyle","bone_age_sds":2.0,"bone_age_centile":98.0,"observation_error":null,"age_type":"chronological_age","calendar_age":"8 years and 2 months","lay_comment":"Your child was born at term. No correction for gestation has been made.","clinician_comment":"Born at term. No correction for gestation has been made.","age_error":null,"centile_band":"This height measurement is on or near the 2nd centile.","observation_value_error":null},"corrected_decimal_age_data":{"x":8.167008898015059,"y":-2.139034562567385,"b":10.0,"centile":1.6216,"sds":null,"bone_age_label":"This bone age is advanced","events_text":["Growth hormone start","Growth Hormone Deficiency diagnosis"],"bone_age_type":"greulich-pyle","bone_age_sds":2.0,"bone_age_centile":98.0,"observation_error":null,"age_type":"corrected_age","calendar_age":"8 years and 2 months","corrected_gestational_age":"","lay_comment":"Your child was born at term. No correction for gestation has been made.","clinician_comment":"Born at term. No correction for gestation has been made.","age_error":null,"centile_band":"This height measurement is on or near the 2nd centile.","observation_value_error":null}}},"bone_age":{"bone_age":10.0,"bone_age_type":"greulich-pyle","bone_age_sds":2.0,"bone_age_centile":98.0,"bone_age_text":"This bone age is advanced"},"events_data":{"events_text":["Growth hormone start","Growth Hormone Deficiency diagnosis"]}} |
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,250 @@ | ||
""" | ||
Tests for the UK-WHO endpoints | ||
""" | ||
|
||
# standard imports | ||
import json | ||
import hashlib | ||
|
||
# third party imports | ||
from fastapi.testclient import TestClient | ||
import pytest | ||
|
||
# local / rcpch imports | ||
from main import app | ||
|
||
client = TestClient(app) | ||
|
||
|
||
def test_who_calculation_with_valid_request(): | ||
|
||
body = { | ||
"birth_date": "2020-04-12", | ||
"observation_date": "2028-06-12", | ||
"observation_value": 115, | ||
"sex": "female", | ||
"gestation_weeks": 40, | ||
"gestation_days": 0, | ||
"measurement_method": "height", | ||
"bone_age": 10, | ||
"bone_age_centile": 98, | ||
"bone_age_sds": 2.0, | ||
"bone_age_text": "This bone age is advanced", | ||
"bone_age_type": "greulich-pyle", | ||
"events_text": ["Growth hormone start", "Growth Hormone Deficiency diagnosis"], | ||
} | ||
|
||
response = client.post("/who/calculation", json=body) | ||
|
||
assert response.status_code == 200 | ||
|
||
# load the known-correct response from file | ||
with open(r"tests/test_data/test_who_calculation_valid.json", "r") as file: | ||
calculation_file = file.read() | ||
# load the two JSON responses as Python Dicts so enable comparison (slow but more reliable) | ||
assert response.json() == json.loads(calculation_file) | ||
|
||
|
||
def test_who_calculation_with_invalid_request(): | ||
|
||
# this is a garbage request which should trigger appropriate validation responses | ||
body = { | ||
"birth_date": "invalid_birth_date", | ||
"observation_date": "invalid_observation_date", | ||
"observation_value": "invalid_observation_value", | ||
"sex": "invalid_sex", | ||
"gestation_weeks": "invalid_gestation_weeks", | ||
"gestation_days": "invalid_gestation_days", | ||
"measurement_method": "invalid_measurement_method", | ||
} | ||
|
||
response = client.post("/who/calculation", json=body) | ||
|
||
assert response.status_code == 422 | ||
|
||
# restructure the response to make it easier to assert tests specifically | ||
validation_errors = {error["loc"][1]: error for error in response.json()["detail"]} | ||
assert ( | ||
validation_errors["birth_date"]["msg"] | ||
== "Value error, time data 'invalid_birth_date' does not match format '%Y-%m-%d'" | ||
) | ||
assert ( | ||
validation_errors["gestation_days"]["msg"] | ||
== "Input should be a valid integer, unable to parse string as an integer" | ||
) | ||
assert ( | ||
validation_errors["gestation_weeks"]["msg"] | ||
== "Input should be a valid integer, unable to parse string as an integer" | ||
) | ||
assert ( | ||
validation_errors["measurement_method"]["msg"] | ||
== "Input should be 'height', 'weight', 'ofc' or 'bmi'" | ||
) | ||
assert ( | ||
validation_errors["observation_date"]["msg"] | ||
== "Input should be a valid date or datetime, invalid character in year" | ||
) | ||
assert ( | ||
validation_errors["observation_value"]["msg"] | ||
== "Input should be a valid number, unable to parse string as a number" | ||
) | ||
assert validation_errors["sex"]["msg"] == "Input should be 'male' or 'female'" | ||
|
||
@pytest.mark.parametrize("input", [ | ||
{ "measurement_method": "height", "observation_value": 200, "birth_date": "2015-10-26", "observation_date": "2020-09-01", "sex": "female" }, # height too tall | ||
{ "measurement_method": "height", "observation_value": 5, "birth_date": "2015-10-26", "observation_date": "2020-09-01", "sex": "female" }, # height too short | ||
{ "measurement_method": "weight", "observation_value": 200, "birth_date": "2015-10-26", "observation_date": "2020-09-01", "sex": "female" }, # weight too high | ||
{ "measurement_method": "weight", "observation_value": 1, "birth_date": "2015-10-26", "observation_date": "2020-09-01", "sex": "female" }, # weight too low | ||
{ "measurement_method": "ofc", "observation_value": 500, "birth_date": "2015-10-26", "observation_date": "2020-09-01", "sex": "female" }, # head circumference too high | ||
{ "measurement_method": "ofc", "observation_value": 1, "birth_date": "2015-10-26", "observation_date": "2020-09-01", "sex": "female" }, # head circumference too low | ||
{ "measurement_method": "ofc", "observation_value": 500, "birth_date": "2015-10-26", "observation_date": "2034-09-01", "sex": "male" }, # 19y boy head circumference beyond age range | ||
{ "measurement_method": "ofc", "observation_value": 1, "birth_date": "2015-10-26", "observation_date": "2033-09-01", "sex": "female" }, # 18y girl head circumference beyond age range | ||
{ "measurement_method": "height", "observation_value": 175, "birth_date": "2015-10-26", "observation_date": "2036-09-01", "sex": "female" }, # height too old (>20y) | ||
{ "measurement_method": "height", "observation_value": 45, "birth_date": "2015-10-26", "observation_date": "2015-10-26", "sex": "female", "gestation_weeks": 23, "gestation_days": 0 }, # height too young (<25 weeks) | ||
{ "measurement_method": "weight", "observation_value": 200, "birth_date": "2015-10-26", "observation_date": "2036-09-01", "sex": "female" }, # weight too old (>20y) | ||
{ "measurement_method": "weight", "observation_value": 1, "birth_date": "2015-10-26", "observation_date": "2015-10-26", "sex": "female", "gestation_weeks": 22, "gestation_days": 0 }, # weight too young (<23 weeks) | ||
]) | ||
def test_who_chart_with_valid_request_for_outside_range_values(input): | ||
|
||
body = input | ||
response = client.post("/who/calculation", json=body) | ||
|
||
assert response.status_code == 422 | ||
|
||
|
||
@pytest.mark.parametrize("input", [ | ||
{ "measurement_method": "height", "sex": "male" }, | ||
{ "measurement_method": "weight", "sex": "male" }, | ||
{ "measurement_method": "ofc", "sex": "male" }, | ||
{ "measurement_method": "bmi", "sex": "male" }, | ||
{ "measurement_method": "height", "sex": "female" }, | ||
{ "measurement_method": "weight", "sex": "female" }, | ||
{ "measurement_method": "ofc", "sex": "female" }, | ||
{ "measurement_method": "bmi", "sex": "female" } | ||
]) | ||
def test_who_chart_data_with_valid_request(input): | ||
body = input | { | ||
"centile_format": "cole-nine-centiles", | ||
"is_sds": False, | ||
} | ||
|
||
response = client.post("/who/chart-coordinates", json=body) | ||
|
||
assert response.status_code == 200 | ||
|
||
# TODO: Check the actual values returned. We do already validate it against the schema though. | ||
|
||
|
||
def test_who_chart_data_with_invalid_request(): | ||
body = {"measurement_method": "invalid_measurement_method", "sex": "invalid_sex"} | ||
|
||
response = client.post("/who/chart-coordinates", json=body) | ||
|
||
assert response.status_code == 422 | ||
|
||
|
||
def test_who_fictional_child_data_with_valid_request(): | ||
|
||
body = { | ||
"measurement_method": "height", | ||
"sex": "female", | ||
"start_chronological_age": 0, | ||
"end_age": 1, | ||
"gestation_weeks": 40, | ||
"gestation_days": 0, | ||
"measurement_interval_type": "days", | ||
"measurement_interval_number": 30, | ||
"start_sds": 0, | ||
"drift": False, | ||
"drift_range": -0.05, | ||
"noise": False, | ||
"noise_range": 0.005, | ||
} | ||
|
||
response = client.post("/who/fictional-child-data", json=body) | ||
|
||
assert response.status_code == 200 | ||
|
||
# load the known-correct response from file | ||
with open( | ||
r"tests/test_data/test_who_fictional_child_data_valid.json", "r" | ||
) as file: | ||
fictional_child_data_file = file.read() | ||
# load the two JSON responses as Python Dicts so enable comparison (slow but more reliable) | ||
assert response.json() == json.loads(fictional_child_data_file) | ||
|
||
|
||
def test_who_fictional_child_data_with_invalid_request(): | ||
|
||
body = { | ||
"measurement_method": "invalid_measurement_method", | ||
"sex": "invalid_sex", | ||
"start_chronological_age": "invalid_start_chronological_age", | ||
"end_age": "invalid_end_age", | ||
"gestation_weeks": "invalid_gestation_weeks", | ||
"gestation_days": "invalid_gestation_days", | ||
"measurement_interval_type": "invalid_measurement_interval_type", | ||
"measurement_interval_number": "invalid_measurement_interval_number", | ||
"start_sds": "invalid_start_sds", | ||
"drift": "invalid_drift", | ||
"drift_range": "invalid_drift_range", | ||
"noise": "invalid_noise", | ||
"noise_range": "invalid_noise_range", | ||
} | ||
|
||
response = client.post("/who/fictional-child-data", json=body) | ||
|
||
assert response.status_code == 422 | ||
|
||
# COMMENTED OUT FOR BRANCH 'dockerise' PENDING DECISION ON #166 (API Test Suite) (pacharanero, 2024-02-07 ) | ||
# restructure the response to make it easier to assert tests specifically | ||
validation_errors = {error["loc"][1]: error for error in response.json()["detail"]} | ||
assert ( | ||
validation_errors["measurement_method"]["msg"] | ||
== "Input should be 'height', 'weight', 'ofc' or 'bmi'" | ||
) | ||
assert validation_errors["sex"]["msg"] == "Input should be 'male' or 'female'" | ||
assert ( | ||
validation_errors["start_chronological_age"]["msg"] | ||
== "Input should be a valid number, unable to parse string as a number" | ||
) | ||
assert ( | ||
validation_errors["end_age"]["msg"] | ||
== "Input should be a valid number, unable to parse string as a number" | ||
) | ||
assert ( | ||
validation_errors["gestation_weeks"]["msg"] | ||
== "Input should be a valid integer, unable to parse string as an integer" | ||
) | ||
assert ( | ||
validation_errors["gestation_days"]["msg"] | ||
== "Input should be a valid integer, unable to parse string as an integer" | ||
) | ||
assert ( | ||
validation_errors["measurement_interval_type"]["msg"] | ||
== "Input should be 'd', 'day', 'days', 'w', 'week', 'weeks', 'm', 'month', 'months', 'y', 'year' or 'years'" | ||
) | ||
assert ( | ||
validation_errors["measurement_interval_number"]["msg"] | ||
== "Input should be a valid integer, unable to parse string as an integer" | ||
) | ||
assert ( | ||
validation_errors["start_sds"]["msg"] | ||
== "Input should be a valid number, unable to parse string as a number" | ||
) | ||
assert ( | ||
validation_errors["drift"]["msg"] | ||
== "Input should be a valid boolean, unable to interpret input" | ||
) | ||
assert ( | ||
validation_errors["drift_range"]["msg"] | ||
== "Input should be a valid number, unable to parse string as a number" | ||
) | ||
assert ( | ||
validation_errors["noise"]["msg"] | ||
== "Input should be a valid boolean, unable to interpret input" | ||
) | ||
assert ( | ||
validation_errors["noise_range"]["msg"] | ||
== "Input should be a valid number, unable to parse string as a number" | ||
) |