Skip to content

Commit 0187135

Browse files
authored
Map Conformance Testing (#1157)
* Map Conformance Testing minor unit test code hammering * whoops * Unit test priority
1 parent 2eead9b commit 0187135

9 files changed

+93
-12
lines changed

_maps/theseus.json

+2-1
Original file line numberDiff line numberDiff line change
@@ -14,5 +14,6 @@
1414
"cook": {
1515
"additional_cqc_areas": ["/area/station/service/bar", "/area/station/service/kitchen/coldroom", "/area/station/commons/lounge"]
1616
}
17-
}
17+
},
18+
"run_mapping_tests": true
1819
}

code/datums/map_config.dm

+7
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,9 @@
4040
/// List of additional areas that count as a part of the library
4141
var/library_areas = list()
4242

43+
/// Do we run mapping standards unit tests on this map?
44+
var/run_mapping_tests = FALSE
45+
4346
/**
4447
* Proc that simply loads the default map config, which should always be functional.
4548
*/
@@ -207,6 +210,10 @@
207210

208211
holomap_offsets = temp
209212

213+
if("run_mapping_tests" in json)
214+
//This should be true, but just in case...
215+
run_mapping_tests = json["run_mapping_tests"]
216+
210217
defaulted = FALSE
211218
return TRUE
212219

code/modules/unit_tests/_unit_tests.dm code/modules/unit_tests/__unit_tests.dm

+22-2
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,9 @@
66
/// For advanced cases, fail unconditionally but don't return (so a test can return multiple results)
77
#define TEST_FAIL(reason) (Fail(reason || "No reason", __FILE__, __LINE__))
88

9+
/// Mark the test as skipped.
10+
#define TEST_SKIP(reason) (return Skip(reason || "No reason"))
11+
912
/// Asserts that a condition is true
1013
/// If the condition is not true, fails the test
1114
#define TEST_ASSERT(assertion, reason) if (!(assertion)) { return Fail("Assertion failed: [reason || "No reason"]", __FILE__, __LINE__) }
@@ -46,8 +49,12 @@
4649
#define UNIT_TEST_FAILED 1
4750
#define UNIT_TEST_SKIPPED 2
4851

52+
/// Capture pre-unit test mapping error reports. Maybe one day we can take this out back and shoot it.
4953
#define TEST_PRE 0
50-
#define TEST_DEFAULT 1
54+
/// Ensures map standards. Runs before standard unit tests as for production maps, these are more important.
55+
#define TEST_MAP_STANDARDS 1
56+
/// Standard unit test priority
57+
#define TEST_DEFAULT 2
5158
/// After most test steps, used for tests that run long so shorter issues can be noticed faster
5259
#define TEST_LONGER 10
5360
/// This must be the last test to run due to the inherent nature of the test iterating every single tangible atom in the game
@@ -61,10 +68,16 @@
6168
#define TEST_OUTPUT_GREEN(text) "\x1B\x5B1;32m[text]\x1B\x5B0m"
6269
/// Change color to yellow on ANSI terminal output, if enabled with -DANSICOLORS.
6370
#define TEST_OUTPUT_YELLOW(text) "\x1B\x5B1;33m[text]\x1B\x5B0m"
71+
/// Change color to blue on ANSI terminal output, if enabled with -DANSICOLORS.
72+
#define TEST_OUTPUT_BLUE(text) "\x1B\x5B1;34m[text]\x1B\x5B0m"
73+
/// Change color to magenta on ANSI terminal output, if enabled with -DANSICOLORS.
74+
#define TEST_OUTPUT_MAGENTA(text) "\x1B\x5B1;35m[text]\x1B\x5B0m"
6475
#else
6576
#define TEST_OUTPUT_RED(text) (text)
6677
#define TEST_OUTPUT_GREEN(text) (text)
6778
#define TEST_OUTPUT_YELLOW(text) (text)
79+
#define TEST_OUTPUT_BLUE(text) (text)
80+
#define TEST_OUTPUT_MAGENTA(text) (text)
6881
#endif
6982

