Asserts and Methods

These are all the methods, bells, whistles and blinky lights you get when you extend the Gut Test Class (extends GutTest).

Most sample code listed for the methods can be found here in test_readme_examples.gd

Assertions

pass_test

pass_test(text)
Useful when you don’t have anything meaningful to assert. Any failing asserts within the test will override this.

func test_nothing():
  pass_test('nothing tested, passing')

fail_test

fail_test(text)
Useful when you need to fail a test but don’t have a meaningful way to assert the condition you are testing. This will also override pass_test.

func test_this_test_just_fails():
  fail_test('a total unbridled failure')

pending

pending(text="")
Flag a test as pending, the optional message is printed in the GUI.

pending('This test is not implemented yet')
pending()

assert_eq

assert_eq(got, expected, text="")
assert got == expected and prints optional text. There are some caveats due to how Godot compares things. Arrays are compared by value (with some additional caveats) and dictionaries are compared by reference. See also assert_eq_deep and Comparing Things

func test_equals():
	var one = 1
	var node1 = Node.new()
	var node2 = node1

	assert_eq(one, 1, 'one should equal one') # PASS
	assert_eq('racecar', 'racecar') # PASS
	assert_eq(node2, node1) # PASS
	assert_eq([1, 2, 3], [1, 2, 3]) # PASS
	var d1_pass = {'a':1}
	var d2_pass = d1_pass
	assert_eq(d1_pass, d2_pass) # PASS

	gut.p('-- failing --')
	assert_eq(1, 2) # FAIL
	assert_eq('hello', 'world') # FAIL
	assert_eq(self, node1) # FAIL
	assert_eq([1, 'two', 3], [1, 2, 3, 4]) # FAIL
	assert_eq({'a':1}, {'a':1}) # FAIL

assert_ne

assert_ne(got, not_expected, text="")
asserts got != expected and prints optional text. Read Comparing Things for array and dictionary caveats.

var two = 2
var node1 = Node.new()

gut.p('-- passing --')
assert_ne(two, 1, 'Two should not equal one.')  # PASS
assert_ne('hello', 'world') # PASS
assert_ne(self, node1) # PASS

gut.p('-- failing --')
assert_ne(two, 2) # FAIL
assert_ne('one', 'one') # FAIL
assert_ne('2', 2) # FAIL

assert_same

assert_same(v1, v2, text='')
This is used to compare references to make sure they are the same. This is the only way to compare dictionaries and arrays by reference instead of by value. Asserts that a call to is_same(v1, v2) is true. See also Comparing Things.

assert_not_same

assert_not_same(v1, v2, text='')
Inverse of assert_same. See also Comparing Things.

assert_gt

assert_gt(got, expected, text="")
assserts got > expected

var bigger = 5
var smaller = 0

gut.p('-- passing --')
assert_gt(bigger, smaller, 'Bigger should be greater than smaller') # PASS
assert_gt('b', 'a') # PASS
assert_gt('a', 'A') # PASS
assert_gt(1.1, 1) # PASS

gut.p('-- failing --')
assert_gt('a', 'a') # FAIL
assert_gt(1.0, 1) # FAIL
assert_gt(smaller, bigger) # FAIL

assert_lt

assert_lt(got, expected, text="")
asserts got < expected

var bigger = 5
var smaller = 0
gut.p('-- passing --')
assert_lt(smaller, bigger, 'Smaller should be less than bigger') # PASS
assert_lt('a', 'b') # PASS

gut.p('-- failing --')
assert_lt('z', 'x') # FAIL
assert_lt(-5, -5) # FAIL

assert_true

assert_true(got, text="")
asserts got == true.

func test_true():
	gut.p('-- passing --')
	assert_true(true, 'True should be true') # PASS
	assert_true(5 == 5, 'That expressions should be true') # PASS

	gut.p('-- failing --')
	assert_true(false) # FAIL
	assert_true('a' == 'b') # FAIL
	assert_true('b') # FAIL
	assert_true(1)

assert_false

assert_false(got, text="")
asserts got == false

func test_false():
	gut.p('-- passing --')
	assert_false(false, 'False is false') # PASS
	assert_false(1 == 2) # PASS
	assert_false('a' == 'z') # PASS
	assert_false(self.has_user_signal('nope')) # PASS

	gut.p('-- failing --')
	assert_false(true) # FAIL
	assert_false('ABC' == 'ABC') # FAIL
	assert_false(null) # FAIL
	assert_false(0)

assert_null

assert_null(got)
asserts the passed in value is null

gut.p('-- passing --')
assert_null(null)

gut.p('-- failing --')
assert_null('a')
assert_null(1)

assert_not_null

assert_not_null(got)
asserts the passed in value is not null

gut.p('-- passing --')
assert_not_null('a')
assert_not_null(1)

gut.p('-- failing --')
assert_not_null(null)

assert_between

assert_between(got, expect_low, expect_high, text="")
asserts got > expect_low and <= expect_high

gut.p('-- passing --')
assert_between(5, 0, 10, 'Five should be between 0 and 10') # PASS
assert_between(10, 0, 10) # PASS
assert_between(0, 0, 10) # PASS
assert_between(2.25, 2, 4.0) # PASS

gut.p('-- failing --')
assert_between('a', 'b', 'c') # FAIL
assert_between(1, 5, 10) # FAIL

assert_not_between

assert_not_between(got, expect_low, expect_high, text="")
asserts that got <= expect_low or got >= expect_high.

gut.p('-- passing --')
assert_not_between(1, 5, 10) # PASS
assert_not_between('a', 'b', 'd') # PASS
assert_not_between('d', 'b', 'd') # PASS
assert_not_between(10, 0, 10) # PASS
assert_not_between(-2, -2, 10) # PASS

gut.p('-- failing --')
assert_not_between(5, 0, 10, 'Five shouldnt be between 0 and 10') # FAIL
assert_not_between(0.25, -2.0, 4.0) # FAIL

assert_almost_eq

assert_almost_eq(got, expected, error_interval, text='')
Asserts that got is within the range of expected +/- error_interval. The upper and lower bounds are included in the check. Verified to work with integers, floats, and Vector2. Should work with anything that can be added/subtracted.

gut.p('-- passing --')
assert_almost_eq(0, 1, 1, '0 within range of 1 +/- 1') # PASS
assert_almost_eq(2, 1, 1, '2 within range of 1 +/- 1') # PASS

assert_almost_eq(1.2, 1.0, .5, '1.2 within range of 1 +/- .5') # PASS
assert_almost_eq(.5, 1.0, .5, '.5 within range of 1 +/- .5') # PASS

