From b2f71133ae912b9c1aa4624a1be3979882a18213 Mon Sep 17 00:00:00 2001 From: RunasSudo Date: Tue, 27 Aug 2024 17:14:45 +1000 Subject: [PATCH] Add unit tests for threshold calculations --- tests/thresholds.test.js | 104 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 104 insertions(+) create mode 100644 tests/thresholds.test.js diff --git a/tests/thresholds.test.js b/tests/thresholds.test.js new file mode 100644 index 0000000..b484cbf --- /dev/null +++ b/tests/thresholds.test.js @@ -0,0 +1,104 @@ +/* + Neonatal jaundice treatment threshold calculator + Copyright (C) 2024 Lee Yingtong Li + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program 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 Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . +*/ + +// Import bilirubin_lib.js +const fs = require('fs'); +eval(fs.readFileSync('src/bilirubin_lib.js').toString()); + +const assert = require('node:assert'); +const { suite, test } = require('node:test'); + +function nearlyEqual(a, b, tol_abs) { + return Math.abs(a - b) <= tol_abs; +} + +suite('Phototherapy thresholds vs NICE', () => { + // Compare with NICE "Data sheet" tab + const expected_phototherapy = { + 38: [100, 125, 150, 175, 200, 212, 225, 237, 250, 262, 275, 287, 300, 312, 325, 337, 350, 350, 350, 350, 350, 350, 350, 350, 350, 350, 350, 350, 350, 350, 350, 350, 350, 350, 350, 350, 350, 350, 350, 350, 350, 350, 350, 350, 350, 350, 350, 350, 350, 350, 350, 350, 350, 350, 350, 350, 350], + 37: [40, 59.1666666666667, 78.3333333333333, 97.5, 116.666666666667, 135.833333333333, 155, 174.166666666667, 193.333333333333, 212.5, 231.666666666667, 250.833333333333, 270, 270, 270, 270, 270, 270, 270, 270, 270, 270, 270, 270, 270, 270, 270, 270, 270, 270, 270, 270, 270, 270, 270, 270, 270, 270, 270, 270, 270, 270, 270, 270, 270, 270, 270, 270, 270, 270, 270, 270, 270, 270, 270, 270, 270], + 36: [40, 58.3333333333333, 76.6666666666667, 95, 113.333333333333, 131.666666666667, 150, 168.333333333333, 186.666666666667, 205, 223.333333333333, 241.666666666667, 260, 260, 260, 260, 260, 260, 260, 260, 260, 260, 260, 260, 260, 260, 260, 260, 260, 260, 260, 260, 260, 260, 260, 260, 260, 260, 260, 260, 260, 260, 260, 260, 260, 260, 260, 260, 260, 260, 260, 260, 260, 260, 260, 260, 260], + 35: [40, 57.5, 75, 92.5, 110, 127.5, 145, 162.5, 180, 197.5, 215, 232.5, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250], + 34: [40, 56.6666666666667, 73.3333333333333, 90, 106.666666666667, 123.333333333333, 140, 156.666666666667, 173.333333333333, 190, 206.666666666667, 223.333333333333, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240], + 33: [40, 55.8333333333333, 71.6666666666667, 87.5, 103.333333333333, 119.166666666667, 135, 150.833333333333, 166.666666666667, 182.5, 198.333333333333, 214.166666666667, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230], + 32: [40, 55, 70, 85, 100, 115, 130, 145, 160, 175, 190, 205, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220], + 31: [40, 54.1666666666667, 68.3333333333333, 82.5, 96.6666666666667, 110.833333333333, 125, 139.166666666667, 153.333333333333, 167.5, 181.666666666667, 195.833333333333, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210, 210], + 30: [40, 53.3333333333333, 66.6666666666667, 80, 93.3333333333333, 106.666666666667, 120, 133.333333333333, 146.666666666667, 160, 173.333333333333, 186.666666666667, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200], + 29: [40, 52.5, 65, 77.5, 90, 102.5, 115, 127.5, 140, 152.5, 165, 177.5, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190, 190], + 28: [40, 51.6666666666667, 63.3333333333333, 75, 86.6666666666667, 98.3333333333333, 110, 121.666666666667, 133.333333333333, 145, 156.666666666667, 168.333333333333, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180, 180], + 27: [40, 50.8333333333333, 61.6666666666667, 72.5, 83.3333333333333, 94.1666666666667, 105, 115.833333333333, 126.666666666667, 137.5, 148.333333333333, 159.166666666667, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170], + 26: [40, 50, 60, 70, 80, 90, 100, 110, 120, 130, 140, 150, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160, 160], + 25: [40, 49.1666666666667, 58.3333333333333, 67.5, 76.6666666666667, 85.8333333333333, 95, 104.166666666667, 113.333333333333, 122.5, 131.666666666667, 140.833333333333, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150, 150], + 24: [40, 48.3333333333333, 56.6666666666667, 65, 73.3333333333333, 81.6666666666667, 90, 98.3333333333333, 106.666666666667, 115, 123.333333333333, 131.666666666667, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140, 140], + 23: [40, 47.5, 55, 62.5, 70, 77.5, 85, 92.5, 100, 107.5, 115, 122.5, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130] + }; + + test('Phototherapy thresholds at >= 38 weeks', () => { + for (let gestation = 42; gestation >= 38; gestation--) { + for (let i = 0, d = 0; d <= 14; i += 1, d += 0.25) { + assert(nearlyEqual(phototherapy_thresh(d, gestation), expected_phototherapy[38][i], 0.5)); + } + } + }); + + for (let gestation = 37; gestation >= 23; gestation--) { + test('Phototherapy thresholds at ' + gestation + ' weeks', () => { + for (let i = 0, d = 0; d <= 14; i += 1, d += 0.25) { + assert(nearlyEqual(phototherapy_thresh(d, gestation), expected_phototherapy[gestation >= 38 ? 38 : gestation][i], 0.5)); + } + }); + } +}); + +suite('Exchange therapy thresholds vs NICE', () => { + // Compare with NICE "Data sheet" tab + const expected_exchange = { + 38: [100, 150, 200, 250, 300, 350, 400, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450], + 37: [80, 104.166666666667, 128.333333333333, 152.5, 176.666666666667, 200.833333333333, 225, 249.166666666667, 273.333333333333, 297.5, 321.666666666667, 345.833333333333, 370, 370, 370, 370, 370, 370, 370, 370, 370, 370, 370, 370, 370, 370, 370, 370, 370, 370, 370, 370, 370, 370, 370, 370, 370, 370, 370, 370, 370, 370, 370, 370, 370, 370, 370, 370, 370, 370, 370, 370, 370, 370, 370, 370, 370], + 36: [80, 103.333333333333, 126.666666666667, 150, 173.333333333333, 196.666666666667, 220, 243.333333333333, 266.666666666667, 290, 313.333333333333, 336.666666666667, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360, 360], + 35: [80, 102.5, 125, 147.5, 170, 192.5, 215, 237.5, 260, 282.5, 305, 327.5, 350, 350, 350, 350, 350, 350, 350, 350, 350, 350, 350, 350, 350, 350, 350, 350, 350, 350, 350, 350, 350, 350, 350, 350, 350, 350, 350, 350, 350, 350, 350, 350, 350, 350, 350, 350, 350, 350, 350, 350, 350, 350, 350, 350, 350], + 34: [80, 101.666666666667, 123.333333333333, 145, 166.666666666667, 188.333333333333, 210, 231.666666666667, 253.333333333333, 275, 296.666666666667, 318.333333333333, 340, 340, 340, 340, 340, 340, 340, 340, 340, 340, 340, 340, 340, 340, 340, 340, 340, 340, 340, 340, 340, 340, 340, 340, 340, 340, 340, 340, 340, 340, 340, 340, 340, 340, 340, 340, 340, 340, 340, 340, 340, 340, 340, 340, 340], + 33: [80, 100.833333333333, 121.666666666667, 142.5, 163.333333333333, 184.166666666667, 205, 225.833333333333, 246.666666666667, 267.5, 288.333333333333, 309.166666666667, 330, 330, 330, 330, 330, 330, 330, 330, 330, 330, 330, 330, 330, 330, 330, 330, 330, 330, 330, 330, 330, 330, 330, 330, 330, 330, 330, 330, 330, 330, 330, 330, 330, 330, 330, 330, 330, 330, 330, 330, 330, 330, 330, 330, 330], + 32: [80, 100, 120, 140, 160, 180, 200, 220, 240, 260, 280, 300, 320, 320, 320, 320, 320, 320, 320, 320, 320, 320, 320, 320, 320, 320, 320, 320, 320, 320, 320, 320, 320, 320, 320, 320, 320, 320, 320, 320, 320, 320, 320, 320, 320, 320, 320, 320, 320, 320, 320, 320, 320, 320, 320, 320, 320], + 31: [80, 99.1666666666667, 118.333333333333, 137.5, 156.666666666667, 175.833333333333, 195, 214.166666666667, 233.333333333333, 252.5, 271.666666666667, 290.833333333333, 310, 310, 310, 310, 310, 310, 310, 310, 310, 310, 310, 310, 310, 310, 310, 310, 310, 310, 310, 310, 310, 310, 310, 310, 310, 310, 310, 310, 310, 310, 310, 310, 310, 310, 310, 310, 310, 310, 310, 310, 310, 310, 310, 310, 310], + 30: [80, 98.3333333333333, 116.666666666667, 135, 153.333333333333, 171.666666666667, 190, 208.333333333333, 226.666666666667, 245, 263.333333333333, 281.666666666667, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300], + 29: [80, 97.5, 115, 132.5, 150, 167.5, 185, 202.5, 220, 237.5, 255, 272.5, 290, 290, 290, 290, 290, 290, 290, 290, 290, 290, 290, 290, 290, 290, 290, 290, 290, 290, 290, 290, 290, 290, 290, 290, 290, 290, 290, 290, 290, 290, 290, 290, 290, 290, 290, 290, 290, 290, 290, 290, 290, 290, 290, 290, 290], + 28: [80, 96.6666666666667, 113.333333333333, 130, 146.666666666667, 163.333333333333, 180, 196.666666666667, 213.333333333333, 230, 246.666666666667, 263.333333333333, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280], + 27: [80, 95.8333333333333, 111.666666666667, 127.5, 143.333333333333, 159.166666666667, 175, 190.833333333333, 206.666666666667, 222.5, 238.333333333333, 254.166666666667, 270, 270, 270, 270, 270, 270, 270, 270, 270, 270, 270, 270, 270, 270, 270, 270, 270, 270, 270, 270, 270, 270, 270, 270, 270, 270, 270, 270, 270, 270, 270, 270, 270, 270, 270, 270, 270, 270, 270, 270, 270, 270, 270, 270, 270], + 26: [80, 95, 110, 125, 140, 155, 170, 185, 200, 215, 230, 245, 260, 260, 260, 260, 260, 260, 260, 260, 260, 260, 260, 260, 260, 260, 260, 260, 260, 260, 260, 260, 260, 260, 260, 260, 260, 260, 260, 260, 260, 260, 260, 260, 260, 260, 260, 260, 260, 260, 260, 260, 260, 260, 260, 260, 260], + 25: [80, 94.1666666666667, 108.333333333333, 122.5, 136.666666666667, 150.833333333333, 165, 179.166666666667, 193.333333333333, 207.5, 221.666666666667, 235.833333333333, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250], + 24: [80, 93.3333333333333, 106.666666666667, 120, 133.333333333333, 146.666666666667, 160, 173.333333333333, 186.666666666667, 200, 213.333333333333, 226.666666666667, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240, 240], + 23: [80, 92.5, 105, 117.5, 130, 142.5, 155, 167.5, 180, 192.5, 205, 217.5, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230] + }; + + test('Exchange transfusion thresholds at >= 38 weeks', () => { + for (let gestation = 42; gestation >= 38; gestation--) { + for (let i = 0, d = 0; d <= 14; i += 1, d += 0.25) { + assert(nearlyEqual(exchange_thresh(d, gestation), expected_exchange[38][i], 0.5)); + } + } + }); + + for (let gestation = 37; gestation >= 23; gestation--) { + test('Exchange transfusion thresholds at ' + gestation + ' weeks', () => { + for (let i = 0, d = 0; d <= 14; i += 1, d += 0.25) { + assert(nearlyEqual(exchange_thresh(d, gestation), expected_exchange[gestation >= 38 ? 38 : gestation][i], 0.5)); + } + }); + } +});