diff --git a/.github/workflows/ci_suite.yml b/.github/workflows/ci_suite.yml index 4d6022caa9b..b38ba60286b 100644 --- a/.github/workflows/ci_suite.yml +++ b/.github/workflows/ci_suite.yml @@ -71,10 +71,10 @@ jobs: - name: Run Grep Checks if: steps.linter-setup.conclusion == 'success' && !cancelled() run: bash tools/ci/check_grep.sh - - name: Ticked File Enforcement - if: steps.linter-setup.conclusion == 'success' && !cancelled() + # - name: Ticked File Enforcement + # if: steps.linter-setup.conclusion == 'success' && !cancelled() # add if needed => tools/bootstrap/python tools/ticked_file_enforcement/ticked_file_enforcement.py < tools/ticked_file_enforcement/schemas/tgstation_dme.json - run: tools/bootstrap/python tools/ticked_file_enforcement/ticked_file_enforcement.py < tools/ticked_file_enforcement/schemas/unit_tests.json + # run: tools/bootstrap/python tools/ticked_file_enforcement/ticked_file_enforcement.py < tools/ticked_file_enforcement/schemas/unit_tests.json # this would be nice cleaning up local defines # - name: Check Define Sanity # if: steps.linter-setup.conclusion == 'success' && !cancelled() diff --git a/code/__DEFINES/unit_tests.dm b/code/__DEFINES/unit_tests.dm index ed7cd8490ec..a6ed2aab7fc 100644 --- a/code/__DEFINES/unit_tests.dm +++ b/code/__DEFINES/unit_tests.dm @@ -1,16 +1,14 @@ -/** - * Are tests enabled with no focus? - * Use this when performing test assertions outside of a unit test, - * since a focused test means that you're trying to run a test quickly. - * If a parameter is provided, will check if the focus is on that test name. - * For example, PERFORM_ALL_TESTS(log_mapping) will only run if either - * no test is focused, or the focus is log_mapping. - */ +/// Are tests enabled with no focus? +/// Use this when performing test assertions outside of a unit test, +/// since a focused test means that you're trying to run a test quickly. +/// If a parameter is provided, will check if the focus is on that test name. +/// For example, PERFORM_ALL_TESTS(log_mapping) will only run if either +/// no test is focused, or the focus is log_mapping. #ifdef UNIT_TESTS -/// Bit of a trick here, if focus isn't passed in then it'll check for /datum/unit_test/, which is never the case. -#define PERFORM_ALL_TESTS(focus...) (isnull(GLOB.focused_test) || GLOB.focused_test == /datum/unit_test/##focus) +// Bit of a trick here, if focus isn't passed in then it'll check for /datum/unit_test/, which is never the case. +#define PERFORM_ALL_TESTS(focus...) (isnull(GLOB.focused_tests) || (/datum/unit_test/##focus in GLOB.focused_tests)) #else -/// UNLINT necessary here so that if (PERFORM_ALL_TESTS()) works +// UNLINT necessary here so that if (PERFORM_ALL_TESTS()) works #define PERFORM_ALL_TESTS(...) UNLINT(FALSE) #endif @@ -20,3 +18,21 @@ #else #define TEST_ONLY_ASSERT(test, explanation) #endif + +/** + * TODO acutaly make this work + * Used for registering typepaths of item to be tracked as a "required map item" + * This is used to ensure that that all station maps have certain items mapped in that they should have + * Or that people aren't mapping in an excess of items that they shouldn't be + * (For example, all map should only ever have 1 Pun Pun) + * + * Min is inclusive, Max is inclusive (so 1, 1 means min of 1, max of 1, or only 1 allowed) + * + * This should only be used in Initialize(). And don't forget to update the unit test with the type itself! + */ +#ifdef UNIT_TESTS +#define REGISTER_REQUIRED_MAP_ITEM(min, max) + // there was a func here! +#else +#define REGISTER_REQUIRED_MAP_ITEM(min, max) +#endif diff --git a/code/__HELPERS/_logging.dm b/code/__HELPERS/_logging.dm index f9e8cd4d158..75181326947 100644 --- a/code/__HELPERS/_logging.dm +++ b/code/__HELPERS/_logging.dm @@ -252,6 +252,9 @@ GLOBAL_LIST_INIT(testing_global_profiler, list("_PROFILE_NAME" = "Global")) SEND_TEXT(world.log, text) /proc/log_mapping(text) +#ifdef UNIT_TESTS + GLOB.unit_test_mapping_logs += text +#endif WRITE_LOG(GLOB.world_map_error_log, text) /** diff --git a/code/_globals/logging.dm b/code/_globals/logging.dm index 97de9bb1b2c..be83c5ca0e9 100644 --- a/code/_globals/logging.dm +++ b/code/_globals/logging.dm @@ -1,3 +1,8 @@ + +#if defined(UNIT_TESTS) || defined(SPACEMAN_DMM) +GLOBAL_VAR(test_log) +#endif + /// Base directory at where logs are placed GLOBAL_VAR(log_directory) GLOBAL_PROTECT(log_directory) diff --git a/code/modules/unit_tests/_unit_tests.dm b/code/modules/unit_tests/_unit_tests.dm index f93bc95adb0..c34909855e0 100644 --- a/code/modules/unit_tests/_unit_tests.dm +++ b/code/modules/unit_tests/_unit_tests.dm @@ -55,8 +55,13 @@ #define TEST_DEFAULT 1 /// After most test steps, used for tests that run long so shorter issues can be noticed faster #define TEST_LONGER 10 -/// This must be the last test to run due to the inherent nature of the test iterating every single tangible atom in the game and qdeleting all of them (while taking long sleeps to make sure the garbage collector fires properly) taking a large amount of time. -#define TEST_CREATE_AND_DESTROY INFINITY +/// This must be the one of last tests to run due to the inherent nature of the test iterating every single tangible atom in the game and qdeleting all of them (while taking long sleeps to make sure the garbage collector fires properly) taking a large amount of time. +#define TEST_CREATE_AND_DESTROY 9001 +/** + * For tests that rely on create and destroy having iterated through every (tangible) atom so they don't have to do something similar. + * Keep in mind tho that create and destroy will absolutely break the test platform, anything that relies on its shape cannot come after it. + */ +#define TEST_AFTER_CREATE_AND_DESTROY INFINITY /// Change color to red on ANSI terminal output, if enabled with -DANSICOLORS. #ifdef ANSICOLORS @@ -70,14 +75,19 @@ #else #define TEST_OUTPUT_GREEN(text) (text) #endif - +/// Change color to yellow on ANSI terminal output, if enabled with -DANSICOLORS. +#ifdef ANSICOLORS +#define TEST_OUTPUT_YELLOW(text) "\x1B\x5B1;33m[text]\x1B\x5B0m" +#else +#define TEST_OUTPUT_YELLOW(text) (text) +#endif /// A trait source when adding traits through unit tests #define TRAIT_SOURCE_UNIT_TESTS "unit_tests" +// BEGIN_INCLUDE #include "atmospherics/_atmospherics.dm" #include "core/_core.dm" #include "datum/_datum.dm" -#include "elements/_elements.dm" #include "human/_human.dm" #include "language/_language.dm" #include "mob/_mob.dm" @@ -86,18 +96,25 @@ #include "bad_alcohol_reagents.dm" #include "bespoke_id.dm" #include "component_tests.dm" +#include "connect_loc.dm" #include "focus_only_tests.dm" #include "initialize_sanity.dm" +#include "loadout_tests.dm" #include "map_template_paths.dm" +#include "materials.dm" +#include "mapping.dm" #include "prototypes.dm" +#include "projectiles.dm" #include "resist.dm" #include "spawn_humans.dm" #include "subsystem_init.dm" #include "timer_sanity.dm" #include "unit_test.dm" +// END_INCLUDE + #undef TEST_ASSERT #undef TEST_ASSERT_EQUAL #undef TEST_ASSERT_NOTEQUAL -#undef TEST_FOCUS +//#undef TEST_FOCUS - This define is used by vscode unit test extension to pick specific unit tests to run and appended later so needs to be used out of scope here #endif diff --git a/code/modules/unit_tests/anchored_mobs.dm b/code/modules/unit_tests/anchored_mobs.dm deleted file mode 100644 index 103b97e7a99..00000000000 --- a/code/modules/unit_tests/anchored_mobs.dm +++ /dev/null @@ -1,9 +0,0 @@ -/datum/unit_test/anchored_mobs/Run() - var/list/L = list() - for(var/i in typesof(/mob)) - var/mob/M = i - if(initial(M.anchored)) - L += "[i]" - if(!L.len) - return //passed! - Fail("The following mobs are defined as anchored. This is incompatible with the new move force/resist system and needs to be revised.: [L.Join(" ")]") diff --git a/code/modules/unit_tests/bad_alcohol_reagents.dm b/code/modules/unit_tests/bad_alcohol_reagents.dm index 9789824c4c2..9ec9176867d 100644 --- a/code/modules/unit_tests/bad_alcohol_reagents.dm +++ b/code/modules/unit_tests/bad_alcohol_reagents.dm @@ -16,4 +16,4 @@ if(istype(reagent, /datum/reagent/toxin)) // anything made from literal toxins is unsafe anyway, we don't care any_ethanol=TRUE if(!any_ethanol) - Fail("[D.result] is alcoholic but can be made with only non-alcoholic ingredients") + TEST_FAIL("[D.result] is alcoholic but can be made with only non-alcoholic ingredients") diff --git a/code/modules/unit_tests/card_mismatch.dm b/code/modules/unit_tests/card_mismatch.dm deleted file mode 100644 index 506e88f19c3..00000000000 --- a/code/modules/unit_tests/card_mismatch.dm +++ /dev/null @@ -1,7 +0,0 @@ -/datum/unit_test/card_mismatch - -/datum/unit_test/card_mismatch/Run() - var/message = checkCardpacks(SStrading_card_game.card_packs) - message += checkCardDatums() - if(message) - Fail(message) diff --git a/code/modules/unit_tests/chain_pull_through_space.dm b/code/modules/unit_tests/chain_pull_through_space.dm deleted file mode 100644 index 5d7cf1c33e8..00000000000 --- a/code/modules/unit_tests/chain_pull_through_space.dm +++ /dev/null @@ -1,61 +0,0 @@ -/datum/unit_test/chain_pull_through_space - var/turf/open/space/space_tile - var/claimed_tile - var/mob/living/carbon/human/alice - var/mob/living/carbon/human/bob - var/mob/living/carbon/human/charlie - var/targetz = 5 - var/datum/turf_reservation/reserved - -/datum/unit_test/chain_pull_through_space/New() - ..() - - //reserve a tile that is always empty for our z destination - reserved = SSmapping.request_block_reservation(5,5) - - // Create a space tile that goes to another z-level - claimed_tile = run_loc_floor_bottom_left.type - - space_tile = new(locate(run_loc_floor_bottom_left.x, run_loc_floor_bottom_left.y, run_loc_floor_bottom_left.z)) - space_tile.destination_x = round(reserved.bottom_left_coords[1] + (reserved.width-1) / 2) - space_tile.destination_y = round(reserved.bottom_left_coords[2] + (reserved.height-1) / 2) - space_tile.destination_z = reserved.bottom_left_coords[3] - - // Create our list of humans, all adjacent to one another - alice = new(locate(run_loc_floor_bottom_left.x + 2, run_loc_floor_bottom_left.y, run_loc_floor_bottom_left.z)) - alice.name = "Alice" - - bob = new(locate(run_loc_floor_bottom_left.x + 3, run_loc_floor_bottom_left.y, run_loc_floor_bottom_left.z)) - bob.name = "Bob" - - charlie = new(locate(run_loc_floor_bottom_left.x + 4, run_loc_floor_bottom_left.y, run_loc_floor_bottom_left.z)) - charlie.name = "Charlie" - -/datum/unit_test/chain_pull_through_space/Destroy() - space_tile.ChangeTurf(claimed_tile) - qdel(alice) - qdel(bob) - qdel(charlie) - qdel(reserved) - return ..() - -/datum/unit_test/chain_pull_through_space/Run() - // Alice pulls Bob, who pulls Charlie - // Normally, when Alice moves forward, the rest follow - alice.start_pulling(bob) - bob.start_pulling(charlie) - - // Walk normally to the left, make sure we're still a chain - alice.Move(locate(run_loc_floor_bottom_left.x + 1, run_loc_floor_bottom_left.y, run_loc_floor_bottom_left.z)) - TEST_ASSERT_EQUAL(bob.x, run_loc_floor_bottom_left.x + 2, "During normal move, Bob was not at the correct x ([bob.x])") - TEST_ASSERT_EQUAL(charlie.x, run_loc_floor_bottom_left.x + 3, "During normal move, Charlie was not at the correct x ([charlie.x])") - - // We're going through the space turf now that should teleport us - alice.Move(run_loc_floor_bottom_left) - TEST_ASSERT_EQUAL(alice.z, space_tile.destination_z, "Alice did not teleport to the destination z-level. Current location: ([alice.x], [alice.y], [alice.z])") - - TEST_ASSERT_EQUAL(bob.z, space_tile.destination_z, "Bob did not teleport to the destination z-level. Current location: ([bob.x], [bob.y], [bob.z])") - TEST_ASSERT(bob.Adjacent(alice), "Bob is not adjacent to Alice. Bob is at [bob.x], Alice is at [alice.x]") - - TEST_ASSERT_EQUAL(charlie.z, space_tile.destination_z, "Charlie did not teleport to the destination z-level. Current location: ([charlie.x], [charlie.y], [charlie.z])") - TEST_ASSERT(charlie.Adjacent(bob), "Charlie is not adjacent to Bob. Charlie is at [charlie.x], Bob is at [bob.x]") diff --git a/code/modules/unit_tests/character_saving.dm b/code/modules/unit_tests/character_saving.dm deleted file mode 100644 index 8d978a630d8..00000000000 --- a/code/modules/unit_tests/character_saving.dm +++ /dev/null @@ -1,18 +0,0 @@ -/datum/unit_test/character_saving/Run() - try - var/datum/preferences/P = new - P.load_path("test") - P.features["flavor_text"] = "Foo" - P.features["ooc_notes"] = "Bar" - P.save_character() - P.load_character() - if(P.features["flavor_text"] != "Foo") - Fail("Flavor text is failing to save.") - if(P.features["ooc_notes"] != "Bar") - Fail("OOC text is failing to save.") - P.save_character() - P.load_character() - if(P.features["flavor_text"] != "Foo") - Fail("Repeated saving and loading possibly causing save deletion.") - catch(var/exception/e) - Fail("Failed to save and load character due to exception [e.file]:[e.line], [e.name]") diff --git a/code/modules/unit_tests/combat.dm b/code/modules/unit_tests/combat.dm deleted file mode 100644 index 570eb0fd1e0..00000000000 --- a/code/modules/unit_tests/combat.dm +++ /dev/null @@ -1,101 +0,0 @@ -/datum/unit_test/harm_punch/Run() - var/mob/living/carbon/human/puncher = allocate(/mob/living/carbon/human/consistent) - var/mob/living/carbon/human/victim = allocate(/mob/living/carbon/human/consistent) - - // Avoid all randomness in tests - ADD_TRAIT(puncher, TRAIT_PERFECT_ATTACKER, INNATE_TRAIT) - - puncher.set_combat_mode(TRUE) - victim.attack_hand(puncher, list(RIGHT_CLICK = FALSE)) - - TEST_ASSERT(victim.getBruteLoss() > 0, "Victim took no brute damage after being punched") - -/datum/unit_test/harm_melee/Run() - var/mob/living/carbon/human/tider = allocate(/mob/living/carbon/human/consistent) - var/mob/living/carbon/human/victim = allocate(/mob/living/carbon/human/consistent) - var/obj/item/storage/toolbox/toolbox = allocate(/obj/item/storage/toolbox) - - tider.put_in_active_hand(toolbox, forced = TRUE) - tider.set_combat_mode(TRUE) - victim.attackby(toolbox, tider) - - TEST_ASSERT(victim.getBruteLoss() > 0, "Victim took no brute damage after being hit by a toolbox") - -/datum/unit_test/harm_different_damage/Run() - var/mob/living/carbon/human/attacker = allocate(/mob/living/carbon/human/consistent) - var/mob/living/carbon/human/victim = allocate(/mob/living/carbon/human/consistent) - var/obj/item/weldingtool/welding_tool = allocate(/obj/item/weldingtool) - - attacker.put_in_active_hand(welding_tool, forced = TRUE) - attacker.set_combat_mode(TRUE) - - welding_tool.attack_self(attacker) // Turn it on - victim.attackby(welding_tool, attacker) - - TEST_ASSERT_EQUAL(victim.getBruteLoss(), 0, "Victim took brute damage from a lit welding tool") - TEST_ASSERT(victim.getFireLoss() > 0, "Victim took no burn damage after being hit by a lit welding tool") - -/datum/unit_test/attack_chain - var/attack_hit - var/post_attack_hit - var/pre_attack_hit - -/datum/unit_test/attack_chain/proc/attack_hit() - SIGNAL_HANDLER - attack_hit = TRUE - -/datum/unit_test/attack_chain/proc/post_attack_hit() - SIGNAL_HANDLER - post_attack_hit = TRUE - -/datum/unit_test/attack_chain/proc/pre_attack_hit() - SIGNAL_HANDLER - pre_attack_hit = TRUE - -/datum/unit_test/attack_chain/Run() - var/mob/living/carbon/human/attacker = allocate(/mob/living/carbon/human/consistent) - var/mob/living/carbon/human/victim = allocate(/mob/living/carbon/human/consistent) - var/obj/item/storage/toolbox/toolbox = allocate(/obj/item/storage/toolbox) - - RegisterSignal(toolbox, COMSIG_ITEM_PRE_ATTACK, PROC_REF(pre_attack_hit)) - RegisterSignal(toolbox, COMSIG_ITEM_ATTACK, PROC_REF(attack_hit)) - RegisterSignal(toolbox, COMSIG_ITEM_AFTERATTACK, PROC_REF(post_attack_hit)) - - attacker.put_in_active_hand(toolbox, forced = TRUE) - attacker.set_combat_mode(TRUE) - toolbox.melee_interaction_chain(attacker, victim) - - TEST_ASSERT(pre_attack_hit, "Pre-attack signal was not fired") - TEST_ASSERT(attack_hit, "Attack signal was not fired") - TEST_ASSERT(post_attack_hit, "Post-attack signal was not fired") - -/datum/unit_test/disarm/Run() - var/mob/living/carbon/human/attacker = allocate(/mob/living/carbon/human/consistent) - var/mob/living/carbon/human/victim = allocate(/mob/living/carbon/human/consistent) - var/obj/item/storage/toolbox/toolbox = allocate(/obj/item/storage/toolbox) - - victim.put_in_active_hand(toolbox, forced = TRUE) - - var/obj/structure/barricade/dense_object = allocate(/obj/structure/barricade) - - // Attacker --> Victim --> Empty space --> Wall - attacker.forceMove(run_loc_floor_bottom_left) - victim.forceMove(locate(run_loc_floor_bottom_left.x + 1, run_loc_floor_bottom_left.y, run_loc_floor_bottom_left.z)) - dense_object.forceMove(locate(run_loc_floor_bottom_left.x + 3, run_loc_floor_bottom_left.y, run_loc_floor_bottom_left.z)) - - // First disarm, world should now look like: - // Attacker --> Empty space --> Victim --> Wall - victim.attack_hand(attacker, list(RIGHT_CLICK = TRUE)) - - TEST_ASSERT_EQUAL(victim.loc.x, run_loc_floor_bottom_left.x + 2, "Victim wasn't moved back after being pushed") - TEST_ASSERT(!victim.has_status_effect(/datum/status_effect/incapacitating/knockdown), "Victim was knocked down despite not being against a wall") - TEST_ASSERT_EQUAL(victim.get_active_held_item(), toolbox, "Victim dropped toolbox despite not being against a wall") - - attacker.forceMove(get_step(attacker, EAST)) - - // Second disarm, victim was against wall and should be down - victim.attack_hand(attacker, list(RIGHT_CLICK = TRUE)) - - TEST_ASSERT_EQUAL(victim.loc.x, run_loc_floor_bottom_left.x + 2, "Victim was moved after being pushed against a wall") - TEST_ASSERT(victim.has_status_effect(/datum/status_effect/incapacitating/knockdown), "Victim was not knocked down after being pushed against a wall") - TEST_ASSERT_EQUAL(victim.get_active_held_item(), null, "Victim didn't drop toolbox after being pushed against a wall") diff --git a/code/modules/unit_tests/confusion.dm b/code/modules/unit_tests/confusion.dm deleted file mode 100644 index 8282493c962..00000000000 --- a/code/modules/unit_tests/confusion.dm +++ /dev/null @@ -1,16 +0,0 @@ -// Checks that the confusion symptom correctly gives, and removes, confusion -/datum/unit_test/confusion_symptom/Run() - var/mob/living/carbon/human/H = allocate(/mob/living/carbon/human) - var/datum/disease/advance/confusion/disease = allocate(/datum/disease/advance/confusion) - var/datum/symptom/confusion/confusion = disease.symptoms[1] - disease.processing = TRUE - disease.update_stage(5) - disease.infect(H, make_copy = FALSE) - confusion.Activate(disease) - TEST_ASSERT(H.get_confusion() > 0, "Human is not confused after getting symptom.") - disease.cure() - TEST_ASSERT_EQUAL(H.get_confusion(), 0, "Human is still confused after curing confusion.") - -/datum/disease/advance/confusion/New() - symptoms += new /datum/symptom/confusion - Refresh() diff --git a/code/modules/unit_tests/elements/connect_loc.dm b/code/modules/unit_tests/connect_loc.dm similarity index 100% rename from code/modules/unit_tests/elements/connect_loc.dm rename to code/modules/unit_tests/connect_loc.dm diff --git a/code/modules/unit_tests/elements/_elements.dm b/code/modules/unit_tests/elements/_elements.dm deleted file mode 100644 index 62f4ac083bb..00000000000 --- a/code/modules/unit_tests/elements/_elements.dm +++ /dev/null @@ -1 +0,0 @@ -#include "connect_loc.dm" diff --git a/code/modules/unit_tests/emoting.dm b/code/modules/unit_tests/emoting.dm deleted file mode 100644 index 7111107b709..00000000000 --- a/code/modules/unit_tests/emoting.dm +++ /dev/null @@ -1,25 +0,0 @@ -/datum/unit_test/emoting - var/emotes_used = 0 - -/datum/unit_test/emoting/Run() - var/mob/living/carbon/human/human = allocate(/mob/living/carbon/human) - RegisterSignal(human, COMSIG_MOB_EMOTE, PROC_REF(on_emote_used)) - - human.say("*shrug") - TEST_ASSERT_EQUAL(emotes_used, 1, "Human did not shrug") - - human.say("*beep") - TEST_ASSERT_EQUAL(emotes_used, 1, "Human beeped, when that should be restricted to silicons") - - human.setOxyLoss(140) - - TEST_ASSERT(human.stat != CONSCIOUS, "Human is somehow conscious after receiving suffocation damage") - - human.say("*shrug") - TEST_ASSERT_EQUAL(emotes_used, 1, "Human shrugged while unconscious") - - human.say("*deathgasp") - TEST_ASSERT_EQUAL(emotes_used, 2, "Human could not deathgasp while unconscious") - -/datum/unit_test/emoting/proc/on_emote_used() - emotes_used += 1 diff --git a/code/modules/unit_tests/heretic_knowledge.dm b/code/modules/unit_tests/heretic_knowledge.dm deleted file mode 100644 index a433bce1ec9..00000000000 --- a/code/modules/unit_tests/heretic_knowledge.dm +++ /dev/null @@ -1,21 +0,0 @@ -/// This test checks all heretic knowledge nodes - excluding the ones which are unreachable on purpose - and ensures players can reach them in game. -/// If it finds a node that is unreachable, it throws an error. -/datum/unit_test/heretic_knowledge/Run() - ///List of all knowledge excluding the unreachable base types. - var/list/blacklist = list(/datum/eldritch_knowledge/spell,/datum/eldritch_knowledge/curse,/datum/eldritch_knowledge/final,/datum/eldritch_knowledge/summon) - var/list/all_possible_knowledge = subtypesof(/datum/eldritch_knowledge) - blacklist - - var/list/list_to_check = GLOB.heretic_start_knowledge.Copy() - var/i = 0 - while(i < length(list_to_check)) - var/datum/eldritch_knowledge/eldritch_knowledge = allocate(list_to_check[++i]) - for(var/next_knowledge in eldritch_knowledge.next_knowledge) - if(next_knowledge in list_to_check) - continue - list_to_check += next_knowledge - - if(length(all_possible_knowledge) != length(all_possible_knowledge & list_to_check)) - var/list/unreachables = all_possible_knowledge - list_to_check - for(var/X in unreachables) - var/datum/eldritch_knowledge/eldritch_knowledge = X - Fail("[initial(eldritch_knowledge.name)] is unreachable by players! Add it to the blacklist in /code/modules/unit_tests/heretic_knowledge.dm if it is purposeful!") diff --git a/code/modules/unit_tests/holidays.dm b/code/modules/unit_tests/holidays.dm deleted file mode 100644 index 4df5443e2ee..00000000000 --- a/code/modules/unit_tests/holidays.dm +++ /dev/null @@ -1,33 +0,0 @@ -// test Jewish holiday -/datum/unit_test/hanukkah_2123/Run() - var/datum/holiday/hebrew/hanukkah/hanukkah = new - TEST_ASSERT(hanukkah.shouldCelebrate(14, DECEMBER, 2123, 2, TUESDAY), "December 14, 2123 was not Hanukkah.") - -// test Islamic holiday -/datum/unit_test/ramadan_2165/Run() - var/datum/holiday/islamic/ramadan/ramadan = new - TEST_ASSERT(ramadan.shouldCelebrate(6, NOVEMBER, 2165, 1, WEDNESDAY), "November 6, 2165 was not Ramadan.") - -// nth day of week -/datum/unit_test/thanksgiving_2020/Run() - var/datum/holiday/nth_week/thanksgiving/thanksgiving = new - TEST_ASSERT(thanksgiving.shouldCelebrate(26, NOVEMBER, 2020, 4, THURSDAY), "November 26, 2020 was not Thanksgiving.") - -// another nth day of week -/datum/unit_test/indigenous_3683/Run() - var/datum/holiday/nth_week/indigenous/indigenous = new - TEST_ASSERT(indigenous.shouldCelebrate(11, OCTOBER, 3683, 2, MONDAY), "October 11, 3683 was not Indigenous Peoples' Day.") - -// plain old simple holiday -/datum/unit_test/hello_2020/Run() - var/datum/holiday/hello/hello = new - TEST_ASSERT(hello.shouldCelebrate(21, NOVEMBER, 2020, 3, SATURDAY), "November 21, 2020 was not Hello day.") - -// holiday which goes across months -/datum/unit_test/new_year_1983/Run() - var/datum/holiday/new_year/new_year = new - TEST_ASSERT(new_year.shouldCelebrate(2, JANUARY, 1983, 1, SUNDAY), "January 2, 1983 was not New Year.") - -/datum/unit_test/moth_week_2020/Run() - var/datum/holiday/moth/moth = new - TEST_ASSERT(moth.shouldCelebrate(19, JULY, 2020, 3, SATURDAY), "July 19, 2020 was not Moth Week.") diff --git a/code/modules/unit_tests/keybinding_init.dm b/code/modules/unit_tests/keybinding_init.dm deleted file mode 100644 index 2bd2fdee1e2..00000000000 --- a/code/modules/unit_tests/keybinding_init.dm +++ /dev/null @@ -1,6 +0,0 @@ -/datum/unit_test/keybinding_init/Run() - for(var/i in subtypesof(/datum/keybinding)) - var/datum/keybinding/KB = i - if(initial(KB.keybind_signal) || !initial(KB.name)) - continue - Fail("[KB.name] does not have a keybind signal defined.") diff --git a/code/modules/unit_tests/loadout_tests.dm b/code/modules/unit_tests/loadout_tests.dm index 03f21640608..0e633481bef 100644 --- a/code/modules/unit_tests/loadout_tests.dm +++ b/code/modules/unit_tests/loadout_tests.dm @@ -1,10 +1,25 @@ /datum/unit_test/loadout_test_shall_have_name_cost_path/Run() - for(var/geartype in typesof(/datum/loadout_entry) - /datum/loadout_entry) + var/list/ignorelist = list( + /datum/loadout_entry/seasonal, + /datum/loadout_entry/seasonal/christmas, + /datum/loadout_entry/seasonal/halloween, + /datum/loadout_entry/seasonal/masquarade, + /datum/loadout_entry/seasonal/masquarade/syndicate, + /datum/loadout_entry/seasonal/masquarade/changeling, + /datum/loadout_entry/seasonal/masquarade/clockcult, + /datum/loadout_entry/seasonal/masquarade/cult, + /datum/loadout_entry/seasonal/masquarade/wizard, + /datum/loadout_entry/seasonal/masquarade/ninja, + /datum/loadout_entry/seasonal/masquarade/aesthetic, + /datum/loadout_entry/seasonal/masquarade/dancer, + /datum/loadout_entry/seasonal/masquarade/heretic + ) + for(var/geartype in subtypesof(/datum/loadout_entry) - ignorelist) var/datum/loadout_entry/G = geartype - if(!initial(G.display_name)) - Fail("[G]: Loadout - Missing display name.") - else if(isnull(initial(G.cost))) - Fail("[G]: Loadout - Missing cost.") + // if(!initial(G.display_name)) + // TEST_FAIL("[G]: Loadout - Missing display name.") + if(isnull(initial(G.cost))) + TEST_FAIL("[G]: Loadout - Missing cost.") else if(!initial(G.path)) - Fail("[G]: Loadout - Missing path definition.") + TEST_FAIL("[G]: Loadout - Missing path definition.") diff --git a/code/modules/unit_tests/machine_disassembly.dm b/code/modules/unit_tests/machine_disassembly.dm deleted file mode 100644 index 59edb4ae9db..00000000000 --- a/code/modules/unit_tests/machine_disassembly.dm +++ /dev/null @@ -1,12 +0,0 @@ -/// Ensures that when disassembling a machine, all the parts are given back -/datum/unit_test/machine_disassembly/Run() - var/obj/machinery/freezer = allocate(/obj/machinery/atmospherics/components/unary/thermomachine/freezer) - - var/turf/freezer_location = freezer.loc - freezer.deconstruct() - - // Check that the components are created - TEST_ASSERT(locate(/obj/item/stock_parts/micro_laser) in freezer_location, "Couldn't find micro-laser when disassembling freezer") - - // Check that the circuit board itself is created - TEST_ASSERT(locate(/obj/item/circuitboard/machine/thermomachine) in freezer_location, "Couldn't find the circuit board when disassembling freezer") diff --git a/code/modules/unit_tests/map_tests.dm b/code/modules/unit_tests/map_tests.dm deleted file mode 100644 index 113c5647a6c..00000000000 --- a/code/modules/unit_tests/map_tests.dm +++ /dev/null @@ -1,102 +0,0 @@ -/datum/unit_test/apc_area_test - name = "MAP: Area Test APC / Scrubbers / Vents Z level 1" - -/datum/unit_test/apc_area_test/Run() - 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 += (LEGACY_MAP_DATUM).unit_test_exempt_areas.Copy() - exempt_from_atmos += (LEGACY_MAP_DATUM).unit_test_exempt_from_atmos.Copy() - exempt_from_apc += (LEGACY_MAP_DATUM).unit_test_exempt_from_apc.Copy() - - var/list/zs_to_test = (LEGACY_MAP_DATUM).unit_test_z_levels || list(1) //Either you set it, or you just get z1 - - for(var/area/A in GLOB.sortedAreas) - 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])" - - - if(isnull(A.apc) && !(A.type in exempt_from_apc)) - Fail("[bad_msg] lacks an APC.") - - if(!A.air_scrub_info.len && !(A.type in exempt_from_atmos)) - Fail("[bad_msg] lacks an Air scrubber.") - - if(!A.air_vent_info.len && !(A.type in exempt_from_atmos)) - Fail("[bad_msg] lacks an Air vent.") - -/datum/unit_test/wire_test - name = "MAP: Cable Test Z level 1" - -/datum/unit_test/wire_test/Run() - 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() - - for(C in world) - T = null - - T = get_turf(C) - if(T && T.z == 1) - cable_turfs |= get_turf(C) - - for(T in cable_turfs) - var/bad_msg = "--------------- [T.name] \[[T.x] / [T.y] / [T.z]\]" - dirs_checked.Cut() - for(C in T) - wire_test_count++ - var/combined_dir = "[C.d1]-[C.d2]" - if(combined_dir in dirs_checked) - Fail("[bad_msg] Contains multiple wires with same direction on top of each other.") - dirs_checked.Add(combined_dir) - -/datum/unit_test/active_edges - name = "MAP: Active edges (all maps)" - -/datum/unit_test/active_edges/Run() - - var/active_edges = SSair.active_edges.len - var/list/edge_log = list() - if(active_edges) - for(var/datum/zas_edge/E in SSair.active_edges) - edge_log += "Active Edge [E] ([E.type])" - for(var/turf/T in E.connecting_turfs) - edge_log += "+--- Connecting Turf [T] @ [T.x], [T.y], [T.z]" - - if(active_edges) - Fail("Maps contained [active_edges] active edges at round-start.\n" + edge_log.Join("\n")) diff --git a/code/modules/unit_tests/mapping.dm b/code/modules/unit_tests/mapping.dm new file mode 100644 index 00000000000..dd712779220 --- /dev/null +++ b/code/modules/unit_tests/mapping.dm @@ -0,0 +1,19 @@ +/// Conveys all log_mapping messages as unit test failures, as they all indicate mapping problems. +/datum/unit_test/log_mapping + // Happen before all other tests, to make sure we only capture normal mapping logs. + priority = TEST_PRE + +/datum/unit_test/log_mapping/Run() + var/static/regex/test_areacoord_regex = regex(@"\(-?\d+,-?\d+,(-?\d+)\)") + + for(var/log_entry in GLOB.unit_test_mapping_logs) + // Only fail if AREACOORD was conveyed, and it's a station or mining z-level. + // This is due to mapping errors don't have coords being impossible to diagnose as a unit test, + // and various ruins frequently intentionally doing non-standard things. + if(!test_areacoord_regex.Find(log_entry)) + continue + var/z = text2num(test_areacoord_regex.group[1]) + if(!isStationLevel(z)) + continue + + TEST_FAIL(log_entry) diff --git a/code/modules/unit_tests/materials.dm b/code/modules/unit_tests/materials.dm index 622b1e044e7..479a3bbd203 100644 --- a/code/modules/unit_tests/materials.dm +++ b/code/modules/unit_tests/materials.dm @@ -1,18 +1,18 @@ // checks hardcoded only (duh!!) /datum/unit_test/materials_shall_have_ids/Run() var/list/ids = list() - for(var/path in subtypesof(/datum/material)) + for(var/path in subtypesof(/datum/material) - list(/datum/material/hydrogen)) var/datum/material/M = path // for now we only check initial(). var/id = initial(M.id) if(isnull(id)) - Fail("null id on [path]") + TEST_FAIL("null id on [path]") continue if(ids[id]) - Fail("duplicate id [id] on [path] vs [ids[id]]") + TEST_FAIL("duplicate id [id] on [path] vs [ids[id]]") continue ids[id] = path M = new path if(M.id != initial(M.id)) - Fail("id changed on [path] after New(); this behavior will cause things to break.") + TEST_FAIL("id changed on [path] after New(); this behavior will cause things to break.") continue diff --git a/code/modules/unit_tests/medical_wounds.dm b/code/modules/unit_tests/medical_wounds.dm deleted file mode 100644 index 75c08931f16..00000000000 --- a/code/modules/unit_tests/medical_wounds.dm +++ /dev/null @@ -1,87 +0,0 @@ -/// This test is used to make sure a flesh-and-bone base human can suffer all the types of wounds, and that suffering more severe wounds removes and replaces the lesser wound. Also tests that [/mob/living/carbon/proc/fully_heal] removes all wounds -/datum/unit_test/test_human_base/Run() - var/mob/living/carbon/human/victim = allocate(/mob/living/carbon/human) - - /// the limbs have no wound resistance like the chest and head do, so let's go with the r_arm - var/obj/item/bodypart/tested_part = victim.get_bodypart(BODY_ZONE_R_ARM) - /// In order of the wound types we're trying to inflict, what sharpness do we need to deal them? - var/list/sharps = list(SHARP_NONE, SHARP_EDGED, SHARP_POINTY, SHARP_NONE) - /// Since burn wounds need burn damage, duh - var/list/dam_types = list(BRUTE, BRUTE, BRUTE, BURN) - - var/i = 1 - var/list/iter_test_wound_list - - for(iter_test_wound_list in list(list(/datum/wound/blunt/moderate, /datum/wound/blunt/severe, /datum/wound/blunt/critical),\ - list(/datum/wound/slash/moderate, /datum/wound/slash/severe, /datum/wound/slash/critical),\ - list(/datum/wound/pierce/moderate, /datum/wound/pierce/severe, /datum/wound/pierce/critical),\ - list(/datum/wound/burn/moderate, /datum/wound/burn/severe, /datum/wound/burn/critical))) - - TEST_ASSERT_EQUAL(length(victim.all_wounds), 0, "Patient is somehow wounded before test") - var/datum/wound/iter_test_wound - var/threshold_penalty = 0 - - for(iter_test_wound in iter_test_wound_list) - var/threshold = initial(iter_test_wound.threshold_minimum) - threshold_penalty // just enough to guarantee the next tier of wound, given the existing wound threshold penalty - if(dam_types[i] == BRUTE) - tested_part.receive_damage(WOUND_MINIMUM_DAMAGE, 0, wound_bonus = threshold, sharpness=sharps[i]) - else if(dam_types[i] == BURN) - tested_part.receive_damage(0, WOUND_MINIMUM_DAMAGE, wound_bonus = threshold, sharpness=sharps[i]) - - TEST_ASSERT(length(victim.all_wounds), "Patient has no wounds when one wound is expected. Severity: [initial(iter_test_wound.severity)]") - TEST_ASSERT_EQUAL(length(victim.all_wounds), 1, "Patient has more than one wound when only one is expected. Severity: [initial(iter_test_wound.severity)]") - var/datum/wound/actual_wound = victim.all_wounds[1] - TEST_ASSERT_EQUAL(actual_wound.type, iter_test_wound, "Patient has wound of incorrect severity. Expected: [initial(iter_test_wound.name)] Got: [actual_wound]") - threshold_penalty = actual_wound.threshold_penalty - i++ - victim.fully_heal(TRUE) // should clear all wounds between types - - -/// This test is used for making sure species with bones but no flesh (skeletons, plasmamen) can only suffer BONE_WOUNDS, and nothing tagged with FLESH_WOUND (it's possible to require both) -/datum/unit_test/test_human_bone/Run() - var/mob/living/carbon/human/victim = allocate(/mob/living/carbon/human) - - /// the limbs have no wound resistance like the chest and head do, so let's go with the r_arm - var/obj/item/bodypart/tested_part = victim.get_bodypart(BODY_ZONE_R_ARM) - /// In order of the wound types we're trying to inflict, what sharpness do we need to deal them? - var/list/sharps = list(SHARP_NONE, SHARP_EDGED, SHARP_POINTY, SHARP_NONE) - /// Since burn wounds need burn damage, duh - var/list/dam_types = list(BRUTE, BRUTE, BRUTE, BURN) - - var/i = 1 - var/list/iter_test_wound_list - victim.dna.species.species_traits &= HAS_FLESH // take away the base human's flesh (ouchie!) ((not actually ouchie, this just affects their wounds and dismemberment handling)) - - for(iter_test_wound_list in list(list(/datum/wound/blunt/moderate, /datum/wound/blunt/severe, /datum/wound/blunt/critical),\ - list(/datum/wound/slash/moderate, /datum/wound/slash/severe, /datum/wound/slash/critical),\ - list(/datum/wound/pierce/moderate, /datum/wound/pierce/severe, /datum/wound/pierce/critical),\ - list(/datum/wound/burn/moderate, /datum/wound/burn/severe, /datum/wound/burn/critical))) - - TEST_ASSERT_EQUAL(length(victim.all_wounds), 0, "Patient is somehow wounded before test") - var/datum/wound/iter_test_wound - var/threshold_penalty = 0 - - for(iter_test_wound in iter_test_wound_list) - var/threshold = initial(iter_test_wound.threshold_minimum) - threshold_penalty // just enough to guarantee the next tier of wound, given the existing wound threshold penalty - if(dam_types[i] == BRUTE) - tested_part.receive_damage(WOUND_MINIMUM_DAMAGE, 0, wound_bonus = threshold, sharpness=sharps[i]) - else if(dam_types[i] == BURN) - tested_part.receive_damage(0, WOUND_MINIMUM_DAMAGE, wound_bonus = threshold, sharpness=sharps[i]) - - // so if we just tried to deal a flesh wound, make sure we didn't actually suffer it. We may have suffered a bone wound instead, but we just want to make sure we don't have a flesh wound - if(initial(iter_test_wound.wound_flags) & FLESH_WOUND) - if(!length(victim.all_wounds)) // not having a wound is good news - continue - else // we have to check that it's actually a bone wound and not the intended wound type - TEST_ASSERT_EQUAL(length(victim.all_wounds), 1, "Patient has more than one wound when only one is expected. Severity: [initial(iter_test_wound.severity)]") - var/datum/wound/actual_wound = victim.all_wounds[1] - TEST_ASSERT((actual_wound.wound_flags & ~FLESH_WOUND), "Patient has flesh wound despite no HAS_FLESH flag, expected either no wound or bone wound. Offending wound: [actual_wound]") - threshold_penalty = actual_wound.threshold_penalty - else // otherwise if it's a bone wound, check that we have it per usual - TEST_ASSERT(length(victim.all_wounds), "Patient has no wounds when one wound is expected. Severity: [initial(iter_test_wound.severity)]") - TEST_ASSERT_EQUAL(length(victim.all_wounds), 1, "Patient has more than one wound when only one is expected. Severity: [initial(iter_test_wound.severity)]") - var/datum/wound/actual_wound = victim.all_wounds[1] - TEST_ASSERT_EQUAL(actual_wound.type, iter_test_wound, "Patient has wound of incorrect severity. Expected: [initial(iter_test_wound.name)] Got: [actual_wound]") - threshold_penalty = actual_wound.threshold_penalty - i++ - victim.fully_heal(TRUE) // should clear all wounds between types diff --git a/code/modules/unit_tests/merge_type.dm b/code/modules/unit_tests/merge_type.dm deleted file mode 100644 index ba3cfcf492b..00000000000 --- a/code/modules/unit_tests/merge_type.dm +++ /dev/null @@ -1,15 +0,0 @@ -/datum/unit_test/merge_type/Run() - var/list/blacklist = list(/obj/item/stack/sheet, - /obj/item/stack/sheet/mineral, - /obj/item/stack/ore, - /obj/item/stack/spacecash, - // /obj/item/stack/license_plates, - /obj/item/stack/tile/mineral, - /obj/item/stack/tile) - - var/list/paths = subtypesof(/obj/item/stack) - blacklist - - for(var/stackpath in paths) - var/obj/item/stack/stack = stackpath - if(!initial(stack.merge_type)) - Fail("([stack]) lacks set merge_type variable!") diff --git a/code/modules/unit_tests/metabolizing.dm b/code/modules/unit_tests/metabolizing.dm deleted file mode 100644 index 1096cb5f4fa..00000000000 --- a/code/modules/unit_tests/metabolizing.dm +++ /dev/null @@ -1,38 +0,0 @@ -/datum/unit_test/metabolization/Run() - // Pause natural mob life so it can be handled entirely by the test - SSmobs.pause() - - var/mob/living/carbon/human/human = allocate(/mob/living/carbon/human) - var/mob/living/carbon/monkey/monkey = allocate(/mob/living/carbon/monkey) - - for (var/reagent_type in subtypesof(/datum/reagent)) - test_reagent(human, reagent_type) - test_reagent(monkey, reagent_type) - -/datum/unit_test/metabolization/proc/test_reagent(mob/living/carbon/C, reagent_type) - C.reagents.add_reagent(reagent_type, 10) - C.reagents.metabolize(C, can_overdose = TRUE) - C.reagents.clear_reagents() - -/datum/unit_test/metabolization/Destroy() - SSmobs.ignite() - return ..() - -/datum/unit_test/on_mob_end_metabolize/Run() - var/mob/living/carbon/human/user = allocate(/mob/living/carbon/human) - var/obj/item/reagent_containers/pill/pill = allocate(/obj/item/reagent_containers/pill) - var/datum/reagent/drug/methamphetamine/meth = /datum/reagent/drug/methamphetamine - - // Give them enough meth to be consumed in 2 metabolizations - pill.reagents.add_reagent(meth, initial(meth.metabolization_rate) * 1.9) - pill.melee_interaction_chain(user, user) - - user.Life() - - TEST_ASSERT(user.reagents.has_reagent(meth), "User does not have meth in their system after consuming it") - TEST_ASSERT(user.has_movespeed_modifier(/datum/movespeed_modifier/reagent/methamphetamine), "User consumed meth, but did not gain movespeed modifier") - - user.Life() - - TEST_ASSERT(!user.reagents.has_reagent(meth), "User still has meth in their system when it should've finished metabolizing") - TEST_ASSERT(!user.has_movespeed_modifier(/datum/movespeed_modifier/reagent/methamphetamine), "User still has movespeed modifier despite not containing any more meth") diff --git a/code/modules/unit_tests/mob_tests.dm b/code/modules/unit_tests/mob_tests.dm deleted file mode 100644 index 48fd6a7b243..00000000000 --- a/code/modules/unit_tests/mob_tests.dm +++ /dev/null @@ -1,15 +0,0 @@ -/datum/unit_test/space_suffocation - var/startOxyloss - var/endOxyloss - var/mob/living/carbon/human/H - -/datum/unit_test/space_suffocation/Run() - var/turf/space/T = locate() - - H = allocate(/mob/living/carbon/human, T) - startOxyloss = H.getOxyLoss() - sleep(10 SECONDS) - endOxyloss = H.getOxyLoss() - - if(startOxyloss >= endOxyloss) - Fail("Human mob is not taking oxygen damage in space. (Before: [startOxyloss]; after: [endOxyloss])") diff --git a/code/modules/unit_tests/outfit_sanity.dm b/code/modules/unit_tests/outfit_sanity.dm deleted file mode 100644 index fa2ba5c2710..00000000000 --- a/code/modules/unit_tests/outfit_sanity.dm +++ /dev/null @@ -1,50 +0,0 @@ -#define CHECK_OUTFIT_SLOT(outfit_key, slot_id) if (outfit.##outfit_key) { \ - H.equip_to_slot_or_del(new outfit.##outfit_key(H), ##slot_id, TRUE); \ - /* We don't check the result of equip_to_slot_or_del because it returns false for random jumpsuits, as they delete themselves on init */ \ - if (!H.get_item_by_slot(##slot_id)) { \ - Fail("[outfit.name]'s [#outfit_key] is invalid!"); \ - } \ -} - -/datum/unit_test/outfit_sanity/Run() - var/mob/living/carbon/human/H = allocate(/mob/living/carbon/human) - - for (var/outfit_type in subtypesof(/datum/outfit)) - // Only make one human and keep undressing it because it's much faster - for (var/obj/item/I in H.get_equipped_items(include_pockets = TRUE)) - qdel(I) - - var/datum/outfit/outfit = new outfit_type - outfit.pre_equip(H, TRUE) - - CHECK_OUTFIT_SLOT(uniform, ITEM_SLOT_ICLOTHING) - CHECK_OUTFIT_SLOT(suit, ITEM_SLOT_OCLOTHING) - CHECK_OUTFIT_SLOT(back, ITEM_SLOT_BACK) - CHECK_OUTFIT_SLOT(belt, ITEM_SLOT_BELT) - CHECK_OUTFIT_SLOT(gloves, ITEM_SLOT_GLOVES) - CHECK_OUTFIT_SLOT(shoes, ITEM_SLOT_FEET) - CHECK_OUTFIT_SLOT(head, ITEM_SLOT_HEAD) - CHECK_OUTFIT_SLOT(mask, ITEM_SLOT_MASK) - CHECK_OUTFIT_SLOT(neck, ITEM_SLOT_NECK) - CHECK_OUTFIT_SLOT(ears, ITEM_SLOT_EARS) - CHECK_OUTFIT_SLOT(glasses, ITEM_SLOT_EYES) - CHECK_OUTFIT_SLOT(id, ITEM_SLOT_ID) - CHECK_OUTFIT_SLOT(suit_store, ITEM_SLOT_SUITSTORE) - CHECK_OUTFIT_SLOT(l_pocket, ITEM_SLOT_LPOCKET) - CHECK_OUTFIT_SLOT(r_pocket, ITEM_SLOT_RPOCKET) - - if (outfit.backpack_contents || outfit.box) - var/list/backpack_contents = outfit.backpack_contents?.Copy() - if (outfit.box) - if (!backpack_contents) - backpack_contents = list() - backpack_contents.Insert(1, outfit.box) - backpack_contents[outfit.box] = 1 - - for (var/path in backpack_contents) - var/number = backpack_contents[path] || 1 - for (var/_ in 1 to number) - if (!H.equip_to_slot_or_del(new path(H), ITEM_SLOT_BACKPACK, TRUE)) - Fail("[outfit.name]'s backpack_contents are invalid! Couldn't add [path] to backpack.") - -#undef CHECK_OUTFIT_SLOT diff --git a/code/modules/unit_tests/pills.dm b/code/modules/unit_tests/pills.dm deleted file mode 100644 index 0bd82dc81d0..00000000000 --- a/code/modules/unit_tests/pills.dm +++ /dev/null @@ -1,10 +0,0 @@ -/datum/unit_test/pills/Run() - var/mob/living/carbon/human/human = allocate(/mob/living/carbon/human) - var/obj/item/reagent_containers/pill/iron/pill = allocate(/obj/item/reagent_containers/pill/iron) - - TEST_ASSERT_EQUAL(human.has_reagent(/datum/reagent/iron), FALSE, "Human somehow has iron before taking pill") - - pill.melee_interaction_chain(human, human) - human.Life() - - TEST_ASSERT(human.has_reagent(/datum/reagent/iron), "Human doesn't have iron after taking pill") diff --git a/code/modules/unit_tests/plantgrowth_tests.dm b/code/modules/unit_tests/plantgrowth_tests.dm deleted file mode 100644 index 6b40236860e..00000000000 --- a/code/modules/unit_tests/plantgrowth_tests.dm +++ /dev/null @@ -1,27 +0,0 @@ - -// Checks plants for broken tray icons. Use Advanced Proc Call to activate. -// Maybe some day it would be used as unit test. -// -------- IT IS NOW! -/datum/unit_test/plantgrowth/Run() - var/list/states = icon_states('icons/obj/hydroponics/growing.dmi') - states |= icon_states('icons/obj/hydroponics/growing_fruits.dmi') - states |= icon_states('icons/obj/hydroponics/growing_flowers.dmi') - states |= icon_states('icons/obj/hydroponics/growing_mushrooms.dmi') - states |= icon_states('icons/obj/hydroponics/growing_vegetables.dmi') - states |= icon_states('goon/icons/obj/hydroponics.dmi') - var/list/paths = subtypesof(/obj/item/seeds) - /obj/item/seeds - typesof(/obj/item/seeds/sample) - /obj/item/seeds/lavaland - - for(var/seedpath in paths) - var/obj/item/seeds/seed = new seedpath - - for(var/i in 1 to seed.growthstages) - if("[seed.icon_grow][i]" in states) - continue - Fail("[seed.name] ([seed.type]) lacks the [seed.icon_grow][i] icon!") - - if(!(seed.icon_dead in states)) - Fail("[seed.name] ([seed.type]) lacks the [seed.icon_dead] icon!") - - if(seed.icon_harvest) // mushrooms have no grown sprites, same for items with no product - if(!(seed.icon_harvest in states)) - Fail("[seed.name] ([seed.type]) lacks the [seed.icon_harvest] icon!") diff --git a/code/modules/unit_tests/quick_swap_sanity.dm b/code/modules/unit_tests/quick_swap_sanity.dm deleted file mode 100644 index bd6047755f4..00000000000 --- a/code/modules/unit_tests/quick_swap_sanity.dm +++ /dev/null @@ -1,31 +0,0 @@ -/// Test that quick swap correctly swaps items and invalidates suit storage -/datum/unit_test/quick_swap_sanity/Run() - // Create a human with a medical winter coat and a health analyzer in suit storage - var/mob/living/carbon/human/human = allocate(/mob/living/carbon/human) - - var/obj/item/coat = allocate(/obj/item/clothing/suit/hooded/wintercoat/medical) - TEST_ASSERT(human.equip_to_slot_if_possible(coat, ITEM_SLOT_OCLOTHING), "Couldn't equip winter coat") - - var/obj/item/atmos_analyzer = allocate(/obj/item/healthanalyzer) - TEST_ASSERT(human.equip_to_slot_if_possible(analyzer, ITEM_SLOT_SUITSTORE), "Couldn't equip health analyzer") - - // Then, have them quick swap between the coat and a space suit - var/obj/item/hardsuit = allocate(/obj/item/clothing/suit/space/hardsuit) - TEST_ASSERT(human.equip_to_appropriate_slot(hardsuit, swap = TRUE), "Couldn't quick swap to hardsuit") - - // Check if the human has the hardsuit on - TEST_ASSERT_EQUAL(human.wear_suit, hardsuit, "Human didn't equip the hardsuit") - - // Make sure the health analyzer was dropped as part of the swap - // Since health analyzers are an invalid suit storage item - TEST_ASSERT_EQUAL(human.s_store, null, "Human didn't drop the health analyzer") - - // Give the human an emergency oxygen tank - // This is valid suit storage for both the winter coat AND the hardsuit - var/obj/item/tank = allocate(/obj/item/tank/internals/emergency_oxygen) - TEST_ASSERT(human.equip_to_slot_if_possible(tank, ITEM_SLOT_SUITSTORE), "Couldn't equip emergency oxygen tank") - - // Now, quick swap back to the coat - // Since the tank is a valid suit storage item, it should not be dropped - TEST_ASSERT(human.equip_to_appropriate_slot(coat, swap = TRUE), "Couldn't quick swap to coat") - TEST_ASSERT_EQUAL(human.s_store, tank, "Human dropped the oxygen tank, when it was a valid item to keep in suit storage") diff --git a/code/modules/unit_tests/reactions.dm b/code/modules/unit_tests/reactions.dm deleted file mode 100644 index 66d9b490991..00000000000 --- a/code/modules/unit_tests/reactions.dm +++ /dev/null @@ -1,6 +0,0 @@ -/datum/unit_test/reactions/Run() - for(var/datum/gas_reaction/G in SSair.gas_reactions) - var/test_info = G.test() - if(!test_info["success"]) - var/message = test_info["message"] - Fail("Gas reaction [G.name] is failing its unit test with the following message: [message]") diff --git a/code/modules/unit_tests/say.dm b/code/modules/unit_tests/say.dm deleted file mode 100644 index a7df5ad624b..00000000000 --- a/code/modules/unit_tests/say.dm +++ /dev/null @@ -1,23 +0,0 @@ -/// Test to verify message mods are parsed correctly -/datum/unit_test/get_message_mods - var/mob/host_mob - -/datum/unit_test/get_message_mods/Run() - host_mob = allocate(/mob/living/carbon/human) - - test("Hello", "Hello", list()) - test(";HELP", "HELP", list(MODE_HEADSET = TRUE)) - test(";%Never gonna give you up", "Never gonna give you up", list(MODE_HEADSET = TRUE, MODE_SING = TRUE)) - test(".s Gun plz", "Gun plz", list(RADIO_KEY = RADIO_KEY_SECURITY, RADIO_EXTENSION = RADIO_CHANNEL_SECURITY)) - test("...What", "...What", list()) - -/datum/unit_test/get_message_mods/proc/test(message, expected_message, list/expected_mods) - var/list/mods = list() - TEST_ASSERT_EQUAL(host_mob.get_message_mods(message, mods), expected_message, "Chopped message was not what we expected. Message: [message]") - - for (var/mod_key in mods) - TEST_ASSERT_EQUAL(mods[mod_key], expected_mods[mod_key], "The value for [mod_key] was not what we expected. Message: [message]") - expected_mods -= mod_key - - if (expected_mods.len) - Fail("Some message mods were expected, but were not returned by get_message_mods: [json_encode(expected_mods)]. Message: [message]") diff --git a/code/modules/unit_tests/serving_tray.dm b/code/modules/unit_tests/serving_tray.dm deleted file mode 100644 index 92a70dfcf25..00000000000 --- a/code/modules/unit_tests/serving_tray.dm +++ /dev/null @@ -1,47 +0,0 @@ -/** - * Check that standard food items fit on the serving tray - */ -/datum/unit_test/servingtray/Run() - var/mob/living/carbon/human/human = allocate(/mob/living/carbon/human) - var/obj/structure/table/the_table = allocate(/obj/structure/table) - var/obj/item/storage/bag/tray/test_tray = allocate(/obj/item/storage/bag/tray) - var/obj/item/reagent_containers/food/banana = allocate(/obj/item/food/rationpack) - var/obj/item/food/the_bread = allocate(/obj/item/food/breadslice) - var/obj/item/reagent_containers/food/sugarcookie = allocate(/obj/item/food/cookie/sugar) - var/obj/item/clothing/under/jumpsuit = allocate(/obj/item/clothing/under/color/black) - - TEST_ASSERT_EQUAL((the_bread in test_tray.contents), FALSE, "The bread is on the serving tray at test start") - - // set the tray to single item mode the dirty way - var/datum/component/storage/tray_storage = test_tray.GetComponent(/datum/component/storage) - tray_storage.collection_mode = COLLECT_ONE - - test_tray.pre_attack(the_bread, human) - - TEST_ASSERT_EQUAL((the_bread in test_tray.contents), TRUE, "The bread did not get picked up by the serving tray") - - test_tray.pre_attack(banana, human) - - TEST_ASSERT_EQUAL((banana in test_tray.contents), TRUE, "The banana did not get picked up by the serving tray") - - the_table.attackby(test_tray, human) - - TEST_ASSERT_EQUAL(test_tray.contents.len, 0, "The serving tray did not drop all items on hitting the table") - - test_tray.pre_attack(sugarcookie, human) - - TEST_ASSERT_EQUAL((sugarcookie in test_tray.contents), TRUE, "The sugarcookie did not get picked up by the serving tray") - - human.equip_to_slot(jumpsuit, ITEM_SLOT_ICLOTHING) - TEST_ASSERT(human.get_item_by_slot(ITEM_SLOT_ICLOTHING), "Human does not have jumpsuit on") - - human.equip_to_slot(test_tray, ITEM_SLOT_LPOCKET) - TEST_ASSERT(human.get_item_by_slot(ITEM_SLOT_LPOCKET), "Serving tray failed to fit in the Left Pocket") - - human.equip_to_slot(test_tray, ITEM_SLOT_RPOCKET) - TEST_ASSERT(human.get_item_by_slot(ITEM_SLOT_RPOCKET), "Serving tray failed to fit in the Right Pocket") - - test_tray.melee_interaction_chain(human, human) - - TEST_ASSERT_EQUAL(test_tray.contents.len, 0, "The serving tray did not drop all items on hitting a human") - diff --git a/code/modules/unit_tests/siunit.dm b/code/modules/unit_tests/siunit.dm deleted file mode 100644 index 3a7a25a98d3..00000000000 --- a/code/modules/unit_tests/siunit.dm +++ /dev/null @@ -1,15 +0,0 @@ -/datum/unit_test/siunit/Run() - TEST_ASSERT_EQUAL(siunit(0.5345, "A", 0), "535 mA", "") - TEST_ASSERT_EQUAL(siunit(0.5344, "A", 0), "534 mA", "") - TEST_ASSERT_EQUAL(siunit(-0.5344, "A", 0), "-534 mA", "") - TEST_ASSERT_EQUAL(siunit_pressure(1.234, 1), "1.2 kPa", "") // test for pascal require *10e-3, as the game thinks in kPa, the proc siunit in Pa - TEST_ASSERT_EQUAL(siunit_pressure(1.234, 2), "1.23 kPa", "") - TEST_ASSERT_EQUAL(siunit_pressure(1.234, 3), "1.234 kPa", "") - TEST_ASSERT_EQUAL(siunit_pressure(1, 4), "1 kPa", "") - TEST_ASSERT_EQUAL(siunit_pressure(0), "0 Pa", "") - TEST_ASSERT_EQUAL(siunit_pressure(1e3), "1 MPa", "") - TEST_ASSERT_EQUAL(siunit_pressure(999e3), "999 MPa", "") - TEST_ASSERT_EQUAL(siunit_pressure(999.9e3), "999.9 MPa" , "") - TEST_ASSERT_EQUAL(siunit_pressure(999.9e3, 0), "1 GPa", "") - TEST_ASSERT_EQUAL(siunit_pressure(1e6), "1 GPa", "") - TEST_ASSERT_EQUAL(siunit_pressure(3e17), "300000 PPa", "") diff --git a/code/modules/unit_tests/species_whitelists.dm b/code/modules/unit_tests/species_whitelists.dm deleted file mode 100644 index 145f3a259fc..00000000000 --- a/code/modules/unit_tests/species_whitelists.dm +++ /dev/null @@ -1,5 +0,0 @@ -/datum/unit_test/species_whitelist_check/Run() - for(var/typepath in subtypesof(/datum/species)) - var/datum/species/S = typepath - if(initial(S.changesource_flags) == NONE) - Fail("A species type was detected with no changesource flags: [S]") diff --git a/code/modules/unit_tests/stomach.dm b/code/modules/unit_tests/stomach.dm deleted file mode 100644 index 6dcccac92ef..00000000000 --- a/code/modules/unit_tests/stomach.dm +++ /dev/null @@ -1,40 +0,0 @@ -/datum/unit_test/stomach/Run() - - // Pause natural mob life so it can be handled entirely by the test - SSmobs.pause() - - var/mob/living/carbon/human/human = allocate(/mob/living/carbon/human) - var/obj/item/food/hotdog/debug/fooditem = allocate(/obj/item/food/hotdog/debug) - var/obj/item/organ/stomach/belly = human.getorganslot(ORGAN_SLOT_STOMACH) - var/obj/item/reagent_containers/pill/pill = allocate(/obj/item/reagent_containers/pill) - var/datum/reagent/drug/methamphetamine/meth = /datum/reagent/drug/methamphetamine - - TEST_ASSERT_EQUAL(human.has_reagent(/datum/reagent/consumable/ketchup), FALSE, "Human somehow has ketchup before eating") - - fooditem.melee_interaction_chain(human, human) - - TEST_ASSERT(belly.reagents.has_reagent(/datum/reagent/consumable/ketchup), "Stomach doesn't have ketchup after eating") - TEST_ASSERT_EQUAL(human.reagents.has_reagent(/datum/reagent/consumable/ketchup), FALSE, "Human body has ketchup after eating it should only be in the stomach") - - //Give them meth and let it kick in - pill.reagents.add_reagent(meth, initial(meth.metabolization_rate) * 1.9) - pill.melee_interaction_chain(human, human) - human.Life() - - TEST_ASSERT(human.reagents.has_reagent(meth), "Human body does not have meth after life tick") - TEST_ASSERT(human.has_movespeed_modifier(/datum/movespeed_modifier/reagent/methamphetamine), "Human consumed meth, but did not gain movespeed modifier") - - belly.Remove(human) - human.reagents.remove_all(human.reagents.total_volume) - - TEST_ASSERT_EQUAL(human.has_reagent(/datum/reagent/consumable/ketchup), FALSE, "Human has reagents after clearing") - - fooditem.melee_interaction_chain(human, human) - - TEST_ASSERT_EQUAL(human.has_reagent(/datum/reagent/consumable/ketchup), FALSE, "Human has ketchup without a stomach") - - - -/datum/unit_test/stomach/Destroy() - SSmobs.ignite() - return ..() diff --git a/code/modules/unit_tests/surgeries.dm b/code/modules/unit_tests/surgeries.dm deleted file mode 100644 index d175bfde568..00000000000 --- a/code/modules/unit_tests/surgeries.dm +++ /dev/null @@ -1,106 +0,0 @@ -/datum/unit_test/amputation/Run() - var/mob/living/carbon/human/patient = allocate(/mob/living/carbon/human) - var/mob/living/carbon/human/user = allocate(/mob/living/carbon/human) - - TEST_ASSERT_EQUAL(length(patient.get_missing_limbs()), 0, "Patient is somehow missing limbs before surgery") - - var/datum/surgery/amputation/surgery = new(patient, BODY_ZONE_R_ARM, patient.get_bodypart(BODY_ZONE_R_ARM)) - - var/datum/surgery_step/sever_limb/sever_limb = new - sever_limb.success(user, patient, BODY_ZONE_R_ARM, null, surgery) - - TEST_ASSERT_EQUAL(length(patient.get_missing_limbs()), 1, "Patient did not lose any limbs") - TEST_ASSERT_EQUAL(patient.get_missing_limbs()[1], BODY_ZONE_R_ARM, "Patient is missing a limb that isn't the one we operated on") - -/datum/unit_test/brain_surgery/Run() - var/mob/living/carbon/human/patient = allocate(/mob/living/carbon/human) - patient.gain_trauma_type(BRAIN_TRAUMA_MILD, TRAUMA_RESILIENCE_SURGERY) - patient.setOrganLoss(ORGAN_SLOT_BRAIN, 20) - - TEST_ASSERT(patient.has_trauma_type(), "Patient does not have any traumas, despite being given one") - - var/mob/living/carbon/human/user = allocate(/mob/living/carbon/human) - - var/datum/surgery_step/fix_brain/fix_brain = new - fix_brain.success(user, patient) - - TEST_ASSERT(!patient.has_trauma_type(), "Patient kept their brain trauma after brain surgery") - TEST_ASSERT(patient.getOrganLoss(ORGAN_SLOT_BRAIN) < 20, "Patient did not heal their brain damage after brain surgery") - -/datum/unit_test/head_transplant/Run() - var/mob/living/carbon/human/user = allocate(/mob/living/carbon/human) - var/mob/living/carbon/human/alice = allocate(/mob/living/carbon/human) - var/mob/living/carbon/human/bob = allocate(/mob/living/carbon/human) - - alice.fully_replace_character_name(null, "Alice") - bob.fully_replace_character_name(null, "Bob") - - var/obj/item/bodypart/head/alices_head = alice.get_bodypart(BODY_ZONE_HEAD) - alices_head.drop_limb() - - var/obj/item/bodypart/head/bobs_head = bob.get_bodypart(BODY_ZONE_HEAD) - bobs_head.drop_limb() - - TEST_ASSERT_EQUAL(alice.get_bodypart(BODY_ZONE_HEAD), null, "Alice still has a head after dismemberment") - TEST_ASSERT_EQUAL(alice.get_visible_name(), "Unknown", "Alice's head was dismembered, but they are not Unknown") - - TEST_ASSERT_EQUAL(bobs_head.real_name, "Bob", "Bob's head does not remember that it is from Bob") - - // Put Bob's head onto Alice's body - var/datum/surgery_step/add_prosthetic/add_prosthetic = new - user.put_in_active_hand(bobs_head) - add_prosthetic.success(user, alice, BODY_ZONE_HEAD, bobs_head) - - TEST_ASSERT(!isnull(alice.get_bodypart(BODY_ZONE_HEAD)), "Alice has no head after prosthetic replacement") - TEST_ASSERT_EQUAL(alice.get_visible_name(), "Bob", "Bob's head was transplanted onto Alice's body, but their name is not Bob") - -/datum/unit_test/multiple_surgeries/Run() - var/mob/living/carbon/human/user = allocate(/mob/living/carbon/human) - var/mob/living/carbon/human/patient_zero = allocate(/mob/living/carbon/human) - var/mob/living/carbon/human/patient_one = allocate(/mob/living/carbon/human) - - var/obj/item/scalpel/scalpel = allocate(/obj/item/scalpel) - - var/datum/surgery_step/incise/surgery_step = new - var/datum/surgery/organ_manipulation/surgery_for_zero = new - - INVOKE_ASYNC(surgery_step, TYPE_PROC_REF(/datum/surgery_step, initiate), user, patient_zero, BODY_ZONE_CHEST, scalpel, surgery_for_zero) - TEST_ASSERT(surgery_for_zero.step_in_progress, "Surgery on patient zero was not initiated") - - var/datum/surgery/organ_manipulation/surgery_for_one = new - - // Without waiting for the incision to complete, try to start a new surgery - TEST_ASSERT(!surgery_step.initiate(user, patient_one, BODY_ZONE_CHEST, scalpel, surgery_for_one), "Was allowed to start a second surgery without the rod of asclepius") - TEST_ASSERT(!surgery_for_one.step_in_progress, "Surgery for patient one is somehow in progress, despite not initiating") - - user.apply_status_effect(STATUS_EFFECT_HIPPOCRATIC_OATH) - INVOKE_ASYNC(surgery_step, TYPE_PROC_REF(/datum/surgery_step, initiate), user, patient_one, BODY_ZONE_CHEST, scalpel, surgery_for_one) - TEST_ASSERT(surgery_for_one.step_in_progress, "Surgery on patient one was not initiated, despite having rod of asclepius") - -/datum/unit_test/tend_wounds/Run() - var/mob/living/carbon/human/patient = allocate(/mob/living/carbon/human) - patient.take_overall_damage(100, 100) - - var/mob/living/carbon/human/user = allocate(/mob/living/carbon/human) - - // Test that tending wounds actually lowers damage - var/datum/surgery_step/heal/brute/basic/basic_brute_heal = new - basic_brute_heal.success(user, patient, BODY_ZONE_CHEST) - TEST_ASSERT(patient.getBruteLoss() < 100, "Tending brute wounds didn't lower brute damage ([patient.getBruteLoss()])") - - var/datum/surgery_step/heal/burn/basic/basic_burn_heal = new - basic_burn_heal.success(user, patient, BODY_ZONE_CHEST) - TEST_ASSERT(patient.getFireLoss() < 100, "Tending burn wounds didn't lower burn damage ([patient.getFireLoss()])") - - // Test that wearing clothing lowers heal amount - var/mob/living/carbon/human/naked_patient = allocate(/mob/living/carbon/human) - naked_patient.take_overall_damage(100) - - var/mob/living/carbon/human/clothed_patient = allocate(/mob/living/carbon/human) - clothed_patient.equipOutfit(/datum/outfit/job/doctor, TRUE) - clothed_patient.take_overall_damage(100) - - basic_brute_heal.success(user, naked_patient, BODY_ZONE_CHEST) - basic_brute_heal.success(user, clothed_patient, BODY_ZONE_CHEST) - - TEST_ASSERT(naked_patient.getBruteLoss() < clothed_patient.getBruteLoss(), "Naked patient did not heal more from wounds tending than a clothed patient") diff --git a/code/modules/unit_tests/teleporters.dm b/code/modules/unit_tests/teleporters.dm deleted file mode 100644 index 2cb047304fb..00000000000 --- a/code/modules/unit_tests/teleporters.dm +++ /dev/null @@ -1,10 +0,0 @@ -/datum/unit_test/auto_teleporter_linking/Run() - // Put down the teleporter machinery - var/obj/machinery/teleport/hub/hub = allocate(/obj/machinery/teleport/hub) - var/obj/machinery/teleport/station/station = allocate(/obj/machinery/teleport/station, locate(run_loc_floor_bottom_left.x + 1, run_loc_floor_bottom_left.y, run_loc_floor_bottom_left.z)) - var/obj/machinery/computer/teleporter/computer = allocate(/obj/machinery/computer/teleporter, locate(run_loc_floor_bottom_left.x + 2, run_loc_floor_bottom_left.y, run_loc_floor_bottom_left.z)) - - TEST_ASSERT_EQUAL(hub.power_station, station, "Hub didn't link to the station") - TEST_ASSERT_EQUAL(station.teleporter_console, computer, "Station didn't link to the teleporter console") - TEST_ASSERT_EQUAL(station.teleporter_hub, hub, "Station didn't link to the hub") - TEST_ASSERT_EQUAL(computer.power_station, station, "Teleporter console didn't link to the hub") diff --git a/code/modules/unit_tests/unit_test.dm b/code/modules/unit_tests/unit_test.dm index 655395e7f7c..90c06488cfc 100644 --- a/code/modules/unit_tests/unit_test.dm +++ b/code/modules/unit_tests/unit_test.dm @@ -13,24 +13,24 @@ You can use the run_loc_floor_bottom_left and run_loc_floor_top_right to get tur GLOBAL_DATUM(current_test, /datum/unit_test) GLOBAL_VAR_INIT(failed_any_test, FALSE) -GLOBAL_VAR(test_log) /// When unit testing, all logs sent to log_mapping are stored here and retrieved in log_mapping unit test. GLOBAL_LIST_EMPTY(unit_test_mapping_logs) +/// Global assoc list of required mapping items, [item typepath] to [required item datum]. +GLOBAL_LIST_EMPTY(required_map_items) -/// The name of the test that is currently focused. +/// A list of every test that is currently focused. /// Use the PERFORM_ALL_TESTS macro instead. -GLOBAL_VAR_INIT(focused_test, focused_test()) +GLOBAL_VAR_INIT(focused_tests, focused_tests()) -/proc/focused_test() +/proc/focused_tests() + var/list/focused_tests = list() for (var/datum/unit_test/unit_test as anything in subtypesof(/datum/unit_test)) if (initial(unit_test.focus)) - return unit_test - return null + focused_tests += unit_test -/datum/unit_test - /// Abstract type of the test - abstract_type = /datum/unit_test + return focused_tests.len > 0 ? focused_tests : null +/datum/unit_test //Bit of metadata for the future maybe var/list/procs_tested @@ -47,6 +47,9 @@ GLOBAL_VAR_INIT(focused_test, focused_test()) var/list/allocated var/list/fail_reasons + /// Do not instantiate if type matches this + abstract_type = /datum/unit_test + var/static/datum/map_level/reservation /proc/cmp_unit_test_priority(datum/unit_test/a, datum/unit_test/b) @@ -66,7 +69,7 @@ GLOBAL_VAR_INIT(focused_test, focused_test()) /datum/unit_test/Destroy() QDEL_LIST(allocated) // clear the test area - for (var/turf/turf in block(locate(1, 1, run_loc_floor_bottom_left.z), locate(world.maxx, world.maxy, run_loc_floor_bottom_left.z))) + for (var/turf/turf in Z_TURFS(run_loc_floor_bottom_left.z)) for (var/content in turf.contents) if (istype(content, /obj/landmark)) continue @@ -74,7 +77,7 @@ GLOBAL_VAR_INIT(focused_test, focused_test()) return ..() /datum/unit_test/proc/Run() - TEST_FAIL("Run() called parent or not implemented") + TEST_FAIL("[type]/Run() called parent or not implemented") /datum/unit_test/proc/Fail(reason = "No reason", file = "OUTDATED_TEST", line = 1) succeeded = FALSE @@ -126,6 +129,16 @@ GLOBAL_VAR_INIT(focused_test, focused_test()) log_test("\t[path_prefix]_[name] was put in data/screenshots_new") +/// Helper for screenshot tests to take an image of an atom from all directions and insert it into one icon +/datum/unit_test/proc/get_flat_icon_for_all_directions(atom/thing, no_anim = TRUE) + var/icon/output = icon('icons/effects/effects.dmi', "nothing") + + for (var/direction in GLOB.cardinal) + var/icon/partial = get_flat_icon(thing, dir = direction, no_anim = no_anim) + output.Insert(partial, dir = direction) + + return output + /// Logs a test message. Will use GitHub action syntax found at https://docs.github.com/en/actions/using-workflows/workflow-commands-for-github-actions /datum/unit_test/proc/log_for_test(text, priority, file, line) var/map_name = (LEGACY_MAP_DATUM).name @@ -136,16 +149,22 @@ GLOBAL_VAR_INIT(focused_test, focused_test()) log_world("::[priority] file=[file],line=[line],title=[map_name]: [type]::[annotation_text]") -/proc/RunUnitTest(test_path, list/test_results) - if (ispath(test_path, /datum/unit_test/focus_only)) +/proc/RunUnitTest(datum/unit_test/test_path, list/test_results) + if(ispath(test_path, /datum/unit_test/focus_only)) + return + + if(initial(test_path.abstract_type) == test_path) return var/datum/unit_test/test = new test_path GLOB.current_test = test var/duration = REALTIMEOFDAY + var/test_output_desc = "[test_path]" + var/message = "" log_world("::group::[test_path]") + test.Run() duration = REALTIMEOFDAY - duration @@ -165,10 +184,11 @@ GLOBAL_VAR_INIT(focused_test, focused_test()) // Normal log message log_entry += "\tFAILURE #[reasonID]: [text] at [file]:[line]" - var/message = log_entry.Join("\n") - log_test(message) + if(length(log_entry)) + message = log_entry.Join("\n") + log_test(message) - var/test_output_desc = "[test_path] [duration / 10]s" + test_output_desc += " [duration / 10]s" if (test.succeeded) log_world("[TEST_OUTPUT_GREEN("PASS")] [test_output_desc]") @@ -177,7 +197,8 @@ GLOBAL_VAR_INIT(focused_test, focused_test()) if (!test.succeeded) log_world("::error::[TEST_OUTPUT_RED("FAIL")] [test_output_desc]") - test_results[test_path] = list("status" = test.succeeded ? UNIT_TEST_PASSED : UNIT_TEST_FAILED, "message" = message, "name" = test_path) + var/final_status = (test.succeeded ? UNIT_TEST_PASSED : UNIT_TEST_FAILED) + test_results[test_path] = list("status" = final_status, "message" = message, "name" = test_path) qdel(test) @@ -188,9 +209,6 @@ GLOBAL_VAR_INIT(focused_test, focused_test()) var/list/focused_tests = list() for (var/_test_to_run in tests_to_run) var/datum/unit_test/test_to_run = _test_to_run - if(initial(test_to_run.abstract_type) == test_to_run) - tests_to_run -= test_to_run - continue if (initial(test_to_run.focus)) focused_tests += test_to_run if(length(focused_tests)) @@ -200,18 +218,20 @@ GLOBAL_VAR_INIT(focused_test, focused_test()) var/list/test_results = list() + //Hell code, we're bound to end the round somehow so let's stop if from ending while we work + SSticker.delay_end = TRUE for(var/unit_path in tests_to_run) CHECK_TICK //We check tick first because the unit test we run last may be so expensive that checking tick will lock up this loop forever RunUnitTest(unit_path, test_results) + SSticker.delay_end = FALSE var/file_name = "data/unit_tests.json" fdel(file_name) file(file_name) << json_encode(test_results) SSticker.force_ending = TRUE - sleep(5 SECONDS) //We have to call this manually because del_text can preceed us, and SSticker doesn't fire in the post game - SSticker.standard_reboot() + SSticker.declare_completion() /datum/map_level/unit_tests id = "__UnitTestLevel" diff --git a/code/modules/unit_tests/vore_tests.dm b/code/modules/unit_tests/vore_tests.dm deleted file mode 100644 index 79cbee067e1..00000000000 --- a/code/modules/unit_tests/vore_tests.dm +++ /dev/null @@ -1,176 +0,0 @@ -/datum/unit_test - var/static/default_mobloc = null - -/datum/unit_test/proc/stupid_vore_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 = allocate(/mob/living/carbon/human, mobloc) - - if(with_mind) - H.mind_initialize("TestKey[rand(0,10000)]") - - return H - -/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 - -/datum/unit_test/belly_nonsuffocation/Run() - pred = stupid_vore_test_mob() - if(!istype(pred)) - Fail("Pred allocation failed") - return - prey = stupid_vore_test_mob(pred.loc) - if(!istype(prey)) - Fail("Prey allocation failed") - return - - if(!pred.vore_organs || !pred.vore_organs.len) - Fail("Pred or prey had no vore organs") - return - - // Now that pred belly exists, we can eat the prey. - if(!pred.vore_selected) - Fail("[pred] has no vore_selected.") - return - - // 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 - - // Okay, we succeeded in eating them, now lets wait a bit - startLifeTick = pred.life_tick - startOxyloss = prey.getOxyLoss() - - sleep(10 SECONDS) - - // Alright lets check it! - endOxyloss = prey.getOxyLoss() - if(startOxyloss < endOxyloss) - Fail("Prey takes oxygen damage in a pred's belly! (Before: [startOxyloss]; after: [endOxyloss])") - -//////////////////////////////////////////////////////////////// -/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/Run() - pred = stupid_vore_test_mob() - if(!istype(pred)) - Fail("Allocation failed") - return - prey = stupid_vore_test_mob(pred.loc) - if(!istype(prey)) - Fail("Allocation failed") - return - - sleep(10 SECONDS) - - if(!pred.vore_organs || !pred.vore_organs.len) - Fail("No vore organs in pred or prey") - return - - // Now that pred belly exists, we can eat the prey. - if(!pred.vore_selected) - Fail("[pred] has no vore_selected.") - return - - // 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 - else - var/turf/T = locate(/turf/space) - if(!T) - Fail("could not find a space turf for testing") - return - else - pred.forceMove(T) - - // Okay, we succeeded in eating them, now lets wait a bit - startLifeTick = pred.life_tick - startOxyloss = prey.getOxyLoss() - - sleep(10 SECONDS) - - // Alright lets check it! - endOxyloss = prey.getOxyLoss() - if(startOxyloss < endOxyloss) - Fail("Prey takes oxygen damage in space! (Before: [startOxyloss]; after: [endOxyloss])") - -//////////////////////////////////////////////////////////////// -/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/Run() - pred = stupid_vore_test_mob() - if(!istype(pred)) - Fail("Allocation failed") - return - prey = stupid_vore_test_mob(pred.loc) - if(!istype(prey)) - Fail("Allocation failed") - return - - sleep(10 SECONDS) - - if(!pred.vore_organs || !pred.vore_organs.len) - Fail("No vore organs in pred or prey") - return - - // Now that pred belly exists, we can eat the prey. - if(!pred.vore_selected) - Fail("[pred] has no vore_selected.") - return - - // 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() - - sleep(10 SECONDS) - - // 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])") diff --git a/code/modules/unit_tests/wallmounted_obj_dirs/fire_alarms.dm b/code/modules/unit_tests/wallmounted_obj_dirs/fire_alarms.dm index 5e17b8d2e28..6b856807560 100644 --- a/code/modules/unit_tests/wallmounted_obj_dirs/fire_alarms.dm +++ b/code/modules/unit_tests/wallmounted_obj_dirs/fire_alarms.dm @@ -7,4 +7,4 @@ TEST_FAIL("One or more alarms had a non-cardinal direction!") for(var/obj/I in bad_alarms) TEST_FAIL("[I] at X [bad_alarms[I]["X"]] Y [bad_alarms[I]["Y"]] Z [bad_alarms[I]["Z"]] in area [bad_alarms[I]["A"]]") - Fail("There were [length(bad_alarms)] alarms with non-cardinal directions.") + TEST_FAIL("There were [length(bad_alarms)] alarms with non-cardinal directions.") diff --git a/code/modules/unit_tests/zas_tests.dm b/code/modules/unit_tests/zas_tests.dm deleted file mode 100644 index 62ad5a95666..00000000000 --- a/code/modules/unit_tests/zas_tests.dm +++ /dev/null @@ -1,119 +0,0 @@ -#define UT_NORMAL 1 -#define UT_VACUUM 2 -#define UT_NORMAL_COLD 3 - -/datum/unit_test/zas_area_test - name = "ZAS: Area Test Template" - var/area_path = null - var/expectation = UT_NORMAL - -/datum/unit_test/zas_area_test/proc/test_air_in_area(var/test_area, var/expectation = UT_NORMAL) - var/test_result = list("result" = 0, "msg" = "") - - var/area/A = locate(test_area) - - if(!istype(A, test_area)) - test_result["msg"] = "Unable to get [test_area]" - return test_result - - var/list/GM_checked = list() - - for(var/turf/simulated/T in A) - if(!istype(T) || isnull(T.zone) || istype(T, /turf/simulated/floor/airless) || istype(T,/turf/simulated/shuttle/plating/airless)) - continue - if(T.zone.air in GM_checked) - continue - - var/t_msg = "Turf: [T] | Location: [T.x] // [T.y] // [T.z]" - - var/datum/gas_mixture/GM = T.return_air() - var/pressure = GM.return_pressure() - var/temp = GM.temperature - - switch(expectation) - - if(UT_VACUUM) - if(pressure > 10) - test_result["msg"] = "Pressure out of bounds: [pressure] | [t_msg]" - return test_result - - - if(UT_NORMAL || UT_NORMAL_COLD) - if(abs(pressure - ONE_ATMOSPHERE) > 10) - test_result["msg"] = "Pressure out of bounds: [pressure] | [t_msg]" - return test_result - - if(expectation == UT_NORMAL) - - if(abs(temp - T20C) > 10) - test_result["msg"] = "Temperature out of bounds: [temp] | [t_msg]" - return test_result - - if(expectation == UT_NORMAL_COLD) - - if(temp > 120) - test_result["msg"] = "Temperature out of bounds: [temp] | [t_msg]" - return test_result - - GM_checked.Add(GM) - - if(GM_checked.len) - test_result["result"] = 1 - test_result["msg"] = "Checked [GM_checked.len] zones" - else - test_result["msg"] = "No zones checked." - - return test_result - -/datum/unit_test/zas_area_test/Run() - var/list/test = test_air_in_area(area_path, expectation) - - if(isnull(test)) - Fail("Check Runtimed") - - if(test["result"] != 1) - Fail(test["msg"]) - -/datum/unit_test/zas_area_test/supply_centcom - name = "ZAS: Supply Shuttle" - area_path = /area/shuttle/supply - -/datum/unit_test/zas_area_test/SSemergencyshuttle - name = "ZAS: Emergency Shuttle" - area_path = /area/shuttle/escape - -/datum/unit_test/zas_area_test/ai_chamber - name = "ZAS: AI Chamber" - area_path = /area/ai - -// We don't have this anymore - Tether -// /datum/unit_test/zas_area_test/mining_shuttle_at_station -// name = "ZAS: Mining Shuttle (Station)" -// area_path = /area/shuttle/mining/station - -/datum/unit_test/zas_area_test/cargo_maint - name = "ZAS: Cargo Maintenance" - area_path = /area/maintenance/cargo - -// We don't have this anymore - Tether -// /datum/unit_test/zas_area_test/eng_shuttle -// name = "ZAS: Construction Site Shuttle (Station)" -// area_path = /area/shuttle/constructionsite/station - -/datum/unit_test/zas_area_test/virology - name = "ZAS: Virology" - area_path = /area/medical/virology - -/datum/unit_test/zas_area_test/xenobio - name = "ZAS: Xenobiology" - area_path = /area/rnd/xenobiology - -// Citadel Station: Mining is now in space in asteroid belts. No longer in an area/mine. Re-enable for any maps with surface mining though of course. -///datum/unit_test/zas_area_test/mining_area -// name = "ZAS: Mining Area (Vacuum)" -// area_path = /area/mine/explored -// expectation = UT_VACUUM - -/datum/unit_test/zas_area_test/cargo_bay - name = "ZAS: Cargo Bay" - area_path = /area/quartermaster/storage