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
{
2020-06-23 17:49:42 +00:00
/// <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: " ;
2020-06-23 17:49:42 +00:00
/// <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 ( ) ;
}
2020-06-23 17:49:42 +00:00
/// <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 )
{
// pass
Log ( PASS + success ) ;
TestRoot . TestsPassed = true ;
return true ;
}
else if ( ! ( obj1 = = null & & obj2 = = null ) & & obj1 . Equals ( obj2 ) & & obj2 . Equals ( obj1 ) )
{
// pass
Log ( PASS + success ) ;
TestRoot . TestsPassed = true ;
return true ;
}
else if ( obj1 ! = null & & ( obj1 ! = null & & ! obj1 . Equals ( obj2 ) ) )
{
// pass
Log ( PASS + success ) ;
TestRoot . TestsPassed = true ;
return true ;
}
else if ( obj2 ! = null & & ! obj2 . Equals ( obj1 ) )
{
// 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 ) ;
}
}
}