Adds a unit test that all roundstart spawnable jobs have a landmark to spawn at (#74995)

## About The Pull Request


https://github.com/tgstation/tgstation/pull/74985#issuecomment-1523773626

Tests that all jobs that have `spawn_position > 0` at roundstart have a
location to spawn at.

Also changes the failure message for
`get_default_roundstart_spawn_point` to send to `log_mapping` rather
than `log_world`, as it is a map error and log world doesn't really help
anyone. This would've been sufficient for the existing unit test
`log_mapping`, but that unit test expects that the log has an areacoord
supplied, which we can't really do, given we're reporting a _lack_ of
something.

## Why It's Good For The Game

Stops maps from regressing and dumping people on the latejoin shuttle
roundstart.

## Changelog

~~Not necessary unless I find a map which forgot a landmark~~

🆑 Melbert
fix: Tramstation Robotics and RD now spawn in their departments
roundstart
fix: Birdboat detective now spawns in their office
/🆑
This commit is contained in:
MrMelbert
2023-05-04 14:03:49 -06:00
committed by GitHub
parent 51a7dc33cd
commit aacc85964a
11 changed files with 86 additions and 26 deletions
+1
View File
@@ -63655,6 +63655,7 @@
dir = 4
},
/obj/effect/decal/cleanable/dirt/dust,
/obj/effect/landmark/start/detective,
/turf/open/floor/wood,
/area/station/security/detectives_office)
"whL" = (
+12 -2
View File
@@ -8282,6 +8282,7 @@
/obj/effect/turf_decal/trimline/purple/filled/line{
dir = 1
},
/obj/effect/landmark/start/roboticist,
/turf/open/floor/iron,
/area/station/science/robotics/lab)
"buQ" = (
@@ -39347,6 +39348,7 @@
"mWe" = (
/obj/machinery/atmospherics/components/unary/vent_scrubber/on/layer2,
/obj/effect/turf_decal/tile/neutral/fourcorners,
/obj/effect/landmark/start/roboticist,
/turf/open/floor/iron/dark,
/area/station/science/robotics/lab)
"mWj" = (
@@ -48889,6 +48891,13 @@
},
/turf/open/floor/iron,
/area/station/hallway/primary/tram/right)
"qtK" = (
/obj/structure/cable,
/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4,
/obj/effect/turf_decal/tile/neutral/fourcorners,
/obj/effect/landmark/start/roboticist,
/turf/open/floor/iron/dark,
/area/station/science/robotics/lab)
"qtS" = (
/obj/effect/decal/cleanable/dirt,
/obj/structure/disposalpipe/segment{
@@ -50314,6 +50323,7 @@
/obj/structure/chair/office/light{
dir = 1
},
/obj/effect/landmark/start/research_director,
/turf/open/floor/glass/reinforced,
/area/station/command/heads_quarters/rd)
"qUF" = (
@@ -178967,7 +178977,7 @@ gyP
aUb
eeE
wFx
uSP
qtK
tPD
uje
uje
@@ -179224,7 +179234,7 @@ gyP
ixu
eeE
muZ
uSP
qtK
bpa
uje
dLO
+3
View File
@@ -3,6 +3,9 @@
"map_name": "MultiZ Debug",
"map_path": "map_files/debug",
"map_file": "multiz.dmm",
"ignored_unit_tests": [
"/datum/unit_test/job_roundstart_spawnpoints"
],
"traits": [
{
"Up": 1,
+3
View File
@@ -4,6 +4,9 @@
"map_path": "map_files/debug",
"map_file": "runtimestation.dmm",
"space_ruin_levels": 1,
"ignored_unit_tests": [
"/datum/unit_test/job_roundstart_spawnpoints"
],
"shuttles": {
"cargo": "cargo_delta"
}
+13
View File
@@ -41,6 +41,9 @@
/// List of additional areas that count as a part of the library
var/library_areas = list()
/// List of unit tests that are skipped when running this map
var/list/skipped_tests
/**
* Proc that simply loads the default map config, which should always be functional.
*/
@@ -199,6 +202,16 @@
continue
library_areas += path
#ifdef UNIT_TESTS
// Check for unit tests to skip, no reason to check these if we're not running tests
for(var/path_as_text in json["ignored_unit_tests"])
var/path_real = text2path(path_as_text)
if(!ispath(path_real, /datum/unit_test))
stack_trace("Invalid path in mapping config for ignored unit tests: \[[path_as_text]\]")
continue
LAZYADD(skipped_tests, path_real)
#endif
defaulted = FALSE
return TRUE
#undef CHECK_EXISTS
+3
View File
@@ -35,8 +35,11 @@ INITIALIZE_IMMEDIATE(/obj/effect/landmark)
var/used = FALSE
/obj/effect/landmark/start/proc/after_round_start()
// We'd like to keep these around for unit tests, so we can check that they exist.
#ifndef UNIT_TESTS
if(delete_after_roundstart)
qdel(src)
#endif
/obj/effect/landmark/start/Initialize(mapload)
. = ..()
+1 -2
View File
@@ -421,8 +421,7 @@
spawn_point.used = TRUE
break
if(!.)
log_world("Couldn't find a round start spawn point for [title]")
log_mapping("Job [title] ([type]) couldn't find a round start spawn point.")
/// Finds a valid latejoin spawn point, checking for events and special conditions.
/datum/job/proc/get_latejoin_spawn_point()
+7 -1
View File
@@ -70,7 +70,12 @@
#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"
@@ -142,6 +147,7 @@
#include "lungs.dm"
#include "load_map_security.dm"
#include "machine_disassembly.dm"
#include "map_landmarks.dm"
#include "mapload_space_verification.dm"
#include "mapping.dm"
#include "mecha_damage.dm"
+12
View File
@@ -0,0 +1,12 @@
/// 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/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
continue
if(job.get_default_roundstart_spawn_point())
continue
TEST_FAIL("Job [job.title] ([job.type]) has no default roundstart spawn landmark.")
-1
View File
@@ -17,4 +17,3 @@
continue
TEST_FAIL(log_entry)
+31 -20
View File
@@ -159,40 +159,51 @@ GLOBAL_VAR_INIT(focused_tests, focused_tests())
GLOB.current_test = test
var/duration = REALTIMEOFDAY
var/skip_test = (test_path in SSmapping.config.skipped_tests)
var/test_output_desc = "[test_path]"
var/message = ""
log_world("::group::[test_path]")
test.Run()
duration = REALTIMEOFDAY - duration
GLOB.current_test = null
GLOB.failed_any_test |= !test.succeeded
if(skip_test)
log_world("[TEST_OUTPUT_YELLOW("SKIPPED")] Skipped run on map [SSmapping.config.map_name].")
var/list/log_entry = list()
var/list/fail_reasons = test.fail_reasons
else
for(var/reasonID in 1 to LAZYLEN(fail_reasons))
var/text = fail_reasons[reasonID][1]
var/file = fail_reasons[reasonID][2]
var/line = fail_reasons[reasonID][3]
test.Run()
test.log_for_test(text, "error", file, line)
duration = REALTIMEOFDAY - duration
GLOB.current_test = null
GLOB.failed_any_test |= !test.succeeded
// Normal log message
log_entry += "\tFAILURE #[reasonID]: [text] at [file]:[line]"
var/list/log_entry = list()
var/list/fail_reasons = test.fail_reasons
var/message = log_entry.Join("\n")
log_test(message)
for(var/reasonID in 1 to LAZYLEN(fail_reasons))
var/text = fail_reasons[reasonID][1]
var/file = fail_reasons[reasonID][2]
var/line = fail_reasons[reasonID][3]
var/test_output_desc = "[test_path] [duration / 10]s"
if (test.succeeded)
log_world("[TEST_OUTPUT_GREEN("PASS")] [test_output_desc]")
test.log_for_test(text, "error", file, line)
// Normal log message
log_entry += "\tFAILURE #[reasonID]: [text] at [file]:[line]"
if(length(log_entry))
message = log_entry.Join("\n")
log_test(message)
test_output_desc += " [duration / 10]s"
if (test.succeeded)
log_world("[TEST_OUTPUT_GREEN("PASS")] [test_output_desc]")
log_world("::endgroup::")
if (!test.succeeded)
if (!test.succeeded && !skip_test)
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 = skip_test ? UNIT_TEST_SKIPPED : (test.succeeded ? UNIT_TEST_PASSED : UNIT_TEST_FAILED)
test_results[test_path] = list("status" = final_status, "message" = message, "name" = test_path)
qdel(test)