Skip to content

Commit 2925879

Browse files
committed
Add Godot Unit Testing (GUT) plugin
Add and enable the Godot Unit Testing (GUT) plugin so we can start unit testing the plugin. GUT and pre-commit have been configured to use the top level `tests` directory so the tests aren't distributed with the plugin.
1 parent 38e7406 commit 2925879

File tree

128 files changed

+15789
-3
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

128 files changed

+15789
-3
lines changed

.gutconfig.json

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
{
2+
"dirs": [
3+
"res://tests"
4+
],
5+
"include_subdirs": true
6+
}

.pre-commit-config.yaml

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,5 +15,4 @@ repos:
1515
hooks:
1616
- id: gdformat
1717
args: [--line-length=200]
18-
files:
19-
^addons/block_code/(?!lib/).*$
18+
files: ^(addons/block_code/(?!lib/).*|tests/.*)$

addons/block_code/README.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,3 +38,9 @@ pre-commit install
3838
```
3939

4040
Now `pre-commit` will run automatically on `git commit`!
41+
42+
## Testing
43+
44+
This plugin uses the [Godot Unit Test](https://gut.readthedocs.io/en/latest/)
45+
(GUT) plugin for testing. In the editor, click on the GUT tab in the bottom
46+
panel to open the test panel. Then click Run All to run the tests.

addons/gut/GutScene.gd

Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
extends Node2D
2+
# ##############################################################################
3+
# This is a wrapper around the normal and compact gui controls and serves as
4+
# the interface between gut.gd and the gui. The GutRunner creates an instance
5+
# of this and then this takes care of managing the different GUI controls.
6+
# ##############################################################################
7+
@onready var _normal_gui = $Normal
8+
@onready var _compact_gui = $Compact
9+
10+
var gut = null :
11+
set(val):
12+
gut = val
13+
_set_gut(val)
14+
15+
16+
func _ready():
17+
_normal_gui.switch_modes.connect(use_compact_mode.bind(true))
18+
_compact_gui.switch_modes.connect(use_compact_mode.bind(false))
19+
20+
_normal_gui.set_title("GUT")
21+
_compact_gui.set_title("GUT")
22+
23+
_normal_gui.align_right()
24+
_compact_gui.to_bottom_right()
25+
26+
use_compact_mode(false)
27+
28+
if(get_parent() == get_tree().root):
29+
_test_running_setup()
30+
31+
func _test_running_setup():
32+
set_font_size(100)
33+
_normal_gui.get_textbox().text = "hello world, how are you doing?"
34+
35+
# ------------------------
36+
# Private
37+
# ------------------------
38+
func _set_gut(val):
39+
if(_normal_gui.get_gut() == val):
40+
return
41+
_normal_gui.set_gut(val)
42+
_compact_gui.set_gut(val)
43+
44+
val.start_run.connect(_on_gut_start_run)
45+
val.end_run.connect(_on_gut_end_run)
46+
val.start_pause_before_teardown.connect(_on_gut_pause)
47+
val.end_pause_before_teardown.connect(_on_pause_end)
48+
49+
func _set_both_titles(text):
50+
_normal_gui.set_title(text)
51+
_compact_gui.set_title(text)
52+
53+
54+
# ------------------------
55+
# Events
56+
# ------------------------
57+
func _on_gut_start_run():
58+
_set_both_titles('Running')
59+
60+
func _on_gut_end_run():
61+
_set_both_titles('Finished')
62+
63+
func _on_gut_pause():
64+
_set_both_titles('-- Paused --')
65+
66+
func _on_pause_end():
67+
_set_both_titles('Running')
68+
69+
70+
# ------------------------
71+
# Public
72+
# ------------------------
73+
func get_textbox():
74+
return _normal_gui.get_textbox()
75+
76+
77+
func set_font_size(new_size):
78+
var rtl = _normal_gui.get_textbox()
79+
80+
rtl.set('theme_override_font_sizes/bold_italics_font_size', new_size)
81+
rtl.set('theme_override_font_sizes/bold_font_size', new_size)
82+
rtl.set('theme_override_font_sizes/italics_font_size', new_size)
83+
rtl.set('theme_override_font_sizes/normal_font_size', new_size)
84+
85+
86+
func set_font(font_name):
87+
_set_all_fonts_in_rtl(_normal_gui.get_textbox(), font_name)
88+
89+
90+
func _set_font(rtl, font_name, custom_name):
91+
if(font_name == null):
92+
rtl.remove_theme_font_override(custom_name)
93+
else:
94+
var dyn_font = FontFile.new()
95+
dyn_font.load_dynamic_font('res://addons/gut/fonts/' + font_name + '.ttf')
96+
rtl.add_theme_font_override(custom_name, dyn_font)
97+
98+
99+
func _set_all_fonts_in_rtl(rtl, base_name):
100+
if(base_name == 'Default'):
101+
_set_font(rtl, null, 'normal_font')
102+
_set_font(rtl, null, 'bold_font')
103+
_set_font(rtl, null, 'italics_font')
104+
_set_font(rtl, null, 'bold_italics_font')
105+
else:
106+
_set_font(rtl, base_name + '-Regular', 'normal_font')
107+
_set_font(rtl, base_name + '-Bold', 'bold_font')
108+
_set_font(rtl, base_name + '-Italic', 'italics_font')
109+
_set_font(rtl, base_name + '-BoldItalic', 'bold_italics_font')
110+
111+
112+
func set_default_font_color(color):
113+
_normal_gui.get_textbox().set('custom_colors/default_color', color)
114+
115+
116+
func set_background_color(color):
117+
_normal_gui.set_bg_color(color)
118+
119+
120+
func use_compact_mode(should=true):
121+
_compact_gui.visible = should
122+
_normal_gui.visible = !should
123+
124+
125+
func set_opacity(val):
126+
_normal_gui.modulate.a = val
127+
_compact_gui.modulate.a = val

addons/gut/GutScene.tscn

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
[gd_scene load_steps=4 format=3 uid="uid://m28heqtswbuq"]
2+
3+
[ext_resource type="Script" path="res://addons/gut/GutScene.gd" id="1_b4m8y"]
4+
[ext_resource type="PackedScene" uid="uid://duxblir3vu8x7" path="res://addons/gut/gui/NormalGui.tscn" id="2_j6ywb"]
5+
[ext_resource type="PackedScene" uid="uid://cnqqdfsn80ise" path="res://addons/gut/gui/MinGui.tscn" id="3_3glw1"]
6+
7+
[node name="GutScene" type="Node2D"]
8+
script = ExtResource("1_b4m8y")
9+
10+
[node name="Normal" parent="." instance=ExtResource("2_j6ywb")]
11+
12+
[node name="Compact" parent="." instance=ExtResource("3_3glw1")]
13+
offset_left = 5.0
14+
offset_top = 273.0
15+
offset_right = 265.0
16+
offset_bottom = 403.0

addons/gut/LICENSE.md

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
The MIT License (MIT)
2+
=====================
3+
4+
Copyright (c) 2018 Tom "Butch" Wesley
5+
6+
Permission is hereby granted, free of charge, to any person obtaining a copy
7+
of this software and associated documentation files (the "Software"), to deal
8+
in the Software without restriction, including without limitation the rights
9+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10+
copies of the Software, and to permit persons to whom the Software is
11+
furnished to do so, subject to the following conditions:
12+
13+
The above copyright notice and this permission notice shall be included in
14+
all copies or substantial portions of the Software.
15+
16+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22+
THE SOFTWARE.

addons/gut/UserFileViewer.gd

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
extends Window
2+
3+
@onready var rtl = $TextDisplay/RichTextLabel
4+
5+
func _get_file_as_text(path):
6+
var to_return = null
7+
var f = FileAccess.open(path, FileAccess.READ)
8+
if(f != null):
9+
to_return = f.get_as_text()
10+
else:
11+
to_return = str('ERROR: Could not open file. Error code ', FileAccess.get_open_error())
12+
return to_return
13+
14+
func _ready():
15+
rtl.clear()
16+
17+
func _on_OpenFile_pressed():
18+
$FileDialog.popup_centered()
19+
20+
func _on_FileDialog_file_selected(path):
21+
show_file(path)
22+
23+
func _on_Close_pressed():
24+
self.hide()
25+
26+
func show_file(path):
27+
var text = _get_file_as_text(path)
28+
if(text == ''):
29+
text = '<Empty File>'
30+
rtl.set_text(text)
31+
self.window_title = path
32+
33+
func show_open():
34+
self.popup_centered()
35+
$FileDialog.popup_centered()
36+
37+
func get_rich_text_label():
38+
return $TextDisplay/RichTextLabel
39+
40+
func _on_Home_pressed():
41+
rtl.scroll_to_line(0)
42+
43+
func _on_End_pressed():
44+
rtl.scroll_to_line(rtl.get_line_count() -1)
45+
46+
func _on_Copy_pressed():
47+
return
48+
# OS.clipboard = rtl.text
49+
50+
func _on_file_dialog_visibility_changed():
51+
if rtl.text.length() == 0 and not $FileDialog.visible:
52+
self.hide()

addons/gut/UserFileViewer.tscn

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
[gd_scene load_steps=2 format=3 uid="uid://bsm7wtt1gie4v"]
2+
3+
[ext_resource type="Script" path="res://addons/gut/UserFileViewer.gd" id="1"]
4+
5+
[node name="UserFileViewer" type="Window"]
6+
exclusive = true
7+
script = ExtResource("1")
8+
9+
[node name="FileDialog" type="FileDialog" parent="."]
10+
access = 1
11+
show_hidden_files = true
12+
__meta__ = {
13+
"_edit_use_anchors_": false
14+
}
15+
16+
[node name="TextDisplay" type="ColorRect" parent="."]
17+
anchor_right = 1.0
18+
anchor_bottom = 1.0
19+
offset_left = 8.0
20+
offset_right = -10.0
21+
offset_bottom = -65.0
22+
color = Color(0.2, 0.188235, 0.188235, 1)
23+
24+
[node name="RichTextLabel" type="RichTextLabel" parent="TextDisplay"]
25+
anchor_right = 1.0
26+
anchor_bottom = 1.0
27+
focus_mode = 2
28+
text = "In publishing and graphic design, Lorem ipsum is a placeholder text commonly used to demonstrate the visual form of a document or a typeface without relying on meaningful content. Lorem ipsum may be used before final copy is available, but it may also be used to temporarily replace copy in a process called greeking, which allows designers to consider form without the meaning of the text influencing the design.
29+
30+
Lorem ipsum is typically a corrupted version of De finibus bonorum et malorum, a first-century BCE text by the Roman statesman and philosopher Cicero, with words altered, added, and removed to make it nonsensical, improper Latin.
31+
32+
Versions of the Lorem ipsum text have been used in typesetting at least since the 1960s, when it was popularized by advertisements for Letraset transfer sheets. Lorem ipsum was introduced to the digital world in the mid-1980s when Aldus employed it in graphic and word-processing templates for its desktop publishing program PageMaker. Other popular word processors including Pages and Microsoft Word have since adopted Lorem ipsum as well."
33+
selection_enabled = true
34+
35+
[node name="OpenFile" type="Button" parent="."]
36+
anchor_left = 1.0
37+
anchor_top = 1.0
38+
anchor_right = 1.0
39+
anchor_bottom = 1.0
40+
offset_left = -158.0
41+
offset_top = -50.0
42+
offset_right = -84.0
43+
offset_bottom = -30.0
44+
text = "Open File"
45+
46+
[node name="Home" type="Button" parent="."]
47+
anchor_left = 1.0
48+
anchor_top = 1.0
49+
anchor_right = 1.0
50+
anchor_bottom = 1.0
51+
offset_left = -478.0
52+
offset_top = -50.0
53+
offset_right = -404.0
54+
offset_bottom = -30.0
55+
text = "Home"
56+
57+
[node name="Copy" type="Button" parent="."]
58+
anchor_top = 1.0
59+
anchor_bottom = 1.0
60+
offset_left = 160.0
61+
offset_top = -50.0
62+
offset_right = 234.0
63+
offset_bottom = -30.0
64+
text = "Copy"
65+
66+
[node name="End" type="Button" parent="."]
67+
anchor_left = 1.0
68+
anchor_top = 1.0
69+
anchor_right = 1.0
70+
anchor_bottom = 1.0
71+
offset_left = -318.0
72+
offset_top = -50.0
73+
offset_right = -244.0
74+
offset_bottom = -30.0
75+
text = "End"
76+
77+
[node name="Close" type="Button" parent="."]
78+
anchor_top = 1.0
79+
anchor_bottom = 1.0
80+
offset_left = 10.0
81+
offset_top = -50.0
82+
offset_right = 80.0
83+
offset_bottom = -30.0
84+
text = "Close"
85+
86+
[connection signal="file_selected" from="FileDialog" to="." method="_on_FileDialog_file_selected"]
87+
[connection signal="visibility_changed" from="FileDialog" to="." method="_on_file_dialog_visibility_changed"]
88+
[connection signal="pressed" from="OpenFile" to="." method="_on_OpenFile_pressed"]
89+
[connection signal="pressed" from="Home" to="." method="_on_Home_pressed"]
90+
[connection signal="pressed" from="Copy" to="." method="_on_Copy_pressed"]
91+
[connection signal="pressed" from="End" to="." method="_on_End_pressed"]
92+
[connection signal="pressed" from="Close" to="." method="_on_Close_pressed"]

addons/gut/autofree.gd

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
# ##############################################################################
2+
#(G)odot (U)nit (T)est class
3+
#
4+
# ##############################################################################
5+
# The MIT License (MIT)
6+
# =====================
7+
#
8+
# Copyright (c) 2020 Tom "Butch" Wesley
9+
#
10+
# Permission is hereby granted, free of charge, to any person obtaining a copy
11+
# of this software and associated documentation files (the "Software"), to deal
12+
# in the Software without restriction, including without limitation the rights
13+
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14+
# copies of the Software, and to permit persons to whom the Software is
15+
# furnished to do so, subject to the following conditions:
16+
#
17+
# The above copyright notice and this permission notice shall be included in
18+
# all copies or substantial portions of the Software.
19+
#
20+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
23+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
26+
# THE SOFTWARE.
27+
#
28+
# ##############################################################################
29+
# Class used to keep track of objects to be freed and utilities to free them.
30+
# ##############################################################################
31+
var _to_free = []
32+
var _to_queue_free = []
33+
34+
func add_free(thing):
35+
if(typeof(thing) == TYPE_OBJECT):
36+
if(!thing is RefCounted):
37+
_to_free.append(thing)
38+
39+
func add_queue_free(thing):
40+
_to_queue_free.append(thing)
41+
42+
func get_queue_free_count():
43+
return _to_queue_free.size()
44+
45+
func get_free_count():
46+
return _to_free.size()
47+
48+
func free_all():
49+
for i in range(_to_free.size()):
50+
if(is_instance_valid(_to_free[i])):
51+
_to_free[i].free()
52+
_to_free.clear()
53+
54+
for i in range(_to_queue_free.size()):
55+
if(is_instance_valid(_to_queue_free[i])):
56+
_to_queue_free[i].queue_free()
57+
_to_queue_free.clear()
58+
59+

0 commit comments

Comments
 (0)