Advanced search object for complex model
Hello all,
Please find here my implementation of advanced search of in-memory object for complex tree model.
Sometimes when the tested app is really complex (especially in heavy client application), the search for object could be too slow due to depth.
One of the solution is to do by finding intermediate object to narrow and guide the search. So you multiply findChildEx. To ease that i made the followg method :
/**
* <a id="system.findContainer"></a>
* Rechercher un objet TestComplete en mémoire de manière containérisé<br>
* Si <i>system.debug</i> est à <b>true</b> alors des logs complémentaires sur la recherche sont inscrits
* @memberof system
* @function
* {Object} ParentObject - Objet parent porteur de l'objet à rechercher. Racine de départ de la recherche. Plus l'objet parent est de haut niveau, plus le temps de recherche peut être long
* {array} Props - Tableau des propriétés des objets à rechercher par container, si plusieurs propriétés recherchées pour un container donnée alors le séparateur est le |, exemple ["Visible|Name", "Name"] -> recherche des 2 propriétés Visble et Name pour le premier container et recherche de Name seulement pour le deuxième container
* {array} Values - Tableau des valeurs des propriétés des objets à rechercher
* {number|array} [Depth=4] - Limiter la recherche a <i>Depth>/i> profondeur depuis l'objet parent. Plus la profondeur est grande, plus le temps de recherche peut être long. Peut être un tableau pour définir un temps de rechercher par container
* @returns {object} Renvoie l'objet s'il existe ou <b>null</b> le cas échéant ou bien en cas d'erreur
*/
system.findContainer = function(ParentObject = null, Props = null, Values = null, Depth = 4) {
// Vérification des paramètres obligatoires
if ((ParentObject == null) || (Props == null) || (Values == null)) {
if (system.debug)
Log.Message('findContainer() - Un paramètre obligatoire est non renseigné (ParentObject ou Props ou Values)', "", pmHigher, system.logWarning);
return null;
}
if (ParentObject == "current") {
if ((typeof system.container != 'undefined') && (system.container != null) && (system.container.Exists))
ParentObject = system.container
else
return null;
}
if (system.debug) {
let propsKey = typeof Props == "string" ? Props : Props.join("|");
let valuesKey;
switch (typeof Values) {
case "string":
valuesKey = Values;
break;
case "number":
case "boolean":
valuesKey = Values.toString();
break;
case "null":
valuesKey = "null";
break;
default:
valuesKey = Values.join("|");
break;
}
Log.Message("findContainer(" + ParentObject.FullName + ", " + propsKey + ", " + valuesKey + ", " + Depth.toString() + ") - Recherche d'objet", "", pmLowest, system.logDebug);
}
var objectfind = ParentObject;
let currentProps;
let currentValues;
let currentDepth;
try {
for (let i=0;i<Props.length;i++) {
currentProps = Props[i].split('|');
currentValues = new Array();
currentDepth = typeof Depth == 'number' ? Depth : Depth[i];
for (let j=0;j<currentProps.length;j++) {
currentValues.push(Values.shift());
}
objectfind = objectfind.FindChildEx(currentProps, currentValues, currentDepth, true, system.time.medium);
if ((typeof objectfind == 'undefined') || ((objectfind != null) && (!objectfind.Exists)))
break;
}
}
catch (e) {
objectfind = null;
if (system.debug)
Log.Message("findContainer() - Une exception est apparue dans la recherche", e.message, pmHighest, system.logError);
}
finally {
// Ne renvoyer que "null" sur non trouvé ou erreur
if ((typeof objectfind == 'undefined') || ((objectfind != null) && (!objectfind.Exists)))
objectfind = null;
if (system.debug) {
if (objectfind == null)
Log.Message("findContainer() renvoie un objet null ou undefined", "", pmLowest, system.logDebug)
else
Log.Message('findContainer() a trouvé un objet', objectfind.FullName, pmLowest, system.logDebug);
}
return objectfind;
}
}
It comes from my testing framework so everything starting by system. is specific but you should understand the use :
system.debug -> true to activate an additionnal level of log.
system.logDebug -> specific debug log attributes.
system.container -> a global variable that can hold a frequently used object in portion of test
system.time.medium -> this is 5 seconds (5000ms)
Samples usage :
let objectToTest = system.findContainer(SourceObject, ["Visible|Name", "Visible|Name"], [true,'dlmAccueil', true,'editionEnfants']);
Will search in SourceObject a visible object named 'editionEnfants' which is located inside another visible object named 'dlmAccueil'. The search will use a default max depth of 4 levels for both objects.
let objectToTest = system.findContainer(SourceObject, ["Visible|Name", "Name", "Header|Index|Visible"], [true, "Saisie", "DockingPanel"', "ILPaneGroup", 1, true], [2, 3, 2]);
Will search in SourceObject a visible object with property Index to 1 and property Header to 'ILPanelGroup' which is located inside another object named 'DockingPanel' which is located inside another visible object named 'Saisie'. The search will use a depth of 2 levels for first object, 3 levels for second object and 2 levels for final object.
Hope it could help someone and feel free to discuss/improve it.