Skip to content

Commit 993f2ea

Browse files
committed
working unit tests
1 parent 1acc9b2 commit 993f2ea

File tree

11 files changed

+183
-51
lines changed

11 files changed

+183
-51
lines changed

delta_backend/.coverage

0 Bytes
Binary file not shown.

delta_backend/README.md

Lines changed: 1 addition & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -82,22 +82,4 @@ This script loads sample FHIR data, runs it through the converter, and automatic
8282
```bash
8383
python test_runner.py
8484
```
85-
86-
### 📁 Output Location
87-
When the script runs, it will automatically:
88-
- Save a **flat JSON file** as `output.json`
89-
- Save a **CSV file** as `output.csv`
90-
91-
These will be located one level up from the `src/` folder:
92-
93-
```
94-
/mnt/c/Users/USER/desktop/shn/immunisation-fhir-api/delta_backend/output.json
95-
/mnt/c/Users/USER/desktop/shn/immunisation-fhir-api/delta_backend/output.csv
96-
```
97-
98-
### 👀 Visualization
99-
You can now:
100-
- Open `output.csv` in Excel or Google Sheets to view cleanly structured records
101-
- Inspect `output.json` to validate the flat key-value output programmatically
102-
103-
---
85+
---

delta_backend/__init__.py

Whitespace-only changes.

delta_backend/poetry.lock

Lines changed: 110 additions & 9 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

delta_backend/pyproject.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,9 @@ boto3 = "~1.26.90"
1111
mypy-boto3-dynamodb = "^1.26.164"
1212
moto = "~4.2.11"
1313

14+
[tool.poetry.group.dev.dependencies]
15+
coverage = "^7.8.0"
16+
1417
[build-system]
1518
requires = ["poetry-core"]
1619
build-backend = "poetry.core.masonry.api"

delta_backend/src/ConversionChecker.py

Lines changed: 27 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -87,28 +87,45 @@ def convertData(self, expressionType, expressionRule, fieldName, fieldValue):
8787
def _convertToDate(self, expressionRule, fieldName, fieldValue, summarise, report_unexpected_exception):
8888
if not fieldValue:
8989
return ""
90+
91+
if not isinstance(fieldValue, str):
92+
raise RecordError(
93+
ExceptionMessages.RECORD_CHECK_FAILED,
94+
f"{fieldName} rejected: not a string.",
95+
f"Received: {type(fieldValue)}",
96+
)
97+
# Reject partial dates like "2024" or "2024-05"
9098
if re.match(r"^\d{4}(-\d{2})?$", fieldValue):
9199
raise RecordError(
92100
ExceptionMessages.RECORD_CHECK_FAILED,
93101
f"{fieldName} rejected: partial date not accepted.",
94102
f"Invalid partial date: {fieldValue}",
95103
)
96-
dt = datetime.fromisoformat(fieldValue)
97-
format_str = expressionRule.replace("format:", "")
98-
return dt.strftime(format_str)
104+
try:
105+
dt = datetime.fromisoformat(fieldValue)
106+
format_str = expressionRule.replace("format:", "")
107+
return dt.strftime(format_str)
108+
except ValueError:
109+
if report_unexpected_exception:
110+
return f"Unexpected format: {fieldValue}"
99111

100112
# Convert FHIR datetime into CSV-safe UTC format
101113
def _convertToDateTime(self, expressionRule, fieldName, fieldValue, summarise, report_unexpected_exception):
102114
if not fieldValue:
103115
return ""
116+
117+
# Reject partial dates like "2024" or "2024-05"
104118
if re.match(r"^\d{4}(-\d{2})?$", fieldValue):
105119
raise RecordError(
106120
ExceptionMessages.RECORD_CHECK_FAILED,
107121
f"{fieldName} rejected: partial datetime not accepted.",
108122
f"Invalid partial datetime: {fieldValue}",
109123
)
110-
111-
dt = datetime.fromisoformat(fieldValue)
124+
try:
125+
dt = datetime.fromisoformat(fieldValue)
126+
except ValueError:
127+
if report_unexpected_exception:
128+
return f"Unexpected format: {fieldValue}"
112129

