Class 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
AssetDatabase.IsValidFolder) 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).
Inherited Members
Namespace: Serenity.ServiceExtensionCreator.Tests.Editor
Assembly: Serenity.ServiceExtensionCreator.Tests.Editor.dll
Syntax
public class ServiceExtensionCreatorValidationTests : MetaFileRaceGuardedFixture
Constructors
ServiceExtensionCreatorValidationTests()
Declaration
public ServiceExtensionCreatorValidationTests()
Methods
ComposeCodeLayerName_InfrastructureFresh_ResolvesToInfrastructureRegardlessOfBaseLayer()
The generated class for InfrastructureFresh lives under Infrastructure, exactly like InfrastructureSubclass — ComposeCodeLayerName(Input) is style-driven, not BaseLayer-driven, for the two Infrastructure styles.
Declaration
public void ComposeCodeLayerName_InfrastructureFresh_ResolvesToInfrastructureRegardlessOfBaseLayer()
ComposeServiceTypeName_BusinessStyle_DoesNotStripUnityPrefix()
Declaration
public void ComposeServiceTypeName_BusinessStyle_DoesNotStripUnityPrefix()
ComposeServiceTypeName_InfrastructureStyle_StripsSingleLeadingUnityPrefix()
Declaration
public void ComposeServiceTypeName_InfrastructureStyle_StripsSingleLeadingUnityPrefix()
ComposeServiceTypeName_NullInput_ReturnsEmpty()
Declaration
public void ComposeServiceTypeName_NullInput_ReturnsEmpty()
ComposeServiceTypeName_SubclassOfNonUnityBase_KeepsTheUserUnityPrefix()
The double-prefix guard only strips a leading "Unity" when the composed name injects one of its
own — Persistence's only eligible base is the non-Unity-prefixed PersistenceService, so a
user extension name starting with "Unity" must survive intact.
Declaration
public void ComposeServiceTypeName_SubclassOfNonUnityBase_KeepsTheUserUnityPrefix()
ComposeServiceTypeName_SubclassWithEmptyBaseName_ResolvesTheCanonicalBase()
An empty SubclassBaseTypeName picks the canonical/first
eligible base — the composed name stays exactly V1's {Name}Unity{Aggregate}Service shape.
Declaration
public void ComposeServiceTypeName_SubclassWithEmptyBaseName_ResolvesTheCanonicalBase()
ComposeTypeName_SubclassStyleWithNonCanonicalBase_ComposesNameFromTheChosenBase()
The Subclass type name is composed from the ACTUAL chosen base's name, not an invented
Unity{Aggregate}Service — a non-canonical base like the fixture CustomComboBase
composes {Name}CustomComboBase. Constructed-descriptor test: no production aggregate has a
non-canonical eligible base yet, so the descriptor is built directly (ComposeTypeName is
pure and never reads the catalog).
Declaration
public void ComposeTypeName_SubclassStyleWithNonCanonicalBase_ComposesNameFromTheChosenBase()
OneTimeSetUp()
Declaration
public void OneTimeSetUp()
OneTimeTearDown()
Declaration
public void OneTimeTearDown()
ValidateSubclassBaseSelection_SimpleNameSharedByTwoBases_DemandsTheFullName()
The base-selection resolver's ambiguity rule, pinned at the unit level with a constructed list — two fixture types sharing a simple name cannot both be matched by it, so the resolver demands the full name instead of first-picking.
Declaration
public void ValidateSubclassBaseSelection_SimpleNameSharedByTwoBases_DemandsTheFullName()
Validate_AllowsBusinessDecoratorStyle()
Declaration
public void Validate_AllowsBusinessDecoratorStyle()
Validate_AllowsBusinessFreshForPersistence()
Business styles do not need a concrete Unity service, so Persistence must remain usable.
Declaration
public void Validate_AllowsBusinessFreshForPersistence()
Validate_AllowsEmptyNamespace()
Declaration
public void Validate_AllowsEmptyNamespace()
Validate_AllowsInfrastructureFreshForAggregateWithoutVirtualMembers()
InfrastructureFresh is never gated on IsInfrastructureAvailable(AggregateDescriptor, out string) — unlike InfrastructureSubclass (see Validate_RejectsInfrastructureForAggregateWithoutVirtualMembers()), it must still validate cleanly for an aggregate with no virtual members at all.
Declaration
public void Validate_AllowsInfrastructureFreshForAggregateWithoutVirtualMembers()
Validate_AllowsInfrastructureFreshForPersistence()
InfrastructureFresh needs no concrete Unity service at all (unlike
InfrastructureSubclass) — Persistence (no UnityPersistenceService,
see Discover_Persistence_IsCoreInstalledWithNoConcreteUnityService())
must still validate cleanly under it.
Declaration
public void Validate_AllowsInfrastructureFreshForPersistence()
Validate_AllowsInfrastructureSubclassForPersistenceViaTheBusinessPersistenceService()
Persistence has no UnityPersistenceService, but the public business PersistenceService
implements IPersistenceService with five public virtual operations — under the
any-eligible-base rule it IS a valid subclass base, so the Subclass style is now available for
Persistence (it was blocked when only the canonical Unity{X}Service counted). The composed
type name follows the actual base: {Name}PersistenceService, no "Unity" prefix invented.
Declaration
public void Validate_AllowsInfrastructureSubclassForPersistenceViaTheBusinessPersistenceService()
Validate_AllowsInfrastructureSubclassForVirtualizedAggregate()
Declaration
public void Validate_AllowsInfrastructureSubclassForVirtualizedAggregate()
Validate_AllowsSubclassWithTheCanonicalBaseNamedExplicitly()
Declaration
public void Validate_AllowsSubclassWithTheCanonicalBaseNamedExplicitly()
Validate_AllowsValidDottedNamespace()
Declaration
public void Validate_AllowsValidDottedNamespace()
Validate_RejectsEmptyName()
Declaration
public void Validate_RejectsEmptyName()
Validate_RejectsExcludedAggregate()
Declaration
public void Validate_RejectsExcludedAggregate()
Validate_RejectsInfrastructureForAggregateWithoutVirtualMembers()
Declaration
public void Validate_RejectsInfrastructureForAggregateWithoutVirtualMembers()
Validate_RejectsInvalidFolder()
Declaration
public void Validate_RejectsInvalidFolder()
Validate_RejectsNamespaceInjectionPayload()
Declaration
public void Validate_RejectsNamespaceInjectionPayload()
Validate_RejectsNamespaceSegmentStartingWithDigit()
Declaration
public void Validate_RejectsNamespaceSegmentStartingWithDigit()
Validate_RejectsNamespaceWithLeadingDot()
Declaration
public void Validate_RejectsNamespaceWithLeadingDot()
Validate_RejectsNamespaceWithTrailingDot()
Declaration
public void Validate_RejectsNamespaceWithTrailingDot()
Validate_RejectsNullInput()
Declaration
public void Validate_RejectsNullInput()
Validate_RejectsTypeNameCollisionWithExistingRealType()
Validate's collision check compares against the layered namespace it will actually generate into
({RootNamespace}.{CodeLayer}.Services), not the raw NamespaceOverride — so this test
collides against a fixture type declared right below, in this same file, whose namespace was chosen
to be exactly the composed namespace for the input below, rather than depending on a real Serenity
aggregate's namespace shape (which no longer has any reason to match the generated layout).
Declaration
public void Validate_RejectsTypeNameCollisionWithExistingRealType()
Validate_RejectsUnknownAggregate()
Declaration
public void Validate_RejectsUnknownAggregate()
Validate_RejectsUnknownSubclassBaseNameListingTheAvailableBases()
Declaration
public void Validate_RejectsUnknownSubclassBaseNameListingTheAvailableBases()