// Copyright (c) Six Labors. // Licensed under the Six Labors Split License. using System.Numerics; using SixLabors.ImageSharp.PixelFormats; namespace SixLabors.ImageSharp.PublicApi.Tests; /// /// Verifies that representation-aware pixel operations can be implemented outside the ImageSharp assembly. /// public class PixelOperationsExtensibilityTests { /// /// Verifies that an external subclass can override and invoke every representation-aware hook. /// [Fact] public void PixelOperationsExposesAllRepresentationHooksToExternalSubclasses() { ExternalRgba32PixelOperations operations = new(); operations.InvokeRepresentationHooks(); Assert.Equal(RepresentationHooks.All, operations.InvokedHooks); } /// /// Verifies that an external subclass can override and invoke every representation-aware hook. /// [Fact] public void AssociatedAlphaPixelOperationsExposesAllRepresentationHooksToExternalSubclasses() { ExternalRgba32PPixelOperations operations = new(); operations.InvokeRepresentationHooks(); Assert.Equal(RepresentationHooks.All, operations.InvokedHooks); } [Flags] private enum RepresentationHooks { None = 0, ToUnassociatedVector4 = 1 << 0, ToAssociatedVector4 = 1 << 1, ToUnassociatedScaledVector4 = 1 << 2, ToAssociatedScaledVector4 = 1 << 3, FromUnassociatedVector4Destructive = 1 << 4, FromAssociatedVector4Destructive = 1 << 5, FromUnassociatedScaledVector4Destructive = 1 << 6, FromAssociatedScaledVector4Destructive = 1 << 7, All = ToUnassociatedVector4 | ToAssociatedVector4 | ToUnassociatedScaledVector4 | ToAssociatedScaledVector4 | FromUnassociatedVector4Destructive | FromAssociatedVector4Destructive | FromUnassociatedScaledVector4Destructive | FromAssociatedScaledVector4Destructive } /// /// Exercises the representation-aware hooks inherited directly from . /// private sealed class ExternalRgba32PixelOperations : PixelOperations { /// /// Gets the hooks invoked through this external subclass. /// public RepresentationHooks InvokedHooks { get; private set; } /// /// Invokes every representation-aware operation exposed to derived classes. /// public void InvokeRepresentationHooks() { // Empty spans isolate accessibility and virtual dispatch; conversion behavior is covered by the pixel-operation test suite. this.ToUnassociatedVector4(Configuration.Default, ReadOnlySpan.Empty, Span.Empty); this.ToAssociatedVector4(Configuration.Default, ReadOnlySpan.Empty, Span.Empty); this.ToUnassociatedScaledVector4(Configuration.Default, ReadOnlySpan.Empty, Span.Empty); this.ToAssociatedScaledVector4(Configuration.Default, ReadOnlySpan.Empty, Span.Empty); this.FromUnassociatedVector4Destructive(Configuration.Default, Span.Empty, Span.Empty); this.FromAssociatedVector4Destructive(Configuration.Default, Span.Empty, Span.Empty); this.FromUnassociatedScaledVector4Destructive(Configuration.Default, Span.Empty, Span.Empty); this.FromAssociatedScaledVector4Destructive(Configuration.Default, Span.Empty, Span.Empty); } /// protected override void ToUnassociatedVector4(Configuration configuration, ReadOnlySpan source, Span destination) => this.InvokedHooks |= RepresentationHooks.ToUnassociatedVector4; /// protected override void ToAssociatedVector4(Configuration configuration, ReadOnlySpan source, Span destination) => this.InvokedHooks |= RepresentationHooks.ToAssociatedVector4; /// protected override void ToUnassociatedScaledVector4(Configuration configuration, ReadOnlySpan source, Span destination) => this.InvokedHooks |= RepresentationHooks.ToUnassociatedScaledVector4; /// protected override void ToAssociatedScaledVector4(Configuration configuration, ReadOnlySpan source, Span destination) => this.InvokedHooks |= RepresentationHooks.ToAssociatedScaledVector4; /// protected override void FromUnassociatedVector4Destructive(Configuration configuration, Span source, Span destination) => this.InvokedHooks |= RepresentationHooks.FromUnassociatedVector4Destructive; /// protected override void FromAssociatedVector4Destructive(Configuration configuration, Span source, Span destination) => this.InvokedHooks |= RepresentationHooks.FromAssociatedVector4Destructive; /// protected override void FromUnassociatedScaledVector4Destructive(Configuration configuration, Span source, Span destination) => this.InvokedHooks |= RepresentationHooks.FromUnassociatedScaledVector4Destructive; /// protected override void FromAssociatedScaledVector4Destructive(Configuration configuration, Span source, Span destination) => this.InvokedHooks |= RepresentationHooks.FromAssociatedScaledVector4Destructive; } /// /// Exercises the representation-aware hooks inherited through . /// private sealed class ExternalRgba32PPixelOperations : AssociatedAlphaPixelOperations { /// /// Gets the hooks invoked through this external subclass. /// public RepresentationHooks InvokedHooks { get; private set; } /// /// Invokes every representation-aware operation exposed to derived classes. /// public void InvokeRepresentationHooks() { // Empty spans isolate accessibility and virtual dispatch; conversion behavior is covered by the pixel-operation test suite. this.ToUnassociatedVector4(Configuration.Default, ReadOnlySpan.Empty, Span.Empty); this.ToAssociatedVector4(Configuration.Default, ReadOnlySpan.Empty, Span.Empty); this.ToUnassociatedScaledVector4(Configuration.Default, ReadOnlySpan.Empty, Span.Empty); this.ToAssociatedScaledVector4(Configuration.Default, ReadOnlySpan.Empty, Span.Empty); this.FromUnassociatedVector4Destructive(Configuration.Default, Span.Empty, Span.Empty); this.FromAssociatedVector4Destructive(Configuration.Default, Span.Empty, Span.Empty); this.FromUnassociatedScaledVector4Destructive(Configuration.Default, Span.Empty, Span.Empty); this.FromAssociatedScaledVector4Destructive(Configuration.Default, Span.Empty, Span.Empty); } /// protected override void ToUnassociatedVector4(Configuration configuration, ReadOnlySpan source, Span destination) => this.InvokedHooks |= RepresentationHooks.ToUnassociatedVector4; /// protected override void ToAssociatedVector4(Configuration configuration, ReadOnlySpan source, Span destination) => this.InvokedHooks |= RepresentationHooks.ToAssociatedVector4; /// protected override void ToUnassociatedScaledVector4(Configuration configuration, ReadOnlySpan source, Span destination) => this.InvokedHooks |= RepresentationHooks.ToUnassociatedScaledVector4; /// protected override void ToAssociatedScaledVector4(Configuration configuration, ReadOnlySpan source, Span destination) => this.InvokedHooks |= RepresentationHooks.ToAssociatedScaledVector4; /// protected override void FromUnassociatedVector4Destructive(Configuration configuration, Span source, Span destination) => this.InvokedHooks |= RepresentationHooks.FromUnassociatedVector4Destructive; /// protected override void FromAssociatedVector4Destructive(Configuration configuration, Span source, Span destination) => this.InvokedHooks |= RepresentationHooks.FromAssociatedVector4Destructive; /// protected override void FromUnassociatedScaledVector4Destructive(Configuration configuration, Span source, Span destination) => this.InvokedHooks |= RepresentationHooks.FromUnassociatedScaledVector4Destructive; /// protected override void FromAssociatedScaledVector4Destructive(Configuration configuration, Span source, Span destination) => this.InvokedHooks |= RepresentationHooks.FromAssociatedScaledVector4Destructive; } }