Blame

36b863 lisa 2026-08-12 09:10:36
Add C07 study pages; regenerate C06 via the shared port script sd/C07: home + Naming Conventions, Internal Documentation, Validation Techniques (21 skill codes), linked from the SD hub. sd/C06 pages regenerated by sat/port-reference-godot-to-wiki.py (marker update; C06-home now generated from the repo README like every other page). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
1
<!-- Generated from applied-computing-au vic/unit3-4/sat/C07-2026/C07-Reference-Godot by port-reference-godot-to-wiki.py — do not hand-edit; re-run the port. -->
2
# Validation Techniques — GDScript
3
4
**Skill codes on this page**
5
6
| Code | Level | Skill |
7
|---|---|---|
8
| C713 | 1–2 | identifies input data for validation |
9
| C723 | 3–4 | existence checking |
10
| C724 | 3–4 | type checking |
11
| C725 | 3–4 | range checking |
12
| C735 | 5–6 | two of the three checks |
13
| C745 | 7–8 | all three checks |
14
| C753 ✍️ | 9–10 | ALL input data, plus reasonableness and completeness |
15
16
**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?).
17
18
**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).
19
20
**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.
21
22
## C713 — Identify the inputs
23
24
Level 1–2 is a written list of what needs validating:
25
26
```gdscript
27
# C713 — inputs to validate in this feature:
28
# team name — NameField (LineEdit), free text
29
# zone — ZoneSpinBox (SpinBox), whole number
30
# top-up — TopUpField (LineEdit), dollars and cents
31
```
32
33
**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*.)
34
35
## C723 — Existence check
36
37
**Definition.** A test to see if a value has been entered as input or not.
38
39
```gdscript
40
# club-ladder — app.gd
41
func add_team(raw_name: String) -> void:
42
var team_name := raw_name.strip_edges()
43
if team_name == "": # C723 — existence: nothing entered
44
message_label.text = "Type a team name first."
45
return
46
```
47
48
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".
49
50
## C724 — Type check
51
52
**Definition.** A test to see if a value is of the specified data type or structure.
53
54
GDScript's idioms — check *before* converting, or the conversion itself is the crash:
55
56
```gdscript
57
# C724 — type: is the text actually a number?
58
if not $TopUpField.text.is_valid_float():
59
$MessageLabel.text = "Enter an amount in dollars, like 10.50"
60
return
61
var amount := float($TopUpField.text)
62
```
63
64
`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`).
65
66
## C725 — Range check
67
68
**Definition.** Tests to see if a value is within a given range of acceptable values.
69
70
```gdscript
71
# C725 — range: zones only run 1..3, amounts have a ceiling
72
if zone < 1 or zone > MAX_ZONE:
73
$MessageLabel.text = "Zone must be 1 to %d" % MAX_ZONE
74
return
75
if amount <= 0.0 or amount > MAX_TOP_UP:
76
$MessageLabel.text = "Top-up must be between $0.01 and $%.2f" % MAX_TOP_UP
77
return
78
```
79
80
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.
81
82
## C735 and C745 — The checks working together
83
84
One validated input, all three checks, in the order that cannot crash — existence, then type, then range:
85
86
```gdscript
87
# C745 — full validation of the top-up amount (existence → type → range)
88
func validate_top_up(raw: String) -> String:
89
var text := raw.strip_edges()
90
if text == "": # C723 — existence
91
return "Enter an amount first."
92
if not text.is_valid_float(): # C724 — type
93
return "Enter a number, like 10.50"
94
var amount := float(text)
95
if amount <= 0.0 or amount > MAX_TOP_UP: # C725 — range
96
return "Amount must be between $0.01 and $%.2f" % MAX_TOP_UP
97
return "" # empty string = valid
98
```
99
100
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).
101
102
## C753 — All inputs, plus reasonableness and completeness ✍️
103
104
Level 9–10 widens the lens from single fields to the **whole data set**:
105
106
- **All relevant inputs** validated — not just the easy one.
107
108
- **Completeness** — is anything missing? Real example: `deck.gd` skips half-empty CSV rows with `if row.size() < 2: continue` (tile-matching-game).
109
110
- **Reasonableness** — can these values be true *together*? The model is club-ladder's cross-check:
111
112
```gdscript
113
# club-ladder — app.gd
114
## In a competition where teams play each other, one team's win is always # C753 ✍️
115
## another's loss — so total wins must equal total losses. Worth saying on
116
## screen rather than quietly showing figures that cannot be true.
117
func totals_warning() -> String:
118
if total_wins == total_losses:
119
return ""
120
return "Check your data: %d wins recorded, but %d losses." % [total_wins, total_losses]
121
```
122
123
**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.
124
125
**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.
126
127
## Check Your Understanding
128
129
1. Name the three validation checks and their level 3–4 codes.
130
131
>| ### Answer
132
>| Existence C723, type C724, range C725.
133
134
2. Why are C735 and C745 single codes rather than lists of checks?
135
136
>| ### Answer
137
>| Above level 3–4 the descriptor rewards the *combination* — two checks working (C735), then all three (C745) — with consistency qualifiers deciding the band.
138
139
3. What makes "Must be between 8 and 72 in length" a better error message than "Invalid input"?
140
141
>| ### Answer
142
>| It tells the user exactly how to fix the problem — specific beats generic.
143
144
4. Give an example of a reasonableness check (C753).
145
146
>| ### Answer
147
>| 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.