Commit graph Aetheria/tests/mutation_tests.py
Author SHA1 Message Date
Meta Vens
ec3be4f4b5 Cut 0: mutation-test the entity-settings-copy rule
Adds a control (no-op) and a red mutation reverting Entity's constructor
to alias its settings argument instead of copying it. Both run against
EntitiesDoNotShareDefaultEntitySettings; the red mutation is killed.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-17 18:32:45 +02:00
Meta Vens
88bcbc94b0 Test that capability events route only to their own kind's subscribers
CapabilityEventsTests.EachEventKindReachesOnlyItsOwnSubscribers publishes one
of each event kind and asserts every subscriber list holds exactly its own
event -- a subscriber to Absorb must never see a Grab/Melee/Thrust event.
Mutation entry in tests/mutation_tests.py kills a mutant that makes
PublishAbsorb also notify the Thrust stream, plus a no-op control proving the
mutation script's own read/replace/restore path is transparent for this file.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-17 14:37:07 +02:00
Meta Vens
ebba4a36b5 Test the IFF/grudge/detection rules and the weapon stance gate
IffAndCombatTests builds a minimal headless world (CultCache catalog, a Ship
hull and a gun with InstantWeaponData, an empty Zone/GalaxyZone) and pins:
override decides outright; clearing restores the derived rule; leaving the
zone clears overrides; the derived reciprocity path can't mirror another
entity's override; grudge triggers immediately whether the mark or the
detection happens second, is detection-gated, is sticky, and never fires for
a player-controlled entity; PerceivedStanceOf is unknown until detected;
Weapon.StanceAllowsFire and InstantWeapon.Trigger refuse to fire on a neutral
target and fire on a hostile one (and with no target at all); LockWeapon
builds lock on the shooter's own stance, not the target's; and
ZoneGenerator.EligibleWandererFactions excludes the owner and nearest faction
(and is empty when neither is eligible).

Adds one mutation per rule to tests/mutation_tests.py, all KILLED against
this HEAD (control still GREEN).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-17 14:01:31 +02:00
Meta Vens
5e9634efcd Pin Brand's same-maker tie-break with a test and a mutant
Brand()'s ordering by record key was only exercised indirectly, through
a test that gives each candidate product a different maker. Add a test
with two FactionProductData for the same maker and same design, distinct
record keys, asserting Brand returns the one first in record-key order.

Add the corresponding mutant (OrderBy -> OrderByDescending at Brand's
ordering) to mutation_tests.py so a regression there gets caught.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-17 12:42:48 +02:00
Meta Vens
333a73709a Cut C: delete ItemData.Manufacturer, derive census makers from products
The manufacturer does not belong to a design (operator ruling); it lives on
FactionProductData and branding is derived, never stored on the design.

- Delete ItemData.cs key 3 (Manufacturer), with a retired-key comment.
- AetherDb census now attributes a design's maker to the first product (in
  record-key order) that sells it, matching ItemManager.Brand's rule; a
  design no product sells shows "(none)".
- AetheriaStoresTests' catalog fixture moves its Manufacturer reference onto
  a FactionProductData selling the design, and FactionIsASingletonInstance
  reads it from there.
- mutation_tests.py gets a paired mutation for that fixture wiring.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-17 12:03:15 +02:00
Meta Vens
8fe09a2303 Delete the persisted-behaviors feature per operator ruling
Operator ruling (docs/item-provenance-cut.md Progress header, 2026-09-17):
delete EntityPack.PersistedBehaviors, IPersistentBehavior,
PersistentBehaviorData and MarkerPersistentBehaviorData outright rather than
keep patching around a feature with no production writer. Key(5) is retired
and left unused; other MessagePack keys are untouched.

Removes the pack/unpack code that read and wrote the field, the feature-only
test ReopenedPackKeepsPersistedBehaviors and its BarePack initializer, and the
matching "not yet reached" mutation notes in tests/mutation_tests.py.
ReopenSurvivesAGeneratedShipWithEntities is kept: it pins the reopen defect
class against a real generated ship, independent of this feature.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-17 05:44:37 +02:00
Meta Vens
c2ff543109 Fix F5: mutation_tests.py normalizes line endings and stops counting compile errors as kills
Anchors were authored with bare "\n" and this checkout is CRLF, so every
multi-line anchor matched zero times and aborted before ever mutating
anything. detect_newline() reads each file's own line ending and
translates both anchor and replacement to it before matching, counting
and writing back; the untouched bytes around the match are written
through unchanged, so the restore stays byte-exact.

run_test() now distinguishes a build failure ("Build FAILED"/"error CS"
in the dotnet test output, which never reaches "Passed!"/"Failed!") from
a genuine test failure. A build failure reports ERROR and is never
counted as a kill, since the mutation may have broken something the
target test never got a chance to exercise. Verified with a deliberate
syntax-breaking mutation, run standalone and reverted (not committed).

Added mutants for F1-F4's rules (docs/item-provenance-cut.md, Cut B, and
its F1 ruling). Two of Cut 0's named F1 mutations ("pack drops data",
"unpack ignores the lookup") are not included: no IBehavior implements
IPersistentBehavior, so Pack's filter and Restore's lookup are always
fed an empty set and mutating either body is unobservable through any
live path. Recorded as not yet reached in the script's own comment
rather than paired with a test that can't tell the difference.

Ran on this checkout (CRLF, HEAD 080d3b49) against the CultLib a0813c6
worktree: all 17 mutations behaved as expected (16 KILLED, 1 GREEN
control), run window 2026-09-17T03:18:14Z-03:20:46Z UTC.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-17 05:22:40 +02:00
Meta Vens
1e647953e5 Add mutation tests proving Cut B's new rules fail under their own mutation
tests/mutation_tests.py applies each named mutation from the cut map's
Cut B table to an exact, unique source anchor, runs the one test that
must catch it, restores the file byte-for-byte, and reports kill/survive.
A no-op control (anchor rewritten to itself) proves the read/replace/
restore path is transparent. Covers the four rules whose tests currently
pass: MissingLotIsLoud (indexer and Reachable throw on an absent lot),
MatchingHardpointsShareALot (same lot, not a fresh mint), Brand's and
Materialize's record-key order, and StatsReadTheLot (Evaluate reads the
lot's role fills, QualityForRole's fallback). All 8 mutations (7 rules
+ control) behave as expected.

MaterializedLotsSurviveSaveAndReload and CommitKeepsOnlyReachableLots
are not yet reached: they fail before any mutation is applied, blocked
by the CultLib int2 dictionary-key gap reported in the previous commit
and the landing report.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-17 04:22:29 +02:00