forked from datawhale/whale-town-front
- 修复 WebSocketManager/SocketIOClient 函数缩进错误 - 重命名 is_connected() 避免与 Object 基类冲突 - 修复 tscn 文件多余前导空格 - 修复测试文件 GUT 断言函数调用 - 添加 GUT 测试框架
222 lines
6.6 KiB
GDScript
222 lines
6.6 KiB
GDScript
# ------------------------------------------------------------------------------
|
|
# It keeps track of the orphans...so this is best name it could ever have.
|
|
# ------------------------------------------------------------------------------
|
|
class Orphanage:
|
|
const UNGROUPED = "Outside Tests"
|
|
const SUBGROUP_SEP = '->'
|
|
|
|
var orphan_ids = {}
|
|
var oprhans_by_group = {}
|
|
var strutils = GutUtils.Strutils.new()
|
|
|
|
# wrapper for stubbing
|
|
func _get_system_orphan_node_ids():
|
|
return Node.get_orphan_node_ids()
|
|
|
|
|
|
func _make_group_key(group=null, subgroup=null):
|
|
var to_return = UNGROUPED
|
|
if(group != null):
|
|
to_return = group
|
|
|
|
if(subgroup == null):
|
|
to_return += str(SUBGROUP_SEP, UNGROUPED)
|
|
else:
|
|
to_return += str(SUBGROUP_SEP, subgroup)
|
|
|
|
return to_return
|
|
|
|
|
|
func _add_orphan_by_group(id, group, subgroup):
|
|
var key = _make_group_key(group, subgroup)
|
|
if(oprhans_by_group.has(key)):
|
|
oprhans_by_group[key].append(id)
|
|
else:
|
|
oprhans_by_group[key] = [id]
|
|
|
|
|
|
func process_orphans(group=null, subgroup=null):
|
|
var new_orphans = []
|
|
for orphan_id in _get_system_orphan_node_ids():
|
|
if(!orphan_ids.has(orphan_id)):
|
|
new_orphans.append(orphan_id)
|
|
orphan_ids[orphan_id] = {
|
|
"group":GutUtils.nvl(group, UNGROUPED),
|
|
"subgroup":GutUtils.nvl(subgroup, UNGROUPED),
|
|
"instance":instance_from_id(orphan_id)
|
|
}
|
|
_add_orphan_by_group(orphan_id, group, subgroup)
|
|
|
|
return new_orphans
|
|
|
|
|
|
func get_orphan_ids(group=null, subgroup=null):
|
|
var key = _make_group_key(group, subgroup)
|
|
return oprhans_by_group.get(key, [])
|
|
|
|
|
|
# Given the likely size, this was way easier than making a dictionary
|
|
# of dictionaries of arrays.
|
|
func get_all_group_orphans(group):
|
|
var to_return = []
|
|
for key in oprhans_by_group:
|
|
if(key == group or key.begins_with(str(group, SUBGROUP_SEP))):
|
|
to_return.append_array(oprhans_by_group[key])
|
|
return to_return
|
|
|
|
|
|
# clears out anything that is not still an orphan.
|
|
func clean():
|
|
oprhans_by_group.clear()
|
|
for key in orphan_ids.keys():
|
|
var inst = orphan_ids[key].instance
|
|
if(!is_instance_valid(inst) or inst.get_parent() != null and not orphan_ids.has(inst.get_parent().get_instance_id())):
|
|
orphan_ids.erase(key)
|
|
else:
|
|
_add_orphan_by_group(key, orphan_ids[key].group, orphan_ids[key].subgroup)
|
|
|
|
|
|
|
|
|
|
# ------------------------------------------------------------------------------
|
|
# ------------------------------------------------------------------------------
|
|
var _strutils = GutStringUtils.new()
|
|
|
|
var orphanage : Orphanage = Orphanage.new()
|
|
var logger = GutUtils.get_logger()
|
|
var autofree = GutUtils.AutoFree.new()
|
|
|
|
|
|
func _count_all_children(instance):
|
|
var count = instance.get_child_count()
|
|
for child in instance.get_children():
|
|
count += _count_all_children(child)
|
|
return count
|
|
|
|
|
|
func get_orphan_list_text(orphan_ids):
|
|
var text = ""
|
|
for id in orphan_ids:
|
|
var kid_count_text = ''
|
|
var inst = orphanage.orphan_ids[id].instance
|
|
if(is_instance_valid(inst) and inst.get_parent() == null):
|
|
var kid_count = _count_all_children(inst)
|
|
if(kid_count != 0):
|
|
kid_count_text = str(' + ', kid_count)
|
|
|
|
var autofree_text = ''
|
|
if(autofree.has_instance_id(id)):
|
|
autofree_text = (" (autofree)")
|
|
|
|
if(text != ''):
|
|
text += "\n"
|
|
text += str('* [', _strutils.type2str(inst), ']', kid_count_text, autofree_text)
|
|
|
|
return text
|
|
|
|
|
|
func orphan_count() -> int:
|
|
return int(Performance.get_monitor(Performance.OBJECT_ORPHAN_NODE_COUNT))
|
|
|
|
|
|
func record_orphans(group, subgroup = null):
|
|
return orphanage.process_orphans(group, subgroup)
|
|
|
|
|
|
func convert_instance_ids_to_valid_instances(instance_ids):
|
|
var to_return = []
|
|
for entry in instance_ids:
|
|
if(is_instance_id_valid(entry)):
|
|
to_return.append(instance_from_id(entry))
|
|
return to_return
|
|
|
|
|
|
func end_script(script_path, should_log):
|
|
record_orphans(script_path)
|
|
var orphans = orphanage.get_all_group_orphans(script_path)
|
|
if(orphans.size() > 0 and should_log):
|
|
logger.orphan(str(orphans.size(), ' orphans'))
|
|
|
|
|
|
func end_test(script_path, test_name, should_log = true):
|
|
record_orphans(script_path, test_name)
|
|
orphanage.clean()
|
|
# Must get all the orphans and not just the results of record_orphans
|
|
# because record_orphans may have been called for this group/subgroup
|
|
# already.
|
|
var orphans = get_orphan_ids(script_path, test_name)
|
|
if(orphans.size() > 0 and should_log):
|
|
logger.orphan(str(orphans.size(), ' Orphans'))
|
|
logger.inc_indent()
|
|
logger.orphan(get_orphan_list_text(orphans))
|
|
logger.dec_indent()
|
|
|
|
|
|
func get_orphan_ids(group=null, subgroup=null):
|
|
var ids = []
|
|
if(group == null):
|
|
ids = orphanage.orphan_ids.keys()
|
|
elif(subgroup == null):
|
|
ids = orphanage.get_all_group_orphans(group)
|
|
else:
|
|
ids = orphanage.get_orphan_ids(group, subgroup)
|
|
|
|
return ids
|
|
|
|
|
|
func get_count() -> int:
|
|
return orphan_count()
|
|
|
|
|
|
func log_all():
|
|
var last_script = ''
|
|
var last_test = ''
|
|
|
|
for id in orphanage.orphan_ids:
|
|
var entry = orphanage.orphan_ids[id]
|
|
|
|
if(last_script != entry.group):
|
|
last_script = entry.group
|
|
last_test = ''
|
|
logger.log(entry.group)
|
|
|
|
if(last_test != entry.subgroup):
|
|
logger.inc_indent()
|
|
logger.log(str('- ', entry.subgroup))
|
|
last_test = entry.subgroup
|
|
logger.inc_indent()
|
|
var orphan_ids = orphanage.get_orphan_ids(last_script, last_test)
|
|
logger.orphan(get_orphan_list_text(orphan_ids))
|
|
logger.dec_indent()
|
|
logger.dec_indent()
|
|
|
|
|
|
# ##############################################################################
|
|
#(G)odot (U)nit (T)est class
|
|
#
|
|
# ##############################################################################
|
|
# The MIT License (MIT)
|
|
# =====================
|
|
#
|
|
# Copyright (c) 2025 Tom "Butch" Wesley
|
|
#
|
|
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
# of this software and associated documentation files (the "Software"), to deal
|
|
# in the Software without restriction, including without limitation the rights
|
|
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
# copies of the Software, and to permit persons to whom the Software is
|
|
# furnished to do so, subject to the following conditions:
|
|
#
|
|
# The above copyright notice and this permission notice shall be included in
|
|
# all copies or substantial portions of the Software.
|
|
#
|
|
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
# THE SOFTWARE.
|
|
#
|
|
# ##############################################################################
|