From 23788e85d40f983d4be58789e0f979d4dd4cbbe4 Mon Sep 17 00:00:00 2001 From: Sascha Kolewa Date: Tue, 21 Dec 2010 18:21:10 +0100 Subject: Added function to compare objects Taken over quite some object comparison functionality from QUnit or http://philrathe.com/articles/equiv to compare different types of Javascript objects --- src/imports/testlib/TestCase.qml | 146 +++++++++++++++++++++++++++++++-------- 1 file changed, 116 insertions(+), 30 deletions(-) (limited to 'src') diff --git a/src/imports/testlib/TestCase.qml b/src/imports/testlib/TestCase.qml index 6c73c1d..ccaad8f 100644 --- a/src/imports/testlib/TestCase.qml +++ b/src/imports/testlib/TestCase.qml @@ -98,55 +98,141 @@ Item { throw new Error("QtQuickTest::fail") } - function qtest_compareInternal(actual, expected) { - var success = false - - if (typeof actual == "number" && typeof expected == "number") { - // Use a fuzzy compare if the two values are floats - if (Math.abs(actual - expected) <= 0.00001) - success = true - } else if (Array.isArray(actual) && Array.isArray(expected)) { - success = qtest_compareInternalArrays(actual, expected) - } else if (typeof actual == "object" && typeof expected == "object") { - // Does the expected value look like a vector3d? - if ("x" in expected && "y" in expected && "z" in expected) { - if (Math.abs(actual.x - expected.x) <= 0.00001 && - Math.abs(actual.y - expected.y) <= 0.00001 && - Math.abs(actual.z - expected.z) <= 0.00001) { - success = true - } - } else if (qtest_compareInternalObjects(actual, expected)) { - success = true + // Determine what is o. + // Discussions and reference: http://philrathe.com/articles/equiv + // Test suites: http://philrathe.com/tests/equiv + // Author: Philippe Rathé + function qtest_typeof(o) { + if (typeof o === "undefined") { + return "undefined"; + + // consider: typeof null === object + } else if (o === null) { + return "null"; + + } else if (o.constructor === String) { + return "string"; + + } else if (o.constructor === Boolean) { + return "boolean"; + + } else if (o.constructor === Number) { + + if (isNaN(o)) { + return "nan"; + } else { + return "number"; } - } else if (actual == expected) { - success = true + // consider: typeof [] === object + } else if (o instanceof Array) { + return "array"; + + // consider: typeof new Date() === object + } else if (o instanceof Date) { + return "date"; + + // consider: /./ instanceof Object; + // /./ instanceof RegExp; + // typeof /./ === "function"; // => false in IE and Opera, + // true in FF and Safari + } else if (o instanceof RegExp) { + return "regexp"; + + } else if (typeof o === "object") { + if ("mapFromItem" in o && "mapToItem" in o) { + return "declarativeitem"; // @todo improve detection of declarative items + } else if ("x" in o && "y" in o && "z" in o) { + return "vector3d"; // Qt3D vector + } + return "object"; + } else if (o instanceof Function) { + return "function"; + } else { + return undefined; } - return success } - // Test for equality any JavaScript type. + // Test for equality + // Large parts contain sources from QUnit or http://philrathe.com // Discussions and reference: http://philrathe.com/articles/equiv // Test suites: http://philrathe.com/tests/equiv // Author: Philippe Rathé - function qtest_compareInternalObjects(a, b) { + function qtest_compareInternal(act, exp) { + var success = false; + + if (act === exp) { + success = true; // catch the most you can + } else if (act === null || exp === null || typeof act === "undefined" || typeof exp === "undefined") { + success = false; // don't lose time with error prone cases + } else { + var typeExp = qtest_typeof(exp), typeAct = qtest_typeof(act) + + if (typeExp !== typeAct) { + // allow object vs string comparison (e.g. for colors) + // else break on different types + if ((typeExp === "string" && typeAct === "object") || (typeExp === "object" && typeAct === "string")) { + success = (act == exp) + } + } else if (typeExp === "string" || typeExp === "boolean" || typeExp === "number" || + typeExp === "null" || typeExp === "undefined") { + if (exp instanceof act.constructor || act instanceof exp.constructor) { + // to catch short annotaion VS 'new' annotation of act declaration + // e.g. var i = 1; + // var j = new Number(1); + success = (act == exp) + } else { + success = (act === exp) + } + } else if (typeExp === "nan") { + success = isNaN(act); + } else if (typeExp == "number") { + // Use act fuzzy compare if the two values are floats + if (Math.abs(act - exp) <= 0.00001) { + success = true + } + } else if (typeExp === "array") { + success = qtest_compareInternalArrays(act, exp) + } else if (typeExp === "object") { + success = qtest_compareInternalObjects(act, exp) + } else if (typeExp === "declarativeitem") { + success = qtest_compareInternalObjects(act, exp) // @todo improve comparison of declarative items + } else if (typeExp === "vector3d") { + success = (Math.abs(act.x - exp.x) <= 0.00001 && + Math.abs(act.y - exp.y) <= 0.00001 && + Math.abs(act.z - exp.z) <= 0.00001) + } else if (typeExp === "date") { + success = (act.valueOf() === exp.valueOf()) + } else if (typeExp === "regexp") { + success = (act.source === exp.source && // the regex itself + act.global === exp.global && // and its modifers (gmi) ... + act.ignoreCase === exp.ignoreCase && + act.multiline === exp.multiline) + } + } + return success + } + + function qtest_compareInternalObjects(act, exp) { var i; var eq = true; // unless we can proove it var aProperties = [], bProperties = []; // collection of strings // comparing constructors is more strict than using instanceof - if (a.constructor !== b.constructor) { + if (act.constructor !== exp.constructor) { return false; } - for (i in a) { // be strict: don't ensures hasOwnProperty and go deep - aProperties.push(i); // collect a's properties - if (!qtest_compareInternal(a[i], b[i])) { + for (i in act) { // be strict: don't ensures hasOwnProperty and go deep + aProperties.push(i); // collect act's properties + + if (!qtest_compareInternal(act[i], exp[i])) { eq = false; + break; } } - for (i in b) { - bProperties.push(i); // collect b's properties + for (i in exp) { + bProperties.push(i); // collect exp's properties } // Ensures identical properties name -- cgit v1.2.3