7083
/// A trait source when adding traits through unit tests
@@ -73,6 +86,13 @@
7386
/// Helper to allocate a new object with the implied type (the type of the variable it's assigned to) in the corner of the test room
7487
#define ALLOCATE_BOTTOM_LEFT(arguments...) allocate(__IMPLIED_TYPE__, run_loc_floor_bottom_left, ##arguments)
7588

89+
// Include unit test base definition
90+
#include "_unit_test.dm"
91+
92+
// Category Includes
93+
#include "mapping_standards\__include.dm"
94+
95+
// Single File Includes
7696
#include "achievements.dm"
7797
#include "anchored_mobs.dm"
7898
#include "anonymous_themes.dm"
@@ -184,7 +204,7 @@
184204
#include "tgui_create_message.dm"
185205
#include "timer_sanity.dm"
186206
#include "traitor.dm"
187-
#include "unit_test.dm"
207+
188208
#include "wizard_loadout.dm"
189209
#include "wounds.dm"
190210
#ifdef REFERENCE_TRACKING_DEBUG //Don't try and parse this file if ref tracking isn't turned on. IE: don't parse ref tracking please mr linter

code/modules/unit_tests/unit_test.dm code/modules/unit_tests/_unit_test.dm

+32-7
Original file line numberDiff line numberDiff line change
@@ -30,10 +30,12 @@ GLOBAL_LIST_EMPTY(unit_test_mapping_logs)
3030
var/priority = TEST_DEFAULT
3131
//internal shit
3232
var/focus = FALSE
33-
var/succeeded = TRUE
33+
var/test_status = UNIT_TEST_PASSED
3434
var/list/allocated
3535
var/list/fail_reasons
3636

37+
var/skip_reason
38+
3739
var/static/datum/space_level/reservation
3840

3941
/proc/cmp_unit_test_priority(datum/unit_test/a, datum/unit_test/b)
@@ -65,13 +67,18 @@ GLOBAL_LIST_EMPTY(unit_test_mapping_logs)
6567
TEST_FAIL("Run() called parent or not implemented")
6668

6769
/datum/unit_test/proc/Fail(reason = "No reason", file = "OUTDATED_TEST", line = 1)
68-
succeeded = FALSE
70+
test_status = UNIT_TEST_FAILED
6971

7072
if(!istext(reason))
7173
reason = "FORMATTED: [reason != null ? reason : "NULL"]"
7274

7375
LAZYADD(fail_reasons, list(list(reason, file, line)))
7476

77+
78+
/datum/unit_test/proc/Skip(reason = "No reason")
79+
test_status = UNIT_TEST_SKIPPED
80+
skip_reason = reason
81+
7582
/// Allocates an instance of the provided type, and places it somewhere in an available loc
7683
/// Instances allocated through this proc will be destroyed when the test is over
7784
/datum/unit_test/proc/allocate(type, ...)
@@ -118,10 +125,21 @@ GLOBAL_LIST_EMPTY(unit_test_mapping_logs)
118125

119126
duration = REALTIMEOFDAY - duration
120127
GLOB.current_test = null
121-
GLOB.failed_any_test |= !test.succeeded
128+
GLOB.failed_any_test |= (test.test_status == UNIT_TEST_FAILED)
129+
130+
var/test_log_prefix
131+
switch(test.test_status)
132+
if(UNIT_TEST_FAILED)
133+
test_log_prefix = TEST_OUTPUT_RED("FAIL")
134+
if(UNIT_TEST_PASSED)
135+
test_log_prefix = TEST_OUTPUT_GREEN("PASS")
136+
if(UNIT_TEST_SKIPPED)
137+
test_log_prefix = TEST_OUTPUT_BLUE("SKIPPED")
138+
else //what
139+
test_log_prefix = TEST_OUTPUT_MAGENTA("BAD STATUS [test.test_status]")
122140

