Files
Bubberstation/code/modules/unit_tests/lungs.dm
SkyratBot 1df520a7df [MIRROR] Refactors and optimizes breath code (Saves 12% of carbon/Life()) [MDB IGNORE] (#20080)
* Refactors and optimizes breath code (Saves 12% of carbon/Life())

* Update lungs.dm

---------

Co-authored-by: LemonInTheDark <58055496+LemonInTheDark@users.noreply.github.com>
Co-authored-by: Gandalf <9026500+Gandalf2k15@users.noreply.github.com>
2023-03-30 21:59:20 -07:00

203 lines
12 KiB
Plaintext

#define TEST_CHECK_BREATH_MESSAGE(lungs_organ, message) "[lungs_organ.type]/check_breath() [message]"
#define TEST_ALERT_THROW_MESSAGE(lungs_organ, alert_name) TEST_CHECK_BREATH_MESSAGE(lungs_organ, "failed to throw alert [alert_name] when expected.")
#define TEST_ALERT_INHIBIT_MESSAGE(lungs_organ, alert_name) TEST_CHECK_BREATH_MESSAGE(lungs_organ, "threw alert [alert_name] when it wasn't expected.")
#define GET_MOLES(gas_mixture, gas_type) (gas_mixture.gases[gas_type] ? gas_mixture.gases[gas_type][MOLES] : 0)
/// Tests the standard, plasmaman, and lavaland lungs organ to ensure breathing and suffocation behave as expected.
/// Performs a check on each main (can be life-sustaining) gas, and ensures gas alerts are only thrown when expected.
/datum/unit_test/lungs
abstract_type = /datum/unit_test/lungs
/datum/unit_test/lungs/lungs_sanity/Run()
// "Standard" form of breathing.
// 2500 Litres of O2/N2 gas mix, ideal for life.
var/datum/gas_mixture/test_mix = create_standard_mix()
var/mob/living/carbon/human/lab_rat = allocate(/mob/living/carbon/human/consistent)
var/obj/item/organ/internal/lungs/test_lungs = allocate(/obj/item/organ/internal/lungs)
// Test one breath of O2/N2 mix.
lungs_test_check_breath("standard gas mixture", lab_rat, test_lungs, test_mix)
// Suffocation with an empty gas mix.
var/datum/gas_mixture/empty_test_mix = allocate(/datum/gas_mixture)
lab_rat = allocate(/mob/living/carbon/human/consistent)
test_lungs = allocate(/obj/item/organ/internal/lungs)
// Test one breath of nothing. Suffocate due to the breath being empty.
lungs_test_check_breath("empty gas mixture", lab_rat, test_lungs, empty_test_mix, expect_failure = TRUE)
// Suffocation with null. This does indeed happen normally.
lab_rat = allocate(/mob/living/carbon/human/consistent)
test_lungs = allocate(/obj/item/organ/internal/lungs)
// Test one breath of nothing. Suffocate due to the breath being null.
lungs_test_check_breath("null", lab_rat, test_lungs, null, expect_failure = TRUE)
// Suffocation with Nitrogen.
var/datum/gas_mixture/nitro_test_mix = create_nitrogen_mix()
lab_rat = allocate(/mob/living/carbon/human/consistent)
test_lungs = allocate(/obj/item/organ/internal/lungs)
// Test one breath of Nitrogen. Suffocate due to the breath being 100% N2.
lungs_test_check_breath("pure Nitrogen", lab_rat, test_lungs, nitro_test_mix, expect_failure = TRUE)
/// Tests the Plasmaman lungs organ to ensure Plasma breathing and suffocation behave as expected.
/datum/unit_test/lungs/lungs_sanity_plasmaman
/datum/unit_test/lungs/lungs_sanity_plasmaman/Run()
// 2500 Litres of pure Plasma.
var/datum/gas_mixture/plasma_test_mix = create_plasma_mix()
var/mob/living/carbon/human/lab_rat = allocate(/mob/living/carbon/human/consistent)
var/obj/item/organ/internal/lungs/plasmaman/test_lungs = allocate(/obj/item/organ/internal/lungs/plasmaman)
// Test one breath of Plasma on Plasmaman lungs.
lungs_test_check_breath("pure Plasma", lab_rat, test_lungs, plasma_test_mix)
// Tests suffocation with Nitrogen.
var/datum/gas_mixture/nitro_test_mix = create_nitrogen_mix()
lab_rat = allocate(/mob/living/carbon/human/consistent)
test_lungs = allocate(/obj/item/organ/internal/lungs/plasmaman)
// Test one breath of Nitrogen on Plasmaman lungs.
lungs_test_check_breath("pure Nitrogen", lab_rat, test_lungs, nitro_test_mix, expect_failure = TRUE)
/// Tests the lavaland/Ashwalker lungs organ.
/// Ensures they can breathe from the lavaland air mixture properly, and suffocate on inadequate mixture.
/datum/unit_test/lungs/lungs_sanity_ashwalker
/datum/unit_test/lungs/lungs_sanity_ashwalker/Run()
// Gas mix resembling one cell of lavaland's atmosphere.
var/datum/gas_mixture/lavaland_test_mix = create_lavaland_mix()
var/obj/item/organ/internal/lungs/lavaland/test_lungs = allocate(/obj/item/organ/internal/lungs/lavaland)
var/mob/living/carbon/human/lab_rat = allocate(/mob/living/carbon/human/consistent)
// Test one breath of Lavaland gas mix on Ashwalker lungs.
lungs_test_check_breath("Lavaland air mixture", lab_rat, test_lungs, lavaland_test_mix)
/// Comprehensive unit test for [/obj/item/organ/internal/lungs/proc/check_breath()]
/// If "expect_failure" is set to TRUE, the test ensures the given Human suffocated.
/// A "test_name" string is required to contextualize test logs. Describe the gas you're testing.
/datum/unit_test/lungs/proc/lungs_test_check_breath(test_name, mob/living/carbon/human/lab_rat, obj/item/organ/internal/lungs/test_lungs, datum/gas_mixture/test_mix, expect_failure = FALSE)
// Setup a small volume of gas which represents one "breath" from test_mix.
var/datum/gas_mixture/test_breath
if(!isnull(test_mix))
var/total_moles = test_mix.total_moles()
if(total_moles > 0)
test_breath = test_mix.remove(total_moles * BREATH_PERCENTAGE)
if(isnull(test_breath))
test_breath = allocate(/datum/gas_mixture, BREATH_VOLUME)
// Backup of the breath mixture, to compare against after testing check_breath().
var/datum/gas_mixture/test_breath_backup = test_breath.copy()
// Get partial pressures for each "main" gas.
var/oxygen_pp = 0
var/nitro_pp = 0
var/co2_pp = 0
var/plasma_pp = 0
if(test_breath.total_moles() > 0)
oxygen_pp = test_breath.get_breath_partial_pressure(GET_MOLES(test_breath, /datum/gas/oxygen))
nitro_pp = test_breath.get_breath_partial_pressure(GET_MOLES(test_breath, /datum/gas/nitrogen))
co2_pp = test_breath.get_breath_partial_pressure(GET_MOLES(test_breath, /datum/gas/carbon_dioxide))
plasma_pp = test_breath.get_breath_partial_pressure(GET_MOLES(test_breath, /datum/gas/plasma))
// Minimum and maximum gas tolerances for the 4 main life-sustaining gases.
var/min_oxygen = test_lungs.safe_oxygen_min
var/min_nitro = test_lungs.safe_nitro_min
var/min_plasma = test_lungs.safe_plasma_min
var/max_oxygen = test_lungs.safe_oxygen_max
var/max_co2 = test_lungs.safe_co2_max
var/max_plasma = test_lungs.safe_plasma_max
// Test a single "breath" of air.
var/status_code = test_lungs.check_breath(test_breath, lab_rat)
// Ensures failed_last_breath is set as we expect, and that check_breath returns a corollary status code.
if(expect_failure)
TEST_ASSERT(!status_code, TEST_CHECK_BREATH_MESSAGE(test_lungs, "returned truthy / status code 1 (success) when it wasn't expected."))
TEST_ASSERT(lab_rat.failed_last_breath, TEST_CHECK_BREATH_MESSAGE(test_lungs, "should suffocate from [test_name]."))
else
TEST_ASSERT(status_code, TEST_CHECK_BREATH_MESSAGE(test_lungs, "returned falsy / status code 0 (failure) when it wasn't expected."))
TEST_ASSERT(!lab_rat.failed_last_breath, TEST_CHECK_BREATH_MESSAGE(test_lungs, "can't get a full breath from [test_name]."))
// Checks each "main" gas to ensure gas alerts are thrown/inhibited when expected.
lungs_test_alert_min(lab_rat, test_lungs, ALERT_NOT_ENOUGH_OXYGEN, min_oxygen, oxygen_pp)
lungs_test_alert_max(lab_rat, test_lungs, ALERT_TOO_MUCH_OXYGEN, max_oxygen, oxygen_pp)
lungs_test_alert_min(lab_rat, test_lungs, ALERT_NOT_ENOUGH_NITRO, min_nitro, nitro_pp)
lungs_test_alert_max(lab_rat, test_lungs, ALERT_TOO_MUCH_CO2, max_co2, co2_pp)
lungs_test_alert_min(lab_rat, test_lungs, ALERT_NOT_ENOUGH_PLASMA, min_plasma, plasma_pp)
lungs_test_alert_max(lab_rat, test_lungs, ALERT_TOO_MUCH_PLASMA, max_plasma, plasma_pp)
// Track the volumes of O2 and CO2 which are expected to be exhaled.
var/expected_oxygen = GET_MOLES(test_breath_backup, /datum/gas/oxygen)
var/expected_nitro = GET_MOLES(test_breath_backup, /datum/gas/nitrogen)
var/expected_co2 = GET_MOLES(test_breath_backup, /datum/gas/carbon_dioxide)
var/expected_plasma = GET_MOLES(test_breath_backup, /datum/gas/plasma)
// Setup expectations for main gas exchange tests.
if(min_oxygen)
expected_co2 += expected_oxygen
expected_oxygen = 0
if(min_nitro)
expected_co2 += GET_MOLES(test_breath_backup, /datum/gas/nitrogen)
expected_nitro = 0
if(min_plasma)
expected_co2 += GET_MOLES(test_breath_backup, /datum/gas/plasma)
expected_plasma = 0
// Validate conversion of inhaled gas to exhaled gas.
if(min_oxygen)
TEST_ASSERT(molar_cmp_equals(GET_MOLES(test_breath, /datum/gas/oxygen), expected_oxygen), TEST_CHECK_BREATH_MESSAGE(test_lungs, "should consume all Oxygen initially present in the breath."))
TEST_ASSERT(molar_cmp_equals(GET_MOLES(test_breath, /datum/gas/carbon_dioxide), expected_co2), TEST_CHECK_BREATH_MESSAGE(test_lungs, "should convert Oxygen into an equivalent volume of CO2."))
if(min_nitro)
TEST_ASSERT(molar_cmp_equals(GET_MOLES(test_breath, /datum/gas/nitrogen), expected_nitro), TEST_CHECK_BREATH_MESSAGE(test_lungs, "should consume all Nitrogen initially present in the breath."))
TEST_ASSERT(molar_cmp_equals(GET_MOLES(test_breath, /datum/gas/carbon_dioxide), expected_co2), TEST_CHECK_BREATH_MESSAGE(test_lungs, "should convert Nitrogen into an equivalent volume of CO2."))
if(min_plasma)
TEST_ASSERT(molar_cmp_equals(GET_MOLES(test_breath, /datum/gas/plasma), expected_plasma), TEST_CHECK_BREATH_MESSAGE(test_lungs, "should consume all Plasma initially present in the breath."))
TEST_ASSERT(molar_cmp_equals(GET_MOLES(test_breath, /datum/gas/carbon_dioxide), expected_co2), TEST_CHECK_BREATH_MESSAGE(test_lungs, "should convert Plasma into an equivalent volume of CO2."))
/// Tests minimum gas alerts by comparing gas pressure.
/datum/unit_test/lungs/proc/lungs_test_alert_min(mob/living/carbon/human/lab_rat, obj/item/organ/internal/lungs/test_lungs, alert_name, min_pressure, pressure)
var/alert_thrown = lab_rat.has_alert(alert_name)
var/pressure_safe = (pressure >= min_pressure) || (min_pressure == 0)
TEST_ASSERT(!pressure_safe && alert_thrown || pressure_safe, TEST_ALERT_THROW_MESSAGE(test_lungs, alert_name))
TEST_ASSERT(pressure_safe && !alert_thrown || !pressure_safe, TEST_ALERT_INHIBIT_MESSAGE(test_lungs, alert_name))
/// Tests maximum gas alerts by comparing gas pressure.
/datum/unit_test/lungs/proc/lungs_test_alert_max(mob/living/carbon/human/lab_rat, obj/item/organ/internal/lungs/test_lungs, alert_name, max_pressure, pressure)
var/alert_thrown = lab_rat.has_alert(alert_name)
var/pressure_safe = (pressure <= max_pressure) || (max_pressure == 0)
TEST_ASSERT(!pressure_safe && alert_thrown || pressure_safe, TEST_ALERT_THROW_MESSAGE(test_lungs, alert_name))
TEST_ASSERT(pressure_safe && !alert_thrown || !pressure_safe, TEST_ALERT_INHIBIT_MESSAGE(test_lungs, alert_name))
/// Set up a 2500-Litre gas mixture with the given gases and percentages.
/datum/unit_test/lungs/proc/create_gas_mix(list/gas_to_percent)
var/datum/gas_mixture/test_mix = allocate(/datum/gas_mixture, 2500)
test_mix.temperature = T20C
for(var/datum/gas/gas_type as anything in gas_to_percent)
test_mix.add_gas(gas_type)
test_mix.gases[gas_type][MOLES] = (ONE_ATMOSPHERE * 2500 / (R_IDEAL_GAS_EQUATION * T20C) * gas_to_percent[gas_type])
return test_mix
/// Set up an O2/N2 gas mix which is "ideal" for organic life.
/datum/unit_test/lungs/proc/create_standard_mix()
return create_gas_mix(list(/datum/gas/oxygen = O2STANDARD, /datum/gas/nitrogen = N2STANDARD))
/// Set up a pure Nitrogen gas mix.
/datum/unit_test/lungs/proc/create_nitrogen_mix()
return create_gas_mix(list(/datum/gas/nitrogen = 1))
/// Set up an O2/N2 gas mix which is "ideal" for plasmamen.
/datum/unit_test/lungs/proc/create_plasma_mix()
return create_gas_mix(list(/datum/gas/plasma = 1))
/// Set up an Lavaland gas mix which is "ideal" for Ashwalker life.
/datum/unit_test/lungs/proc/create_lavaland_mix()
var/datum/gas_mixture/immutable/planetary/lavaland_mix = SSair.planetary[LAVALAND_DEFAULT_ATMOS]
var/datum/gas_mixture/test_mix = allocate(/datum/gas_mixture, 2500)
test_mix.copy_from(lavaland_mix)
return test_mix
#undef TEST_CHECK_BREATH_MESSAGE
#undef TEST_ALERT_THROW_MESSAGE
#undef TEST_ALERT_INHIBIT_MESSAGE
#undef GET_MOLES