// Copyright (c) 2012-2023 Wojciech Figat. All rights reserved. using System; using System.Collections.Generic; using System.Diagnostics; #pragma warning disable 1591 namespace FlaxEngine.Assertions { /// /// The Assert class contains assertion methods for setting invariants in the code. /// [DebuggerStepThrough] [HideInEditor] public static class Assert { /// /// Should an exception be thrown on a failure. /// public static bool RaiseExceptions = true; /// /// Asserts that the values are approximately equal. An absolute error check is used for approximate equality check /// (|a-b| < tolerance). Default tolerance is 0.00001f. /// Note: Every time you call the method with tolerance specified, a new instance of Assertions.Comparers.FloatComparer /// is created. For performance reasons you might want to instance your own comparer and pass it to the AreEqual method. /// If the tolerance is not specifies, a default comparer is used and the issue does not occur. /// /// /// [Conditional("FLAX_ASSERTIONS")] public static void AreApproximatelyEqual(float expected, float actual) { AreEqual(expected, actual, null, FloatComparer.ComparerWithDefaultTolerance); } /// /// Asserts that the values are approximately equal. An absolute error check is used for approximate equality check /// (|a-b| < tolerance). Default tolerance is 0.00001f. /// Note: Every time you call the method with tolerance specified, a new instance of Assertions.Comparers.FloatComparer /// is created. For performance reasons you might want to instance your own comparer and pass it to the AreEqual method. /// If the tolerance is not specifies, a default comparer is used and the issue does not occur. /// /// /// /// [Conditional("FLAX_ASSERTIONS")] public static void AreApproximatelyEqual(float expected, float actual, string message) { AreEqual(expected, actual, message, FloatComparer.ComparerWithDefaultTolerance); } /// /// Asserts that the values are approximately equal. An absolute error check is used for approximate equality check /// (|a-b| < tolerance). Default tolerance is 0.00001f. /// Note: Every time you call the method with tolerance specified, a new instance of Assertions.Comparers.FloatComparer /// is created. For performance reasons you might want to instance your own comparer and pass it to the AreEqual method. /// If the tolerance is not specifies, a default comparer is used and the issue does not occur. /// /// Tolerance of approximation. /// /// [Conditional("FLAX_ASSERTIONS")] public static void AreApproximatelyEqual(float expected, float actual, float tolerance) { AreApproximatelyEqual(expected, actual, tolerance, null); } /// /// Asserts that the values are approximately equal. An absolute error check is used for approximate equality check /// (|a-b| < tolerance). Default tolerance is 0.00001f. /// Note: Every time you call the method with tolerance specified, a new instance of Assertions.Comparers.FloatComparer /// is created. For performance reasons you might want to instance your own comparer and pass it to the AreEqual method. /// If the tolerance is not specifies, a default comparer is used and the issue does not occur. /// /// Tolerance of approximation. /// /// /// [Conditional("FLAX_ASSERTIONS")] public static void AreApproximatelyEqual(float expected, float actual, float tolerance, string message) { AreEqual(expected, actual, message, new FloatComparer(tolerance)); } /// /// Asserts that the values are approximately equal. /// /// The value type. /// The expected value. /// The actual value. [Conditional("FLAX_ASSERTIONS")] public static void AreEqual(T expected, T actual) { AreEqual(expected, actual, null); } /// /// Asserts that the values are approximately equal. /// /// The value type. /// The expected value. /// The actual value. /// The error message. [Conditional("FLAX_ASSERTIONS")] public static void AreEqual(T expected, T actual, string message) { AreEqual(expected, actual, message, EqualityComparer.Default); } /// /// Asserts that the values are approximately equal. /// /// The value type. /// The expected value. /// The actual value. /// The error message. /// The equality comparer. [Conditional("FLAX_ASSERTIONS")] public static void AreEqual(T expected, T actual, string message, IEqualityComparer comparer) { if (typeof(Object).IsAssignableFrom(typeof(T))) { AreEqual((object)expected as Object, (object)actual as Object, message); return; } if (!comparer.Equals(actual, expected)) Fail(GetEqualityMessage(actual, expected, true), message); } /// /// Asserts that the values are approximately equal. /// /// The expected value. /// The actual value. /// The error message. [Conditional("FLAX_ASSERTIONS")] public static void AreEqual(Object expected, Object actual, string message) { if (actual != expected) Fail(GetEqualityMessage(actual, expected, true), message); } /// /// Asserts that the values are approximately not equal. An absolute error check is used for approximate equality check /// (|a-b| < tolerance). Default tolerance is 0.00001f. /// /// /// [Conditional("FLAX_ASSERTIONS")] public static void AreNotApproximatelyEqual(float expected, float actual) { AreNotEqual(expected, actual, null, FloatComparer.ComparerWithDefaultTolerance); } /// /// Asserts that the values are approximately not equal. An absolute error check is used for approximate equality check /// (|a-b| < tolerance). Default tolerance is 0.00001f. /// /// /// /// [Conditional("FLAX_ASSERTIONS")] public static void AreNotApproximatelyEqual(float expected, float actual, string message) { AreNotEqual(expected, actual, message, FloatComparer.ComparerWithDefaultTolerance); } /// /// Asserts that the values are approximately not equal. An absolute error check is used for approximate equality check /// (|a-b| < tolerance). Default tolerance is 0.00001f. /// /// Tolerance of approximation. /// /// [Conditional("FLAX_ASSERTIONS")] public static void AreNotApproximatelyEqual(float expected, float actual, float tolerance) { AreNotApproximatelyEqual(expected, actual, tolerance, null); } /// /// Asserts that the values are approximately not equal. An absolute error check is used for approximate equality check /// (|a-b| < tolerance). Default tolerance is 0.00001f. /// /// Tolerance of approximation. /// /// /// [Conditional("FLAX_ASSERTIONS")] public static void AreNotApproximatelyEqual(float expected, float actual, float tolerance, string message) { AreNotEqual(expected, actual, message, new FloatComparer(tolerance)); } [Conditional("FLAX_ASSERTIONS")] public static void AreNotEqual(T expected, T actual) { AreNotEqual(expected, actual, null); } [Conditional("FLAX_ASSERTIONS")] public static void AreNotEqual(T expected, T actual, string message) { AreNotEqual(expected, actual, message, EqualityComparer.Default); } [Conditional("FLAX_ASSERTIONS")] public static void AreNotEqual(T expected, T actual, string message, IEqualityComparer comparer) { if (typeof(Object).IsAssignableFrom(typeof(T))) { AreNotEqual((object)expected as Object, (object)actual as Object, message); return; } if (comparer.Equals(actual, expected)) Fail(GetEqualityMessage(actual, expected, false), message); } [Conditional("FLAX_ASSERTIONS")] public static void AreNotEqual(Object expected, Object actual, string message) { if (actual == expected) Fail(GetEqualityMessage(actual, expected, false), message); } public static void Fail(string message = "", string userMessage = "") { if (RaiseExceptions) throw new AssertionException(message, userMessage); if (message == null) message = "Assertion has failed\n"; if (userMessage != null) message = string.Concat(userMessage, '\n', message); Debug.LogAssertion(message); } /// /// Asserts that the condition is false. /// /// [Conditional("FLAX_ASSERTIONS")] public static void IsFalse(bool condition) { IsFalse(condition, null); } /// /// Asserts that the condition is false. /// /// /// [Conditional("FLAX_ASSERTIONS")] public static void IsFalse(bool condition, string message) { if (condition) Fail(BooleanFailureMessage(false), message); } [Conditional("FLAX_ASSERTIONS")] public static void IsNotNull(T value) where T : class { IsNotNull(value, null); } [Conditional("FLAX_ASSERTIONS")] public static void IsNotNull(T value, string message) where T : class { if (typeof(Object).IsAssignableFrom(typeof(T))) IsNotNull((object)value as Object, message); else if (value == null) Fail(NullFailureMessage(null, false), message); } [Conditional("FLAX_ASSERTIONS")] public static void IsNotNull(Object value, string message) { if (value == null) Fail(NullFailureMessage(null, false), message); } [Conditional("FLAX_ASSERTIONS")] public static void IsNull(T value) where T : class { IsNull(value, null); } [Conditional("FLAX_ASSERTIONS")] public static void IsNull(T value, string message) where T : class { if (typeof(Object).IsAssignableFrom(typeof(T))) IsNull((object)value as Object, message); else if (value != null) Fail(NullFailureMessage(value, true), message); } [Conditional("FLAX_ASSERTIONS")] public static void IsNull(Object value, string message) { if (value != null) Fail(NullFailureMessage(value, true), message); } /// /// Asserts that the condition is true. /// /// [Conditional("FLAX_ASSERTIONS")] public static void IsTrue(bool condition) { IsTrue(condition, null); } /// /// Asserts that the condition is true. /// /// /// [Conditional("FLAX_ASSERTIONS")] public static void IsTrue(bool condition, string message) { if (!condition) Fail(BooleanFailureMessage(true), message); } /// /// Expect action to fail /// /// Type of exception to expect /// Action to expect /// User custom message to display [Conditional("FLAX_ASSERTIONS")] public static void ExceptionExpected(Type exceptionType, Action action, string message = "") { try { action(); } catch (Exception e) { if (exceptionType != e.GetType()) { Fail(GetMessage("Expected exception of type " + exceptionType.FullName + " got " + e.GetType().FullName), message); } return; } Fail(GetMessage("Expected exception of type " + exceptionType.FullName), message); } public static string BooleanFailureMessage(bool expected) { return GetMessage(string.Concat("Value was ", !expected), expected.ToString()); } public static string GetEqualityMessage(object actual, object expected, bool expectEqual) { string str = string.Format("Values are {0}equal.", new object[] { !expectEqual ? string.Empty : "not " }); object[] objArray = { actual, expected, null }; objArray[2] = !expectEqual ? "!=" : "=="; return GetMessage(str, string.Format("{0} {2} {1}", objArray)); } public static string GetMessage(string failureMessage) { return string.Format("{0} {1}", new object[] { "Assertion failed.", failureMessage }); } public static string GetMessage(string failureMessage, string expected) { return GetMessage($"{failureMessage}\nExpected: {expected}"); } public static string NullFailureMessage(object value, bool expectNull) { return GetMessage(string.Format("Value was {0}Null", new object[] { !expectNull ? string.Empty : "not " }), string.Format("Value was {0}Null", new object[] { !expectNull ? "not " : string.Empty })); } } }