Merge branch 'master' of https://github.com/tgstation/tgstation into upstream-15-10-2025

This commit is contained in:
Roxy
2025-10-15 19:34:41 -04:00
656 changed files with 24772 additions and 15866 deletions
+6 -1
View File
@@ -90,6 +90,7 @@
#include "abductor_baton_spell.dm"
#include "ablative_hud.dm"
#include "achievements.dm"
#include "alerts.dm"
#include "anchored_mobs.dm"
#include "anonymous_themes.dm"
#include "antag_conversion.dm"
@@ -109,6 +110,7 @@
#include "blindness.dm"
#include "bloody_footprints.dm"
#include "breath.dm"
#include "buckle.dm"
#include "burning.dm"
#include "cable_powernets.dm"
#include "can_see.dm"
@@ -172,7 +174,6 @@
#include "gloves_and_shoes_armor.dm"
#include "greyscale_config.dm"
#include "hallucination_icons.dm"
#include "heretic_knowledge.dm"
#include "heretic_rituals.dm"
#include "high_five.dm"
#include "holder_loving.dm"
@@ -251,6 +252,7 @@
#include "quirks.dm"
#include "range_return.dm"
#include "rcd.dm"
#include "reachable_soup.dm"
#include "reagent_container_defaults.dm"
#include "reagent_id_typos.dm"
#include "reagent_mob_expose.dm"
@@ -302,6 +304,7 @@
#include "strange_reagent.dm"
#include "strippable.dm"
#include "stuns.dm"
#include "style_hotswapping.dm"
#include "subsystem_init.dm"
#include "suit_storage_icons.dm"
#include "surgeries.dm"
@@ -314,9 +317,11 @@
#include "trait_addition_and_removal.dm"
#include "traitor.dm"
#include "traitor_mail_content_check.dm"
#include "trash_food.dm"
#include "trauma_granting.dm"
#include "turf_icons.dm"
#include "tutorial_sanity.dm"
#include "unequip_defib.dm"
#include "unit_test.dm"
#include "verify_config_tags.dm"
#include "verify_emoji_names.dm"
+32
View File
@@ -0,0 +1,32 @@
/// Tests screen alerts are clickable
/datum/unit_test/alerts
var/was_clicked = FALSE
/datum/unit_test/alerts/Run()
var/mob/living/carbon/human/dummy = allocate(/mob/living/carbon/human/consistent)
dummy.mock_client = new /datum/client_interface()
var/old_usr = usr // Click still relies on usr so let's not mess this up
usr = dummy
var/atom/movable/screen/alert/test_alert/clickme = dummy.throw_alert(TRAIT_SOURCE_UNIT_TESTS, /atom/movable/screen/alert/test_alert)
clickme.linked = src
clickme.Click()
if(!was_clicked)
TEST_FAIL("Screen alert was not clickable.")
usr = old_usr
/atom/movable/screen/alert/test_alert
var/datum/unit_test/alerts/linked
/atom/movable/screen/alert/test_alert/Click(location, control, params)
. = ..()
if(!.)
return
linked.was_clicked = TRUE
/atom/movable/screen/alert/test_alert/Destroy()
linked = null
return ..()
+2 -2
View File
@@ -1,9 +1,9 @@
/// Verifies that an area's perception of their "turfs" is correct, and no other area overlaps with them
/// Quite slow, but needed
/datum/unit_test/area_contents
/datum/unit_test/maptest_area_contents
priority = TEST_LONGER
/datum/unit_test/area_contents/Run()
/datum/unit_test/maptest_area_contents/Run()
// First, we check that there are no entries in more then one area
// That or duplicate entries
for (var/area/area_to_test in GLOB.areas)
+9 -9
View File
@@ -5,9 +5,9 @@
turf.assemble_baseturfs(initial(turf.baseturfs))
/// Validates that unmodified baseturfs tear down properly
/datum/unit_test/baseturfs_unmodified_scrape
/datum/unit_test/maptest_baseturfs_unmodified_scrape
/datum/unit_test/baseturfs_unmodified_scrape/Run()
/datum/unit_test/maptest_baseturfs_unmodified_scrape/Run()
// What this is specifically doesn't matter, just as long as the test is built for it
TEST_ASSERT_EQUAL(run_loc_floor_bottom_left.type, EXPECTED_FLOOR_TYPE, "run_loc_floor_bottom_left should be an iron floor")
@@ -21,14 +21,14 @@
run_loc_floor_bottom_left.ScrapeAway()
TEST_ASSERT_EQUAL(run_loc_floor_bottom_left.type, /turf/open/space, "Space should scrape away to space")
/datum/unit_test/baseturfs_unmodified_scrape/Destroy()
/datum/unit_test/maptest_baseturfs_unmodified_scrape/Destroy()
RESET_TO_EXPECTED(run_loc_floor_bottom_left)
return ..()
/// Validates that specially placed baseturfs tear down properly
/datum/unit_test/baseturfs_placed_on_top
/datum/unit_test/maptest_baseturfs_placed_on_top
/datum/unit_test/baseturfs_placed_on_top/Run()
/datum/unit_test/maptest_baseturfs_placed_on_top/Run()
TEST_ASSERT_EQUAL(run_loc_floor_bottom_left.type, EXPECTED_FLOOR_TYPE, "run_loc_floor_bottom_left should be an iron floor")
// Do this instead of just ChangeTurf to guarantee that baseturfs is completely default on-init behavior
@@ -40,14 +40,14 @@
run_loc_floor_bottom_left.ScrapeAway()
TEST_ASSERT_EQUAL(run_loc_floor_bottom_left.type, EXPECTED_FLOOR_TYPE, "Rock wall should've been scraped off, back into the expected type")
/datum/unit_test/baseturfs_placed_on_top/Destroy()
/datum/unit_test/maptest_baseturfs_placed_on_top/Destroy()
RESET_TO_EXPECTED(run_loc_floor_bottom_left)
return ..()
/// Validates that specially placed baseturfs BELOW tear down properly
/datum/unit_test/baseturfs_placed_on_bottom
/datum/unit_test/maptest_baseturfs_placed_on_bottom
/datum/unit_test/baseturfs_placed_on_bottom/Run()
/datum/unit_test/maptest_baseturfs_placed_on_bottom/Run()
TEST_ASSERT_EQUAL(run_loc_floor_bottom_left.type, EXPECTED_FLOOR_TYPE, "run_loc_floor_bottom_left should be an iron floor")
// Do this instead of just ChangeTurf to guarantee that baseturfs is completely default on-init behavior
@@ -68,7 +68,7 @@
run_loc_floor_bottom_left.ScrapeAway()
TEST_ASSERT_EQUAL(run_loc_floor_bottom_left.type, /turf/open/floor/plating, "Rock wall should've scraped down back to plating (because it's a wall)")
/datum/unit_test/baseturfs_placed_on_bottom/Destroy()
/datum/unit_test/maptest_baseturfs_placed_on_bottom/Destroy()
RESET_TO_EXPECTED(run_loc_floor_bottom_left)
return ..()
+1 -1
View File
@@ -1,4 +1,4 @@
#define HAS_SCREEN_OVERLAY(mob, type) (locate(type) in flatten_list(mob.screens))
#define HAS_SCREEN_OVERLAY(mob, type) (locate(type) in assoc_to_values(mob.screens))
#define HAS_CLIENT_COLOR(mob, type) (locate(type) in mob.client_colours)
/**
+36
View File
@@ -0,0 +1,36 @@
/// Test you can buckle yourself to a chair
/datum/unit_test/buckling_self
/datum/unit_test/buckling_self/Run()
var/mob/living/carbon/human/consistent/dummy = EASY_ALLOCATE()
dummy.mock_client = new()
var/obj/structure/chair/chair = EASY_ALLOCATE()
var/old_usr = usr
usr = dummy // mouse drop still uses usr
dummy.MouseDrop(chair)
if(dummy.buckled != chair)
TEST_FAIL("The dummy failed to buckle themselves to a chair via mouse drop.")
usr = old_usr
/// Test you can buckle someone else to a chair
/datum/unit_test/buckling_others
/datum/unit_test/buckling_others/Run()
var/mob/living/carbon/human/consistent/dummy = EASY_ALLOCATE()
dummy.mock_client = new()
var/mob/living/carbon/human/consistent/victim = EASY_ALLOCATE()
var/obj/structure/chair/chair = EASY_ALLOCATE()
var/old_usr = usr
usr = dummy // mouse drop still uses usr
victim.MouseDrop(chair)
if(victim.buckled != chair)
TEST_FAIL("The dummy failed to buckle the victim to a chair via mouse drop.")
usr = old_usr
+2 -2
View File
@@ -2,7 +2,7 @@
/datum/unit_test/valid_dna_infusion
/datum/unit_test/valid_dna_infusion/Run()
for(var/datum/infuser_entry/infuser_entry as anything in flatten_list(GLOB.infuser_entries))
for(var/datum/infuser_entry/infuser_entry as anything in assoc_to_values(GLOB.infuser_entries))
for(var/input_type in infuser_entry.input_obj_or_mob)
if(ispath(input_type, /mob/living))
continue
@@ -35,7 +35,7 @@
/datum/infuser_entry/fly,
))
// Fetch the globally instantiated DNA Infuser entries.
for(var/datum/infuser_entry/infuser_entry as anything in flatten_list(GLOB.infuser_entries))
for(var/datum/infuser_entry/infuser_entry as anything in assoc_to_values(GLOB.infuser_entries))
var/output_organs = infuser_entry.output_organs
var/mob/living/carbon/human/lab_rat = allocate(/mob/living/carbon/human/consistent)
// BUBBER EDIT ADDITION BEGIN - Customization
@@ -30,6 +30,9 @@
/// Checks that nightvision eyes have a full set of color lists
/datum/unit_test/focus_only/nightvision_color_cutoffs
/// Ensures that items that got the nullrod_core element with the chaptain_spawnable arg can be selected by the chaplain
/datum/unit_test/focus_only/nullrod_variants
/// Checks that no light shares a tile/pixel offsets with another
/datum/unit_test/focus_only/stacked_lights
+2 -2
View File
@@ -1,8 +1,8 @@
///ensures that get_turf_pixel() returns turfs within the bounds of the map,
///even when called on a movable with its sprite out of bounds
/datum/unit_test/get_turf_pixel
/datum/unit_test/maptest_get_turf_pixel
/datum/unit_test/get_turf_pixel/Run()
/datum/unit_test/maptest_get_turf_pixel/Run()
//we need long larry to peek over the top edge of the earth
var/turf/north = locate(1, world.maxy, run_loc_floor_bottom_left.z)
@@ -1,46 +0,0 @@
/*
* This test checks all heretic knowledge nodes and validates they are setup correctly.
* We check that all knowledge is reachable by players (through the research tree)
* and that all knowledge have a valid next_knowledge list.
*/
/datum/unit_test/heretic_knowledge
/datum/unit_test/heretic_knowledge/Run()
if(!GLOB.heretic_research_tree)
GLOB.heretic_research_tree = generate_heretic_research_tree()
// First, we get a list of all knowledge types
// EXCLUDING all abstract types
var/list/all_possible_knowledge = typesof(/datum/heretic_knowledge)
for(var/datum/heretic_knowledge/knowledge_type as anything in all_possible_knowledge)
if(initial(knowledge_type.abstract_parent_type) == knowledge_type)
all_possible_knowledge -= knowledge_type
// Now, let's build a list of all researchable knowledge
// from the ground up. We start with all starting knowledge,
// then add the next possible knowledges back into the list
// repeatedly, until we run out of knowledges to add.
var/list/list_to_check = GLOB.heretic_start_knowledge.Copy()
var/i = 0
while(i < length(list_to_check))
var/datum/heretic_knowledge/knowledge = list_to_check[++i]
if(!ispath(knowledge))
TEST_FAIL("Heretic Knowledge: Got a non-heretic knowledge datum (Got: [knowledge]) in the list knowledges!")
// Next knowledge is a list of typepaths.
for(var/datum/heretic_knowledge/next_knowledge as anything in GLOB.heretic_research_tree[knowledge][HKT_NEXT])
if(!ispath(next_knowledge))
TEST_FAIL("Heretic Knowledge: [next_knowledge.type] has a [isnull(next_knowledge) ? "null":"invalid path"] in its next_knowledge list!")
continue
if(next_knowledge in list_to_check)
continue
list_to_check += next_knowledge
// We now have a list that SHOULD contain all knowledges with a path set (list_to_check).
// Let's compare it to our original list (all_possible_knowledge). If they're not identical,
// then somewhere we missed a knowledge somewhere, and should throw a fail.
if(length(all_possible_knowledge) != length(all_possible_knowledge & list_to_check))
// Unreachables is a list of typepaths - all paths that cannot be obtained.
var/list/unreachables = all_possible_knowledge - list_to_check
for(var/datum/heretic_knowledge/lost_knowledge as anything in unreachables)
TEST_FAIL("Heretic Knowledge: [lost_knowledge] is unreachable by players! Add it to another knowledge's 'next_knowledge' list. If it is purposeful, set its route to 'null'.")
+2 -2
View File
@@ -12,8 +12,8 @@
TEST_ASSERT_NOTNULL(offer_guy.has_status_effect(/datum/status_effect/offering/no_item_received/high_five), \
"Offerer doesn't have the high five offer status effect after offering (giving) to takers nearby")
var/atom/movable/screen/alert/give/highfive/alert_to_click = locate() in flatten_list(take_guy.alerts)
var/atom/movable/screen/alert/give/highfive/bystander_alert_we_dont_click = locate() in flatten_list(random_bystander.alerts)
var/atom/movable/screen/alert/give/highfive/alert_to_click = locate() in assoc_to_values(take_guy.alerts)
var/atom/movable/screen/alert/give/highfive/bystander_alert_we_dont_click = locate() in assoc_to_values(random_bystander.alerts)
TEST_ASSERT_NOTNULL(alert_to_click, "Taker had no alert to click to accept the high five offer")
TEST_ASSERT_NOTNULL(bystander_alert_we_dont_click, "Bystander had no alert from the high fiver offer")
+3 -3
View File
@@ -2,9 +2,9 @@
#define VALID_TEST_MAP "runtimestation"
/// Tests to ensure we can load a map from a whitelisted directory (_maps), but not a non-whitelisted directory (i.e "fartyShitPants")
/datum/unit_test/load_map_security
/datum/unit_test/maptest_load_map_security
/datum/unit_test/load_map_security/Run()
/datum/unit_test/maptest_load_map_security/Run()
// Copy our valid map into a bad directory
// We can technically load from /unitTestTempDir by passing it in our map name
@@ -34,7 +34,7 @@
TEST_ASSERT(bad_config.defaulted, "Loaded from non-whitelisted directory: data/load_map_security_temp/[VALID_TEST_MAP]")
/datum/unit_test/load_map_security/Destroy()
/datum/unit_test/maptest_load_map_security/Destroy()
// Clean up our temp directory
fdel("data/load_map_security_temp/")
return ..()
+2 -2
View File
@@ -1,7 +1,7 @@
/// Tests that [/datum/job/proc/get_default_roundstart_spawn_point] returns a landmark from all joinable jobs.
/datum/unit_test/job_roundstart_spawnpoints
/datum/unit_test/maptest_job_roundstart_spawnpoints
/datum/unit_test/job_roundstart_spawnpoints/Run()
/datum/unit_test/maptest_job_roundstart_spawnpoints/Run()
for(var/datum/job/job as anything in SSjob.joinable_occupations)
if(job.spawn_positions <= 0)
// Zero spawn positions means we don't need to care if they don't have a roundstart landmark
@@ -1,10 +1,10 @@
/// Verifies that there are no space turfs inside a station area, or on any planetary z-level. Sometimes, these are introduced during the load of the map and are not present in the DMM itself.
/// Let's just make sure that we have a stop-gap measure in place to catch these if they pop up so we don't put it onto production servers should something errant come up.
/datum/unit_test/mapload_space_verification
/datum/unit_test/maptest_mapload_space_verification
// This test is quite taxing time-wise, so let's run it later than other faster tests.
priority = TEST_LONGER
/datum/unit_test/mapload_space_verification/Run()
/datum/unit_test/maptest_mapload_space_verification/Run()
// Is our current map a planetary station (NO space turfs allowed)? If so, check for ANY space turfs.
if(SSmapping.is_planetary())
validate_planetary_map()
@@ -41,7 +41,7 @@
/// Verifies that there are ZERO space turfs on a valid planetary station. We NEVER want space turfs here, so we do not check for /area/space here since something completely undesirable is happening.
/// There are also a few considerations specific to planetary stations included within, so let's spin it out into a separate proc for clarity.
/datum/unit_test/mapload_space_verification/proc/validate_planetary_map()
/datum/unit_test/maptest_mapload_space_verification/proc/validate_planetary_map()
// We want to get both the station level and the mining level (if the two are seperate for any reason).
var/list/testable_levels = list()
testable_levels += SSmapping.levels_by_trait(ZTRAIT_STATION) // Station z-levels get to be in by default because they can derail an entire round and cause LINDA to weep if a space turf is present.
+2 -2
View File
@@ -1,9 +1,9 @@
/// Conveys all log_mapping messages as unit test failures, as they all indicate mapping problems.
/datum/unit_test/log_mapping
/datum/unit_test/maptest_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()
/datum/unit_test/maptest_log_mapping/Run()
var/static/regex/test_areacoord_regex = regex(@"\(-?\d+,-?\d+,(-?\d+)\)")
for(var/log_entry in GLOB.unit_test_mapping_logs)
@@ -1,8 +1,8 @@
///Detects movables that may have been accidentally placed in space, as well as movables which do not have the proper nearspace area (meaning they aren't lit properly.)
/datum/unit_test/mapping_nearstation_test
/datum/unit_test/maptest_mapping_nearstation_test
priority = TEST_PRE
/datum/unit_test/mapping_nearstation_test/Run()
/datum/unit_test/maptest_mapping_nearstation_test/Run()
if(SSmapping.is_planetary())
return //No need to test for orphaned spaced atoms on this map.
@@ -1,6 +1,6 @@
/datum/unit_test/modular_map_loader
/datum/unit_test/maptest_modular_map_loader
/datum/unit_test/modular_map_loader/Run()
/datum/unit_test/maptest_modular_map_loader/Run()
for (var/obj/modular_map_root/map_root_type as anything in subtypesof(/obj/modular_map_root))
var/config_file = initial(map_root_type.config_file)
if (!fexists(config_file))
+14 -1
View File
@@ -11,6 +11,15 @@
priority = TEST_LONGER
var/monkey_timer = 30 SECONDS
var/monkey_angry_nth = 5 // every nth monkey will be angry
var/monkey_weapon_index = 1 // which weapon to give the next angry monkey
var/list/monkey_weapon_list = list(
/obj/item/knife/shiv,
/obj/item/gun/ballistic/automatic/pistol,
/obj/item/gun/energy/laser,
/obj/item/melee/baseball_bat,
/obj/item/melee/baton,
/obj/item/storage/toolbox,
)
/datum/unit_test/monkey_business/Run()
for(var/monkey_id in 1 to length(GLOB.the_station_areas))
@@ -19,8 +28,12 @@
monkey.set_species(/datum/species/monkey)
monkey.set_name("Monkey [monkey_id]")
if(monkey_id % monkey_angry_nth == 0) // BLOOD FOR THE BLOOD GODS
monkey.put_in_active_hand(new /obj/item/knife/shiv)
var/obj/next_weapon = monkey_weapon_list[monkey_weapon_index]
monkey_weapon_index = (monkey_weapon_index % length(monkey_weapon_list)) + 1
monkey.put_in_active_hand(new next_weapon())
new /datum/ai_controller/monkey/angry(monkey)
if(ispath(next_weapon, /obj/item/gun))
monkey.ai_controller.set_blackboard_key(BB_MONKEY_GUN_NEURONS_ACTIVATED, TRUE)
else
new /datum/ai_controller/monkey(monkey)
monkey.ai_controller.set_blackboard_key(BB_MONKEY_TARGET_MONKEYS, TRUE)
+13
View File
@@ -124,3 +124,16 @@
var/obj/item/organ/brain = locate() in dummy.organs
brain.forceMove(dummy.loc)
allocated += brain
/datum/unit_test/felinid_ears
/datum/unit_test/felinid_ears/Run()
var/mob/living/carbon/human/normal_dummy = allocate(/mob/living/carbon/human/consistent)
normal_dummy.dna.features[FEATURE_EARS] = SPRITE_ACCESSORY_NONE
normal_dummy.set_species(/datum/species/human/felinid, pref_load = TRUE)
TEST_ASSERT(!istype(normal_dummy.get_organ_slot(ORGAN_SLOT_EARS), /obj/item/organ/ears/cat), "Felinid with NONE ears set had cat ears on species gain.")
TEST_ASSERT_NOTNULL(normal_dummy.get_organ_slot(ORGAN_SLOT_EARS), "Felinid with NONE ears set had NO ears on species gain.")
var/mob/living/carbon/human/anime_dummy = allocate(/mob/living/carbon/human/consistent)
anime_dummy.set_species(/datum/species/human/felinid, pref_load = TRUE)
TEST_ASSERT(istype(anime_dummy.get_organ_slot(ORGAN_SLOT_EARS), /obj/item/organ/ears/cat), "Felinid with default ears set did not have cat ears on species gain.")
+13
View File
@@ -0,0 +1,13 @@
/datum/unit_test/reachable_soup
/datum/unit_test/reachable_soup/Run()
var/obj/machinery/oven/range/range = EASY_ALLOCATE()
var/obj/item/reagent_containers/cup/soup_pot/soup = EASY_ALLOCATE()
var/mob/living/carbon/human/dummy = EASY_ALLOCATE()
dummy.put_in_active_hand(soup)
click_wrapper(dummy, range)
TEST_ASSERT_EQUAL(soup.loc, range, "Soup pot should have been placed on the stove.")
click_wrapper(dummy, soup)
TEST_ASSERT_EQUAL(soup.loc, dummy, "Soup pot should have been picked up by the dummy.")
@@ -5,14 +5,14 @@
* - Add the typepath(s) to setup_expected_types
* - In the type's initialize, REGISTER_REQUIRED_MAP_ITEM() a minimum and maximum
*/
/datum/unit_test/required_map_items
/datum/unit_test/maptest_required_map_items
/// A list of all typepaths that we expect to be in the required items list
var/list/expected_types = list()
/// Used to fill the expected types list with all the types we look for on the map.
/// This list will just be full of typepaths that we expect.
/// More detailed information about each item (mainly, how much of each should exist) is set on a per item basis
/datum/unit_test/required_map_items/proc/setup_expected_types()
/datum/unit_test/maptest_required_map_items/proc/setup_expected_types()
expected_types += subtypesof(/obj/item/stamp/head)
expected_types += subtypesof(/obj/machinery/modular_computer/preset/cargochat)
@@ -23,7 +23,7 @@
expected_types += /obj/machinery/drone_dispenser
expected_types += /obj/item/piggy_bank/vault
/datum/unit_test/required_map_items/Run()
/datum/unit_test/maptest_required_map_items/Run()
setup_expected_types()
var/list/required_map_items = GLOB.required_map_items.Copy()
Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 KiB

