#!/usr/bin/env bash # What the result document says about one damaged machine. # # MM_HOME extracted MegaMek release, with data/scenarios and MegaMek.jar # JAVA_HOME a JDK # ARENA_JAR arena.jar; built into a temporary file if unset # # src/arena/UnitReport.java reads MegaMek's end-of-match state and writes the # per-unit half of result.json - the armour and structure on every location, # every critical slot, and what became of the machine and its pilot. Nothing # downstream can tell a misreading from a quiet fight: a report saying every # location is untouched is exactly what an undamaged force looks like. # # So the damage is applied here, deliberately, and the document is checked for # it. tests/src/check/UnitReportCheck.java is the harness; this is the # assertion. set -euo pipefail ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" : "${MM_HOME:?MM_HOME is required}" : "${JAVA_HOME:?JAVA_HOME is required}" TMP="$(mktemp -d)" trap 'rm -rf "$TMP"' EXIT JAR="${ARENA_JAR:-}" if [ -z "$JAR" ]; then JAR="$TMP/arena.jar" OUT_JAR="$JAR" CLASSES="$TMP/classes" "$ROOT/src/build-jar.sh" >/dev/null fi CP="$MM_HOME/MegaMek.jar" for jar in "$MM_HOME"/lib/*.jar; do CP="$CP:$jar"; done CP="$CP:$JAR" "$JAVA_HOME/bin/javac" -nowarn -Xlint:-options -classpath "$CP" -d "$TMP/classes-check" \ "$ROOT/tests/src/check/UnitReportCheck.java" # Any scenario with a Mek in it; the first training one is the smallest. SCENARIO="${UNIT_REPORT_SCENARIO:-$MM_HOME/data/scenarios/TrainingScenarios/1-FirstRun.mms}" [ -f "$SCENARIO" ] || { echo "ERROR: no scenario at $SCENARIO" >&2; exit 1; } cd "$MM_HOME" "$JAVA_HOME/bin/java" -classpath "$CP:$TMP/classes-check" arena.UnitReportCheck "$SCENARIO" \ > "$TMP/unit.json" # Asserted against the whole document rather than one unit. whole() { # if [ "$(jq -r "$2" "$TMP/unit.json")" = "true" ]; then printf ' ok %s\n' "$1" else printf ' FAIL %s\n' "$1" fail=1 fi } fail=0 # The harness prints every unit in the scenario; the damaged Mek is the first # of them, and is what these assert on. check() { # if [ "$(jq -r ".units[0] | $2" "$TMP/unit.json")" = "true" ]; then printf ' ok %s\n' "$1" else printf ' FAIL %s\n' "$1" fail=1 fi } check "it is JSON at all" '. != null' check "every unit is reported" '. != null' check "the machine is named" '(.name | length) > 0 and (.chassis | length) > 0' check "it knows what kind it is" '.kind == "mek"' check "it carries tonnage and BV" '.tons > 0 and .bv > 0' check "every location is reported" '(.locations | length) >= 8' check "armour comes with its start" '[.locations[] | select(.armorMax > 0)] | length > 0' # The damage UnitReportCheck applied, read back out of the document. check "the stripped torso shows it" '[.locations[] | select(.abbr == "CT")][0] | .armor == 0 and .internal == 3 and .internalMax > 3' check "the blown-off arm says so" '[.locations[] | select(.abbr == "LA")][0].blownOff == true' check "the hit slot is a hit" '[.locations[].slots // [] | .[] | select(. != null) | select(.hit)] | length > 0' check "slots are named" '[.locations[].slots // [] | .[] | select(. != null) | select(.name | length > 0)] | length > 0' # Empty slots are kept as nulls: a slot is a position on a record sheet, and a # list with the gaps closed up moves every slot below a gap one line. check "empty slots keep their place" '[.locations[] | select(.abbr == "HD") | .slots[]] | length >= 6' check "the wounded pilot is wounded" '.crew.hits == 2' check "the pilot has skills" '.crew.gunnery >= 0 and .crew.piloting >= 0' # Everything the machine carries, wherever it sits. The slot list says where # damage landed; this says what the machine is, and for a class whose slots # are empty it is the only such list. check "its equipment is listed" '(.equipment | length) > 0' check "equipment says where it sits" '[.equipment[] | select(.loc | length > 0)] | length > 0' whole "every unit in the scenario is reported" '(.units | length) > 1' # The armour and the internal structure are mounted equipment as far as # MegaMek is concerned and are the diagram as far as a record sheet is # concerned. Left in, every machine's list opens with two lines saying # "Standard". check "the armour is not listed as equipment" '[.equipment[] | select(.name == "Standard")] | length == 0' # --- the classes that are not Meks ------------------------------------------- # # A vehicle is not a Mek and its record is not a Mek's: it has its own body # plan, its own criticals - a locked turret, a wrecked drive train, a hit # driver - and twenty-five slots a location with four of them filled. A # reader drawing it needs to be able to tell that from the document. VEHICLE_SCENARIO="${UNIT_REPORT_VEHICLE_SCENARIO:-$MM_HOME/data/scenarios/1stSomersetStrikers/6-EnemyOfMyEnemy.mms}" if [ -f "$VEHICLE_SCENARIO" ]; then # MegaMek's own logging goes to stderr and is not this test's business. "$JAVA_HOME/bin/java" -classpath "$CP:$TMP/classes-check" arena.UnitReportCheck "$VEHICLE_SCENARIO" \ > "$TMP/vehicles.json" 2>/dev/null vcheck() { # if [ "$(jq -r "[.units[] | select(.kind == \"vehicle\")][0] | $2" "$TMP/vehicles.json")" = "true" ]; then printf ' ok %s\n' "$1" else printf ' FAIL %s\n' "$1" fail=1 fi } vcheck "a vehicle is reported as one" '. != null' vcheck "it carries its own criticals" '.vehicle != null and (.vehicle | has("turretLocked"))' vcheck "it is not given a crew of Meks" '.infantry == null' vcheck "its equipment is listed" '(.equipment | length) > 0' vcheck "its locations are the vehicle's" '[.locations[].abbr] | contains(["FR"]) and contains(["BD"])' else echo " skip a vehicle is reported as one (no scenario with one)" fi check "a live machine is active" '.status == "active"' # MegaMek's own reading of how hurt the machine is - a rules judgement about # what it can still do, not an average of its armour. It is the one thing in # this document a reader does not have to know record sheets to use. check "it says how hurt the machine is" '.damage == "heavy" or .damage == "crippled"' # A bin's full load is the ammo type's own count: getOriginalShots is only set # where something set it, and is zero on a bin that came off the scenario. check "ammo bins report a full load" '[.ammo[] | select(.shotsMax > 0)] | length > 0' check "ammo bins say where they are" '[.ammo[] | select(.loc | length > 0)] | length > 0' if [ "$fail" -ne 0 ]; then echo echo "the document was:" >&2 jq . "$TMP/unit.json" >&2 || cat "$TMP/unit.json" >&2 fi exit "$fail"