assert_almost_eq(Vector2(.5, 1.5), Vector2(1.0, 1.0), Vector2(.5, .5))  # PASS

gut.p('-- failing --')
assert_almost_eq(1, 3, 1, '1 outside range of 3 +/- 1') # FAIL
assert_almost_eq(2.6, 3.0, .2, '2.6 outside range of 3 +/- .2') # FAIL

assert_almost_eq(Vector2(.5, 1.5), Vector2(1.0, 1.0), Vector2(.25, .25))  # PASS

assert_almost_ne

assert_almost_ne(got, expected, error_interval, text='')
This is the inverse of assert_almost_eq. This will pass if got is outside the range of expected +/- error_interval.

gut.p('-- passing --')
assert_almost_ne(1, 3, 1, '1 outside range of 3 +/- 1') # PASS
assert_almost_ne(2.6, 3.0, .2, '2.6 outside range of 3 +/- .2') # PASS

assert_almost_ne(Vector2(.5, 1.5), Vector2(1.0, 1.0), Vector2(.25, .25))  # PASS

gut.p('-- failing --')
assert_almost_ne(0, 1, 1, '0 within range of 1 +/- 1') # FAIL
assert_almost_ne(2, 1, 1, '2 within range of 1 +/- 1') # FAIL

assert_almost_ne(1.2, 1.0, .5, '1.2 within range of 1 +/- .5') # FAIL
assert_almost_ne(.5, 1.0, .5, '.5 within range of 1 +/- .5') # FAIL

assert_almost_ne(Vector2(.5, 1.5), Vector2(1.0, 1.0), Vector2(.5, .5))  # FAIL

assert_has

assert_has(obj, element, text='')
Asserts that the object passed in “has” the element. This works with any object that has a has method.

var an_array = [1, 2, 3, 'four', 'five']
var a_hash = { 'one':1, 'two':2, '3':'three'}

gut.p('-- passing --')
assert_has(an_array, 'four') # PASS
assert_has(an_array, 2) # PASS
# the hash's has method checks indexes not values
assert_has(a_hash, 'one') # PASS
assert_has(a_hash, '3') # PASS

gut.p('-- failing --')
assert_has(an_array, 5) # FAIL
assert_has(an_array, self) # FAIL
assert_has(a_hash, 3) # FAIL
assert_has(a_hash, 'three') # FAIL

assert_does_not_have

assert_does_not_have(obj, element, text='')
The inverse of assert_has

var an_array = [1, 2, 3, 'four', 'five']
var a_hash = { 'one':1, 'two':2, '3':'three'}

gut.p('-- passing --')
assert_does_not_have(an_array, 5) # PASS
assert_does_not_have(an_array, self) # PASS
assert_does_not_have(a_hash, 3) # PASS
assert_does_not_have(a_hash, 'three') # PASS

gut.p('-- failing --')
assert_does_not_have(an_array, 'four') # FAIL
assert_does_not_have(an_array, 2) # FAIL
# the hash's has method checks indexes not values
assert_does_not_have(a_hash, 'one') # FAIL
assert_does_not_have(a_hash, '3') # FAIL

assert_string_contains

assert_string_contains(text, search, match_case=true)
Assert that text contains search. Can perform case insensitive search by passing false for match_case.

func test_string_contains():
	gut.p('-- passing --')
	assert_string_contains('abc 123', 'a')
	assert_string_contains('abc 123', 'BC', false)
	assert_string_contains('abc 123', '3')

	gut.p('-- failing --')
	assert_string_contains('abc 123', 'A')
	assert_string_contains('abc 123', 'BC')
	assert_string_contains('abc 123', '012')

assert_string_starts_with

assert_string_starts_with(text, search, match_case=true)
Assert that text starts with search. Can perform case insensitive check by passing false for match_case

func test_string_starts_with():
	gut.p('-- passing --')
	assert_string_starts_with('abc 123', 'a')
	assert_string_starts_with('abc 123', 'ABC', false)
	assert_string_starts_with('abc 123', 'abc 123')

	gut.p('-- failing --')
	assert_string_starts_with('abc 123', 'z')
	assert_string_starts_with('abc 123', 'ABC')
	assert_string_starts_with('abc 123', 'abc 1234')

assert_string_ends_with

assert_string_ends_with(text, search, match_case=true)
Assert that text ends with search. Can perform case insensitive check by passing false for match_case

func test_string_ends_with():
	gut.p('-- passing --')
	assert_string_ends_with('abc 123', '123')
	assert_string_ends_with('abc 123', 'C 123', false)
	assert_string_ends_with('abc 123', 'abc 123')

	gut.p('-- failing --')
	assert_string_ends_with('abc 123', '1234')
	assert_string_ends_with('abc 123', 'C 123')
	assert_string_ends_with('abc 123', 'nope')

assert_has_signal

assert_has_signal(object, signal_name)
Asserts the passed in object has a signal with the specified name. It should be noted that all the asserts that verify a signal was/wasn’t emitted will first check that the object has the signal being asserted against. If it does not, a specific failure message will be given. This means you can usually skip the step of specifically verifying that the object has a signal and move on to making sure it emits the signal correctly.

class SignalObject:
	func _init():
		add_user_signal('some_signal')
		add_user_signal('other_signal')

func test_assert_has_signal():
	var obj = SignalObject.new()

	gut.p('-- passing --')
	assert_has_signal(obj, 'some_signal')
	assert_has_signal(obj, 'other_signal')

	gut.p('-- failing --')
	assert_has_signal(obj, 'not_a real SIGNAL')
	assert_has_signal(obj, 'yea, this one doesnt exist either')
	# Fails because the signal is not a user signal.  Node2D does have the
	# specified signal but it can't be checked this way.  It could be watched
	# and asserted that it fired though.
	assert_has_signal(Node2D.new(), 'exit_tree')

assert_connected

assert_connected(signaler_obj, connect_to_obj, signal_name, method_name="")
Asserts that signaler_obj is connected to connect_to_obj on signal signal_name. The method that is connected is optional. If method_name is supplied then this will pass only if the signal is connected to the method. If it is not provided then any connection to the signal will cause a pass.

class Signaler:
	signal the_signal

class Connector:
	func connect_this():
		pass
	func  other_method():
		pass

func test_assert_connected():
	var signaler = Signaler.new()
	var connector  = Connector.new()
	signaler.connect('the_signal', connector, 'connect_this')

	# Passing
	assert_connected(signaler, connector, 'the_signal')
	assert_connected(signaler, connector, 'the_signal', 'connect_this')

	# Failing
	var foo = Connector.new()
	assert_connected(signaler,  connector, 'the_signal', 'other_method')
	assert_connected(signaler, connector, 'other_signal')
	assert_connected(signaler, foo, 'the_signal')

