Document project architecture and asset provenance

This commit is contained in:
Alexander Sellite 2026-08-03 15:44:59 -04:00
parent 930acdb1a6
commit 866cc0fc06
10 changed files with 705 additions and 0 deletions

48
CONTRIBUTING.md Normal file
View file

@ -0,0 +1,48 @@
# Contributing
NETfishing is currently developed through focused changes on the repository's
active development branch. Coordinate scope with the project owner before
starting substantial work.
## Change discipline
- Keep a change focused; avoid unrelated cleanup.
- Inspect the working tree before editing and preserve existing work.
- Do not change protocol, save, settings, identity, or portable-data versions
as release-label housekeeping.
- Treat the host as authoritative for catches, purchases, sales, jobs, mail,
and other shared state.
- Keep presentation-only systems out of save files and network messages.
- Store runtime assets under repository-owned paths; never reference a
workstation sync or temporary directory.
- Record the source and license of newly imported assets.
- Do not commit `.godot/`, test data, logs, captures, or build outputs.
## Before requesting review
```sh
git diff --check
scripts/run_validations.sh quick
git status --short
```
Choose additional focused tests from [`docs/TESTING.md`](docs/TESTING.md).
Changes involving networking should run the network suite and a real
two-process check. Visual changes still require graphical review; headless
tests are supporting evidence, not a replacement.
## Commits
- Stage audited paths explicitly.
- Use a concise imperative subject that describes the outcome.
- Do not mix generated build artifacts with source changes.
- Do not rewrite published release tags.
- Describe behavior, compatibility impact, validation, and asset provenance in
the review or release record.
## Style
Follow the conventions already present in the surrounding GDScript, scene, and
resource files. Prefer typed values, named constants, shared resources, and
small domain-specific services. Avoid duplicating protocol definitions or
using display strings as persistent identifiers.

50
CREDITS.md Normal file
View file

@ -0,0 +1,50 @@
# Credits
## Project direction
NETfishing is designed, directed, reviewed, and released by its project
creator. A public-facing creator or studio credit has not yet been recorded in
this repository.
## Development assistance
Development has used automated coding assistance for implementation,
investigation, testing, documentation, and review. Design choices, supplied
artwork, acceptance decisions, repository operations, and releases remain
human-controlled.
This disclosure is intentionally about process. Commit style, code style, or
repository metadata cannot reliably prove whether a particular change was
written with or without assistance.
## Fonts
- Tuffy: Thatcher Ulrich, Karoly Barta, and Michael Evans. The bundled license
dedicates the work to the public domain; see `ui/fonts/Tuffy-LICENSE.txt`.
- Seattle Avenue: bundled as `ui/fonts/seattle_avenue.otf`. Author and
redistribution terms still need to be recorded before public distribution.
## Music
- `audio/music/title/as_in_four_wolves.ogg`: original title/ambient music by
the project owner.
## Sound effects
- “Spinning reel.wav” by tosha73, used as the source for the fishing fight and
manual-reeling loops. Freesound sound 509902, Creative Commons Zero (CC0):
https://freesound.org/s/509902/
- “Gentle Ocean Waves Loop” by kkenny101, used for the saltwater shoreline
ambience. Freesound sound 852826, Creative Commons Zero (CC0):
https://freesound.org/s/852826/
- “Quick Water Droplet” by qubodup, used for the bobber water-impact sound.
Freesound sound 792931, Creative Commons Zero (CC0):
https://freesound.org/s/792931/
## Artwork
- 2D artwork: Rheannon Eisworth, contributor.
- 3D models: original work by the project owner.
Asset categories and release-record requirements are listed in
[`docs/ASSET-PROVENANCE.md`](docs/ASSET-PROVENANCE.md).

82
README.md Normal file
View file

