mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2025-12-10 17:52:36 +00:00
* Cleans up the fallout from plane cube (#70235) * Cleans up the fallout from plane cube Alright. Makes cleaning bubbles respect planes Adds support for updating overlays on move, fixing an issue with pointing at items Adds better error messages for failing to provide args for mutable_appearance() Fixes a bug where string overlays were not respecting insertion order * Adds documentation for offset spokesman and offset_const * Better stack trace * Removes some redundant uses of cached MAs At this scale, attempting to cache MAs like this has 0 impact on anything And just makes things more messy then they need to be * ensures fullscreen objects START offset, so things are always proper * ensures chatmessages always have the right offset * fixes compile * whoops, the above lighting plane should actually be ABOVE the lighting plane * fixes compile, also cleans up the fire overlay a tad * Adds a unit test for plane masters that are shrunk by multiz being double shrunk This is slightly hacky because of how I'm handing the plane master group, but it's not THAT bad, and gives me some real good coverage * Properly targets the seethrough plane at the game world plate. This fixes unit tests, and also just makes more sense * whoops * oh * adds datum support for allocate(), cleans up a harddel from testing * Makes camera chunks index at 1, and also makes them support non powers of two sizes, since that was unneeded * fixes runtime in allocate * Cleans up the fallout from plane cube * liquid tweaks * oop Co-authored-by: LemonInTheDark <58055496+LemonInTheDark@users.noreply.github.com> Co-authored-by: tastyfish <crazychris32@gmail.com>
200 lines
6.6 KiB
Plaintext
200 lines
6.6 KiB
Plaintext
/*
|
|
|
|
Usage:
|
|
Override /Run() to run your test code
|
|
|
|
Call TEST_FAIL() to fail the test (You should specify a reason)
|
|
|
|
You may use /New() and /Destroy() for setup/teardown respectively
|
|
|
|
You can use the run_loc_floor_bottom_left and run_loc_floor_top_right to get turfs for testing
|
|
|
|
*/
|
|
|
|
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)
|
|
|
|
/datum/unit_test
|
|
//Bit of metadata for the future maybe
|
|
var/list/procs_tested
|
|
|
|
/// The bottom left floor turf of the testing zone
|
|
var/turf/run_loc_floor_bottom_left
|
|
|
|
/// The top right floor turf of the testing zone
|
|
var/turf/run_loc_floor_top_right
|
|
///The priority of the test, the larger it is the later it fires
|
|
var/priority = TEST_DEFAULT
|
|
//internal shit
|
|
var/focus = FALSE
|
|
var/succeeded = TRUE
|
|
var/list/allocated
|
|
var/list/fail_reasons
|
|
|
|
var/static/datum/space_level/reservation
|
|
|
|
/proc/cmp_unit_test_priority(datum/unit_test/a, datum/unit_test/b)
|
|
return initial(a.priority) - initial(b.priority)
|
|
|
|
/datum/unit_test/New()
|
|
if (isnull(reservation))
|
|
var/datum/map_template/unit_tests/template = new
|
|
reservation = template.load_new_z()
|
|
|
|
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)
|
|
|
|
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])")
|
|
|
|
/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/content in turf.contents)
|
|
if (istype(content, /obj/effect/landmark))
|
|
continue
|
|
qdel(content)
|
|
return ..()
|
|
|
|
/datum/unit_test/proc/Run()
|
|
TEST_FAIL("Run() called parent or not implemented")
|
|
|
|
/datum/unit_test/proc/Fail(reason = "No reason", file = "OUTDATED_TEST", line = 1)
|
|
succeeded = FALSE
|
|
|
|
if(!istext(reason))
|
|
reason = "FORMATTED: [reason != null ? reason : "NULL"]"
|
|
|
|
LAZYADD(fail_reasons, list(list(reason, file, line)))
|
|
|
|
/// 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, ...)
|
|
var/list/arguments = args.Copy(2)
|
|
if(ispath(type, /atom))
|
|
if (!arguments.len)
|
|
arguments = list(run_loc_floor_bottom_left)
|
|
else if (arguments[1] == null)
|
|
arguments[1] = run_loc_floor_bottom_left
|
|
var/instance
|
|
// Byond will throw an index out of bounds if arguments is empty in that arglist call. Sigh
|
|
if(length(arguments))
|
|
instance = new type(arglist(arguments))
|
|
else
|
|
instance = new type()
|
|
allocated += instance
|
|
return instance
|
|
|
|
/datum/unit_test/proc/test_screenshot(name, icon/icon)
|
|
if (!istype(icon))
|
|
TEST_FAIL("[icon] is not an icon.")
|
|
return
|
|
|
|
var/path_prefix = replacetext(replacetext("[type]", "/datum/unit_test/", ""), "/", "_")
|
|
name = replacetext(name, "/", "_")
|
|
|
|
var/filename = "code/modules/unit_tests/screenshots/[path_prefix]_[name].png"
|
|
|
|
if (fexists(filename))
|
|
var/data_filename = "data/screenshots/[path_prefix]_[name].png"
|
|
fcopy(icon, data_filename)
|
|
log_test("\t[path_prefix]_[name] was found, putting in data/screenshots")
|
|
else if (fexists("code"))
|
|
// We are probably running in a local build
|
|
fcopy(icon, filename)
|
|
TEST_FAIL("Screenshot for [name] did not exist. One has been created.")
|
|
else
|
|
// We are probably running in real CI, so just pretend it worked and move on
|
|
fcopy(icon, "data/screenshots_new/[path_prefix]_[name].png")
|
|
|
|
log_test("\t[path_prefix]_[name] was put in data/screenshots_new")
|
|
|
|
/// 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 = SSmapping.config.map_name
|
|
|
|
// Need to escape the text to properly support newlines.
|
|
var/annotation_text = replacetext(text, "%", "%25")
|
|
annotation_text = replacetext(annotation_text, "\n", "%0A")
|
|
|
|
log_world("::[priority] file=[file],line=[line],title=[map_name]: [type]::[annotation_text]")
|
|
|
|
/proc/RunUnitTest(test_path, list/test_results)
|
|
var/datum/unit_test/test = new test_path
|
|
|
|
GLOB.current_test = test
|
|
var/duration = REALTIMEOFDAY
|
|
|
|
log_world("::group::[test_path]")
|
|
test.Run()
|
|
|
|
duration = REALTIMEOFDAY - duration
|
|
GLOB.current_test = null
|
|
GLOB.failed_any_test |= !test.succeeded
|
|
|
|
var/list/log_entry = list()
|
|
var/list/fail_reasons = test.fail_reasons
|
|
|
|
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.log_for_test(text, "error", file, line)
|
|
|
|
// Normal log message
|
|
log_entry += "\tFAILURE #[reasonID]: [text] at [file]:[line]"
|
|
|
|
var/message = log_entry.Join("\n")
|
|
log_test(message)
|
|
|
|
var/test_output_desc = "[test_path] [duration / 10]s"
|
|
if (test.succeeded)
|
|
log_world("[TEST_OUTPUT_GREEN("PASS")] [test_output_desc]")
|
|
|
|
log_world("::endgroup::")
|
|
|
|
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)
|
|
|
|
qdel(test)
|
|
|
|
/proc/RunUnitTests()
|
|
CHECK_TICK
|
|
|
|
var/list/tests_to_run = subtypesof(/datum/unit_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.focus))
|
|
focused_tests += test_to_run
|
|
if(length(focused_tests))
|
|
tests_to_run = focused_tests
|
|
|
|
tests_to_run = sortTim(tests_to_run, /proc/cmp_unit_test_priority)
|
|
|
|
var/list/test_results = list()
|
|
|
|
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)
|
|
|
|
var/file_name = "data/unit_tests.json"
|
|
fdel(file_name)
|
|
file(file_name) << json_encode(test_results)
|
|
|
|
SSticker.force_ending = TRUE
|
|
//We have to call this manually because del_text can preceed us, and SSticker doesn't fire in the post game
|
|
SSticker.standard_reboot()
|
|
|
|
/datum/map_template/unit_tests
|
|
name = "Unit Tests Zone"
|
|
mappath = "_maps/templates/unit_tests.dmm"
|