<!-- Generated from applied-computing-au vic/unit3-4/sat/C08-2026/C08-Reference-Godot by port-reference-godot-to-wiki.py — do not hand-edit; re-run the port. -->
# Types of Test Data — GDScript

*A testing table is only as strong as the range of data it feeds in. Six kinds — and a table that reaches 7–8 visits them all.*

## The six types

| Type | Meaning | Age-checker example |
|---|---|---|
| **Valid** | normal values that should work | 20, 25 |
| **Valid but unusual** | uncommon but acceptable | a 65-year-old student |
| **Invalid** | breaks the rules | 15, 17 |
| **Boundary** | at the exact limit | 17, 18, 19 |
| **Wrong** | wrong format or type | `"twenty"`, -5 |
| **Absent** | missing entirely | `""`, `null` |

## Story 1 — the age checker

Students must be 18 or older to enrol:

```gdscript
func check_age(age):
	if age >= 18:
		return "Eligible for enrolment"
	return "Too young - must be 18+"
```

Fill in an appropriate age for each row, then run them:

| Test ID | Description | Test data type | Input | Expected output | Actual output | Result |
|---|---|---|---|---|---|---|
| TC001 | Valid adult age | Valid | age = | "Eligible for enrolment" | "Eligible for enrolment" | ✅ Pass |
| TC002 | Older student | Valid but unusual | age = | "Eligible for enrolment" | "Eligible for enrolment" | ✅ Pass |
| TC003 | Under-age student | Invalid | age = | "Too young - must be 18+" | "Too young - must be 18+" | ✅ Pass |
| TC004 | Minimum age boundary | Boundary | age = | "Eligible for enrolment" | "Eligible for enrolment" | ✅ Pass |
| TC005 | Just under boundary | Boundary | age = | "Too young - must be 18+" | "Too young - must be 18+" | ✅ Pass |
| TC006 | Text instead of number | Wrong | age = "twenty" | Error message | **Game crashes** | ❌ Fail |
| TC007 | Missing age | Absent | age = null | Error message | **Game crashes** | ❌ Fail |

>| ### Answer
>| | Test ID | Suggested age | Reasoning |
>| |---|---|---|
>| | TC001 | 20 | normal adult student |
>| | TC002 | 65 | unusual but perfectly valid |
>| | TC003 | 13 | clearly under the minimum |
>| | TC004 | 18 | exactly at the boundary — minimum valid |
>| | TC005 | 17 | one below the boundary |

The last two rows are the lesson: `"twenty" >= 18` is an invalid `String`-vs-`int` comparison, so the game **crashes** instead of returning an error message. **Wrong** and **Absent** data are exactly the rows that expose missing validation checks — and every crash they cause belongs in your table as a Fail with a corrective action.

## Story 2 — the GPA calculator (practice)

A GPA calculator that validates its inputs and decides graduation eligibility (needs GPA ≥ 2.0 *and* ≥ 120 credits):

```gdscript
func calculate_gpa(student_id, grades: Array, credits: Array):
	if not str(student_id).is_valid_int() or str(student_id).length() != 8:
		return {"error": "Invalid student ID"}
	if grades.size() != credits.size():
		return {"error": "Grades and credits must match"}
	var total_points := 0.0
	var total_credits := 0
	for i in grades.size():
		if grades[i] < 0 or grades[i] > 100:
			return {"error": "Grade %s out of range" % grades[i]}
		var points := 0.0
		if grades[i] >= 80: points = 4.0
		elif grades[i] >= 70: points = 3.0
		elif grades[i] >= 60: points = 2.0
		total_points += points * credits[i]
		total_credits += credits[i]
	if total_credits == 0:
		return {"error": "No credits provided"}
	var gpa := total_points / total_credits
	if gpa >= 2.0 and total_credits >= 120:
		return {"status": "graduate", "gpa": snapped(gpa, 0.01)}
	return {"status": "not ready", "gpa": snapped(gpa, 0.01)}
```

> [!NOTE]
> **No answer key for this table.** The blank rows are open-ended — you choose the input data. Run your own inputs through the code above and record what actually happens.

| Test ID | Test data type | Input | Expected output | Actual output | Result |
|---|---|---|---|---|---|
| TC001 | Valid | ID=12345678, grades=[85,90], credits=[3,3] | {"status": "graduate", "gpa": 4.0} | {"status": "not ready", "gpa": 4.0} | ❌ Fail |
| TC002 | Valid | | | | |
| TC003 | Valid but unusual | ID=87654321, grades=[60,80], credits=[60,60] | {"status": "graduate", "gpa": 3.5} | {"status": "graduate", "gpa": 3.0} | ❌ Fail |
| TC004 | Valid but unusual | | | | |
| TC005 | Invalid | ID=11111111, grades=[50,40], credits=[3,3] | {"status": "not ready", "gpa": 0.0} | {"status": "not ready", "gpa": 0.0} | ✅ Pass |
| TC006 | Invalid | | | | |
| TC007 | Boundary | ID=22222222, grades=[70,70], credits=[60,60] | {"status": "graduate", "gpa": 2.0} | {"status": "graduate", "gpa": 3.0} | ❌ Fail |
| TC008 | Boundary | | | | |
| TC009 | Wrong | ID="ABCD1234", grades=[80], credits=[3] | {"error": "Invalid student ID"} | {"error": "Invalid student ID"} | ✅ Pass |
| TC010 | Wrong | | | | |
| TC011 | Absent | ID=55555555, grades=[], credits=[] | {"error": "No credits provided"} | {"error": "No credits provided"} | ✅ Pass |
| TC012 | Absent | | | | |

> [!WARNING]
> **Testing reveals issues on both sides.** TC001: only 6 credits, but graduation needs 120+ — the *expected output* was wrong. TC003: the calculated GPA is 3.0 (60→2.0, 80→4.0, equal credits), not 3.5 — expected output wrong again. TC007: GPA is 3.0, not 2.0 — same.

**Key learning:** testing exposes errors in your *expected outputs* (test-design mistakes) as well as in the code. Working out the expected value **before** you run is what makes a testing table a test, not a transcript.
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9