@ -0,0 +1,82 @@
# NETfishing
NETfishing is a multiplayer-first fishing game built with Godot 4.7. The
current pre-alpha includes host-authoritative fishing and economy flows,
freshwater and saltwater habitats, persistent player data, social features,
customization, jobs, and a controller-aware interface.
The project is under active development. Interfaces, balance, content, and
save migrations may continue to change before a stable release.
## Requirements
- Godot 4.7.x with the GL Compatibility renderer
- Linux, Windows, or an Android development environment supported by Godot
- Bash for the repository helper scripts
Open `project.godot` in Godot, or start the editor from the repository root:
```sh
godot --editor --path .
```
Run the game directly with:
```sh
godot --path .
```
## Validation
The validation scripts isolate Godot's settings and application-data roots.
Run the fast, deterministic suite before submitting a change:
```sh
scripts/run_validations.sh quick
```
Additional suites and individual commands are documented in
[`docs/TESTING.md`](docs/TESTING.md).
## Building
Export presets are maintained for Linux, Windows, and Android. Repository
scripts expect the matching Godot export templates and platform toolchains to
already be installed:
```sh
scripts/build_playtest.sh
scripts/build_android_debug.sh
```
Build outputs belong under the ignored `builds/` directory. Release builds
must follow the project's separate tagged-release checklist; these convenience
scripts do not create or publish tags.
## Project map
- `main/`: composition root and application orchestration
- `world/`: map, environment, water, and world presentation
- `player/`, `fishing/`, `fish/`: player and fishing domain
- `network/`: transport, identity, and host-authoritative services
- `inventory/`, `items/`, `economy/`, `progression/`, `jobs/`: game state
- `save/`, `settings/`: versioned persistence
- `ui/`: gameplay and menu presentation
- `tests/`: focused Godot validation scripts
- `scripts/`: build, bake, and validation entry points
See [`docs/ARCHITECTURE.md`](docs/ARCHITECTURE.md) and
[`world/README-WORLD-AUTHORING.md`](world/README-WORLD-AUTHORING.md) for more
detail.
## Authorship and assets
NETfishing is human-directed and uses a mixture of human-authored assets and
software-development assistance. The project records this plainly rather than
claiming that repository history can prove how each line was produced. See
[`CREDITS.md`](CREDITS.md) and
[`docs/ASSET-PROVENANCE.md`](docs/ASSET-PROVENANCE.md).
No project-wide source license has been selected yet. Do not assume permission
to redistribute the source or bundled assets beyond rights stated in their
individual license records.

72
docs/ARCHITECTURE.md Normal file
View file

@ -0,0 +1,72 @@
# Architecture
## Composition
`main/main.tscn` is the application composition root. It owns long-lived
services, the active world, player container, save/settings managers, and the
pixelated UI viewport. Services are scene-owned rather than global autoloads,
which makes their dependencies visible in the main scene and allows focused
tests to instantiate the same composition.
The main script coordinates title, session, world, and UI lifecycle. Domain
logic remains in typed resources and services rather than being stored solely
in controls.
## Domain boundaries
- `fish/` defines species, availability, catches, pools, quality, and selection.
- `fishing/` owns cast/chase state and resolves authoritative fishing surfaces.
- `inventory/`, `items/`, `economy/`, `progression/`, and `jobs/` own persistent
player-facing game state.
- `world/` owns authored map composition and presentation. Water type is a
shared typed definition used by water bodies, fish habitat, fishing
validation, Logbook classification, and saltwater shoreline presentation.
- `ui/` observes and invokes domain services. It does not define stable item or
fish identity.
Resource files (`.tres`) are authored data. Stable IDs, not display names or
node names, connect persistent and networked state to that data.
## Networking
`NetworkSession` owns ENet session lifecycle and peer registration. Dedicated
network services validate and replicate bounded domains such as fishing,
sales, shops, item use, profiles, jobs, mail, chat, drawings, time, and weather.
The host is authoritative. Clients submit requests or evidence; the host
derives trusted context from registered peers, authoritative regions, and
server-owned state before mutating inventory, wallet, progression, or shared
world state. See [`decisions/0001-host-authority.md`](decisions/0001-host-authority.md).
Protocol compatibility is defined in `network/network_protocol.gd`. A visible
release version is not a reason to change the protocol number.
## Persistence
`PlayerDataRoot` selects and validates a portable data root. Stores receive
paths from that owner rather than inventing unrelated locations. Progression is
written by `PlayerSaveManager`; device settings and social/identity stores have
separate formats and lifecycles.
Save migrations are sequential and explicit. Existing catches and ownership
are keyed by stable IDs so authored metadata can evolve without rewriting
historical records. Current source constants—not documentation—are
authoritative for format versions.
## Presentation
Gameplay is rendered in 3D with the GL Compatibility renderer. The main UI is
presented through a uniformly scaled SubViewport. Shared UI components and
palette resources prevent page-specific geometry and style drift.
World presentation systems (time/weather visuals, procedural sky and water,
shoreline ribbons, player blob shadows) do not own gameplay collision or
network authority. Generated shoreline meshes are deterministic presentation
resources baked from explicitly configured static terrain.
## Validation
Tests are executable Godot `SceneTree` scripts. Some are pure content/domain
checks, some instantiate the main scene, and multiplayer checks run paired host
and client processes on loopback. The repository runner provides isolation and
consistent entry points; see [`TESTING.md`](TESTING.md).

