diff --git a/tests/src/Util.hx b/tests/src/Util.hx index a19833b..13398bd 100644 --- a/tests/src/Util.hx +++ b/tests/src/Util.hx @@ -1,102 +1,100 @@ import hscript.Expr.Error; import hscript.Printer; import haxe.Constraints.IMap; +import haxe.EnumTools.EnumValueTools; using StringTools; class Util { - // TODO: check this for bugs - static function deepEqual(a:Dynamic, b:Dynamic):Bool { - if (a == b) { - return true; - } + static inline function isNull(a:Dynamic):Bool { + return Type.typeof(a) == TNull; + } - if (a == null || b == null) { + static inline function isFunction(a:Dynamic):Bool { + return Type.typeof(a) == TFunction; + } + + // TODO: check this for bugs + // Code from https://github.com/elnabo/equals/blob/master/src/equals/Equal.hx, (MIT License), but updated to work with haxe 4 + public static function deepEqual (a:T, b:T) : Bool { + if (a == b) { return true; } // if physical equality + if (isNull(a) || isNull(b)) { return false; } - if ((a is String) && (b is String)) { - return a == b; - } - - if ((a is Array) && (b is Array)) { - var aArray:Array = cast a; - var bArray:Array = cast b; - - if (aArray.length != bArray.length) { - return false; - } - - for (i in 0...aArray.length) { - if (!deepEqual(aArray[i], bArray[i])) { + switch (Type.typeof(a)) { + case TNull, TInt, TBool, TUnknown: + return a == b; + case TFloat: + return Math.isNaN(cast a) && Math.isNaN(cast b); // only valid true result remaining + case TFunction: + return Reflect.compareMethods(a, b); // only physical equality can be tested for function + case TEnum(_): + if (EnumValueTools.getIndex(cast a) != EnumValueTools.getIndex(cast b)) { return false; } - } + var a_args = EnumValueTools.getParameters(cast a); + var b_args = EnumValueTools.getParameters(cast b); + return deepEqual(a_args, b_args); + case TClass(_): + if (Std.isOfType(a, String) && Std.isOfType(b, String)) { + return a == b; + } + if (Std.isOfType(a, Array) && Std.isOfType(b, Array)) { + var a = cast(a, Array); + var b = cast(b, Array); + if (a.length != b.length) { return false; } + for (i in 0...a.length) { + if (!deepEqual(a[i], b[i])) { + return false; + } + } + return true; + } - return true; + if (Std.isOfType(a, IMap) && Std.isOfType(b, IMap)) { + var a = cast(a, Map); + var b = cast(b, Map); + var a_keys = [ for (key in a.keys()) key ]; + var b_keys = [ for (key in b.keys()) key ]; + a_keys.sort(Reflect.compare); + b_keys.sort(Reflect.compare); + if (!deepEqual(a_keys, b_keys)) { return false; } + for (key in a_keys) { + if (!deepEqual(a.get(key), b.get(key))) { + return false; + } + } + return true; + } + + if (Std.isOfType(a, Date) && Std.isOfType(b, Date)) { + return cast(a, Date).getTime() == cast(b, Date).getTime(); + } + + if (Std.isOfType(a, haxe.io.Bytes) && Std.isOfType(b, haxe.io.Bytes)) { + return deepEqual(cast(a, haxe.io.Bytes).getData(), cast(b, haxe.io.Bytes).getData()); + } + + case TObject: } - if(Std.isOfType(a, Enum) && Std.isOfType(b, Enum)) { - if(Type.enumEq(a, b)) - return true; - } - - // Check Map Equality - if (Std.isOfType(a, IMap) && Std.isOfType(b, IMap)) { - var aMap:IMap = cast a; - var bMap:IMap = cast b; - - var aFields = [for(v in aMap.keys()) v]; - var bFields = [for(v in bMap.keys()) v]; - - if (aFields.length != bFields.length) { - return false; - } - - // Sort fields to ensure consistent comparison - aFields.sort(Reflect.compare); - bFields.sort(Reflect.compare); - - for (key in aMap.keys()) { - if (!bMap.exists(key) || !deepEqual(aMap.get(key), bMap.get(key))) { + for (field in Reflect.fields(a)) { + var pa = Reflect.field(a, field); + var pb = Reflect.field(b, field); + if (isFunction(pa)) { + // ignore function as only physical equality can be tested, unless null + if (isNull(pa) != isNull(pb)) { return false; } + continue; } - return true; - } - - if (Reflect.isObject(a) && Reflect.isObject(b)) { - var aFields = Reflect.fields(a); - var bFields = Reflect.fields(b); - - if (aFields.length != bFields.length) { + if (!deepEqual(pa, pb)) { return false; } - - // Sort fields to ensure consistent comparison - aFields.sort(Reflect.compare); - bFields.sort(Reflect.compare); - - for (i in 0...aFields.length) { - var field = aFields[i]; - if (field != bFields[i] || !deepEqual(Reflect.field(a, field), Reflect.field(b, field))) { - return false; - } - } - - return true; } - if(!Type.enumEq(Type.typeof(a), Type.typeof(b))) { - if(Type.typeof(a) == TInt && Type.typeof(b) == TFloat) { - return cast(a, Int) == cast(b, Float); - } - if(Type.typeof(a) == TFloat && Type.typeof(b) == TInt) { - return cast(a, Float) == cast(b, Int); - } - } - - return false; + return true; }