Skip to content

Commit

Permalink
I650 more warnings (#653)
Browse files Browse the repository at this point in the history
* tool to change warnings from command line
* command line is suppressing all warnings now
* disable warnings when running from editor
* add diff option, use it with set output
* some changes to test w/ and w/o warnings manager
  • Loading branch information
bitwes authored Aug 3, 2024
1 parent 3515446 commit 26e0a80
Show file tree
Hide file tree
Showing 21 changed files with 565 additions and 95 deletions.
239 changes: 239 additions & 0 deletions addons/gut/cli/change_project_warnings.gd
Original file line number Diff line number Diff line change
@@ -0,0 +1,239 @@
extends SceneTree

var Optparse = load('res://addons/gut/cli/optparse.gd')
var WarningsManager = load("res://addons/gut/warnings_manager.gd")
const WARN_VALUE_PRINT_POSITION = 36

var godot_default_warnings = {
"assert_always_false": 1, "assert_always_true": 1, "confusable_identifier": 1,
"confusable_local_declaration": 1, "confusable_local_usage": 1, "constant_used_as_function": 1,
"deprecated_keyword": 1, "empty_file": 1, "enable": true,
"exclude_addons": true, "function_used_as_property": 1, "get_node_default_without_onready": 2,
"incompatible_ternary": 1, "inference_on_variant": 2, "inferred_declaration": 0,
"int_as_enum_without_cast": 1, "int_as_enum_without_match": 1, "integer_division": 1,
"narrowing_conversion": 1, "native_method_override": 2, "onready_with_export": 2,
"property_used_as_function": 1, "redundant_await": 1, "redundant_static_unload": 1,
"renamed_in_godot_4_hint": 1, "return_value_discarded": 0, "shadowed_global_identifier": 1,
"shadowed_variable": 1, "shadowed_variable_base_class": 1, "standalone_expression": 1,
"standalone_ternary": 1, "static_called_on_instance": 1, "unassigned_variable": 1,
"unassigned_variable_op_assign": 1, "unreachable_code": 1, "unreachable_pattern": 1,
"unsafe_call_argument": 0, "unsafe_cast": 0, "unsafe_method_access": 0,
"unsafe_property_access": 0, "unsafe_void_return": 1, "untyped_declaration": 0,
"unused_local_constant": 1, "unused_parameter": 1, "unused_private_class_variable": 1,
"unused_signal": 1, "unused_variable": 1
}

var gut_default_changes = {
"exclude_addons": false, "redundant_await": 0,
}

var warning_settings = {}

func _setup_warning_settings():
warning_settings["godot_default"] = godot_default_warnings
warning_settings["current"] = WarningsManager.create_warnings_dictionary_from_project_settings()
warning_settings["all_warn"] = WarningsManager.create_warn_all_warnings_dictionary()

var gut_default = godot_default_warnings.duplicate()
gut_default.merge(gut_default_changes, true)
warning_settings["gut_default"] = gut_default


func _warn_value_to_s(value):
var readable = str(value).capitalize()
if(typeof(value) == TYPE_INT):
readable = WarningsManager.WARNING_LOOKUP.get(value, str(readable, ' ???'))
readable = readable.capitalize()
return readable


func _human_readable(warnings):
var to_return = ""
for key in warnings:
var readable = _warn_value_to_s(warnings[key])
to_return += str(key.capitalize().rpad(35, ' '), readable, "\n")
return to_return


func _dump_settings(which):
if(warning_settings.has(which)):
GutUtils.pretty_print(warning_settings[which])
else:
print("UNKNOWN print option ", which)


func _print_settings(which):
if(warning_settings.has(which)):
print(_human_readable(warning_settings[which]))
else:
print("UNKNOWN print option ", which)


func _apply_settings(which):
if(!warning_settings.has(which)):
print("UNKNOWN set option ", which)
return

var pre_settings = warning_settings["current"]
var new_settings = warning_settings[which]

if(new_settings == pre_settings):
print("-- Settings are the same, no changes were made --")
return

WarningsManager.apply_warnings_dictionary(new_settings)
ProjectSettings.save()
print("-- Project Warning Settings have been updated --")
print(_diff_changes_text(pre_settings))


func _diff_text(w1, w2, diff_col_pad=10):
var to_return = ""
for key in w1:
var v1_text = _warn_value_to_s(w1[key])
var v2_text = _warn_value_to_s(w2[key])
var diff_text = v1_text
var prefix = " "

if(v1_text != v2_text):
var diff_prefix = " "
if(w1[key] > w2[key]):
diff_prefix = "-"
else:
diff_prefix = "+"
prefix = "* "
diff_text = str(v1_text.rpad(diff_col_pad, ' '), diff_prefix, v2_text)

to_return += str(str(prefix, key.capitalize()).rpad(WARN_VALUE_PRINT_POSITION, ' '), diff_text, "\n")

return to_return.rstrip("\n")


func _diff_changes_text(pre_settings):
var orig_diff_text = _diff_text(
pre_settings,
WarningsManager.create_warnings_dictionary_from_project_settings(),
0)
# these next two lines are fragile and brute force...enjoy
var diff_text = orig_diff_text.replace("-", " -> ")
diff_text = diff_text.replace("+", " -> ")

if(orig_diff_text == diff_text):
diff_text += "\n-- No changes were made --"
else:
diff_text += "\nChanges will not be visible in Godot until it is restarted.\n"
diff_text += "Even if it asks you to reload...Maybe. Probably."

return diff_text



func _diff(name_1, name_2):
if(warning_settings.has(name_1) and warning_settings.has(name_2)):
var c2_pad = name_1.length() + 2
var heading = str(" ".repeat(WARN_VALUE_PRINT_POSITION), name_1.rpad(c2_pad, ' '), name_2, "\n")
heading += str(
" ".repeat(WARN_VALUE_PRINT_POSITION),
"-".repeat(name_1.length()).rpad(c2_pad, " "),
"-".repeat(name_2.length()),
"\n")

var text = _diff_text(warning_settings[name_1], warning_settings[name_2], c2_pad)

print(heading)
print(text)

var diff_count = 0
for line in text.split("\n"):
if(!line.begins_with(" ")):
diff_count += 1

if(diff_count == 0):
print('-- [', name_1, "] and [", name_2, "] are the same --")
else:
print('-- There are ', diff_count, ' differences between [', name_1, "] and [", name_2, "] --")
else:
print("One or more unknown Warning Level Names:, [", name_1, "] [", name_2, "]")


func _set_settings(nvps):
var pre_settings = warning_settings["current"]
for i in range(nvps.size()/2):
var s_name = nvps[i * 2]
var s_value = nvps[i * 2 + 1]
if(godot_default_warnings.has(s_name)):
var t = typeof(godot_default_warnings[s_name])
if(t == TYPE_INT):
s_value = s_value.to_int()
elif(t == TYPE_BOOL):
s_value = s_value.to_lower() == 'true'

WarningsManager.set_project_setting_warning(s_name, s_value)
ProjectSettings.save()
print(_diff_changes_text(pre_settings))



func _setup_options():
var opts = Optparse.new()
opts.banner = """
This script prints info about or sets the warning settings for the project.
Each action requires one or more Warning Level Names.
Warning Level Names:
* current The current settings for the project.
* godot_default The default settings for Godot.
* gut_default The warning settings that is used when developing GUT.
* all_warn Everything set to warn.
""".dedent()

opts.add('-h', false, 'Print this help')
opts.add('-set', [], "Sets a single setting in the project settings and saves.\n" +
"Use -dump to see a list of setting names and values.\n" +
"Example: -set enabled,true -set unsafe_cast,2 -set unreachable_code,0")
opts.add_heading(" Actions (require Warning Level Name)")
opts.add('-diff', [], "Shows the difference between two Warning Level Names.\n" +
"Example: -diff current,all_warn")
opts.add('-dump', 'none', "Prints a dictionary of the warning values.")
opts.add('-print', 'none', "Print human readable warning values.")
opts.add('-apply', 'none', "Applys one of the Warning Level Names to the project settings. You should restart after using this")

return opts

func _print_help(opts):
opts.print_help()



func _init():
# Testing might set this flag but it should never be disabled for this tool
# or it cannot save project settings, but says it did. Sneakily use the
# private property to get around this property being read-only. Don't
# try this at home.
WarningsManager._disabled = false

_setup_warning_settings()

var opts = _setup_options()
opts.parse()

if(opts.unused.size() != 0):
opts.print_help()
print("Unknown arguments ", opts.unused)
if(opts.values.h):
opts.print_help()
elif(opts.values.print != 'none'):
_print_settings(opts.values.print)
elif(opts.values.dump != 'none'):
_dump_settings(opts.values.dump)
elif(opts.values.apply != 'none'):
_apply_settings(opts.values.apply )
elif(opts.values.diff.size() == 2):
_diff(opts.values.diff[0], opts.values.diff[1])
elif(opts.values.set.size() % 2 == 0):
_set_settings(opts.values.set)
else:
opts.print_help()
print("You didn't specify any options or too many or not the right size or something invalid. I don't know what you want to do.")

quit()
1 change: 0 additions & 1 deletion addons/gut/cli/gut_cli.gd
Original file line number Diff line number Diff line change
Expand Up @@ -214,7 +214,6 @@ func _run_tests(opt_resolver):
_gut_config.options = _final_opts

var runner = GutRunner.instantiate()
runner.ran_from_editor = false
runner.set_gut_config(_gut_config)
get_tree().root.add_child(runner)

Expand Down
21 changes: 19 additions & 2 deletions addons/gut/cli/optparse.gd
Original file line number Diff line number Diff line change
Expand Up @@ -161,8 +161,10 @@ class Option:


func to_s(min_space=0):
var line_indent = str("\n", " ".repeat(min_space + 1))
var subbed_desc = description
subbed_desc = subbed_desc.replace('[default]', str(default))
subbed_desc = subbed_desc.replace("\n", line_indent)
return str(option_name.rpad(min_space), ' ', subbed_desc)


Expand Down Expand Up @@ -236,7 +238,7 @@ class Options:
if(heading != default_heading):
text += str("\n", heading.display, "\n")
for option in heading.options:
text += str(' ', option.to_s(longest + 2), "\n")
text += str(' ', option.to_s(longest + 2).replace("\n", "\n "), "\n")


return text
Expand Down Expand Up @@ -292,6 +294,8 @@ class Options:





#-------------------------------------------------------------------------------
#
# optarse
Expand All @@ -302,6 +306,18 @@ var banner = ''
var option_name_prefix = '-'
var unused = []
var parsed_args = []
var values = {}

func _populate_values_dictionary():
for entry in options.options:
var value_key = entry.option_name.lstrip('-')
values[value_key] = entry.value

for entry in options.positional:
var value_key = entry.option_name.lstrip('-')
values[value_key] = entry.value



func _convert_value_to_array(raw_value):
var split = raw_value.split(',')
Expand Down Expand Up @@ -386,7 +402,7 @@ func _parse_command_line_arguments(args):


func is_option(arg):
return arg.begins_with(option_name_prefix)
return str(arg).begins_with(option_name_prefix)


func add(op_name, default, desc):
Expand Down Expand Up @@ -478,6 +494,7 @@ func parse(cli_args=null):
parsed_args.append_array(OS.get_cmdline_user_args())

unused = _parse_command_line_arguments(parsed_args)
_populate_values_dictionary()


func get_missing_required_options():
Expand Down
2 changes: 1 addition & 1 deletion addons/gut/gui/GutBottomPanel.gd
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,7 @@ func _run_tests():
_ctrls.run_results.clear()
_ctrls.run_results.add_centered_text('Running...')

_interface.play_custom_scene('res://addons/gut/gui/GutRunner.tscn')
_interface.play_custom_scene('res://addons/gut/gui/run_from_editor.tscn')
_is_running = true
_ctrls.output_ctrl.add_text('Running...')

Expand Down
3 changes: 0 additions & 3 deletions addons/gut/gui/GutControl.gd
Original file line number Diff line number Diff line change
Expand Up @@ -50,9 +50,6 @@ func _ready():
_config_gui = GutConfigGui.new(_ctrls.settings_vbox)

_ctrls.test_tree.hide_root = true
# Stop tests from kicking off when the runner is "ready" and prevents it
# from writing results file that is used by the panel.
_gut_runner.ran_from_editor = false
add_child(_gut_runner)

# TODO This might not need to be called deferred after changing GutUtils to
Expand Down
Loading

0 comments on commit 26e0a80

Please sign in to comment.