Class UpdateInPlaceRoundTripContract
Reusable EditMode contract for the rule that an editor tool managing an existing asset owns everything
that asset already has: confirming an update-in-place wizard run with ZERO edits must leave every
already-set field on every asset it touches
untouched — name, hide flags, and every serialized field alike. Guards against a wizard's own
SeedFromTarget seeding only a handful of fields and
silently reverting everything else to its static template default the moment Confirm is pressed.
A wizard registers by implementing UpdateInPlaceRoundTripContract.IAdapter<TAsset> — seed from a SET of existing assets, confirm with no further edits — a single asset is the trivial case of a one-element set, for the multi-asset adopters (Wave Set, Player Input, Character) coming in later slices.
Built entirely on the existing UnitySerializedFieldReflection / UnitySerializedFieldSeeds /
UnitySerializedFieldAssertions trio (Serenity.Tests.Shared) rather than a new
UnityEditor.SerializedObject-based walker of its own — the same machinery
SystemConfigurationSettingsCreatorTests already exercises for its own field-walk regression test,
so an Object-reference field is mutated (via MutateEveryFieldToNonDefault(Object, Object, string)'s
alternateObjectReference) and compared by asset identity, never silently skipped.
Inherited Members
Namespace: Serenity.Tests.Shared.Editor
Assembly: Serenity.Tests.Shared.Editor.dll
Syntax
public static class UpdateInPlaceRoundTripContract
Methods
AssertRoundTripsUnchanged<TAsset>(IAdapter<TAsset>, IReadOnlyList<TAsset>, IReadOnlyCollection<string>, IReadOnlyCollection<string>)
Runs the contract: snapshots every asset in existingAssets (name, hide flags,
every serialized field), seeds and confirms through adapter with zero edits, then
asserts every one of them round-tripped unchanged.
Declaration
public static void AssertRoundTripsUnchanged<TAsset>(UpdateInPlaceRoundTripContract.IAdapter<TAsset> adapter, IReadOnlyList<TAsset> existingAssets, IReadOnlyCollection<string> actualUnmutatedFieldNames, IReadOnlyCollection<string> expectedUnmutatedFieldNames) where TAsset : Object
Parameters
| Type | Name | Description |
|---|---|---|
| UpdateInPlaceRoundTripContract.IAdapter<TAsset> | adapter | The wizard-specific seed/confirm seam. |
| IReadOnlyList<TAsset> | existingAssets | The already-authored assets the run must leave untouched — built with MutateEveryFieldToNonDefault(Object, Object, string) so every field carries a value distinct from a freshly created asset's own defaults. |
| IReadOnlyCollection<string> | actualUnmutatedFieldNames | The union of every path MutateEveryFieldToNonDefault(Object, Object, string)
reported as unmutated while building |
| IReadOnlyCollection<string> | expectedUnmutatedFieldNames | What the test deliberately acknowledges as fields the
fixture builder cannot mutate generically (an Object-reference field with no compatible alternate, a
composite kind deeper than Serenity.Tests.Shared.Editor.UpdateInPlaceRoundTripContract.MaxCompositeDepth). Must match |
Type Parameters
| Name | Description |
|---|---|
| TAsset |
MutateEveryFieldToNonDefault(Object, Object, string)
Sets every field UnitySerializedFieldReflection can see on asset to a
value distinct from what it currently holds — the "existing asset whose every field was set to a
non-default value" fixture AssertRoundTripsUnchanged<TAsset>(IAdapter<TAsset>, IReadOnlyList<TAsset>, IReadOnlyCollection<string>, IReadOnlyCollection<string>) needs. Scalar and enum
fields are seeded via SeedValueDistinctFrom(FieldInfo, object, string, Object); an Object-reference
field (or an array of one) is seeded when alternateObjectReference is assignable to
it; a nested struct field, or an array of one (e.g. a Sync Map row), is walked the same way one level
down. Returns the dotted paths of every field this could not mutate — an Object-reference field with no
compatible alternate, or a composite nested past Serenity.Tests.Shared.Editor.UpdateInPlaceRoundTripContract.MaxCompositeDepth — so a caller's own
AssertRoundTripsUnchanged<TAsset>(IAdapter<TAsset>, IReadOnlyList<TAsset>, IReadOnlyCollection<string>, IReadOnlyCollection<string>) call must acknowledge them explicitly, never silently.
Declaration
public static IReadOnlyList<string> MutateEveryFieldToNonDefault(Object asset, Object alternateObjectReference = null, string seedSalt = "")
Parameters
| Type | Name | Description |
|---|---|---|
| Object | asset | The asset to mutate. Marked dirty; the caller saves. |
| Object | alternateObjectReference | An asset (or in-memory instance) whose type mutates an Object-reference field with a real value instead of leaving it reported as unmutated. |
| string | seedSalt | Distinguishes the SEED TEXT (never the reported field paths) between two calls that mutate different assets of the SAME type in the same test (e.g. two sibling wave configs) — without it, every string field's seed text is derived from the field's own dotted path alone, so two same-typed assets would seed an Id-shaped field to the exact same string and collide on the by-Id lookup the round trip depends on. Empty (the default) matches every other adopter, which mutates exactly one asset per type. |
Returns
| Type | Description |
|---|---|
| IReadOnlyList<string> |