Namespace Serenity.ServiceExtensionCreator.Tests.Editor
Classes
AggregateCatalogTests
EditMode tests for Discover(): the reflection-based aggregate discovery that every other Service Extension Creator piece relies on. Asserts against the live project catalog rather than a fake one, since discovery is inherently a scan over loaded assemblies.
AlreadyVirtualMethodsVirtualizerFixture
Fixture for the already-subclass-friendly path: every public method is virtual (a patchable property remains, but property-only patches are pointless for eligibility and must not be written).
AsmdefReferenceWriterTests
EditMode tests for AsmdefReferenceWriter: assembly-name resolution, required-reference sets per layer, and the brand-new-asmdef writer. Every mutation happens against a temp folder created for the test — a real project asmdef is never edited, since AsmdefReferenceWriter no longer mutates existing asmdefs at all (every generated layer owns its own folder and asmdef).
ExtensionPointCatalogTests
EditMode tests for Discover(): the reflection-based discovery of
every extension point kind beyond the I{X}Service aggregates AggregateCatalog
already covers. Asserts against the live project catalog, since discovery is inherently a scan over
loaded assemblies.
ExtensionPointGenerationTests
EditMode tests for Create(Input) across the Store/Repository/Gateway/Factory/Installer
extension point kinds (Catalog V2). Mirrors ServiceExtensionCreatorGenerationTests'
conventions: every input uses RegisterAsAddressables = false so a test run never touches the
project's real Addressables settings, and every test targets its own uniquely-named subfolder.
ExtensionPointValidationTests
EditMode tests for Validate(Input) across the Store/Repository/Gateway/Factory/Installer
extension point kinds (Catalog V2). Mirrors ServiceExtensionCreatorValidationTests'
conventions: a single shared temp folder for the whole fixture, since Validate never writes into it —
it only accepts or rejects the target folder via SerenityProjectOutputFolderRules.
MetaFileRaceGuardedFixture
Base fixture that suppresses Unity's log-as-failure handling for the whole fixture run. Rapid create/delete of a fixture's temp folders across many tests occasionally races an external file watcher (AV/cloud-sync) still holding a just-deleted folder's .meta file, and because AssetDatabase's underlying file I/O is not guaranteed synchronous with the C# call that triggered it, the resulting console error can surface on a later frame than the operation that caused it — suppressing per-test would leave a gap between one test's TearDown and the next test's SetUp where the delayed log lands. Real assertions in derived fixtures run normally; only the log-as-failure path Unity's test runner applies to unexpected console errors is suppressed.
PropertiesOnlyVirtualizerFixture
Fixture for the methods-only eligibility gate: patchable properties, zero methods — can never become subclass-eligible, so TryMakeSubclassFriendly(Type, out string) must refuse.
ProtectedVirtualOnlyFixture
Fixture whose ONLY virtual method is protected — proves the eligibility rule counts protected
virtuals (see TryMakeSubclassFriendly_ClassWhoseOnlyVirtualMethodIsProtected_ReportsAlreadySubclassFriendly).
SealedWithOverrideVirtualizerFixture
Reproduces the reported bug: a sealed class (like BossDefeatedAction) whose only public
method is an inherited override. Its override is virtual and not patchable, so the pre-fix code fell
through to AggregateCatalog.HasVirtualMembers and wrongly reported "already subclass-friendly" —
C# forbids inheriting a sealed class regardless of how many virtual members it exposes.
ServiceExtensionCreatorGenerationTests
EditMode tests for Create(Input): actual file/asset generation in a temp folder, for the
layered aggregate layout ({CodeLayer}/Services, Installation/Installers,
Installation/Settings, Tests, root README.md) across the three
ServiceExtensionCreator.Style shapes, and the try/catch rollback contract on failure. Every input uses
RegisterAsAddressables = false and AppendToPipelineProfile = false so a test run never
touches the project's real Addressables settings or initialization pipeline profile (project rule —
see CLAUDE.md's Addressables section). Every test targets its own uniquely-named subfolder of
Serenity.ServiceExtensionCreator.Tests.Editor.ServiceExtensionCreatorGenerationTests.TempFolder (via Serenity.ServiceExtensionCreator.Tests.Editor.ServiceExtensionCreatorGenerationTests.CreateTargetSubfolder(System.String)) rather than Serenity.ServiceExtensionCreator.Tests.Editor.ServiceExtensionCreatorGenerationTests.TempFolder
itself — generating the SAME nested layer folder names ("Application", "Installation", "Tests")
directly under a shared parent that gets deleted and recreated between every test risks a stale
AssetDatabase meta-file cache from the previous test's teardown colliding with the next test's setup.
ServiceExtensionCreatorValidationTests
EditMode tests for Validate(Input) and its pure preview helpers
(ComposeServiceTypeName(Input) / ComposeSanitizedExtensionName(Input)). Aliased
as Creator because the class name collides with its own namespace segment
(Serenity.ServiceExtensionCreator.Editor.ServiceExtensionCreator). Every case that needs a real
aggregate uses "Combo" (gameplay, virtualized, no InterfaceAdapters layer) from the live
AggregateCatalog. Validate only reads the target folder (via
Serenity.Global.Infrastructure.Editor.SerenityProjectOutputFolderRules.IsAcceptableOutputFolder(System.String), which accepts a
well-formed folder whether or not it exists yet) and never writes into it, so one folder is created
for the whole fixture instead of per-test — nothing here ever mutates it, and a shared folder means
no repeated create/delete churn that could race an external file watcher (AV/cloud-sync).
ServiceExtensionRunnerTests
EditMode tests for CreateFromJson(string): spec parsing, enum-error
aggregation, the JSON report round trip, and the Catalog V2 extensionPointKind/extensionPointName
spec fields (including their back-compat coexistence with the legacy aggregate field).
ServiceExtensionSpec is internal to the runner's assembly, so specs are written here as plain JSON
text — exactly what a CLI caller would produce.
VirtualBaseForSealedVirtualizerFixture
Base carrying the one virtual method SealedWithOverrideVirtualizerFixture overrides
— a sealed class's own override still reflects as IsVirtual == true, which is exactly what made
the pre-fix code mistake it for "already subclass-friendly".
VirtualizationEngineTests
EditMode tests for Rewrite(string, IReadOnlyList<MemberPatch>) (pure text, no IO/AssetDatabase) and CollectPatchableMembers(Type) (pure reflection over a fixture type declared below — member enumeration never goes through discovery, so a Tests-assembly fixture is a faithful subject). The engine's contract under test: anchor precisely, skip already-virtual/override/static declarations, and refuse the WHOLE rewrite on any mismatch — never partial output.
VirtualizerEnumerationFixture
Reflection subject for CollectPatchableMembers(Type): one member per enumeration rule — plain method, overload pair, already-virtual method, static method, plain property, virtual property, static property, indexer and event. Living in the Tests assembly is fine here: member enumeration is pure reflection and never goes through the (test-assembly-excluding) discovery.