logo SERENITY
Game Systems Foundation
Search Results for

    Show / Hide Table of Contents

    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 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).

    Inheritance
    object
    MetaFileRaceGuardedFixture
    ServiceExtensionCreatorValidationTests
    Inherited Members
    MetaFileRaceGuardedFixture.SuppressFailingLogMessagesForFixture()
    MetaFileRaceGuardedFixture.RestoreFailingLogMessages()
    MetaFileRaceGuardedFixture.SuppressFailingLogMessagesForTest()
    object.ToString()
    object.Equals(object)
    object.Equals(object, object)
    object.ReferenceEquals(object, object)
    object.GetHashCode()
    object.GetType()
    object.MemberwiseClone()
    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_PlainServiceStyle_SanitizedNameAlreadyEndsInAggregateService_DoesNotDoubleTheSuffix()

    Same doubling guard, for the plain (non-Subclass) Service composition ({Name}{Aggregate}Service) — a sanitized name already ending in "{Aggregate}Service" must not double either.

    Declaration
    public void ComposeTypeName_PlainServiceStyle_SanitizedNameAlreadyEndsInAggregateService_DoesNotDoubleTheSuffix()

    ComposeTypeName_SanitizedNameAlreadyEndsInConcreteBaseName_DoesNotDoubleTheSuffix()

    Regression test for the reported doubling bug: when the user-typed extension name already ends in the chosen concrete base's type name (e.g. "CustomAssetPrefetcherService" against a base literally named "AssetPrefetcherService"), the composed name must not double the suffix into "CustomAssetPrefetcherServiceAssetPrefetcherService".

    Declaration
    public void ComposeTypeName_SanitizedNameAlreadyEndsInConcreteBaseName_DoesNotDoubleTheSuffix()

    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_OutputFolderMissing_IsAccepted()

    Declaration
    public void Validate_OutputFolderMissing_IsAccepted()

    Validate_RejectsEmptyName()

    Declaration
    public void Validate_RejectsEmptyName()

    Validate_RejectsExcludedAggregate()

    Declaration
    public void Validate_RejectsExcludedAggregate()

    Validate_RejectsFolderOutsideAssets()

    Declaration
    public void Validate_RejectsFolderOutsideAssets()

    Validate_RejectsInfrastructureForAggregateWithoutVirtualMembers()

    Declaration
    public void Validate_RejectsInfrastructureForAggregateWithoutVirtualMembers()

    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()
    In this article
    © 2026 Serenity. All Rights Reserved