public void CycleWithDuplicates() { var testValues = new { A = TestValue.Create("a ", "e"), B = TestValue.Create(" B", " c "), A2 = TestValue.Create("A ", "C"), C = TestValue.Create("C", "A", "D"), D = TestValue.Create("d"), E = TestValue.Create("E"), }; var graph = new[] { testValues.A, testValues.B, testValues.C, testValues.D, testValues.E, testValues.A2, }; var ignoreCase = DerivedComparer.Create(StringComparer.OrdinalIgnoreCase, (string t) => t.Trim()); var equalityComparer = TestValue.CreateComparer(ignoreCase); var vertexValueComparer = new VertexValueComparer <TestValue <string> >(equalityComparer); var byValue = graph.ToLookup(t => t.Value, ignoreCase); var vertices = VertexBuilder.BuildVertices(graph, s => s.DependsOn.SelectMany(d => byValue[d]), equalityComparer).ToList(); Assert.AreEqual(6, vertices.Count, "every source element should yield a vertex"); Assert.AreEqual(5, vertices.Distinct().Count(), "'A' and 'a ' should yield the exact same vertex"); var finder = new StronglyConnectedComponentFinder <TestValue <string> >(); var simpleComponents = finder.DetectCycle(vertices, vertexValueComparer); var components = simpleComponents.ExtractCycles(equalityComparer); Assert.AreEqual(4, components.Count, "It should be only 4 components"); Assert.AreEqual(3, components.IndependentComponents().Count(), "B, D & E are acylic"); Assert.AreEqual(1, components.Cycles().Count(), "Only 1 cycle should be found"); Assert.AreEqual (2, components.Take(2) .SelectMany(t => t) .Intersect(new[] { testValues.D, testValues.E }) .Count(), "D & E should be the first components."); var component3 = components.Skip(2).First(); var component4 = components.Skip(3).First(); Assert.AreEqual(component3.Count, 2, "3rd component should be a cycle of 2"); Assert.AreEqual (component3.Intersect(new[] { testValues.A, testValues.C }).Count(), 2, "3rd component should be a cycle of A & C"); Assert.AreEqual(testValues.B, component4.Single()); // 4th one has to be B (uses A) }
public void Cycle4WithStubIgnoreCaseAndTrim() { var testValues = new { A = TestValue.Create("a ", "B"), B = TestValue.Create(" B", " c "), C = TestValue.Create("C", "A", "D"), D = TestValue.Create("d"), E = TestValue.Create("e", "b"), A2 = TestValue.Create("A ", "B"), }; var graph = new[] { testValues.A, testValues.B, testValues.C, testValues.D, testValues.E, testValues.A2, }; var ignoreCase = DerivedComparer.Create(StringComparer.OrdinalIgnoreCase, (string t) => t.Trim()); var components1 = graph.DetectCyclesUsingKey(t => t.Value, s => s.DependsOn, keyComparer: ignoreCase, comparer: TestValue.CreateComparer(ignoreCase)); RunAssertions(components1); var byValue = graph.ToLookup(t => t.Value, ignoreCase); var components2 = graph.DetectCycles(s => s.DependsOn.SelectMany(d => byValue[d]), TestValue.CreateComparer(ignoreCase)); RunAssertions(components2); void RunAssertions(ICollection <DependencyCycle <TestValue <string> > > components) { Assert.AreEqual(3, components.Count); Assert.AreEqual(2, components.IndependentComponents().Count()); // D & E are acyclic Assert.AreEqual(1, components.Cycles().Count()); Assert.AreEqual(1, components.Count(c => c.Count == 3)); Assert.AreEqual(2, components.Count(c => c.Count == 1)); var component1 = components.First(); Assert.IsTrue(component1.Single() == testValues.D); // first component has to be D (used by C which is in a cycle) var component2 = components.Skip(1).First().ToList(); var component3 = components.Skip(2).First(); Assert.IsTrue(component3.Single() == testValues.E); // 3rd component has to be E (requires B which is in a cycle) Assert.IsTrue(component2[0] == testValues.C); // first one has to be C (used by A & B) Assert.IsTrue(component2[1] == testValues.B); // first one has to be B (used by A) Assert.IsTrue(component2[2] == testValues.A); // first one has to be A (used by C, but was in the list ) } }