109
docs/ASSET-PROVENANCE.md Normal file
View file

@ -0,0 +1,109 @@
# Asset provenance
This document records where runtime assets came from and what must be verified
before redistribution. A Git commit proves when bytes entered this repository;
it does not by itself prove authorship or licensing.
## Intake policy
For every new external or supplied asset, record:
- creator or supplying party;
- original source location or delivery channel;
- source filename and repository destination;
- source and destination SHA-256 when copied without modification;
- license or explicit permission;
- any permitted transformations;
- the importing commit or release.
Runtime resources must use `res://` paths. Workstation Sync folders are intake
locations only and must never appear in scenes or resources.
## Current inventory
| Asset family | Repository location | Recorded provenance |
| --- | --- | --- |
| Fish art and portraits | `fish/species/`, `art/exported/fish/` | 2D artwork by contributor Rheannon Eisworth. |
| Item icons | `items/icons/` | 2D artwork by contributor Rheannon Eisworth. |
| Inventory notepad | `art/ui/ui_notepad.png` | 2D artwork by contributor Rheannon Eisworth; integrated without a runtime external path. |
| Environment textures | `art/exported/environment/textures/` | 2D artwork by contributor Rheannon Eisworth. |
| UI patterns | `art/patterns/` | 2D artwork by contributor Rheannon Eisworth. |
| Character and world models | `art/exported/` | Original 3D models by the project owner. Any embedded 2D artwork is by Rheannon Eisworth. |
| Tuffy font | `ui/fonts/Tuffy_Bold.otf` | Public-domain dedication in `ui/fonts/Tuffy-LICENSE.txt`. |
| Seattle Avenue font | `ui/fonts/seattle_avenue.otf` | License and attribution not present; resolve before public distribution. |
| Title music | `audio/music/title/as_in_four_wolves.ogg` | Original music composed and owned by the project owner. |
| Fishing fight loop | `audio/sfx/fishing/fighting.wav` | Edited from “Spinning reel.wav” by Freesound user tosha73, sound 509902, CC0. |
| Manual-reeling loop | `audio/sfx/fishing/reeling.wav` | Edited from the same CC0 “Spinning reel.wav” source. |
| Saltwater wave ambience | `audio/ambience/waves.wav` | “Gentle Ocean Waves Loop” by Freesound user kkenny101, sound 852826, CC0. |
| Bobber water impact | `audio/sfx/fishing/bobber.wav` | “Quick Water Droplet” by Freesound user qubodup, sound 792931, CC0. |
### Fishing fight loop source record
- Source page: https://freesound.org/s/509902/
- Creator: tosha73
- Source title: `Spinning reel.wav`
- License: Creative Commons Zero (CC0)
- Downloaded source filename: `509902__tosha73__spinning-reel.wav`
- Downloaded source SHA-256:
`9741afdb1ec9c73f5e039f0e5ac174998cb0a1f737b626531e63919d4d232fad`
- Audacity working project: `fighting.aup3`
- Audacity project SHA-256:
`9928f077ecf48d01416f8d05700707e1b07d0f731846db80e27116f5b82dbbf5`
- Runtime edit source/destination SHA-256:
`b6f3f2f94bfaf9254ac04dd96b1fd28c15e1011a1db44bb3e70eeaa95de3c212`
- Runtime format: 48 kHz, 16-bit, stereo PCM WAV; 2.593479 seconds;
configured as a forward loop by the fishing presentation.
- Manual-reeling Audacity project: `reeling.aup3`
- Manual-reeling Audacity project SHA-256:
`20ad52f6bdd16ae6561f06f8355fe309e95023e815053fd5dfbd5a5ce3c1f9f9`
- Manual-reeling runtime source/destination SHA-256:
`e403d5b7c8af1da4b28599cc0f51de3eda70d9e9296db27852fe7dc95617a29d`
- Manual-reeling runtime format: 48 kHz, 16-bit, stereo PCM WAV;
2.388083 seconds; configured as a forward loop.
- The downloaded source and Audacity projects remain in the project owner's
source-work archive; only the finished runtime edits ship in the game.
### Saltwater wave ambience source record
- Source page: https://freesound.org/s/852826/
- Creator: kkenny101
- Source title: `Gentle Ocean Waves Loop`
- License: Creative Commons Zero (CC0)
- Downloaded source filename:
`852826__kkenny101__gentle-ocean-waves-loop.wav`
- Downloaded source and runtime source/destination SHA-256:
`f93e9890583f072ac52cf197b8b5942397d3d5e889fbdb9112a0776142f50229`
- Runtime format: 48 kHz, 24-bit, mono PCM WAV; 21.769917 seconds;
configured as a forward loop.
- The downloaded source remains in the project owner's source-work archive;
only the finished runtime loop ships in the game.
### Bobber water-impact source record
- Source page: https://freesound.org/s/792931/
- Creator: qubodup
- Source title: `Quick Water Droplet`
- License: Creative Commons Zero (CC0)
- Downloaded source filename: `792931__qubodup__quick-water-droplet.wav`
- Downloaded source and runtime source/destination SHA-256:
`aef0d16384efed4a7b071c4d80c21597617f882f4e0c1d5295ac194d315eafb7`
- Runtime format: 48 kHz, 16-bit, mono PCM WAV; 0.197146 seconds; one-shot.
- The downloaded source remains in the project owner's source-work archive;
only the finished runtime sound ships in the game.
## Generated resources
Godot `.import` sidecars and deterministic shoreline `.tres` meshes are derived
repository resources, not original artwork. `.godot/imported/`, editor caches,
captures, exports, and temporary test data are not tracked.
## Release gate
Before a public binary or source release:
1. Resolve the Seattle Avenue font license and attribution gap above.
2. Record the public owner/studio credit and the contributor's redistribution
permission in the chosen project license or release records.
3. Confirm the project-wide source/content license selected by the owner.
4. Search exported resources for external filesystem paths.
5. Preserve required third-party notices with the package.

