'use strict'; const common = require('../common'); const assert = require('assert'); function findInGraph(graph, type, n) { let found = 0; for (let i = 0; i < graph.length; i++) { const node = graph[i]; if (node.type === type) found++; if (found === n) return node; } } function pruneTickObjects(activities) { // Remove one TickObject on each pass until none is left anymore // not super efficient, but simplest especially to handle // multiple TickObjects in a row const tickObject = { found: true, index: null, data: null, }; if (!Array.isArray(activities)) return activities; while (tickObject.found) { for (let i = 0; i < activities.length; i++) { if (activities[i].type === 'TickObject') { tickObject.index = i; break; } else if (i + 1 >= activities.length) { tickObject.found = false; } } if (tickObject.found) { // Point all triggerAsyncIds that point to the tickObject // to its triggerAsyncId and finally remove it from the activities tickObject.data = activities[tickObject.index]; const triggerId = { new: tickObject.data.triggerAsyncId, old: tickObject.data.uid, }; activities.forEach(function repointTriggerId(x) { if (x.triggerAsyncId === triggerId.old) x.triggerAsyncId = triggerId.new; }); activities.splice(tickObject.index, 1); } } return activities; } module.exports = common.mustCallAtLeast(function verifyGraph(hooks, graph) { pruneTickObjects(hooks); // Map actual ids to standin ids defined in the graph const idtouid = {}; const uidtoid = {}; const typeSeen = {}; const errors = []; const activities = pruneTickObjects(hooks.activities); activities.forEach(processActivity); function processActivity(x) { typeSeen[x.type] ||= 0; typeSeen[x.type]++; const node = findInGraph(graph, x.type, typeSeen[x.type]); if (node == null) return; idtouid[node.id] = x.uid; uidtoid[x.uid] = node.id; if (node.triggerAsyncId == null) return; const tid = idtouid[node.triggerAsyncId]; if (x.triggerAsyncId === tid) return; errors.push({ id: node.id, expectedTid: node.triggerAsyncId, actualTid: uidtoid[x.triggerAsyncId], }); } if (errors.length) { errors.forEach((x) => console.error( `'${x.id}' expected to be triggered by '${x.expectedTid}', ` + `but was triggered by '${x.actualTid}' instead.`, ), ); } assert.strictEqual(errors.length, 0); // Verify that all expected types are present (but more/others are allowed) const expTypes = { __proto__: null }; for (let i = 0; i < graph.length; i++) { expTypes[graph[i].type] ??= 0; expTypes[graph[i].type]++; } for (const type in expTypes) { assert.ok(typeSeen[type] >= expTypes[type], `Type '${type}': expecting: ${expTypes[type]} ` + `found: ${typeSeen[type]}`); } }, 0);