Files
whale-town-front/addons/gut/orphan_counter.gd
WhaleTown Developer c8e73bec59 fix: 修复聊天系统编译错误
- 修复 WebSocketManager/SocketIOClient 函数缩进错误
- 重命名 is_connected() 避免与 Object 基类冲突
- 修复 tscn 文件多余前导空格
- 修复测试文件 GUT 断言函数调用
- 添加 GUT 测试框架
2026-01-08 00:11:12 +08:00

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.
#
# ##############################################################################