Introduction - dicksonlaw583/gmassert2 GitHub Wiki

Introduction

What is an assertion?

An assertion is a condition that must be satisfied during runtime in order to proceed correctly. If an assertion is not satisfied, the program stops and reports failure. This can be used to help bring problems in your code to light.

How to use GMAssert

Basic Usage

Here is an example of one of the most common GMAssert assertions, assert_equal(got, expected, [msg]):

assert_equal(name, "Alice", "Name is wrong!");
  • The first argument (got) represents the value that you wish to check the validity of.
  • The second argument (expected) represents the correct reference value.
  • The last argument ([msg]) is an optional message that helps remind you of what has gone wrong if the assertion is not satisfied. If left unspecified, a default error message will be shown.

If the assertion is satisfied, then nothing happens. Otherwise, an error message similar to the following would appear, indicating what has gone wrong, the expected value and the value received by the assertion:


___________________________________________
############################################################################################
FATAL ERROR in Room Creation Code for room rm_test

Name is wrong!

Expected: (string)
"Alice"

Got: (string)
"Bob"


 at gml_Script___gma_assert_error__ (line 11) -       show_error(msg, true);
############################################################################################
--------------------------------------------------------------------------------------------
stack frame is
gml_Script___gma_assert_error__ (line 11)
called from - gml_Script_assert_equal (line 23) -     __gma_assert_error__(msg, argument[1], argument[0]);
called from - gml_Room_rm_test_Create (line 3) -        assert_equal(name, "Alice", "Name is wrong!");

For a full list of available assertions, please see Function Listings.

Use Case 1: Automated Test Suites

Assertions can be run in series to create a test suite. This can help you automatically check the functionality of your code against known examples.

Example: You have just created a script that shuffles the contents of an array, but are unsure whether it behaves as expected. This can be checked by running the following:

// Setting up a test
var array = array_create(6);
for (var i = 0; i < 6; i++) {
  array[i] = i;
}
array_shuffle(array);
// Running the test
assert_equal(array_length_1d(array), 6, "The shuffle changed the array's size!");
for (var i = 0; i < 6; i++) {
  assert_contains(array, i, "The shuffle lost entries!");
}

Use Case 2: Diagnosing Runtime Errors

You can also use assertions to help diagnose runtime errors. Place assertions in front of the error-inducing line checking for likely causes, set the breakpoint hook, and run the project under debug mode (F6).

Example: A line of code is raising errors about an unknown instance.

draw_text(x, y, "Ammo: " + string(gun.ammo));

You can try to diagnose this by checking for noone and verifying instance_exists() as assertions:

assert_not_equal(gun, noone, "gun should not be noone!");
assert(instance_exists(gun), "gun no longer exists!");
draw_text(x, y, "Ammo: " + string(gun.ammo));

If either assertion fails, the debugger would stop and allow you time to explore the runtime state at that point for potential causes.

Reading Debug Values

When an assertion failure message appears, the expected and gotten values will appear in a detailed debug format.

  • Strings, real-valued integers, infinity and NaN, arrays, non-constructor structs: Same notation as standard GMS 2.3 GML literal syntax (Examples: "Hello world!" 365 -infinity [1, 2, 3] {x: 5, y: 6, z: 7})
  • Real-valued decimal number: Scientific notation with up to 15 significant digits (Example: 3.675)
  • 64-bit or 32-bit integer: Same as real-valued integers, but enclosed by brackets and preceded by the actual type (Example: int64(642) int32(2))
  • Pointers: Hexadecimal value enclosed by ptr() (Example: ptr($3f))
  • Constructor-made structs: Same as non-constructor structs, but enclosed by another set of brackets and preceded by the constructor's name (Example: Vector2({x: 0, y: 0}))
  • "Hard booleans" (i.e. those that is_bool() would return true on): bool(true) for true and bool(false) for false.
  • References: Numeric value enclosed by ref() (Example: ref(100000))

Some assertions also accept data structure IDs. For those that do, here is their debug format:

  • Lists: Comma-separated content, enclosed by list() (Example: list(1, 2, 3))
  • Maps: Comma-separated key:value pairs, enclosed by map() (Example: map("x": 3, "y": 4, "z": 5))
  • Grids: Comma-separated content in row-major order, rows separated by semicolons, enclosed by grid() (Example: grid(1, 2, 3; 4, 5, 6; 7, 8, 9))