assert_not_connected

assert_not_connected(signaler_obj, connect_to_obj, signal_name, method_name="")
The inverse of assert_connected.

watch_signals(object)

``
This must be called in order to make assertions based on signals being emitted. Right now, this only supports signals that are emitted with 9 or less parameters. This can be extended but nine seemed like enough for now. The Godot documentation suggests that the limit is four but in my testing I found you can pass more.

This must be called in each test in which you want to make signal based assertions in. You can call it multiple times with different objects. You should not call it multiple times with the same object in the same test. The objects that are watched are cleared after each test (specifically right before teardown is called). Under the covers, Gut will connect to all the signals an object has and it will track each time they fire. You can then use the following asserts and methods to verify things are acting correct.

assert_signal_emitted

assert_signal_emitted(object, signal_name)
Assert that the specified object emitted the named signal. You must call watch_signals and pass it the object that you are making assertions about. This will fail if the object is not being watched or if the object does not have the specified signal. Since this will fail if the signal does not exist, you can often skip using assert_has_signal.

class SignalObject:
	func _init():
		add_user_signal('some_signal')
		add_user_signal('other_signal')

func test_assert_signal_emitted():
	var obj = SignalObject.new()

	watch_signals(obj)
	obj.emit_signal('some_signal')

	gut.p('-- passing --')
	assert_signal_emitted(obj, 'some_signal')

	gut.p('-- failing --')
	# Fails with specific message that the object does not have the signal
	assert_signal_emitted(obj, 'signal_does_not_exist')
	# Fails because the object passed is not being watched
	assert_signal_emitted(SignalObject.new(), 'some_signal')
	# Fails because the signal was not emitted
	assert_signal_emitted(obj, 'other_signal')

assert_signal_not_emitted

assert_signal_not_emitted(object, signal_name)
This works opposite of assert_signal_emitted. This will fail if the object is not being watched or if the object does not have the signal.

class SignalObject:
	func _init():
		add_user_signal('some_signal')
		add_user_signal('other_signal')

func test_assert_signal_not_emitted():
	var obj = SignalObject.new()

	watch_signals(obj)
	obj.emit_signal('some_signal')

	gut.p('-- passing --')
	assert_signal_not_emitted(obj, 'other_signal')

	gut.p('-- failing --')
	# Fails with specific message that the object does not have the signal
	assert_signal_not_emitted(obj, 'signal_does_not_exist')
	# Fails because the object passed is not being watched
	assert_signal_not_emitted(SignalObject.new(), 'some_signal')
	# Fails because the signal was emitted
	assert_signal_not_emitted(obj, 'some_signal')

assert_signal_emitted_with_parameters

assert_signal_emitted_with_parameters(object, signal_name, parameters, index=-1)
Asserts that a signal was fired with the specified parameters. The expected parameters should be passed in as an array. An optional index can be passed when a signal has fired more than once. The default is to retrieve the most recent emission of the signal.

This will fail with specific messages if the object is not being watched or the object does not have the specified signal

class SignalObject:
	func _init():
		add_user_signal('some_signal')
		add_user_signal('other_signal')

func test_assert_signal_emitted_with_parameters():
	var obj = SignalObject.new()

	watch_signals(obj)
	# emit the signal 3 times to illustrate how the index works in
	# assert_signal_emitted_with_parameters
	obj.emit_signal('some_signal', 1, 2, 3)
	obj.emit_signal('some_signal', 'a', 'b', 'c')
	obj.emit_signal('some_signal', 'one', 'two', 'three')

	gut.p('-- passing --')
	# Passes b/c the default parameters to check are the last emission of
	# the signal
	assert_signal_emitted_with_parameters(obj, 'some_signal', ['one', 'two', 'three'])
	# Passes because the parameters match the specified emission based on index.
	assert_signal_emitted_with_parameters(obj, 'some_signal', [1, 2, 3], 0)

	gut.p('-- failing --')
	# Fails with specific message that the object does not have the signal
	assert_signal_emitted_with_parameters(obj, 'signal_does_not_exist', [])
	# Fails because the object passed is not being watched
	assert_signal_emitted_with_parameters(SignalObject.new(), 'some_signal', [])
	# Fails because parameters do not match latest emission
	assert_signal_emitted_with_parameters(obj, 'some_signal', [1, 2, 3])
	# Fails because the parameters for the specified index do not match
	assert_signal_emitted_with_parameters(obj, 'some_signal', [1, 2, 3], 1)

assert_signal_emit_count

assert_signal_emit_count(object, signal_name)
Asserts that a signal fired a specific number of times.

class SignalObject:
	func _init():
		add_user_signal('some_signal')
		add_user_signal('other_signal')

func test_assert_signal_emit_count():
	var obj_a = SignalObject.new()
	var obj_b = SignalObject.new()

	watch_signals(obj_a)
	watch_signals(obj_b)
	obj_a.emit_signal('some_signal')
	obj_a.emit_signal('some_signal')

	obj_b.emit_signal('some_signal')
	obj_b.emit_signal('other_signal')

	gut.p('-- passing --')
	assert_signal_emit_count(obj_a, 'some_signal', 2)
	assert_signal_emit_count(obj_a, 'other_signal', 0)

	assert_signal_emit_count(obj_b, 'other_signal', 1)

	gut.p('-- failing --')
	# Fails with specific message that the object does not have the signal
	assert_signal_emit_count(obj_a, 'signal_does_not_exist', 99)
	# Fails because the object passed is not being watched
	assert_signal_emit_count(SignalObject.new(), 'some_signal', 99)
	# The following fail for obvious reasons
	assert_signal_emit_count(obj_a, 'some_signal', 0)
	assert_signal_emit_count(obj_b, 'other_signal', 283)

assert_file_exists

assert_file_exists(file_path)
asserts a file exists at the specified path

func before_each():
	gut.file_touch('user://some_test_file')

func after_each():
	gut.file_delete('user://some_test_file')

func test_assert_file_exists():
	gut.p('-- passing --')
	assert_file_exists('res://addons/gut/gut.gd') # PASS
	assert_file_exists('user://some_test_file') # PASS

	gut.p('-- failing --')
	assert_file_exists('user://file_does_not.exist') # FAIL
	assert_file_exists('res://some_dir/another_dir/file_does_not.exist') # FAIL

assert_file_does_not_exist

assert_file_does_not_exist(file_path)
asserts a file does not exist at the specified path

func before_each():
	gut.file_touch('user://some_test_file')

