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.
PackageCacheAssemblyDefinitionScanTests
EditMode tests for the package-cache source of Serenity.ServiceExtensionCreator.Editor.ProjectAssemblyDefinitionIndex on its own: a
package whose define constraints keep it out of compilation never reaches the compilation pipeline, so its
assembly name is known only by reading its assembly definition from the package cache. The index is pointed
at a scratch package cache under the project's Temp folder — outside Assets, so nothing is
imported — holding a package no compiled assembly comes from.
ProjectAssemblyDefinitionIndexTests
EditMode tests for Serenity.ServiceExtensionCreator.Editor.ProjectAssemblyDefinitionIndex: Unity rejects a second assembly with a name any compiled assembly already has, wherever its assembly definition lives — so the index must know the assemblies compiled from registry packages, not only the ones under the project's own folders. The package-cache scan that catches a package kept out of compilation is covered on its own by PackageCacheAssemblyDefinitionScanTests.
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.
ServiceExtensionCreatorCollisionTests
EditMode tests for the rule that a generated extension never breaks the build of the project it lands in: a second run with the same name refuses instead of writing uniquified copies, a second extension into the same target gets its own folder so no folder ever holds two assembly definitions, an assembly name already declared anywhere in the project is refused, and no generated assembly definition ever pulls in a script the generator did not write.
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 (tests must not
pollute Addressables settings). 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).
ServiceExtensionLayoutTests
EditMode tests for PlanLayout(Input): the name the author typed is kept when the extension-point suffix is off, every name the extension carries derives from one root that is never the type name itself, each extension owns a child folder of the target, and the files a run writes are exactly the files its plan lists.
ServiceExtensionRunnerEndToEndTests
The JSON runner driven the way a command-line caller drives it: the extension-point suffix is the author's choice rather than forced, a Service-kind spec that names the wrong target field is told why, and two extensions generated one after the other into the same target folder leave a project whose assembly layout still compiles — proven on the asmdef files themselves (one per folder, unique names, every reference resolvable, no pre-existing script captured), since a headless EditMode run cannot perform the domain reload a real compile needs.
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.