A stable modding interface between Techblox and mods https://mod.exmods.org/
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

221 lines
6.6KB

  1. using System;
  2. using System.Collections.Concurrent;
  3. using System.IO;
  4. using System.Runtime.CompilerServices;
  5. using Unity.Mathematics;
  6. namespace GamecraftModdingAPI.Tests
  7. {
  8. /// <summary>
  9. /// API test system assertion utilities.
  10. /// </summary>
  11. public static class Assert
  12. {
  13. private static StreamWriter logFile = null;
  14. private static ConcurrentDictionary<string, string> callbacks = new ConcurrentDictionary<string, string>();
  15. private const string PASS = "SUCCESS: ";
  16. private const string FAIL = "FAILURE: ";
  17. private const string WARN = "WARNING: ";
  18. private const string INFO = "DEBUG: ";
  19. /// <summary>
  20. /// Log a message to the test log.
  21. /// </summary>
  22. /// <param name="msg">Message.</param>
  23. /// <param name="end">Message ending.</param>
  24. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  25. public static void Log(string msg, string end = "\n")
  26. {
  27. if (logFile == null) openTestLog();
  28. logFile.Write(msg + end);
  29. logFile.Flush();
  30. }
  31. /// <summary>
  32. /// Asserts that the event receives a callback... eventually.
  33. /// Add the eventhandler returned by this method to the relevant event.
  34. /// This does not assert that the callback happens under that event's intended circumstances.
  35. /// Add another event handler to assert specific circumstance requirements.
  36. /// </summary>
  37. /// <returns>The callback event handler.</returns>
  38. /// <param name="eventName">Event name.</param>
  39. /// <param name="eventMsg">Event error message.</param>
  40. /// <typeparam name="T">The event handler callback argument object.</typeparam>
  41. public static EventHandler<T> CallsBack<T>(string eventName, string eventMsg = null)
  42. {
  43. if (eventMsg == null) eventMsg = $"expected callback to {eventName} but it never occurred...";
  44. callbacks[eventName] = eventMsg;
  45. return (sender, args) =>
  46. {
  47. string value = null;
  48. 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())}')"); }
  49. Log(PASS + $"callback to {eventName} occurred... (Received '{args.ToString()}' from '{(sender == null ? (string)sender : sender.ToString())}')");
  50. TestRoot.TestsPassed = true;
  51. };
  52. }
  53. public static bool NotNull<T>(T obj, string err = null, string success = null)
  54. {
  55. if (err == null) err = $"{nameof(T)} object was null.";
  56. if (success == null) success = $"{nameof(T)} '{obj}' not null";
  57. if (obj == null)
  58. {
  59. Log(FAIL + err);
  60. TestRoot.TestsPassed = false;
  61. return false;
  62. }
  63. else
  64. {
  65. Log(PASS + success);
  66. TestRoot.TestsPassed = true;
  67. return true;
  68. }
  69. }
  70. public static bool Equal<T>(T obj1, T obj2, string err = null, string success = null)
  71. {
  72. if (err == null) err = $"{nameof(T)} '{obj1}' is not equal to '{obj2}'.";
  73. if (success == null) success = $"{nameof(T)} '{obj1}' is equal to '{obj2}'.";
  74. if ((obj1 == null && obj2 == null)
  75. || (obj1 != null && obj2 != null && obj1.Equals(obj2) && obj2.Equals(obj1)))
  76. {
  77. // pass
  78. Log(PASS + success);
  79. TestRoot.TestsPassed = true;
  80. return true;
  81. }
  82. else
  83. {
  84. // fail
  85. Log(FAIL + err);
  86. TestRoot.TestsPassed = false;
  87. return false;
  88. }
  89. }
  90. public static bool Errorless(Action tryThis, string err = null, string success = null)
  91. {
  92. if (err == null) err = $"{tryThis} raised an exception: ";
  93. if (success == null) success = $"{tryThis} completed without raising an exception.";
  94. try
  95. {
  96. tryThis();
  97. }
  98. catch (Exception e)
  99. {
  100. Log(FAIL + err + e);
  101. TestRoot.TestsPassed = false;
  102. return false;
  103. }
  104. TestRoot.TestsPassed = true;
  105. Log(PASS + success);
  106. return true;
  107. }
  108. public static bool CloseTo(float a, float b, string err = null, string success = null, float delta = float.Epsilon)
  109. {
  110. if (err == null) err = $"{a} is not within {delta} of {b}.";
  111. if (success == null) success = $"{a} is close enough to {b}.";
  112. if (Math.Abs(a - b) > delta)
  113. {
  114. Log(FAIL + err);
  115. TestRoot.TestsPassed = false;
  116. return false;
  117. }
  118. else
  119. {
  120. TestRoot.TestsPassed = true;
  121. Log(PASS + success);
  122. return true;
  123. }
  124. }
  125. public static bool CloseTo(double a, double b, string err = null, string success = null, double delta = double.Epsilon)
  126. {
  127. if (err == null) err = $"{a} is not within {delta} of {b}.";
  128. if (success == null) success = $"{a} is close enough to {b}.";
  129. if (Math.Abs(a - b) > delta)
  130. {
  131. Log(FAIL + err);
  132. TestRoot.TestsPassed = false;
  133. return false;
  134. }
  135. else
  136. {
  137. TestRoot.TestsPassed = true;
  138. Log(PASS + success);
  139. return true;
  140. }
  141. }
  142. public static bool CloseTo(float3 a, float3 b, string err = null, string success = null, float delta = float.Epsilon)
  143. {
  144. if (err == null) err = $"{a} is not within {delta} of {b} in every direction.";
  145. if (success == null) success = $"{a} is close enough to {b}.";
  146. bool xClose = CloseTo(a.x, b.x, err, success, delta);
  147. bool yClose = CloseTo(a.y, b.y, err, success, delta);
  148. bool zClose = CloseTo(a.z, b.z, err, success, delta);
  149. if (xClose && yClose && zClose)
  150. {
  151. //TestRoot.TestsPassed = true;
  152. //Log(PASS + success);
  153. return true;
  154. }
  155. else
  156. {
  157. //Log(FAIL + err);
  158. //TestRoot.TestsPassed = false;
  159. return false;
  160. }
  161. }
  162. public static void Fail(string msg = null)
  163. {
  164. if (msg == null) msg = $"Manual test failure with no message provided.";
  165. Log(FAIL + msg);
  166. TestRoot.TestsPassed = false;
  167. }
  168. public static void Pass(string msg = null)
  169. {
  170. if (msg == null) msg = $"Manual test pass with no message provided.";
  171. Log(PASS + msg);
  172. TestRoot.TestsPassed = true;
  173. }
  174. public static void Warn(string msg = null)
  175. {
  176. if (msg == null) msg = $"Manual test warning with no message provided.";
  177. Log(WARN + msg);
  178. TestRoot.TestsPassed = true;
  179. }
  180. internal static void CallsComplete()
  181. {
  182. foreach(string key in callbacks.Keys)
  183. {
  184. Log(FAIL + callbacks[key]);
  185. TestRoot.TestsPassed = false;
  186. }
  187. }
  188. internal static void CloseLog()
  189. {
  190. if (logFile != null) logFile.Close();
  191. }
  192. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  193. private static void openTestLog()
  194. {
  195. logFile = File.CreateText(TestRoot.ReportFile);
  196. }
  197. }
  198. }