func after_each():
	gut.file_delete('user://some_test_file')

func test_assert_file_does_not_exist():
	gut.p('-- passing --')
	assert_file_does_not_exist('user://file_does_not.exist') # PASS
	assert_file_does_not_exist('res://some_dir/another_dir/file_does_not.exist') # PASS

	gut.p('-- failing --')
	assert_file_does_not_exist('res://addons/gut/gut.gd') # FAIL

assert_file_empty

assert_file_empty(file_path)
asserts the specified file is empty

func before_each():
	gut.file_touch('user://some_test_file')

func after_each():
	gut.file_delete('user://some_test_file')

func test_assert_file_empty():
	gut.p('-- passing --')
	assert_file_empty('user://some_test_file') # PASS

	gut.p('-- failing --')
	assert_file_empty('res://addons/gut/gut.gd') # FAIL

assert_file_not_empty

assert_file_not_empty(file_path)
asserts the specified file is not empty

func before_each():
	gut.file_touch('user://some_test_file')

func after_each():
	gut.file_delete('user://some_test_file')

func test_assert_file_not_empty():
	gut.p('-- passing --')
	assert_file_not_empty('res://addons/gut/gut.gd') # PASS

	gut.p('-- failing --')
	assert_file_not_empty('user://some_test_file') # FAIL

assert_is

assert_is(object, a_class, text)
Asserts that “object” extends “a_class”. object must be an instance of an object. It cannot be any of the built in classes like Array or Int or Float. a_class must be a class, it can be loaded via load, a GDNative class such as Node or Label or anything else.

func test_assert_is():
	gut.p('-- passing --')
	assert_is(Node2D.new(), Node2D)
	assert_is(Label.new(), CanvasItem)
	assert_is(SubClass.new(), BaseClass)
	# Since this is a test script that inherits from test.gd, so
	# this passes.  It's not obvious w/o seeing the whole script
	# so I'm telling you.  You'll just have to trust me.
	assert_is(self, load('res://addons/gut/test.gd'))

	var Gut = load('res://addons/gut/gut.gd')
	var a_gut = Gut.new()
	assert_is(a_gut, Gut)

	gut.p('-- failing --')
	assert_is(Node2D.new(), Node2D.new())
	assert_is(BaseClass.new(), SubClass)
	assert_is('a', 'b')
	assert_is([], Node)

assert_typeof

assert_typeof(object, type, text='')
Asserts that object is the the type specified. type should be one of the Godot TYPE_ constants.

func test_assert_typeof():
	gut.p('-- passing --')
	var c = Color(1, 1, 1, 1)
	gr.test.assert_typeof(c, TYPE_COLOR)
	assert_pass(gr.test)

	gut.p('-- failing --')
	gr.test.assert_typeof('some string', TYPE_INT)
	assert_fail(gr.test)

assert_not_typeof

assert_not_typeof(object, type, text='')
The inverse of assert_typeof

assert_freed

assert_freed(obj, text)
Asserts that the passed in object has been freed. This assertion requires that you pass in some text in the form of a title since, if the object is freed, we won’t have anything to convert to a string to put in the output statement.

Note that this currently does not detect if a node has been queued free.

func test_object_is_freed_should_pass():
	var obj = Node.new()
	obj.free()
	test.assert_freed(obj, "New Node")

assert_not_freed

assert_not_freed(obj, text)
The inverse of assert_freed

func test_object_is_not_freed_should_pass():
	var obj = Node.new()
	assert_not_freed(obj, "New Node")

func test_queued_free_is_not_freed():
	var obj = Node.new()
	add_child(obj)
	obj.queue_free()
	assert_not_freed(obj, "New Node")

assert_exports

assert_exports(obj, property_name, type)
Asserts that obj exports a property with the name property_name and a type of type. The type must be one of the various Godot built-in TYPE_ constants.

class ExportClass:
	export var some_number = 5
	export(PackedScene) var some_scene
	var some_variable = 1

func test_assert_exports():
	var obj = ExportClass.new()

	gut.p('-- passing --')
	assert_exports(obj, "some_number", TYPE_INT)
	assert_exports(obj, "some_scene", TYPE_OBJECT)

	gut.p('-- failing --')
	assert_exports(obj, 'some_number', TYPE_VECTOR2)
	assert_exports(obj, 'some_scene', TYPE_AABB)
	assert_exports(obj, 'some_variable', TYPE_INT)

assert_called

assert_called(inst, method_name, parameters=null)
This assertion is is one of the ways Gut implements Spies. It requires that you pass it an instance of a “doubled” object. An instance created with double will record when a method it has is called. You can then make assertions based on this.

This assert will check the object to see if a call to the specified method (optionally with parameters) was called over the course of the test. If it finds a match this test will pass, if not it will fail.

The parameters parameter is an array of values that you expect to have been passed to method_name. If you do not specify any parameters then any call to method_name will match and the assert will pass. If you specify parameters then all the parameter values must match. You must specify all parameters the method takes, even if they have defaults. Gut is not able (yet?) to fill in default values.

Methods that are inherited from built-in parent classes are not yet recorded. For example, you cannot make “called” assertions on methods like set_position unless your sub-class specifically implements it. But since those methods retain their built-in functionality, you can just make normal assertions on them.

# Given the following class located at 'res://test/doubler_test_objects/double_extends_node2d.gd'
# --------------------
	extends Node2D
	var _value = 0

	func get_value():
	    return _value
	func set_value(val):
	    _value = val
	func has_one_param(one):
	    pass
	func has_two_params_one_default(one, two=null):
	    pass
	func get_position():
	    return .get_position()
# --------------------

# This is how assert_called behaves
func test_assert_called():
	var DOUBLE_ME_PATH = 'res://test/doubler_test_objects/double_extends_node2d.gd'

	var doubled = double(DOUBLE_ME_PATH).new()
	doubled.set_value(4)
	doubled.set_value(5)
	doubled.has_two_params_one_default('a')
	doubled.has_two_params_one_default('a', 'b')

	gut.p('-- passing --')
	assert_called(doubled, 'set_value')
	assert_called(doubled, 'set_value', [5])
	# note the passing of `null` here.  Default parameters must be supplied.
	assert_called(doubled, 'has_two_params_one_default', ['a', null])
	assert_called(doubled, 'has_two_params_one_default', ['a', 'b'])

	gut.p('-- failing --')
	assert_called(doubled, 'get_value')
	assert_called(doubled, 'set_value', ['nope'])
	# This fails b/c Gut isn't smart enough to fill in default values for you...
	# ast least not yet.
	assert_called(doubled, 'has_two_params_one_default', ['a'])
	# This fails with a specific message indicating that you have to pass an
	# instance of a doubled class.
	assert_called(GDScript.new(), 'some_method')

