mirror of
https://github.com/SPLURT-Station/S.P.L.U.R.T-Station-13.git
synced 2026-08-22 12:16:40 +01:00
unit test
this is the easy part, believe it or not
This commit is contained in:
@@ -3,7 +3,7 @@
|
||||
Usage:
|
||||
Override /Run() to run your test code
|
||||
|
||||
Call Fail() to fail the test (You should specify a reason)
|
||||
Call TEST_FAIL() to fail the test (You should specify a reason)
|
||||
|
||||
You may use /New() and /Destroy() for setup/teardown respectively
|
||||
|
||||
@@ -15,6 +15,18 @@ GLOBAL_DATUM(current_test, /datum/unit_test)
|
||||
GLOBAL_VAR_INIT(failed_any_test, FALSE)
|
||||
GLOBAL_VAR(test_log)
|
||||
|
||||
/// A list of every test that is currently focused.
|
||||
/// Use the PERFORM_ALL_TESTS macro instead.
|
||||
GLOBAL_VAR_INIT(focused_tests, focused_tests())
|
||||
|
||||
/proc/focused_tests()
|
||||
var/list/focused_tests = list()
|
||||
for (var/datum/unit_test/unit_test as anything in subtypesof(/datum/unit_test))
|
||||
if (initial(unit_test.focus))
|
||||
focused_tests += unit_test
|
||||
|
||||
return focused_tests.len > 0 ? focused_tests : null
|
||||
|
||||
/datum/unit_test
|
||||
//Bit of metadata for the future maybe
|
||||
var/list/procs_tested
|
||||
@@ -62,15 +74,15 @@ GLOBAL_VAR(test_log)
|
||||
return ..()
|
||||
|
||||
/datum/unit_test/proc/Run()
|
||||
Fail("Run() called parent or not implemented")
|
||||
TEST_FAIL("Run() called parent or not implemented")
|
||||
|
||||
/datum/unit_test/proc/Fail(reason = "No reason")
|
||||
/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, reason)
|
||||
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
|
||||
@@ -80,16 +92,71 @@ GLOBAL_VAR(test_log)
|
||||
arguments = list(run_loc_floor_bottom_left)
|
||||
else if (arguments[1] == null)
|
||||
arguments[1] = run_loc_floor_bottom_left
|
||||
var/instance = new type(arglist(arguments))
|
||||
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")
|
||||
|
||||
/// Helper for screenshot tests to take an image of an atom from all directions and insert it into one icon
|
||||
/datum/unit_test/proc/get_flat_icon_for_all_directions(atom/thing, no_anim = TRUE)
|
||||
var/icon/output = icon('icons/effects/effects.dmi', "nothing")
|
||||
|
||||
for (var/direction in GLOB.cardinals)
|
||||
var/icon/partial = getFlatIcon(thing, defdir = direction, no_anim = no_anim)
|
||||
output.Insert(partial, dir = direction)
|
||||
|
||||
return output
|
||||
*/
|
||||
/// 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)
|
||||
/*
|
||||
if (ispath(test_path, /datum/unit_test/focus_only))
|
||||
return
|
||||
*/
|
||||
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
|
||||
@@ -99,11 +166,28 @@ GLOBAL_VAR(test_log)
|
||||
var/list/log_entry = list("[test.succeeded ? "PASS" : "FAIL"]: [test_path] [duration / 10]s")
|
||||
var/list/fail_reasons = test.fail_reasons
|
||||
|
||||
for(var/J in 1 to LAZYLEN(fail_reasons))
|
||||
log_entry += "\tREASON #[J]: [fail_reasons[J]]"
|
||||
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 += "\tREASON #[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)
|
||||
@@ -112,11 +196,13 @@ GLOBAL_VAR(test_log)
|
||||
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))
|
||||
tests_to_run = list(test_to_run)
|
||||
break
|
||||
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)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user