41
docs/BALANCE.md Normal file
View file

@ -0,0 +1,41 @@
# Balance and content notes
Balance is authored data and should change deliberately. This document records
the policy; exact current values remain authoritative in `.tres` resources and
typed scripts.
## Fish
- Stable fish IDs and catalog numbers must not be changed for display cleanup.
- Species availability may constrain water type, time, weather, bait, and other
authored context.
- Location pools control selection weight; the global catalog remains
comprehensive.
- Freshwater/saltwater habitat is validated by the host in addition to pool
membership.
- Value, rarity, quality, and weight ranges should be reviewed together because
they affect economy and catch difficulty.
## Economy and progression
- Sales and purchases are host-authoritative and must mutate inventory and
wallet exactly once.
- Reserved assets are rejected atomically; mixed valid/reserved batches must
not partially succeed.
- Item effects, shop prices, cooler capacity, fishing upgrades, jobs, and
experience are separate balance axes. Avoid changing several in an unrelated
presentation pass.
## Recording a balance change
Include in the change description:
1. affected stable IDs and resource paths;
2. old and new values;
3. intended player-facing outcome;
4. interactions with quality, availability, and economy;
5. deterministic validation performed;
6. whether existing saves remain semantically valid.
Do not bump the save schema or network protocol simply because an authored
number changed. Bump a format only when its serialized contract changes.

63
docs/TESTING.md Normal file
View file

