Validation Techniques — GDScript

Skill codes on this page

Code Level Skill
C713 1–2 identifies input data for validation
C723 3–4 existence checking
C724 3–4 type checking
C725 3–4 range checking
C735 5–6 two of the three checks
C745 7–8 all three checks
C753 ✍️ 9–10 ALL input data, plus reasonableness and completeness

Definition. Validation checks the reasonableness of data inputs, while the program runs. It is not testing (testing happens to the finished program; validation happens to every input, every run). The three named checks: existence (was anything entered?), type (is it the right kind of value?), range (is it within acceptable limits?).

This ladder is not a checklist. The individual checks are separate codes only at level 3–4. Above that, single codes stand for the combination: C735 = two checks working, C745 = all three, C753 = all inputs plus reasonableness and completeness. Consistency qualifiers decide the band: some inconsistencies (5–6) → minor (7–8) → none (9–10).

In the validation Part B you add existence/type/range checks to the picked feature's real inputs, label them as you go, and run a test to show a check actually fires — a validation that never catches a bad value is scenery.

C713 — Identify the inputs

Level 1–2 is a written list of what needs validating:

# C713 — inputs to validate in this feature:
#   team name   — NameField (LineEdit), free text
#   zone        — ZoneSpinBox (SpinBox), whole number
#   top-up      — TopUpField (LineEdit), dollars and cents

Earns the tick: every user-facing input of the picked feature named. (Choosing constrained controls — a SpinBox can't receive letters — is good design, but the codes below want checks in code.)

C723 — Existence check

Definition. A test to see if a value has been entered as input or not.

# club-ladder — app.gd
func add_team(raw_name: String) -> void:
    var team_name := raw_name.strip_edges()
    if team_name == "":                        # C723 — existence: nothing entered
        message_label.text = "Type a team name first."
        return

Note the real-world details worth copying: strip_edges() first (spaces are not a name), and an error message that says what to do, not just "invalid".

C724 — Type check

Definition. A test to see if a value is of the specified data type or structure.

GDScript's idioms — check before converting, or the conversion itself is the crash:

# C724 — type: is the text actually a number?
if not $TopUpField.text.is_valid_float():
    $MessageLabel.text = "Enter an amount in dollars, like 10.50"
    return
var amount := float($TopUpField.text)

String.is_valid_int() and is_valid_float() are the workhorses. The is keyword type-checks objects — real use in tile-matching-game: if child is Card: (board.gd).

C725 — Range check

Definition. Tests to see if a value is within a given range of acceptable values.

# C725 — range: zones only run 1..3, amounts have a ceiling
if zone < 1 or zone > MAX_ZONE:
    $MessageLabel.text = "Zone must be 1 to %d" % MAX_ZONE
    return
if amount <= 0.0 or amount > MAX_TOP_UP:
    $MessageLabel.text = "Top-up must be between $0.01 and $%.2f" % MAX_TOP_UP
    return

The limits are named constants (MAX_ZONE, MAX_TOP_UP) — that's C7-1 working for C7-3. Clamping (maxi(1, column_count) in club-ladder's board.gd) is the accept-and-correct cousin of reject-and-message; for user input, prefer the message — silent correction hides the user's mistake from them.

C735 and C745 — The checks working together

One validated input, all three checks, in the order that cannot crash — existence, then type, then range:

# C745 — full validation of the top-up amount (existence → type → range)
func validate_top_up(raw: String) -> String:
    var text := raw.strip_edges()
    if text == "":                                   # C723 — existence
        return "Enter an amount first."
    if not text.is_valid_float():                    # C724 — type
        return "Enter a number, like 10.50"
    var amount := float(text)
    if amount <= 0.0 or amount > MAX_TOP_UP:         # C725 — range
        return "Amount must be between $0.01 and $%.2f" % MAX_TOP_UP
    return ""   # empty string = valid

C735 (5–6) is two of these working on real inputs; C745 (7–8) is all three, with at most minor inconsistencies. Error messages are part of the standard — "Must be between 8 and 72 in length" beats "Invalid input" because it tells the user how to fix it (that Discord message was the class's best-in-show in the Validation Detective activity).

C753 — All inputs, plus reasonableness and completeness ✍️

Level 9–10 widens the lens from single fields to the whole data set:

  • All relevant inputs validated — not just the easy one.

  • Completeness — is anything missing? Real example: deck.gd skips half-empty CSV rows with if row.size() < 2: continue (tile-matching-game).

  • Reasonableness — can these values be true together? The model is club-ladder's cross-check:

# club-ladder — app.gd
## In a competition where teams play each other, one team's win is always      # C753 ✍️
## another's loss — so total wins must equal total losses. Worth saying on
## screen rather than quietly showing figures that cannot be true.
func totals_warning() -> String:
    if total_wins == total_losses:
        return ""
    return "Check your data: %d wins recorded, but %d losses." % [total_wins, total_losses]

Earns the tick: every input covered, a completeness check on incoming records, at least one reasonableness rule that crosses fields — and (✍️) the rule written down: work out what rules your data has to obey, and say so in a comment.

Then prove it fires. End the validation task by entering a bad value and showing the message appear — the package script asks for exactly this test run.

Check Your Understanding

  1. Name the three validation checks and their level 3–4 codes.
Answer

Existence C723, type C724, range C725.

  1. Why are C735 and C745 single codes rather than lists of checks?
Answer

Above level 3–4 the descriptor rewards the combination — two checks working (C735), then all three (C745) — with consistency qualifiers deciding the band.

  1. What makes "Must be between 8 and 72 in length" a better error message than "Invalid input"?
Answer

It tells the user exactly how to fix the problem — specific beats generic.

  1. Give an example of a reasonableness check (C753).
Answer

A cross-field rule — e.g. club-ladder's "total wins must equal total losses"; values that are individually fine but cannot be true together.