public void SortingCircular() { // Circular dependencies are not supported in Rhetos, // but this test verifies robustness of the algorithm implementation // and error detection. var cA = new C1 { Name = "A" }; var cB = new C1 { Name = "B" }; cA.Ref1 = cB; cB.Ref1 = cA; var cInit = new InitializationConcept { RhetosVersion = "init" }; var cDependant = new C2 { Name = "dep", Ref1 = cA, Ref2 = cB }; var testData = new List <IConceptInfo> { cDependant, cA, cB, cInit }; var dslContainer = new DslContainerAccessor { ResolvedConcepts = testData }; TestUtility.ShouldFail <FrameworkException>( () => dslContainer.SortReferencesBeforeUsingConcept(InitialConceptsSort.None), "C1 A"); }
public void UnresolvedReferences() { var dslContainer = new DslContainerAccessor(); var missing = new C0 { Name = "X" }; var a = new C0 { Name = "A" }; // should be resolved var b = new C1 { Name = "B", Ref1 = a }; // should be resolved var c = new C1 { Name = "C", Ref1 = b }; // should be resolved var d = new C2 { Name = "D", Ref1 = c, Ref2 = missing }; // unresolved var i = new C1 { Name = "I", Ref1 = d }; // resolved, but references unresolved var j = new C1 { Name = "J", Ref1 = i }; // resolved, but indirectly references unresolved var g = new C2 { Name = "G", Ref2 = missing }; // unresolved var h = new C1 { Name = "H" }; // resolved, but references unresolved g.Ref1 = h; h.Ref1 = g; var newConcepts = dslContainer.AddNewConceptsAndReplaceReferences(new IConceptInfo[] { a }).NewUniqueConcepts; Assert.AreEqual("A", TestUtility.DumpSorted(newConcepts, item => ((dynamic)item).Name)); Assert.AreEqual("A", TestUtility.DumpSorted(dslContainer.Concepts, item => ((dynamic)item).Name)); newConcepts = dslContainer.AddNewConceptsAndReplaceReferences(new IConceptInfo[] { i, d, c, b, g, h, i, j, a }).NewUniqueConcepts; Assert.AreEqual("B, C, D, G, H, I, J", TestUtility.DumpSorted(newConcepts, item => ((dynamic)item).Name)); Assert.AreEqual("A, B, C", TestUtility.DumpSorted(dslContainer.Concepts, item => ((dynamic)item).Name)); newConcepts = dslContainer.AddNewConceptsAndReplaceReferences(new IConceptInfo[] { i, d, c, b, g, h, i, j, a }).NewUniqueConcepts; Assert.AreEqual("", TestUtility.DumpSorted(newConcepts, item => ((dynamic)item).Name)); Assert.AreEqual("A, B, C", TestUtility.DumpSorted(dslContainer.Concepts, item => ((dynamic)item).Name)); var ex = TestUtility.ShouldFail <DslSyntaxException>( () => dslContainer.ReportErrorForUnresolvedConcepts(), "Referenced concept is not defined in DSL scripts", missing.GetUserDescription()); Assert.IsTrue(new IConceptInfo[] { d, i, j, g, h } .Any(conceptInfo => ex.Message.Contains(conceptInfo.GetUserDescription()))); }
public void SortEmpty() { var testData = new List <IConceptInfo> { }; var dslContainer = new DslContainerAccessor { ResolvedConcepts = testData }; dslContainer.SortReferencesBeforeUsingConcept(InitialConceptsSort.None); Assert.AreEqual( TestUtility.Dump(testData, c => c.GetKey()), TestUtility.Dump(dslContainer.ResolvedConcepts, c => c.GetKey())); }
private void TestDifferentConceptSameKey(ListOfTuples <IConceptInfo[], string, string, string[]> newConceptsSets) { var dslContainer = new DslContainerAccessor(); foreach (var newConceptsSet in newConceptsSets) { if (newConceptsSet.Item4 == null) { var report = dslContainer.AddNewConceptsAndReplaceReferences(newConceptsSet.Item1); Assert.AreEqual(newConceptsSet.Item2, TestUtility.DumpSorted(report.NewUniqueConcepts, item => item.GetShortDescription())); Assert.AreEqual(newConceptsSet.Item3, TestUtility.DumpSorted(dslContainer.Concepts, item => item.GetShortDescription())); } else { TestUtility.ShouldFail(() => dslContainer.AddNewConceptsAndReplaceReferences(newConceptsSet.Item1), newConceptsSet.Item4); } } }
public void SortInitOnly() { var cInit = new InitializationConcept { RhetosVersion = "init" }; var testData = new List <IConceptInfo> { cInit }; var dslContainer = new DslContainerAccessor { ResolvedConcepts = testData }; dslContainer.SortReferencesBeforeUsingConcept(InitialConceptsSort.None); Assert.AreEqual( TestUtility.Dump(testData, c => c.GetKey()), TestUtility.Dump(dslContainer.ResolvedConcepts, c => c.GetKey())); }
public void UnresolvedReferences() { var dslContainer = new DslContainerAccessor(); var missing = new C0 { Name = "X" }; var a = new C0 { Name = "A" }; // should be resolved var b = new C1 { Name = "B", Ref1 = a }; // should be resolved var c = new C1 { Name = "C", Ref1 = b }; // should be resolved var d = new C2 { Name = "D", Ref1 = c, Ref2 = missing }; // unresolved var i = new C1 { Name = "I", Ref1 = d }; // resolved, but references unresolved var j = new C1 { Name = "J", Ref1 = i }; // resolved, but indirectly references unresolved var e = new C1 { Name = "E" }; // should be resolved, circular reference should not be a problem var f = new C1 { Name = "F" }; // should be resolved, circular reference should not be a problem e.Ref1 = f; f.Ref1 = e; var g = new C2 { Name = "G", Ref2 = missing }; // unresolved var h = new C1 { Name = "H" }; // resolved, but references unresolved g.Ref1 = h; h.Ref1 = g; var newConcepts = dslContainer.AddNewConceptsAndReplaceReferences(new IConceptInfo[] { a }).NewUniqueConcepts; Assert.AreEqual("A", TestUtility.DumpSorted(newConcepts, item => ((dynamic)item).Name)); Assert.AreEqual("A", TestUtility.DumpSorted(dslContainer.Concepts, item => ((dynamic)item).Name)); newConcepts = dslContainer.AddNewConceptsAndReplaceReferences(new IConceptInfo[] { i, d, c, b, e, f, g, h, i, j, a }).NewUniqueConcepts; Assert.AreEqual("B, C, D, E, F, G, H, I, J", TestUtility.DumpSorted(newConcepts, item => ((dynamic)item).Name)); Assert.AreEqual("A, B, C, E, F", TestUtility.DumpSorted(dslContainer.Concepts, item => ((dynamic)item).Name)); newConcepts = dslContainer.AddNewConceptsAndReplaceReferences(new IConceptInfo[] { i, d, c, b, e, f, g, h, i, j, a }).NewUniqueConcepts; Assert.AreEqual("", TestUtility.DumpSorted(newConcepts, item => ((dynamic)item).Name)); Assert.AreEqual("A, B, C, E, F", TestUtility.DumpSorted(dslContainer.Concepts, item => ((dynamic)item).Name)); var ex = TestUtility.ShouldFail<DslSyntaxException>( () => dslContainer.ReportErrorForUnresolvedConcepts(), "Referenced concept is not defined in DSL scripts", missing.GetUserDescription()); Assert.IsTrue(new IConceptInfo[] { d, i, j, g, h } .Any(conceptInfo => ex.Message.Contains(conceptInfo.GetUserDescription()))); }
public void CircularReferences() { var dslContainer = new DslContainerAccessor(); var a = new C0 { Name = "A" }; // should be resolved var b = new C1 { Name = "B" }; // referencing circular dependency var c = new C1 { Name = "C" }; // circular dependency var d = new C1 { Name = "D" }; // circular dependency var e = new C1 { Name = "E" }; // referencing circular dependency b.Ref1 = c; c.Ref1 = d; d.Ref1 = c; e.Ref1 = d; var report = dslContainer.AddNewConceptsAndReplaceReferences(new IConceptInfo[] { a, b, c, d, e }); Assert.AreEqual("A, B, C, D, E", TestUtility.DumpSorted(report.NewUniqueConcepts, item => ((dynamic)item).Name)); Assert.AreEqual("A", TestUtility.DumpSorted(report.NewlyResolvedConcepts, item => ((dynamic)item).Name)); Assert.AreEqual("A", TestUtility.DumpSorted(dslContainer.Concepts, item => ((dynamic)item).Name)); var ex = TestUtility.ShouldFail <DslSyntaxException>( () => dslContainer.ReportErrorForUnresolvedConcepts(), "circular dependency"); // Circular dependency error message should contain only the circle, not external references to it. Assert.IsTrue(new IConceptInfo[] { c, d }.All(conceptInfo => ex.Message.Contains(conceptInfo.GetUserDescription()))); Assert.IsFalse(new IConceptInfo[] { b, e }.Any(conceptInfo => ex.Message.Contains(conceptInfo.GetUserDescription()))); }
public void Sorting() { var cInit = new InitializationConcept { RhetosVersion = "init" }; var c01 = new C0 { Name = "1" }; var c02 = new C0 { Name = "2" }; var c03 = new C0 { Name = "3" }; var cB1 = new CBase { Name = "1" }; var cB2 = new CBase { Name = "2" }; var c2Dependant = new C2 { Name = "dep", Ref1 = c01, Ref2 = cB2 }; var testData = new List <IConceptInfo> { c02, c01, cB2, c2Dependant, cInit, c03, cB1 }; // The expected positions may somewhat change if the sorting algorithm internals change. var tests = new List <(string SortMethod, List <IConceptInfo> ExpectedResult)> { // cInit always goes first. cDependant does not need to move because it is after referenced c1 and c5. ("None", new List <IConceptInfo> { cInit, c02, c01, cB2, c2Dependant, c03, cB1 }), // cB2 is pushed before c2Dependant, to respect dependency precedence. ("Key", new List <IConceptInfo> { cInit, c01, c02, c03, cB2, c2Dependant, cB1 }), // c01 is pushed before c2Dependant, to respect dependency precedence. ("KeyDescending", new List <IConceptInfo> { cInit, cB2, cB1, c01, c2Dependant, c03, c02 }), }; foreach (var test in tests) { var configuration = new MockConfiguration { { "CommonConcepts.Debug.SortConcepts", test.SortMethod } }; var dslContainer = new DslContainerAccessor(configuration); dslContainer.ResolvedConcepts = testData; dslContainer.SortReferencesBeforeUsingConcept(); Assert.AreEqual( TestUtility.Dump(test.ExpectedResult, c => c.GetKey()), TestUtility.Dump(dslContainer.ResolvedConcepts, c => c.GetKey()), test.SortMethod); } }
private void TestDifferentConceptSameKey(ListOfTuples<IConceptInfo[], string, string, string[]> newConceptsSets) { var dslContainer = new DslContainerAccessor(); foreach (var newConceptsSet in newConceptsSets) { if (newConceptsSet.Item4 == null) { var report = dslContainer.AddNewConceptsAndReplaceReferences(newConceptsSet.Item1); Assert.AreEqual(newConceptsSet.Item2, TestUtility.DumpSorted(report.NewUniqueConcepts, item => item.GetShortDescription())); Assert.AreEqual(newConceptsSet.Item3, TestUtility.DumpSorted(dslContainer.Concepts, item => item.GetShortDescription())); } else { TestUtility.ShouldFail(() => dslContainer.AddNewConceptsAndReplaceReferences(newConceptsSet.Item1), newConceptsSet.Item4); } } }
public void Sorting() { var cInit = new InitializationConcept { RhetosVersion = "init" }; var c01 = new C0 { Name = "1" }; var c02 = new C0 { Name = "2" }; var c03 = new C0 { Name = "3" }; var cB1 = new CBase { Name = "1" }; var cB2 = new CBase { Name = "2" }; var c2Dependant = new C2 { Name = "dep", Ref1 = c01, Ref2 = cB2 }; var testData = new List <IConceptInfo> { c02, c01, cB2, c2Dependant, cInit, c03, cB1 }; // The expected positions may somewhat change if the sorting algorithm internals change. var tests = new List <(InitialConceptsSort SortMethod, List <IConceptInfo> ExpectedResult)> { // cInit always goes first. cDependant is moved to the end, even though it does not need to be moved // because it is after referenced c01 and cB2. Putting all level 2 concept after level 1, // instead of keeping the initial sort based on dynamic evaluation, should result with // less changes in the final generated code. (InitialConceptsSort.None, new List <IConceptInfo> { cInit, c02, c01, cB2, c03, cB1, c2Dependant }), // Keeping the InitialConceptsSort ordering between the concepts of the same level. (InitialConceptsSort.Key, new List <IConceptInfo> { cInit, c01, c02, c03, cB1, cB2, c2Dependant }), // Keeping the InitialConceptsSort ordering between the concepts of the same level. (InitialConceptsSort.KeyDescending, new List <IConceptInfo> { cInit, cB2, cB1, c03, c02, c01, c2Dependant }), }; foreach (var test in tests) { var dslContainer = new DslContainerAccessor { ResolvedConcepts = testData }; dslContainer.SortReferencesBeforeUsingConcept(test.SortMethod); Assert.AreEqual( TestUtility.Dump(test.ExpectedResult, c => c.GetKey()), TestUtility.Dump(dslContainer.ResolvedConcepts, c => c.GetKey()), $"SortConceptsMethod: {test.SortMethod}"); } }