@ -0,0 +1,63 @@
# Testing
NETfishing validations are Godot `SceneTree` scripts. They use assertions and
exit nonzero on failure. Run them with isolated user data so development checks
cannot touch real saves, identity, trust, relationships, or settings.
## Consolidated runner
```sh
scripts/run_validations.sh quick
scripts/run_validations.sh full
scripts/run_validations.sh host
scripts/run_validations.sh network
scripts/run_validations.sh all
scripts/run_validations.sh --list
```
- `quick` runs deterministic content and domain validations.
- `full` adds socket-free scene/runtime checks suitable for headless execution.
- `host` runs single-process authoritative-host checks that bind a local UDP
port.
- `network` runs the loopback host/client validations in pairs.
- `all` runs `full`, `host`, and then `network`.
Set `GODOT_BIN` to select another executable. Set `TEST_TIMEOUT_SECONDS` to
change the per-process timeout. The runner creates one temporary XDG root per
process and removes it on exit.
## One focused test
```sh
test_root="$(mktemp -d)"
XDG_DATA_HOME="$test_root/data" \
XDG_CONFIG_HOME="$test_root/config" \
godot --headless --path . --script tests/fish_catalog_content_validation.gd
rm -rf -- "$test_root"
```
Do not set `NETFISHING_DATA_DIR` to an arbitrary empty folder: that variable is
an explicit portable-data override and must point at a valid NETfishing data
root. Isolating XDG paths is sufficient for the validation scripts.
## Graphical checks
Headless tests cannot prove visual alignment, actual mouse routing, shader
appearance, controller feel, or window-resize behavior. Presentation changes
need a real graphical startup with isolated XDG roots and inspection at the
canonical 1280×720 layout plus relevant low/high and ultrawide resolutions.
## Network checks
Host and paired tests bind loopback UDP ports defined in their scripts. Ensure
no old Godot validation process is holding those ports and that the execution
environment permits local sockets. The runner starts paired hosts before their
clients and requires both processes to exit successfully. Network tests do not
contact external servers.
## Release checks
A release audit additionally includes clean Git/tag verification, editor import,
export-template checks, platform exports, executable smoke tests, archive
inspection, and SHA-256 verification. Those checks are intentionally not hidden
inside the development runner.

View file

@ -0,0 +1,27 @@
# ADR 0001: Host-authoritative shared state
Status: accepted
## Context
NETfishing supports private hosts, open hosts, and joined clients. Catches,
currency, owned items, jobs, mail, drawings, profiles, and moderation affect
state that cannot safely trust a client's local presentation.
## Decision
The host validates requests against registered peers and host-owned context,
then performs the authoritative mutation. Clients receive results and replicated
presentation state. Client evidence is bounded and reconstructed where
possible; it is not treated as authority.
Private single-player uses the same host path. Presentation-only state does not
add RPCs or persistence.
## Consequences
- Shared behavior is consistent across private, open-host, and joined-client
modes.
- Tests must cover local-host and paired host/client paths.
- Stable protocol payloads and rejection cleanup require explicit handling.
- UI activation cannot be used as proof that a server-side mutation succeeded.

View file

@ -0,0 +1,27 @@
# ADR 0002: Authored resources and stable identifiers
Status: accepted
## Context
Fish, items, pools, availability, shop stock, and other game content evolve
independently from saved catches and network messages. Display labels and scene
node names are expected to change during development.
## Decision
Repository-owned resources are the authoritative authored data. Persistent and
networked records refer to stable IDs. Display names, filenames, node names,
coordinates, and pool names are not compatibility identifiers.
Cross-domain concepts such as water type use one typed definition rather than
duplicated strings. Comprehensive catalogs remain separate from location-
specific selection pools.
## Consequences
- Renaming visible UI does not require save migration.
- Removing or changing a stable ID requires an explicit compatibility plan.
- Content validation checks uniqueness, catalog completeness, pool membership,
and typed habitat compatibility.
- New authored assets need provenance records as well as resource references.

186
scripts/run_validations.sh Executable file
View file

