/// <inheritdoc /> public ITestCommand BuildCommands(TestModel testModel, FilterSet <ITestDescriptor> filterSet, bool exactFilter, ITestContextManager contextManager) { if (testModel == null) { throw new ArgumentNullException("testModel"); } if (filterSet == null) { throw new ArgumentNullException("filterSet"); } if (contextManager == null) { throw new ArgumentNullException("contextManager"); } var commands = new Dictionary <Test, ManagedTestCommand>(); bool hasExplicitAncestor = !filterSet.HasInclusionRules; ManagedTestCommand rootCommand = CreateFilteredClosure(commands, testModel.RootTest, filterSet, exactFilter, hasExplicitAncestor, contextManager); if (rootCommand == null) { return(null); } var siblingDependencies = new MultiMap <ManagedTestCommand, ManagedTestCommand>(); PopulateCommandDependencies(commands, siblingDependencies); SortChildren(rootCommand, siblingDependencies); return(rootCommand); }
/// <summary> /// Gets the list of children as an array. /// </summary> /// <returns>The array of children.</returns> public ManagedTestCommand[] ChildrenToArray() { if (children == null) { return(EmptyArray <ManagedTestCommand> .Instance); } ManagedTestCommand[] array = new ManagedTestCommand[children.Count]; children.CopyTo(array); return(array); }
/// <summary> /// Adds a test command dependency. /// </summary> /// <param name="dependency">The dependency to add.</param> public void AddDependency(ManagedTestCommand dependency) { if (dependency == null) { throw new ArgumentNullException("dependency"); } if (dependencies == null) { dependencies = new List <ITestCommand>(); } dependencies.Add(dependency); }
/// <summary> /// Adds a child test command. /// </summary> /// <param name="child">The child to add.</param> public void AddChild(ManagedTestCommand child) { if (child == null) { throw new ArgumentNullException("child"); } if (children == null) { children = new List <ITestCommand>(); } children.Add(child); }
private ManagedTestCommand CreateCommand(Dictionary <Test, ManagedTestCommand> commands, Test test, IEnumerable <ManagedTestCommand> children, bool isExplicit, ITestContextManager contextManager) { var testMonitor = new ManagedTestCommand(contextManager, test, isExplicit); foreach (ManagedTestCommand child in children) { testMonitor.AddChild(child); } commands.Add(test, testMonitor); return(testMonitor); }
private ManagedTestCommand CreateFilteredClosure(Dictionary <Test, ManagedTestCommand> commands, Test test, FilterSet <ITestDescriptor> filterSet, bool exactFilter, bool hasExplicitAncestor, ITestContextManager contextManager) { FilterSetResult filterSetResult = filterSet.Evaluate(test); if (filterSetResult == FilterSetResult.Exclude) { return(null); } bool isMatch = filterSetResult == FilterSetResult.Include; bool isExplicit = isMatch && !hasExplicitAncestor; bool hasExplicitChild = false; var children = new List <ManagedTestCommand>(test.Children.Count); foreach (Test child in test.Children) { ManagedTestCommand childMonitor = CreateFilteredClosure(commands, child, filterSet, exactFilter, hasExplicitAncestor || isExplicit, contextManager); if (childMonitor != null) { children.Add(childMonitor); if (childMonitor.IsExplicit) { hasExplicitChild = true; } } } if (isMatch || children.Count != 0 || (!exactFilter && hasExplicitAncestor)) { return(CreateCommand(commands, test, children, isExplicit || hasExplicitChild, contextManager)); } return(null); }
/// <summary> /// Gets the list of children as an array. /// </summary> /// <returns>The array of children.</returns> public ManagedTestCommand[] ChildrenToArray() { if (children == null) return EmptyArray<ManagedTestCommand>.Instance; ManagedTestCommand[] array = new ManagedTestCommand[children.Count]; children.CopyTo(array); return array; }
/// <summary> /// Adds a test command dependency. /// </summary> /// <param name="dependency">The dependency to add.</param> public void AddDependency(ManagedTestCommand dependency) { if (dependency == null) throw new ArgumentNullException("dependency"); if (dependencies == null) dependencies = new List<ITestCommand>(); dependencies.Add(dependency); }
/// <summary> /// Adds a child test command. /// </summary> /// <param name="child">The child to add.</param> public void AddChild(ManagedTestCommand child) { if (child == null) throw new ArgumentNullException("child"); if (children == null) children = new List<ITestCommand>(); children.Add(child); }
public DepthFirstEntry(ManagedTestCommand source, IEnumerable<ManagedTestCommand> dependencies) { Source = source; DependencyEnumerator = dependencies.GetEnumerator(); }
private void SortCommandsByOrder(ManagedTestCommand[] commands) { Array.Sort(commands, (a, b) => testOrderStrategy.Compare(a.Test, b.Test)); }
private void SortChildren(ManagedTestCommand parent, MultiMap<ManagedTestCommand, ManagedTestCommand> siblingDependencies) { ManagedTestCommand[] children = parent.ChildrenToArray(); if (children.Length == 0) return; // Clear the array of children since we are about to reshuffle them. parent.ClearChildren(); // Sort the children by order. Because the topological sort emits vertices precisely // in the ordert that it visits them (depth-first) it will preserve the relative ordering // of independent vertices. So we influence test execution order by pre-sorting. // Dependencies will of course interfere with the ordering slightly. However, if the // user explicitly specifies orderings in dependency order then they'll indeed run in // that specified order. -- Jeff. SortCommandsByOrder(children); // Perform a topological sort of the children using depth-first search. // Because at this stage a command only has dependencies on its siblings the depth-first search // actually proceeds down the chain of sibling dependencies only; it does not // traverse the whole test hierarchy. -- Jeff. Dictionary<ManagedTestCommand, bool> visitedSet = new Dictionary<ManagedTestCommand, bool>(); Stack<DepthFirstEntry> stack = new Stack<DepthFirstEntry>(); stack.Push(new DepthFirstEntry(null, children)); for (;;) { DepthFirstEntry top = stack.Peek(); if (top.DependencyEnumerator.MoveNext()) { ManagedTestCommand current = top.DependencyEnumerator.Current; bool inProgressFlag; if (visitedSet.TryGetValue(current, out inProgressFlag)) { if (inProgressFlag) throw new ModelException(String.Format("Found a test dependency cycle involving test '{0}'.", current.Test.FullName)); } else { IList<ManagedTestCommand> unorderedDependencies = siblingDependencies[current]; if (unorderedDependencies.Count != 0) { visitedSet[current] = true; // We need to sort all visited children so that dependencies run in relative order. ManagedTestCommand[] dependencies = GenericCollectionUtils.ToArray(unorderedDependencies); SortCommandsByOrder(dependencies); stack.Push(new DepthFirstEntry(current, dependencies)); } else { parent.AddChild(current); visitedSet[current] = false; } } } else { ManagedTestCommand current = top.Source; if (current == null) break; parent.AddChild(current); visitedSet[current] = false; stack.Pop(); } } // Recursively sort the children of this command. foreach (ManagedTestCommand child in children) SortChildren(child, siblingDependencies); }
private ManagedTestCommand CreateCommand(Dictionary<Test, ManagedTestCommand> commands, Test test, IEnumerable<ManagedTestCommand> children, bool isExplicit, ITestContextManager contextManager) { var testMonitor = new ManagedTestCommand(contextManager, test, isExplicit); foreach (ManagedTestCommand child in children) testMonitor.AddChild(child); commands.Add(test, testMonitor); return testMonitor; }
public DepthFirstEntry(ManagedTestCommand source, IEnumerable <ManagedTestCommand> dependencies) { Source = source; DependencyEnumerator = dependencies.GetEnumerator(); }
private void SortChildren(ManagedTestCommand parent, MultiMap <ManagedTestCommand, ManagedTestCommand> siblingDependencies) { ManagedTestCommand[] children = parent.ChildrenToArray(); if (children.Length == 0) { return; } // Clear the array of children since we are about to reshuffle them. parent.ClearChildren(); // Sort the children by order. Because the topological sort emits vertices precisely // in the ordert that it visits them (depth-first) it will preserve the relative ordering // of independent vertices. So we influence test execution order by pre-sorting. // Dependencies will of course interfere with the ordering slightly. However, if the // user explicitly specifies orderings in dependency order then they'll indeed run in // that specified order. -- Jeff. SortCommandsByOrder(children); // Perform a topological sort of the children using depth-first search. // Because at this stage a command only has dependencies on its siblings the depth-first search // actually proceeds down the chain of sibling dependencies only; it does not // traverse the whole test hierarchy. -- Jeff. Dictionary <ManagedTestCommand, bool> visitedSet = new Dictionary <ManagedTestCommand, bool>(); Stack <DepthFirstEntry> stack = new Stack <DepthFirstEntry>(); stack.Push(new DepthFirstEntry(null, children)); for (;;) { DepthFirstEntry top = stack.Peek(); if (top.DependencyEnumerator.MoveNext()) { ManagedTestCommand current = top.DependencyEnumerator.Current; bool inProgressFlag; if (visitedSet.TryGetValue(current, out inProgressFlag)) { if (inProgressFlag) { throw new ModelException(String.Format("Found a test dependency cycle involving test '{0}'.", current.Test.FullName)); } } else { IList <ManagedTestCommand> unorderedDependencies = siblingDependencies[current]; if (unorderedDependencies.Count != 0) { visitedSet[current] = true; // We need to sort all visited children so that dependencies run in relative order. ManagedTestCommand[] dependencies = GenericCollectionUtils.ToArray(unorderedDependencies); SortCommandsByOrder(dependencies); stack.Push(new DepthFirstEntry(current, dependencies)); } else { parent.AddChild(current); visitedSet[current] = false; } } } else { ManagedTestCommand current = top.Source; if (current == null) { break; } parent.AddChild(current); visitedSet[current] = false; stack.Pop(); } } // Recursively sort the children of this command. foreach (ManagedTestCommand child in children) { SortChildren(child, siblingDependencies); } }