assert_not_called

assert_not_called(inst, method_name, parameters=null)
This is the inverse of assert_called and works the same way except, you know, inversely. Matches are found based on parameters in the same fashion. If a matching call is found then this assert will fail, if not it will pass.

assert_call_count

assert_call_count(inst, method_name, expected_count, parameters=null)
This assertion is is one of the ways Gut implements Spies. It requires that you pass it an instance of a “doubled” object. An instance created with double will record when a method it has is called. You can then make assertions based on this.

This asserts that a method on a doubled instance has been called a number of times. If you do not specify any parameters then all calls to the method will be counted. If you specify parameters, then only those calls that were passed matching values will be counted.

The parameters parameter is an array of values that you expect to have been passed to method_name. If you do not specify any parameters then any call to method_name will match and the assert will pass. If you specify parameters then all the parameter values must match. You must specify all parameters the method takes, even if they have defaults. Gut is not able (yet?) to fill in default values.

Methods that are inherited from built-in parent classes are not yet recorded. For example, you cannot make “call” assertions on methods like set_position unless your sub-class specifically implements it (you can, they will just always return 0). Since those methods retain their built-in functionality, you can just make normal assertions on them.

# Given the following class located at 'res://test/doubler_test_objects/double_extends_node2d.gd'
# --------------------
	extends Node2D
	var _value = 0

	func get_value():
	    return _value
	func set_value(val):
	    _value = val
	func has_one_param(one):
	    pass
	func has_two_params_one_default(one, two=null):
	    pass
	func get_position():
	    return .get_position()
# --------------------

# This is how assert_call_count behaves
func test_assert_call_count():
	var DOUBLE_ME_PATH = 'res://test/doubler_test_objects/double_extends_node2d.gd'

	var doubled = double(DOUBLE_ME_PATH).new()
	doubled.set_value(4)
	doubled.set_value(5)
	doubled.has_two_params_one_default('a')
	doubled.has_two_params_one_default('a', 'b')
	doubled.set_position(Vector2(100, 100))

	gut.p('-- passing --')
	assert_call_count(doubled, 'set_value', 2)
	assert_call_count(doubled, 'set_value', 1, [4])
	# note the passing of `null` here.  Default parameters must be supplied.
	assert_call_count(doubled, 'has_two_params_one_default', 1, ['a', null])
	assert_call_count(doubled, 'get_value', 0)

	gut.p('-- failing --')
	assert_call_count(doubled, 'set_value', 5)
	assert_call_count(doubled, 'set_value', 2, [4])
	assert_call_count(doubled, 'get_value', 1)
	# This fails with a specific message indicating that you have to pass an
	# instance of a doubled class even though technically the method was called.
	assert_call_count(GDScript.new(), 'some_method', 0)
	# This fails b/c double_extends_node2d does not have it's own implementation
	# of set_position.  The function is supplied by the parent class and these
	# methods are not yet being recorded.
	assert_call_count(doubled, 'set_position', 1)

assert_has_method

assert_has_method(obj, method)
Asserts that the passed in object has a method named method.

class SomeClass:
	var _count = 0

	func get_count():
		return _count
	func set_count(number):
		_count = number

	func get_nothing():
		pass
	func set_nothing(val):
		pass

func test_assert_has_method():
	var some_class = SomeClass.new()
	gut.p('-- passing --')
	assert_has_method(some_class, 'get_nothing')
	assert_has_method(some_class, 'set_count')

	gut.p('-- failing --')
	assert_has_method(some_class, 'method_does_not_exist')

assert_accessors

assert_accessors(obj, property, default, set_to)
I found that making tests for most getters and setters was repetitious and annoying. Enter assert_accessors. This assertion handles 80% of your getter and setter testing needs. Given an object and a property name it will verify:

  • The object has a method called get_<PROPERTY_NAME>

  • The object has a method called set_<PROPERTY_NAME>

  • The method get_<PROPERTY_NAME> returns the expected default value when first called.

  • Once you set the property, the get_<PROPERTY_NAME>will return the value passed in.

On the inside Gut actually performs up to 4 assertions. So if everything goes right you will have four passing asserts each time you call assert_accessors. I say “up to 4 assertions” because there are 2 assertions to make sure the object has the methods and then 2 to verify they act correctly. If the object does not have the methods, it does not bother running the tests for the methods.

class SomeClass:
	var _count = 0

	func get_count():
		return _count
	func set_count(number):
		_count = number

	func get_nothing():
		pass
	func set_nothing(val):
		pass

func test_assert_accessors():
  var some_class = SomeClass.new()
  gut.p('-- passing --')
  assert_accessors(some_class, 'count', 0, 20) # 4 PASSING

  gut.p('-- failing --')
  # 1 FAILING, 3 PASSING
  assert_accessors(some_class, 'count', 'not_default', 20)
  # 2 FAILING, 2 PASSING
  assert_accessors(some_class, 'nothing', 'hello', 22)
  # 2 FAILING
  assert_accessors(some_class, 'does_not_exist', 'does_not', 'matter')

assert_no_new_orphans

assert_no_new_orphans(text='')
This method will assert that no orphaned nodes have been introduced by the test when the assert is executed. See the Memory Management page for more information.

assert_eq_deep

assert_eq_deep(v1, v2)
Performs a deep comparison between two arrays or dictionaries and asserts they are equal. If they are not equal then a formatted list of differences are displayed. See Comparing Things for more information.

func test_assert_eq_deep():
	var complex_example = [
		'a', 'b', 'c',
		[1, 2, 3, 4],
		{'a':1, 'b':2, 'c':3},
		[{'a':1}, {'b':2}]
	]

	# Passing
	assert_eq_deep([1, 2, {'a':1}], [1, 2, {'a':1}])
	assert_eq_deep({'a':1, 'b':{'c':1}}, {'b':{'c':1}, 'a':1})

	var shallow_copy  = complex_example.duplicate(false)
	var deep_copy = complex_example.duplicate(true)
	assert_eq_deep(complex_example, shallow_copy)
	assert_eq_deep(complex_example, deep_copy)
	assert_eq_deep(shallow_copy, deep_copy)

	# Failing
	assert_eq_shallow([1, 2], [1, 2 ,3]) # missing index
	assert_eq_shallow({'a':1}, {'a':1, 'b':2}) # missing key
	assert_eq_deep([1, 2, {'a':1}], [1, 2, {'a':1.0}]) # floats != ints

assert_ne_deep