After

Width:  |  Height:  |  Size: 1.5 KiB

@@ -0,0 +1,43 @@
/// Ensures that hotswapping only occurs when hitting inventory items and allows item interactions to go through
/datum/unit_test/style_hotswapping
/datum/unit_test/style_hotswapping/Run()
var/mob/living/carbon/human/john_ultrakill = allocate(/mob/living/carbon/human/consistent)
var/obj/item/storage/backpack/bag = allocate(__IMPLIED_TYPE__, john_ultrakill.loc)
john_ultrakill.equip_to_slot(bag, ITEM_SLOT_BACK)
TEST_ASSERT_EQUAL(john_ultrakill.get_item_by_slot(ITEM_SLOT_BACK), bag, "Human wasn't able to equip a backpack!")
var/datum/component/style/style = john_ultrakill.AddComponent(/datum/component/style)
try_stabilize(john_ultrakill, john_ultrakill.loc, "while it was on the user's turf")
try_stabilize(john_ultrakill, bag, "while it was in the user's bag")
var/obj/item/coin/gold/coin_one = allocate(__IMPLIED_TYPE__, john_ultrakill.loc)
var/obj/item/coin/silver/coin_two = allocate(__IMPLIED_TYPE__, john_ultrakill.loc)
coin_two.forceMove(bag)
john_ultrakill.put_in_active_hand(coin_one, TRUE)
TEST_ASSERT_EQUAL(john_ultrakill.get_active_held_item(), coin_one, "Human wasn't able to pick up a gold coin!")
john_ultrakill.ClickOn(coin_two)
TEST_ASSERT_EQUAL(john_ultrakill.get_active_held_item(), coin_one, "Human hotswapped from their storage despite not having enough points!")
john_ultrakill.next_click = 0
john_ultrakill.next_move = 0
john_ultrakill.temporarilyRemoveItemFromInventory(coin_one, TRUE)
QDEL_NULL(coin_one)
style.style_points = INFINITY
style.update_screen(style.point_to_rank())
try_stabilize(john_ultrakill, john_ultrakill.loc, "while it was on the user's turf with hotswapping active")
try_stabilize(john_ultrakill, bag, "while it was in the user's bag with hotswapping active")
coin_one = allocate(__IMPLIED_TYPE__, john_ultrakill.loc)
john_ultrakill.put_in_active_hand(coin_one, TRUE)
TEST_ASSERT_EQUAL(john_ultrakill.get_active_held_item(), coin_one, "Human wasn't able to pick up a gold coin!")
john_ultrakill.ClickOn(coin_two)
TEST_ASSERT_EQUAL(john_ultrakill.get_active_held_item(), coin_two, "Human wasn't able to hotswap with their storage!")
/datum/unit_test/style_hotswapping/proc/try_stabilize(mob/living/carbon/human/john_ultrakill, core_loc, desc = null)
var/obj/item/organ/monster_core/regenerative_core/legion/core = allocate(__IMPLIED_TYPE__, john_ultrakill.loc)
core.forceMove(core_loc)
TEST_ASSERT(core.decay_timer, "Legion core spawned without a decay timer!")
var/obj/item/mining_stabilizer/serum = allocate(__IMPLIED_TYPE__, john_ultrakill.loc)
john_ultrakill.put_in_active_hand(serum, TRUE)
TEST_ASSERT_EQUAL(john_ultrakill.get_active_held_item(), serum, "Human wasn't able to pick up a stabilizer serum!")
john_ultrakill.ClickOn(core)
TEST_ASSERT(!core.decay_timer, "Clicking on a legion core with a serum did not stabilize it [desc]!")
john_ultrakill.next_click = 0
john_ultrakill.next_move = 0
+22
View File
@@ -131,3 +131,25 @@
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")
/// Tests items-as-prosthetic-limbs can apply
/datum/unit_test/prosthetic_item
/datum/unit_test/prosthetic_item/Run()
var/mob/living/carbon/human/patient = allocate(/mob/living/carbon/human/consistent)
var/obj/item/claymore/sword = allocate(/obj/item/claymore)
patient.make_item_prosthetic(sword)
TEST_ASSERT(HAS_TRAIT_FROM(sword, TRAIT_NODROP, HAND_REPLACEMENT_TRAIT), "Prosthetic item attachment failed! Item does not have the nodrop trait")
/// Specifically checks the chainsaw nullrod
/datum/unit_test/prosthetic_item/nullrod
/datum/unit_test/prosthetic_item/nullrod/Run()
var/mob/living/carbon/human/picker = allocate(/mob/living/carbon/human/consistent)
var/obj/item/nullrod/chainsaw/nullrod = allocate(/obj/item/nullrod/chainsaw)
nullrod.on_selected(null, null, picker)
TEST_ASSERT(HAS_TRAIT_FROM(nullrod, TRAIT_NODROP, HAND_REPLACEMENT_TRAIT), "Chainsaw nullrod item attachment failed! Item does not have the nodrop trait")
+34
View File
@@ -0,0 +1,34 @@
/// Checks to make sure all food trash is included in /obj/effect/spawner/random/trash/food_packaging
/datum/unit_test/trash_food
/datum/unit_test/trash_food/Run()
var/list/food_trash = /obj/effect/spawner/random/trash/food_packaging::loot
// list of pieces of trash we never want to include because they are special or rare (usually mutated botany plants)
var/list/food_trash_blacklist = list(
// already added to botanical_waste spawner or too exotic
/obj/item/grown/bananapeel,
/obj/item/grown/bananapeel/bombanana,
/obj/item/grown/bananapeel/mimanapeel,
/obj/item/grown/bananapeel/bluespace,
/obj/item/food/grown/bungopit,
/obj/item/food/egg,
/obj/item/gun/ballistic/revolver/peashooter,
/obj/item/grown/corncob,
/obj/item/grown/corncob/pepper,
// misc waste products that don't belong in trash spawner
/obj/item/reagent_containers/cup/bowl,
/obj/item/plate,
/obj/item/stack/rods, // kebab
/obj/item/paper/paperslip/fortune, // fortune cookie
/obj/item/dice/fudge, // /obj/item/food/fudgedice
)
for(var/path in subtypesof(/obj/item/food))
var/obj/item/food/food = path
var/trash = food::trash_type
if(!trash)
continue
if(trash in food_trash_blacklist)
continue
TEST_ASSERT(food_trash[trash], "[food] must include its trash_type for loot table /obj/effect/spawner/random/trash/food_packaging or be added to this unit tests food_trash_blacklist")
+2 -2
View File
@@ -1,8 +1,8 @@
/// Makes sure turf icons actually exist. :)
/datum/unit_test/turf_icons
/datum/unit_test/maptest_turf_icons
var/modular_mineral_turf_file = 'modular_skyrat/modules/xenoarch/icons/mining.dmi' //= 'icons/turf/mining.dmi' //MODULARITY SUPPORT - insert your snowflake MAP_SWITCH icon file here if you use that define. // SKYRAT EDIT - Added our modular file here (thanks)
/datum/unit_test/turf_icons/Run()
/datum/unit_test/maptest_turf_icons/Run()
for(var/turf/turf_path as anything in (subtypesof(/turf) - typesof(/turf/closed/mineral)))
var/icon_state = initial(turf_path.icon_state)
+19
View File
@@ -0,0 +1,19 @@
/// Test you can mouse-drop a defib off your back to unequip it
/datum/unit_test/unequip_defib
/datum/unit_test/unequip_defib/Run()
var/mob/living/carbon/human/consistent/dummy = EASY_ALLOCATE()
dummy.mock_client = new()
dummy.set_hud_used(new dummy.hud_type(dummy))
var/obj/item/defibrillator/defib = EASY_ALLOCATE()
dummy.equip_to_slot(defib, ITEM_SLOT_BACK)
var/old_usr = usr
usr = dummy // mouse drop still uses usr
defib.MouseDrop(dummy.hud_used.hand_slots["1"])
if(!dummy.is_holding(defib))
TEST_FAIL("The dummy failed to remove the defib from their back via mouse drop.")
usr = old_usr
+10 -1
View File
@@ -67,9 +67,14 @@ GLOBAL_VAR_INIT(focused_tests, focused_tests())
uncreatables = build_list_of_uncreatables()
allocated = new
run_loc_floor_bottom_left = get_turf(locate(/obj/effect/landmark/unit_test_bottom_left) in GLOB.landmarks_list)
run_loc_floor_top_right = get_turf(locate(/obj/effect/landmark/unit_test_top_right) in GLOB.landmarks_list)
if(priority > TEST_CREATE_AND_DESTROY) //the create and destroy test WILL wreck havok in the unit test room. You CANNOT stop the inevitable.
return
//Make sure that the top and bottom locations in the diagonal are floors. Anything else may get in the way of several tests.
TEST_ASSERT(isfloorturf(run_loc_floor_bottom_left), "run_loc_floor_bottom_left was not a floor ([run_loc_floor_bottom_left])")
TEST_ASSERT(isfloorturf(run_loc_floor_top_right), "run_loc_floor_top_right was not a floor ([run_loc_floor_top_right])")
@@ -97,6 +102,9 @@ GLOBAL_VAR_INIT(focused_tests, focused_tests())
/// Allocates an instance of the provided type, and places it somewhere in an available loc
/// Instances allocated through this proc will be destroyed when the test is over
/datum/unit_test/proc/allocate(type, ...)
if(priority > TEST_CREATE_AND_DESTROY) //I'm not using TEST_ASSERT here since these are just numbers that tell nothing useful about the problem.
TEST_FAIL("allocate() was called for a unit test after 'create_and_destroy' has finished. The unit test room is no longer a reliable testing ground for atoms.")
return null //you deserve runtime errors for it
var/list/arguments = args.Copy(2)
if(ispath(type, /atom))
if (!arguments.len)
@@ -204,7 +212,8 @@ GLOBAL_VAR_INIT(focused_tests, focused_tests())
else
test.Run()
test.restore_atmos()
if(test.priority < TEST_CREATE_AND_DESTROY) //We shouldn't care about restoring atmos after create_and_destroy.
test.restore_atmos()
duration = REALTIMEOFDAY - duration
GLOB.current_test = null