123141
var/list/log_entry = list(
124-
"[test.succeeded ? TEST_OUTPUT_GREEN("PASS") : TEST_OUTPUT_RED("FAIL")]: [test_path] [duration / 10]s",
142+
"[test_log_prefix]: [test_path] [(test.test_status != UNIT_TEST_SKIPPED ? "[duration / 10]s" : "| [test.skip_reason]")]",
125143
)
126144
var/list/fail_reasons = test.fail_reasons
127145
var/map_name = SSmapping.config.map_name
@@ -146,7 +164,9 @@ GLOBAL_LIST_EMPTY(unit_test_mapping_logs)
146164
var/message = log_entry.Join("\n")
147165
log_test(message)
148166

149-
test_results[test_path] = list("status" = test.succeeded ? UNIT_TEST_PASSED : UNIT_TEST_FAILED, "message" = message, "name" = test_path)
167+
168+
169+
test_results[test_path] = list("status" = test.test_status, "message" = message, "name" = test_path)
150170

151171
qdel(test)
152172

@@ -157,10 +177,15 @@ GLOBAL_LIST_EMPTY(unit_test_mapping_logs)
157177

158178
var/list/tests_to_run = subtypesof(/datum/unit_test)
159179
var/list/focused_tests = list()
160-
for (var/_test_to_run in tests_to_run)
161-
var/datum/unit_test/test_to_run = _test_to_run
180+
181+
for (var/datum/unit_test/test_to_run as anything in tests_to_run)
182+
// Handle VSCode Testing Integration Focus Tests
162183
if (initial(test_to_run.focus))
163184
focused_tests += test_to_run
185+
// Remove abstract tests.
186+
if (isabstract(test_to_run))
187+
tests_to_run -= test_to_run
188+
164189
if(length(focused_tests))
165190
tests_to_run = focused_tests
166191

code/modules/unit_tests/atmos_moles_tests.dm

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
#define ALL_GASIDS xgm_gas_data.gases
22

33
/datum/unit_test/atmos_machinery
4-
//template = /datum/unit_test/atmos_machinery
4+
abstract_type = /datum/unit_test/atmos_machinery
55
var/list/test_cases = list()
66

77
/datum/unit_test/atmos_machinery/Run()
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
// Master Include file for Mapping Standards Conformance Tests
2+
3+
#include "_mapping_standards.dm"
4+
5+
#include "ladders_must_have_openspace.dm"
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
2+
/datum/unit_test/mapping_standards
3+
abstract_type = /datum/unit_test/mapping_standards
4+
5+
/datum/unit_test/mapping_standards/Run()
6+
SHOULD_CALL_PARENT(TRUE)
7+
. = 0 && ..() //linter defeat
8+
if(!SSmapping.config.run_mapping_tests)
9+
Skip("Standards tests disabled by config")
10+
return TRUE
11+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
2+
// Ensure openspace between two linked ladders.
3+
// There's an edge case here bay solves with 'allowed_directions'
4+
// If you encounter it, well. Good luck and god help you -Francinum
5+
6+
/datum/unit_test/mapping_standards/ladders_must_have_openspace
7+
8+
/datum/unit_test/mapping_standards/ladders_must_have_openspace/Run()
9+
if(..()) {return};
10+
for(var/obj/structure/ladder/ladder as anything in INSTANCES_OF(/obj/structure/ladder))
11+
if(ladder.down && (!isopenspaceturf(get_turf(ladder))))
12+
TEST_FAIL("Ladder with down linkage is not on openspace turf, at: [AREACOORD(ladder)]")

daedalus.dme

+1-1
Original file line numberDiff line numberDiff line change
@@ -4502,7 +4502,7 @@
45024502
#include "code\modules\three_dsix\stats\psyche.dm"
45034503
#include "code\modules\three_dsix\stats\soma.dm"
45044504
#include "code\modules\tooltip\tooltip.dm"
4505-
#include "code\modules\unit_tests\_unit_tests.dm"
4505+
#include "code\modules\unit_tests\__unit_tests.dm"
45064506
#include "code\modules\universal_states\resonance_jump.dm"
45074507
#include "code\modules\universal_states\universal_state.dm"
45084508
#include "code\modules\uplink\uplink_devices.dm"

0 commit comments

Comments
 (0)