assert_ne_deep(v1, v2)
Performs a deep comparison of two arrays or dictionaries and asserts they are not equal. See Comparing Things for more information.

assert_eq_shallow

assert_eq_shallow(v1, v2)
Performs a shallow comparison between two arrays or dictionaries and asserts they are equal. If they are not equal then a formatted list of differences are displayed. See Comparing Things for more information.

func test_assert_eq_shallow():
	var complex_example = [
		'a', 'b', 'c',
		[1, 2, 3, 4],
		{'a':1, 'b':2, 'c':3},
		[{'a':1}, {'b':2}]
	]

	# Passing
	assert_eq_shallow([1, 2, 3], [1, 2, 3])
	assert_eq_shallow([1, [2, 3], 4], [1, [2, 3], 4])
	var d1 = {'foo':'bar'}
	assert_eq_shallow([1, 2, d1], [1, 2, d1])
	assert_eq_shallow({'a':1}, {'a':1})
	assert_eq_shallow({'a':[1, 2, 3, d1]}, {'a':[1, 2, 3, d1]})

	var shallow_copy = complex_example.duplicate(false)
	assert_eq_shallow(complex_example, shallow_copy)

	# Failing
	assert_eq_shallow([1, 2], [1, 2 ,3]) # missing index
	assert_eq_shallow({'a':1}, {'a':1, 'b':2}) # missing key
	assert_eq_shallow([1, 2], [1.0, 2.0]) # floats != ints
	assert_eq_shallow([1, 2, {'a':1}], [1, 2, {'a':1}]) # compare [2] by ref
	assert_eq_shallow({'a':1}, {'a':1.0}) # floats != ints
	assert_eq_shallow({'a':1, 'b':{'c':1}}, {'a':1, 'b':{'c':1}}) # compare 'b' by ref

	var deep_copy = complex_example.duplicate(true)
	assert_eq_shallow(complex_example, deep_copy)

assert_ne_shallow

assert_ne_shallow(v1, v2)
Performs a shallow comparison of two arrays or dictionaries and asserts they are not equal. See Comparing Things for more information.

assert_property

assert_property(obj, name_property, default_value, set_to_value)
This method does a couple of common tests for properties. It checks if:

  • the named setter and getter functions exist

  • the given default value is set_to_value

  • the value is set correctly to the given set_to_value

  • the named setter and getter functions are called when the property is accessed directly

It fails if at least one of the mentioned sub-checks fails.

The parameter obj can be any Object. Depending on what you put in the function will try retrieve the underlying class or to instantiate from obj. It is tested for classes extending Script or PackedScene in case you want to put in a class / scene. It is tested for objects extending the Node class. The method may fail if you try to put in something else.

Under the cover it runs assert_accessors and assert_setget_called. Look into assert_accessors or assert_setget_called to get further information on how they work.

In the following script you can see some examples how to use this assert function. The class under test is a “Health” component. It has a max_hap field with no setter or getter assigned. It also has a current_hp property with assigned setter and getter functions.

gut.p('-- class under test --')
class Health:
  extends Node


  export(int) var max_hp = 0
  export(int) var current_hp = 0 setget set_current_hp, get_current_hp


  func set_max_hp(value: int) -> void:
  	if value < 0:
  		value = 0
  	max_hp = value


  func get_max_hp() -> int:
  	return max_hp


  func set_current_hp(value: int) -> void:
  	current_hp = clamp(value, 0, max_hp)


  func get_current_hp() -> int:
  	return current_hp


gut.p('-- passing --')
assert_property(Health, 'current_hp', 0, 0) # PASS
var health = Health.new()
health.max_hp = 10
assert_property(health, 'current_hp', 0, 5) # PASS

gut.p('-- failing --')
assert_property(Health, 'max_hp', 0, 5) # FAIL => no setget keyword
assert_property(Health, 'current_hp', 0, 5) # FAIL => method will clamp current_hp to max_hp which is 0 by default
var directory = Directory.new()
assert_property(directory, 'current_dir', '', 'new_dir') # FAIL => directory is not a Resource nor a Node

assert_setget_called

assert_setget_called(type, name_property, name_setter="", name_getter="")
This method checks if the named setter and getter functions are called when the given property is accessed.

In GDScript this is realized by using the setget keyword. The keyword requires you to specify a setter or getter function, you can also specify both:

class SomeClass:
  var property_both = null setget set_property_both, get_property_both
  var property_setter = null setget set_property_setter
  var property_getter = null setget , get_property_getter
  var normal_class_attribute = null
  var another_property = null setget some_completely_different_name, another_different_name

With this assert you can test for scenarios equivalent to property_both, property_setter and property_getter. As shown in the example GDScript allows any names for the setter and getter functions. With this assert you can test for this scenario as well. With this assert you cannot test for normal class attributes.

The parameter type has to be a Resource. Therefore you can put in a Script or a PackedScene but no instances of your class / scene under test.

The parameters name_setter and name_getter are optional.

In the following script you can see some examples how to use this assert function. The class under test is a “Health” component. It has a max_hap field with no setter or getter assigned. It also has a current_hp property with assigned setter and getter functions. For slightly more convenient ways to test properties with setget keyword also look into assert_setget or assert_property. They wrap around this assert function and set some common defaults to safe you some time.

gut.p('-- class under test --')
class Health:
  extends Node


  export(int) var max_hp = 0
  export(int) var current_hp = 0 setget set_current_hp, get_current_hp


  func set_max_hp(value: int) -> void:
  	if value < 0:
  		value = 0
  	max_hp = value


  func get_max_hp() -> int:
  	return max_hp


  func set_current_hp(value: int) -> void:
  	current_hp = clamp(value, 0, max_hp)


  func get_current_hp() -> int:
  	return current_hp


gut.p('-- passing --')
assert_setget_called(Health, 'current_hp', 'set_current_hp', 'get_current_hp') # PASS
assert_setget_called(Health, 'current_hp', 'set_current_hp') # PASS
assert_setget_called(Health, 'current_hp', '', 'get_current_hp') # PASS


gut.p('-- failing --')
assert_setget_called(Health, 'max_hp', 'set_max_hp') # FAIL
assert_setget_called(Health, 'max_hp') # FAIL => out of scope
assert_setget_called(Health, 'current_hp') # FAIL => setter or getter name must be specified
assert_setget_called(Health, 'current_hp', 'set_current_hp', 'get_current_hp') # FAIL => typo...
var health = Health.new()
assert_setget_called(health, 'current_hp', 'set_current_hp') # FAIL => type has to be a Resource
assert_setget_called(Health, max_hp, null, null) # FAIL => methods do not exist
assert_setget_called(Health, max_hp, 1, 1)  # FAIL => methods do not exist
assert_setget_called(5, 'current_hp', 'set_current_hp')  # FAIL => type has to be a Resource
assert_setget_called(double(Health), 'current_hp', 'set_current_hp') # FAIL => type has to be a Resource that can be doubled

