TechbloxModdingAPI/GamecraftModdingAPI/Tests/Assert.cs

221 lines
6.6 KiB
C#
Raw Normal View History

2020-06-18 01:04:40 +00:00
using System;
using System.Collections.Concurrent;
using System.IO;
using System.Runtime.CompilerServices;
2020-07-01 00:43:14 +00:00
using Unity.Mathematics;
2020-06-18 01:04:40 +00:00
namespace GamecraftModdingAPI.Tests
{
/// <summary>
/// API test system assertion utilities.
/// </summary>
2020-06-18 01:04:40 +00:00
public static class Assert
{
private static StreamWriter logFile = null;
private static ConcurrentDictionary<string, string> callbacks = new ConcurrentDictionary<string, string>();
private const string PASS = "SUCCESS: ";
private const string FAIL = "FAILURE: ";
private const string WARN = "WARNING: ";
private const string INFO = "DEBUG: ";
/// <summary>
/// Log a message to the test log.
/// </summary>
/// <param name="msg">Message.</param>
/// <param name="end">Message ending.</param>
2020-06-18 01:04:40 +00:00
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void Log(string msg, string end = "\n")
{
if (logFile == null) openTestLog();
logFile.Write(msg + end);
logFile.Flush();
}
/// <summary>
/// Asserts that the event receives a callback... eventually.
/// Add the eventhandler returned by this method to the relevant event.
/// This does not assert that the callback happens under that event's intended circumstances.
/// Add another event handler to assert specific circumstance requirements.
/// </summary>
/// <returns>The callback event handler.</returns>
/// <param name="eventName">Event name.</param>
/// <param name="eventMsg">Event error message.</param>
/// <typeparam name="T">The event handler callback argument object.</typeparam>
2020-06-18 01:04:40 +00:00
public static EventHandler<T> CallsBack<T>(string eventName, string eventMsg = null)
{
if (eventMsg == null) eventMsg = $"expected callback to {eventName} but it never occurred...";
callbacks[eventName] = eventMsg;
return (sender, args) =>
{
string value = null;
if (!callbacks.TryRemove(eventName, out value)) { Log(WARN + $"callback to {eventName} occurred again or a related error occurred... (Received '{args.ToString()}' from '{(sender == null ? (string)sender : sender.ToString())}')"); }
Log(PASS + $"callback to {eventName} occurred... (Received '{args.ToString()}' from '{(sender == null ? (string)sender : sender.ToString())}')");
TestRoot.TestsPassed = true;
};
}
2020-07-01 00:43:14 +00:00
public static bool NotNull<T>(T obj, string err = null, string success = null)
{
if (err == null) err = $"{nameof(T)} object was null.";
if (success == null) success = $"{nameof(T)} '{obj}' not null";
if (obj == null)
{
Log(FAIL + err);
TestRoot.TestsPassed = false;
return false;
}
else
{
Log(PASS + success);
TestRoot.TestsPassed = true;
return true;
}
}
public static bool Equal<T>(T obj1, T obj2, string err = null, string success = null)
{
if (err == null) err = $"{nameof(T)} '{obj1}' is not equal to '{obj2}'.";
if (success == null) success = $"{nameof(T)} '{obj1}' is equal to '{obj2}'.";
if ((obj1 == null && obj2 == null)
|| (obj1 != null && obj2 != null && obj1.Equals(obj2) && obj2.Equals(obj1)))
2020-07-01 00:43:14 +00:00
{
// pass
Log(PASS + success);
TestRoot.TestsPassed = true;
return true;
}
else
{
// fail
Log(FAIL + err);
TestRoot.TestsPassed = false;
return false;
}
}
public static bool Errorless(Action tryThis, string err = null, string success = null)
{
if (err == null) err = $"{tryThis} raised an exception: ";
if (success == null) success = $"{tryThis} completed without raising an exception.";
try
{
tryThis();
}
catch (Exception e)
{
Log(FAIL + err + e);
TestRoot.TestsPassed = false;
return false;
}
TestRoot.TestsPassed = true;
Log(PASS + success);
return true;
}
public static bool CloseTo(float a, float b, string err = null, string success = null, float delta = float.Epsilon)
{
if (err == null) err = $"{a} is not within {delta} of {b}.";
if (success == null) success = $"{a} is close enough to {b}.";
if (Math.Abs(a - b) > delta)
{
Log(FAIL + err);
TestRoot.TestsPassed = false;
return false;
}
else
{
TestRoot.TestsPassed = true;
Log(PASS + success);
return true;
}
}
public static bool CloseTo(double a, double b, string err = null, string success = null, double delta = double.Epsilon)
{
if (err == null) err = $"{a} is not within {delta} of {b}.";
if (success == null) success = $"{a} is close enough to {b}.";
if (Math.Abs(a - b) > delta)
{
Log(FAIL + err);
TestRoot.TestsPassed = false;
return false;
}
else
{
TestRoot.TestsPassed = true;
Log(PASS + success);
return true;
}
}
public static bool CloseTo(float3 a, float3 b, string err = null, string success = null, float delta = float.Epsilon)
{
if (err == null) err = $"{a} is not within {delta} of {b} in every direction.";
if (success == null) success = $"{a} is close enough to {b}.";
bool xClose = CloseTo(a.x, b.x, err, success, delta);
bool yClose = CloseTo(a.y, b.y, err, success, delta);
bool zClose = CloseTo(a.z, b.z, err, success, delta);
if (xClose && yClose && zClose)
{
//TestRoot.TestsPassed = true;
//Log(PASS + success);
return true;
}
else
{
//Log(FAIL + err);
//TestRoot.TestsPassed = false;
return false;
}
}
public static void Fail(string msg = null)
{
if (msg == null) msg = $"Manual test failure with no message provided.";
Log(FAIL + msg);
TestRoot.TestsPassed = false;
}
public static void Pass(string msg = null)
{
if (msg == null) msg = $"Manual test pass with no message provided.";
Log(PASS + msg);
TestRoot.TestsPassed = true;
}
public static void Warn(string msg = null)
{
if (msg == null) msg = $"Manual test warning with no message provided.";
Log(WARN + msg);
TestRoot.TestsPassed = true;
}
2020-06-18 01:04:40 +00:00
internal static void CallsComplete()
{
foreach(string key in callbacks.Keys)
{
Log(FAIL + callbacks[key]);
TestRoot.TestsPassed = false;
}
}
internal static void CloseLog()
{
if (logFile != null) logFile.Close();
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static void openTestLog()
{
logFile = File.CreateText(TestRoot.ReportFile);
}
}
}