mirror of
https://github.com/VOREStation/VOREStation.git
synced 2026-07-19 19:15:11 +01:00
Unit Test rework & Master/Ticker update (#17912)
* Unit Test rework & Master/Ticker update * Fixes and working unit testing * Fixes * Test fixes and FA update * Fixed runtimes * Radio subsystem * move that glob wherever later * ident * CIBUILDING compile option * Fixed runtimes * Some changes to the workflow * CI Split * More split * Pathing * Linters and Annotators * ci dir fix * Missing undef fixed * Enable grep checks * More test conversions * More split * Correct file * Removes unneeded inputs * oop * More dependency changes * More conversions * Conversion fixes * Fixes * Some assert fixes * Corrects start gate * Converted some README.dms to README.mds * Removes duplicate proc * Removes unused defines * Example configs * fix dll access viol by double calling * Post-rebase fixes * Cleans up names global list * Undef restart counter * More code/game/ cleanup * Statpanel update * Skybox * add * Fix ticker * Roundend fix * Persistence dependency update * Reordering * Reordering * Reordering * Initstage fix * . * . * Reorder * Reorder * Circle * Mobs * Air * Test fix * CI Script Fix * Configs * More ticker stuff * This is now in 'reboot world' * Restart world announcements * no glob in PreInit * to define * Update * Removed old include * Make this file normal again * moved * test * shared unit testing objects * Updates batched_spritesheets and universal_icon * . * job data debug * rm that * init order * show us * . * i wonder * . * . * urg * do we not have a job ID? * . * rm sleep for now * updated rust-g linux binaries * binaries update 2 * binaries update 3 * testing something * change that * test something * . * . * . * locavar * test * move that * . * debug * don't run this test * strack trace it * cleaner * . * . * cras again * also comment this out * return to official rust g * Update robot_icons.dm * monitor the generation * . --------- Co-authored-by: Kashargul <144968721+Kashargul@users.noreply.github.com>
This commit is contained in:
@@ -1,177 +0,0 @@
|
||||
/datum/unit_test/all_clothing_shall_be_valid
|
||||
name = "CLOTHING: All clothing shall be valid"
|
||||
var/signal_failed = FALSE
|
||||
|
||||
/datum/unit_test/all_clothing_shall_be_valid/start_test()
|
||||
var/failed = 0
|
||||
var/obj/storage = new()
|
||||
|
||||
var/list/scan = subtypesof(/obj/item/clothing)
|
||||
scan -= typesof(/obj/item/clothing/head/hood) // These are part of clothing, need to be tested uniquely
|
||||
// Remove material armors, as dev_warning cannot be used to set their name
|
||||
scan -= /obj/item/clothing/suit/armor/material
|
||||
scan -= /obj/item/clothing/head/helmet/material
|
||||
scan -= /obj/item/clothing/ears/offear // This is used for equip logic, not ingame
|
||||
scan -= /obj/item/clothing/mask/ai // Breaks unit test entirely TODO
|
||||
|
||||
var/i = 0
|
||||
var/tenths = 1
|
||||
var/a_tenth = scan.len / 10
|
||||
for(var/path as anything in scan)
|
||||
var/obj/item/clothing/C = new path(storage)
|
||||
failed += test_clothing(C)
|
||||
|
||||
if(i > tenths * a_tenth)
|
||||
log_unit_test("Clothing - Progress [tenths * 10]% - [i]/[scan.len]")
|
||||
log_unit_test("---------------------------------------------------")
|
||||
tenths++
|
||||
|
||||
if(istype(C,/obj/item/clothing/suit/storage/hooded))
|
||||
var/obj/item/clothing/suit/storage/hooded/H = C
|
||||
if(H.hood) // Testing hoods when they init
|
||||
failed += test_clothing(H.hood,storage)
|
||||
|
||||
i++
|
||||
qdel(C)
|
||||
qdel(storage)
|
||||
|
||||
if(failed)
|
||||
fail("One or more /obj/item/clothing items had invalid flags or icons")
|
||||
else
|
||||
pass("All /obj/item/clothing are valid.")
|
||||
return 1
|
||||
|
||||
/datum/unit_test/all_clothing_shall_be_valid/proc/test_clothing(var/obj/item/clothing/C,var/obj/storage)
|
||||
var/failed = FALSE
|
||||
|
||||
// Do not test base-types
|
||||
if(C.name == DEVELOPER_WARNING_NAME)
|
||||
return FALSE
|
||||
|
||||
// ID
|
||||
if(!C.name)
|
||||
log_unit_test("[C.type]: Clothing - Missing name.")
|
||||
failed = TRUE
|
||||
|
||||
if(C.name == "")
|
||||
log_unit_test("[C.type]: Clothing - Empty name.")
|
||||
failed = TRUE
|
||||
|
||||
// Icons
|
||||
if(!("[C.icon_state]" in cached_icon_states(C.icon)))
|
||||
if(C.icon == initial(C.icon) && C.icon_state == initial(C.icon_state))
|
||||
log_unit_test("[C.type]: Clothing - Icon_state \"[C.icon_state]\" is not present in [C.icon].")
|
||||
else
|
||||
log_unit_test("[C.type]: Clothing - Icon_state \"[C.icon_state]\" is not present in [C.icon]. This icon/state was changed by init. Initial icon \"[initial(C.icon)]\". initial icon_state \"[initial(C.icon_state)]\". Check code.")
|
||||
failed = TRUE
|
||||
|
||||
// Disabled, as currently not working in a presentable way, spams the CI hard, do not enable unless fixed
|
||||
#ifdef UNIT_TEST
|
||||
// Time for the most brutal part. Dressing up some mobs with set species, and checking they have art
|
||||
// An entire signal just for unittests had to be made for this!
|
||||
var/list/body_types = list(SPECIES_HUMAN,SPECIES_VOX,SPECIES_TESHARI) // Otherwise we would be here for centuries
|
||||
// **************************************************************************************************************************
|
||||
body_types = list() // DISABLED FOR NOW, No single person can resolve how many sprites are missing.
|
||||
// **************************************************************************************************************************
|
||||
if(body_types.len)
|
||||
if(C.species_restricted && C.species_restricted.len)
|
||||
if(C.species_restricted[1] == "exclude")
|
||||
for(var/B in body_types)
|
||||
if(B in C.species_restricted)
|
||||
body_types -= B
|
||||
else
|
||||
var/list/new_list = list()
|
||||
for(var/B in body_types)
|
||||
if(B in C.species_restricted)
|
||||
new_list += B
|
||||
body_types = new_list
|
||||
// Get actual species that can use this, based on the mess of restricted/excluded logic above
|
||||
var/obj/mob_storage = new()
|
||||
var/mob/living/carbon/human/H = new(mob_storage)
|
||||
RegisterSignal(H, COMSIG_UNITTEST_DATA, PROC_REF(get_signal_data))
|
||||
for(var/B in body_types)
|
||||
H.set_species(B)
|
||||
// spawn the mob, signalize it, and then give it the item to see what it gets.
|
||||
H.put_in_active_hand(C)
|
||||
H.equip_to_appropriate_slot(C)
|
||||
H.drop_from_inventory(C, storage)
|
||||
UnregisterSignal(H, COMSIG_UNITTEST_DATA)
|
||||
qdel(H)
|
||||
qdel(mob_storage)
|
||||
// We failed the mob check
|
||||
if(signal_failed)
|
||||
failed = TRUE
|
||||
#endif
|
||||
|
||||
// Temps
|
||||
if(C.min_cold_protection_temperature < 0)
|
||||
log_unit_test("[C.type]: Clothing - Cold protection was lower than 0.")
|
||||
failed = TRUE
|
||||
|
||||
if(C.max_heat_protection_temperature && C.min_cold_protection_temperature && C.max_heat_protection_temperature < C.min_cold_protection_temperature)
|
||||
log_unit_test("[C.type]: Clothing - Maximum heat protection was greater than minimum cold protection.")
|
||||
failed = TRUE
|
||||
|
||||
//var/valid_range = HEAD|UPPER_TORSO|LOWER_TORSO|LEGS|FEET|ARMS|HANDS
|
||||
if(C.cold_protection)
|
||||
if(islist(C.cold_protection))
|
||||
log_unit_test("[C.type]: Clothing - cold_protection was defined as a list, when it is a bitflag.")
|
||||
failed = TRUE
|
||||
else if(!isnum(C.cold_protection))
|
||||
log_unit_test("[C.type]: Clothing - cold_protection was defined as something other than a number, when it is a bitflag.")
|
||||
failed = TRUE
|
||||
else
|
||||
if(C.cold_protection && C.cold_protection != FULL_BODY)
|
||||
// Check flags that should be unused
|
||||
if(C.cold_protection & FACE)
|
||||
log_unit_test("[C.type]: Clothing - cold_protection uses FACE bitflag, this provides no protection, use HEAD.")
|
||||
failed = TRUE
|
||||
if(C.cold_protection & EYES)
|
||||
log_unit_test("[C.type]: Clothing - cold_protection uses EYES bitflag, this provides no protection, use HEAD.")
|
||||
failed = TRUE
|
||||
|
||||
if(C.heat_protection)
|
||||
if(islist(C.heat_protection))
|
||||
log_unit_test("[C.type]: Clothing - heat_protection was defined as a list, when it is a bitflag.")
|
||||
failed = TRUE
|
||||
else if(!isnum(C.heat_protection))
|
||||
log_unit_test("[C.type]: Clothing - heat_protection was defined as something other than a number, when it is a bitflag.")
|
||||
failed = TRUE
|
||||
else
|
||||
if(C.heat_protection && C.heat_protection != FULL_BODY)
|
||||
// Check flags that should be unused
|
||||
if(C.heat_protection & FACE)
|
||||
log_unit_test("[C.type]: Clothing - heat_protection uses FACE bitflag, this provides no protection, use HEAD.")
|
||||
failed = TRUE
|
||||
if(C.heat_protection & EYES)
|
||||
log_unit_test("[C.type]: Clothing - heat_protection uses EYES bitflag, this provides no protection, use HEAD.")
|
||||
failed = TRUE
|
||||
return failed
|
||||
|
||||
/datum/unit_test/all_clothing_shall_be_valid/get_signal_data(atom/source, list/data = list())
|
||||
switch(data[1])
|
||||
if("set_slot")
|
||||
var/slot_name = data[2]
|
||||
var/set_icon = data[3]
|
||||
var/set_state = data[4]
|
||||
//var/in_hands = data[5]
|
||||
var/item_path = data[6]
|
||||
var/species = data[7]
|
||||
if(!species)
|
||||
return
|
||||
if(!set_icon)
|
||||
return
|
||||
if(!set_state)
|
||||
return
|
||||
|
||||
// Ignore storage
|
||||
if(slot_name == slot_l_hand_str)
|
||||
return
|
||||
if(slot_name == slot_r_hand_str)
|
||||
return
|
||||
|
||||
// All that matters
|
||||
if(!("[set_state]" in cached_icon_states(set_icon)))
|
||||
log_unit_test("[item_path]: Clothing - Testing \"[species]\" state \"[set_state]\" for slot \"[slot_name]\", but it was not in dmi \"[set_icon]\"")
|
||||
signal_failed = TRUE
|
||||
return
|
||||
@@ -1,91 +0,0 @@
|
||||
/datum/unit_test/sprite_accessories_shall_be_unique
|
||||
name = "COSMETICS: Entries shall have unique name."
|
||||
|
||||
/datum/unit_test/sprite_accessories_shall_be_unique/start_test()
|
||||
var/failed = 0
|
||||
|
||||
failed += validate_accessory_list( /datum/sprite_accessory/ears)
|
||||
failed += validate_accessory_list( /datum/sprite_accessory/facial_hair)
|
||||
failed += validate_accessory_list( /datum/sprite_accessory/hair)
|
||||
failed += validate_accessory_list( /datum/sprite_accessory/hair_accessory)
|
||||
failed += validate_accessory_list( /datum/sprite_accessory/marking)
|
||||
failed += validate_accessory_list( /datum/sprite_accessory/tail)
|
||||
failed += validate_accessory_list( /datum/sprite_accessory/wing)
|
||||
|
||||
if(failed)
|
||||
fail("One or more /datum/sprite_accessory definitions had invalid names, icon_states, or names were reused definitions")
|
||||
else
|
||||
pass("All /datum/sprite_accessory definitions had correct settings.")
|
||||
return 1
|
||||
|
||||
/datum/unit_test/sprite_accessories_shall_be_unique/proc/validate_accessory_list(var/path)
|
||||
var/failed = 0
|
||||
var/total_good = 0
|
||||
var/total_all = 0
|
||||
|
||||
var/list/collection = list()
|
||||
for(var/SP in subtypesof(path))
|
||||
total_all++
|
||||
var/datum/sprite_accessory/A = new SP()
|
||||
if(!A)
|
||||
log_unit_test("[SP]: Cosmetic - Path resolved to null in list.")
|
||||
continue
|
||||
|
||||
if(!A.name)
|
||||
log_unit_test("[A] - [A.type]: Cosmetic - Missing name.")
|
||||
failed = 1
|
||||
|
||||
if(A.name == DEVELOPER_WARNING_NAME)
|
||||
continue
|
||||
|
||||
if(collection[A.name])
|
||||
log_unit_test("[A] - [A.type]: Cosmetic - Name defined twice. Original def [collection[A.name]]")
|
||||
failed = 1
|
||||
else
|
||||
collection[A.name] = A.type
|
||||
|
||||
if(istype(A,text2path("[path]/invisible")))
|
||||
if(A.icon_state)
|
||||
log_unit_test("[A] - [A.type]: Cosmetic - Invisible subtype has icon_state.")
|
||||
failed = 1
|
||||
else if(!A.icon_state)
|
||||
log_unit_test("[A] - [A.type]: Cosmetic - Has no icon_state.")
|
||||
failed = 1
|
||||
else
|
||||
// Check if valid icon
|
||||
failed += validate_icons(A)
|
||||
|
||||
total_good++
|
||||
qdel(A)
|
||||
|
||||
log_unit_test("[path]: Cosmetic - Total valid count: [total_good]/[total_all].")
|
||||
return failed
|
||||
|
||||
/datum/unit_test/sprite_accessories_shall_be_unique/proc/validate_icons(var/datum/sprite_accessory/A)
|
||||
var/failed = 0
|
||||
var/actual_icon_state = A.icon_state
|
||||
if(istype(A,/datum/sprite_accessory/hair))
|
||||
actual_icon_state = "[A.icon_state]_s"
|
||||
if(!(actual_icon_state in cached_icon_states(A.icon)))
|
||||
log_unit_test("[A] - [A.type]: Cosmetic - Icon_state \"[actual_icon_state]\" is not present in [A.icon].")
|
||||
failed = 1
|
||||
|
||||
if(istype(A,/datum/sprite_accessory/facial_hair))
|
||||
actual_icon_state = "[A.icon_state]_s"
|
||||
if(!(actual_icon_state in cached_icon_states(A.icon)))
|
||||
log_unit_test("[A] - [A.type]: Cosmetic - Icon_state \"[actual_icon_state]\" is not present in [A.icon].")
|
||||
failed = 1
|
||||
|
||||
if(istype(A,/datum/sprite_accessory/marking))
|
||||
var/datum/sprite_accessory/marking/MA = A
|
||||
for(var/BP in MA.body_parts)
|
||||
if(!(BP in BP_ALL))
|
||||
log_unit_test("[A] - [A.type]: Cosmetic - Has an illegal bodypart \"[BP]\". ONLY use parts listed in BP_ALL.")
|
||||
failed = 1
|
||||
|
||||
actual_icon_state = "[A.icon_state]-[BP]"
|
||||
if(!(actual_icon_state in cached_icon_states(A.icon)))
|
||||
log_unit_test("[A] - [A.type]: Cosmetic - Icon_state \"[actual_icon_state]\" is not present in [A.icon].")
|
||||
failed = 1
|
||||
|
||||
return failed
|
||||
@@ -1,26 +0,0 @@
|
||||
/datum/unit_test/emotes_shall_have_unique_keys
|
||||
name = "DECLS: Emotes Shall Have Unique Keys"
|
||||
|
||||
/datum/unit_test/emotes_shall_have_unique_keys/start_test()
|
||||
|
||||
var/list/keys = list()
|
||||
var/list/duplicates = list()
|
||||
|
||||
var/list/all_emotes = decls_repository.get_decls_of_subtype(/decl/emote)
|
||||
for(var/etype in all_emotes)
|
||||
var/decl/emote/emote = all_emotes[etype]
|
||||
if(!emote.key)
|
||||
continue
|
||||
if(emote.key in keys)
|
||||
if(!duplicates[emote.key])
|
||||
duplicates[emote.key] = list()
|
||||
duplicates[emote.key] += etype
|
||||
else
|
||||
keys += emote.key
|
||||
|
||||
if(length(duplicates))
|
||||
fail("[length(duplicates)] emote\s had overlapping keys: [english_list(duplicates)].")
|
||||
else
|
||||
pass("All emotes had unique keys.")
|
||||
|
||||
return TRUE
|
||||
@@ -1,32 +0,0 @@
|
||||
/datum/unit_test/disease_must_be_valid
|
||||
name = "DISEASE: All diseases must have valid data"
|
||||
|
||||
/datum/unit_test/disease_must_be_valid/start_test()
|
||||
var/failed = FALSE
|
||||
var/list/used_ids = list()
|
||||
|
||||
var/count = 0
|
||||
for(var/datum/disease/D as anything in subtypesof(/datum/disease))
|
||||
if(initial(D.name) == DEVELOPER_WARNING_NAME)
|
||||
continue
|
||||
|
||||
count++
|
||||
if(initial(D.medical_name) in used_ids)
|
||||
log_unit_test("[D]: Disease - Had a reused medical name, this is used as an ID and must be unique.")
|
||||
failed = TRUE
|
||||
else
|
||||
used_ids.Add(initial(D.medical_name))
|
||||
|
||||
if(!initial(D.name) || initial(D.name) == "")
|
||||
log_unit_test("[D]: Disease - Lacks a name.")
|
||||
failed = TRUE
|
||||
|
||||
if(!initial(D.desc) || initial(D.desc) == "")
|
||||
log_unit_test("[D]: Disease - Lacks a description.")
|
||||
failed = TRUE
|
||||
|
||||
if(failed)
|
||||
fail("All diseases must have valid data.")
|
||||
else
|
||||
pass("All [count] diseases have proper data.")
|
||||
return failed
|
||||
@@ -1,160 +0,0 @@
|
||||
/datum/unit_test/enough_free_gene_slots_must_be_available
|
||||
name = "GENETICS: Enough free gene slots must be available."
|
||||
|
||||
/datum/unit_test/enough_free_gene_slots_must_be_available/start_test()
|
||||
var/failed = FALSE
|
||||
|
||||
if(GLOB.dna_genes.len > (DNA_SE_LENGTH - 10)) // Based off of traitgenes scanned on startup
|
||||
failed = TRUE
|
||||
|
||||
if(failed)
|
||||
fail("Too few geneslots are empty, minimum 10. Increase DNA_SE_LENGTH.")
|
||||
else
|
||||
pass("DNA_SE_LENGTH has enough free space remaining.")
|
||||
return failed
|
||||
|
||||
|
||||
/datum/unit_test/enough_positive_genes_must_exist
|
||||
name = "GENETICS: Must be at least one positive gene."
|
||||
|
||||
/datum/unit_test/enough_positive_genes_must_exist/start_test()
|
||||
var/failed = FALSE
|
||||
|
||||
if(GLOB.dna_genes_good.len < 1) // Based off of traitgenes scanned on startup
|
||||
failed = TRUE
|
||||
|
||||
if(failed)
|
||||
fail("Must have at least one positive gene.")
|
||||
else
|
||||
pass("Has at least one positive gene.")
|
||||
return failed
|
||||
|
||||
|
||||
/datum/unit_test/enough_neutral_genes_must_exist
|
||||
name = "GENETICS: Must be at least one neutral gene."
|
||||
|
||||
/datum/unit_test/enough_neutral_genes_must_exist/start_test()
|
||||
var/failed = FALSE
|
||||
|
||||
if(GLOB.dna_genes_neutral.len < 1) // Based off of traitgenes scanned on startup
|
||||
failed = TRUE
|
||||
|
||||
if(failed)
|
||||
fail("Must have at least one neutral gene.")
|
||||
else
|
||||
pass("Has at least one neutral gene.")
|
||||
return failed
|
||||
|
||||
|
||||
/datum/unit_test/enough_bad_genes_must_exist
|
||||
name = "GENETICS: Must be at least one bad gene."
|
||||
|
||||
/datum/unit_test/enough_bad_genes_must_exist/start_test()
|
||||
var/failed = FALSE
|
||||
|
||||
if(GLOB.dna_genes_bad.len < 1) // Based off of traitgenes scanned on startup
|
||||
failed = TRUE
|
||||
|
||||
if(failed)
|
||||
fail("Must have at least one bad gene.")
|
||||
else
|
||||
pass("Has at least one bad gene.")
|
||||
return failed
|
||||
|
||||
|
||||
/datum/unit_test/all_dna_injectors_must_be_valid
|
||||
name = "GENETICS: All dna injectors must be valid."
|
||||
|
||||
/datum/unit_test/all_dna_injectors_must_be_valid/start_test()
|
||||
var/failed = FALSE
|
||||
|
||||
for(var/injector_path in subtypesof(/obj/item/dnainjector/set_trait))
|
||||
var/obj/item/dnainjector/D = new injector_path()
|
||||
if(!D.block)
|
||||
log_unit_test("[injector_path]: Genetics - Injector could not resolve geneblock for trait. Missing traitgene?")
|
||||
failed = TRUE
|
||||
qdel(D)
|
||||
|
||||
if(failed)
|
||||
fail("Dna injectors have traits that are not genetraits or are missing.")
|
||||
else
|
||||
pass("No invalid dna injectors.")
|
||||
return failed
|
||||
|
||||
|
||||
/datum/unit_test/all_genes_shall_have_unique_name
|
||||
name = "GENETICS: All genes shall be init with unique names."
|
||||
|
||||
/datum/unit_test/all_genes_shall_have_unique_name/start_test()
|
||||
var/failed = FALSE
|
||||
|
||||
var/collection = list()
|
||||
for(var/datum/gene/G in GLOB.dna_genes)
|
||||
if(collection[G.name])
|
||||
log_unit_test("[G.name]: Genetics - Gene name was already in use.")
|
||||
failed = TRUE
|
||||
else
|
||||
collection[G.name] = G.name
|
||||
|
||||
if(failed)
|
||||
fail("Genes shared names. This should not be possible on init, all genes should have their blocknumber attached to them to ensure unique names.")
|
||||
else
|
||||
pass("All genes have unique names to use as list ids.")
|
||||
return failed
|
||||
|
||||
|
||||
|
||||
/datum/unit_test/genetraits_should_have_valid_dna_bounds
|
||||
name = "GENETICS: All genes should have valid activation bounds."
|
||||
|
||||
/datum/unit_test/genetraits_should_have_valid_dna_bounds/start_test()
|
||||
var/failed = FALSE
|
||||
|
||||
for(var/datum/gene/trait/G in GLOB.trait_to_dna_genes)
|
||||
if(!G.linked_trait)
|
||||
log_unit_test("[G.name]: Genetics - Has missing linked trait.")
|
||||
failed = TRUE
|
||||
continue
|
||||
|
||||
if(!G.linked_trait.activity_bounds)
|
||||
log_unit_test("[G.name]: Genetics - Has no activation bounds.")
|
||||
failed = TRUE
|
||||
continue
|
||||
|
||||
if(!G.linked_trait.activity_bounds.len)
|
||||
log_unit_test("[G.name]: Genetics - Has empty activation bounds.")
|
||||
failed = TRUE
|
||||
continue
|
||||
|
||||
// DNA activation bounds. Usually they are in a list as follows:
|
||||
// [1]DNA_OFF_LOWERBOUND = 1, begining of the threshold where a gene turns off.
|
||||
// [2]DNA_OFF_UPPERBOUND = a number above 1, end of the treshold where a gene turns off.
|
||||
// [3]DNA_ON_LOWERBOUND = a number above DNA_OFF_UPPERBOUND(even if just by 1), threshold where a gene turns on.
|
||||
// [4]DNA_ON_UPPERBOUND = 4095, end of the threshold where a gene turns on.
|
||||
|
||||
var/list/bounds = G.linked_trait.activity_bounds
|
||||
if(bounds[1] < 1) // lowest value a gene can be to turn off
|
||||
log_unit_test("[G.name]: Genetics - DNA_OFF_LOWERBOUND, was smaller than 1.")
|
||||
failed = TRUE
|
||||
|
||||
if(bounds[2] < bounds[1])
|
||||
log_unit_test("[G.name]: Genetics - DNA_OFF_UPPERBOUND must be larger than DNA_OFF_LOWERBOUND, and never equal.")
|
||||
failed = TRUE
|
||||
|
||||
if(bounds[2] >= bounds[3])
|
||||
log_unit_test("[G.name]: Genetics - DNA_OFF_UPPERBOUND must be smaller than DNA_ON_LOWERBOUND, and never equal.")
|
||||
failed = TRUE
|
||||
|
||||
if(bounds[3] > bounds[4])
|
||||
log_unit_test("[G.name]: Genetics - DNA_ON_LOWERBOUND must be smaller than DNA_ON_UPPERBOUND, and never equal.")
|
||||
failed = TRUE
|
||||
|
||||
if(bounds[4] > 4095) // highest value a gene can be to turn on
|
||||
log_unit_test("[G.name]: Genetics - DNA_ON_UPPERBOUND, was larger than 4095.")
|
||||
failed = TRUE
|
||||
|
||||
if(failed)
|
||||
fail("Invalid activity bounds for one or more traitgenes")
|
||||
else
|
||||
pass("All traitgenes have activity bounds, and activity bounds are legal.")
|
||||
return failed
|
||||
@@ -1,29 +0,0 @@
|
||||
/datum/unit_test/language_test_shall_have_distinct_names
|
||||
name = "LANGUAGES: Entries shall have distinct names"
|
||||
|
||||
/datum/unit_test/language_test_shall_have_distinct_names/start_test()
|
||||
if(length(GLOB.language_name_conflicts) != 0)
|
||||
var/list/name_conflict_log = list()
|
||||
for(var/conflicted_name in GLOB.language_name_conflicts)
|
||||
name_conflict_log += "+[length(GLOB.language_name_conflicts[conflicted_name])] languages with name \"[conflicted_name]\"!"
|
||||
for(var/datum/language/L in GLOB.language_name_conflicts[conflicted_name])
|
||||
name_conflict_log += "+-+[L.type]"
|
||||
fail("Some names are used by more than one language:\n" + name_conflict_log.Join("\n"))
|
||||
else
|
||||
pass("All languages have distinct names")
|
||||
return 1
|
||||
|
||||
/datum/unit_test/language_test_shall_have_distinct_keys
|
||||
name = "LANGUAGES: Entries shall have distinct keys"
|
||||
|
||||
/datum/unit_test/language_test_shall_have_distinct_keys/start_test()
|
||||
if(length(GLOB.language_key_conflicts) != 0)
|
||||
var/list/key_conflict_log = list()
|
||||
for(var/conflicted_key in GLOB.language_key_conflicts)
|
||||
key_conflict_log += "+[length(GLOB.language_key_conflicts[conflicted_key])] languages with key \"[conflicted_key]\"!"
|
||||
for(var/datum/language/L in GLOB.language_key_conflicts[conflicted_key])
|
||||
key_conflict_log += "+-+[L]([L.type])"
|
||||
fail("Some keys are used by more than one language:\n" + key_conflict_log.Join("\n"))
|
||||
else
|
||||
pass("All languages in GLOB.all_languages have distinct keys")
|
||||
return 1
|
||||
@@ -1,22 +0,0 @@
|
||||
/datum/unit_test/loadout_test_shall_have_name_cost_path
|
||||
name = "LOADOUT: Entries shall have name, cost, and path definitions"
|
||||
|
||||
/datum/unit_test/loadout_test_shall_have_name_cost_path/start_test()
|
||||
var/failed = 0
|
||||
for(var/datum/gear/G as anything in subtypesof(/datum/gear))
|
||||
|
||||
if(!initial(G.display_name))
|
||||
log_unit_test("[G]: Loadout - Missing display name.")
|
||||
failed = 1
|
||||
else if(isnull(initial(G.cost)))
|
||||
log_unit_test("[G]: Loadout - Missing cost.")
|
||||
failed = 1
|
||||
else if(!initial(G.path))
|
||||
log_unit_test("[G]: Loadout - Missing path definition.")
|
||||
failed = 1
|
||||
|
||||
if(failed)
|
||||
fail("One or more /datum/gear definitions had invalid display names, costs, or path definitions")
|
||||
else
|
||||
pass("All /datum/gear definitions had correct settings.")
|
||||
return 1
|
||||
@@ -1,242 +0,0 @@
|
||||
/datum/unit_test/apc_area_test
|
||||
name = "MAP: Area Test APC / Scrubbers / Vents (Defined Z-Levels)"
|
||||
|
||||
/datum/unit_test/apc_area_test/start_test()
|
||||
var/list/bad_areas = list()
|
||||
var/area_test_count = 0
|
||||
var/list/exempt_areas = typesof(/area/space,
|
||||
/area/syndicate_station,
|
||||
/area/skipjack_station,
|
||||
/area/solar,
|
||||
/area/shuttle,
|
||||
/area/holodeck,
|
||||
/area/supply/station,
|
||||
/area/mine,
|
||||
/area/vacant/vacant_shop,
|
||||
/area/turbolift,
|
||||
/area/submap )
|
||||
|
||||
var/list/exempt_from_atmos = typesof(/area/maintenance,
|
||||
/area/storage,
|
||||
/area/engineering/atmos/storage,
|
||||
/area/rnd/test_area,
|
||||
/area/construction,
|
||||
/area/server,
|
||||
/area/mine,
|
||||
/area/vacant/vacant_shop,
|
||||
/area/rnd/research_storage, // This should probably be fixed,
|
||||
/area/security/riot_control, // This should probably be fixed,
|
||||
)
|
||||
|
||||
var/list/exempt_from_apc = typesof(/area/construction,
|
||||
/area/medical/genetics,
|
||||
/area/mine,
|
||||
/area/vacant/vacant_shop
|
||||
)
|
||||
|
||||
// Some maps have areas specific to the map, so include those.
|
||||
exempt_areas += using_map.unit_test_exempt_areas.Copy()
|
||||
exempt_from_atmos += using_map.unit_test_exempt_from_atmos.Copy()
|
||||
exempt_from_apc += using_map.unit_test_exempt_from_apc.Copy()
|
||||
|
||||
var/list/zs_to_test = using_map.unit_test_z_levels || list(1) //Either you set it, or you just get z1
|
||||
|
||||
for(var/area/A in world)
|
||||
if((A.z in zs_to_test) && !(A.type in exempt_areas))
|
||||
area_test_count++
|
||||
var/area_good = 1
|
||||
var/bad_msg = "--------------- [A.name]([A.type])"
|
||||
|
||||
// Scan for areas with extra APCs
|
||||
if(!(A.type in exempt_from_apc))
|
||||
if(isnull(A.apc))
|
||||
log_unit_test("[bad_msg] lacks an APC. (X[A.x]|Y[A.y]) - Z[A.z])")
|
||||
area_good = 0
|
||||
else
|
||||
var/list/apc_list = list()
|
||||
for(var/turf/T in get_current_area_turfs(A))
|
||||
for(var/atom/S in T.contents)
|
||||
if(istype(S,/obj/machinery/power/apc))
|
||||
apc_list.Add(S)
|
||||
if(apc_list.len > 1)
|
||||
area_good = 0
|
||||
for(var/obj/machinery/power/P in apc_list)
|
||||
log_unit_test("[bad_msg] has too many APCs. (X[P.x]|Y[P.y]) - Z[P.z])")
|
||||
|
||||
if(!A.air_scrub_info.len && !(A.type in exempt_from_atmos))
|
||||
log_unit_test("[bad_msg] lacks an Air scrubber. (X[A.x]|Y[A.y]) - (Z[A.z])")
|
||||
area_good = 0
|
||||
|
||||
if(!A.air_vent_info.len && !(A.type in exempt_from_atmos))
|
||||
log_unit_test("[bad_msg] lacks an Air vent. (X[A.x]|Y[A.y]) - (Z[A.z])")
|
||||
area_good = 0
|
||||
|
||||
if(!area_good)
|
||||
bad_areas.Add(A)
|
||||
|
||||
if(bad_areas.len)
|
||||
fail("\[[bad_areas.len]/[area_test_count]\]Some areas lacked APCs, Air Scrubbers, or Air vents.")
|
||||
else
|
||||
pass("All \[[area_test_count]\] areas contained APCs, Air scrubbers, and Air vents.")
|
||||
|
||||
return 1
|
||||
|
||||
/datum/unit_test/wire_test
|
||||
name = "MAP: Cable Test (Defined Z-Levels)"
|
||||
|
||||
/datum/unit_test/wire_test/start_test()
|
||||
set background=1
|
||||
|
||||
var/wire_test_count = 0
|
||||
var/bad_tests = 0
|
||||
var/turf/T = null
|
||||
var/obj/structure/cable/C = null
|
||||
var/list/cable_turfs = list()
|
||||
var/list/dirs_checked = list()
|
||||
|
||||
var/list/exempt_from_wires = list()
|
||||
exempt_from_wires += using_map.unit_test_exempt_from_wires.Copy()
|
||||
|
||||
var/list/zs_to_test = using_map.unit_test_z_levels || list(1) //Either you set it, or you just get z1
|
||||
|
||||
for(var/color in GLOB.possible_cable_coil_colours)
|
||||
cable_turfs = list()
|
||||
|
||||
for(C in world)
|
||||
T = null
|
||||
|
||||
T = get_turf(C)
|
||||
var/area/A = get_area(T)
|
||||
if(T && (T.z in zs_to_test) && !(A.type in exempt_from_wires))
|
||||
if(C.color == GLOB.possible_cable_coil_colours[color])
|
||||
cable_turfs |= get_turf(C)
|
||||
|
||||
for(T in cable_turfs)
|
||||
var/bad_msg = "--------------- [T.name] \[[T.x] / [T.y] / [T.z]\] [color]"
|
||||
dirs_checked.Cut()
|
||||
for(C in T)
|
||||
wire_test_count++
|
||||
var/combined_dir = "[C.d1]-[C.d2]"
|
||||
if(combined_dir in dirs_checked)
|
||||
bad_tests++
|
||||
log_unit_test("[bad_msg] Contains multiple wires with same direction on top of each other.")
|
||||
if(C.dir != SOUTH)
|
||||
bad_tests++
|
||||
log_unit_test("[bad_msg] Contains wire with dir set, wires MUST face south, use icon_states.")
|
||||
dirs_checked.Add(combined_dir)
|
||||
|
||||
log_unit_test("[color] wires checked.")
|
||||
|
||||
if(bad_tests)
|
||||
fail("\[[bad_tests] / [wire_test_count]\] Some turfs had overlapping wires going the same direction.")
|
||||
else
|
||||
pass("All \[[wire_test_count]\] wires had no overlapping cables going the same direction.")
|
||||
|
||||
return 1
|
||||
|
||||
/datum/unit_test/template_noops
|
||||
name = "MAP: Template no-ops (all maps)"
|
||||
|
||||
/datum/unit_test/template_noops/start_test()
|
||||
|
||||
var/list/log = list()
|
||||
|
||||
var/turf_noop_count = 0
|
||||
for(var/turf/template_noop/T in world)
|
||||
turf_noop_count++
|
||||
log += "+-- Template Turf @ [T.x], [T.y], [T.z] ([T.loc])"
|
||||
|
||||
var/area_noop_count = 0
|
||||
for(var/area/template_noop/A in world)
|
||||
area_noop_count++
|
||||
log += "+-- Template Area"
|
||||
|
||||
if(turf_noop_count || area_noop_count)
|
||||
fail("Map contained [turf_noop_count] template turfs and [area_noop_count] template areas at round-start.\n" + log.Join("\n"))
|
||||
else
|
||||
pass("No template turfs or areas.")
|
||||
|
||||
return 1
|
||||
|
||||
/datum/unit_test/active_edges
|
||||
name = "MAP: Active edges (all maps)"
|
||||
|
||||
/datum/unit_test/active_edges/start_test()
|
||||
|
||||
var/active_edges = SSair.active_edges.len
|
||||
var/list/edge_log = list()
|
||||
if(active_edges)
|
||||
for(var/connection_edge/E in SSair.active_edges)
|
||||
var/a_temp = E.A.air.temperature
|
||||
var/a_moles = E.A.air.total_moles
|
||||
var/a_vol = E.A.air.volume
|
||||
var/a_gas = ""
|
||||
for(var/gas in E.A.air.gas)
|
||||
a_gas += "[gas]=[E.A.air.gas[gas]]"
|
||||
|
||||
var/b_temp
|
||||
var/b_moles
|
||||
var/b_vol
|
||||
var/b_gas = ""
|
||||
|
||||
// Two zones mixing
|
||||
if(istype(E, /connection_edge/zone))
|
||||
var/connection_edge/zone/Z = E
|
||||
b_temp = Z.B.air.temperature
|
||||
b_moles = Z.B.air.total_moles
|
||||
b_vol = Z.B.air.volume
|
||||
for(var/gas in Z.B.air.gas)
|
||||
b_gas += "[gas]=[Z.B.air.gas[gas]]"
|
||||
|
||||
// Zone and unsimulated turfs mixing
|
||||
if(istype(E, /connection_edge/unsimulated))
|
||||
var/connection_edge/unsimulated/U = E
|
||||
b_temp = U.B.temperature
|
||||
b_moles = "Unsim"
|
||||
b_vol = "Unsim"
|
||||
for(var/gas in U.air.gas)
|
||||
b_gas += "[gas]=[U.air.gas[gas]]"
|
||||
|
||||
edge_log += "Active Edge [E] ([E.type])"
|
||||
edge_log += "Edge side A: T:[a_temp], Mol:[a_moles], Vol:[a_vol], Gas:[a_gas]"
|
||||
edge_log += "Edge side B: T:[b_temp], Mol:[b_moles], Vol:[b_vol], Gas:[b_gas]"
|
||||
|
||||
for(var/turf/T in E.connecting_turfs)
|
||||
edge_log += "+--- Connecting Turf [T] ([T.type]) @ [T.x], [T.y], [T.z] ([T.loc])"
|
||||
|
||||
if(active_edges)
|
||||
fail("Maps contained [active_edges] active edges at round-start.\n" + edge_log.Join("\n"))
|
||||
else
|
||||
pass("No active edges.")
|
||||
|
||||
return 1
|
||||
|
||||
/datum/unit_test/ladder_test
|
||||
name = "MAP: Ladder Test"
|
||||
|
||||
/datum/unit_test/ladder_test/start_test()
|
||||
var/failed = FALSE
|
||||
|
||||
for(var/obj/structure/ladder/L in world)
|
||||
var/turf/T = get_turf(L)
|
||||
if(!T)
|
||||
log_unit_test("[L.x].[L.y].[L.z]: Map - Ladder on invalid turf")
|
||||
failed = TRUE
|
||||
continue
|
||||
if(L.allowed_directions & UP)
|
||||
if(!L.target_up)
|
||||
log_unit_test("[T.x].[T.y].[T.z]: Map - Ladder allows upward movement, but had no ladder above it")
|
||||
failed = TRUE
|
||||
if(L.allowed_directions & DOWN)
|
||||
if(!L.target_down)
|
||||
log_unit_test("[T.x].[T.y].[T.z]: Map - Ladder allows downward movement, but had no ladder beneath it")
|
||||
failed = TRUE
|
||||
if(T.density)
|
||||
log_unit_test("[L.x].[L.y].[L.z]: Map - Ladder is inside a wall")
|
||||
failed = TRUE
|
||||
|
||||
if(failed)
|
||||
fail("Ladders were incorrectly placed, or missing connections.")
|
||||
else
|
||||
pass("All ladders were correctly placed and had connections.")
|
||||
return failed
|
||||
@@ -1,19 +0,0 @@
|
||||
/datum/unit_test/materials_shall_have_names
|
||||
name = "MATERIALS: Materials Shall Have All Names"
|
||||
|
||||
/datum/unit_test/materials_shall_have_names/start_test()
|
||||
var/list/failures = list()
|
||||
populate_material_list()
|
||||
for(var/name in global.name_to_material)
|
||||
var/datum/material/mat = global.name_to_material[name]
|
||||
if(!mat)
|
||||
continue // how did we get here?
|
||||
if(!mat.display_name || !mat.use_name || !mat.sheet_singular_name || !mat.sheet_plural_name || !mat.sheet_collective_name)
|
||||
failures[name] = mat.type
|
||||
|
||||
if(length(failures))
|
||||
fail("[length(failures)] material\s had missing name strings: [english_list(failures)].")
|
||||
else
|
||||
pass("All materials had all their name strings.")
|
||||
|
||||
return TRUE
|
||||
@@ -1,24 +0,0 @@
|
||||
/datum/unit_test/posters_shall_have_legal_states
|
||||
name = "POSTERS: All poster decls shall have valid icon and icon overrides"
|
||||
|
||||
/datum/unit_test/posters_shall_have_legal_states/start_test()
|
||||
var/failed = 0
|
||||
var/list/all_posters = decls_repository.get_decls_of_type(/decl/poster)
|
||||
all_posters -= decls_repository.get_decl(/decl/poster/lewd) // Dumb exclusion for now. This really needs to become a valid poster instead of an illegaly made base type
|
||||
|
||||
for(var/path in all_posters)
|
||||
var/decl/poster/D = all_posters[path]
|
||||
var/obj/structure/sign/poster/P = /obj/structure/sign/poster // The base poster shows ALL subtypes except /lewd, so all posters should function here regardless!
|
||||
var/icon/I = initial(P.icon)
|
||||
if(D.icon_override)
|
||||
I = D.icon_override
|
||||
if(!(D.icon_state in cached_icon_states(I)))
|
||||
failed += 1
|
||||
log_unit_test("[D.type]: Poster - missing icon_state \"[D.icon_state]\" in \"[I]\", as [D.icon_override ? "override" : "base"] dmi.")
|
||||
|
||||
if(failed)
|
||||
fail("[failed] posters had missing icon_states or bad icon overrides.")
|
||||
else
|
||||
pass("All [all_posters.len] posters have their icon_states and overrides set correctly.")
|
||||
|
||||
return TRUE
|
||||
@@ -1,378 +0,0 @@
|
||||
/datum/unit_test/reagent_shall_have_unique_name_and_id
|
||||
name = "REAGENTS: Reagent IDs and names shall be unique"
|
||||
|
||||
/datum/unit_test/reagent_shall_have_unique_name_and_id/start_test()
|
||||
var/failed = FALSE
|
||||
var/collection_name = list()
|
||||
var/collection_id = list()
|
||||
|
||||
for(var/Rpath in subtypesof(/datum/reagent))
|
||||
var/datum/reagent/R = new Rpath()
|
||||
|
||||
if(R.name == REAGENT_DEVELOPER_WARNING) // Ignore these types as they are meant to be overridden
|
||||
continue
|
||||
|
||||
if(R.name == "")
|
||||
log_unit_test("[Rpath]: Reagents - reagent name blank.")
|
||||
failed = TRUE
|
||||
|
||||
if(R.id == REAGENT_ID_DEVELOPER_WARNING)
|
||||
log_unit_test("[Rpath]: Reagents - reagent ID not set.")
|
||||
failed = TRUE
|
||||
|
||||
if(R.id == "")
|
||||
log_unit_test("[Rpath]: Reagents - reagent ID blank.")
|
||||
failed = TRUE
|
||||
|
||||
if(R.id != lowertext(R.id))
|
||||
log_unit_test("[Rpath]: Reagents - Reagent ID must be all lowercase.")
|
||||
failed = TRUE
|
||||
|
||||
if(!(R.wiki_flag & WIKI_SPOILER)) // If wiki hidden then don't conflict test it against name, used for intentionally copied names like beer2's
|
||||
if(collection_name[R.name])
|
||||
log_unit_test("[Rpath]: Reagents - reagent name \"[R.name]\" is not unique, used first in [collection_name[R.name]].")
|
||||
failed = TRUE
|
||||
collection_name[R.name] = R.type
|
||||
|
||||
if(collection_id[R.id])
|
||||
log_unit_test("[Rpath]: Reagents - reagent ID \"[R.id]\" is not unique, used first in [collection_id[R.id]].")
|
||||
failed = TRUE
|
||||
collection_id[R.id] = R.type
|
||||
|
||||
if(!R.supply_conversion_value)
|
||||
log_unit_test("[Rpath]: Reagents - reagent ID \"[R.id]\" does not have supply_conversion_value set.")
|
||||
failed = TRUE
|
||||
|
||||
if(!R.industrial_use || !R.industrial_use == "")
|
||||
log_unit_test("[Rpath]: Reagents - reagent ID \"[R.id]\" does not have industrial_use set.")
|
||||
failed = TRUE
|
||||
|
||||
if(R.description == REAGENT_DESC_DEVELOPER_WARNING)
|
||||
log_unit_test("[Rpath]: Reagents - reagent description unset.")
|
||||
failed = TRUE
|
||||
|
||||
qdel(R)
|
||||
|
||||
if(failed)
|
||||
fail("One or more /datum/reagent subtypes had invalid definitions.")
|
||||
else
|
||||
pass("All /datum/reagent subtypes had correct settings.")
|
||||
return TRUE
|
||||
|
||||
|
||||
|
||||
/datum/unit_test/chemical_reactions_shall_use_and_produce_valid_reagents
|
||||
name = "REAGENTS: Chemical Reactions shall use and produce valid reagents"
|
||||
|
||||
/datum/unit_test/chemical_reactions_shall_use_and_produce_valid_reagents/start_test()
|
||||
var/failed = FALSE
|
||||
var/list/collection_id = list()
|
||||
|
||||
var/list/all_reactions = decls_repository.get_decls_of_subtype(/decl/chemical_reaction)
|
||||
for(var/rtype in all_reactions)
|
||||
var/decl/chemical_reaction/CR = all_reactions[rtype]
|
||||
if(CR.name == REAGENT_DEVELOPER_WARNING) // Ignore these types as they are meant to be overridden
|
||||
continue
|
||||
|
||||
if(!CR.name)
|
||||
log_unit_test("[CR.type]: Reagents - chemical reaction had null name.")
|
||||
failed = TRUE
|
||||
|
||||
if(CR.name == "")
|
||||
log_unit_test("[CR.type]: Reagents - chemical reaction had blank name.")
|
||||
failed = TRUE
|
||||
|
||||
if(!CR.id)
|
||||
log_unit_test("[CR.type]: Reagents - chemical reaction had invalid ID.")
|
||||
failed = TRUE
|
||||
|
||||
if(CR.id != lowertext(CR.id))
|
||||
log_unit_test("[CR.type]: Reagents - chemical reaction ID must be all lowercase.")
|
||||
failed = TRUE
|
||||
|
||||
if(CR.id in collection_id)
|
||||
log_unit_test("[CR.type]: Reagents - chemical reaction ID \"[CR.name]\" is not unique, used first in [collection_id[CR.id]].")
|
||||
failed = TRUE
|
||||
else
|
||||
collection_id[CR.id] = CR.type
|
||||
|
||||
if(CR.result_amount < 0)
|
||||
log_unit_test("[CR.type]: Reagents - chemical reaction ID \"[CR.name]\" had less than 0 as as result_amount?")
|
||||
failed = TRUE
|
||||
|
||||
if(CR.required_reagents && CR.required_reagents.len)
|
||||
for(var/RR in CR.required_reagents)
|
||||
if(!SSchemistry.chemical_reagents[RR])
|
||||
log_unit_test("[CR.type]: Reagents - chemical reaction had invalid required reagent ID \"[RR]\".")
|
||||
failed = TRUE
|
||||
if(CR.required_reagents[RR] <= 0)
|
||||
log_unit_test("[CR.type]: Reagents - chemical reaction had invalid required reagent amount or in invalid format \"[CR.required_reagents[RR]]\".")
|
||||
failed = TRUE
|
||||
|
||||
|
||||
if(CR.catalysts && CR.catalysts.len)
|
||||
for(var/RR in CR.catalysts)
|
||||
if(!SSchemistry.chemical_reagents[RR])
|
||||
log_unit_test("[CR.type]: Reagents - chemical reaction had invalid required reagent ID \"[RR]\".")
|
||||
failed = TRUE
|
||||
if(CR.catalysts[RR] <= 0)
|
||||
log_unit_test("[CR.type]: Reagents - chemical reaction had invalid catalysts amount or in invalid format \"[CR.catalysts[RR]]\".")
|
||||
failed = TRUE
|
||||
|
||||
if(CR.inhibitors && CR.inhibitors.len)
|
||||
for(var/RR in CR.inhibitors)
|
||||
if(!SSchemistry.chemical_reagents[RR])
|
||||
log_unit_test("[CR.type]: Reagents - chemical reaction had invalid required reagent ID \"[RR]\".")
|
||||
failed = TRUE
|
||||
if(CR.inhibitors[RR] <= 0)
|
||||
log_unit_test("[CR.type]: Reagents - chemical reaction had invalid inhibitors amount or in invalid format \"[CR.inhibitors[RR]]\".")
|
||||
failed = TRUE
|
||||
|
||||
if(CR.result)
|
||||
if(!SSchemistry.chemical_reagents[CR.result])
|
||||
log_unit_test("[CR.type]: Reagents - chemical reaction had invalid result reagent ID \"[CR.result]\".")
|
||||
failed = TRUE
|
||||
|
||||
if(failed)
|
||||
fail("One or more /decl/chemical_reaction subtypes had invalid results or components.")
|
||||
else
|
||||
pass("All /decl/chemical_reaction subtypes had correct settings.")
|
||||
return TRUE
|
||||
|
||||
|
||||
|
||||
/datum/unit_test/prefilled_reagent_containers_shall_have_valid_reagents
|
||||
name = "REAGENTS: Prefilled reagent containers shall have valid reagents"
|
||||
|
||||
/datum/unit_test/prefilled_reagent_containers_shall_have_valid_reagents/start_test()
|
||||
var/failed = FALSE
|
||||
|
||||
var/obj/container = new /obj
|
||||
for(var/RC in subtypesof(/obj/item/reagent_containers/glass))
|
||||
var/obj/item/reagent_containers/glass/R = new RC(container)
|
||||
|
||||
if(R.prefill && R.prefill.len)
|
||||
for(var/ID in R.prefill)
|
||||
if(!SSchemistry.chemical_reagents[ID])
|
||||
log_unit_test("[RC]: Reagents - reagent prefill had invalid reagent ID \"[ID]\".")
|
||||
failed = TRUE
|
||||
|
||||
qdel(R)
|
||||
|
||||
for(var/DC in subtypesof(/obj/item/reagent_containers/chem_disp_cartridge))
|
||||
var/obj/item/reagent_containers/chem_disp_cartridge/D = new DC(container)
|
||||
|
||||
if(D.spawn_reagent)
|
||||
if(!SSchemistry.chemical_reagents[D.spawn_reagent])
|
||||
log_unit_test("[DC]: Reagents - chemical dispenser cartridge had invalid reagent ID \"[D.spawn_reagent]\".")
|
||||
failed = TRUE
|
||||
|
||||
qdel(D)
|
||||
|
||||
qdel(container)
|
||||
|
||||
if(failed)
|
||||
fail("One or more /obj/item/reagent_containers had an invalid prefill reagent.")
|
||||
else
|
||||
pass("All /obj/item/reagent_containers had valid prefill reagents.")
|
||||
return TRUE
|
||||
|
||||
|
||||
/datum/unit_test/chemical_reactions_shall_not_conflict
|
||||
name = "REAGENTS: Chemical Reactions shall not conflict"
|
||||
var/obj/fake_beaker = null
|
||||
var/list/result_reactions = list()
|
||||
|
||||
/datum/unit_test/chemical_reactions_shall_not_conflict/start_test()
|
||||
var/failed = FALSE
|
||||
|
||||
#ifdef UNIT_TEST
|
||||
var/list/all_reactions = decls_repository.get_decls_of_subtype(/decl/chemical_reaction)
|
||||
for(var/rtype in all_reactions)
|
||||
var/decl/chemical_reaction/CR = all_reactions[rtype]
|
||||
|
||||
if(CR.name == REAGENT_DEVELOPER_WARNING) // Ignore these types as they are meant to be overridden
|
||||
continue
|
||||
if(!CR.name || CR.name == "" || !CR.id || CR.id == "")
|
||||
continue
|
||||
if(CR.result_amount <= 0) //Makes nothing anyway, or maybe an effect/explosion!
|
||||
continue
|
||||
if(!CR.result) // Cannot check for this
|
||||
continue
|
||||
|
||||
if(istype(CR, /decl/chemical_reaction/instant/slime))
|
||||
// slime time
|
||||
var/decl/chemical_reaction/instant/slime/SR = CR
|
||||
if(!SR.required)
|
||||
continue
|
||||
var/obj/item/slime_extract/E = new SR.required()
|
||||
qdel_swap(fake_beaker, E)
|
||||
fake_beaker.reagents.maximum_volume = 5000
|
||||
else if(istype(CR, /decl/chemical_reaction/distilling))
|
||||
// distilling
|
||||
var/obj/distilling_tester/D = new()
|
||||
qdel_swap(fake_beaker, D)
|
||||
fake_beaker.reagents.maximum_volume = 5000
|
||||
else
|
||||
// regular beaker
|
||||
qdel_swap(fake_beaker, new /obj/item/reagent_containers/glass/beaker())
|
||||
fake_beaker.reagents.maximum_volume = 5000
|
||||
|
||||
// Perform test! If it fails once, it will perform a deeper check trying to use the inhibitors of anything in the beaker
|
||||
RegisterSignal(fake_beaker.reagents, COMSIG_UNITTEST_DATA, PROC_REF(get_signal_data))
|
||||
if(perform_reaction(CR))
|
||||
// Check if we failed the test with inhibitors in use, if so we absolutely couldn't make it...
|
||||
// Uncomment the UNIT_TEST section in code\modules\reagents\reactions\_reactions.dm if you require more info
|
||||
log_unit_test("[CR.type]: Reagents - chemical reaction did not produce \"[CR.result]\". CONTAINS: \"[fake_beaker.reagents.get_reagents()]\"")
|
||||
failed = TRUE
|
||||
UnregisterSignal(fake_beaker.reagents, COMSIG_UNITTEST_DATA)
|
||||
qdel_null(fake_beaker)
|
||||
#endif
|
||||
|
||||
if(failed)
|
||||
fail("One or more /decl/chemical_reaction subtypes conflict with another reaction.")
|
||||
else
|
||||
pass("All /decl/chemical_reaction subtypes had no conflicts.")
|
||||
return TRUE
|
||||
|
||||
/datum/unit_test/chemical_reactions_shall_not_conflict/proc/perform_reaction(var/decl/chemical_reaction/CR, var/list/inhib = list())
|
||||
var/scale = 1
|
||||
if(CR.result_amount < 1)
|
||||
scale = 1 / CR.result_amount // Create at least 1 unit
|
||||
|
||||
// Weird loop here, but this is used to test both instant and distilling reactions
|
||||
// Instants will meet the while() condition on the first loop and go to the next stuff
|
||||
// but distilling will repeat over and over until the temperature test is finished!
|
||||
var/temp_test = 0
|
||||
do
|
||||
// clear for inhibitor searches
|
||||
fake_beaker.reagents.clear_reagents()
|
||||
result_reactions.Cut()
|
||||
|
||||
if(inhib.len) // taken from argument and not reaction! Put in FIRST!
|
||||
for(var/RR in inhib)
|
||||
fake_beaker.reagents.add_reagent(RR, inhib[RR] * scale)
|
||||
if(CR.catalysts) // Required for reaction
|
||||
for(var/RR in CR.catalysts)
|
||||
fake_beaker.reagents.add_reagent(RR, CR.catalysts[RR] * scale)
|
||||
if(CR.required_reagents)
|
||||
for(var/RR in CR.required_reagents)
|
||||
fake_beaker.reagents.add_reagent(RR, CR.required_reagents[RR] * scale)
|
||||
|
||||
if(!istype(CR, /decl/chemical_reaction/distilling))
|
||||
break // Skip the next section if we're not distilling
|
||||
|
||||
// Check distillation at 10 points along its temperature range!
|
||||
// This is so multiple reactions with the same requirements, but different temps, can be tested.
|
||||
temp_test += 0.1
|
||||
var/obj/distilling_tester/DD = fake_beaker
|
||||
DD.test_distilling(CR,temp_test)
|
||||
|
||||
if(fake_beaker.reagents.has_reagent(CR.result))
|
||||
return FALSE // Distilling success
|
||||
|
||||
while(temp_test > 1)
|
||||
|
||||
// Check beaker to see if we reached our goal!
|
||||
if(fake_beaker.reagents.has_reagent(CR.result))
|
||||
return FALSE // INSTANT SUCCESS!
|
||||
|
||||
if(inhib.len)
|
||||
// We've checked with inhibitors, so we're already in inhibitor checking phase.
|
||||
// So we've absolutely failed this time. There is no way to make this...
|
||||
return TRUE
|
||||
|
||||
if(!result_reactions.len)
|
||||
// Nothing to check for inhibitors...
|
||||
for(var/decl/chemical_reaction/test_react in result_reactions)
|
||||
log_unit_test("[CR.type]: Reagents - Used [test_react] but failed.")
|
||||
return TRUE
|
||||
|
||||
// Otherwise we check the resulting reagents and use their inhibitor this time!
|
||||
for(var/decl/chemical_reaction/test_react in result_reactions)
|
||||
if(!test_react)
|
||||
continue
|
||||
if(!test_react.inhibitors.len)
|
||||
continue
|
||||
// Test one by one
|
||||
for(var/each in test_react.inhibitors)
|
||||
if(!perform_reaction(CR, list("[each]" = test_react.inhibitors["[each]"])))
|
||||
return FALSE // SUCCESS using an inhibitor!
|
||||
// Test all at once
|
||||
if(!perform_reaction(CR, test_react.inhibitors))
|
||||
return FALSE // SUCCESS using all inhibitors!
|
||||
|
||||
// No inhibiting reagent worked...
|
||||
for(var/decl/chemical_reaction/test_react in result_reactions)
|
||||
log_unit_test("[CR.type]: Reagents - Used [test_react] but failed.")
|
||||
return TRUE
|
||||
|
||||
/datum/unit_test/chemical_reactions_shall_not_conflict/get_signal_data(atom/source, list/data = list())
|
||||
result_reactions.Add(data[1]) // Append the reactions that happened, then use that to check their inhibitors
|
||||
|
||||
|
||||
/datum/unit_test/chemical_grinding_must_produce_valid_results
|
||||
name = "REAGENTS: Chemical Grinding Must Have Valid Results"
|
||||
|
||||
/datum/unit_test/chemical_grinding_must_produce_valid_results/start_test()
|
||||
var/failed = FALSE
|
||||
|
||||
for(var/grind in GLOB.sheet_reagents + GLOB.ore_reagents)
|
||||
var/list/results = GLOB.sheet_reagents[grind]
|
||||
if(!results)
|
||||
results = GLOB.ore_reagents[grind]
|
||||
if(!results || !islist(results))
|
||||
log_unit_test("[grind]: Reagents - Grinding result had invalid list.")
|
||||
failed = TRUE
|
||||
continue
|
||||
if(!results.len)
|
||||
log_unit_test("[grind]: Reagents - Grinding result had empty.")
|
||||
failed = TRUE
|
||||
continue
|
||||
for(var/reg_id in results)
|
||||
if(!SSchemistry.chemical_reagents[reg_id])
|
||||
log_unit_test("[grind]: Reagents - Grinding result had invalid reagent id \"[reg_id]\".")
|
||||
failed = TRUE
|
||||
|
||||
if(failed)
|
||||
fail("One or more grindable sheet or ore entries had invalid reagents or lists.")
|
||||
else
|
||||
pass("All grindable sheet or ore entries had valid lists and reagents.")
|
||||
return TRUE
|
||||
|
||||
|
||||
|
||||
// Used to test distillations without hacking the other machinery's code up
|
||||
/obj/distilling_tester
|
||||
icon = 'icons/obj/weapons.dmi'
|
||||
icon_state = "cartridge"
|
||||
var/datum/gas_mixture/GM = new()
|
||||
var/current_temp = 0
|
||||
|
||||
/obj/distilling_tester/Initialize(mapload)
|
||||
create_reagents(5000,/datum/reagents/distilling)
|
||||
. = ..()
|
||||
|
||||
/obj/distilling_tester/return_air()
|
||||
return GM
|
||||
|
||||
/obj/distilling_tester/proc/test_distilling(var/decl/chemical_reaction/distilling/D, var/temp_prog)
|
||||
qdel_swap(GM,new())
|
||||
if(D.require_xgm_gas)
|
||||
GM.gas[D.require_xgm_gas] = 100
|
||||
else
|
||||
if(D.rejects_xgm_gas == GAS_N2)
|
||||
GM.gas[GAS_O2] = 100
|
||||
else
|
||||
GM.gas[GAS_N2] = 100
|
||||
if(D.minimum_xgm_pressure)
|
||||
GM.temperature = (D.minimum_xgm_pressure * CELL_VOLUME) / (GM.gas[D.require_xgm_gas] * R_IDEAL_GAS_EQUATION)
|
||||
|
||||
// Try this 10 times, We need to know if something is blocking at multiple temps.
|
||||
// If it passes unit test, it might still be awful to make though, gotta find the right gas mix!
|
||||
current_temp = LERP( D.temp_range[1], D.temp_range[2], temp_prog)
|
||||
reagents.handle_reactions()
|
||||
|
||||
/obj/distilling_tester/Destroy(force, ...)
|
||||
qdel_null(GM)
|
||||
. = ..()
|
||||
@@ -1,29 +0,0 @@
|
||||
/datum/unit_test/recipe_test_shall_have_valid_result_and_quantity
|
||||
name = "RECIPES: Recipes shall have valid result and result_quantity definitions"
|
||||
|
||||
/datum/unit_test/recipe_test_shall_have_valid_result_and_quantity/start_test()
|
||||
var/failed = FALSE
|
||||
for(var/datum/recipe/R in subtypesof(/datum/recipe))
|
||||
var/our_result = initial(R.result)
|
||||
var/our_amount = initial(R.result_quantity)
|
||||
if(!our_result)
|
||||
log_unit_test("[R]: Recipes - Missing result.")
|
||||
failed = TRUE
|
||||
else if(!ispath(our_result, /atom/movable))
|
||||
log_unit_test("[R]: Recipes - Improper result; [our_result] is not an obj or mob.")
|
||||
failed = TRUE
|
||||
if(isnull(our_amount))
|
||||
log_unit_test("[R]: Recipes - result_quantity must be set.")
|
||||
failed = TRUE
|
||||
if(our_amount <= 0)
|
||||
log_unit_test("[R]: Recipes - result_quantity must be greater than zero.")
|
||||
failed = TRUE
|
||||
else if(!ISINTEGER(our_amount))
|
||||
log_unit_test("[R]: Recipes - result_quantity must be an integer.")
|
||||
failed = TRUE
|
||||
|
||||
if(failed)
|
||||
fail("One or more /datum/recipe subtypes had invalid results or result_quantity definitions.")
|
||||
else
|
||||
pass("All /datum/recipe subtypes had correct settings.")
|
||||
return TRUE
|
||||
@@ -1,30 +0,0 @@
|
||||
/datum/unit_test/recycler_vendor_entry_invalid
|
||||
name = "RECYCLER: Recycler Vendor Entry shall have valid definitions"
|
||||
|
||||
/datum/unit_test/recycler_vendor_entry_invalid/start_test()
|
||||
var/failed = FALSE
|
||||
|
||||
|
||||
|
||||
for(var/datum/maint_recycler_vendor_entry/R in subtypesof(/datum/maint_recycler_vendor_entry))
|
||||
var/item_to_spawn = initial(R.object_type_to_spawn)
|
||||
var/item_cost = initial(R.item_cost)
|
||||
var/global_item_cap = initial(R.per_round_cap)
|
||||
var/individual_item_cap = initial(R.per_person_cap)
|
||||
var/is_scam = initial(R.is_scam)
|
||||
if(!item_to_spawn && !is_scam)
|
||||
log_unit_test("[R] : Vendor Entry - Missing Object Type on non-scam entry")
|
||||
failed = TRUE
|
||||
if(item_cost < 0)
|
||||
log_unit_test("[R] : Vendor Entry - Negative Cost")
|
||||
failed = TRUE
|
||||
if((item_cost == 0) && ((global_item_cap < 0)&&(individual_item_cap < 0))) //nobody SHOULD set the cost to 0 but it's possible i guess. maybe for future scams
|
||||
log_unit_test("[R] : Vendor Entry - Infinite Item Spawning due to no individual or global item cap")
|
||||
failed = TRUE
|
||||
|
||||
if(failed)
|
||||
fail("One or more /datum/maint_recycler_vendor_entry had invalid results or definitions.")
|
||||
else
|
||||
pass("All /datum/maint_recycler_vendor_entry subtypes had correct settings.")
|
||||
|
||||
return TRUE
|
||||
@@ -1,224 +0,0 @@
|
||||
/datum/unit_test/all_robot_sprites_must_be_valid
|
||||
name = "ROBOTS: Robot sprites must be valid"
|
||||
var/signal_failed = FALSE
|
||||
|
||||
/datum/unit_test/all_robot_sprites_must_be_valid/start_test()
|
||||
var/failed = 0
|
||||
|
||||
for(var/sprite in subtypesof(/datum/robot_sprite))
|
||||
var/datum/robot_sprite/RS = new sprite()
|
||||
if(!RS.name) // Parent type, ignore me
|
||||
continue
|
||||
|
||||
if(!RS.sprite_icon)
|
||||
log_unit_test("[RS.type]: Robots - Robot sprite \"[RS.name]\", missing sprite_icon.")
|
||||
failed = TRUE
|
||||
continue
|
||||
|
||||
var/list/checks = list(
|
||||
"[ROBOT_HAS_SPEED_SPRITE]" = "-roll",
|
||||
"[ROBOT_HAS_SHIELD_SPRITE]" = "-shield",
|
||||
"[ROBOT_HAS_SHIELD_SPEED_SPRITE]" = "-speed_shield",
|
||||
"[ROBOT_HAS_MELEE_SPRITE]" = "-melee",
|
||||
"[ROBOT_HAS_DAGGER_SPRITE]" = "-dagger",
|
||||
"[ROBOT_HAS_BLADE_SPRITE]" = "-blade",
|
||||
"[ROBOT_HAS_GUN_SPRITE]" = "-gun",
|
||||
"[ROBOT_HAS_LASER_SPRITE]" = "-laser",
|
||||
"[ROBOT_HAS_TASER_SPRITE]" = "-taser",
|
||||
"[ROBOT_HAS_DISABLER_SPRITE]" = "-disabler"
|
||||
)
|
||||
for(var/C in checks)
|
||||
if(RS.sprite_flag_check(text2num(C)))
|
||||
if(check_state(RS,checks[C]))
|
||||
failed = TRUE
|
||||
// eyes, lights, markings
|
||||
if(RS.has_eye_sprites)
|
||||
if(check_state(RS,"-eyes"))
|
||||
failed = TRUE
|
||||
if(RS.has_eye_light_sprites)
|
||||
if(check_state(RS,"-lights"))
|
||||
failed = TRUE
|
||||
if(LAZYLEN(RS.sprite_decals))
|
||||
for(var/decal in RS.sprite_decals)
|
||||
if(check_state(RS,"-[decal]"))
|
||||
failed = TRUE
|
||||
if(LAZYLEN(RS.sprite_animations))
|
||||
for(var/animation in RS.sprite_animations)
|
||||
if(check_state(RS,"-[animation]"))
|
||||
failed = TRUE
|
||||
// Control panel
|
||||
if(RS.has_custom_open_sprites)
|
||||
if(check_state(RS,"-openpanel_nc"))
|
||||
failed = TRUE
|
||||
if(check_state(RS,"-openpanel_c"))
|
||||
failed = TRUE
|
||||
if(check_state(RS,"-openpanel_w"))
|
||||
failed = TRUE
|
||||
// Glow State
|
||||
if(RS.has_glow_sprites)
|
||||
if(check_state(RS,"-glow"))
|
||||
failed = TRUE
|
||||
// Bellies
|
||||
if(RS.has_vore_belly_sprites && !RS.belly_capacity_list)
|
||||
if(RS.has_sleeper_light_indicator)
|
||||
// belly r/g light
|
||||
if(check_state(RS,"-sleeper-r"))
|
||||
failed = TRUE
|
||||
if(check_state(RS,"-sleeper-g"))
|
||||
failed = TRUE
|
||||
if(RS.has_vore_belly_resting_sprites)
|
||||
for(var/rest_style in RS.rest_sprite_options)
|
||||
rest_style = lowertext(rest_style)
|
||||
if(rest_style == "default")
|
||||
rest_style = "rest"
|
||||
if(check_state(RS,"-sleeper-r-[rest_style]"))
|
||||
failed = TRUE
|
||||
if(check_state(RS,"-sleeper-g-[rest_style]"))
|
||||
failed = TRUE
|
||||
// struggling
|
||||
if(RS.has_vore_struggle_sprite)
|
||||
if(check_state(RS,"-sleeper-r-struggle"))
|
||||
failed = TRUE
|
||||
if(check_state(RS,"-sleeper-g-struggle"))
|
||||
failed = TRUE
|
||||
if(RS.has_vore_belly_resting_sprites)
|
||||
for(var/rest_style in RS.rest_sprite_options)
|
||||
rest_style = lowertext(rest_style)
|
||||
if(rest_style == "default")
|
||||
rest_style = "rest"
|
||||
if(check_state(RS,"-sleeper-r-[rest_style]-struggle"))
|
||||
failed = TRUE
|
||||
if(check_state(RS,"-sleeper-g-[rest_style]-struggle"))
|
||||
failed = TRUE
|
||||
else
|
||||
// belly
|
||||
if(check_state(RS,"-sleeper"))
|
||||
failed = TRUE
|
||||
if(RS.has_vore_belly_resting_sprites)
|
||||
for(var/rest_style in RS.rest_sprite_options)
|
||||
rest_style = lowertext(rest_style)
|
||||
if(rest_style == "default")
|
||||
rest_style = "rest"
|
||||
if(check_state(RS,"-sleeper-[rest_style]"))
|
||||
failed = TRUE
|
||||
// struggling
|
||||
if(RS.has_vore_struggle_sprite)
|
||||
if(check_state(RS,"-sleeper-struggle"))
|
||||
failed = TRUE
|
||||
if(RS.has_vore_belly_resting_sprites)
|
||||
for(var/rest_style in RS.rest_sprite_options)
|
||||
rest_style = lowertext(rest_style)
|
||||
if(rest_style == "default")
|
||||
rest_style = "rest"
|
||||
if(check_state(RS,"-sleeper-[rest_style]-struggle"))
|
||||
failed = TRUE
|
||||
else if (RS.belly_capacity_list)
|
||||
for(var/belly in RS.belly_capacity_list)
|
||||
for(var/num = 1 to RS.belly_capacity_list[belly])
|
||||
// big belly
|
||||
if(check_state(RS,"-[belly]-[num]"))
|
||||
failed = TRUE
|
||||
if(RS.has_vore_belly_resting_sprites)
|
||||
for(var/rest_style in RS.rest_sprite_options)
|
||||
rest_style = lowertext(rest_style)
|
||||
if(rest_style == "default")
|
||||
rest_style = "rest"
|
||||
if(check_state(RS,"-[belly]-[num]-[rest_style]"))
|
||||
failed = TRUE
|
||||
// struggling
|
||||
if(RS.has_vore_struggle_sprite)
|
||||
if(check_state(RS,"-[belly]-[num]-struggle"))
|
||||
failed = TRUE
|
||||
if(RS.has_vore_belly_resting_sprites)
|
||||
for(var/rest_style in RS.rest_sprite_options)
|
||||
rest_style = lowertext(rest_style)
|
||||
if(rest_style == "default")
|
||||
rest_style = "rest"
|
||||
if(check_state(RS,"-[belly]-[num]-[rest_style]-struggle"))
|
||||
failed = TRUE
|
||||
if(RS.belly_light_list)
|
||||
for(var/belly in RS.belly_light_list)
|
||||
for(var/num = 1 to RS.belly_light_list[belly])
|
||||
// multi belly r/g light
|
||||
if(check_state(RS,"-[belly]-[num]-r"))
|
||||
failed = TRUE
|
||||
if(check_state(RS,"-[belly]-[num]-g"))
|
||||
failed = TRUE
|
||||
if(RS.has_vore_belly_resting_sprites)
|
||||
for(var/rest_style in RS.rest_sprite_options)
|
||||
rest_style = lowertext(rest_style)
|
||||
if(rest_style == "default")
|
||||
rest_style = "rest"
|
||||
if(check_state(RS,"-[belly]-[num]-r-[rest_style]"))
|
||||
failed = TRUE
|
||||
if(check_state(RS,"-[belly]-[num]-g-[rest_style]"))
|
||||
failed = TRUE
|
||||
// struggling
|
||||
if(RS.has_vore_struggle_sprite)
|
||||
if(check_state(RS,"-[belly]-[num]-r-struggle"))
|
||||
failed = TRUE
|
||||
if(check_state(RS,"-[belly]-[num]-g-struggle"))
|
||||
failed = TRUE
|
||||
if(RS.has_vore_belly_resting_sprites)
|
||||
for(var/rest_style in RS.rest_sprite_options)
|
||||
rest_style = lowertext(rest_style)
|
||||
if(rest_style == "default")
|
||||
rest_style = "rest"
|
||||
if(check_state(RS,"-[belly]-[num]-r-[rest_style]-struggle"))
|
||||
failed = TRUE
|
||||
if(check_state(RS,"-[belly]-[num]-g-[rest_style]-struggle"))
|
||||
failed = TRUE
|
||||
// reseting
|
||||
for(var/rest_style in RS.rest_sprite_options)
|
||||
rest_style = lowertext(rest_style)
|
||||
if(rest_style == "default")
|
||||
rest_style = "rest"
|
||||
if(check_state(RS,"-[rest_style]"))
|
||||
failed = TRUE
|
||||
if(RS.has_glow_sprites)
|
||||
if(check_state(RS,"-[rest_style]-glow"))
|
||||
failed = TRUE
|
||||
if(RS.has_rest_lights_sprites)
|
||||
if(check_state(RS,"-[rest_style]-lights"))
|
||||
failed = TRUE
|
||||
if(RS.has_rest_eyes_sprites)
|
||||
if(check_state(RS,"-[rest_style]-eyes"))
|
||||
failed = TRUE
|
||||
// death
|
||||
if(RS.has_dead_sprite)
|
||||
if(check_state(RS,"-wreck"))
|
||||
failed = TRUE
|
||||
if(RS.has_dead_sprite_overlay) // Only one per dmi
|
||||
if(!("wreck-overlay" in cached_icon_states(RS.sprite_icon)))
|
||||
log_unit_test("[RS.type]: Robots - Robot sprite \"[RS.name]\", missing icon_state wreck-overlay, in dmi \"[RS.sprite_icon]\".")
|
||||
failed = TRUE
|
||||
// offset
|
||||
var/icon/I = new(RS.sprite_icon)
|
||||
if(RS.icon_x != I.Width())
|
||||
log_unit_test("[RS.type]: Robots - Robot sprite \"[RS.name]\", icon_x \"[RS.icon_x]\" did not match dmi configured width \"[I.Width()]\"")
|
||||
failed = TRUE
|
||||
if(RS.icon_y != I.Height())
|
||||
log_unit_test("[RS.type]: Robots - Robot sprite \"[RS.name]\", icon_y \"[RS.icon_y]\" did not match dmi configured height \"[I.Height()]\"")
|
||||
failed = TRUE
|
||||
if(RS.icon_y != RS.vis_height)
|
||||
log_unit_test("[RS.type]: Robots - Robot sprite \"[RS.name]\", vis_height \"[RS.vis_height]\" did not match icon_y \"[RS.icon_y]\"")
|
||||
failed = TRUE
|
||||
var/legal_offset = (I.Width() - world.icon_size) / 2
|
||||
if(RS.pixel_x != -legal_offset)
|
||||
log_unit_test("[RS.type]: Robots - Robot sprite \"[RS.name]\", pixel_x \"[RS.pixel_x]\" did not have correct offset, should be \"[-legal_offset]\"")
|
||||
failed = TRUE
|
||||
qdel(I)
|
||||
qdel(RS)
|
||||
|
||||
if(failed)
|
||||
fail("One or more /datum/robot_sprite items had invalid flags or icons")
|
||||
else
|
||||
pass("All /datum/robot_sprite are valid.")
|
||||
return 1
|
||||
|
||||
/datum/unit_test/all_robot_sprites_must_be_valid/proc/check_state(var/datum/robot_sprite/RS,var/append)
|
||||
var/check_state = "[RS.sprite_icon_state][append]"
|
||||
if(!(check_state in cached_icon_states(RS.sprite_icon)))
|
||||
log_unit_test("[RS.type]: Robots - Robot sprite \"[RS.name]\", enabled but missing icon_state \"[check_state]\", in dmi \"[RS.sprite_icon]\".")
|
||||
return TRUE
|
||||
return FALSE
|
||||
@@ -1,69 +0,0 @@
|
||||
/datum/unit_test/sqlite
|
||||
name = "SQLite template" // Template has to be in the name or this test will be ran, and fail.
|
||||
var/database/stub_sqlite_db = null
|
||||
|
||||
/datum/unit_test/sqlite/proc/setup_stub_db()
|
||||
fdel("data/sqlite/testing_[name].db") // In case any remain from a previous local test, so we can have a clean new database.
|
||||
stub_sqlite_db = new("data/sqlite/testing_[name].db") // Unfortunately, byond doesn't like having working sqlite stuff w/o a file existing.
|
||||
SSsqlite.init_schema(stub_sqlite_db)
|
||||
|
||||
// Feedback table tests.
|
||||
/datum/unit_test/sqlite/feedback/insert
|
||||
name = "SQLITE FEEDBACK: Insert and Retrieve Data"
|
||||
|
||||
/datum/unit_test/sqlite/feedback/insert/start_test()
|
||||
// Arrange.
|
||||
setup_stub_db()
|
||||
var/test_author = "alice"
|
||||
var/test_topic = "Test"
|
||||
var/test_content = "Bob is lame."
|
||||
|
||||
// Act.
|
||||
SSsqlite.insert_feedback(author = test_author, topic = test_topic, content = test_content, sqlite_object = stub_sqlite_db)
|
||||
var/database/query/Q = new("SELECT * FROM [SQLITE_TABLE_FEEDBACK]")
|
||||
Q.Execute(stub_sqlite_db)
|
||||
SSsqlite.sqlite_check_for_errors(Q, "Sqlite Insert Unit Test")
|
||||
Q.NextRow()
|
||||
|
||||
// Assert.
|
||||
var/list/row_data = Q.GetRowData()
|
||||
if(row_data[SQLITE_FEEDBACK_COLUMN_AUTHOR] == test_author && row_data[SQLITE_FEEDBACK_COLUMN_TOPIC] == test_topic && row_data[SQLITE_FEEDBACK_COLUMN_CONTENT] == test_content)
|
||||
pass("No issues found.")
|
||||
else
|
||||
fail("Data insert and loading failed to have matching information.")
|
||||
return TRUE
|
||||
|
||||
|
||||
/datum/unit_test/sqlite/feedback/cooldown
|
||||
name = "SQLITE FEEDBACK: Cooldown"
|
||||
|
||||
/datum/unit_test/sqlite/feedback/cooldown/start_test()
|
||||
// Arrange.
|
||||
setup_stub_db()
|
||||
var/days_to_wait = 1
|
||||
var/issues = 0
|
||||
|
||||
// Act.
|
||||
SSsqlite.insert_feedback(author = "Alice", topic = "Testing", content = "This is a test.", sqlite_object = stub_sqlite_db)
|
||||
|
||||
var/alice_cooldown_block = SSsqlite.get_feedback_cooldown("Alice", days_to_wait, stub_sqlite_db)
|
||||
var/bob_cooldown = SSsqlite.get_feedback_cooldown("Bob", days_to_wait, stub_sqlite_db)
|
||||
days_to_wait = 0
|
||||
var/alice_cooldown_allow = SSsqlite.get_feedback_cooldown("Alice", days_to_wait, stub_sqlite_db)
|
||||
|
||||
// Assert.
|
||||
if(alice_cooldown_block <= 0)
|
||||
issues++
|
||||
log_unit_test("User 'Alice' did not receive a cooldown, when they were supposed to.")
|
||||
if(bob_cooldown > 0)
|
||||
issues++
|
||||
log_unit_test("User 'Bob' did receive a cooldown, when they did not do anything.")
|
||||
if(alice_cooldown_allow > 0)
|
||||
issues++
|
||||
log_unit_test("User 'Alice' did receive a cooldown, when no cooldown is supposed to be enforced.")
|
||||
|
||||
if(issues)
|
||||
fail("[issues] issues were found.")
|
||||
else
|
||||
pass("No issues found.")
|
||||
return TRUE
|
||||
@@ -1,46 +0,0 @@
|
||||
/datum/unit_test/subsystem_shall_be_initialized
|
||||
name = "SUBSYSTEM - INIT: Subsystems shall be initalized"
|
||||
|
||||
/datum/unit_test/subsystem_shall_be_initialized/start_test()
|
||||
var/list/bad_subsystems = list()
|
||||
for(var/datum/controller/subsystem/SS in Master.subsystems)
|
||||
if (SS.flags & SS_NO_INIT)
|
||||
continue
|
||||
if(!SS.subsystem_initialized)
|
||||
bad_subsystems += SS.type
|
||||
|
||||
if(bad_subsystems.len)
|
||||
fail("Found improperly initialized subsystems: [english_list(bad_subsystems)]")
|
||||
else
|
||||
pass("All susbsystems have initialized properly")
|
||||
|
||||
return 1
|
||||
|
||||
/* Uncomment when all atoms init properly
|
||||
/datum/unit_test/subsystem_atom_shall_have_no_bad_init_calls
|
||||
name = "SUBSYSTEM - ATOMS: Shall have no bad init calls"
|
||||
|
||||
/datum/unit_test/subsystem_atom_shall_have_no_bad_init_calls/start_test()
|
||||
if(SSatoms.BadInitializeCalls.len)
|
||||
log_bad(jointext(SSatoms.InitLog(), null))
|
||||
fail("[SSatoms] had bad initialization calls.")
|
||||
else
|
||||
pass("[SSatoms] had no bad initialization calls.")
|
||||
return 1
|
||||
|
||||
/datum/unit_test/all_atoms_shall_be_initialized
|
||||
name = "SUBSYSTEM - ATOMS: All atoms shall be initialized."
|
||||
|
||||
/datum/unit_test/all_atoms_shall_be_initialized/start_test()
|
||||
set background = TRUE // avoid infinite loop warning; SS will still wait for us.
|
||||
var/fail = FALSE
|
||||
for(var/atom/atom in world)
|
||||
if(!(atom.initialized))
|
||||
log_bad("Uninitialized atom: [atom.log_info_line()]")
|
||||
fail = TRUE
|
||||
if(fail)
|
||||
fail("There were uninitialized atoms.")
|
||||
else
|
||||
pass("All atoms were initialized")
|
||||
return 1
|
||||
*/
|
||||
@@ -1,58 +0,0 @@
|
||||
/datum/unit_test/all_traits_unique_names
|
||||
name = "TRAITS: All traits shall have unique names"
|
||||
|
||||
/datum/unit_test/all_traits_unique_names/start_test()
|
||||
var/failed = FALSE
|
||||
|
||||
var/list/used_named = list()
|
||||
for(var/traitpath in GLOB.all_traits)
|
||||
var/datum/trait/T = GLOB.all_traits[traitpath]
|
||||
if(T.name in used_named)
|
||||
log_unit_test("[T.type]: Trait - The name \"[T.name]\" is already in use.")
|
||||
failed = TRUE
|
||||
else
|
||||
used_named.Add(T.name)
|
||||
|
||||
if(failed)
|
||||
fail("One or more traits shared a name.")
|
||||
else
|
||||
pass("All [GLOB.all_traits.len] have unique names.")
|
||||
return failed
|
||||
|
||||
|
||||
/datum/unit_test/autohiss_shall_be_exclusive
|
||||
name = "TRAITS: Autohiss traits shall be exclusive"
|
||||
|
||||
/datum/unit_test/autohiss_shall_be_exclusive/start_test()
|
||||
var/failed = FALSE
|
||||
|
||||
var/list/hiss_list = list()
|
||||
for(var/traitpath in GLOB.all_traits)
|
||||
var/datum/trait/T = GLOB.all_traits[traitpath]
|
||||
if(!T.var_changes)
|
||||
continue
|
||||
if(!islist(T.var_changes["autohiss_basic_map"]))
|
||||
continue
|
||||
hiss_list += T
|
||||
|
||||
for(var/datum/trait/T in hiss_list)
|
||||
if(T.type in T.excludes)
|
||||
log_unit_test("[T.type]: Trait - Autohiss excludes itself.")
|
||||
failed = TRUE
|
||||
|
||||
if(!T.excludes)
|
||||
log_unit_test("[T.type]: Trait - Autohiss missing exclusion list.")
|
||||
failed = TRUE
|
||||
continue
|
||||
|
||||
var/list/exempt_list = hiss_list.Copy() - T // MUST exclude all others except itself
|
||||
for(var/datum/trait/EX in exempt_list)
|
||||
if(!(EX.type in T.excludes))
|
||||
log_unit_test("[T.type]: Trait - Autohiss missing exclusion for [EX].")
|
||||
failed = TRUE
|
||||
|
||||
if(failed)
|
||||
fail("One or more autohiss traits allow another autohiss to be chosen with it.")
|
||||
else
|
||||
pass("All [hiss_list.len] autohiss traits are properly exclusive.")
|
||||
return failed
|
||||
@@ -1,114 +0,0 @@
|
||||
var/all_unit_tests_passed = 1
|
||||
var/failed_unit_tests = 0
|
||||
var/total_unit_tests = 0
|
||||
|
||||
/datum/unit_test
|
||||
var/name = "template"
|
||||
var/disabled = ""
|
||||
var/async = 0
|
||||
var/reported = 0
|
||||
|
||||
/datum/unit_test/proc/fail(var/message)
|
||||
all_unit_tests_passed = 0
|
||||
failed_unit_tests++
|
||||
reported = 1
|
||||
log_unit_test("[ASCII_RED]!! FAILURE !! \[[name]\]: [message][ASCII_RESET]")
|
||||
|
||||
/datum/unit_test/proc/pass(var/message)
|
||||
reported = 1
|
||||
log_unit_test("[ASCII_GREEN]** SUCCESS ** \[[name]\]: [message][ASCII_RESET]")
|
||||
|
||||
/datum/unit_test/proc/start_test()
|
||||
fail("No test proc.")
|
||||
|
||||
/datum/unit_test/proc/check_result()
|
||||
fail("No check results proc.")
|
||||
return 1
|
||||
|
||||
|
||||
/proc/initialize_unit_tests()
|
||||
log_unit_test("Initializing Unit Testing")
|
||||
|
||||
if(!ticker)
|
||||
stack_trace("No Ticker")
|
||||
world.Del()
|
||||
|
||||
var/said_msg = 0
|
||||
while(!Master.current_runlevel) // Make sure the initial startup is complete.
|
||||
if(!said_msg)
|
||||
said_msg = 1
|
||||
log_unit_test("Waiting for subystems initilization to finish.")
|
||||
stoplag(10)
|
||||
|
||||
world.save_mode("extended")
|
||||
|
||||
sleep(1)
|
||||
|
||||
ticker.current_state = GAME_STATE_SETTING_UP
|
||||
Master.SetRunLevel(RUNLEVEL_SETUP)
|
||||
|
||||
log_unit_test("Round has been started. Waiting 10 seconds to start tests.")
|
||||
sleep(100)
|
||||
|
||||
var/list/test_datums = typesof(/datum/unit_test)
|
||||
|
||||
var/list/async_test = list()
|
||||
var/list/started_tests = list()
|
||||
|
||||
log_unit_test("Testing Started.")
|
||||
|
||||
for(var/test in test_datums)
|
||||
var/datum/unit_test/d = new test()
|
||||
|
||||
if(d.disabled)
|
||||
d.pass("[ASCII_RED]Check Disabled: [d.disabled][ASCII_RESET]")
|
||||
continue
|
||||
|
||||
if(findtext(d.name, "template"))
|
||||
continue
|
||||
|
||||
if(isnull(d.start_test())) // Start the test.
|
||||
d.fail("Test Runtimed")
|
||||
|
||||
if(d.async) // If it's async then we'll need to check back on it later.
|
||||
async_test.Add(d)
|
||||
total_unit_tests++
|
||||
|
||||
//
|
||||
// Check the async tests to see if they are finished.
|
||||
//
|
||||
|
||||
while(async_test.len)
|
||||
for(var/datum/unit_test/test in async_test)
|
||||
if(test.check_result())
|
||||
async_test.Remove(test)
|
||||
sleep(1)
|
||||
|
||||
//
|
||||
// Make sure all Unit Tests reported a result
|
||||
//
|
||||
|
||||
for(var/datum/unit_test/test in started_tests)
|
||||
if(!test.reported)
|
||||
test.fail("Test failed to report a result.")
|
||||
|
||||
if(all_unit_tests_passed)
|
||||
log_unit_test("[ASCII_GREEN]*** All Unit Tests Passed \[[total_unit_tests]\] ***[ASCII_RESET]")
|
||||
else
|
||||
log_unit_test("[ASCII_RED]!!! \[[failed_unit_tests]\\[total_unit_tests]\] Unit Tests Failed !!![ASCII_RESET]")
|
||||
log_unit_test("Caught [GLOB.total_runtimes] Runtime\s.")
|
||||
world.Del()
|
||||
|
||||
/datum/unit_test/proc/get_standard_turf()
|
||||
return locate(20,20,1)
|
||||
|
||||
/datum/unit_test/proc/log_bad(var/message)
|
||||
log_unit_test("[ASCII_RED]\[[name]\]: [message][ASCII_RESET]")
|
||||
|
||||
/datum/unit_test/proc/log_debug(var/message)
|
||||
log_unit_test("[ASCII_YELLOW]--- DEBUG --- \[[name]\]: [message][ASCII_RESET]")
|
||||
|
||||
// This signal should never be possible to call if the game is not compiled for unit tests
|
||||
/datum/unit_test/proc/get_signal_data(atom/source, list/data = list())
|
||||
SIGNAL_HANDLER
|
||||
return
|
||||
@@ -1,27 +0,0 @@
|
||||
//
|
||||
// VOREStation extensions to unit test framework.
|
||||
//
|
||||
|
||||
/datum/unit_test
|
||||
var/static/default_mobloc = null
|
||||
|
||||
/datum/unit_test/proc/create_test_mob(var/turf/mobloc = null, var/mobtype = /mob/living/carbon/human, var/with_mind = FALSE)
|
||||
if(isnull(mobloc))
|
||||
if(!default_mobloc)
|
||||
for(var/turf/simulated/floor/tiled/T in world)
|
||||
var/pressure = T.zone.air.return_pressure()
|
||||
if(90 < pressure && pressure < 120) // Find a turf between 90 and 120
|
||||
default_mobloc = T
|
||||
break
|
||||
mobloc = default_mobloc
|
||||
if(!mobloc)
|
||||
fail("Unable to find a location to create test mob")
|
||||
return 0
|
||||
|
||||
var/mob/living/carbon/human/H = new mobtype(mobloc)
|
||||
H.init_vore()
|
||||
|
||||
if(with_mind)
|
||||
H.mind_initialize("TestKey[rand(0,10000)]")
|
||||
|
||||
return H
|
||||
@@ -1,186 +0,0 @@
|
||||
/datum/unit_test/belly_nonsuffocation
|
||||
name = "MOB: human mob does not suffocate in a belly"
|
||||
var/startLifeTick
|
||||
var/startOxyloss
|
||||
var/endOxyloss
|
||||
var/mob/living/carbon/human/pred
|
||||
var/mob/living/carbon/human/prey
|
||||
async = 1
|
||||
|
||||
/datum/unit_test/belly_nonsuffocation/start_test()
|
||||
pred = create_test_mob()
|
||||
if(!istype(pred))
|
||||
return 0
|
||||
prey = create_test_mob(pred.loc)
|
||||
if(!istype(prey))
|
||||
return 0
|
||||
|
||||
return 1
|
||||
|
||||
/datum/unit_test/belly_nonsuffocation/check_result()
|
||||
// Unfortuantely we need to wait for the pred's belly to initialize. (Currently after a spawn())
|
||||
if(!pred.vore_organs || !pred.vore_organs.len)
|
||||
return 0
|
||||
|
||||
// Now that pred belly exists, we can eat the prey.
|
||||
if(!pred.vore_selected)
|
||||
fail("[pred] has no vore_selected.")
|
||||
return 1
|
||||
|
||||
// Attempt to eat the prey
|
||||
if(prey.loc != pred.vore_selected)
|
||||
pred.vore_selected.nom_mob(prey)
|
||||
|
||||
if(prey.loc != pred.vore_selected)
|
||||
fail("[pred.vore_selected].nom_mob([prey]) did not put prey inside [pred]")
|
||||
return 1
|
||||
|
||||
// Okay, we succeeded in eating them, now lets wait a bit
|
||||
startLifeTick = pred.life_tick
|
||||
startOxyloss = prey.getOxyLoss()
|
||||
return 0
|
||||
|
||||
if(pred.life_tick < (startLifeTick + 10))
|
||||
return 0 // Wait for them to breathe a few times
|
||||
|
||||
// Alright lets check it!
|
||||
endOxyloss = prey.getOxyLoss()
|
||||
if(startOxyloss < endOxyloss)
|
||||
fail("Prey takes oxygen damage in a pred's belly! (Before: [startOxyloss]; after: [endOxyloss])")
|
||||
else
|
||||
pass("Prey is not taking oxygen damage in pred's belly. (Before: [startOxyloss]; after: [endOxyloss])")
|
||||
|
||||
qdel(prey)
|
||||
qdel(pred)
|
||||
return 1
|
||||
////////////////////////////////////////////////////////////////
|
||||
/datum/unit_test/belly_spacesafe
|
||||
name = "MOB: human mob protected from space in a belly"
|
||||
var/startLifeTick
|
||||
var/startOxyloss
|
||||
var/endOxyloss
|
||||
var/mob/living/carbon/human/pred
|
||||
var/mob/living/carbon/human/prey
|
||||
async = 1
|
||||
|
||||
/datum/unit_test/belly_spacesafe/start_test()
|
||||
pred = create_test_mob()
|
||||
if(!istype(pred))
|
||||
return 0
|
||||
prey = create_test_mob(pred.loc)
|
||||
if(!istype(prey))
|
||||
return 0
|
||||
|
||||
return 1
|
||||
|
||||
/datum/unit_test/belly_spacesafe/check_result()
|
||||
// Unfortuantely we need to wait for the pred's belly to initialize. (Currently after a spawn())
|
||||
if(!pred.vore_organs || !pred.vore_organs.len)
|
||||
return 0
|
||||
|
||||
// Now that pred belly exists, we can eat the prey.
|
||||
if(!pred.vore_selected)
|
||||
fail("[pred] has no vore_selected.")
|
||||
return 1
|
||||
|
||||
// Attempt to eat the prey
|
||||
if(prey.loc != pred.vore_selected)
|
||||
pred.vore_selected.nom_mob(prey)
|
||||
|
||||
if(prey.loc != pred.vore_selected)
|
||||
fail("[pred.vore_selected].nom_mob([prey]) did not put prey inside [pred]")
|
||||
return 1
|
||||
else
|
||||
// Get an empty space level instead of just picking a random space turf
|
||||
var/empty_z = using_map.get_empty_zlevel()
|
||||
if(!empty_z)
|
||||
fail("Unable to get empty z-level for vore space protection test!")
|
||||
return 1
|
||||
|
||||
// Away from map edges so they don't transit while we're testing
|
||||
var/mid_w = round(world.maxx*0.5)
|
||||
var/mid_h = round(world.maxy*0.5)
|
||||
|
||||
var/turf/T = locate(mid_w, mid_h, empty_z)
|
||||
|
||||
if(!T)
|
||||
fail("Unable to get turf for vore space protection test!")
|
||||
return 1
|
||||
else
|
||||
pred.forceMove(T)
|
||||
|
||||
// Okay, we succeeded in eating them, now lets wait a bit
|
||||
startLifeTick = pred.life_tick
|
||||
startOxyloss = prey.getOxyLoss()
|
||||
return 0
|
||||
|
||||
if(pred.life_tick < (startLifeTick + 10))
|
||||
return 0 // Wait for them to breathe a few times
|
||||
|
||||
// Alright lets check it!
|
||||
endOxyloss = prey.getOxyLoss()
|
||||
if(startOxyloss < endOxyloss)
|
||||
fail("Prey takes oxygen damage in space! (Before: [startOxyloss]; after: [endOxyloss])")
|
||||
else
|
||||
pass("Prey is not taking oxygen damage in space. (Before: [startOxyloss]; after: [endOxyloss])")
|
||||
|
||||
qdel(prey)
|
||||
qdel(pred)
|
||||
return 1
|
||||
////////////////////////////////////////////////////////////////
|
||||
/datum/unit_test/belly_damage
|
||||
name = "MOB: human mob takes damage from digestion"
|
||||
var/startLifeTick
|
||||
var/startBruteBurn
|
||||
var/endBruteBurn
|
||||
var/mob/living/carbon/human/pred
|
||||
var/mob/living/carbon/human/prey
|
||||
async = 1
|
||||
|
||||
/datum/unit_test/belly_damage/start_test()
|
||||
pred = create_test_mob()
|
||||
if(!istype(pred))
|
||||
return 0
|
||||
prey = create_test_mob(pred.loc)
|
||||
if(!istype(prey))
|
||||
return 0
|
||||
|
||||
return 1
|
||||
|
||||
/datum/unit_test/belly_damage/check_result()
|
||||
// Unfortuantely we need to wait for the pred's belly to initialize. (Currently after a spawn())
|
||||
if(!pred.vore_organs || !pred.vore_organs.len)
|
||||
return 0
|
||||
|
||||
// Now that pred belly exists, we can eat the prey.
|
||||
if(!pred.vore_selected)
|
||||
fail("[pred] has no vore_selected.")
|
||||
return 1
|
||||
|
||||
// Attempt to eat the prey
|
||||
if(prey.loc != pred.vore_selected)
|
||||
pred.vore_selected.nom_mob(prey)
|
||||
|
||||
if(prey.loc != pred.vore_selected)
|
||||
fail("[pred.vore_selected].nom_mob([prey]) did not put prey inside [pred]")
|
||||
return 1
|
||||
|
||||
// Okay, we succeeded in eating them, now lets wait a bit
|
||||
pred.vore_selected.digest_mode = DM_DIGEST
|
||||
startLifeTick = pred.life_tick
|
||||
startBruteBurn = prey.getBruteLoss() + prey.getFireLoss()
|
||||
return 0
|
||||
|
||||
if(pred.life_tick < (startLifeTick + 10))
|
||||
return 0 // Wait a few ticks for damage to happen
|
||||
|
||||
// Alright lets check it!
|
||||
endBruteBurn = prey.getBruteLoss() + prey.getFireLoss()
|
||||
if(startBruteBurn >= endBruteBurn)
|
||||
fail("Prey doesn't take damage in digesting belly! (Before: [startBruteBurn]; after: [endBruteBurn])")
|
||||
else
|
||||
pass("Prey is taking damage in pred's belly. (Before: [startBruteBurn]; after: [endBruteBurn])")
|
||||
|
||||
qdel(prey)
|
||||
qdel(pred)
|
||||
return 1
|
||||
@@ -1,30 +0,0 @@
|
||||
///NOTE: LEAVE THIS FILE UNTICKED AND THE SEGMENTS OF CODE COMMENTED OUT UNLESS YOU NEED TO DO SOMETHING SPECIFIC / TRACK SOMETHING SPECIFIC.
|
||||
|
||||
|
||||
/*
|
||||
/// Testing if DNA & Species datums get destoryed or not. Use this as a basis to test for memory leaks.
|
||||
/// This happens if DNA is copied from somewhere but not qdel_swap()'d. WARNING: Not every time it's copied should be qdel_swap()'d.
|
||||
/// But if you are doing anything DNA copy related, turn this on and make sure it's not infintely storing a datum somewhere.
|
||||
GLOBAL_VAR(total_dna_counters)
|
||||
GLOBAL_VAR(total_species_counters)
|
||||
|
||||
/datum/dna/New()
|
||||
. = ..()
|
||||
GLOB.total_dna_counters += 1
|
||||
|
||||
/datum/dna/Destroy()
|
||||
. = ..()
|
||||
GLOB.total_dna_counters -= 1
|
||||
|
||||
/datum/species/New()
|
||||
. = ..()
|
||||
GLOB.total_species_counters += 1
|
||||
|
||||
/datum/species/Destroy()
|
||||
. = ..()
|
||||
GLOB.total_species_counters -= 1
|
||||
|
||||
/proc/delete_all_monkeys()
|
||||
for(var/mob/living/carbon/human/monkey/monkeys in world)
|
||||
qdel(monkeys)
|
||||
*/
|
||||
Reference in New Issue
Block a user