Split the resulting execution tree out from TreeProcessor

This commit is contained in:
Steve Gravrock
2025-08-16 09:17:48 -07:00
parent b89a870a59
commit a3e1abfa12
4 changed files with 120 additions and 94 deletions
+45 -32
View File
@@ -9407,7 +9407,7 @@ getJasmineRequireObj().Runner = function(j$) {
#runableResources; #runableResources;
#runQueue; #runQueue;
#TreeProcessor; #TreeProcessor;
#treeProcessor; #executionTree;
#globalErrors; #globalErrors;
#reportDispatcher; #reportDispatcher;
#getConfig; #getConfig;
@@ -9470,7 +9470,7 @@ getJasmineRequireObj().Runner = function(j$) {
seed: j$.isNumber_(config.seed) ? config.seed + '' : config.seed seed: j$.isNumber_(config.seed) ? config.seed + '' : config.seed
}); });
this.#treeProcessor = new this.#TreeProcessor({ const treeProcessor = new this.#TreeProcessor({
tree: this.#topSuite, tree: this.#topSuite,
runnableIds: runablesToRun, runnableIds: runablesToRun,
orderChildren: function(node) { orderChildren: function(node) {
@@ -9480,7 +9480,7 @@ getJasmineRequireObj().Runner = function(j$) {
return !config.specFilter(spec); return !config.specFilter(spec);
} }
}); });
this.#treeProcessor.processTree(); this.#executionTree = treeProcessor.processTree();
return this.#execute2(runablesToRun, order); return this.#execute2(runablesToRun, order);
} }
@@ -9565,7 +9565,7 @@ getJasmineRequireObj().Runner = function(j$) {
async #executeTopSuite() { async #executeTopSuite() {
const wrappedChildren = this.#wrapNodes( const wrappedChildren = this.#wrapNodes(
this.#treeProcessor.childrenOfTopSuite() this.#executionTree.childrenOfTopSuite()
); );
const queueableFns = this.#addBeforeAndAfterAlls( const queueableFns = this.#addBeforeAndAfterAlls(
this.#topSuite, this.#topSuite,
@@ -9589,7 +9589,7 @@ getJasmineRequireObj().Runner = function(j$) {
#executeSuiteSegment(suite, segmentNumber, done) { #executeSuiteSegment(suite, segmentNumber, done) {
const wrappedChildren = this.#wrapNodes( const wrappedChildren = this.#wrapNodes(
this.#treeProcessor.childrenOfSuiteSegment(suite, segmentNumber) this.#executionTree.childrenOfSuiteSegment(suite, segmentNumber)
); );
const onStart = { const onStart = {
fn: next => { fn: next => {
@@ -9627,7 +9627,7 @@ getJasmineRequireObj().Runner = function(j$) {
this.#runQueueWithSkipPolicy.bind(this), this.#runQueueWithSkipPolicy.bind(this),
this.#globalErrors, this.#globalErrors,
done, done,
this.#treeProcessor.isExcluded(spec), this.#executionTree.isExcluded(spec),
config.failSpecWithNoExpectations, config.failSpecWithNoExpectations,
config.detectLateRejectionHandling config.detectLateRejectionHandling
); );
@@ -9648,7 +9648,7 @@ getJasmineRequireObj().Runner = function(j$) {
} }
#addBeforeAndAfterAlls(suite, wrappedChildren) { #addBeforeAndAfterAlls(suite, wrappedChildren) {
if (this.#treeProcessor.isExcluded(suite)) { if (this.#executionTree.isExcluded(suite)) {
return wrappedChildren; return wrappedChildren;
} }
@@ -11401,13 +11401,15 @@ getJasmineRequireObj().TreeProcessor = function(j$) {
const defaultMin = Infinity; const defaultMin = Infinity;
const defaultMax = 1 - Infinity; const defaultMax = 1 - Infinity;
// Transforms the suite tree into an execution tree, which represents the set
// of specs and (possibly interleaved) suites to be run in the order they are
// to be run in.
class TreeProcessor { class TreeProcessor {
#tree; #tree;
#runnableIds; #runnableIds;
#orderChildren; #orderChildren;
#excludeNode; #excludeNode;
#stats; #stats;
#processed;
constructor(attrs) { constructor(attrs) {
this.#tree = attrs.tree; this.#tree = attrs.tree;
@@ -11423,34 +11425,14 @@ getJasmineRequireObj().TreeProcessor = function(j$) {
function(node) { function(node) {
return false; return false;
}; };
this.#stats = {};
this.#processed = false;
} }
processTree() { processTree() {
this.#stats = {};
this.#processNode(this.#tree, true); this.#processNode(this.#tree, true);
this.#processed = true; const result = new ExecutionTree(this.#tree, this.#stats);
} this.#stats = null;
return result;
childrenOfTopSuite() {
return this.childrenOfSuiteSegment(this.#tree, 0);
}
childrenOfSuiteSegment(suite, segmentNumber) {
const segmentChildren = this.#stats[suite.id].segments[segmentNumber]
.nodes;
return segmentChildren.map(function(child) {
if (child.owner.children) {
return { suite: child.owner, segmentNumber: child.index };
} else {
return { spec: child.owner };
}
});
}
isExcluded(node) {
const nodeStats = this.#stats[node.id];
return node.children ? !nodeStats.willExecute : nodeStats.excluded;
} }
#runnableIndex(id) { #runnableIndex(id) {
@@ -11517,6 +11499,37 @@ getJasmineRequireObj().TreeProcessor = function(j$) {
} }
} }
class ExecutionTree {
#topSuite;
#stats;
constructor(topSuite, stats) {
this.#topSuite = topSuite;
this.#stats = stats;
}
childrenOfTopSuite() {
return this.childrenOfSuiteSegment(this.#topSuite, 0);
}
childrenOfSuiteSegment(suite, segmentNumber) {
const segmentChildren = this.#stats[suite.id].segments[segmentNumber]
.nodes;
return segmentChildren.map(function(child) {
if (child.owner.children) {
return { suite: child.owner, segmentNumber: child.index };
} else {
return { spec: child.owner };
}
});
}
isExcluded(node) {
const nodeStats = this.#stats[node.id];
return node.children ? !nodeStats.willExecute : nodeStats.excluded;
}
}
function segmentChildren(node, orderedChildren, stats, executableIndex) { function segmentChildren(node, orderedChildren, stats, executableIndex) {
let currentSegment = { let currentSegment = {
index: 0, index: 0,
+30 -30
View File
@@ -33,9 +33,9 @@ describe('TreeProcessor', function() {
runnableIds: [leaf.id] runnableIds: [leaf.id]
}); });
processor.processTree(); const result = processor.processTree();
expect(processor.isExcluded(leaf)).toEqual(false); expect(result.isExcluded(leaf)).toEqual(false);
}); });
it('processes a single pending leaf', function() { it('processes a single pending leaf', function() {
@@ -45,9 +45,9 @@ describe('TreeProcessor', function() {
runnableIds: [leaf.id] runnableIds: [leaf.id]
}); });
processor.processTree(); const result = processor.processTree();
expect(processor.isExcluded(leaf)).toEqual(false); expect(result.isExcluded(leaf)).toEqual(false);
}); });
it('processes a single non-specified leaf', function() { it('processes a single non-specified leaf', function() {
@@ -57,9 +57,9 @@ describe('TreeProcessor', function() {
runnableIds: [] runnableIds: []
}); });
processor.processTree(); const result = processor.processTree();
expect(processor.isExcluded(leaf)).toEqual(true); expect(result.isExcluded(leaf)).toEqual(true);
}); });
it('processes a single excluded leaf', function() { it('processes a single excluded leaf', function() {
@@ -72,9 +72,9 @@ describe('TreeProcessor', function() {
} }
}); });
processor.processTree(); const result = processor.processTree();
expect(processor.isExcluded(leaf)).toEqual(true); expect(result.isExcluded(leaf)).toEqual(true);
}); });
it('processes a tree with a single leaf with the root specified', function() { it('processes a tree with a single leaf with the root specified', function() {
@@ -85,11 +85,11 @@ describe('TreeProcessor', function() {
runnableIds: [parent.id] runnableIds: [parent.id]
}); });
processor.processTree(); const result = processor.processTree();
expect(processor.isExcluded(parent)).toEqual(false); expect(result.isExcluded(parent)).toEqual(false);
expect(processor.childrenOfTopSuite()).toEqual([{ spec: leaf }]); expect(result.childrenOfTopSuite()).toEqual([{ spec: leaf }]);
expect(processor.isExcluded(leaf)).toEqual(false); expect(result.isExcluded(leaf)).toEqual(false);
}); });
it('processes a tree with a single pending leaf, with the root specified', function() { it('processes a tree with a single pending leaf, with the root specified', function() {
@@ -100,11 +100,11 @@ describe('TreeProcessor', function() {
runnableIds: [parent.id] runnableIds: [parent.id]
}); });
processor.processTree(); const result = processor.processTree();
expect(processor.isExcluded(parent)).toEqual(true); expect(result.isExcluded(parent)).toEqual(true);
expect(processor.childrenOfTopSuite()).toEqual([{ spec: leaf }]); expect(result.childrenOfTopSuite()).toEqual([{ spec: leaf }]);
expect(processor.isExcluded(leaf)).toEqual(false); expect(result.isExcluded(leaf)).toEqual(false);
}); });
it('processes a complicated tree with the root specified', function() { it('processes a complicated tree with the root specified', function() {
@@ -127,38 +127,38 @@ describe('TreeProcessor', function() {
runnableIds: [root.id] runnableIds: [root.id]
}); });
processor.processTree(); const result = processor.processTree();
expect(processor.isExcluded(parent)).toEqual(false); expect(result.isExcluded(parent)).toEqual(false);
expect(processor.childrenOfTopSuite()).toEqual([ expect(result.childrenOfTopSuite()).toEqual([
{ suite: parent, segmentNumber: 0 }, { suite: parent, segmentNumber: 0 },
{ suite: parentOfPendings, segmentNumber: 0 } { suite: parentOfPendings, segmentNumber: 0 }
]); ]);
expect(processor.isExcluded(parentOfPendings)).toEqual(true); expect(result.isExcluded(parentOfPendings)).toEqual(true);
expect(processor.childrenOfSuiteSegment(parentOfPendings, 0)).toEqual([ expect(result.childrenOfSuiteSegment(parentOfPendings, 0)).toEqual([
{ suite: childless, segmentNumber: 0 }, { suite: childless, segmentNumber: 0 },
{ suite: pendingNode, segmentNumber: 0 } { suite: pendingNode, segmentNumber: 0 }
]); ]);
expect(processor.isExcluded(childless)).toEqual(true); expect(result.isExcluded(childless)).toEqual(true);
expect(processor.childrenOfSuiteSegment(childless, 0)).toEqual([]); expect(result.childrenOfSuiteSegment(childless, 0)).toEqual([]);
expect(processor.isExcluded(pendingLeaf)).toEqual(false); expect(result.isExcluded(pendingLeaf)).toEqual(false);
expect(processor.isExcluded(executableLeaf)).toEqual(false); expect(result.isExcluded(executableLeaf)).toEqual(false);
expect(processor.isExcluded(parent)).toEqual(false); expect(result.isExcluded(parent)).toEqual(false);
expect(processor.childrenOfSuiteSegment(parent, 0)).toEqual([ expect(result.childrenOfSuiteSegment(parent, 0)).toEqual([
{ spec: pendingLeaf }, { spec: pendingLeaf },
{ spec: executableLeaf } { spec: executableLeaf }
]); ]);
expect(processor.isExcluded(pendingNode)).toEqual(true); expect(result.isExcluded(pendingNode)).toEqual(true);
expect(processor.childrenOfSuiteSegment(pendingNode, 0)).toEqual([ expect(result.childrenOfSuiteSegment(pendingNode, 0)).toEqual([
{ spec: childOfPending } { spec: childOfPending }
]); ]);
expect(processor.isExcluded(childOfPending)).toEqual(false); expect(result.isExcluded(childOfPending)).toEqual(false);
}); });
it('throws if the specified order would re-enter a node that does not allow re-entry', function() { it('throws if the specified order would re-enter a node that does not allow re-entry', function() {
+7 -7
View File
@@ -6,7 +6,7 @@ getJasmineRequireObj().Runner = function(j$) {
#runableResources; #runableResources;
#runQueue; #runQueue;
#TreeProcessor; #TreeProcessor;
#treeProcessor; #executionTree;
#globalErrors; #globalErrors;
#reportDispatcher; #reportDispatcher;
#getConfig; #getConfig;
@@ -69,7 +69,7 @@ getJasmineRequireObj().Runner = function(j$) {
seed: j$.isNumber_(config.seed) ? config.seed + '' : config.seed seed: j$.isNumber_(config.seed) ? config.seed + '' : config.seed
}); });
this.#treeProcessor = new this.#TreeProcessor({ const treeProcessor = new this.#TreeProcessor({
tree: this.#topSuite, tree: this.#topSuite,
runnableIds: runablesToRun, runnableIds: runablesToRun,
orderChildren: function(node) { orderChildren: function(node) {
@@ -79,7 +79,7 @@ getJasmineRequireObj().Runner = function(j$) {
return !config.specFilter(spec); return !config.specFilter(spec);
} }
}); });
this.#treeProcessor.processTree(); this.#executionTree = treeProcessor.processTree();
return this.#execute2(runablesToRun, order); return this.#execute2(runablesToRun, order);
} }
@@ -164,7 +164,7 @@ getJasmineRequireObj().Runner = function(j$) {
async #executeTopSuite() { async #executeTopSuite() {
const wrappedChildren = this.#wrapNodes( const wrappedChildren = this.#wrapNodes(
this.#treeProcessor.childrenOfTopSuite() this.#executionTree.childrenOfTopSuite()
); );
const queueableFns = this.#addBeforeAndAfterAlls( const queueableFns = this.#addBeforeAndAfterAlls(
this.#topSuite, this.#topSuite,
@@ -188,7 +188,7 @@ getJasmineRequireObj().Runner = function(j$) {
#executeSuiteSegment(suite, segmentNumber, done) { #executeSuiteSegment(suite, segmentNumber, done) {
const wrappedChildren = this.#wrapNodes( const wrappedChildren = this.#wrapNodes(
this.#treeProcessor.childrenOfSuiteSegment(suite, segmentNumber) this.#executionTree.childrenOfSuiteSegment(suite, segmentNumber)
); );
const onStart = { const onStart = {
fn: next => { fn: next => {
@@ -226,7 +226,7 @@ getJasmineRequireObj().Runner = function(j$) {
this.#runQueueWithSkipPolicy.bind(this), this.#runQueueWithSkipPolicy.bind(this),
this.#globalErrors, this.#globalErrors,
done, done,
this.#treeProcessor.isExcluded(spec), this.#executionTree.isExcluded(spec),
config.failSpecWithNoExpectations, config.failSpecWithNoExpectations,
config.detectLateRejectionHandling config.detectLateRejectionHandling
); );
@@ -247,7 +247,7 @@ getJasmineRequireObj().Runner = function(j$) {
} }
#addBeforeAndAfterAlls(suite, wrappedChildren) { #addBeforeAndAfterAlls(suite, wrappedChildren) {
if (this.#treeProcessor.isExcluded(suite)) { if (this.#executionTree.isExcluded(suite)) {
return wrappedChildren; return wrappedChildren;
} }
+38 -25
View File
@@ -2,13 +2,15 @@ getJasmineRequireObj().TreeProcessor = function(j$) {
const defaultMin = Infinity; const defaultMin = Infinity;
const defaultMax = 1 - Infinity; const defaultMax = 1 - Infinity;
// Transforms the suite tree into an execution tree, which represents the set
// of specs and (possibly interleaved) suites to be run in the order they are
// to be run in.
class TreeProcessor { class TreeProcessor {
#tree; #tree;
#runnableIds; #runnableIds;
#orderChildren; #orderChildren;
#excludeNode; #excludeNode;
#stats; #stats;
#processed;
constructor(attrs) { constructor(attrs) {
this.#tree = attrs.tree; this.#tree = attrs.tree;
@@ -24,34 +26,14 @@ getJasmineRequireObj().TreeProcessor = function(j$) {
function(node) { function(node) {
return false; return false;
}; };
this.#stats = {};
this.#processed = false;
} }
processTree() { processTree() {
this.#stats = {};
this.#processNode(this.#tree, true); this.#processNode(this.#tree, true);
this.#processed = true; const result = new ExecutionTree(this.#tree, this.#stats);
} this.#stats = null;
return result;
childrenOfTopSuite() {
return this.childrenOfSuiteSegment(this.#tree, 0);
}
childrenOfSuiteSegment(suite, segmentNumber) {
const segmentChildren = this.#stats[suite.id].segments[segmentNumber]
.nodes;
return segmentChildren.map(function(child) {
if (child.owner.children) {
return { suite: child.owner, segmentNumber: child.index };
} else {
return { spec: child.owner };
}
});
}
isExcluded(node) {
const nodeStats = this.#stats[node.id];
return node.children ? !nodeStats.willExecute : nodeStats.excluded;
} }
#runnableIndex(id) { #runnableIndex(id) {
@@ -118,6 +100,37 @@ getJasmineRequireObj().TreeProcessor = function(j$) {
} }
} }
class ExecutionTree {
#topSuite;
#stats;
constructor(topSuite, stats) {
this.#topSuite = topSuite;
this.#stats = stats;
}
childrenOfTopSuite() {
return this.childrenOfSuiteSegment(this.#topSuite, 0);
}
childrenOfSuiteSegment(suite, segmentNumber) {
const segmentChildren = this.#stats[suite.id].segments[segmentNumber]
.nodes;
return segmentChildren.map(function(child) {
if (child.owner.children) {
return { suite: child.owner, segmentNumber: child.index };
} else {
return { spec: child.owner };
}
});
}
isExcluded(node) {
const nodeStats = this.#stats[node.id];
return node.children ? !nodeStats.willExecute : nodeStats.excluded;
}
}
function segmentChildren(node, orderedChildren, stats, executableIndex) { function segmentChildren(node, orderedChildren, stats, executableIndex) {
let currentSegment = { let currentSegment = {
index: 0, index: 0,