using NUnit.Framework;

namespace e_suite.API.Common.UnitTests.helper;

public static class ExceptionTester
{
    public static void PerformTestSuite(Type exceptionUnderTest)
    {
        Assert.That(exceptionUnderTest, Is.Not.Null);
        Assert.That(InheritsFrom<Exception>(exceptionUnderTest), Is.True);
        Assert.That(CreateInstanceWithNoMessage(exceptionUnderTest), Is.True);
        Assert.That(CreateInstanceWithMessage(exceptionUnderTest), Is.True);
        Assert.That(CreateInstanceWithMessageAndInnerException(exceptionUnderTest), Is.True);
    }

    private static bool CreateInstanceWithMessageAndInnerException(Type exceptionUnderTest)
    {
        var innerException = new Exception("InnerException");

        var newInstance = (Exception)Activator.CreateInstance(exceptionUnderTest, "Test", innerException)!;

        Assert.That(newInstance, Is.Not.Null);
        Assert.That(newInstance?.InnerException, Is.EqualTo(innerException));

        return newInstance?.GetType() == exceptionUnderTest;
    }

    private static bool CreateInstanceWithMessage(Type exceptionUnderTest)
    {
        var newInstance = Activator.CreateInstance(exceptionUnderTest, "Test");
        Assert.That(newInstance, Is.Not.Null);
        return newInstance?.GetType() == exceptionUnderTest;
    }

    private static bool CreateInstanceWithNoMessage(Type exceptionUnderTest)
    {
        var newInstance = Activator.CreateInstance(exceptionUnderTest);
        Assert.That(newInstance, Is.Not.Null);
        return newInstance?.GetType() == exceptionUnderTest;
    }

    private static bool InheritsFrom<T>(Type exceptionUnderTest)
    {
        var typeUnderTest = exceptionUnderTest;

        while (typeUnderTest != null)
        {
            if (typeUnderTest == typeof(T))
            {
                return true;
            }
            typeUnderTest = typeUnderTest.BaseType;
        }

        return false;
    }
}