// Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. using System; using System.Buffers; using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.PixelFormats; using SixLabors.Memory; using Xunit; // ReSharper disable InconsistentNaming namespace SixLabors.ImageSharp.Tests.Memory { public class MemorySourceTests { public class Construction { [Theory] [InlineData(false)] [InlineData(true)] public void InitializeAsOwner(bool isInternalMemorySource) { var data = new Rgba32[21]; var mmg = new TestMemoryManager(data); var a = new MemorySource(mmg, isInternalMemorySource); Assert.Equal(mmg, a.MemoryOwner); Assert.Equal(mmg.Memory, a.Memory); Assert.Equal(isInternalMemorySource, a.HasSwappableContents); } [Fact] public void InitializeAsObserver_MemoryOwner_IsNull() { var data = new Rgba32[21]; var mmg = new TestMemoryManager(data); var a = new MemorySource(mmg.Memory); Assert.Null(a.MemoryOwner); Assert.Equal(mmg.Memory, a.Memory); Assert.False(a.HasSwappableContents); } } public class Dispose { [Theory] [InlineData(false)] [InlineData(true)] public void WhenOwnershipIsTransferred_ShouldDisposeMemoryOwner(bool isInternalMemorySource) { var mmg = new TestMemoryManager(new int[10]); var bmg = new MemorySource(mmg, isInternalMemorySource); bmg.Dispose(); Assert.True(mmg.IsDisposed); } [Fact] public void WhenMemoryObserver_ShouldNotDisposeAnything() { var mmg = new TestMemoryManager(new int[10]); var bmg = new MemorySource(mmg.Memory); bmg.Dispose(); Assert.False(mmg.IsDisposed); } } public class SwapOrCopyContent { private MemoryAllocator MemoryAllocator { get; } = new TestMemoryAllocator(); private MemorySource AllocateMemorySource(int length, AllocationOptions options = AllocationOptions.None) where T : struct { IMemoryOwner owner = this.MemoryAllocator.Allocate(length, options); return new MemorySource(owner, true); } [Fact] public void WhenBothAreMemoryOwners_ShouldSwap() { MemorySource a = this.AllocateMemorySource(13); MemorySource b = this.AllocateMemorySource(17); IMemoryOwner aa = a.MemoryOwner; IMemoryOwner bb = b.MemoryOwner; Memory aaa = a.Memory; Memory bbb = b.Memory; MemorySource.SwapOrCopyContent(ref a, ref b); Assert.Equal(bb, a.MemoryOwner); Assert.Equal(aa, b.MemoryOwner); Assert.Equal(bbb, a.Memory); Assert.Equal(aaa, b.Memory); Assert.NotEqual(a.Memory, b.Memory); } [Theory] [InlineData(false, false)] [InlineData(true, true)] [InlineData(true, false)] public void WhenDestIsNotMemoryOwner_SameSize_ShouldCopy(bool sourceIsOwner, bool isInternalMemorySource) { var data = new Rgba32[21]; var color = new Rgba32(1, 2, 3, 4); var destOwner = new TestMemoryManager(data); var dest = new MemorySource(destOwner.Memory); IMemoryOwner sourceOwner = this.MemoryAllocator.Allocate(21); MemorySource source = sourceIsOwner ? new MemorySource(sourceOwner, isInternalMemorySource) : new MemorySource(sourceOwner.Memory); sourceOwner.Memory.Span[10] = color; // Act: MemorySource.SwapOrCopyContent(ref dest, ref source); // Assert: Assert.Equal(color, dest.Memory.Span[10]); Assert.NotEqual(sourceOwner, dest.MemoryOwner); Assert.NotEqual(destOwner, source.MemoryOwner); } [Theory] [InlineData(false)] [InlineData(true)] public void WhenDestIsNotMemoryOwner_DifferentSize_Throws(bool sourceIsOwner) { var data = new Rgba32[21]; var color = new Rgba32(1, 2, 3, 4); var destOwner = new TestMemoryManager(data); var dest = new MemorySource(destOwner.Memory); IMemoryOwner sourceOwner = this.MemoryAllocator.Allocate(22); MemorySource source = sourceIsOwner ? new MemorySource(sourceOwner, true) : new MemorySource(sourceOwner.Memory); sourceOwner.Memory.Span[10] = color; // Act: Assert.ThrowsAny( () => MemorySource.SwapOrCopyContent(ref dest, ref source) ); Assert.Equal(color, source.Memory.Span[10]); Assert.NotEqual(color, dest.Memory.Span[10]); } } } }