113130
# Allow only +00:00 or +01:00 offsets (UTC and BST) and reject unsupported timezones
114131
offset = dt.utcoffset()
@@ -126,10 +143,12 @@ def _convertToDateTime(self, expressionRule, fieldName, fieldValue, summarise, r
126143
format_str = expressionRule.replace("format:", "")
127144

128145
if format_str == "csv-utc":
129-
formatted = dt_utc.strftime("%Y-%m-%dT%H:%M:%S %z")
130-
return formatted
131-
146+
formatted = dt_utc.strftime("%Y%m%dT%H%M%S%z")
147+
return formatted.replace("+0000", "00").replace("+0100", "01")
148+
132149
return dt_utc.strftime(format_str)
150+
151+
133152

134153
# Not Empty Validate
135154
def _convertToNotEmpty(self, expressionRule, fieldName, fieldValue, summarise, report_unexpected_exception):

delta_backend/src/ConversionLayout.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@
4141
"expression": {
4242
"expressionName": "Date Convert",
4343
"expressionType": "DATECONVERT",
44-
"expressionRule": "%Y-%m-%d"
44+
"expressionRule": "%Y%m%d"
4545
}
4646
},
4747
{
@@ -221,7 +221,7 @@
221221
"expression": {
222222
"expressionName": "Date Convert",
223223
"expressionType": "DATECONVERT",
224-
"expressionRule": "format:%Y-%m-%d"
224+
"expressionRule": "format:%Y%m%d"
225225
}
226226
},
227227
{

delta_backend/src/__init__.py

Whitespace-only changes.

delta_backend/src/test_runner.py

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,12 @@
1-
from Converter import Converter
1+
22
import json
33
import csv
44
import os
5+
import sys
6+
7+
sys.path.insert(0, os.path.abspath(os.path.dirname(__file__)))
8+
from Converter import Converter
9+
510

611
# Sample FHIR Immunization resource (minimal test data)
712
fhir_sample = {
@@ -178,5 +183,5 @@
178183
writer.writeheader()
179184
writer.writerows(result)
180185

181-
print("CSV saved to:", csv_path)
182-
print("JSON saved to:", json_path)
186+
print("CSV saved to:", csv_path)
187+
print("JSON saved to:", json_path)

delta_backend/tests/test_convert_to_flat_json.py

Lines changed: 30 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@
3131
@mock_dynamodb
3232
@mock_sqs
3333
class TestConvertToFlatJson(unittest.TestCase):
34-
34+
maxDiff = None
3535
def setUp(self):
3636
"""Set up mock DynamoDB table."""
3737
self.dynamodb_resource = boto3_resource("dynamodb", "eu-west-2")
@@ -327,16 +327,38 @@ def test_convert_to_date(self, MockLookUpData):
327327
checker = ConversionChecker(dataParser, summarise=False, report_unexpected_exception=True)
328328

329329
valid_date = "2022-01-01"
330-
result = checker._convertToDate("%Y-%m-%d", "fieldName", valid_date, False, True)
331-
self.assertEqual(result, "2022-01-01")
332-
330+
result = checker._convertToDate("%Y%m%d", "fieldName", valid_date, False, True)
331+
self.assertEqual(result, "20220101")
332+
333333
invalid_date = "invalid_date"
334-
result = checker._convertToDate("%Y-%m-%d", "fieldName", invalid_date, False, True)
335-
self.assertTrue("Unexpected exception" in result)
334+
result = checker._convertToDate("format:%Y%m%d", "fieldName", invalid_date, False, True)
335+
self.assertEqual(result, "Unexpected format: invalid_date")
336336

337337
# Test for error case with exception
338-
result = checker._convertToDate("%Y-%m-%d", "fieldName", None, False, True)
339-
self.assertTrue("Unexpected exception" in result)
338+
result = checker._convertToDate("%Y%m%d", "fieldName", None, False, True)
339+
self.assertEqual(result, "")
340+
341+
@patch("ConversionChecker.LookUpData")
342+
def test_convert_to_date_time(self, MockLookUpData):
343+
dataParser = Mock()
344+
345+
checker = ConversionChecker(dataParser, summarise=False, report_unexpected_exception=True)
346+
347+
valid_date_time = "2022-01-01T12:00:00+00:00"
348+
result = checker._convertToDateTime("%Y%m%dT%H%M%S", "fieldName", valid_date_time, False, True)
349+
self.assertEqual(result, "20220101T120000")
350+
351+
valid_csv_utc = "2022-01-01T13:28:17+00:00"
352+
result = checker._convertToDateTime("format:csv-utc", "fieldName", valid_csv_utc, False, True)
353+
self.assertEqual(result, "20220101T13281700")
354+
355+
invalid_date_time = "invalid_date_time"
356+
result = checker._convertToDateTime("format:%Y%m%dT%H%M%S", "fieldName", invalid_date_time, False, True)
357+
self.assertEqual(result, "Unexpected format: invalid_date_time")
358+
359+
# Empty input returns blank
360+
result = checker._convertToDateTime("format:%Y%m%dT%H%M%S", "fieldName", "", False, True)
361+
self.assertEqual(result, "")
340362

341363
def clear_table(self):
342364
scan = self.table.scan()

0 commit comments

Comments
 (0)