File: System\Windows\Forms\DataObject_BitmapBinderTests.cs
Web Access
Project: src\src\System.Windows.Forms\tests\UnitTests\System.Windows.Forms.Tests.csproj (System.Windows.Forms.Tests)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
 
using System.Collections;
using System.Drawing;
using System.Drawing.Imaging;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;
 
namespace System.Windows.Forms.Tests;
 
public class DataObject_BitmapBinderTests
{
    private static readonly SerializationBinder s_serializationBinder
        = (SerializationBinder)Activator.CreateInstance(typeof(DataObject).Assembly.GetType("System.Windows.Forms.DataObject+BitmapBinder"));
 
    [WinFormsTheory]
    [MemberData(nameof(AllowedSerializationTypes))]
    public void BitmapBinder_BindToName_AllowedSerializationTypes(object value)
    {
        using BinaryFormatterScope formatterScope = new(enable: true);
        using (value as IDisposable)
        {
            using MemoryStream stream = new();
#pragma warning disable SYSLIB0011 // Type or member is obsolete
            BinaryFormatter formatter = new()
            {
                Binder = s_serializationBinder
            };
#pragma warning restore
 
            formatter.Serialize(stream, value);
            stream.Length.Should().BeGreaterThan(0);
        }
    }
 
    [WinFormsTheory]
    [MemberData(nameof(AllowedSerializationTypes))]
    public unsafe void BitmapBinder_BindToType_AllowedSerializationTypes(object value)
    {
        using BinaryFormatterScope formatterScope = new(enable: true);
        using (value as IDisposable)
        {
            using MemoryStream stream = new();
#pragma warning disable SYSLIB0011 // Type or member is obsolete
            // cs/binary-formatter-without-binder
            BinaryFormatter formatter = new(); // CodeQL [SM04191] This is a test. Safe because the deserialization process is performed on trusted data and the types are controlled and validated.
#pragma warning restore
            formatter.Serialize(stream, value);
            stream.Length.Should().BeGreaterThan(0);
            stream.Position = 0;
 
            formatter = new()
            {
                Binder = s_serializationBinder
            };
 
            // cs/dangerous-binary-deserialization
            object deserialized = formatter.Deserialize(stream); // CodeQL [SM03722] : Testing legacy feature. Safe use because input stream is controlled contains strings and Bitmap which is instantiated by a binder. 
            deserialized.Should().NotBeNull();
 
            if (value is not Bitmap bitmap)
            {
                deserialized.Should().BeEquivalentTo(value);
            }
            else
            {
                Bitmap deserializedBitmap = deserialized.Should().BeOfType<Bitmap>().Which;
                BitmapData originalData = bitmap.LockBits(default, ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb);
                BitmapData deserializedData = deserializedBitmap.LockBits(default, ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb);
                try
                {
                    ReadOnlySpan<byte> originalBytes = new((byte*)originalData.Scan0, originalData.Stride * originalData.Height);
                    ReadOnlySpan<byte> deserializedBytes = new((byte*)deserializedData.Scan0, deserializedData.Stride * deserializedData.Height);
                    deserializedBytes.SequenceEqual(originalBytes).Should().BeTrue();
                }
                finally
                {
                    bitmap.UnlockBits(originalData);
                    deserializedBitmap.UnlockBits(deserializedData);
                }
            }
        }
    }
 
    public static TheoryData<object> AllowedSerializationTypes => new()
    {
        "Information At your Fingertips",
        new string[] { "Hello" },
        new Bitmap(5, 5)
    };
 
    [WinFormsTheory]
    [MemberData(nameof(DisallowedSerializationTypes))]
    public void BitmapBinder_BindToName_DisallowedSerializationTypes(object value)
    {
        using BinaryFormatterScope formatterScope = new(enable: true);
        using MemoryStream stream = new();
#pragma warning disable SYSLIB0011 // Type or member is obsolete
        BinaryFormatter formatter = new()
        {
            Binder = s_serializationBinder
        };
#pragma warning restore SYSLIB0011
 
        Action action = () => formatter.Serialize(stream, value);
        action.Should().Throw<SerializationException>();
    }
 
    [WinFormsTheory]
    [MemberData(nameof(DisallowedSerializationTypes))]
    public void BitmapBinder_BindToType_DisallowedSerializationTypes(object value)
    {
        using BinaryFormatterScope formatterScope = new(enable: true);
        using MemoryStream stream = new();
#pragma warning disable SYSLIB0011 // Type or member is obsolete
        // cs/binary-formatter-without-binder
        BinaryFormatter formatter = new(); // CodeQL [SM04191] : This is a test. Safe use because the deserialization process is performed on trusted data and the types are controlled and validated.
#pragma warning restore SYSLIB0011
        formatter.Serialize(stream, value);
        stream.Length.Should().BeGreaterThan(0);
        stream.Position = 0;
 
        formatter = new()
        {
            Binder = s_serializationBinder
        };
 
        Action action = () => formatter.Deserialize(stream);
        action.Should().Throw<SerializationException>();
    }
 
    public static TheoryData<object> DisallowedSerializationTypes => new()
    {
        new List<string>() { "Hello" },
        new Hashtable() { { "Silver", "Hammer" } }
    };
}