/// <summary> /// Given: /// - a file-to-file map (<paramref name="file2file"/>), and /// - indexes of changed nodes (<paramref name="changed"/>) /// computes /// - downstream nodes (and asserts they match <paramref name="expectedDownstream"/> /// - upsteram nodes (and asserts they match <paramref name="expectedUpstream"/> /// - indirect upstream nodes (and asserts they match <paramref name="expectedIndirectUpstream"/> /// - all affected nodes (and asserts they match <paramref name="expectedAffected"/> /// /// Definitions: /// - 'downstream' nodes: all nodes reachable from <paramref name="changed"/> (excluding the /// changed nodes themselves) by following the reverse edges in <paramref name="file2file"/> /// - 'upstream' nodes: all nodes reachable from <paramref name="changed"/> (excluding the /// changed nodes themselves) by following the edges in <paramref name="file2file"/> /// - 'affected' nodes: upstream of 'changed' + 'downstream' nodes, including the changed and /// downstream nodes themselves /// - 'indirect upstream' nodes: 'affected' nodes that are neither 'changed' or 'upstream' or 'downstream' /// </summary> /// <remarks> /// Some remarks about the notation in the comments below: /// - the '^' means transitive closure /// - the '*' means reflexive transitive closure /// - the '.' means relational join /// For example /// - changed.^Edges means all reachable nodes from 'changed' by following 'Edges', excluding the nodes in 'changed' /// - changed.*Edges means all reachable nodes from 'changed' by following 'Edges', including the nodes in 'changed'. /// </remarks> private void ComputeAndCheckSpecStates(SimpleGraph file2file, int[] changed, int[] expectedDownstream, int[] expectedUpstream, int[] expectedIndirectUpstream, int[] expectedAffected) { // downstream = changed.^reverseEdges var downstream = file2file.ComputeDownstream(changed); XAssert.AreSetsEqual(expectedDownstream, downstream, expectedResult: true, format: "Downstream nodes don't match"); // upstream = changed.^edges var upstream = file2file.ComputeUpstream(changed); XAssert.AreSetsEqual(expectedUpstream, upstream, expectedResult: true, format: "Upstream nodes don't match"); // allAffected = (changed.*reverseEdges).*edges var allAffected = file2file.ComputeReflexiveUpstream(file2file.ComputeReflexiveDownstream(changed)); XAssert.AreSetsEqual(expectedAffected, allAffected, expectedResult: true, format: "Affected nodes don't match"); // indirectUpstream = allAffected - changed - upstream - downstream var indirectUpstream = allAffected.Except(changed).Except(upstream).Except(downstream); XAssert.AreSetsEqual(expectedIndirectUpstream, indirectUpstream, expectedResult: true, format: "Indirect upstream nodes don't match"); }