// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

#nullable disable

using System.Drawing;
using System.Reflection;

namespace System.Windows.Forms.Tests;

// NB: doesn't require thread affinity
public class CursorsTests
{
    public static IEnumerable<object[]> Cursors_TestData()
    {
        // Identity function to avoid constant casting
        static Func<Cursor> I(Func<Cursor> factory) => factory;

        yield return new object[] { I(() => Cursors.AppStarting) };
        yield return new object[] { I(() => Cursors.Arrow) };
        yield return new object[] { I(() => Cursors.Cross) };
        yield return new object[] { I(() => Cursors.Default) };
        yield return new object[] { I(() => Cursors.Hand) };
        yield return new object[] { I(() => Cursors.Help) };
        yield return new object[] { I(() => Cursors.HSplit) };
        yield return new object[] { I(() => Cursors.IBeam) };
        yield return new object[] { I(() => Cursors.No) };
        yield return new object[] { I(() => Cursors.NoMove2D) };
        yield return new object[] { I(() => Cursors.NoMoveHoriz) };
        yield return new object[] { I(() => Cursors.NoMoveVert) };
        yield return new object[] { I(() => Cursors.PanEast) };
        yield return new object[] { I(() => Cursors.PanNE) };
        yield return new object[] { I(() => Cursors.PanNorth) };
        yield return new object[] { I(() => Cursors.PanNW) };
        yield return new object[] { I(() => Cursors.PanSE) };
        yield return new object[] { I(() => Cursors.PanSouth) };
        yield return new object[] { I(() => Cursors.PanSW) };
        yield return new object[] { I(() => Cursors.PanWest) };
        yield return new object[] { I(() => Cursors.SizeAll) };
        yield return new object[] { I(() => Cursors.SizeNESW) };
        yield return new object[] { I(() => Cursors.SizeNS) };
        yield return new object[] { I(() => Cursors.SizeNWSE) };
        yield return new object[] { I(() => Cursors.SizeWE) };
        yield return new object[] { I(() => Cursors.UpArrow) };
        yield return new object[] { I(() => Cursors.VSplit) };
        yield return new object[] { I(() => Cursors.WaitCursor) };
    }

    [Theory]
    [MemberData(nameof(Cursors_TestData))]
    public void Cursors_KnownCursor_Get_ReturnsExpected(Func<Cursor> getCursor)
    {
        Cursor cursor = getCursor();
        Assert.NotEqual(IntPtr.Zero, cursor.Handle);
        Point hotSpot = cursor.HotSpot;
        Assert.True(hotSpot.X >= 0 && hotSpot.X <= cursor.Size.Width);
        Assert.True(hotSpot.Y >= 0 && hotSpot.Y <= cursor.Size.Height);
        Assert.True(cursor.Size == new Size(32, 32) || cursor.Size == new Size(64, 64));
        Assert.Null(cursor.Tag);

        // Cursor statics aren't thread safe. While rare, this can and does fail.
        // Assert.Same(cursor, getCursor());
    }

    [Fact]
    public void Cursors_Properties_Get_NotNull()
    {
        foreach (var property in typeof(Cursors).GetProperties(BindingFlags.Static | BindingFlags.Public))
        {
            object[] tempIndex = null;
            Assert.NotNull((Cursor)property.GetValue(null, tempIndex));
        }
    }

    [Theory]
    [MemberData(nameof(Cursors_TestData))]
    public void Cursors_ToString_KnownCursor_ReturnsExpected(Func<Cursor> getCursor)
    {
        // Regression test for https://github.com/dotnet/winforms/issues/9464
        Cursor cursor = getCursor();
        Assert.NotEqual("[Cursor: System.Windows.Forms.Cursor]", cursor.ToString());
    }
}
