2023-08-22 08:27:30 +00:00
|
|
|
package;
|
|
|
|
|
|
|
|
import flixel.math.FlxPoint;
|
|
|
|
import flixel.math.FlxRect;
|
|
|
|
import haxe.PosInfos;
|
|
|
|
import massive.munit.Assert;
|
|
|
|
|
|
|
|
using flixel.util.FlxArrayUtil;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @see https://github.com/HaxeFlixel/flixel/tree/dev/tests/unit
|
|
|
|
*/
|
2023-08-30 22:31:59 +00:00
|
|
|
@:nullSafety
|
2023-08-22 08:27:30 +00:00
|
|
|
class FunkinAssert
|
|
|
|
{
|
|
|
|
/**
|
|
|
|
* Assert if `expected` is within `margin` of `actual`, and fail if not.
|
|
|
|
* Useful for comparting Float values.
|
|
|
|
*
|
|
|
|
* @param expected The expected value of the test.
|
|
|
|
* @param actual The actual value of the test.
|
|
|
|
* @param margin The allowed margin of error between the expected and actual values.
|
|
|
|
* @param info Info on the position this function was called from. Magic value, passed automatically.
|
|
|
|
*/
|
2023-08-30 22:31:59 +00:00
|
|
|
public static function areNear(expected:Float, ?actual:Float, margin:Float = 0.001, ?info:PosInfos):Void
|
2023-08-22 08:27:30 +00:00
|
|
|
{
|
2023-08-30 22:31:59 +00:00
|
|
|
if (actual == null) Assert.fail('Value [$actual] is null, and cannot be compared to [$expected]', info);
|
2023-08-22 08:27:30 +00:00
|
|
|
if (areNearHelper(expected, actual)) Assert.assertionCount++;
|
|
|
|
else
|
|
|
|
Assert.fail('Value [$actual] is not within [$margin] of [$expected]', info);
|
|
|
|
}
|
|
|
|
|
2023-08-30 22:31:59 +00:00
|
|
|
public static function rectsNear(expected:FlxRect, ?actual:FlxRect, margin:Float = 0.001, ?info:PosInfos):Void
|
2023-08-22 08:27:30 +00:00
|
|
|
{
|
2023-08-30 22:31:59 +00:00
|
|
|
if (actual == null) Assert.fail('Value [$actual] is null, and cannot be compared to [$expected]', info);
|
2023-08-22 08:27:30 +00:00
|
|
|
var areNear = areNearHelper(expected.x, actual.x, margin)
|
|
|
|
&& areNearHelper(expected.y, actual.y, margin)
|
|
|
|
&& areNearHelper(expected.width, actual.width, margin)
|
|
|
|
&& areNearHelper(expected.height, actual.height, margin);
|
|
|
|
|
|
|
|
if (areNear) Assert.assertionCount++;
|
|
|
|
else
|
|
|
|
Assert.fail('Value [$actual] is not within [$margin] of [$expected]', info);
|
|
|
|
}
|
|
|
|
|
|
|
|
static function areNearHelper(expected:Float, actual:Float, margin:Float = 0.001):Bool
|
|
|
|
{
|
|
|
|
return actual >= expected - margin && actual <= expected + margin;
|
|
|
|
}
|
|
|
|
|
2023-08-30 22:31:59 +00:00
|
|
|
public static function arraysEqual<T>(expected:Array<T>, ?actual:Array<T>, ?info:PosInfos):Void
|
2023-08-22 08:27:30 +00:00
|
|
|
{
|
2023-08-30 22:31:59 +00:00
|
|
|
if (actual == null) Assert.fail('Value [$actual] is null, and cannot be compared to [$expected]', info);
|
2023-08-22 08:27:30 +00:00
|
|
|
if (expected.equals(actual)) Assert.assertionCount++;
|
|
|
|
else
|
|
|
|
Assert.fail('\nExpected\n ${expected}\nbut was\n ${actual}\n', info);
|
|
|
|
}
|
|
|
|
|
2023-08-30 22:31:59 +00:00
|
|
|
public static function arraysNotEqual<T>(expected:Array<T>, ?actual:Array<T>, ?info:PosInfos):Void
|
2023-08-22 08:27:30 +00:00
|
|
|
{
|
2023-08-30 22:31:59 +00:00
|
|
|
if (actual == null) Assert.fail('Value [$actual] is null, and cannot be compared to [$expected]', info);
|
2023-08-22 08:27:30 +00:00
|
|
|
if (!expected.equals(actual)) Assert.assertionCount++;
|
|
|
|
else
|
|
|
|
Assert.fail('\nValue\n ${actual}\nwas equal to\n ${expected}\n', info);
|
|
|
|
}
|
|
|
|
|
2023-08-30 22:31:59 +00:00
|
|
|
public static function pointsEqual(expected:FlxPoint, ?actual:FlxPoint, ?msg:String, ?info:PosInfos)
|
2023-08-22 08:27:30 +00:00
|
|
|
{
|
2023-08-30 22:31:59 +00:00
|
|
|
if (actual == null) Assert.fail('Value [$actual] is null, and cannot be compared to [$expected]', info);
|
2023-08-22 08:27:30 +00:00
|
|
|
if (expected.equals(actual)) Assert.assertionCount++;
|
|
|
|
else if (msg != null) Assert.fail(msg, info);
|
|
|
|
else
|
|
|
|
Assert.fail("Value [" + actual + "] was not equal to expected value [" + expected + "]", info);
|
|
|
|
}
|
|
|
|
|
2023-08-30 22:31:59 +00:00
|
|
|
public static function pointsNotEqual(expected:FlxPoint, ?actual:FlxPoint, ?msg:String, ?info:PosInfos)
|
2023-08-22 08:27:30 +00:00
|
|
|
{
|
2023-08-30 22:31:59 +00:00
|
|
|
if (actual == null) Assert.fail('Value [$actual] is null, and cannot be compared to [$expected]', info);
|
2023-08-22 08:27:30 +00:00
|
|
|
if (!expected.equals(actual)) Assert.assertionCount++;
|
|
|
|
else if (msg != null) Assert.fail(msg, info);
|
|
|
|
else
|
|
|
|
Assert.fail("Value [" + actual + "] was equal to value [" + expected + "]", info);
|
|
|
|
}
|
2023-08-30 22:31:59 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Execute `targetFunc`, expecting it to throw an exception.
|
|
|
|
* If it doesn't, or if the exception doesn't validate against the provided `predicate`, fail.
|
|
|
|
*/
|
|
|
|
public static function validateThrows(targetFunc:Void->Void, predicate:Dynamic->Bool, ?info:PosInfos)
|
|
|
|
{
|
|
|
|
try
|
|
|
|
{
|
|
|
|
targetFunc();
|
|
|
|
Assert.fail("Expected exception to be thrown, got no failure.", info);
|
|
|
|
}
|
|
|
|
catch (e:Dynamic)
|
|
|
|
{
|
|
|
|
if (predicate(e))
|
|
|
|
{
|
|
|
|
Assert.assertionCount++;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
Assert.fail('Expected exception to match predicate, but failed (got ${e})', info);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Execute `targetFunc`, expecting it to throw a `json2object.Error.CustomFunctionException` with a message matching `expected`.
|
|
|
|
* I made this its own function since it's the most common specific use case of `validateThrows`.
|
|
|
|
*/
|
|
|
|
public static function validateThrowsJ2OCustom(targetFunc:Void->Void, expected:String, ?info:PosInfos)
|
|
|
|
{
|
|
|
|
var predicate:Dynamic->Bool = function(err:Dynamic):Bool {
|
|
|
|
if (!Std.isOfType(err, json2object.Error)) Assert.fail('Expected error of type json2object.Error, got ${Type.typeof(err)}');
|
|
|
|
|
|
|
|
switch (err)
|
|
|
|
{
|
|
|
|
case json2object.Error.CustomFunctionException(msg, pos):
|
|
|
|
if (msg != expected) Assert.fail('Expected message [${expected}], got [${msg}].');
|
|
|
|
default:
|
|
|
|
Assert.fail('Expected error of type CustomFunctionException, got [${err}].');
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
};
|
|
|
|
validateThrows(targetFunc, predicate, info);
|
|
|
|
}
|
2023-09-08 21:46:10 +00:00
|
|
|
|
|
|
|
static var capturedTraces:Array<String> = [];
|
|
|
|
|
|
|
|
public static function initAssertTrace():Void
|
|
|
|
{
|
|
|
|
var oldTrace = haxe.Log.trace;
|
|
|
|
haxe.Log.trace = function(v:Dynamic, ?infos:haxe.PosInfos) {
|
|
|
|
onTrace(v, infos);
|
|
|
|
// oldTrace(v, infos);
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
public static function clearTraces():Void
|
|
|
|
{
|
|
|
|
capturedTraces = [];
|
|
|
|
}
|
|
|
|
|
|
|
|
@:nullSafety(Off) // Why isn't haxe.std null-safe?
|
|
|
|
static function onTrace(v:Dynamic, ?infos:haxe.PosInfos)
|
|
|
|
{
|
|
|
|
// var str:String = haxe.Log.formatOutput(v, infos);
|
|
|
|
var str:String = Std.string(v);
|
|
|
|
capturedTraces.push(str);
|
|
|
|
|
|
|
|
#if (sys && echo_traces)
|
|
|
|
Sys.println('[TESTLOG] $str');
|
|
|
|
#end
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Check the first string that was traced and validate it.
|
|
|
|
* @param expected
|
|
|
|
*/
|
|
|
|
public static inline function assertTrace(expected:String):Void
|
|
|
|
{
|
|
|
|
var actual:Null<String> = capturedTraces.shift();
|
|
|
|
Assert.isNotNull(actual);
|
|
|
|
Assert.areEqual(expected, actual);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Check the first string that was traced and validate it.
|
|
|
|
* @param expected
|
|
|
|
*/
|
|
|
|
public static inline function assertLastTrace(expected:String):Void
|
|
|
|
{
|
|
|
|
var actual:Null<String> = capturedTraces.pop();
|
|
|
|
Assert.isNotNull(actual);
|
|
|
|
Assert.areEqual(expected, actual);
|
|
|
|
}
|
2023-08-22 08:27:30 +00:00
|
|
|
}
|