@ -0,0 +1,186 @@
#!/usr/bin/env bash
set -euo pipefail
readonly SCRIPT_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)"
readonly PROJECT_ROOT="$(cd -- "${SCRIPT_DIR}/.." && pwd)"
readonly GODOT_BIN="${GODOT_BIN:-godot}"
readonly TEST_TIMEOUT_SECONDS="${TEST_TIMEOUT_SECONDS:-120}"
readonly RUN_ROOT="$(mktemp -d -t netfishing-validations.XXXXXX)"
readonly -a QUICK_TESTS=(
"tests/android_readiness_validation.gd"
"tests/fish_catalog_content_validation.gd"
"tests/fish_quality_validation.gd"
"tests/fishing_audio_validation.gd"
"tests/fishing_surface_validation.gd"
"tests/logbook_validation.gd"
"tests/player_experience_validation.gd"
"tests/shoreline_ambience_validation.gd"
"tests/surface_drawing_validation.gd"
"tests/terrain_projection_validation.gd"
"tests/world_time_validation.gd"
"tests/world_weather_validation.gd"
)
readonly -a RUNTIME_TESTS=(
"tests/inventory_notepad_art_validation.gd"
"tests/logbook_runtime_validation.gd"
"tests/player_experience_ui_validation.gd"
"tests/ui_scaling_runtime_validation.gd"
)
readonly -a HOST_TESTS=(
"tests/art_tools_validation.gd"
"tests/economy_regression_validation.gd"
"tests/fish_hotbar_showcase_validation.gd"
"tests/fishing_authority_validation.gd"
"tests/job_system_validation.gd"
"tests/surface_drawing_runtime_validation.gd"
)
readonly -a NETWORK_TESTS=(
"tests/economy_regression_validation.gd"
"tests/fish_showcase_multiplayer_validation.gd"
"tests/fishing_multiplayer_validation.gd"
"tests/job_multiplayer_validation.gd"
"tests/surface_drawing_multiplayer_validation.gd"
"tests/world_time_multiplayer_validation.gd"
)
cleanup() {
rm -rf -- "${RUN_ROOT}"
}
trap cleanup EXIT INT TERM
usage() {
printf 'Usage: %s {quick|full|host|network|all|--list}\n' "$0"
}
prepare_root() {
local name="$1"
local root="${RUN_ROOT}/${name}"
mkdir -p -- "${root}/data" "${root}/config" "${root}/cache"
printf '%s\n' "${root}"
}
run_test() {
local script="$1"
local name="${script#tests/}"
name="${name%.gd}"
local root
root="$(prepare_root "${name}")"
printf '\n==> %s\n' "${script}"
XDG_DATA_HOME="${root}/data" \
XDG_CONFIG_HOME="${root}/config" \
XDG_CACHE_HOME="${root}/cache" \
timeout "${TEST_TIMEOUT_SECONDS}s" "${GODOT_BIN}" \
--headless --path "${PROJECT_ROOT}" --script "${script}"
}
run_network_test() {
local script="$1"
local name="${script#tests/}"
name="${name%.gd}"
local host_root client_root host_pid host_status client_status
host_root="$(prepare_root "${name}-host")"
client_root="$(prepare_root "${name}-client")"
printf '\n==> %s (host + client)\n' "${script}"
XDG_DATA_HOME="${host_root}/data" \
XDG_CONFIG_HOME="${host_root}/config" \
XDG_CACHE_HOME="${host_root}/cache" \
timeout "${TEST_TIMEOUT_SECONDS}s" "${GODOT_BIN}" \
--headless --path "${PROJECT_ROOT}" --script "${script}" -- host \
>"${host_root}/output.log" 2>&1 &
host_pid=$!
sleep 0.75
set +e
XDG_DATA_HOME="${client_root}/data" \
XDG_CONFIG_HOME="${client_root}/config" \
XDG_CACHE_HOME="${client_root}/cache" \
timeout "${TEST_TIMEOUT_SECONDS}s" "${GODOT_BIN}" \
--headless --path "${PROJECT_ROOT}" --script "${script}" -- client \
>"${client_root}/output.log" 2>&1
client_status=$?
wait "${host_pid}"
host_status=$?
set -e
printf '%s\n' '-- host output --'
sed -n '1,240p' "${host_root}/output.log"
printf '%s\n' '-- client output --'
sed -n '1,240p' "${client_root}/output.log"
if ((host_status != 0 || client_status != 0)); then
printf 'error: host exited %d; client exited %d\n' \
"${host_status}" "${client_status}" >&2
return 1
fi
}
run_quick() {
local test_script
for test_script in "${QUICK_TESTS[@]}"; do
run_test "${test_script}"
done
}
run_full() {
local test_script
run_quick
for test_script in "${RUNTIME_TESTS[@]}"; do
run_test "${test_script}"
done
}
run_host() {
local test_script
for test_script in "${HOST_TESTS[@]}"; do
run_test "${test_script}"
done
}
run_network() {
local test_script
for test_script in "${NETWORK_TESTS[@]}"; do
run_network_test "${test_script}"
done
}
list_tests() {
printf '%s\n' 'Quick tests:'
printf ' %s\n' "${QUICK_TESTS[@]}"
printf '%s\n' 'Additional full-suite tests:'
printf ' %s\n' "${RUNTIME_TESTS[@]}"
printf '%s\n' 'Single-process tests requiring a local UDP bind:'
printf ' %s\n' "${HOST_TESTS[@]}"
printf '%s\n' 'Paired network tests:'
printf ' %s\n' "${NETWORK_TESTS[@]}"
}
case "${1:-}" in
quick)
run_quick
;;
full)
run_full
;;
host)
run_host
;;
network)
run_network
;;
all)
run_full
run_host
run_network
;;
--list)
list_tests
;;
*)
usage >&2
exit 2
;;
esac
printf '\nAll requested validations passed.\n'