Please note the last example. So far an already doubled type cannot be doubled again. Since the class under test will be doubled within the assert procession it is important to only feed in types that can be doubled. For more information about doubling its restrictions see the wiki page about Doubles.

assert_property

assert_property(obj, name_property, has_setter=false, has_getter=false)
This method checks if the named setter and getter functions are called when the given property is accessed.

In GDScript this is realized by using the setget keyword. The keyword requires you to specify a setter or getter function, you can also specify both:

class SomeClass:
  var property_both = null setget set_property_both, get_property_both
  var property_setter = null setget set_property_setter
  var property_getter = null setget , get_property_getter

The parameter obj can be any Object. Depending on what you put in the function will try retrieve the underlying class or to instantiate from obj. It is tested for classes extending Script or PackedScene in case you want to put in a class / scene. It is tested for objects extending the Node class. The method may fail if you try to put in something else.

The parameters name_setter and name_getter are optional.

Under the cover it runs assert_setget_called. Look into assert_setget_called to get further information on how it works.

In the following script you can see some examples how to use this assert function. The class under test is a “Health bar” component. It has a health field with a setter but no getter assigned.

gut.p('-- class under test --')
class HealthBar:
  extends Control

const Health = preload("res://some_path/health.gd")
var health: Health = null setget set_health

onready var progress_bar = $ProgressBar
onready var label = $Label


func set_health(node: Health) -> void:
	health = node


func _on_Health_updated() -> void:
	if health != null:
		label.text = "%s / %s" %[health.current_hp, health.max_hp]
		progress_bar.max_value = health.max_hp
		progress_bar.value = health.current_hp


gut.p('-- passing --')
assert_setget(HealthBar, 'health', true) # PASS
var health_bar = load("res://some_path/HealthBar.tscn").instance()
assert_setget(health_bar, 'health', true) # PASS

gut.p('-- failing --')
assert_setget(HealthBar, 'label') # FAIL => setter or getter has to be specified
assert_setget(HealthBar, 'label', true) # FAIL => setter does not exist

Utilities

is_passing

is_passing()
Returns true if the test is passing as of the time of calling it. This will return false if there haven’t been any asserts or if any of the asserts are failing. Usable in after_each but not after_all.

is_failing

is_failing()
Returns true if any failing asserts have occurred as of the time of calling it. Usable in after_each but not after_all.

add_child_autofree

add_child_autofree(object)
Calls add_child and autofree with the passed in object and returns it. See Memory Management page for more details.

add_child_autoqfree

add_child_autoqfree(object)
Calls add_child and autoqfree with the passed in object and returns it. See Memory Management page for more details.

autofree

autofree(object)
Marks an object so that free will be called on it after the test finishes. Returns the object passed in. See Memory Management page for more details.

autoqfree

autoqfree(object)
Marks an object so that queue_free will be called on it after the test finishes. Returns the object passed in. See Memory Management page for more details.

get_signal_emit_count

get_signal_emit_count(object, signal_name)
This will return the number of times a signal was fired. This gives you the freedom to make more complicated assertions if the spirit moves you. This will return -1 if the signal was not fired or the object was not being watched, or if the object does not have the signal.

get_signal_parameters

get_signal_parameters(object, signal_name, index=-1)
If you need to inspect the parameters in order to make more complicate assertions, then this will give you access to the parameters of any watched signal. This works the same way that assert_signal_emitted_with_parameters does. It takes an object, signal name, and an optional index. If the index is not specified then the parameters from the most recent emission will be returned. If the object is not being watched, the signal was not fired, or the object does not have the signal then null will be returned.

class SignalObject:
	func _init():
		add_user_signal('some_signal')
		add_user_signal('other_signal')

func test_get_signal_parameters():
	var obj = SignalObject.new()
	watch_signals(obj)
	obj.emit_signal('some_signal', 1, 2, 3)
	obj.emit_signal('some_signal', 'a', 'b', 'c')

	gut.p('-- passing --')
	# passes because get_signal_parameters returns the most recent emission
	# by default
	assert_eq(get_signal_parameters(obj, 'some_signal'), ['a', 'b', 'c'])
	assert_eq(get_signal_parameters(obj, 'some_signal', 0), [1, 2, 3])
	# if the signal was not fired null is returned
	assert_eq(get_signal_parameters(obj, 'other_signal'), null)
	# if the signal does not exist or isn't being watched null is returned
	assert_eq(get_signal_parameters(obj, 'signal_dne'), null)

	gut.p('-- failing --')
	assert_eq(get_signal_parameters(obj, 'some_signal'), [1, 2, 3])
	assert_eq(get_signal_parameters(obj, 'some_signal', 0), ['a', 'b', 'c'])

get_call_parameters

get_call_parameters(obj, method_name, index=-1)
This method allows you to get the parameters that were sent to a call to a doubled object’s method. You must pass it an object created with/from double. It will return and array containing the parameters from the most recent call by default. You can optionally specify an index to get where the first call to the method is at position 0. If no calls were made to the method or you pass in a object this is not a double then null is returned.

func test_get_call_parameters():
	var DOUBLE_ME_PATH = 'res://test/resources/doubler_test_objects/double_extends_node2d.gd'

	var doubled = double(DOUBLE_ME_PATH).new()
	doubled.set_value(5)
	doubled.has_two_params_one_default('a')
	doubled.has_two_params_one_default('x', 'y')

	# prints [5]
	print(get_call_parameters(doubled, 'set_value'))
	# prints [x, y]
	print(get_call_parameters(doubled, 'has_two_params_one_default'))
	# prints [a, Null]
	print(get_call_parameters(doubled, 'has_two_params_one_default', 0))

get_call_count

get_call_count(obj, method_name, parameters=null)
Get the number of times a method was called on a double. Include the optional parameters array to only get the count for calls with matching parameters. This is essentially assert_call_count without the assert, in case you need to do something else with the count.

	func test_called_10_times():
		var doubled = partial_double(DOUBLE_ME_PATH).new()
		for i in range(10):
			doubled.set_value(5)
		var count = get_call_count(doubled, 'set_value') # 10

	func test_it_works_with_parameters():
		var doubled = double(DOUBLE_ME_PATH).new()
		for i in range(3):
			doubled.set_value(3)

		for i in range(5):
			doubled.set_value(5)
		var count = get_call_count(doubled, 'set_value', [3]) # 3

