From 33eaf8ae42ba25effb074773f3045cf485efc4b2 Mon Sep 17 00:00:00 2001 From: warriorstar-orion Date: Sun, 22 Dec 2024 19:20:49 -0500 Subject: [PATCH] Create interaction test harness. (#27643) * Create interaction test harness. * retrofit tests, add janicart attack chain tests * extract puppeteer to separate file * move puppeteer creation to constructor --- code/tests/_game_test_puppeteer.dm | 68 +++++++++++++++++++ .../test_attack_chain_cult_dagger.dm | 17 +++++ .../test_attack_chain_vehicles.dm | 26 +++++++ code/tests/game_tests.dm | 3 + code/tests/test_runner.dm | 10 ++- 5 files changed, 123 insertions(+), 1 deletion(-) create mode 100644 code/tests/_game_test_puppeteer.dm create mode 100644 code/tests/attack_chain/test_attack_chain_cult_dagger.dm create mode 100644 code/tests/attack_chain/test_attack_chain_vehicles.dm diff --git a/code/tests/_game_test_puppeteer.dm b/code/tests/_game_test_puppeteer.dm new file mode 100644 index 00000000000..e9f560fe86a --- /dev/null +++ b/code/tests/_game_test_puppeteer.dm @@ -0,0 +1,68 @@ +/** + * A testing object used to control mobs in game tests. + * + * Puppeteers provide an easy way to create mobs and objects, + * perform interactions in the same way that a player would, + * and check the state of the mob during tests. + */ +/datum/test_puppeteer + var/mob/living/carbon/puppet + var/datum/game_test/origin_test + +/datum/test_puppeteer/New(datum/game_test/origin_test_, carbon_type = /mob/living/carbon/human, turf/initial_location) + if(!ispath(carbon_type, /mob/living/carbon/human)) + origin_test.Fail("unexpected puppeteer carbon type [carbon_type]", __FILE__, __LINE__) + + if(!initial_location) + initial_location = locate(179, 136, 1) // Center of admin testing area + origin_test = origin_test_ + puppet = origin_test.allocate(carbon_type, initial_location) + var/datum/mind/new_mind = new("interaction_test_[puppet.UID()]") + new_mind.transfer_to(puppet) + +/datum/test_puppeteer/proc/spawn_puppet_nearby(carbon_type = /mob/living/carbon/human) + for(var/turf/T in RANGE_TURFS(1, puppet.loc)) + if(!is_blocked_turf(T, exclude_mobs = FALSE)) + return new/datum/test_puppeteer(origin_test, carbon_type, T) + + origin_test.Fail("could not spawn puppeteer near [src]") + +/datum/test_puppeteer/proc/spawn_obj_in_hand(obj_type) + var/obj/new_obj = origin_test.allocate(obj_type, null) + if(puppet.put_in_hands(new_obj)) + return new_obj + + origin_test.Fail("could not spawn obj [obj_type] in hand of [puppet]") + +/datum/test_puppeteer/proc/spawn_obj_nearby(obj_type) + for(var/turf/T in RANGE_TURFS(1, puppet.loc)) + if(!is_blocked_turf(T, exclude_mobs = FALSE)) + return origin_test.allocate(obj_type, T) + + origin_test.Fail("could not spawn obj [obj_type] near [src]") + +/datum/test_puppeteer/proc/click_on(target, params) + var/datum/test_puppeteer/puppet_target = target + sleep(max(puppet.next_click, puppet.next_move) - world.time + 1) + if(istype(puppet_target)) + puppet.ClickOn(puppet_target.puppet, params) + return + + puppet.ClickOn(target, params) + +/datum/test_puppeteer/proc/spawn_mob_nearby(mob_type) + for(var/turf/T in RANGE_TURFS(1, puppet)) + if(!is_blocked_turf(T, exclude_mobs = FALSE)) + var/mob/new_mob = origin_test.allocate(mob_type, T) + return new_mob + +/datum/test_puppeteer/proc/check_attack_log(snippet) + for(var/log_text in puppet.attack_log_old) + if(findtextEx(log_text, snippet)) + return TRUE + +/datum/test_puppeteer/proc/set_intent(new_intent) + puppet.a_intent_change(new_intent) + +/datum/test_puppeteer/proc/rejuvenate() + puppet.rejuvenate() diff --git a/code/tests/attack_chain/test_attack_chain_cult_dagger.dm b/code/tests/attack_chain/test_attack_chain_cult_dagger.dm new file mode 100644 index 00000000000..b150d67cb60 --- /dev/null +++ b/code/tests/attack_chain/test_attack_chain_cult_dagger.dm @@ -0,0 +1,17 @@ +/datum/game_test/attack_chain_cult_dagger/Run() + var/datum/test_puppeteer/cultist = new(src) + var/datum/test_puppeteer/target = cultist.spawn_puppet_nearby() + + cultist.puppet.mind.add_antag_datum(/datum/antagonist/cultist) + cultist.spawn_obj_in_hand(/obj/item/melee/cultblade/dagger) + cultist.set_intent("harm") + cultist.click_on(target) + + TEST_ASSERT(target.check_attack_log("Attacked with ritual dagger"), "non-cultist missing dagger attack log") + TEST_ASSERT_NOTEQUAL(target.puppet.health, target.puppet.getMaxHealth(), "cultist attacking non-cultist with dagger caused no damage") + + target.rejuvenate() + target.puppet.mind.add_antag_datum(/datum/antagonist/cultist) + + cultist.click_on(target) + TEST_ASSERT_EQUAL(target.puppet.health, target.puppet.getMaxHealth(), "cultist attacking cultist with dagger caused damage") diff --git a/code/tests/attack_chain/test_attack_chain_vehicles.dm b/code/tests/attack_chain/test_attack_chain_vehicles.dm new file mode 100644 index 00000000000..791b45497ba --- /dev/null +++ b/code/tests/attack_chain/test_attack_chain_vehicles.dm @@ -0,0 +1,26 @@ +/datum/game_test/attack_chain_vehicles/Run() + var/datum/test_puppeteer/player = new(src) + var/obj/item/key/janitor/janicart_key = player.spawn_obj_in_hand(/obj/item/key/janitor) + var/obj/vehicle/janicart/janicart = player.spawn_obj_nearby(/obj/vehicle/janicart) + + player.click_on(janicart) + TEST_ASSERT_EQUAL(janicart.inserted_key, janicart_key, "did not find janicart key in vehicle") + + var/move_delay = janicart.vehicle_move_delay + player.spawn_obj_in_hand(/obj/item/borg/upgrade/vtec) + player.click_on(janicart) + TEST_ASSERT(janicart.vehicle_move_delay < move_delay, "VTEC upgrade not applied properly") + + TEST_ASSERT_NULL(janicart.mybag, "unexpected trash bag on janicart") + var/obj/item/storage/bag/trash/bag = player.spawn_obj_in_hand(/obj/item/storage/bag/trash) + player.click_on(janicart) + TEST_ASSERT_EQUAL(janicart.mybag, bag, "trash bag not attached to janicart") + + var/obj/item/kitchen/knife/knife = player.spawn_obj_in_hand(/obj/item/kitchen/knife) + player.set_intent("harm") + player.click_on(janicart) + TEST_ASSERT(janicart.obj_integrity < janicart.max_integrity, "knife attack not performed") + + player.set_intent("help") + player.click_on(janicart) + TEST_ASSERT(knife in bag, "knife not placed in trash bag") diff --git a/code/tests/game_tests.dm b/code/tests/game_tests.dm index c7c35e38667..254673e8b34 100644 --- a/code/tests/game_tests.dm +++ b/code/tests/game_tests.dm @@ -2,8 +2,11 @@ //Keep this sorted alphabetically #ifdef GAME_TESTS +#include "_game_test_puppeteer.dm" #include "_game_test.dm" #include "atmos\test_ventcrawl.dm" +#include "attack_chain\test_attack_chain_cult_dagger.dm" +#include "attack_chain\test_attack_chain_vehicles.dm" #include "games\test_cards.dm" #include "jobs\test_job_globals.dm" #include "test_aicard_icons.dm" diff --git a/code/tests/test_runner.dm b/code/tests/test_runner.dm index 2d43ad51655..206d31a2205 100644 --- a/code/tests/test_runner.dm +++ b/code/tests/test_runner.dm @@ -70,7 +70,15 @@ if(!test.succeeded) failed_any_test = TRUE - test_logs[I] += test.fail_reasons + for(var/fail_reason in test.fail_reasons) + if(islist(fail_reason)) + var/text = fail_reason[1] + var/file = fail_reason[2] + var/line = fail_reason[3] + + test_logs[I] += "[file]:[line]: [text]" + else + test_logs[I] += fail_reason qdel(test)