11cb0ef41Sopenharmony_ci'use strict'; 21cb0ef41Sopenharmony_ci 31cb0ef41Sopenharmony_cirequire('../common'); 41cb0ef41Sopenharmony_ciconst assert = require('assert'); 51cb0ef41Sopenharmony_ciconst util = require('util'); 61cb0ef41Sopenharmony_ci 71cb0ef41Sopenharmony_cifunction findInGraph(graph, type, n) { 81cb0ef41Sopenharmony_ci let found = 0; 91cb0ef41Sopenharmony_ci for (let i = 0; i < graph.length; i++) { 101cb0ef41Sopenharmony_ci const node = graph[i]; 111cb0ef41Sopenharmony_ci if (node.type === type) found++; 121cb0ef41Sopenharmony_ci if (found === n) return node; 131cb0ef41Sopenharmony_ci } 141cb0ef41Sopenharmony_ci} 151cb0ef41Sopenharmony_ci 161cb0ef41Sopenharmony_cifunction pruneTickObjects(activities) { 171cb0ef41Sopenharmony_ci // Remove one TickObject on each pass until none is left anymore 181cb0ef41Sopenharmony_ci // not super efficient, but simplest especially to handle 191cb0ef41Sopenharmony_ci // multiple TickObjects in a row 201cb0ef41Sopenharmony_ci const tickObject = { 211cb0ef41Sopenharmony_ci found: true, 221cb0ef41Sopenharmony_ci index: null, 231cb0ef41Sopenharmony_ci data: null, 241cb0ef41Sopenharmony_ci }; 251cb0ef41Sopenharmony_ci 261cb0ef41Sopenharmony_ci if (!Array.isArray(activities)) 271cb0ef41Sopenharmony_ci return activities; 281cb0ef41Sopenharmony_ci 291cb0ef41Sopenharmony_ci while (tickObject.found) { 301cb0ef41Sopenharmony_ci for (let i = 0; i < activities.length; i++) { 311cb0ef41Sopenharmony_ci if (activities[i].type === 'TickObject') { 321cb0ef41Sopenharmony_ci tickObject.index = i; 331cb0ef41Sopenharmony_ci break; 341cb0ef41Sopenharmony_ci } else if (i + 1 >= activities.length) { 351cb0ef41Sopenharmony_ci tickObject.found = false; 361cb0ef41Sopenharmony_ci } 371cb0ef41Sopenharmony_ci } 381cb0ef41Sopenharmony_ci 391cb0ef41Sopenharmony_ci if (tickObject.found) { 401cb0ef41Sopenharmony_ci // Point all triggerAsyncIds that point to the tickObject 411cb0ef41Sopenharmony_ci // to its triggerAsyncId and finally remove it from the activities 421cb0ef41Sopenharmony_ci tickObject.data = activities[tickObject.index]; 431cb0ef41Sopenharmony_ci const triggerId = { 441cb0ef41Sopenharmony_ci new: tickObject.data.triggerAsyncId, 451cb0ef41Sopenharmony_ci old: tickObject.data.uid, 461cb0ef41Sopenharmony_ci }; 471cb0ef41Sopenharmony_ci 481cb0ef41Sopenharmony_ci activities.forEach(function repointTriggerId(x) { 491cb0ef41Sopenharmony_ci if (x.triggerAsyncId === triggerId.old) 501cb0ef41Sopenharmony_ci x.triggerAsyncId = triggerId.new; 511cb0ef41Sopenharmony_ci }); 521cb0ef41Sopenharmony_ci 531cb0ef41Sopenharmony_ci activities.splice(tickObject.index, 1); 541cb0ef41Sopenharmony_ci } 551cb0ef41Sopenharmony_ci } 561cb0ef41Sopenharmony_ci return activities; 571cb0ef41Sopenharmony_ci} 581cb0ef41Sopenharmony_ci 591cb0ef41Sopenharmony_cimodule.exports = function verifyGraph(hooks, graph) { 601cb0ef41Sopenharmony_ci pruneTickObjects(hooks); 611cb0ef41Sopenharmony_ci 621cb0ef41Sopenharmony_ci // Map actual ids to standin ids defined in the graph 631cb0ef41Sopenharmony_ci const idtouid = {}; 641cb0ef41Sopenharmony_ci const uidtoid = {}; 651cb0ef41Sopenharmony_ci const typeSeen = {}; 661cb0ef41Sopenharmony_ci const errors = []; 671cb0ef41Sopenharmony_ci 681cb0ef41Sopenharmony_ci const activities = pruneTickObjects(hooks.activities); 691cb0ef41Sopenharmony_ci activities.forEach(processActivity); 701cb0ef41Sopenharmony_ci 711cb0ef41Sopenharmony_ci function processActivity(x) { 721cb0ef41Sopenharmony_ci if (!typeSeen[x.type]) typeSeen[x.type] = 0; 731cb0ef41Sopenharmony_ci typeSeen[x.type]++; 741cb0ef41Sopenharmony_ci 751cb0ef41Sopenharmony_ci const node = findInGraph(graph, x.type, typeSeen[x.type]); 761cb0ef41Sopenharmony_ci if (node == null) return; 771cb0ef41Sopenharmony_ci 781cb0ef41Sopenharmony_ci idtouid[node.id] = x.uid; 791cb0ef41Sopenharmony_ci uidtoid[x.uid] = node.id; 801cb0ef41Sopenharmony_ci if (node.triggerAsyncId == null) return; 811cb0ef41Sopenharmony_ci 821cb0ef41Sopenharmony_ci const tid = idtouid[node.triggerAsyncId]; 831cb0ef41Sopenharmony_ci if (x.triggerAsyncId === tid) return; 841cb0ef41Sopenharmony_ci 851cb0ef41Sopenharmony_ci errors.push({ 861cb0ef41Sopenharmony_ci id: node.id, 871cb0ef41Sopenharmony_ci expectedTid: node.triggerAsyncId, 881cb0ef41Sopenharmony_ci actualTid: uidtoid[x.triggerAsyncId], 891cb0ef41Sopenharmony_ci }); 901cb0ef41Sopenharmony_ci } 911cb0ef41Sopenharmony_ci 921cb0ef41Sopenharmony_ci if (errors.length) { 931cb0ef41Sopenharmony_ci errors.forEach((x) => 941cb0ef41Sopenharmony_ci console.error( 951cb0ef41Sopenharmony_ci `'${x.id}' expected to be triggered by '${x.expectedTid}', ` + 961cb0ef41Sopenharmony_ci `but was triggered by '${x.actualTid}' instead.`, 971cb0ef41Sopenharmony_ci ), 981cb0ef41Sopenharmony_ci ); 991cb0ef41Sopenharmony_ci } 1001cb0ef41Sopenharmony_ci assert.strictEqual(errors.length, 0); 1011cb0ef41Sopenharmony_ci 1021cb0ef41Sopenharmony_ci // Verify that all expected types are present (but more/others are allowed) 1031cb0ef41Sopenharmony_ci const expTypes = Object.create(null); 1041cb0ef41Sopenharmony_ci for (let i = 0; i < graph.length; i++) { 1051cb0ef41Sopenharmony_ci if (expTypes[graph[i].type] == null) expTypes[graph[i].type] = 0; 1061cb0ef41Sopenharmony_ci expTypes[graph[i].type]++; 1071cb0ef41Sopenharmony_ci } 1081cb0ef41Sopenharmony_ci 1091cb0ef41Sopenharmony_ci for (const type in expTypes) { 1101cb0ef41Sopenharmony_ci assert.ok(typeSeen[type] >= expTypes[type], 1111cb0ef41Sopenharmony_ci `Type '${type}': expecting: ${expTypes[type]} ` + 1121cb0ef41Sopenharmony_ci `found: ${typeSeen[type]}`); 1131cb0ef41Sopenharmony_ci } 1141cb0ef41Sopenharmony_ci}; 1151cb0ef41Sopenharmony_ci 1161cb0ef41Sopenharmony_ci// 1171cb0ef41Sopenharmony_ci// Helper to generate the input to the verifyGraph tests 1181cb0ef41Sopenharmony_ci// 1191cb0ef41Sopenharmony_cifunction inspect(obj, depth) { 1201cb0ef41Sopenharmony_ci console.error(util.inspect(obj, false, depth || 5, true)); 1211cb0ef41Sopenharmony_ci} 1221cb0ef41Sopenharmony_ci 1231cb0ef41Sopenharmony_cimodule.exports.printGraph = function printGraph(hooks) { 1241cb0ef41Sopenharmony_ci const ids = {}; 1251cb0ef41Sopenharmony_ci const uidtoid = {}; 1261cb0ef41Sopenharmony_ci const activities = pruneTickObjects(hooks.activities); 1271cb0ef41Sopenharmony_ci const graph = []; 1281cb0ef41Sopenharmony_ci activities.forEach(procesNode); 1291cb0ef41Sopenharmony_ci 1301cb0ef41Sopenharmony_ci function procesNode(x) { 1311cb0ef41Sopenharmony_ci const key = x.type.replace(/WRAP/, '').toLowerCase(); 1321cb0ef41Sopenharmony_ci if (!ids[key]) ids[key] = 1; 1331cb0ef41Sopenharmony_ci const id = `${key}:${ids[key]++}`; 1341cb0ef41Sopenharmony_ci uidtoid[x.uid] = id; 1351cb0ef41Sopenharmony_ci const triggerAsyncId = uidtoid[x.triggerAsyncId] || null; 1361cb0ef41Sopenharmony_ci graph.push({ type: x.type, id, triggerAsyncId }); 1371cb0ef41Sopenharmony_ci } 1381cb0ef41Sopenharmony_ci inspect(graph); 1391cb0ef41Sopenharmony_ci}; 140