pause_before_teardown

pause_before_teardown()
This method will cause Gut to pause before it moves on to the next test. This is useful for debugging, for instance if you want to investigate the screen or anything else after a test has finished executing.

Sometimes you get lazy, and you don’t remove calls to pause_before_teardown after you are done with them. You can tell GUT to ignore calls to pause_before_teardown through the panel or the command line. Setting this in your .gutconfig.json file is recommended for CI/CD Pipelines.

wait_seconds

wait_seconds(time, msg='')
See Awaiting

wait_frames

wait_frames(frames, msg='')
See Awaiting

wait_for_signal

wait_for_signal(sig, max_wait, msg='')
See Awaiting

double

double(path_or_class, inner_class_path=null)
This will return a double of a class. See Doubles for more information.

simulate

simulate(obj, times, delta)
This will call _process or _physics_process on the passed in object and all children of the object. It will call them times times and pass in delta to each call. See Simulate for more information.

stub

stub(...)
Allows you to stub a doubled instance of a script or scene to return a value. See Stubbing for a list of parameters and instructions on Stubbing.

ignore_method_when_doubling

ignore_method_when_doubling(path_or_class, method_name)
This was implemented to allow the doubling of classes with static methods. There might be other valid use cases for this method, but you should always try stubbing before using this method. Using stub(my_double, 'method').to_call_super() or creating a partial_double works for any other known scenario. You cannot stub or spy on methods passed to ignore_method_when_doubling.

This method will add a method for a script to an ignore list. This means the method will not be included in the double. This is required if you are attempting to double a class that has static methods. Each of the static methods must be added to the ignore list or you will get a parser error similar to:

Parser Error: Function signature doesn't match the parent. Parent signature is: 'Variant foo()'.

ignore_method_when_doubling takes two parameters. The first parameter can be a path to a script, a path to a scene, a loaded script, or a loaded scene. The second is the name of the method to ignore.

# -----------------------------------------------
# Given this as res://scripts/has_statics.gd
# -----------------------------------------------
static func this_is_static():
  pass

func not_static():
  return 'foo'

# -----------------------------------------------
# You can double this script like this:
# -----------------------------------------------
func test_can_double_classes_with_statics_if_ignored():
  ignore_method_when_doubling('res://scripts/has_statics.gd', 'this_is_static')
  var d_has_statics = double('res://scripts/has_statics.gd').new()
  assert_not_null(d_has_statics)

func test_can_use_loaded_scripts_to_ignore_statics():
  var HasStatics = load('res://scripts/has_statics.gd')
  ignore_method_when_doubling(HasStatics, 'this_is_static')
  var d_has_statics = double(HasStatics).new()
  assert_not_null(d_has_statics)

func test_cannot_spy_or_stub_ignored_methods():
  var HasStatics = load('res://scripts/has_statics.gd')
  ignore_method_when_doubling(HasStatics, 'this_is_static')
  ignore_method_when_doubling(HasStatics, 'not_static')

  var d_has_statics = double(HasStatics).new()
  # This stub will not be used since the method was ignored
  stub(d_has_statics, 'not_static').to_return('bar')
  var result = d_has_statics.not_static()

  assert_eq(result, 'foo', 'not stubbed so "foo" will be returned')
  # this will pass, even though the method was called,
  # because you cannot spy on ignored methods.
  assert_not_called(d_has_statics, 'not_static')

replace_node

replace_node(base_node, path_or_node, with_this)
Replaces the child node of base_node with with_this. You can pass a path to a node or a child node of base_node. with_this will get all groups that the replaced node had. with_this also gets the same “name” that the replaced node had so that any references to it via $ will work. The replaced node is freed via queue_free.

This is useful when you want to double a node in another node. Your code might be referencing the node via a call to get_node or might be using the $ syntax to get to the object. replace_node allows you to replace a node in another node and retain all of your get_node and $ references.

This will only work for references to the node are made after replace_node has been called. If your object has a local variable that points to the node that gets replaced and:

  • it was set on _init

  • or it was set in _ready or via an onready variable, and the base object has already been added to the tree

then these variables will point to the old object (which gets freed after the call to replace_node).

func test_replace_node():
	# This scene has:
	# Node2D
	#   - Label
	#   - MyPanel
	#     - MyButton
	#
	# And code:
	#
	# double_me_scene.gd:
	# extends Node2D
	#
	# onready var label = get_node('Label')
	#
	# func return_hello():
	# 	return 'hello'
	#
	# func set_label_text(text):
	# 	$Label.set_text(text)
	#
	# func get_button():
	# 	return $MyPanel/MyButton
	var DOUBLE_ME_SCENE = 'res://test/resources/doubler_test_objects/double_me_scene.tscn'

	var scene = load(DOUBLE_ME_SCENE).instance()
	add_child_autofree(scene)
	var replace_label = Label.new()
	replace_node(scene, 'Label', replace_label)

	# Passing
	scene.set_label_text('asdf')
	assert_eq(replace_label.get_text(), 'asdf',
	  "Since set_label_text references the label using $ this will point to the new one.")

	var replace_button = Button.new()
	replace_node(scene, 'MyPanel/MyButton', replace_button)
	assert_eq(scene.get_button(), replace_button,
	  'Get button uses $ so this will work.')

	# Failing
	assert_eq(scene.label, replace_label,
	  'The variable "label" was set as onready so it will not be updated')

compare_deep

compare_deep(v1, v2, max_differences=30)
Performs a deep comparison between two arrays or dictionaries. A CompareResult object is returned. See Comparing Things for more information and examples.

set_double_strategy

set_double_strategy(strategy)

See Double Strategy

Gut Utilities

These methods exist on the GUT instance, and not in GutTest. They must all be prefixed with gut.

gut.directory_delete_files

directory_delete_files(path)
BE VERY CAREFUL when using this. There are no checks to make sure you are in a safe place to be deleting files. You should ALWAYS use this with user:\\ directories.

Deletes all the files at the specified path. Only files are deleted, no directories are deleted. The contents of directories in the specified path are not altered.

gut.file_delete

file_delete(path)
Deletes the file at the path. You should be careful with this one too. Maybe not as careful as directory_delete_files, but still, careful.

gut.file_touch

file_touch(path)
Creates an empty file ath the specified path.

gut.is_file_empty

is_file_empty(path)

Returns true if the file at the specified path has nothing in it or it does not exist, false if it there’s something.

gut.p

gut.p(text, level=0)
Print info to the GUI and console (if enabled). You can see examples if this in the sample code above. In order to be able to spot check the sample code, I print out a divider between the passing and failing tests.