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

322 lines
10 KiB
GDScript

@tool
extends ConfirmationDialog
const RUN_MODE_EDITOR = 'Editor'
const RUN_MODE_BLOCKING = 'Blocking'
const RUN_MODE_NON_BLOCKING = 'NonBlocking'
var GutEditorGlobals = load('res://addons/gut/gui/editor_globals.gd')
@onready var _bad_arg_dialog = $AcceptDialog
@onready var _main_container = $ScrollContainer/VBoxContainer
var _blurb_style_box = StyleBoxEmpty.new()
var _opt_maker_setup = false
var _arg_vbox : VBoxContainer = null
var _my_ok_button : Button = null
# Run mode button stuff
var _run_mode_theme = load('res://addons/gut/gui/EditorRadioButton.tres')
var _button_group = ButtonGroup.new()
var _btn_in_editor : Button = null
var _btn_blocking : Button = null
var _btn_non_blocking : Button = null
var _txt_additional_arguments = null
var _btn_godot_help = null
var _btn_gut_help = null
var opt_maker = null
var default_path = GutEditorGlobals.run_externally_options_path
# I like this. It holds values loaded/saved which makes for an easy
# reset mechanism. Hit OK; values get written to this object (not the file
# system). Hit Cancel; values are reloaded from this object. Call the
# save/load methods to interact with the file system.
#
# Downside: If the keys/sections in the config file change, this ends up
# preserving old data. So you gotta find a way to clean it out
# somehow.
# Downside solved: Clear the config file at the start of the save method.
var _config_file = ConfigFile.new()
var _run_mode = RUN_MODE_EDITOR
var run_mode = _run_mode:
set(val):
_run_mode = val
if(is_inside_tree()):
_btn_in_editor.button_pressed = _run_mode == RUN_MODE_EDITOR
if(_btn_in_editor.button_pressed):
_btn_in_editor.pressed.emit()
_btn_blocking.button_pressed = _run_mode == RUN_MODE_BLOCKING
if(_btn_blocking.button_pressed):
_btn_blocking.pressed.emit()
_btn_non_blocking.button_pressed = _run_mode == RUN_MODE_NON_BLOCKING
if(_btn_non_blocking.button_pressed):
_btn_non_blocking.pressed.emit()
get():
return _run_mode
var additional_arguments = '' :
get():
if(_opt_maker_setup):
return opt_maker.controls.additional_arguments.value
else:
return additional_arguments
func _debug_ready():
popup_centered()
default_path = GutEditorGlobals.temp_directory.path_join('test_external_run_options.cfg')
exclusive = false
var save_btn = Button.new()
save_btn.text = 'save'
save_btn.pressed.connect(func():
save_to_file()
print(_config_file.encode_to_text()))
save_btn.position = Vector2(100, 20)
save_btn.size = Vector2(100, 100)
get_tree().root.add_child(save_btn)
var load_btn = Button.new()
load_btn.text = 'load'
load_btn.pressed.connect(func():
load_from_file()
print(_config_file.encode_to_text()))
load_btn.position = Vector2(100, 130)
load_btn.size = Vector2(100, 100)
get_tree().root.add_child(load_btn)
var show_btn = Button.new()
show_btn.text = 'Show'
show_btn.pressed.connect(popup_centered)
show_btn.position = Vector2(100, 250)
show_btn.size = Vector2(100, 100)
get_tree().root.add_child(show_btn)
func _ready():
opt_maker = GutUtils.OptionMaker.new(_main_container)
_add_controls()
if(get_parent() == get_tree().root):
_debug_ready.call_deferred()
_my_ok_button = Button.new()
_my_ok_button.text = 'OK'
_my_ok_button.pressed.connect(_validate_and_confirm)
get_ok_button().add_sibling(_my_ok_button)
get_ok_button().modulate.a = 0.0
get_ok_button().text = ''
get_ok_button().disabled = true
canceled.connect(reset)
_button_group.pressed.connect(_on_mode_button_pressed)
run_mode = run_mode
func _validate_and_confirm():
if(validate_arguments()):
_save_to_config_file(_config_file)
confirmed.emit()
hide()
else:
var dlg_text = str("Invalid arguments. The following cannot be used:\n",
' '.join(_invalid_args))
if(run_mode == RUN_MODE_BLOCKING):
dlg_text += str("\nThese cannot be used with blocking mode:\n",
' '.join(_invalid_blocking_args))
_bad_arg_dialog.dialog_text = dlg_text
_bad_arg_dialog.popup_centered()
func _on_mode_button_pressed(which):
if(which == _btn_in_editor):
_arg_vbox.modulate.a = .3
else:
_arg_vbox.modulate.a = 1.0
_txt_additional_arguments.value_ctrl.editable = which != _btn_in_editor
if(which == _btn_in_editor):
_run_mode = RUN_MODE_EDITOR
elif(which == _btn_blocking):
_run_mode = RUN_MODE_BLOCKING
elif(which == _btn_non_blocking):
_run_mode = RUN_MODE_NON_BLOCKING
func _add_run_mode_button(text, desc_label, description):
var btn = Button.new()
btn.size_flags_horizontal = Control.SIZE_EXPAND_FILL
btn.toggle_mode = true
btn.text = text
btn.button_group = _button_group
btn.theme = _run_mode_theme
btn.pressed.connect(func(): desc_label.text = str('[b]', text, "[/b]\n", description))
return btn
func _add_blurb(text):
var ctrl = opt_maker.add_blurb(text)
ctrl.set("theme_override_styles/normal", _blurb_style_box)
return ctrl
func _add_title(text):
var ctrl = opt_maker.add_title(text)
ctrl.get_child(0).horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER
return ctrl
func _add_controls():
_add_title("Run Modes")
_add_blurb(
"Choose how GUT will launch tests. Normally you just run them through the editor, but now " +
"you can run them externally. This is an experimental feature. It has been tested on Mac " +
"and Windows. Your results may vary. Feedback welcome at [url]https://github.com/bitwes/Gut/issues[/url].\n ")
var button_desc_box = HBoxContainer.new()
var button_box = VBoxContainer.new()
var button_desc = RichTextLabel.new()
button_desc.fit_content = true
button_desc.bbcode_enabled = true
button_desc.size_flags_horizontal = Control.SIZE_EXPAND_FILL
button_desc.autowrap_mode = TextServer.AUTOWRAP_WORD_SMART
_main_container.add_child(button_desc_box)
button_desc_box.add_child(button_box)
button_desc_box.add_child(button_desc)
_btn_in_editor = _add_run_mode_button("In Editor (default)", button_desc,
"This is the default. Runs through the editor. When an error occurs " +
"the debugger is invoked. [b]print[/b] output " +
"appears in the Output panel and errors show up in the Debugger panel.")
button_box.add_child(_btn_in_editor)
_btn_blocking = _add_run_mode_button("Externally - Blocking", button_desc,
"Debugger is not enabled, and cannot be enabled. All output (print, errors, warnings, etc) " +
"appears in the GUT panel, and [b]not[/b] the Output or Debugger panels. \n" +
"The Editor cannot be used while tests are running. If you are trying to test for errors, this " +
"mode provides the best output.")
button_box.add_child(_btn_blocking)
_btn_non_blocking = _add_run_mode_button("Externally - NonBlocking", button_desc,
"Debugger is not enabled, and cannot be enabled. All output (print, errors, warnings, etc) " +
"appears in the GUT panel, and [b]not[/b] the Output or Debugger panels. \n" +
"Test output is streamed to the GUT panel. The editor is not blocked, but can be less " +
"responsive when there is a lot of output. This is the only mode that supports the --headless argument." )
button_box.add_child(_btn_non_blocking)
_add_title("Command Line Arguments")
_arg_vbox = VBoxContainer.new()
_main_container.add_child(_arg_vbox)
opt_maker.base_container = _arg_vbox
_txt_additional_arguments = opt_maker.add_value("additional_arguments", additional_arguments, '', '')
_txt_additional_arguments.value_ctrl.placeholder_text = "Put your arguments here. Ex: --verbose -glog 0"
_txt_additional_arguments.value_ctrl.select_all_on_focus = false
_add_blurb(
"Supply any command line options for GUT and/or Godot when running externally. You cannot use " +
"spaces in values. See the Godot and GUT documentation for valid arguments. GUT arguments " +
"specified here take precedence over your config.")
_add_blurb("[b]Be Careful[/b] There are plenty of argument combinations that may make this " +
"act wrong/odd/bad/horrible. Some arguments you might [i]want[/i] " +
"to use but [b]shouldn't[/b] are checked for, but not that many. Choose your arguments carefully (generally good advice).")
opt_maker.base_container = _main_container
_add_title("Display CLI Help")
_add_blurb("You can use these buttons to get a list of valid GUT and Godot options. They print the CLI help text for each to the [b]Output Panel[/b].")
_btn_godot_help = Button.new()
_btn_godot_help.text = "Print Godot CLI Help"
_main_container.add_child(_btn_godot_help)
_btn_godot_help.pressed.connect(func():
await _show_help("get_godot_help"))
_btn_gut_help = Button.new()
_btn_gut_help.text = "Print GUT CLI Help"
_main_container.add_child(_btn_gut_help)
_btn_gut_help.pressed.connect(func():
await _show_help("get_gut_help"))
_opt_maker_setup = true
func _show_help(help_method_name):
_btn_godot_help.disabled = true
_btn_gut_help.disabled = true
var re = GutUtils.RunExternallyScene.instantiate()
add_child(re)
re.visible = false
var text = await re.call(help_method_name)
print(text)
re.queue_free()
_btn_godot_help.disabled = false
_btn_gut_help.disabled = false
if(GutEditorGlobals.gut_plugin != null):
GutEditorGlobals.gut_plugin.show_output_panel()
func _save_to_config_file(f : ConfigFile):
f.clear()
f.set_value('main', 'run_mode', run_mode)
f.set_value('main', 'additional_arguments', opt_maker.controls.additional_arguments.value)
func save_to_file(path = default_path):
_save_to_config_file(_config_file)
_config_file.save(path)
func _load_from_config_file(f):
run_mode = f.get_value('main', 'run_mode', RUN_MODE_EDITOR)
opt_maker.controls.additional_arguments.value = \
f.get_value('main', 'additional_arguments', '')
func load_from_file(path = default_path):
_config_file.load(path)
_load_from_config_file(_config_file)
func reset():
_load_from_config_file(_config_file)
func get_additional_arguments_array():
return additional_arguments.split(" ", false)
func should_run_externally():
return run_mode != RUN_MODE_EDITOR
var _invalid_args = [
'-d', '--debug',
'-s', '--script',
'-e', '--editor'
]
var _invalid_blocking_args = [
'--headless'
]
func validate_arguments():
var arg_array = get_additional_arguments_array()
var i = 0
var invalid_found = false
while i < _invalid_args.size() and !invalid_found:
if(arg_array.has(_invalid_args[i])):
invalid_found = true
i += 1
if(run_mode == RUN_MODE_BLOCKING):
i = 0
while i < _invalid_blocking_args.size() and !invalid_found:
if(arg_array.has(_invalid_blocking_args[i])):
invalid_found = true
i += 1
return !invalid_found
func get_godot_help():
return ''